@samitouri / QOSamiQemu / commits / 6df405b1cf

ati-vga: Introduce ATI2DCtx struct for 2D blit context

Previously all state derived from registers was moved to locals. Now we can mechanically replace those locals with fields on the new ATI2DCtx struct. Signed-off-by: Chad Jablonski <chad@jablonski.xyz> Reviewed-by: BALATON Zoltan <balaton@eik.bme.hu> [balaton: Fix build without pixman] Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Message-ID: <20260309130926.942145969E5@zero.eik.bme.hu> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Chad Jablonski committed Mar 9, 2026 at 14:09 UTC 6df405b1cf03f80b1fb0c821bbd846c857a75f0a
1 file changed +132 -97
hw/display/ati_2d.c
+132 -97
@@ -13,6 +13,7 @@
13 #include "qemu/log.h"
14 #include "ui/pixel_ops.h"
15 #include "ui/console.h"
16 +#include "ui/rect.h"
17
18 /*
19 * NOTE:
@@ -43,22 +44,39 @@ static int ati_bpp_from_datatype(ATIVGAState *s)
44 }
45 }
46
46 -static void ati_set_dirty(ATIVGAState *s,
47 - const uint8_t *dst_bits, unsigned dst_y)
47 +typedef struct {
48 + int bpp;
49 + uint32_t rop3;
50 + bool left_to_right;
51 + bool top_to_bottom;
52 + uint32_t frgd_clr;
53 + const uint8_t *palette;
54 + const uint8_t *vram_end;
55 +
56 + QemuRect dst;
57 + int dst_stride;
58 + uint8_t *dst_bits;
59 + uint32_t dst_offset;
60 +
61 + QemuRect src;
62 + int src_stride;
63 + const uint8_t *src_bits;
64 +} ATI2DCtx;
65 +
66 +static void ati_set_dirty(VGACommonState *vga, const ATI2DCtx *ctx)
67 {
49 - VGACommonState *vga = &s->vga;
68 DisplaySurface *ds = qemu_console_surface(vga->con);
69
70 DPRINTF("%p %u ds: %p %d %d rop: %x\n", vga->vram_ptr, vga->vbe_start_addr,
71 surface_data(ds), surface_stride(ds), surface_bits_per_pixel(ds),
54 - (s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
55 - if (dst_bits >= vga->vram_ptr + vga->vbe_start_addr &&
56 - dst_bits < vga->vram_ptr + vga->vbe_start_addr +
57 - vga->vbe_regs[VBE_DISPI_INDEX_YRES] * vga->vbe_line_offset) {
72 + ctx->rop3 >> 16);
73 + if (ctx->dst_bits >= vga->vram_ptr + vga->vbe_start_addr &&
74 + ctx->dst_bits < vga->vram_ptr + vga->vbe_start_addr +
75 + vga->vbe_regs[VBE_DISPI_INDEX_YRES] * vga->vbe_line_offset) {
76 memory_region_set_dirty(&vga->vram,
59 - vga->vbe_start_addr + s->regs.dst_offset
60 - + dst_y * surface_stride(ds),
61 - s->regs.dst_height * surface_stride(ds));
77 + vga->vbe_start_addr + ctx->dst_offset +
78 + ctx->dst.y * surface_stride(ds),
79 + ctx->dst.height * surface_stride(ds));
80 }
81 }
82
@@ -66,100 +84,109 @@ void ati_2d_blt(ATIVGAState *s)
84 {
85 /* FIXME it is probably more complex than this and may need to be */
86 /* rewritten but for now as a start just to get some output: */
69 - uint32_t rop3 = s->regs.dp_mix & GMC_ROP3_MASK;
70 - bool left_to_right = s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT;
71 - bool top_to_bottom = s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM;
72 - uint32_t frgd_clr = s->regs.dp_brush_frgd_clr;
73 - uint8_t *palette = s->vga.palette;
74 - unsigned dst_offset = s->regs.dst_offset;
75 - unsigned dst_width = s->regs.dst_width;
76 - unsigned dst_height = s->regs.dst_height;
77 - unsigned dst_x = (left_to_right ?
78 - s->regs.dst_x : s->regs.dst_x + 1 - dst_width);
79 - unsigned dst_y = (top_to_bottom ?
80 - s->regs.dst_y : s->regs.dst_y + 1 - dst_height);
81 - int bpp = ati_bpp_from_datatype(s);
82 - if (!bpp) {
87 + ATI2DCtx ctx_;
88 + ATI2DCtx *ctx = &ctx_;
89 + ctx->rop3 = s->regs.dp_mix & GMC_ROP3_MASK;
90 + ctx->left_to_right = s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT;
91 + ctx->top_to_bottom = s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM;
92 + ctx->frgd_clr = s->regs.dp_brush_frgd_clr;
93 + ctx->palette = s->vga.palette;
94 + ctx->dst_offset = s->regs.dst_offset;
95 + ctx->dst.width = s->regs.dst_width;
96 + ctx->dst.height = s->regs.dst_height;
97 + ctx->dst.x = (ctx->left_to_right ?
98 + s->regs.dst_x : s->regs.dst_x + 1 - ctx->dst.width);
99 + ctx->dst.y = (ctx->top_to_bottom ?
100 + s->regs.dst_y : s->regs.dst_y + 1 - ctx->dst.height);
101 + ctx->bpp = ati_bpp_from_datatype(s);
102 + if (!ctx->bpp) {
103 qemu_log_mask(LOG_GUEST_ERROR, "Invalid bpp\n");
104 return;
105 }
86 - int dst_stride = s->regs.dst_pitch;
87 - if (!dst_stride) {
106 + ctx->dst_stride = s->regs.dst_pitch;
107 + if (!ctx->dst_stride) {
108 qemu_log_mask(LOG_GUEST_ERROR, "Zero dest pitch\n");
109 return;
110 }
91 - uint8_t *dst_bits = s->vga.vram_ptr + dst_offset;
111 + ctx->dst_bits = s->vga.vram_ptr + ctx->dst_offset;
112
113 if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
94 - dst_bits += s->regs.crtc_offset & 0x07ffffff;
95 - dst_stride *= bpp;
114 + ctx->dst_bits += s->regs.crtc_offset & 0x07ffffff;
115 + ctx->dst_stride *= ctx->bpp;
116 }
97 - uint8_t *end = s->vga.vram_ptr + s->vga.vram_size;
98 - if (dst_x > 0x3fff || dst_y > 0x3fff || dst_bits >= end
99 - || dst_bits + dst_x + (dst_y + dst_height) * dst_stride >= end) {
117 + ctx->vram_end = s->vga.vram_ptr + s->vga.vram_size;
118 + if (ctx->dst.x > 0x3fff || ctx->dst.y > 0x3fff ||
119 + ctx->dst_bits >= ctx->vram_end || ctx->dst_bits + ctx->dst.x +
120 + (ctx->dst.y + ctx->dst.height) * ctx->dst_stride >= ctx->vram_end) {
121 qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
122 return;
123 }
124 DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d %c %c\n",
104 - s->regs.src_offset, dst_offset, s->regs.default_offset,
105 - s->regs.src_pitch, dst_stride, s->regs.default_pitch,
106 - s->regs.src_x, s->regs.src_y, dst_x, dst_y,
107 - dst_width, dst_height,
108 - (left_to_right ? '>' : '<'),
109 - (top_to_bottom ? 'v' : '^'));
110 - switch (rop3) {
125 + s->regs.src_offset, ctx->dst_offset, s->regs.default_offset,
126 + ctx->src_stride, ctx->dst_stride, s->regs.default_pitch,
127 + ctx->src.x, ctx->src.y, ctx->dst.x, ctx->dst.y,
128 + ctx->dst.width, ctx->dst.height,
129 + (ctx->left_to_right ? '>' : '<'),
130 + (ctx->top_to_bottom ? 'v' : '^'));
131 + switch (ctx->rop3) {
132 case ROP3_SRCCOPY:
133 {
134 bool fallback = false;
114 - unsigned src_x = (left_to_right ?
115 - s->regs.src_x : s->regs.src_x + 1 - dst_width);
116 - unsigned src_y = (top_to_bottom ?
117 - s->regs.src_y : s->regs.src_y + 1 - dst_height);
118 - int src_stride = s->regs.src_pitch;
119 - if (!src_stride) {
135 + ctx->src.x = (ctx->left_to_right ?
136 + s->regs.src_x : s->regs.src_x + 1 - ctx->dst.width);
137 + ctx->src.y = (ctx->top_to_bottom ?
138 + s->regs.src_y : s->regs.src_y + 1 - ctx->dst.height);
139 + ctx->src_stride = s->regs.src_pitch;
140 + if (!ctx->src_stride) {
141 qemu_log_mask(LOG_GUEST_ERROR, "Zero source pitch\n");
142 return;
143 }
123 - uint8_t *src_bits = s->vga.vram_ptr + s->regs.src_offset;
144 + ctx->src_bits = s->vga.vram_ptr + s->regs.src_offset;
145
146 if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
126 - src_bits += s->regs.crtc_offset & 0x07ffffff;
127 - src_stride *= bpp;
147 + ctx->src_bits += s->regs.crtc_offset & 0x07ffffff;
148 + ctx->src_stride *= ctx->bpp;
149 }
129 - if (src_x > 0x3fff || src_y > 0x3fff || src_bits >= end
130 - || src_bits + src_x
131 - + (src_y + dst_height) * src_stride >= end) {
150 + if (ctx->src.x > 0x3fff || ctx->src.y > 0x3fff ||
151 + ctx->src_bits >= ctx->vram_end ||
152 + ctx->src_bits + ctx->src.x + (ctx->src.y + ctx->dst.height) *
153 + ctx->src_stride >= ctx->vram_end) {
154 qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
155 return;
156 }
157
158 DPRINTF("pixman_blt(%p, %p, %ld, %ld, %d, %d, %d, %d, %d, %d, %d, %d)\n",
137 - src_bits, dst_bits, src_stride / sizeof(uint32_t),
138 - dst_stride / sizeof(uint32_t), bpp, bpp, src_x, src_y, dst_x,
139 - dst_y, dst_width, dst_height);
159 + ctx->src_bits, ctx->dst_bits,
160 + ctx->src_stride / sizeof(uint32_t),
161 + ctx->dst_stride / sizeof(uint32_t),
162 + ctx->bpp, ctx->bpp, ctx->src.x, ctx->src.y, ctx->dst.x,
163 + ctx->dst.y, ctx->dst.width, ctx->dst.height);
164 #ifdef CONFIG_PIXMAN
141 - int src_stride_words = src_stride / sizeof(uint32_t);
142 - int dst_stride_words = dst_stride / sizeof(uint32_t);
143 - if ((s->use_pixman & BIT(1)) && left_to_right && top_to_bottom) {
144 - fallback = !pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
145 - src_stride_words, dst_stride_words, bpp, bpp,
146 - src_x, src_y, dst_x, dst_y,
147 - dst_width, dst_height);
165 + int src_stride_words = ctx->src_stride / sizeof(uint32_t);
166 + int dst_stride_words = ctx->dst_stride / sizeof(uint32_t);
167 + if ((s->use_pixman & BIT(1)) &&
168 + ctx->left_to_right && ctx->top_to_bottom) {
169 + fallback = !pixman_blt((uint32_t *)ctx->src_bits,
170 + (uint32_t *)ctx->dst_bits, src_stride_words,
171 + dst_stride_words, ctx->bpp, ctx->bpp,
172 + ctx->src.x, ctx->src.y, ctx->dst.x,
173 + ctx->dst.y, ctx->dst.width, ctx->dst.height);
174 } else if (s->use_pixman & BIT(1)) {
175 /* FIXME: We only really need a temporary if src and dst overlap */
150 - int llb = dst_width * (bpp / 8);
176 + int llb = ctx->dst.width * (ctx->bpp / 8);
177 int tmp_stride_words = DIV_ROUND_UP(llb, sizeof(uint32_t));
178 uint32_t *tmp = g_malloc(tmp_stride_words * sizeof(uint32_t) *
153 - dst_height);
154 - fallback = !pixman_blt((uint32_t *)src_bits, tmp,
155 - src_stride_words, tmp_stride_words, bpp, bpp,
156 - src_x, src_y, 0, 0,
157 - dst_width, dst_height);
179 + ctx->dst.height);
180 + fallback = !pixman_blt((uint32_t *)ctx->src_bits, tmp,
181 + src_stride_words, tmp_stride_words, ctx->bpp,
182 + ctx->bpp, ctx->src.x, ctx->src.y, 0, 0,
183 + ctx->dst.width, ctx->dst.height);
184 if (!fallback) {
159 - fallback = !pixman_blt(tmp, (uint32_t *)dst_bits,
185 + fallback = !pixman_blt(tmp, (uint32_t *)ctx->dst_bits,
186 tmp_stride_words, dst_stride_words,
161 - bpp, bpp, 0, 0, dst_x, dst_y,
162 - dst_width, dst_height);
187 + ctx->bpp, ctx->bpp, 0, 0,
188 + ctx->dst.x, ctx->dst.y,
189 + ctx->dst.width, ctx->dst.height);
190 }
191 g_free(tmp);
192 } else
@@ -168,18 +195,21 @@ void ati_2d_blt(ATIVGAState *s)
195 fallback = true;
196 }
197 if (fallback) {
171 - unsigned int y, i, j, bypp = bpp / 8;
172 - for (y = 0; y < dst_height; y++) {
173 - i = dst_x * bypp;
174 - j = src_x * bypp;
175 - if (top_to_bottom) {
176 - i += (dst_y + y) * dst_stride;
177 - j += (src_y + y) * src_stride;
198 + unsigned int y, i, j, bypp = ctx->bpp / 8;
199 + for (y = 0; y < ctx->dst.height; y++) {
200 + i = ctx->dst.x * bypp;
201 + j = ctx->src.x * bypp;
202 + if (ctx->top_to_bottom) {
203 + i += (ctx->dst.y + y) * ctx->dst_stride;
204 + j += (ctx->src.y + y) * ctx->src_stride;
205 } else {
179 - i += (dst_y + dst_height - 1 - y) * dst_stride;
180 - j += (src_y + dst_height - 1 - y) * src_stride;
206 + i += (ctx->dst.y + ctx->dst.height - 1 - y)
207 + * ctx->dst_stride;
208 + j += (ctx->src.y + ctx->dst.height - 1 - y)
209 + * ctx->src_stride;
210 }
182 - memmove(&dst_bits[i], &src_bits[j], dst_width * bypp);
211 + memmove(&ctx->dst_bits[i], &ctx->src_bits[j],
212 + ctx->dst.width * bypp);
213 }
214 }
215 break;
@@ -190,35 +220,40 @@ void ati_2d_blt(ATIVGAState *s)
220 {
221 uint32_t filler = 0;
222
193 - switch (rop3) {
223 + switch (ctx->rop3) {
224 case ROP3_PATCOPY:
195 - filler = frgd_clr;
225 + filler = ctx->frgd_clr;
226 break;
227 case ROP3_BLACKNESS:
198 - filler = 0xffUL << 24 | rgb_to_pixel32(palette[0], palette[1],
199 - palette[2]);
228 + filler = 0xffUL << 24 | rgb_to_pixel32(ctx->palette[0],
229 + ctx->palette[1],
230 + ctx->palette[2]);
231 break;
232 case ROP3_WHITENESS:
202 - filler = 0xffUL << 24 | rgb_to_pixel32(palette[3], palette[4],
203 - palette[5]);
233 + filler = 0xffUL << 24 | rgb_to_pixel32(ctx->palette[3],
234 + ctx->palette[4],
235 + ctx->palette[5]);
236 break;
237 }
238
239 DPRINTF("pixman_fill(%p, %ld, %d, %d, %d, %d, %d, %x)\n",
208 - dst_bits, dst_stride / sizeof(uint32_t), bpp, dst_x, dst_y,
209 - dst_width, dst_height, filler);
240 + ctx->dst_bits, ctx->dst_stride / sizeof(uint32_t), ctx->bpp,
241 + ctx->dst.x, ctx->dst.y, ctx->dst.width, ctx->dst.height,
242 + filler);
243 #ifdef CONFIG_PIXMAN
244 if (!(s->use_pixman & BIT(0)) ||
212 - !pixman_fill((uint32_t *)dst_bits, dst_stride / sizeof(uint32_t),
213 - bpp, dst_x, dst_y, dst_width, dst_height, filler))
245 + !pixman_fill((uint32_t *)ctx->dst_bits,
246 + ctx->dst_stride / sizeof(uint32_t), ctx->bpp,
247 + ctx->dst.x, ctx->dst.y,
248 + ctx->dst.width, ctx->dst.height, filler))
249 #endif
250 {
251 /* fallback when pixman failed or we don't want to call it */
217 - unsigned int x, y, i, bypp = bpp / 8;
218 - for (y = 0; y < dst_height; y++) {
219 - i = dst_x * bypp + (dst_y + y) * dst_stride;
220 - for (x = 0; x < dst_width; x++, i += bypp) {
221 - stn_he_p(&dst_bits[i], bypp, filler);
252 + unsigned int x, y, i, bypp = ctx->bpp / 8;
253 + for (y = 0; y < ctx->dst.height; y++) {
254 + i = ctx->dst.x * bypp + (ctx->dst.y + y) * ctx->dst_stride;
255 + for (x = 0; x < ctx->dst.width; x++, i += bypp) {
256 + stn_he_p(&ctx->dst_bits[i], bypp, filler);
257 }
258 }
259 }
@@ -226,9 +261,9 @@ void ati_2d_blt(ATIVGAState *s)
261 }
262 default:
263 qemu_log_mask(LOG_UNIMP, "Unimplemented ati_2d blt op %x\n",
229 - rop3 >> 16);
264 + ctx->rop3 >> 16);
265 return;
266 }
267
233 - ati_set_dirty(s, dst_bits, dst_y);
268 + ati_set_dirty(&s->vga, ctx);
269 }