+ u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width;
+ u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix;
+
+ if (par->asleep)
+ return;
+ if (!image->width || !image->height)
+ return;
+ if (!par->accel_flags ||
+ (image->depth != 1 && info->var.bits_per_pixel != image->depth)) {
+ if (par->blitter_may_be_busy)
+ wait_for_idle(par);
+
+ cfb_imageblit(info, image);
+ return;
+ }
+
+ wait_for_idle(par);
+ pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
+ host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
+
+ switch (image->depth) {
+ case 1:
+ pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
+ pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP);
+ break;
+ case 4:
+ pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
+ pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP);
+ break;
+ case 8:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_8BPP;
+ break;
+ case 15:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_15BPP;
+ break;
+ case 16:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_16BPP;
+ break;
+ case 24:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_24BPP;
+ break;
+ case 32:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_32BPP;
+ break;
+ }
+
+ if (info->var.bits_per_pixel == 24) {
+ /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+ /* horizontal coordinates and widths must be adjusted */
+ dx *= 3;
+ width *= 3;
+
+ rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
+
+ pix_width &= ~DST_MASK;
+ pix_width |= DST_8BPP;
+
+ /*
+ * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit
+ * this hwaccelerated triple has an issue with not aligned data
+ */
+ if (M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
+ pix_width |= DP_HOST_TRIPLE_EN;
+ }
+
+ if (image->depth == 1) {
+ u32 fg, bg;
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ fg = ((u32*)(info->pseudo_palette))[image->fg_color];
+ bg = ((u32*)(info->pseudo_palette))[image->bg_color];
+ } else {
+ fg = image->fg_color;
+ bg = image->bg_color;
+ }
+
+ wait_for_fifo(2, par);
+ aty_st_le32(DP_BKGD_CLR, bg, par);
+ aty_st_le32(DP_FRGD_CLR, fg, par);
+ src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR;
+ mix = FRGD_MIX_S | BKGD_MIX_S;
+ } else {
+ src = MONO_SRC_ONE | FRGD_SRC_HOST;
+ mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D;
+ }
+
+ wait_for_fifo(6, par);
+ aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par);
+ aty_st_le32(DP_PIX_WIDTH, pix_width, par);
+ aty_st_le32(DP_MIX, mix, par);
+ aty_st_le32(DP_SRC, src, par);
+ aty_st_le32(HOST_CNTL, host_cntl, par);
+ aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par);
+
+ draw_rect(dx, dy, width, image->height, par);
+ src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
+
+ /* manual triple each pixel */
+ if (info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
+ int inbit, outbit, mult24, byte_id_in_dword, width;
+ u8 *pbitmapin = (u8*)image->data, *pbitmapout;
+ u32 hostdword;
+
+ for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) {
+ for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0;
+ byte_id_in_dword < 4 && src_bytes;
+ byte_id_in_dword++, pbitmapout++) {
+ for (outbit = 7; outbit >= 0; outbit--) {
+ *pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit);
+ mult24++;
+ /* next bit */
+ if (mult24 == 3) {
+ mult24 = 0;
+ inbit--;
+ width--;
+ }
+
+ /* next byte */
+ if (inbit < 0 || width == 0) {
+ src_bytes--;
+ pbitmapin++;
+ inbit = 7;
+
+ if (width == 0) {
+ width = image->width;
+ outbit = 0;
+ }
+ }
+ }
+ }
+ wait_for_fifo(1, par);
+ aty_st_le32(HOST_DATA0, hostdword, par);
+ }
+ } else {
+ u32 *pbitmap, dwords = (src_bytes + 3) / 4;
+ for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) {
+ wait_for_fifo(1, par);
+ aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par);
+ }
+ }
+
+ wait_for_idle(par);
+
+ /* restore pix_width */
+ wait_for_fifo(1, par);
+ aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);