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
}