aboutsummaryrefslogtreecommitdiff
path: root/hw/display/ati_2d.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/display/ati_2d.c')
-rw-r--r--hw/display/ati_2d.c55
1 files changed, 40 insertions, 15 deletions
diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
index b09753320a..42e82311eb 100644
--- a/hw/display/ati_2d.c
+++ b/hw/display/ati_2d.c
@@ -53,6 +53,10 @@ void ati_2d_blt(ATIVGAState *s)
s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds),
surface_bits_per_pixel(ds),
(s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
+ int dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
+ s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width);
+ int dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
+ s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height);
int bpp = ati_bpp_from_datatype(s);
int dst_stride = DEFAULT_CNTL ? s->regs.dst_pitch : s->regs.default_pitch;
uint8_t *dst_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
@@ -63,20 +67,25 @@ void ati_2d_blt(ATIVGAState *s)
dst_stride *= bpp;
}
uint8_t *end = s->vga.vram_ptr + s->vga.vram_size;
- if (dst_bits >= end ||
- dst_bits + s->regs.dst_x + (s->regs.dst_y + s->regs.dst_height) *
+ if (dst_bits >= end || dst_bits + dst_x + (dst_y + s->regs.dst_height) *
dst_stride >= end) {
qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
return;
}
- DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d\n",
+ DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d %c %c\n",
s->regs.src_offset, s->regs.dst_offset, s->regs.default_offset,
s->regs.src_pitch, s->regs.dst_pitch, s->regs.default_pitch,
s->regs.src_x, s->regs.src_y, s->regs.dst_x, s->regs.dst_y,
- s->regs.dst_width, s->regs.dst_height);
+ s->regs.dst_width, s->regs.dst_height,
+ (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? '>' : '<'),
+ (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? 'v' : '^'));
switch (s->regs.dp_mix & GMC_ROP3_MASK) {
case ROP3_SRCCOPY:
{
+ int src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
+ s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width);
+ int src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
+ s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height);
int src_stride = DEFAULT_CNTL ?
s->regs.src_pitch : s->regs.default_pitch;
uint8_t *src_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
@@ -86,9 +95,8 @@ void ati_2d_blt(ATIVGAState *s)
src_bits += s->regs.crtc_offset & 0x07ffffff;
src_stride *= bpp;
}
- if (src_bits >= end ||
- src_bits + s->regs.src_x + (s->regs.src_y + s->regs.dst_height) *
- src_stride >= end) {
+ if (src_bits >= end || src_bits + src_x +
+ (src_y + s->regs.dst_height) * src_stride >= end) {
qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
return;
}
@@ -97,19 +105,36 @@ void ati_2d_blt(ATIVGAState *s)
dst_stride /= sizeof(uint32_t);
DPRINTF("pixman_blt(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)\n",
src_bits, dst_bits, src_stride, dst_stride, bpp, bpp,
- s->regs.src_x, s->regs.src_y, s->regs.dst_x, s->regs.dst_y,
+ src_x, src_y, dst_x, dst_y,
s->regs.dst_width, s->regs.dst_height);
- pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
- src_stride, dst_stride, bpp, bpp,
- s->regs.src_x, s->regs.src_y,
- s->regs.dst_x, s->regs.dst_y,
- s->regs.dst_width, s->regs.dst_height);
+ if (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT &&
+ s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM) {
+ pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
+ src_stride, dst_stride, bpp, bpp,
+ src_x, src_y, dst_x, dst_y,
+ s->regs.dst_width, s->regs.dst_height);
+ } else {
+ /* FIXME: We only really need a temporary if src and dst overlap */
+ int llb = s->regs.dst_width * (bpp / 8);
+ int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
+ uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) *
+ s->regs.dst_height);
+ pixman_blt((uint32_t *)src_bits, tmp,
+ src_stride, tmp_stride, bpp, bpp,
+ src_x, src_y, 0, 0,
+ s->regs.dst_width, s->regs.dst_height);
+ pixman_blt(tmp, (uint32_t *)dst_bits,
+ tmp_stride, dst_stride, bpp, bpp,
+ 0, 0, dst_x, dst_y,
+ s->regs.dst_width, s->regs.dst_height);
+ g_free(tmp);
+ }
if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr &&
dst_bits < s->vga.vram_ptr + s->vga.vbe_start_addr +
s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] * s->vga.vbe_line_offset) {
memory_region_set_dirty(&s->vga.vram, s->vga.vbe_start_addr +
s->regs.dst_offset +
- s->regs.dst_y * surface_stride(ds),
+ dst_y * surface_stride(ds),
s->regs.dst_height * surface_stride(ds));
}
s->regs.dst_x += s->regs.dst_width;
@@ -151,7 +176,7 @@ void ati_2d_blt(ATIVGAState *s)
s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] * s->vga.vbe_line_offset) {
memory_region_set_dirty(&s->vga.vram, s->vga.vbe_start_addr +
s->regs.dst_offset +
- s->regs.dst_y * surface_stride(ds),
+ dst_y * surface_stride(ds),
s->regs.dst_height * surface_stride(ds));
}
s->regs.dst_y += s->regs.dst_height;