@samitouri / QOSamiQemu / commits / 1b079e183d

ati-vga: Add scissor clipping register support

Implement read and write operations on SC_TOP_LEFT, SC_BOTTOM_RIGHT, and SRC_SC_BOTTOM_RIGHT registers. These registers are also updated when the src and/or dst clipping fields on DP_GUI_MASTER_CNTL are set to default clipping. Scissor clipping is used when rendering text in X.org. The r128 driver sends host data much wider than is necessary to draw a glyph and cuts it down to size using clipping before rendering. The actual clipping implementation follows in a future patch. This also includes a very minor refactor of the combined default_sc_bottom_right field in the registers struct to default_sc_bottom and default_sc_right. This was done to stay consistent with the other scissor registers and prevent repeated masking and extraction. Signed-off-by: Chad Jablonski <chad@jablonski.xyz> Reviewed-by: BALATON Zoltan <balaton@eik.bme.hu> Message-ID: <20260303024730.1489136-7-chad@jablonski.xyz> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Chad Jablonski committed Mar 2, 2026 at 21:47 UTC 1b079e183d4c1da8741e4cc313b939ea1f62439a
3 files changed +78 -3
hw/display/ati.c
+68 -2
@@ -514,7 +514,32 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
514 val |= s->regs.default_tile << 16;
515 break;
516 case DEFAULT_SC_BOTTOM_RIGHT:
517 - val = s->regs.default_sc_bottom_right;
517 + val = (s->regs.default_sc_bottom << 16) |
518 + s->regs.default_sc_right;
519 + break;
520 + case SC_TOP:
521 + val = s->regs.sc_top;
522 + break;
523 + case SC_LEFT:
524 + val = s->regs.sc_left;
525 + break;
526 + case SC_BOTTOM:
527 + val = s->regs.sc_bottom;
528 + break;
529 + case SC_RIGHT:
530 + val = s->regs.sc_right;
531 + break;
532 + case SRC_SC_BOTTOM:
533 + val = s->regs.src_sc_bottom;
534 + break;
535 + case SRC_SC_RIGHT:
536 + val = s->regs.src_sc_right;
537 + break;
538 + case SC_TOP_LEFT:
539 + case SC_BOTTOM_RIGHT:
540 + case SRC_SC_BOTTOM_RIGHT:
541 + qemu_log_mask(LOG_GUEST_ERROR,
542 + "Read from write-only register 0x%x\n", (unsigned)addr);
543 break;
544 default:
545 break;
@@ -877,6 +902,16 @@ static void ati_mm_write(void *opaque, hwaddr addr,
902 s->regs.dst_offset = s->regs.default_offset;
903 s->regs.dst_pitch = s->regs.default_pitch;
904 }
905 + if (!(data & GMC_SRC_CLIPPING)) {
906 + s->regs.src_sc_right = s->regs.default_sc_right;
907 + s->regs.src_sc_bottom = s->regs.default_sc_bottom;
908 + }
909 + if (!(data & GMC_DST_CLIPPING)) {
910 + s->regs.sc_top = 0;
911 + s->regs.sc_left = 0;
912 + s->regs.sc_right = s->regs.default_sc_right;
913 + s->regs.sc_bottom = s->regs.default_sc_bottom;
914 + }
915 break;
916 case DST_WIDTH_X:
917 s->regs.dst_x = data & 0x3fff;
@@ -956,7 +991,38 @@ static void ati_mm_write(void *opaque, hwaddr addr,
991 }
992 break;
993 case DEFAULT_SC_BOTTOM_RIGHT:
959 - s->regs.default_sc_bottom_right = data & 0x3fff3fff;
994 + s->regs.default_sc_right = data & 0x3fff;
995 + s->regs.default_sc_bottom = (data >> 16) & 0x3fff;
996 + break;
997 + case SC_TOP_LEFT:
998 + s->regs.sc_left = data & 0x3fff;
999 + s->regs.sc_top = (data >> 16) & 0x3fff;
1000 + break;
1001 + case SC_LEFT:
1002 + s->regs.sc_left = data & 0x3fff;
1003 + break;
1004 + case SC_TOP:
1005 + s->regs.sc_top = data & 0x3fff;
1006 + break;
1007 + case SC_BOTTOM_RIGHT:
1008 + s->regs.sc_right = data & 0x3fff;
1009 + s->regs.sc_bottom = (data >> 16) & 0x3fff;
1010 + break;
1011 + case SC_RIGHT:
1012 + s->regs.sc_right = data & 0x3fff;
1013 + break;
1014 + case SC_BOTTOM:
1015 + s->regs.sc_bottom = data & 0x3fff;
1016 + break;
1017 + case SRC_SC_BOTTOM_RIGHT:
1018 + s->regs.src_sc_right = data & 0x3fff;
1019 + s->regs.src_sc_bottom = (data >> 16) & 0x3fff;
1020 + break;
1021 + case SRC_SC_RIGHT:
1022 + s->regs.src_sc_right = data & 0x3fff;
1023 + break;
1024 + case SRC_SC_BOTTOM:
1025 + s->regs.src_sc_bottom = data & 0x3fff;
1026 break;
1027 default:
1028 break;
hw/display/ati_int.h
+8 -1
@@ -78,14 +78,21 @@ typedef struct ATIVGARegs {
78 uint32_t dp_brush_frgd_clr;
79 uint32_t dp_src_frgd_clr;
80 uint32_t dp_src_bkgd_clr;
81 + uint16_t sc_top;
82 + uint16_t sc_left;
83 + uint16_t sc_bottom;
84 + uint16_t sc_right;
85 + uint16_t src_sc_bottom;
86 + uint16_t src_sc_right;
87 uint32_t dp_cntl;
88 uint32_t dp_datatype;
89 uint32_t dp_mix;
90 uint32_t dp_write_mask;
91 uint32_t default_offset;
92 uint32_t default_pitch;
93 + uint16_t default_sc_bottom;
94 + uint16_t default_sc_right;
95 uint32_t default_tile;
88 - uint32_t default_sc_bottom_right;
96 } ATIVGARegs;
97
98 struct ATIVGAState {
hw/display/ati_regs.h
+2
@@ -397,6 +397,8 @@
397 #define GMC_DST_PITCH_OFFSET_CNTL 0x00000002
398 #define GMC_SRC_CLIP_DEFAULT 0x00000000
399 #define GMC_DST_CLIP_DEFAULT 0x00000000
400 +#define GMC_SRC_CLIPPING 0x00000004
401 +#define GMC_DST_CLIPPING 0x00000008
402 #define GMC_BRUSH_SOLIDCOLOR 0x000000d0
403 #define GMC_SRC_DSTCOLOR 0x00003000
404 #define GMC_BYTE_ORDER_MSB_TO_LSB 0x00000000