executor/src/srcblt.c

297 lines
8.8 KiB
C

/* Copyright 1995 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_srcblt[] =
"$Id: srcblt.c 63 2004-12-24 18:19:43Z ctm $";
#endif
#include "rsys/common.h"
#include "rsys/srcblt.h"
#include "rsys/quick.h"
#include "rsys/xdblt.h"
#include "rsys/vdriver.h"
#include "rsys/prefs.h"
#include "rsys/host.h"
int srcblt_log2_bpp asm ("_srcblt_log2_bpp");
const INTEGER *srcblt_rgn_start asm ("_srcblt_rgn_start");
const void **srcblt_stub_table asm ("_srcblt_stub_table");
int32 srcblt_x_offset asm ("_srcblt_x_offset");
int32 srcblt_src_row_bytes asm ("_srcblt_src_row_bytes");
int32 srcblt_dst_row_bytes asm ("_srcblt_dst_row_bytes");
uint32 srcblt_fg_color asm ("_srcblt_fg_color");
uint32 srcblt_bk_color asm ("_srcblt_bk_color");
char *srcblt_src_baseaddr asm ("_srcblt_src_baseaddr");
char *srcblt_dst_baseaddr asm ("_srcblt_dst_baseaddr");
int srcblt_shift_offset asm ("_srcblt_shift_offset");
boolean_t srcblt_reverse_scanlines_p asm ("_srcblt_reverse_scanlines_p");
#if defined (VGA_SCREEN_NEEDS_FAR_PTR)
uint16 srcblt_src_selector asm ("_srcblt_src_selector");
uint16 srcblt_dst_selector asm ("_srcblt_dst_selector");
#endif
/* We use this macro to avoid page faults when aligning pointers. */
#define MIN_PAGE_SIZE 512
boolean_t
srcblt_rgn (RgnHandle rh, int mode, int log2_bpp,
const blt_bitmap_t *src, const blt_bitmap_t *dst,
Point *src_origin, Point *dst_origin,
uint32 fg_color, uint32 bk_color)
{
uint32 mask, tile;
unsigned long dst_align32_offset, src_align32_offset;
long src_x_offset, src_y_offset, left_shift;
char *dst_baseaddr, *src_baseaddr;
#if defined (VDRIVER_SUPPORTS_REAL_SCREEN_BLITS)
boolean_t cursor_maybe_changed_p, old_vis_p;
#endif
#if defined (VGA_SCREEN_NEEDS_FAR_PTR)
boolean_t needs_seg_override_p;
#endif
/* check_bitmap (src, CHKR_RO); */
check_bitmap (dst, CHKR_WO);
/* Record log2 bpp. */
srcblt_log2_bpp = log2_bpp;
/* Tile fg and bk colors out to 32bpp. */
mask = ROMlib_pixel_size_mask[log2_bpp];
tile = ROMlib_pixel_tile_scale[log2_bpp];
srcblt_fg_color = (fg_color & mask) * tile;
srcblt_bk_color = (bk_color & mask) * tile;
/* Canonicalize mode for RGB. */
if (log2_bpp > 3)
mode ^= (srcCopy ^ notSrcCopy);
mode &= 7;
#if defined (VDRIVER_SUPPORTS_REAL_SCREEN_BLITS)
cursor_maybe_changed_p = old_vis_p = FALSE;
if (VDRIVER_BYPASS_INTERNAL_FBUF_P ())
{
int top, left;
RgnPtr rp = STARH (rh);
if (active_screen_addr_p (src))
{
srcblt_src_row_bytes = vdriver_real_screen_row_bytes;
src_baseaddr = (char *) vdriver_real_screen_baseaddr;
if (vdriver_flip_real_screen_pixels_p)
mode ^= (srcCopy ^ notSrcCopy);
#if defined (VGA_SCREEN_NEEDS_FAR_PTR)
srcblt_src_selector = vga_screen_selector;
#endif
/* I'm a lazy bastard and don't want to figure out the
* coordinate system sludge. Copying from the screen is
* uncommon anyway.
*/
old_vis_p = host_set_cursor_visible (FALSE);
cursor_maybe_changed_p = TRUE;
}
else
{
srcblt_src_row_bytes = CW (src->rowBytes) & ROWBYTES_VALUE_BITS;
src_baseaddr = (char *) MR (src->baseAddr);
#if defined (VGA_SCREEN_NEEDS_FAR_PTR)
asm ("movw %%ds,%0" : "=m" (srcblt_src_selector));
#endif
}
if (active_screen_addr_p (dst))
{
srcblt_dst_row_bytes = vdriver_real_screen_row_bytes;
dst_baseaddr = (char *) vdriver_real_screen_baseaddr;
#if defined (VGA_SCREEN_NEEDS_FAR_PTR)
srcblt_dst_selector = vga_screen_selector;
#endif
top = CW (dst->bounds.top);
left = CW (dst->bounds.left);
/* Hide the cursor if necessary. */
old_vis_p |= (host_hide_cursor_if_intersects
(CW (rp->rgnBBox.top) - top,
CW (rp->rgnBBox.left) - left,
CW (rp->rgnBBox.bottom) - top,
CW (rp->rgnBBox.right) - left));
cursor_maybe_changed_p = TRUE;
}
else
{
srcblt_dst_row_bytes = CW (dst->rowBytes) & ROWBYTES_VALUE_BITS;
dst_baseaddr = (char *) MR (dst->baseAddr);
#if defined (VGA_SCREEN_NEEDS_FAR_PTR)
asm ("movw %%ds,%0" : "=m" (srcblt_dst_selector));
#endif
}
}
else
#endif /* VDRIVER_SUPPORTS_REAL_SCREEN_BLITS */
{
/* Default to values for non-screen blit. */
srcblt_src_row_bytes = CW (src->rowBytes) & ROWBYTES_VALUE_BITS;
srcblt_dst_row_bytes = CW (dst->rowBytes) & ROWBYTES_VALUE_BITS;
src_baseaddr = (char *) MR (src->baseAddr);
dst_baseaddr = (char *) MR (dst->baseAddr);
#if defined (VGA_SCREEN_NEEDS_FAR_PTR)
asm ("movw %%ds,%0\n\t"
"movw %%ds,%1"
: "=m" (srcblt_src_selector), "=m" (srcblt_dst_selector));
#endif
}
/* Compute the offset to map dst y coords to src bitmap coords.*/
src_y_offset = (CW (src_origin->v) - CW (src->bounds.top)
- CW (dst_origin->v));
src_baseaddr += src_y_offset * srcblt_src_row_bytes;
dst_baseaddr -= CW (dst->bounds.top) * srcblt_dst_row_bytes;
/* Handle the common case of flipped fg/bk colors and a copy xfer mode. */
if ((mode & 3) == (srcCopy & 3) /* either srcCopy or notSrcCopy */
&& srcblt_fg_color == 0 && srcblt_bk_color == (uint32) ~0)
{
mode ^= (srcCopy ^ notSrcCopy);
srcblt_bk_color = 0;
srcblt_fg_color = ~0;
}
srcblt_x_offset = -(CW (dst->bounds.left) << log2_bpp);
src_x_offset = (((CW (src_origin->h) - CW (src->bounds.left))
- (CW (dst_origin->h) - CW (dst->bounds.left)))
<< log2_bpp);
src_baseaddr += (src_x_offset >> 3);
left_shift = src_x_offset & 7;
dst_align32_offset = (unsigned long) dst_baseaddr & 3;
/* Only align dst % 4 bytes when that cannot cause src to get pushed
* across a page boundary (which might cause a segfault). If that
* fails, we'll try to align src % 4 bytes.
*/
if (dst_align32_offset)
{
int offset;
offset = -1; /* default value. */
if (((unsigned long) src_baseaddr & (MIN_PAGE_SIZE - 1))
>= dst_align32_offset)
offset = dst_align32_offset;
else if (!left_shift)
{
/* Might as well align src if we can't align dst. */
src_align32_offset = (unsigned long) src_baseaddr & 3;
if (((unsigned long) dst_baseaddr & (MIN_PAGE_SIZE - 1))
>= src_align32_offset)
offset = src_align32_offset;
}
if (offset > 0)
{
int bit_offset = offset * 8;
srcblt_fg_color = ((srcblt_fg_color >> bit_offset)
| (srcblt_fg_color << (32 - bit_offset)));
srcblt_bk_color = ((srcblt_bk_color >> bit_offset)
| (srcblt_bk_color << (32 - bit_offset)));
srcblt_x_offset += bit_offset;
dst_baseaddr -= offset;
src_baseaddr -= offset;
}
}
/* If we are forced to do bit shifting anyway, we might as well
* long-align the source bitmap and increase the shift count.
*/
if (left_shift)
{
src_align32_offset = (unsigned long) src_baseaddr & 3;
src_baseaddr -= src_align32_offset;
left_shift += src_align32_offset * 8;
}
srcblt_shift_offset = left_shift;
srcblt_src_baseaddr = src_baseaddr;
srcblt_dst_baseaddr = dst_baseaddr;
/* Note whether we should reverse the order in which we process
* scanlines. This trick will only work for certain simple regions
* (e.g. those with only one repeated scanline). At the moment,
* more complex regions require the bitmap be copied offscreen to a
* temp buffer.
*/
srcblt_reverse_scanlines_p = (src_baseaddr < dst_baseaddr);
#if defined (VGA_SCREEN_NEEDS_FAR_PTR)
needs_seg_override_p = (srcblt_src_selector != srcblt_dst_selector);
# define FIRST_DIM [needs_seg_override_p]
#else
# define FIRST_DIM
#endif
if (left_shift == 0)
{
if (srcblt_fg_color == (uint32) ~0 && srcblt_bk_color == 0)
srcblt_stub_table = srcblt_noshift_stubs FIRST_DIM[mode];
else
srcblt_stub_table = srcblt_noshift_fgbk_stubs FIRST_DIM[mode];
}
else
{
#if defined (USE_PORTABLE_SRCBLT) || !defined (i386)
if (srcblt_fg_color == (uint32) ~0 && srcblt_bk_color == 0)
srcblt_stub_table = srcblt_shift_stubs[mode];
else
srcblt_stub_table = srcblt_shift_fgbk_stubs[mode];
#else /* i386 */
if (arch_type == ARCH_TYPE_I386)
{
/* i386 */
if (srcblt_fg_color == (uint32) ~0 && srcblt_bk_color == 0)
srcblt_stub_table = srcblt_shift_i386_stubs FIRST_DIM[mode];
else
srcblt_stub_table = srcblt_shift_fgbk_i386_stubs FIRST_DIM[mode];
}
else
{
/* i486 or better */
if (srcblt_fg_color == (uint32) ~0 && srcblt_bk_color == 0)
srcblt_stub_table = srcblt_shift_i486_stubs FIRST_DIM[mode];
else
srcblt_stub_table = srcblt_shift_fgbk_i486_stubs FIRST_DIM[mode];
}
#endif /* i386 */
}
SETUP_SPECIAL_RGN (rh, srcblt_rgn_start);
/* Make sure we have access to the raw screen bits. */
vdriver_accel_wait ();
/* Actually do the blit. */
srcblt_bitmap ();
#if defined (VDRIVER_SUPPORTS_REAL_SCREEN_BLITS)
if (cursor_maybe_changed_p)
host_set_cursor_visible (old_vis_p);
#endif
return !VDRIVER_BYPASS_INTERNAL_FBUF_P ();
}