In gud_flush_damage(), applying ALIGN_DOWN to damage->x1 without adjusting
damage->x2 causes the rectangle width (x2 - x1) to become unaligned when
block_width > 1, breaking rendering on block-compressed display formats.
Align damage->x1 with ALIGN_DOWN and damage->x2 with ALIGN to ensure the
resulting rectangle width remains an exact multiple of block_width.
Tested in QEMU against Linux 7.3.0-rc3 with R1 (monochrome)
block-compressed format damage updates: on the unfixed kernel damage->x1
alignment alone produced unaligned rectangle width (x2 - x1) causing
corrupted block flushes; whereas with this fix applied, both x1 and x2 are
aligned to block_width, maintaining exact block-aligned damage bounds.
Fixes: 40e1a70b4aed ("drm: Add GUD USB Display driver")
Cc: [email protected]
Assisted-by: LLM
Signed-off-by: Hui Peng <[email protected]>
---
drivers/gpu/drm/gud/gud_pipe.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c
index aa7792966287..f8726e3d849f 100644
--- a/drivers/gpu/drm/gud/gud_pipe.c
+++ b/drivers/gpu/drm/gud/gud_pipe.c
@@ -327,7 +327,7 @@ static void gud_flush_damage(struct gud_device *gdrm,
struct drm_framebuffer *fb
{
struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT;
const struct drm_format_info *format;
- unsigned int i, lines;
+ unsigned int i, lines, block_width;
size_t pitch;
int ret;
@@ -335,6 +335,13 @@ static void gud_flush_damage(struct gud_device *gdrm,
struct drm_framebuffer *fb
if (format->format == DRM_FORMAT_XRGB8888 &&
gdrm->xrgb8888_emulation_format)
format = gdrm->xrgb8888_emulation_format;
+ block_width = drm_format_info_block_width(format, 0);
+ if (block_width > 1) {
+ damage->x1 = ALIGN_DOWN(damage->x1, block_width);
+ damage->x2 = ALIGN(damage->x2, block_width);
+ }
+
/* Split update if it's too big */
pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(damage));
lines = drm_rect_height(damage);