diff options
Diffstat (limited to 'drivers/gpu/drm/vkms')
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_composer.c | 104 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_drv.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_drv.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_output.c | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_plane.c | 51 |
5 files changed, 125 insertions, 72 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); diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 2173b82606f6..027ffe759440 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -44,6 +44,10 @@ static bool enable_writeback = true; module_param_named(enable_writeback, enable_writeback, bool, 0444); MODULE_PARM_DESC(enable_writeback, "Enable/Disable writeback connector support"); +static bool enable_overlay; +module_param_named(enable_overlay, enable_overlay, bool, 0444); +MODULE_PARM_DESC(enable_overlay, "Enable/Disable overlay support"); + DEFINE_DRM_GEM_FOPS(vkms_driver_fops); static void vkms_release(struct drm_device *dev) @@ -198,6 +202,7 @@ static int __init vkms_init(void) config->cursor = enable_cursor; config->writeback = enable_writeback; + config->overlay = enable_overlay; return vkms_create(config); } diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 35540c7c4416..ac8c9c2fa4ed 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -37,6 +37,10 @@ struct vkms_plane_state { struct vkms_composer *composer; }; +struct vkms_plane { + struct drm_plane base; +}; + /** * vkms_crtc_state - Driver specific CRTC state * @base: base CRTC state @@ -85,6 +89,7 @@ struct vkms_device; struct vkms_config { bool writeback; bool cursor; + bool overlay; /* only set when instantiated */ struct vkms_device *dev; }; @@ -114,8 +119,8 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, int vkms_output_init(struct vkms_device *vkmsdev, int index); -struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type, int index); +struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, + enum drm_plane_type type, int index); /* CRC Support */ const char *const *vkms_get_crc_sources(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index f5f6f15c362c..04406bd3ff02 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -39,7 +39,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) struct drm_connector *connector = &output->connector; struct drm_encoder *encoder = &output->encoder; struct drm_crtc *crtc = &output->crtc; - struct drm_plane *primary, *cursor = NULL; + struct vkms_plane *primary, *cursor = NULL, *overlay = NULL; int ret; int writeback; @@ -47,17 +47,24 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) if (IS_ERR(primary)) return PTR_ERR(primary); + if (vkmsdev->config->overlay) { + overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); + if (IS_ERR(overlay)) + return PTR_ERR(overlay); + + if (!overlay->base.possible_crtcs) + overlay->base.possible_crtcs = drm_crtc_mask(crtc); + } + if (vkmsdev->config->cursor) { cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index); - if (IS_ERR(cursor)) { - ret = PTR_ERR(cursor); - goto err_cursor; - } + if (IS_ERR(cursor)) + return PTR_ERR(cursor); } - ret = vkms_crtc_init(dev, crtc, primary, cursor); + ret = vkms_crtc_init(dev, crtc, &primary->base, &cursor->base); if (ret) - goto err_crtc; + return ret; ret = drm_connector_init(dev, connector, &vkms_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); @@ -100,12 +107,5 @@ err_encoder: err_connector: drm_crtc_cleanup(crtc); -err_crtc: - if (vkmsdev->config->cursor) - drm_plane_cleanup(cursor); - -err_cursor: - drm_plane_cleanup(primary); - return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 6d310d31b75d..107521ace597 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -16,8 +16,9 @@ static const u32 vkms_formats[] = { DRM_FORMAT_XRGB8888, }; -static const u32 vkms_cursor_formats[] = { +static const u32 vkms_plane_formats[] = { DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888 }; static struct drm_plane_state * @@ -86,7 +87,6 @@ static void vkms_plane_reset(struct drm_plane *plane) static const struct drm_plane_funcs vkms_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_plane_cleanup, .reset = vkms_plane_reset, .atomic_duplicate_state = vkms_plane_duplicate_state, .atomic_destroy_state = vkms_plane_destroy_state, @@ -133,7 +133,7 @@ static int vkms_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (plane->type == DRM_PLANE_TYPE_CURSOR) + if (plane->type != DRM_PLANE_TYPE_PRIMARY) can_position = true; ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, @@ -191,39 +191,42 @@ static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { .cleanup_fb = vkms_cleanup_fb, }; -struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type, int index) +struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, + enum drm_plane_type type, int index) { struct drm_device *dev = &vkmsdev->drm; const struct drm_plane_helper_funcs *funcs; - struct drm_plane *plane; + struct vkms_plane *plane; const u32 *formats; - int ret, nformats; + int nformats; - plane = kzalloc(sizeof(*plane), GFP_KERNEL); - if (!plane) - return ERR_PTR(-ENOMEM); - - if (type == DRM_PLANE_TYPE_CURSOR) { - formats = vkms_cursor_formats; - nformats = ARRAY_SIZE(vkms_cursor_formats); + switch (type) { + case DRM_PLANE_TYPE_PRIMARY: + formats = vkms_formats; + nformats = ARRAY_SIZE(vkms_formats); funcs = &vkms_primary_helper_funcs; - } else { + break; + case DRM_PLANE_TYPE_CURSOR: + case DRM_PLANE_TYPE_OVERLAY: + formats = vkms_plane_formats; + nformats = ARRAY_SIZE(vkms_plane_formats); + funcs = &vkms_primary_helper_funcs; + break; + default: formats = vkms_formats; nformats = ARRAY_SIZE(vkms_formats); funcs = &vkms_primary_helper_funcs; + break; } - ret = drm_universal_plane_init(dev, plane, 1 << index, - &vkms_plane_funcs, - formats, nformats, - NULL, type, NULL); - if (ret) { - kfree(plane); - return ERR_PTR(ret); - } + plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index, + &vkms_plane_funcs, + formats, nformats, + NULL, type, NULL); + if (IS_ERR(plane)) + return plane; - drm_plane_helper_add(plane, funcs); + drm_plane_helper_add(&plane->base, funcs); return plane; } |