Received: by 2002:a05:7412:bbc7:b0:fc:a2b0:25d7 with SMTP id kh7csp327872rdb; Thu, 1 Feb 2024 09:33:05 -0800 (PST) X-Google-Smtp-Source: AGHT+IG0U26vH7bSWgDiVnvieDHatFGxg+qztzqghPchDJ+y83xRDjPBKutovtzJ6v62UnP6uARe X-Received: by 2002:a17:906:2dd2:b0:a36:e12a:1019 with SMTP id h18-20020a1709062dd200b00a36e12a1019mr933662eji.47.1706808785024; Thu, 01 Feb 2024 09:33:05 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706808785; cv=pass; d=google.com; s=arc-20160816; b=i0lEnCrFtCQ37g3ff6OpFLBJp+G0QWVsMxK4wPZ8BgDzEflGL1nd1Q2KoxOGAlyV9n oH5DrRma63I1Aew/sjWZcwTbojwtI78JM9OdtzDrGgPz6Ulzl2ABKEoj3L6Lp6L95aud yqvbNChbdFQa+I1vCmh3d366yGUM1zPDJE1slT6+BpTRmBS07MfSfyq+ECpTj1yy5Sc3 oS2A+n/mraR+DqLI45Zv0MMN9RLe8hSHA/19td/pRhaaSaOr6sjijZF5XK8t2ksd4dVU sCWfTsKyyXyYKQYt6Z8VbsYJ0FXMB+8JJTL0U6k+wEhPt6GZW96AfESd0gzMwpMcJGs2 dzyg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :subject:date:from:dkim-signature; bh=w3zxaDJx0ige/xrGelusoCYKzSbgA6rlzzgnKpQREhA=; fh=+rAKyUgBUUmBg+vPLPg06nj67KN2ai9ptuKF3VNbIQY=; b=xiO1lWNysErM9twZmDLWa29A8RPK7lBO/lrfWA+gn7YgCHXWeL2CnRt6PAxKLhhCO3 eO41jl/hi935Hc8sT74v9IrtJVOfSzsOcJ/yumrZLZ6mHlN3FTg3Fvz6GjMmnvYsmqTX 6nS8qmlEGQk0Fp+KXmbFA9M9//on0LCDuGFscWM6OPP+0jMuNIssxjxy8bXvn1VPvB6Z 8Z3ORJcCLgHkb9LZT8GRAGSQGM6Ds5GcFpRdvFQcfRFh0OwZUbpk7NbNPgkLU3VNZ44k AQGYpx1foroNo4a9zx4OhABEbQYmExygtZYwGTtEXae2ejQptPV3TsgMJ1Aa37EIIhQY Qt1g==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@bootlin.com header.s=gm1 header.b=GKaN44fN; arc=pass (i=1 spf=pass spfdomain=bootlin.com dkim=pass dkdomain=bootlin.com dmarc=pass fromdomain=bootlin.com); spf=pass (google.com: domain of linux-kernel+bounces-48596-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-48596-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bootlin.com X-Forwarded-Encrypted: i=1; AJvYcCW2F1ZkFvPbubQRVmv8a/B9illRzr7pFkBwg6QmsoTzScWVGHi4rWXwqhyaVWwH288yxTncT8PKtvx/khGNmMWJNrH+hXClTfgjV9q2KA== Return-Path: Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id a3-20020a17090680c300b00a358b7843c5si8301ejx.113.2024.02.01.09.33.04 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Feb 2024 09:33:05 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-48596-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@bootlin.com header.s=gm1 header.b=GKaN44fN; arc=pass (i=1 spf=pass spfdomain=bootlin.com dkim=pass dkdomain=bootlin.com dmarc=pass fromdomain=bootlin.com); spf=pass (google.com: domain of linux-kernel+bounces-48596-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-48596-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bootlin.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 507021F2A2CF for ; Thu, 1 Feb 2024 17:33:04 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A51F15C052; Thu, 1 Feb 2024 17:32:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="GKaN44fN" Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8401F84027 for ; Thu, 1 Feb 2024 17:32:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.197 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706808743; cv=none; b=lr7MdsXgs1fhyp8Askak3iRU/mwYCDAPQPOpDfv8/5warS/CMLoDg9kHICScsnzjyRmQyaBqG6dC/0H1iateTspboPbIRO+oVIs6v9L2zeR+57qDJV+CSQASlSSjl3JSbKI/Tn7ktXWetAaWi0Yup78l0xGUvkuBxc0XDAx4oA8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706808743; c=relaxed/simple; bh=Lyvp37yqP/RKGqGObubMXl4szy7JAwmzZhexN7cT3RY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oaVqZYSmw+FeTSitJg3dT2U8yRATvn+Fmv9v+6ePOVhCzya80PZ1PMOJYAZE1akL3xsjuJc4P00BYjZxNchgdDBSgrR6f1/CxZ8fL83w0Lag4H3eZmKsJllivM0md+/UBXSMqOu2auhyIwj37FucGdOph+UgKwUGQyTbsLg9t3w= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=GKaN44fN; arc=none smtp.client-ip=217.70.183.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Received: by mail.gandi.net (Postfix) with ESMTPSA id 180691C000B; Thu, 1 Feb 2024 17:32:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1706808732; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=w3zxaDJx0ige/xrGelusoCYKzSbgA6rlzzgnKpQREhA=; b=GKaN44fNIPV1Q3EWB45XLQBsfN24J28ISFD43uu+ngs+is/9nKz+gcL+1fvcdGimGjJHwY f/UsdfzOf+HQwMHT2nROXP84j+eZcyYo2L/Y/m1yi6FfkmQ1jsJ/M0QSlIbaRMYBsqO9Kp Z1BYsAAcy+XDteXWe1/09Lff6xN9XCYBLoag+Wyz23oKmh6d0aiWHqR2Uywk2fRVCIJaL/ EcAB6iT5AzO45MJYH9SX2ieAfuXRJbD3QKo9AUnux4OayeYnu1zmhv98WKMaLqVatgSlaG IoHVbN8QTQtYOuoN0nVsWk6WxyhJGpVQBOFpQ7XAK6o0xi0mzyk6Tzy0XkvMRQ== From: Louis Chauvet Date: Thu, 01 Feb 2024 18:31:32 +0100 Subject: [PATCH 2/2] drm/vkms: Use a simpler composition function Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20240201-yuv-v1-2-3ca376f27632@bootlin.com> References: <20240201-yuv-v1-0-3ca376f27632@bootlin.com> In-Reply-To: <20240201-yuv-v1-0-3ca376f27632@bootlin.com> To: Rodrigo Siqueira , Melissa Wen , =?utf-8?q?Ma=C3=ADra_Canal?= , Haneen Mohammed , Daniel Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , marcheu@google.com, seanpaul@google.com, nicolejadeyee@google.com Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Louis Chauvet , thomas.petazzoni@bootlin.com, miquel.raynal@bootlin.com X-Mailer: b4 0.12.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=25546; i=louis.chauvet@bootlin.com; h=from:subject:message-id; bh=Lyvp37yqP/RKGqGObubMXl4szy7JAwmzZhexN7cT3RY=; b=owEBbQKS/ZANAwAIASCtLsZbECziAcsmYgBlu9WZN+h0hVSORpgCsnNgPV3oNEnfy78OJ2TZx6Uk FWszM9OJAjMEAAEIAB0WIQRPj7g/vng8MQxQWQQgrS7GWxAs4gUCZbvVmQAKCRAgrS7GWxAs4keKD/ 9iYIHu+QsSQBi1SNKIGSIvJrvqhGO+pJqNubzaebjCgoxnY9DxjzaCqS9Isc4Cw+dKgJoQPKOxYmjZ f7zZye/8+AiFpNd8lGgmAGkzffeNVw9TciajNLlOaYw/tRca/g5d9NChLh9WsJkTern7wri0/jMLcy gnKV5lsEheLhkyDzdafRPlDxXBubzariATSOKnAY1yPkGMQ9Ah0spU00TROkifkMsYi5nc5h2Y5NoB sBj+P3svpie6urXSyckKnMZzV+8VjfHn1MH36Vd2ZW4X7fgM3WCSVgTEgYT7Pi1Kvt4ZIu4udcwlz8 gx/XIu4pACUN/Dysc5L18jlYa5GrbLxbfubPQshVV6BYbm4VFdBXWzDp1SYu7zoZssmQBO3MQAnLW8 rBbB95fPy468pAUtw9Af3XgtVJyutQLcAj2DsbIxih6y7yZ4Awctb0rQyviziqB49nWUApZtXs9+6T tPlKL9BL5NMMHJ//j1UjxcbDH7BUTZ1GYfnIJjxllJi1quq5yGS/Sd8A7v2clBHZ0qe52/LDUe1x2D po/wDiUh/te4YwkpYza+wI2ba9Wy6nBW2SIsQObE85ngYNU7dVN4m8C2cPKCB+pENxVKRSBjZcQQAq wtu63wPmIpTNLu7XZSn37O1evYyQ8pkZKJR6sk+VcbEXpailezRMZFZf37Rw== X-Developer-Key: i=louis.chauvet@bootlin.com; a=openpgp; fpr=8B7104AE9A272D6693F527F2EC1883F55E0B40A5 X-GND-Sasl: louis.chauvet@bootlin.com Change the composition algorithm to iterate over pixels instead of lines. It allows a simpler management of rotation and pixel access for complex formats. This new algorithm allows read_pixel function to have access to x/y coordinates and make it possible to read the correct thing in a block when block_w and block_h are not 1. The iteration pixel-by-pixel in the same method also allows a simpler management of rotation with drm_rect_* helpers. This way it's not needed anymore to have misterious switch-case distributed in multiple places. This patch is tested with IGT: - kms_plane@pixel_format - kms_plane@pixel-format-source-clamping - kms_plane@plane-position-covered - kms_plane@plane-position-hole - kms_plane@plane-position-hole-dpms - kms_plane@plane-panning-top-left - kms_plane@plane-panning-bottom-right - kms_plane@test-odd-size-with-yuv - See [1] - kms_cursor_crc@cursor-size-change - kms_cursor_crc@cursor-alpha-opaque - kms_cursor_crc@cursor-alpha-transparent - kms_cursor_crc@cursor-dpms - kms_cursor_crc@cursor-onscreen-* - kms_cursor_crc@cursor-offscreen-* - kms_cursor_crc@cursor-sliding-* - kms_cursor_crc@cursor-random-* - kms_cursor_crc@cursor-rapid-movement-* - FAIL, but with Overflow of CRC buffer - kms_rotation_crc@primary-rotation-* - See [1] - kms_rotation_crc@sprite-rotation-* - See [1] - kms_rotation_crc@cursor-rotation-* - See [1] - kms_rotation_crc@sprite-rotation-90-pos-100-0 - See [1] - kms_rotation_crc@multiplane-rotation - See [1] - kms_rotation_crc@multiplane-rotation-cropping-* - See [1] [1]: https://lore.kernel.org/igt-dev/20240201-kms_tests-v1-0-bc34c5d28b3f@bootlin.com/T/#t Signed-off-by: Louis Chauvet --- drivers/gpu/drm/vkms/vkms_composer.c | 97 +++++++++----- drivers/gpu/drm/vkms/vkms_drv.h | 21 ++- drivers/gpu/drm/vkms/vkms_formats.c | 250 ++++++++++++++++++----------------- drivers/gpu/drm/vkms/vkms_plane.c | 13 +- 4 files changed, 221 insertions(+), 160 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 3c99fb8b54e2..4c5439209907 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -43,7 +43,7 @@ static void pre_mul_alpha_blend(struct vkms_frame_info *frame_info, { int x_dst = frame_info->dst.x1; struct pixel_argb_u16 *out = output_buffer->pixels + x_dst; - struct pixel_argb_u16 *in = stage_buffer->pixels; + struct pixel_argb_u16 *in = stage_buffer->pixels + x_dst; int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), stage_buffer->n_pixels); @@ -55,33 +55,6 @@ static void pre_mul_alpha_blend(struct vkms_frame_info *frame_info, } } -static int get_y_pos(struct vkms_frame_info *frame_info, int y) -{ - if (frame_info->rotation & DRM_MODE_REFLECT_Y) - return drm_rect_height(&frame_info->rotated) - y - 1; - - switch (frame_info->rotation & DRM_MODE_ROTATE_MASK) { - case DRM_MODE_ROTATE_90: - return frame_info->rotated.x2 - y - 1; - case DRM_MODE_ROTATE_270: - return y + frame_info->rotated.x1; - default: - return y; - } -} - -static bool check_limit(struct vkms_frame_info *frame_info, int pos) -{ - if (drm_rotation_90_or_270(frame_info->rotation)) { - if (pos >= 0 && pos < drm_rect_width(&frame_info->rotated)) - return true; - } else { - if (pos >= frame_info->rotated.y1 && pos < frame_info->rotated.y2) - return true; - } - - return false; -} static void fill_background(const struct pixel_argb_u16 *background_color, struct line_buffer *output_buffer) @@ -182,18 +155,74 @@ static void blend(struct vkms_writeback_job *wb, const struct pixel_argb_u16 background_color = { .a = 0xffff }; size_t crtc_y_limit = crtc_state->base.crtc->mode.vdisplay; + size_t crtc_x_limit = crtc_state->base.crtc->mode.hdisplay; + /* + * Iterating over each pixel to simplify the handling of rotations by using drm_rect_* + * helpers. + * Iteration per pixel also allosw a simple management of complex pixel formats. + * + * If needed, this triple loop might be a good place for optimizations. + */ for (size_t y = 0; y < crtc_y_limit; y++) { fill_background(&background_color, output_buffer); /* The active planes are composed associatively in z-order. */ for (size_t i = 0; i < n_active_planes; i++) { - y_pos = get_y_pos(plane[i]->frame_info, y); - - if (!check_limit(plane[i]->frame_info, y_pos)) - continue; - - vkms_compose_row(stage_buffer, plane[i], y_pos); + for (size_t x = 0; x < crtc_x_limit; x++) { + /* + * @x and @y are the coordinate in the output crtc. + * @dst_px is used to easily check if a pixel must be blended. + * @src_px is used to handle rotation. Just before blending, it + * will contain the coordinate of the wanted source pixel in + * the source buffer. + * @tmp_src is the conversion of src rectangle to integer. + */ + + struct drm_rect dst_px = DRM_RECT_INIT(x, y, 1, 1); + struct drm_rect src_px = DRM_RECT_INIT(x, y, 1, 1); + struct drm_rect tmp_src; + + drm_rect_fp_to_int(&tmp_src, &plane[i]->frame_info->src); + + /* + * Check that dst_px is inside the plane output + * Note: This is destructive for dst_px, if you need this + * rectangle you have to do a copy + */ + if (!drm_rect_intersect(&dst_px, &plane[i]->frame_info->dst)) + continue; + + /* + * Transform the coordinate x/y from the crtc to coordinates into + * coordinates for the src buffer. + * + * First step is to cancel the offset of the dst buffer. + * Then t will have to invert the rotation. This assumes that + * dst = drm_rect_rotate(src, rotation) (dst and src have the + * space size, but can be rotated). + * And then, apply the offset of the source rectangle to the + * coordinate. + */ + drm_rect_translate(&src_px, -plane[i]->frame_info->dst.x1, + -plane[i]->frame_info->dst.y1); + drm_rect_rotate_inv(&src_px, + drm_rect_width(&tmp_src), + drm_rect_height(&tmp_src), + plane[i]->frame_info->rotation); + drm_rect_translate(&src_px, tmp_src.x1, tmp_src.y1); + + /* + * Now, as the src_px contains the correct position, we can use + * it to convert the pixel color + */ + plane[i]->pixel_read(plane[i]->frame_info, + src_px.x1, + src_px.y1, + &stage_buffer->pixels[x], + plane[i]->base.base.color_encoding, + plane[i]->base.base.color_range); + } pre_mul_alpha_blend(plane[i]->frame_info, stage_buffer, output_buffer); } diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index cb20bab26cae..ba3c063adc5f 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -25,10 +25,20 @@ #define VKMS_LUT_SIZE 256 +/** + * struct vkms_frame_info - structure to store the state of a frame + * + * @fb: backing drm framebuffer + * @src: source rectangle of this frame in the source framebuffer + * @dst: destination rectangle in the crtc buffer + * @map: see drm_shadow_plane_state@data + * @rotation: rotation applied to the source. + * + * @src and @dst should have the same size modulo the rotation. + */ struct vkms_frame_info { struct drm_framebuffer *fb; struct drm_rect src, dst; - struct drm_rect rotated; struct iosys_map map[DRM_FORMAT_MAX_PLANES]; unsigned int rotation; }; @@ -51,14 +61,15 @@ struct vkms_writeback_job { /** * typedef pixel_read_t - These functions are used to read the pixels in the source frame, convert * them to argb16 and write them to out_pixel. - * It assumes that src_pixels point to a valid pixel (not a block, or a block of 1x1 pixel) * - * @src_pixels: Source pointer to a pixel + * @frame_info: Frame used as source for the pixel value + * @x: X (width) coordinate in the source buffer + * @y: Y (height) coordinate in the source buffer * @out_pixel: Pointer where to write the pixel value * @encoding: Color encoding to use (mainly used for YUV formats) * @range: Color range to use (mainly used for YUV formats) */ -typedef void (*pixel_read_t)(u8 **src_pixels, int y, +typedef void (*pixel_read_t)(struct vkms_frame_info *frame_info, int x, int y, struct pixel_argb_u16 *out_pixel, enum drm_color_encoding enconding, enum drm_color_range range); @@ -66,6 +77,8 @@ typedef void (*pixel_read_t)(u8 **src_pixels, int y, * vkms_plane_state - Driver specific plane state * @base: base plane state * @frame_info: data required for composing computation + * @pixel_read: function to read a pixel in this plane. The creator of a vkms_plane_state must + * ensure that this pointer is valid */ struct vkms_plane_state { struct drm_shadow_plane_state base; diff --git a/drivers/gpu/drm/vkms/vkms_formats.c b/drivers/gpu/drm/vkms/vkms_formats.c index c6376db58d38..8ff85ffda94f 100644 --- a/drivers/gpu/drm/vkms/vkms_formats.c +++ b/drivers/gpu/drm/vkms/vkms_formats.c @@ -11,79 +11,88 @@ #include "vkms_formats.h" -static size_t pixel_offset(const struct vkms_frame_info *frame_info, int x, int y, size_t index) + +/** + * packed_pixels_offset() - Get the offset of the block containing the pixel at coordinates x/y + * + * @frame_info: Buffer metadata + * @x: The x coordinate of the wanted pixel in the buffer + * @y: The y coordinate of the wanted pixel in the buffer + * @plane: The index of the plane to use + * + * The caller must be aware that this offset is not always a pointer to a pixel. If individual + * pixel values are needed, they have to be extracted from the block. + */ +static size_t packed_pixels_offset(const struct vkms_frame_info *frame_info, int x, int y, size_t plane) { struct drm_framebuffer *fb = frame_info->fb; - - return fb->offsets[index] + (y * fb->pitches[index]) - + (x * fb->format->cpp[index]); + const struct drm_format_info *format = frame_info->fb->format; + /* Directly using x and y to multiply pitches and format->ccp is not sufficient because + * in some formats a block can represent multiple pixels. + * + * Dividing x and y by the block size allows to extract the correct offset of the block + * containing the pixel. + */ + return fb->offsets[plane] + + (y / drm_format_info_block_width(format, plane)) * fb->pitches[plane] + + (x / drm_format_info_block_height(format, plane)) * format->char_per_block[plane]; } /* - * packed_pixels_addr - Get the pointer to pixel of a given pair of coordinates + * packed_pixels_addr - Get the pointer to the block containing the pixel at the given coordinate * * @frame_info: Buffer metadata - * @x: The x(width) coordinate of the 2D buffer - * @y: The y(Heigth) coordinate of the 2D buffer + * @x: The x(width) coordinate inside the 2D buffer + * @y: The y(Heigth) coordinate inside the 2D buffer * @index: The index of the plane on the 2D buffer * - * Takes the information stored in the frame_info, a pair of coordinates, and - * returns the address of the first color channel on the desired index. The - * format's specific subsample is applied. + * Takes the information stored in the frame_info, a pair of coordinates, and returns the address + * of the block containing this pixel. + * The caller must be aware that this pointer is sometimes not directly a pixel, it needs some + * additional work to extract pixel color from this block. */ static void *packed_pixels_addr(const struct vkms_frame_info *frame_info, int x, int y, size_t index) { - int vsub = index == 0 ? 1 : frame_info->fb->format->vsub; - int hsub = index == 0 ? 1 : frame_info->fb->format->hsub; - size_t offset = pixel_offset(frame_info, x / hsub, y / vsub, index); - - return (u8 *)frame_info->map[0].vaddr + offset; + return (u8 *)frame_info->map[0].vaddr + packed_pixels_offset(frame_info, x, y, index); } -static void *get_packed_src_addr(const struct vkms_frame_info *frame_info, int y, size_t index) +static void ARGB8888_to_argb_u16(struct vkms_frame_info *frame_info, int x, int y, + struct pixel_argb_u16 *out_pixel, enum drm_color_encoding encoding, + enum drm_color_range range) { - int x_src = frame_info->src.x1 >> 16; - int y_src = y - frame_info->rotated.y1 + (frame_info->src.y1 >> 16); - - return packed_pixels_addr(frame_info, x_src, y_src, index); -} + u8 *src_pixel = packed_pixels_addr(frame_info, x, y, 0); -static int get_x_position(const struct vkms_frame_info *frame_info, int limit, int x) -{ - if (frame_info->rotation & (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270)) - return limit - x - 1; - return x; -} - -static void ARGB8888_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, - enum drm_color_encoding encoding, enum drm_color_range range) -{ /* * The 257 is the "conversion ratio". This number is obtained by the * (2^16 - 1) / (2^8 - 1) division. Which, in this case, tries to get * the best color value in a pixel format with more possibilities. * A similar idea applies to others RGB color conversions. */ - out_pixel->a = (u16)src_pixels[0][3] * 257; - out_pixel->r = (u16)src_pixels[0][2] * 257; - out_pixel->g = (u16)src_pixels[0][1] * 257; - out_pixel->b = (u16)src_pixels[0][0] * 257; + out_pixel->a = (u16)src_pixel[3] * 257; + out_pixel->r = (u16)src_pixel[2] * 257; + out_pixel->g = (u16)src_pixel[1] * 257; + out_pixel->b = (u16)src_pixel[0] * 257; } -static void XRGB8888_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, - enum drm_color_encoding encoding, enum drm_color_range range) +static void XRGB8888_to_argb_u16(struct vkms_frame_info *frame_info, int x, int y, + struct pixel_argb_u16 *out_pixel, enum drm_color_encoding encoding, + enum drm_color_range range) { + u8 *src_pixel = packed_pixels_addr(frame_info, x, y, 0); out_pixel->a = (u16)0xffff; - out_pixel->r = (u16)src_pixels[0][2] * 257; - out_pixel->g = (u16)src_pixels[0][1] * 257; - out_pixel->b = (u16)src_pixels[0][0] * 257; + out_pixel->r = (u16)src_pixel[2] * 257; + out_pixel->g = (u16)src_pixel[1] * 257; + out_pixel->b = (u16)src_pixel[0] * 257; } -static void ARGB16161616_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, - enum drm_color_encoding encoding, enum drm_color_range range) +static void ARGB16161616_to_argb_u16(struct vkms_frame_info *frame_info, int x, int y, + struct pixel_argb_u16 *out_pixel, + enum drm_color_encoding encoding, + enum drm_color_range range) { - u16 *pixels = (u16 *)src_pixels[0]; + u8 *src_pixel = packed_pixels_addr(frame_info, x, y, 0); + u16 *pixels = (u16 *)src_pixel; out_pixel->a = le16_to_cpu(pixels[3]); out_pixel->r = le16_to_cpu(pixels[2]); @@ -91,10 +100,13 @@ static void ARGB16161616_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out out_pixel->b = le16_to_cpu(pixels[0]); } -static void XRGB16161616_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, - enum drm_color_encoding encoding, enum drm_color_range range) +static void XRGB16161616_to_argb_u16(struct vkms_frame_info *frame_info, int x, int y, + struct pixel_argb_u16 *out_pixel, + enum drm_color_encoding encoding, + enum drm_color_range range) { - u16 *pixels = (u16 *)src_pixels[0]; + u8 *src_pixel = packed_pixels_addr(frame_info, x, y, 0); + u16 *pixels = (u16 *)src_pixel; out_pixel->a = (u16)0xffff; out_pixel->r = le16_to_cpu(pixels[2]); @@ -102,10 +114,12 @@ static void XRGB16161616_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out out_pixel->b = le16_to_cpu(pixels[0]); } -static void RGB565_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, - enum drm_color_encoding encoding, enum drm_color_range range) +static void RGB565_to_argb_u16(struct vkms_frame_info *frame_info, int x, int y, + struct pixel_argb_u16 *out_pixel, enum drm_color_encoding encoding, + enum drm_color_range range) { - u16 *pixels = (u16 *)src_pixels[0]; + u8 *src_pixel = packed_pixels_addr(frame_info, x, y, 0); + u16 *pixels = (u16 *)src_pixel; s64 fp_rb_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(31)); s64 fp_g_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(63)); @@ -121,12 +135,19 @@ static void RGB565_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel out_pixel->b = drm_fixp2int_round(drm_fixp_mul(fp_b, fp_rb_ratio)); } +/** + * ycbcr2rgb() - helper to convert ycbcr 8 bits to rbg 16 bits + * + * @m: conversion matrix to use + * @y, @cb, @cr: component of the ycbcr pixel + * @r, @g, @b: pointers to write the rbg pixel + */ static void ycbcr2rgb(const s16 m[3][3], u8 y, u8 cb, u8 cr, u8 y_offset, u8 *r, u8 *g, u8 *b) { s32 y_16, cb_16, cr_16; s32 r_16, g_16, b_16; - y_16 = y - y_offset; + y_16 = y - y_offset; cb_16 = cb - 128; cr_16 = cr - 128; @@ -139,6 +160,14 @@ static void ycbcr2rgb(const s16 m[3][3], u8 y, u8 cb, u8 cr, u8 y_offset, u8 *r, *b = clamp(b_16, 0, 0xffff) >> 8; } +/** + * yuv_u8_to_argb_u16() - helper to convert yuv 8 bits to argb 16 bits + * + * @argb_u16: pointer to write the converted pixel + * @yuv_u8: pointer to the source yuv pixel + * @encoding: encoding to use + * @range: range to use + */ VISIBLE_IF_KUNIT void yuv_u8_to_argb_u16(struct pixel_argb_u16 *argb_u16, const struct pixel_yuv_u8 *yuv_u8, enum drm_color_encoding encoding, @@ -205,104 +234,89 @@ VISIBLE_IF_KUNIT void yuv_u8_to_argb_u16(struct pixel_argb_u16 *argb_u16, } EXPORT_SYMBOL_IF_KUNIT(yuv_u8_to_argb_u16); -static void semi_planar_yuv_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, +static void semi_planar_yuv_to_argb_u16(struct vkms_frame_info *frame_info, int x, + int y, struct pixel_argb_u16 *out_pixel, enum drm_color_encoding encoding, enum drm_color_range range) { struct pixel_yuv_u8 yuv_u8; - yuv_u8.y = src_pixels[0][0]; - yuv_u8.u = src_pixels[1][0]; - yuv_u8.v = src_pixels[1][1]; + /* Subsampling must be applied for semi-planar yuv formats */ + int vsub = frame_info->fb->format->vsub; + int hsub = frame_info->fb->format->hsub; + + u8 *src_y = packed_pixels_addr(frame_info, x, y, 0); + u8 *src_uv = packed_pixels_addr(frame_info, x / hsub, y / vsub, 1); + + yuv_u8.y = src_y[0]; + yuv_u8.u = src_uv[0]; + yuv_u8.v = src_uv[1]; yuv_u8_to_argb_u16(out_pixel, &yuv_u8, encoding, range); } -static void semi_planar_yvu_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, +static void semi_planar_yvu_to_argb_u16(struct vkms_frame_info *frame_info, int x, + int y, struct pixel_argb_u16 *out_pixel, enum drm_color_encoding encoding, enum drm_color_range range) { struct pixel_yuv_u8 yuv_u8; - yuv_u8.y = src_pixels[0][0]; - yuv_u8.v = src_pixels[1][0]; - yuv_u8.u = src_pixels[1][1]; + /* Subsampling must be applied for semi-planar yuv formats */ + int vsub = frame_info->fb->format->vsub ? frame_info->fb->format->vsub : 1; + int hsub = frame_info->fb->format->hsub ? frame_info->fb->format->hsub : 1; + u8 *src_y = packed_pixels_addr(frame_info, x, y, 0); + u8 *src_vu = packed_pixels_addr(frame_info, x / hsub, y / vsub, 1); + + yuv_u8.y = src_y[0]; + yuv_u8.v = src_vu[0]; + yuv_u8.u = src_vu[1]; yuv_u8_to_argb_u16(out_pixel, &yuv_u8, encoding, range); } -static void planar_yuv_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, - enum drm_color_encoding encoding, enum drm_color_range range) +static void planar_yuv_to_argb_u16(struct vkms_frame_info *frame_info, int x, int y, + struct pixel_argb_u16 *out_pixel, + enum drm_color_encoding encoding, + enum drm_color_range range) { struct pixel_yuv_u8 yuv_u8; - yuv_u8.y = src_pixels[0][0]; - yuv_u8.u = src_pixels[1][0]; - yuv_u8.v = src_pixels[2][0]; + /* Subsampling must be applied for planar yuv formats */ + int vsub = frame_info->fb->format->vsub ? frame_info->fb->format->vsub : 1; + int hsub = frame_info->fb->format->hsub ? frame_info->fb->format->hsub : 1; + + u8 *src_y = packed_pixels_addr(frame_info, x, y, 0); + u8 *src_u = packed_pixels_addr(frame_info, x / hsub, y / vsub, 1); + u8 *src_v = packed_pixels_addr(frame_info, x / hsub, y / vsub, 2); + + yuv_u8.y = src_y[0]; + yuv_u8.u = src_u[0]; + yuv_u8.v = src_v[0]; yuv_u8_to_argb_u16(out_pixel, &yuv_u8, encoding, range); } -static void planar_yvu_to_argb_u16(u8 **src_pixels, struct pixel_argb_u16 *out_pixel, - enum drm_color_encoding encoding, enum drm_color_range range) +static void planar_yvu_to_argb_u16(struct vkms_frame_info *frame_info, int x, int y, + struct pixel_argb_u16 *out_pixel, + enum drm_color_encoding encoding, + enum drm_color_range range) { struct pixel_yuv_u8 yuv_u8; - yuv_u8.y = src_pixels[0][0]; - yuv_u8.v = src_pixels[1][0]; - yuv_u8.u = src_pixels[2][0]; + /* Subsampling must be applied for semi-planar yuv formats */ + int vsub = frame_info->fb->format->vsub ? frame_info->fb->format->vsub : 1; + int hsub = frame_info->fb->format->hsub ? frame_info->fb->format->hsub : 1; - yuv_u8_to_argb_u16(out_pixel, &yuv_u8, encoding, range); -} + u8 *src_y = packed_pixels_addr(frame_info, x, y, 0); + u8 *src_u = packed_pixels_addr(frame_info, x / hsub, y / vsub, 1); + u8 *src_v = packed_pixels_addr(frame_info, x / hsub, y / vsub, 2); -/** - * vkms_compose_row - compose a single row of a plane - * @stage_buffer: output line with the composed pixels - * @plane: state of the plane that is being composed - * @y: y coordinate of the row - * - * This function composes a single row of a plane. It gets the source pixels - * through the y coordinate (see get_packed_src_addr()) and goes linearly - * through the source pixel, reading the pixels and converting it to - * ARGB16161616 (see the pixel_read() callback). For rotate-90 and rotate-270, - * the source pixels are not traversed linearly. The source pixels are queried - * on each iteration in order to traverse the pixels vertically. - */ -void vkms_compose_row(struct line_buffer *stage_buffer, struct vkms_plane_state *plane, int y) -{ - struct pixel_argb_u16 *out_pixels = stage_buffer->pixels; - struct vkms_frame_info *frame_info = plane->frame_info; - const struct drm_format_info *frame_format = frame_info->fb->format; - int limit = min_t(size_t, drm_rect_width(&frame_info->dst), stage_buffer->n_pixels); - u8 *src_pixels[DRM_FORMAT_MAX_PLANES]; - - enum drm_color_encoding encoding = plane->base.base.color_encoding; - enum drm_color_range range = plane->base.base.color_range; - - for (size_t i = 0; i < frame_format->num_planes; i++) - src_pixels[i] = get_packed_src_addr(frame_info, y, i); - - for (size_t x = 0; x < limit; x++) { - int x_pos = get_x_position(frame_info, limit, x); - - bool shoud_inc = !((x + 1) % frame_format->num_planes); - - if (drm_rotation_90_or_270(frame_info->rotation)) { - for (size_t i = 0; i < frame_format->num_planes; i++) { - src_pixels[i] = get_packed_src_addr(frame_info, - x + frame_info->rotated.y1, i); - if (!i || shoud_inc) - src_pixels[i] += frame_format->cpp[i] * y; - } - } - - plane->pixel_read(src_pixels, &out_pixels[x_pos], encoding, range); - - for (size_t i = 0; i < frame_format->num_planes; i++) { - if (!i || shoud_inc) - src_pixels[i] += frame_format->cpp[i]; - } - } + yuv_u8.y = src_y[0]; + yuv_u8.v = src_u[0]; + yuv_u8.u = src_v[0]; + + yuv_u8_to_argb_u16(out_pixel, &yuv_u8, encoding, range); } /* diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 932736fc3ee9..d818ed246a46 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -118,13 +118,20 @@ static void vkms_plane_atomic_update(struct drm_plane *plane, return; fmt = fb->format->format; + pixel_read_t pixel_read = get_pixel_conversion_function(fmt); + + if (!pixel_read) { + DRM_WARN("The requested pixel format is not supported by VKMS. The new state is " + "not applied.\n"); + return; + } + vkms_plane_state = to_vkms_plane_state(new_state); shadow_plane_state = &vkms_plane_state->base; frame_info = vkms_plane_state->frame_info; memcpy(&frame_info->src, &new_state->src, sizeof(struct drm_rect)); memcpy(&frame_info->dst, &new_state->dst, sizeof(struct drm_rect)); - memcpy(&frame_info->rotated, &new_state->dst, sizeof(struct drm_rect)); frame_info->fb = fb; memcpy(&frame_info->map, &shadow_plane_state->data, sizeof(frame_info->map)); drm_framebuffer_get(frame_info->fb); @@ -134,10 +141,8 @@ static void vkms_plane_atomic_update(struct drm_plane *plane, DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); - drm_rect_rotate(&frame_info->rotated, drm_rect_width(&frame_info->rotated), - drm_rect_height(&frame_info->rotated), frame_info->rotation); - vkms_plane_state->pixel_read = get_pixel_conversion_function(fmt); + vkms_plane_state->pixel_read = pixel_read; } static int vkms_plane_atomic_check(struct drm_plane *plane, -- 2.43.0