From patchwork Sat May 26 15:56:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 920988 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="skk0a2/D"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40tSTD56k6z9s02 for ; Sun, 27 May 2018 01:58:24 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1032138AbeEZP6L (ORCPT ); Sat, 26 May 2018 11:58:11 -0400 Received: from mail-wm0-f67.google.com ([74.125.82.67]:33629 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1031975AbeEZP5q (ORCPT ); Sat, 26 May 2018 11:57:46 -0400 Received: by mail-wm0-f67.google.com with SMTP id x12-v6so36777600wmc.0; Sat, 26 May 2018 08:57:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=pmy6TgggvhXkP0sGw8FmR82nD4PQXyZoe1wKfk7thh4=; b=skk0a2/DO2W+1ugTMG/mJSfblR7TGYWT4OR20/8TsfYSzNYSc7W7fQc4ADxhh6jjWt iJqAC3Thx7D9s9XzT7GM70BSsLE0tPR6D2JM8kAAouSrAHAQrInij0T2SIDjYl/m7Qfb /cI4zv3gsmLETzDgB+pSxOpUEnTJjTaSxL75y7X1mg7CDWhyXB8R3KKcTbJboE0CJqgV mO8v2wI+MyLJhbvZrTtqOziGYiUZaLzNTWO++10W9TJetKOOuWZGjIYhT3l1eAGPDT6C dUZUa1KBp0O3OuhJpjAc2uH5l9lt/OdBgkWnHHNZFKCY5bLg9xt+pdTiOeV5h9IDJOGx 5HCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=pmy6TgggvhXkP0sGw8FmR82nD4PQXyZoe1wKfk7thh4=; b=W8enub6vyvmjoDntxm2PrKhvyzMbC3QNqMf2GYgMS5wx3WHsFWyzoPI/CAsV9yZgGa uCKHbiOqN+Eteq61LRQbfjIwlPjLXHUidSYYx8K6s70V/bsJXirOBz/uL3i/igMvMqLt ouW37C/aPpglCQk8ujClceO0++cinx6hYZ7MvKds4djVWoSULC6O8UfNcUdYmMOdvxnA G2QHn2ibhKgLYELGNQfeKEesmEDHW2UVAILyfwR13DQJ9Fw6MVRNituREMs9iXgBTErU +OKnBEJm0AmDtLzz7AjwbEGtgdY5eAGLZb35DzIXglE3hS3Ucv0pP8b9xkd+nfD+hcK+ 7uhQ== X-Gm-Message-State: ALKqPwewvvmER11Nvk/NFR7UALEi/0VGRbw+Mt3YZVN96dKWbO13wPV8 qLRyEXj6dxH58dE4WnsyVQk= X-Google-Smtp-Source: ADUXVKLzkXWfobsnMYDGepf6V/FgYXPmJf7O7QpHnE6j3z/nGBazriSD2w5mfTDZizOzKA9jkEp49Q== X-Received: by 2002:a2e:89d7:: with SMTP id c23-v6mr4468433ljk.22.1527350264281; Sat, 26 May 2018 08:57:44 -0700 (PDT) Received: from localhost.localdomain (109-252-91-41.nat.spd-mgts.ru. [109.252.91.41]) by smtp.gmail.com with ESMTPSA id k23-v6sm2571010ljh.27.2018.05.26.08.57.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 26 May 2018 08:57:43 -0700 (PDT) From: Dmitry Osipenko To: Laurent Pinchart , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , Thierry Reding , Neil Armstrong , Maxime Ripard , dri-devel@lists.freedesktop.org Cc: linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, Alexandru Gheorghe , Russell King , Ben Skeggs , Sinclair Yeh , Thomas Hellstrom , Jani Nikula , Joonas Lahtinen , Rodrigo Vivi , linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH v2 1/2] drm: Add generic colorkey properties Date: Sat, 26 May 2018 18:56:22 +0300 Message-Id: <20180526155623.12610-2-digetx@gmail.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180526155623.12610-1-digetx@gmail.com> References: <20180526155623.12610-1-digetx@gmail.com> Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Color keying is the action of replacing pixels matching a given color (or range of colors) with transparent pixels in an overlay when performing blitting. Depending on the hardware capabilities, the matching pixel can either become fully transparent or gain adjustment of the pixels component values. Color keying is found in a large number of devices whose capabilities often differ, but they still have enough common features in range to standardize color key properties. This commit adds nine generic DRM plane properties related to the color keying to cover various HW capabilities. This patch is based on the initial work done by Laurent Pinchart, most of credits for this patch goes to him. Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/drm_atomic.c | 36 ++++++ drivers/gpu/drm/drm_blend.c | 229 +++++++++++++++++++++++++++++++++++ include/drm/drm_blend.h | 3 + include/drm/drm_plane.h | 77 ++++++++++++ 4 files changed, 345 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 895741e9cd7d..5b808cb68654 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -799,6 +799,24 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, state->rotation = val; } else if (property == plane->zpos_property) { state->zpos = val; + } else if (property == plane->colorkey.mode_property) { + state->colorkey.mode = val; + } else if (property == plane->colorkey.min_property) { + state->colorkey.min = val; + } else if (property == plane->colorkey.max_property) { + state->colorkey.max = val; + } else if (property == plane->colorkey.format_property) { + state->colorkey.format = val; + } else if (property == plane->colorkey.mask_property) { + state->colorkey.mask = val; + } else if (property == plane->colorkey.inverted_match_property) { + state->colorkey.inverted_match = val; + } else if (property == plane->colorkey.replacement_mask_property) { + state->colorkey.replacement_mask = val; + } else if (property == plane->colorkey.replacement_value_property) { + state->colorkey.replacement_value = val; + } else if (property == plane->colorkey.replacement_format_property) { + state->colorkey.replacement_format = val; } else if (property == plane->color_encoding_property) { state->color_encoding = val; } else if (property == plane->color_range_property) { @@ -864,6 +882,24 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->rotation; } else if (property == plane->zpos_property) { *val = state->zpos; + } else if (property == plane->colorkey.mode_property) { + *val = state->colorkey.mode; + } else if (property == plane->colorkey.min_property) { + *val = state->colorkey.min; + } else if (property == plane->colorkey.max_property) { + *val = state->colorkey.max; + } else if (property == plane->colorkey.format_property) { + *val = state->colorkey.format; + } else if (property == plane->colorkey.mask_property) { + *val = state->colorkey.mask; + } else if (property == plane->colorkey.inverted_match_property) { + *val = state->colorkey.inverted_match; + } else if (property == plane->colorkey.replacement_mask_property) { + *val = state->colorkey.replacement_mask; + } else if (property == plane->colorkey.replacement_value_property) { + *val = state->colorkey.replacement_value; + } else if (property == plane->colorkey.replacement_format_property) { + *val = state->colorkey.replacement_format; } else if (property == plane->color_encoding_property) { *val = state->color_encoding; } else if (property == plane->color_range_property) { diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index a16a74d7e15e..05e5632ce375 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -107,6 +107,11 @@ * planes. Without this property the primary plane is always below the cursor * plane, and ordering between all other planes is undefined. * + * colorkey: + * Color keying is set up with drm_plane_create_colorkey_properties(). + * It adds support for replacing a range of colors with a transparent + * color in the plane. + * * Note that all the property extensions described here apply either to the * plane or the CRTC (e.g. for the background color, which currently is not * exposed and assumed to be black). @@ -448,3 +453,227 @@ int drm_atomic_normalize_zpos(struct drm_device *dev, return 0; } EXPORT_SYMBOL(drm_atomic_normalize_zpos); + +static const char * const plane_colorkey_mode_name[] = { + [DRM_PLANE_COLORKEY_MODE_DISABLED] = "disabled", + [DRM_PLANE_COLORKEY_MODE_SRC] = "src-match-src-replace", + [DRM_PLANE_COLORKEY_MODE_DST] = "dst-match-src-replace", +}; + +/** + * drm_plane_create_colorkey_properties - create colorkey properties + * @plane: drm plane + * @supported_modes: bitmask of supported color keying modes + * + * This function creates the generic color keying properties and attach them to + * the plane to enable color keying control for blending operations. + * + * Color keying is controlled through nine properties: + * + * colorkey.mode: + * The mode is an enumerated property that controls how color keying + * operates. The "disabled" mode that disables color keying and is + * very likely to exist if color keying is supported, it should be the + * default mode. + * + * colorkey.min, colorkey.max: + * These two properties specify the colors that are treated as the color + * key. Pixel whose value is in the [min, max] range is the color key + * matching pixel. The minimum and maximum values are expressed as a + * 64-bit integer in AXYZ16161616 format, where A is the alpha value and + * X, Y and Z correspond to the color components of the colorkey.format. + * In most cases XYZ will be either RGB or YUV. + * + * When a single color key is desired instead of a range, userspace shall + * set the min and max properties to the same value. + * + * Drivers return an error from their plane atomic check if range can't be + * handled. + * + * colorkey.format: + * This property specifies the pixel format for the colorkey.min / max + * properties. The format is given in a form of DRM fourcc code. + * + * Drivers return an error from their plane atomic check if pixel format + * is unsupported. + * + * colorkey.mask: + * This property specifies the pixel components mask. Unmasked pixel + * components are not participating in the matching. This mask value is + * applied to colorkey.min / max values. The mask value is given in a + * form of DRM fourcc code corresponding to the colorkey.format property. + * + * For example: userspace shall set the colorkey.mask to 0x0000ff00 + * to match only the green component if colorkey.format is set to + * DRM_FORMAT_XRGB8888. + * + * Drivers return an error from their plane atomic check if mask value + * can't be handled. + * + * colorkey.inverted-match: + * This property specifies whether the matching min-max range should + * be inverted, i.e. pixels outside of the given color range become + * the color key match. + * + * Drivers return an error from their plane atomic check if inversion + * mode can't be handled. + * + * colorkey.replacement-value: + * This property specifies the color value that replaces pixels matching + * the color key. The value is expressed in AXYZ16161616 format, where A + * is the alpha value and X, Y and Z correspond to the color components + * of the colorkey.replacement-format. + * + * Drivers return an error from their plane atomic check if replacement + * value can't be handled. + * + * colorkey.replacement-format: + * This property specifies the pixel format for the + * colorkey.replacement-value property. The format is given in a form of + * DRM fourcc code. + * + * Drivers return an error from their plane atomic check if replacement + * pixel format is unsupported. + * + * colorkey.replacement-mask: + * This property specifies the pixel components mask that defines + * what components of the colorkey.replacement-value will participate in + * replacement of the pixels color. Unmasked pixel components are not + * participating in the replacement. The mask value is given in a form of + * DRM fourcc code corresponding to the colorkey.replacement-format + * property. + * + * For example: userspace shall set the colorkey.replacement-mask to + * 0x0000ff00 to replace only the green component if + * colorkey.replacement-format is set to DRM_FORMAT_XRGB8888. + * + * Userspace shall set colorkey.replacement-mask to 0 to disable the color + * replacement. In this case matching pixels become transparent. + * + * Drivers return an error from their plane atomic check if replacement + * mask value can't be handled. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_plane_create_colorkey_properties(struct drm_plane *plane, + u32 supported_modes) +{ + struct drm_prop_enum_list modes_list[DRM_PLANE_COLORKEY_MODES_NUM]; + struct drm_property *replacement_format_prop; + struct drm_property *replacement_value_prop; + struct drm_property *replacement_mask_prop; + struct drm_property *inverted_match_prop; + struct drm_property *format_prop; + struct drm_property *mask_prop; + struct drm_property *mode_prop; + struct drm_property *min_prop; + struct drm_property *max_prop; + unsigned int modes_num = 0; + unsigned int i; + + /* at least two modes should be supported */ + if (!supported_modes) + return -EINVAL; + + /* modes are driver-specific, build the list of supported modes */ + for (i = 0; i < DRM_PLANE_COLORKEY_MODES_NUM; i++) { + if (!(supported_modes & BIT(i))) + continue; + + modes_list[modes_num].name = plane_colorkey_mode_name[i]; + modes_list[modes_num].type = i; + modes_num++; + } + + mode_prop = drm_property_create_enum(plane->dev, 0, "colorkey.mode", + modes_list, modes_num); + if (!mode_prop) + return -ENOMEM; + + mask_prop = drm_property_create_range(plane->dev, 0, "colorkey.mask", + 0, U64_MAX); + if (!mask_prop) + goto err_destroy_mode_prop; + + min_prop = drm_property_create_range(plane->dev, 0, "colorkey.min", + 0, U64_MAX); + if (!min_prop) + goto err_destroy_mask_prop; + + max_prop = drm_property_create_range(plane->dev, 0, "colorkey.max", + 0, U64_MAX); + if (!max_prop) + goto err_destroy_min_prop; + + format_prop = drm_property_create_range(plane->dev, 0, + "colorkey.format", + 0, U32_MAX); + if (!format_prop) + goto err_destroy_max_prop; + + inverted_match_prop = drm_property_create_bool(plane->dev, 0, + "colorkey.inverted-match"); + if (!inverted_match_prop) + goto err_destroy_format_prop; + + replacement_mask_prop = drm_property_create_range(plane->dev, 0, + "colorkey.replacement-mask", + 0, U64_MAX); + if (!replacement_mask_prop) + goto err_destroy_inverted_match_prop; + + replacement_value_prop = drm_property_create_range(plane->dev, 0, + "colorkey.replacement-value", + 0, U64_MAX); + if (!replacement_value_prop) + goto err_destroy_replacement_mask_prop; + + replacement_format_prop = drm_property_create_range(plane->dev, 0, + "colorkey.replacement-format", + 0, U64_MAX); + if (!replacement_format_prop) + goto err_destroy_replacement_value_prop; + + drm_object_attach_property(&plane->base, min_prop, 0); + drm_object_attach_property(&plane->base, max_prop, 0); + drm_object_attach_property(&plane->base, mode_prop, 0); + drm_object_attach_property(&plane->base, mask_prop, 0); + drm_object_attach_property(&plane->base, format_prop, 0); + drm_object_attach_property(&plane->base, inverted_match_prop, 0); + drm_object_attach_property(&plane->base, replacement_mask_prop, 0); + drm_object_attach_property(&plane->base, replacement_value_prop, 0); + drm_object_attach_property(&plane->base, replacement_format_prop, 0); + + plane->colorkey.min_property = min_prop; + plane->colorkey.max_property = max_prop; + plane->colorkey.mode_property = mode_prop; + plane->colorkey.mask_property = mask_prop; + plane->colorkey.format_property = format_prop; + plane->colorkey.inverted_match_property = inverted_match_prop; + plane->colorkey.replacement_mask_property = replacement_mask_prop; + plane->colorkey.replacement_value_property = replacement_value_prop; + plane->colorkey.replacement_format_property = replacement_format_prop; + + return 0; + +err_destroy_replacement_value_prop: + drm_property_destroy(plane->dev, replacement_value_prop); +err_destroy_replacement_mask_prop: + drm_property_destroy(plane->dev, replacement_mask_prop); +err_destroy_inverted_match_prop: + drm_property_destroy(plane->dev, inverted_match_prop); +err_destroy_format_prop: + drm_property_destroy(plane->dev, format_prop); +err_destroy_max_prop: + drm_property_destroy(plane->dev, max_prop); +err_destroy_min_prop: + drm_property_destroy(plane->dev, min_prop); +err_destroy_mask_prop: + drm_property_destroy(plane->dev, mask_prop); +err_destroy_mode_prop: + drm_property_destroy(plane->dev, mode_prop); + + return -ENOMEM; +} +EXPORT_SYMBOL(drm_plane_create_colorkey_properties); diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 330c561c4c11..8e80d33b643e 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -52,4 +52,7 @@ int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, unsigned int zpos); int drm_atomic_normalize_zpos(struct drm_device *dev, struct drm_atomic_state *state); + +int drm_plane_create_colorkey_properties(struct drm_plane *plane, + u32 supported_modes); #endif diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 26fa50c2a50e..ff7f5ebe2b79 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -32,6 +32,42 @@ struct drm_crtc; struct drm_printer; struct drm_modeset_acquire_ctx; +/** + * enum drm_plane_colorkey_mode - uapi plane colorkey mode enumeration + */ +enum drm_plane_colorkey_mode { + /** + * @DRM_PLANE_COLORKEY_MODE_DISABLED: + * + * No color matching performed in this mode. This is the default + * common mode. + */ + DRM_PLANE_COLORKEY_MODE_DISABLED, + + /** + * @DRM_PLANE_COLORKEY_MODE_SRC: + * + * In this mode color matching is performed with the pixels of + * the given plane and the matched pixels are fully (or partially) + * replaced with the replacement color or become completely + * transparent. + */ + DRM_PLANE_COLORKEY_MODE_SRC, + + /** + * @DRM_PLANE_COLORKEY_MODE_DST: + * + * In this mode color matching is performed with the pixels of the + * planes z-positioned under the given plane and the pixels of the + * hovering plane that are xy-positioned as the underlying + * color-matched pixels are fully (or partially) replaced with the + * replacement color or become completely transparent. + */ + DRM_PLANE_COLORKEY_MODE_DST, + + DRM_PLANE_COLORKEY_MODES_NUM, +}; + /** * struct drm_plane_state - mutable plane state * @plane: backpointer to the plane @@ -54,6 +90,21 @@ struct drm_modeset_acquire_ctx; * where N is the number of active planes for given crtc. Note that * the driver must set drm_mode_config.normalize_zpos or call * drm_atomic_normalize_zpos() to update this before it can be trusted. + * @colorkey.mode: color key mode + * @colorkey.min: color key range minimum. The value is stored in AXYZ16161616 + * format, where A is the alpha value and X, Y and Z correspond to the + * color components of the plane's pixel format (usually RGB or YUV) + * @colorkey.max: color key range maximum (in AXYZ16161616 format) + * @colorkey.mask: color key mask value (in AXYZ16161616 format) + * @colorkey.format: color key min/max/mask values pixel format (in + * DRM_FORMAT_AXYZ16161616 form) + * @colorkey.inverted_match: color key min-max matching range is inverted + * @colorkey.replacement_mask: color key replacement mask value (in + * AXYZ16161616 format) + * @colorkey.replacement_value: color key replacement value (in + * AXYZ16161616 format) + * @colorkey.replacement_format: color key replacement value / mask + * pixel format (in DRM_FORMAT_AXYZ16161616 form) * @src: clipped source coordinates of the plane (in 16.16) * @dst: clipped destination coordinates of the plane * @state: backpointer to global drm_atomic_state @@ -124,6 +175,19 @@ struct drm_plane_state { unsigned int zpos; unsigned int normalized_zpos; + /* Plane colorkey */ + struct { + enum drm_plane_colorkey_mode mode; + u64 min; + u64 max; + u64 mask; + u32 format; + bool inverted_match; + u64 replacement_mask; + u64 replacement_value; + u32 replacement_format; + } colorkey; + /** * @color_encoding: * @@ -510,6 +574,7 @@ enum drm_plane_type { * @alpha_property: alpha property for this plane * @zpos_property: zpos property for this plane * @rotation_property: rotation property for this plane + * @colorkey: colorkey properties for this plane * @helper_private: mid-layer private data */ struct drm_plane { @@ -587,6 +652,18 @@ struct drm_plane { struct drm_property *zpos_property; struct drm_property *rotation_property; + struct { + struct drm_property *min_property; + struct drm_property *max_property; + struct drm_property *mode_property; + struct drm_property *mask_property; + struct drm_property *format_property; + struct drm_property *inverted_match_property; + struct drm_property *replacement_mask_property; + struct drm_property *replacement_value_property; + struct drm_property *replacement_format_property; + } colorkey; + /** * @color_encoding_property: * From patchwork Sat May 26 15:56:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 920987 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="jjRtZUa8"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40tSSt5pw4z9s02 for ; Sun, 27 May 2018 01:58:06 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1032097AbeEZP5u (ORCPT ); Sat, 26 May 2018 11:57:50 -0400 Received: from mail-wm0-f67.google.com ([74.125.82.67]:37344 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1032050AbeEZP5r (ORCPT ); Sat, 26 May 2018 11:57:47 -0400 Received: by mail-wm0-f67.google.com with SMTP id l1-v6so21892401wmb.2; Sat, 26 May 2018 08:57:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=AfbmA4XXBSErzGN+oVE+PXRmsMaZB7ea0kS9W/9u5Ls=; b=jjRtZUa859xogtK1lh/MvdS2luAD+vXKy9Mq5hbOVKZVy/AIBzkvNXXAQwShtza5E8 7+o5OX4VuCAtTqvwrJm9XVNDM29VnkYwEPyrUr9JoqCW1sTEGij5Dp7qyqG5XCDVwyVP udR4pe5ore4n9E/8Fj4PrXTnNkphElOvcEDGG45Q6bgWQ7ySW0fapZRfaTcLtmBIlr0m vkIFRhKC+sCgdXq/Avw0Gw5eohqvHsuAPVSJBhA8JJRjfbynx8jccBr/e7h/PDToeJ5R R8eWVAuO4DaBY7HNs14ooHhv8WboiDNygr4bJtupauWzlrZ7D6XyeBQHqUT/TAmINXLA ZqYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=AfbmA4XXBSErzGN+oVE+PXRmsMaZB7ea0kS9W/9u5Ls=; b=cRAt710Sbgtd4aonZ4BaM8LbhjDtizqZsENWvEYff3Py5Ar07jsw7kOYbZJt536UvF cQsJneAh/61BGMyhA6Gn0/i6gHcUa+2R3urqdo0jEDnehlTHiZn62f2k+t+ahA8TGzyX 4wBZMuogf4OWFYBU7tJBePpGUClLTSG6SvNCJKXjOkk26w1Fcsej7BWlghOjSSw0PbOi eSHlS0N+r0TUfrJ1zJAIzfRVVP4xSfQbjAQaRa2fRcUsvRsUrBfO8TEMViB2xS8nDw7k tWi1pYsvh4KLEgJaMZafRSbNjxP54wniq0dFYxQMMyGf9zcGAQLTQoiQbZWFthw7CdmW e9CQ== X-Gm-Message-State: ALKqPwe3PHmCV5cJ+teKbHzkt3nLQyU7tC8+Pp32exy3vctRqu/MOaUy C1iSEFpIoGVDTXKouxMcIa8= X-Google-Smtp-Source: AB8JxZpXUdmp1cU1tdzQLnFwhH3zAUYvEjWVGrKAX+rROqTKd+1ZyqLf0Te0C6hcK9NzW76Im0HSgQ== X-Received: by 2002:a2e:93cf:: with SMTP id p15-v6mr4366145ljh.30.1527350265498; Sat, 26 May 2018 08:57:45 -0700 (PDT) Received: from localhost.localdomain (109-252-91-41.nat.spd-mgts.ru. [109.252.91.41]) by smtp.gmail.com with ESMTPSA id k23-v6sm2571010ljh.27.2018.05.26.08.57.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 26 May 2018 08:57:44 -0700 (PDT) From: Dmitry Osipenko To: Laurent Pinchart , =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= , Thierry Reding , Neil Armstrong , Maxime Ripard , dri-devel@lists.freedesktop.org Cc: linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, Alexandru Gheorghe , Russell King , Ben Skeggs , Sinclair Yeh , Thomas Hellstrom , Jani Nikula , Joonas Lahtinen , Rodrigo Vivi , linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH v2 2/2] drm/tegra: plane: Implement generic colorkey property for older Tegra's Date: Sat, 26 May 2018 18:56:23 +0300 Message-Id: <20180526155623.12610-3-digetx@gmail.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180526155623.12610-1-digetx@gmail.com> References: <20180526155623.12610-1-digetx@gmail.com> Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Color keying allows to draw on top of overlapping planes, like for example on top of a video plane. Older Tegra's have a limited color keying capability, such that blending features are reduced when color keying is enabled. In particular dependent weighting isn't possible, meaning that cursors plane can't be displayed properly. In most cases it is more useful to display content on top of video overlay, so sacrificing mouse cursor in the area of three planes intersection with colorkey mismatch is a reasonable tradeoff. This patch implements the generic DRM colorkey property. For the starter a minimal color keying support is implemented, it is enough to provide userspace like Opentegra Xorg driver with ability to support color keying by the XVideo extension. Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/dc.c | 31 +++++++ drivers/gpu/drm/tegra/dc.h | 7 ++ drivers/gpu/drm/tegra/plane.c | 147 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/tegra/plane.h | 1 + 4 files changed, 186 insertions(+) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 31e12a9dfcb8..a5add64e40e2 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -172,6 +172,11 @@ static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane) state = to_tegra_plane_state(plane->base.state); + if (state->ckey_enabled) { + background[0] |= BLEND_COLOR_KEY_0; + background[2] |= BLEND_COLOR_KEY_0; + } + if (state->opaque) { /* * Since custom fix-weight blending isn't utilized and weight @@ -776,6 +781,11 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs); drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255); + if (dc->soc->has_legacy_blending) + drm_plane_create_colorkey_properties(&plane->base, + BIT(DRM_PLANE_COLORKEY_MODE_DISABLED) | + BIT(DRM_PLANE_COLORKEY_MODE_DST)); + return &plane->base; } @@ -1053,6 +1063,11 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs); drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255); + if (dc->soc->has_legacy_blending) + drm_plane_create_colorkey_properties(&plane->base, + BIT(DRM_PLANE_COLORKEY_MODE_DISABLED) | + BIT(DRM_PLANE_COLORKEY_MODE_DST)); + return &plane->base; } @@ -1153,6 +1168,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) @@ -1164,6 +1180,9 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) copy->div = state->div; copy->planes = state->planes; + for (i = 0; i < 2; i++) + copy->ckey[i] = state->ckey[i]; + return ©->base; } @@ -1893,6 +1912,18 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, struct tegra_dc *dc = to_tegra_dc(crtc); u32 value; + if (dc->soc->has_legacy_blending) { + tegra_dc_writel(dc, + state->ckey[0].lower, DC_DISP_COLOR_KEY0_LOWER); + tegra_dc_writel(dc, + state->ckey[0].upper, DC_DISP_COLOR_KEY0_UPPER); + + tegra_dc_writel(dc, + state->ckey[1].lower, DC_DISP_COLOR_KEY1_LOWER); + tegra_dc_writel(dc, + state->ckey[1].upper, DC_DISP_COLOR_KEY1_UPPER); + } + value = state->planes << 8 | GENERAL_UPDATE; tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index e96f582ca692..8209cb7d598a 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -18,6 +18,11 @@ struct tegra_output; +struct tegra_dc_color_key_state { + u32 lower; + u32 upper; +}; + struct tegra_dc_state { struct drm_crtc_state base; @@ -26,6 +31,8 @@ struct tegra_dc_state { unsigned int div; u32 planes; + + struct tegra_dc_color_key_state ckey[2]; }; static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state) diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 0406c2ef432c..ba08b66d2499 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -57,6 +57,7 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane) copy->format = state->format; copy->swap = state->swap; copy->opaque = state->opaque; + copy->ckey_enabled = state->ckey_enabled; for (i = 0; i < 2; i++) copy->blending[i] = state->blending[i]; @@ -464,6 +465,148 @@ static int tegra_plane_setup_transparency(struct tegra_plane *tegra, return 0; } +static int tegra_plane_setup_colorkey(struct tegra_plane *tegra, + struct tegra_plane_state *tegra_state) +{ + struct drm_plane_state *state; + struct drm_plane_state *new_plane; + struct drm_plane_state *old_plane; + struct drm_crtc_state *crtc_state; + struct drm_crtc_state *new_crtc; + struct tegra_dc_state *dc_state; + struct drm_plane *plane; + unsigned int mode; + u32 min, max; + u32 format; + + /* at first check if plane has the colorkey property attached */ + if (!tegra->base.colorkey.mode_property) + return 0; + + format = tegra_state->base.colorkey.format; + mode = tegra_state->base.colorkey.mode; + min = tegra_state->base.colorkey.min; + max = tegra_state->base.colorkey.max; + + state = &tegra_state->base; + old_plane = drm_atomic_get_old_plane_state(state->state, &tegra->base); + + /* no need to proceed if color keying is (and was) disabled */ + if (mode == DRM_PLANE_COLORKEY_MODE_DISABLED && + (!old_plane || old_plane->colorkey.mode == mode)) + return 0; + + /* + * Currently color keying implemented only for the middle plane + * to simplify things, hence check the ordering. + */ + if (state->normalized_zpos != 1) { + if (mode == DRM_PLANE_COLORKEY_MODE_DISABLED) + goto update_planes; + + return -EINVAL; + } + + /* validate the color key mode */ + if (mode != DRM_PLANE_COLORKEY_MODE_DST) + return -EINVAL; + + /* validate the color key mask */ + if ((state->colorkey.mask & 0xFFFFFF) != 0xFFFFFF) + return -EINVAL; + + /* validate the replacement mask */ + if (state->colorkey.replacement_mask != 0) + return -EINVAL; + + /* validate the color key inversion mode */ + if (state->colorkey.inverted_match != true) + return -EINVAL; + + /* + * There is no need to proceed, adding CRTC and other planes to + * the atomic update, if color key value is unchanged. + */ + if (old_plane && + old_plane->colorkey.mode != DRM_PLANE_COLORKEY_MODE_DISABLED && + old_plane->colorkey.format == format && + old_plane->colorkey.min == min && + old_plane->colorkey.max == max) + return 0; + + /* validate pixel format and convert color key value if necessary */ + switch (format) { + case DRM_FORMAT_XBGR8888: +#define XBGR8888_to_XRGB8888(v) \ + ((((v) & 0xFF0000) >> 16) | ((v) & 0x00FF00) | (((v) & 0x0000FF) << 16)) + + min = XBGR8888_to_XRGB8888(min); + max = XBGR8888_to_XRGB8888(max); + break; + + case DRM_FORMAT_XRGB8888: + break; + + default: + return -EINVAL; + } + + /* + * Tegra's HW stores the color key values within CRTC, hence adjust + * planes CRTC atomic state. + */ + crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + new_crtc = drm_atomic_get_new_crtc_state(state->state, state->crtc); + if (IS_ERR(new_crtc)) + return PTR_ERR(new_crtc); + + dc_state = to_dc_state(new_crtc); + + /* update CRTC's color key state */ + dc_state->ckey[0].lower = min; + dc_state->ckey[0].upper = max; + +update_planes: + /* + * Currently the only supported color keying mode is + * "dst-match-src-replace", i.e. in our case the actual matching + * is performed by the underlying plane. Hence setup the color + * matching for that plane and update other planes by including + * them into the atomic update. + */ + drm_for_each_plane(plane, tegra->base.dev) { + struct tegra_plane *p = to_tegra_plane(plane); + + /* skip this plane and planes on different CRTCs */ + if (p == tegra || p->dc != tegra->dc) + continue; + + state = drm_atomic_get_plane_state(state->state, plane); + if (IS_ERR(state)) + return PTR_ERR(state); + + new_plane = drm_atomic_get_new_plane_state(state->state, plane); + tegra_state = to_tegra_plane_state(new_plane); + + /* skip planes hovering this plane */ + if (new_plane->normalized_zpos > 1) { + tegra_state->ckey_enabled = false; + continue; + } + + /* update planes color keying state */ + if (mode == DRM_PLANE_COLORKEY_MODE_DISABLED) + tegra_state->ckey_enabled = false; + else + tegra_state->ckey_enabled = true; + } + + return 0; +} + int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, struct tegra_plane_state *state) { @@ -477,5 +620,9 @@ int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, if (err < 0) return err; + err = tegra_plane_setup_colorkey(tegra, state); + if (err < 0) + return err; + return 0; } diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h index 7360ddfafee8..617f57d98135 100644 --- a/drivers/gpu/drm/tegra/plane.h +++ b/drivers/gpu/drm/tegra/plane.h @@ -49,6 +49,7 @@ struct tegra_plane_state { /* used for legacy blending support only */ struct tegra_plane_legacy_blending_state blending[2]; bool opaque; + bool ckey_enabled; }; static inline struct tegra_plane_state *