47
typedef struct {
48
int bpp;
49
uint32_t rop3;
50
+ bool host_data_active;
51
bool left_to_right;
52
bool top_to_bottom;
53
uint32_t frgd_clr;
86
{
87
ctx->bpp = ati_bpp_from_datatype(s);
88
ctx->rop3 = s->regs.dp_mix & GMC_ROP3_MASK;
89
+ ctx->host_data_active = s->host_data.active;
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;
180
qemu_log_mask(LOG_GUEST_ERROR, "Zero source pitch\n");
181
return false;
182
}
181
- if (vis_src.x > 0x3fff || vis_src.y > 0x3fff ||
183
+ if (!ctx->host_data_active &&
184
+ (vis_src.x > 0x3fff || vis_src.y > 0x3fff ||
185
ctx->src_bits >= ctx->vram_end || ctx->src_bits + vis_src.x +
183
- (vis_src.y + vis_dst.height) * ctx->src_stride >= ctx->vram_end) {
186
+ (vis_src.y + vis_dst.height) * ctx->src_stride >= ctx->vram_end)) {
187
qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
188
return false;
189
}
303
void ati_2d_blt(ATIVGAState *s)
304
{
305
ATI2DCtx ctx;
306
+ uint32_t src_source = s->regs.dp_mix & DP_SRC_SOURCE;
307
+
308
+ /* Finish any active HOST_DATA blits before starting a new blit */
309
+ ati_host_data_finish(s);
310
+
311
+ if (src_source == DP_SRC_HOST || src_source == DP_SRC_HOST_BYTEALIGN) {
312
+ /* Begin a HOST_DATA blit */
313
+ s->host_data.active = true;
314
+ s->host_data.next = 0;
315
+ s->host_data.col = 0;
316
+ s->host_data.row = 0;
317
+ return;
318
+ }
319
setup_2d_blt_ctx(s, &ctx);
320
if (ati_2d_do_blt(&ctx, s->use_pixman)) {
321
ati_set_dirty(&s->vga, &ctx);
322
}
323
}
324
+
325
+bool ati_host_data_flush(ATIVGAState *s)
326
+{
327
+ ATI2DCtx ctx, chunk;
328
+ uint32_t fg = s->regs.dp_src_frgd_clr;
329
+ uint32_t bg = s->regs.dp_src_bkgd_clr;
330
+ unsigned bypp, pix_count, row, col, idx;
331
+ uint8_t pix_buf[ATI_HOST_DATA_ACC_BITS * sizeof(uint32_t)];
332
+ uint32_t byte_pix_order = s->regs.dp_datatype & DP_BYTE_PIX_ORDER;
333
+ uint32_t src_source = s->regs.dp_mix & DP_SRC_SOURCE;
334
+ uint32_t src_datatype = s->regs.dp_datatype & DP_SRC_DATATYPE;
335
+
336
+ if (!s->host_data.active) {
337
+ return false;
338
+ }
339
+ if (src_source != DP_SRC_HOST) {
340
+ qemu_log_mask(LOG_GUEST_ERROR,
341
+ "host_data_blt: unsupported src_source %x\n", src_source);
342
+ return false;
343
+ }
344
+ if (src_datatype != SRC_MONO_FRGD_BKGD && src_datatype != SRC_MONO_FRGD &&
345
+ src_datatype != SRC_COLOR) {
346
+ qemu_log_mask(LOG_GUEST_ERROR,
347
+ "host_data_blt: undefined src_datatype %x\n",
348
+ src_datatype);
349
+ return false;
350
+ }
351
+
352
+ setup_2d_blt_ctx(s, &ctx);
353
+
354
+ if (!ctx.left_to_right || !ctx.top_to_bottom) {
355
+ qemu_log_mask(LOG_UNIMP,
356
+ "host_data_blt: unsupported blit direction %c%c\n",
357
+ ctx.left_to_right ? '>' : '<',
358
+ ctx.top_to_bottom ? 'v' : '^');
359
+ return false;
360
+ }
361
+
362
+ bypp = ctx.bpp / 8;
363
+
364
+ if (src_datatype == SRC_COLOR) {
365
+ pix_count = ATI_HOST_DATA_ACC_BITS / ctx.bpp;
366
+ memcpy(pix_buf, &s->host_data.acc[0], sizeof(s->host_data.acc));
367
+ } else {
368
+ pix_count = ATI_HOST_DATA_ACC_BITS;
369
+ /* Expand monochrome bits to color pixels */
370
+ idx = 0;
371
+ for (int word = 0; word < 4; word++) {
372
+ for (int byte = 0; byte < 4; byte++) {
373
+ uint8_t byte_val = s->host_data.acc[word] >> (byte * 8);
374
+ for (int i = 0; i < 8; i++) {
375
+ bool is_fg = byte_val & BIT(byte_pix_order ? i : 7 - i);
376
+ uint32_t color = is_fg ? fg : bg;
377
+ stn_he_p(&pix_buf[idx], bypp, color);
378
+ idx += bypp;
379
+ }
380
+ }
381
+ }
382
+ }
383
+
384
+ /* Copy and then modify blit ctx for use in a chunked blit */
385
+ chunk = ctx;
386
+ chunk.src_bits = pix_buf;
387
+ chunk.src.y = 0;
388
+ chunk.src_stride = ATI_HOST_DATA_ACC_BITS * bypp;
389
+
390
+ /* Blit one scanline chunk at a time */
391
+ row = s->host_data.row;
392
+ col = s->host_data.col;
393
+ idx = 0;
394
+ DPRINTF("blt %dpx @ row: %d, col: %d\n", pix_count, row, col);
395
+ while (idx < pix_count && row < ctx.dst.height) {
396
+ unsigned pix_in_scanline = MIN(pix_count - idx,
397
+ ctx.dst.width - col);
398
+ chunk.src.x = idx;
399
+ /* Build a rect for this scanline chunk */
400
+ chunk.dst.x = ctx.dst.x + col;
401
+ chunk.dst.y = ctx.dst.y + row;
402
+ chunk.dst.width = pix_in_scanline;
403
+ chunk.dst.height = 1;
404
+ DPRINTF("blt %dpx span @ row: %d, col: %d to dst (%d,%d)\n",
405
+ pix_in_scanline, row, col, chunk.dst.x, chunk.dst.y);
406
+ if (ati_2d_do_blt(&chunk, s->use_pixman)) {
407
+ ati_set_dirty(&s->vga, &chunk);
408
+ }
409
+ idx += pix_in_scanline;
410
+ col += pix_in_scanline;
411
+ if (col >= ctx.dst.width) {
412
+ col = 0;
413
+ row += 1;
414
+ }
415
+ }
416
+
417
+ /* Track state of the overall blit for use by the next flush */
418
+ s->host_data.next = 0;
419
+ s->host_data.row = row;
420
+ s->host_data.col = col;
421
+ if (s->host_data.row >= ctx.dst.height) {
422
+ s->host_data.active = false;
423
+ }
424
+
425
+ return s->host_data.active;
426
+}
427
+
428
+void ati_host_data_finish(ATIVGAState *s)
429
+{
430
+ if (ati_host_data_flush(s)) {
431
+ qemu_log_mask(LOG_GUEST_ERROR,
432
+ "HOST_DATA blit ended before all data was written\n");
433
+ }
434
+ s->host_data.active = false;
435
+}