Annotation of uae/src/picasso96.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * UAE - The U*nix Amiga Emulator
                      3:  *
                      4:  * Picasso96 Support Module
                      5:  *
                      6:  * Copyright 1997 Brian King <[email protected], [email protected]>
                      7:  *
                      8:  * Theory of operation:
                      9:  * On the Amiga side, a Picasso card consists mainly of a memory area that
                     10:  * contains the frame buffer.  On the UAE side, we allocate a block of memory
                     11:  * that will hold the frame buffer.  This block is in normal memory, it is
                     12:  * never directly on the graphics card.  All graphics operations, which are
                     13:  * mainly reads and writes into this block and a few basic operations like
                     14:  * filling a rectangle, operate on this block of memory.
                     15:  * Since the memory is not on the graphics card, some work must be done to
                     16:  * synchronize the display with the data in the Picasso frame buffer.  There
                     17:  * are various ways to do this.  One possibility is to allocate a second
                     18:  * buffer of the same size, and perform all write operations twice.  Since
                     19:  * we never read from the second buffer, it can actually be placed in video
                     20:  * memory.  The X11 driver could be made to use the Picasso frame buffer as
                     21:  * the data buffer of an XImage, which could then be XPutImage()d from time
                     22:  * to time.  Another possibility is to translate all Picasso accesses into
                     23:  * Xlib (or GDI, or whatever your graphics system is) calls.  This possibility
                     24:  * is a bit tricky, since there is a risk of generating very many single pixel
                     25:  * accesses which may be rather slow.
                     26:  *
                     27:  * TODO:
                     28:  * - add panning capability
                     29:  */
                     30: 
                     31: #include "sysconfig.h"
                     32: #include "sysdeps.h"
                     33: 
                     34: #include "config.h"
                     35: #include "options.h"
                     36: #include "threaddep/penguin.h"
                     37: #include "uae.h"
                     38: #include "memory.h"
                     39: #include "custom.h"
                     40: #include "readcpu.h"
                     41: #include "newcpu.h"
                     42: #include "xwin.h"
                     43: #include "picasso96.h"
                     44: 
                     45: #ifdef PICASSO96
                     46: 
                     47: static uae_u32 gfxmem_lget (uaecptr) REGPARAM;
                     48: static uae_u32 gfxmem_wget (uaecptr) REGPARAM;
                     49: static uae_u32 gfxmem_bget (uaecptr) REGPARAM;
                     50: static void gfxmem_lput (uaecptr, uae_u32) REGPARAM;
                     51: static void gfxmem_wput (uaecptr, uae_u32) REGPARAM;
                     52: static void gfxmem_bput (uaecptr, uae_u32) REGPARAM;
                     53: static int gfxmem_check (uaecptr addr, uae_u32 size) REGPARAM;
                     54: static uae_u8 *gfxmem_xlate (uaecptr addr) REGPARAM;
                     55: 
                     56: static void write_gfx_long (uaecptr addr, uae_u32 value);
                     57: static void write_gfx_word (uaecptr addr, uae_u16 value);
                     58: static void write_gfx_byte (uaecptr addr, uae_u8 value);
                     59: 
                     60: static uae_u8 all_ones_bitmap, all_zeros_bitmap; /* yuk */
                     61: 
                     62: struct picasso96_state_struct picasso96_state;
                     63: struct picasso_vidbuf_description picasso_vidinfo;
                     64: 
                     65: /* These are the maximum resolutions... They are filled in by GetSupportedResolutions() */
                     66: /* have to fill this in, otherwise problems occur
                     67:  * @@@ ??? what problems?
                     68:  */
                     69: struct ScreenResolution planar = { 320, 240 };
                     70: struct ScreenResolution chunky = { 640, 480 };
                     71: struct ScreenResolution hicolour = { 640, 480 };
                     72: struct ScreenResolution truecolour = { 640, 480 };
                     73: struct ScreenResolution alphacolour = { 460, 480 };
                     74: 
                     75: uae_u16 picasso96_pixel_format = RGBFF_CHUNKY;
                     76: 
                     77: struct PicassoResolution DisplayModes[MAX_PICASSO_MODES];
                     78: 
                     79: static int mode_count = 0;
                     80: 
                     81: static uae_u32 p2ctab[256][2];
                     82: 
                     83: /*
                     84:  * Debugging dumps
                     85:  */
                     86: 
                     87: static void DumpModeInfoStructure (uaecptr amigamodeinfoptr)
                     88: {
1.1.1.2 ! root       89:     write_log ("ModeInfo Structure Dump:\n");
        !            90:     write_log ("  Node.ln_Succ  = 0x%x\n", get_long (amigamodeinfoptr));
        !            91:     write_log ("  Node.ln_Pred  = 0x%x\n", get_long (amigamodeinfoptr + 4));
        !            92:     write_log ("  Node.ln_Type  = 0x%x\n", get_byte (amigamodeinfoptr + 8));
        !            93:     write_log ("  Node.ln_Pri   = %d\n", get_byte (amigamodeinfoptr + 9));
        !            94:     /*write_log ("  Node.ln_Name  = %s\n", uaememptr->Node.ln_Name); */
        !            95:     write_log ("  OpenCount     = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_OpenCount));
        !            96:     write_log ("  Active        = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Active));
        !            97:     write_log ("  Width         = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Width));
        !            98:     write_log ("  Height        = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Height));
        !            99:     write_log ("  Depth         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Depth));
        !           100:     write_log ("  Flags         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Flags));
        !           101:     write_log ("  HorTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorTotal));
        !           102:     write_log ("  HorBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorBlankSize));
        !           103:     write_log ("  HorSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncStart));
        !           104:     write_log ("  HorSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSize));
        !           105:     write_log ("  HorSyncSkew   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSkew));
        !           106:     write_log ("  HorEnableSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorEnableSkew));
        !           107:     write_log ("  VerTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerTotal));
        !           108:     write_log ("  VerBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerBlankSize));
        !           109:     write_log ("  VerSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncStart));
        !           110:     write_log ("  VerSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncSize));
        !           111:     write_log ("  Clock         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_first_union));
        !           112:     write_log ("  ClockDivide   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_second_union));
        !           113:     write_log ("  PixelClock    = %d\n", get_long (amigamodeinfoptr + PSSO_ModeInfo_PixelClock));
1.1       root      114: }
                    115: 
                    116: static void DumpLibResolutionStructure (uaecptr amigalibresptr)
                    117: {
                    118:     int i;
                    119:     uaecptr amigamodeinfoptr;
                    120:     struct LibResolution *uaememptr = (struct LibResolution *)get_mem_bank(amigalibresptr).xlateaddr(amigalibresptr);
                    121:     
                    122:     return;
                    123: 
1.1.1.2 ! root      124:     write_log ("LibResolution Structure Dump:\n");
1.1       root      125: 
                    126:     if (get_long (amigalibresptr + PSSO_LibResolution_DisplayID) == 0xFFFFFFFF) {
1.1.1.2 ! root      127:        write_log ("  Finished With LibResolutions...\n");
1.1       root      128:     } else {
1.1.1.2 ! root      129:        write_log ("  Name      = %s\n", uaememptr->P96ID);
        !           130:        write_log ("  DisplayID = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_DisplayID));
        !           131:        write_log ("  Width     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Width));
        !           132:        write_log ("  Height    = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Height));
        !           133:        write_log ("  Flags     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Flags));
1.1       root      134:        for (i = 0; i < MAXMODES; i++) {
                    135:            amigamodeinfoptr = get_long (amigalibresptr + PSSO_LibResolution_Modes + i*4);
1.1.1.2 ! root      136:            write_log ("  ModeInfo[%d] = 0x%x\n", i, amigamodeinfoptr);
1.1       root      137:            if (amigamodeinfoptr)
1.1.1.2 ! root      138:                DumpModeInfoStructure (amigamodeinfoptr);
1.1       root      139:        }
1.1.1.2 ! root      140:        write_log ("  BoardInfo = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_BoardInfo));
1.1       root      141:     }
                    142: }
                    143: 
                    144: static char binary_byte[8];
                    145: 
                    146: static char *BuildBinaryString (uae_u8 value)
                    147: {
                    148:     int i;
                    149:     for (i = 0; i < 8; i++) {
                    150:        binary_byte[i] = (value & (1 << (7 - i))) ? '#' : '.';
                    151:     }
                    152:     return binary_byte;
                    153: }
                    154: 
                    155: static void DumpPattern (struct Pattern *patt)
                    156: {
                    157:     uae_u8 *mem;
                    158:     int row, col;
                    159:     for (row = 0; row < (1 << patt->Size); row++) {
                    160:        mem = patt->Memory + row * 2;
                    161:        for (col = 0; col < 2; col++) {
1.1.1.2 ! root      162:            write_log ("%s", BuildBinaryString (*mem++));
1.1       root      163:        }
1.1.1.2 ! root      164:        write_log ("\n");
1.1       root      165:     }
                    166: }
                    167: 
                    168: static void DumpTemplate (struct Template *tmp, uae_u16 w, uae_u16 h)
                    169: {
                    170:     uae_u8 *mem = tmp->Memory;
                    171:     int row, col, width;
                    172:     width = (w + 7) >> 3;
1.1.1.2 ! root      173:     write_log ("xoffset = %d, bpr = %d\n", tmp->XOffset, tmp->BytesPerRow);
1.1       root      174:     for (row = 0; row < h; row++) {
                    175:        mem = tmp->Memory + row * tmp->BytesPerRow;
                    176:        for (col = 0; col < width; col++) {
1.1.1.2 ! root      177:            write_log ("%s", BuildBinaryString (*mem++));
1.1       root      178:        }
1.1.1.2 ! root      179:        write_log ("\n");
1.1       root      180:     }
                    181: }
                    182: 
                    183: static void ShowSupportedResolutions (void)
                    184: {
                    185:     int i;
                    186:     
                    187:     return;
                    188: 
                    189:     for (i = 0; i < mode_count; i++)
1.1.1.2 ! root      190:        write_log ("%s\n", DisplayModes[i].name);
        !           191: }
        !           192: 
        !           193: static uae_u8 GetBytesPerPixel (uae_u32 RGBfmt)
        !           194: {
        !           195:     switch (RGBfmt) {
        !           196:      case RGBFB_CLUT:
        !           197:        return 1;
        !           198: 
        !           199:      case RGBFB_A8R8G8B8:
        !           200:      case RGBFB_A8B8G8R8:
        !           201:      case RGBFB_R8G8B8A8:
        !           202:      case RGBFB_B8G8R8A8:
        !           203:        return 4;
        !           204: 
        !           205:      case RGBFB_B8G8R8:
        !           206:      case RGBFB_R8G8B8:
        !           207:        return 3;
        !           208: 
        !           209:      case RGBFB_R5G5B5:
        !           210:      case RGBFB_R5G6B5:
        !           211:      case RGBFB_R5G6B5PC:
        !           212:      case RGBFB_R5G5B5PC:
        !           213:      case RGBFB_B5G6R5PC:
        !           214:      case RGBFB_B5G5R5PC:
        !           215:        return 2;
        !           216:      default:
        !           217:        write_log ("ERROR - GetBytesPerPixel() was unsuccessful with 0x%x?!\n", RGBfmt);
        !           218:        return 0;
        !           219:     }
1.1       root      220: }
                    221: 
                    222: /*
                    223:  * Amiga <-> native structure conversion functions
                    224:  */
                    225: 
                    226: static int CopyRenderInfoStructureA2U (uaecptr amigamemptr, struct RenderInfo *ri)
                    227: {
                    228:     uaecptr memp = get_long (amigamemptr + PSSO_RenderInfo_Memory);
                    229: 
                    230:     if (valid_address (memp, 1 /* FIXME */)) {
                    231:        ri->Memory = get_real_address (memp);
                    232:        ri->BytesPerRow = get_word (amigamemptr + PSSO_RenderInfo_BytesPerRow);
                    233:        ri->RGBFormat = get_long (amigamemptr + PSSO_RenderInfo_RGBFormat);
                    234:        return 1;
                    235:     }
1.1.1.2 ! root      236:     write_log ("ERROR - Invalid RenderInfo memory area...\n");
1.1       root      237:     return 0;
                    238: }
                    239: 
                    240: static int CopyPatternStructureA2U (uaecptr amigamemptr, struct Pattern *pattern)
                    241: {
                    242:     uaecptr memp = get_long (amigamemptr + PSSO_Pattern_Memory);
                    243:     if (valid_address (memp, 1 /* FIXME */)) {
                    244:        pattern->Memory = get_real_address (memp);
                    245:        pattern->XOffset = get_word (amigamemptr + PSSO_Pattern_XOffset);
                    246:        pattern->YOffset = get_word (amigamemptr + PSSO_Pattern_YOffset);
                    247:        pattern->FgPen = get_long (amigamemptr + PSSO_Pattern_FgPen);
                    248:        pattern->BgPen = get_long (amigamemptr + PSSO_Pattern_BgPen);
                    249:        pattern->Size = get_byte (amigamemptr + PSSO_Pattern_Size);
                    250:        pattern->DrawMode = get_byte (amigamemptr + PSSO_Pattern_DrawMode);
                    251:        return 1;
                    252:     }
1.1.1.2 ! root      253:     write_log ("ERROR - Invalid Pattern memory area...\n");
1.1       root      254:     return 0;
                    255: }
                    256: 
                    257: static void CopyColorIndexMappingA2U (uaecptr amigamemptr, struct ColorIndexMapping *cim)
                    258: {
                    259:     int i;
                    260:     cim->ColorMask = get_long (amigamemptr);
                    261:     for (i = 0; i < 256; i++, amigamemptr += 4)
                    262:        cim->Colors[i] = get_long (amigamemptr + 4);
                    263: }
                    264: 
                    265: static int CopyBitMapStructureA2U (uaecptr amigamemptr, struct BitMap *bm)
                    266: {
                    267:     int i;
                    268: 
                    269:     bm->BytesPerRow = get_word (amigamemptr + PSSO_BitMap_BytesPerRow);
                    270:     bm->Rows = get_word (amigamemptr + PSSO_BitMap_Rows);
                    271:     bm->Flags = get_byte (amigamemptr + PSSO_BitMap_Flags);
                    272:     bm->Depth = get_byte (amigamemptr + PSSO_BitMap_Depth);
                    273: 
                    274:     for (i = 0; i < bm->Depth; i++) {
                    275:        uaecptr plane = get_long (amigamemptr + PSSO_BitMap_Planes + i*4);
                    276:        switch (plane) {
                    277:         case 0:
                    278:            bm->Planes[i] = &all_zeros_bitmap;
                    279:            break;
                    280:         case 0xFFFFFFFF:
                    281:            bm->Planes[i] = &all_ones_bitmap;
                    282:            break;
                    283:         default:
                    284:            if (valid_address (plane, bm->BytesPerRow * bm->Rows))
                    285:                bm->Planes[i] = get_real_address (plane);
                    286:            else
                    287:                return 0;
                    288:            break;
                    289:        }
                    290:     }
                    291:     return 1;
                    292: }
                    293: 
                    294: static int CopyTemplateStructureA2U (uaecptr amigamemptr, struct Template *tmpl)
                    295: {
                    296:     uaecptr memp = get_long (amigamemptr + PSSO_Template_Memory);
                    297: 
                    298:     if (valid_address (memp, 1 /* FIXME */)) {
                    299:        tmpl->Memory = get_real_address (memp);
                    300:        tmpl->BytesPerRow = get_word (amigamemptr + PSSO_Template_BytesPerRow);
                    301:        tmpl->XOffset = get_byte (amigamemptr + PSSO_Template_XOffset);
                    302:        tmpl->DrawMode = get_byte (amigamemptr + PSSO_Template_DrawMode);
                    303:        tmpl->FgPen = get_long (amigamemptr + PSSO_Template_FgPen);
                    304:        tmpl->BgPen = get_long (amigamemptr + PSSO_Template_BgPen);
                    305:        return 1;
                    306:     }
1.1.1.2 ! root      307:     write_log ("ERROR - Invalid Template memory area...\n");
1.1       root      308:     return 0;
                    309: }
                    310: 
                    311: static void CopyLibResolutionStructureU2A (struct LibResolution *libres, uaecptr amigamemptr)
                    312: {
                    313:     char *uaememptr = 0;
                    314:     int i;
                    315: 
                    316:     uaememptr = gfxmem_xlate(amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
                    317:     memset(uaememptr, 0, PSSO_LibResolution_sizeof); /* zero out our LibResolution structure */
                    318:     strcpy(uaememptr + PSSO_LibResolution_P96ID, libres->P96ID);
1.1.1.2 ! root      319:     put_long (amigamemptr + PSSO_LibResolution_DisplayID, libres->DisplayID);
        !           320:     put_word (amigamemptr + PSSO_LibResolution_Width, libres->Width);
        !           321:     put_word (amigamemptr + PSSO_LibResolution_Height, libres->Height);
        !           322:     put_word (amigamemptr + PSSO_LibResolution_Flags, libres->Flags);
1.1       root      323:     for (i = 0; i < MAXMODES; i++)
1.1.1.2 ! root      324:        put_long (amigamemptr + PSSO_LibResolution_Modes + i*4, libres->Modes[i]);
1.1       root      325: #if 0
1.1.1.2 ! root      326:     put_long (amigamemptr, libres->Node.ln_Succ);
        !           327:     put_long (amigamemptr + 4, libres->Node.ln_Pred);
        !           328:     put_byte (amigamemptr + 8, libres->Node.ln_Type);
        !           329:     put_byte (amigamemptr + 9, libres->Node.ln_Pri);
1.1       root      330: #endif
1.1.1.2 ! root      331:     put_long (amigamemptr + 10, amigamemptr + PSSO_LibResolution_P96ID);
        !           332:     put_long (amigamemptr + PSSO_LibResolution_BoardInfo, libres->BoardInfo);
1.1       root      333: }
                    334: 
                    335: /* list is Amiga address of list, in correct endian format for UAE
                    336:  * node is Amiga address of node, in correct endian format for UAE */
                    337: static void AmigaListAddTail (uaecptr list, uaecptr node)
                    338: {
                    339:     uaecptr amigamemptr = 0;
                    340: 
                    341:     if (get_long (list + 8) == list) {
                    342:        /* Empty list - set it up */
1.1.1.2 ! root      343:        put_long (list, node);     /* point the lh_Head to our new node */
        !           344:        put_long (list + 4, 0);    /* set the lh_Tail to NULL */
        !           345:        put_long (list + 8, node); /* point the lh_TailPred to our new node */
1.1       root      346: 
                    347:        /* Adjust the new node - don't rely on it being zeroed out */
1.1.1.2 ! root      348:        put_long (node, 0); /* ln_Succ */
        !           349:        put_long (node + 4, 0); /* ln_Pred */
1.1       root      350:     } else {
                    351:        amigamemptr = get_long (list + 8); /* get the lh_TailPred contents */
                    352: 
1.1.1.2 ! root      353:        put_long (list + 8, node); /* point the lh_TailPred to our new node */
1.1       root      354: 
                    355:        /* Adjust the previous lh_TailPred node */
1.1.1.2 ! root      356:        put_long (amigamemptr, node); /* point the ln_Succ to our new node */
1.1       root      357: 
                    358:        /* Adjust the new node - don't rely on it being zeroed out */
1.1.1.2 ! root      359:        put_long (node, 0); /* ln_Succ */
        !           360:        put_long (node + 4, amigamemptr); /* ln_Pred */
1.1       root      361:     }
                    362: }
                    363: 
                    364: /*
                    365:  * Functions to perform an action on the real screen
                    366:  */
                    367: 
                    368: /*
                    369:  * Fill a rectangle on the screen.  src points to the start of a line of the
                    370:  * filled rectangle in the frame buffer; it can be used as a memcpy source if
                    371:  * there is no OS specific function to fill the rectangle.
                    372:  */
                    373: 
                    374: static void do_fillrect (uae_u8 *src, int x, int y, int width, int height)
                    375: {
                    376:     uae_u8 *dst;
                    377:     /* Try OS specific fillrect function here; and return if successful.  */
                    378: 
                    379:     DX_Invalidate (y, y + height - 1);
                    380:     if (! picasso_vidinfo.extra_mem)
                    381:        return;
                    382: 
                    383:     width *= picasso96_state.BytesPerPixel;
1.1.1.2 ! root      384:     dst = gfx_lock_picasso ();
1.1       root      385:     if (!dst)
1.1.1.2 ! root      386:        goto out;
1.1       root      387: 
1.1.1.2 ! root      388:     dst += y*picasso_vidinfo.rowbytes + x*picasso_vidinfo.pixbytes;
        !           389:     if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
        !           390:        while (height-- > 0) {
        !           391:            memcpy (dst, src, width);
        !           392:            dst += picasso_vidinfo.rowbytes;
        !           393:        }
        !           394:     } else {
        !           395:        int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
        !           396:        if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
        !           397:            abort ();
        !           398: 
        !           399:        while (height-- > 0) {
        !           400:            int i;
        !           401:            switch (psiz) {
        !           402:             case 2:
        !           403:                for (i = 0; i < width; i++)
        !           404:                    *((uae_u16 *)dst + i) = picasso_vidinfo.clut[src[i]];
        !           405:                break;
        !           406:             case 4:
        !           407:                for (i = 0; i < width; i++)
        !           408:                    *((uae_u32 *)dst + i) = picasso_vidinfo.clut[src[i]];
        !           409:                break;
        !           410:             default:
        !           411:                abort ();                       
        !           412:            }
        !           413:            dst += picasso_vidinfo.rowbytes;
        !           414:        }
1.1       root      415:     }
1.1.1.2 ! root      416:     out:
        !           417:     gfx_unlock_picasso ();
1.1       root      418: }
                    419: 
                    420: /*
                    421:  * This routine modifies the real screen buffer after a blit has been
                    422:  * performed in the save area. If can_do_blit is nonzero, the blit can
                    423:  * be performed within the real screen buffer; otherwise, this routine
                    424:  * must do it by hand using the data in the save area, pointed to by
                    425:  * srcp.
                    426:  */
                    427: 
                    428: static void do_blit (uae_u8 *srcp, unsigned long src_rowbytes,
                    429:                     int srcx, int srcy, int dstx, int dsty,
                    430:                     int width, int height, int can_do_blit)
                    431: {
                    432:     uae_u8 *dstp;
                    433:     /* If this RenderInfo points at something else than the currently visible
                    434:      * screen, we must ignore the blit.  */
                    435:     if (can_do_blit) {
                    436:        /*
                    437:         * Call OS blitting function that can do it in video memory.
                    438:         * Should return if it was successful
                    439:         */
                    440:     }
                    441: 
                    442:     DX_Invalidate (dsty, dsty + height - 1);
                    443:     if (! picasso_vidinfo.extra_mem)
                    444:        return;
                    445: 
1.1.1.2 ! root      446:     dstp = gfx_lock_picasso ();
1.1       root      447:     if (dstp == 0)
1.1.1.2 ! root      448:        goto out;
1.1       root      449: 
                    450:     /* The areas can't overlap: the source is always in the Picasso frame buffer,
                    451:      * and the destination is a different buffer owned by the graphics code.  */
                    452: 
1.1.1.2 ! root      453:     dstp += dsty * picasso_vidinfo.rowbytes + dstx * picasso_vidinfo.pixbytes;
        !           454:     if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
        !           455:        width *= picasso96_state.BytesPerPixel;
        !           456:        while (height-- > 0) {
        !           457:            memcpy (dstp, srcp, width);
        !           458:            srcp += src_rowbytes;
        !           459:            dstp += picasso_vidinfo.rowbytes;
        !           460:        }
        !           461:     } else {
        !           462:        int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
        !           463:        if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
        !           464:            abort ();
        !           465: 
        !           466:        while (height-- > 0) {
        !           467:            int i;
        !           468:            switch (psiz) {
        !           469:             case 2:
        !           470:                for (i = 0; i < width; i++)
        !           471:                    *((uae_u16 *)dstp + i) = picasso_vidinfo.clut[srcp[i]];
        !           472:                break;
        !           473:             case 4:
        !           474:                for (i = 0; i < width; i++)
        !           475:                    *((uae_u32 *)dstp + i) = picasso_vidinfo.clut[srcp[i]];
        !           476:                break;
        !           477:             default:
        !           478:                abort ();                       
        !           479:            }
        !           480:            srcp += src_rowbytes;
        !           481:            dstp += picasso_vidinfo.rowbytes;
        !           482:        }
1.1       root      483:     }
1.1.1.2 ! root      484:     out:
        !           485:     gfx_unlock_picasso ();
1.1       root      486: }
                    487: 
                    488: /*
                    489:  * Invert a rectangle on the screen.  src and src_rowbytes describe the
                    490:  * inverted rectangle in the frame buffer, so that do_blit can be used if
                    491:  * there is no OS specific function to fill the rectangle.
                    492:  */
                    493: 
                    494: static void do_invertrect (uae_u8 *src, unsigned long src_rowbytes,
                    495:                           int x, int y, int width, int height)
                    496: {
1.1.1.2 ! root      497:     /* TODO: Try OS specific invertrect function here; and return if successful.  */
1.1       root      498: 
                    499:     do_blit (src, src_rowbytes, 0, 0, x, y, width, height, 0);
                    500: }
                    501: 
                    502: static uaecptr wgfx_linestart;
                    503: static uaecptr wgfx_lineend;
                    504: static uaecptr wgfx_min, wgfx_max;
                    505: static unsigned long wgfx_y;
                    506: 
                    507: static void wgfx_do_flushline (void)
                    508: {
                    509:     uae_u8 *src, *dstp;
                    510: 
                    511:     DX_Invalidate (wgfx_y, wgfx_y);
                    512:     if (! picasso_vidinfo.extra_mem)
                    513:        goto out;
                    514: 
1.1.1.2 ! root      515:     dstp = gfx_lock_picasso ();
1.1       root      516:     if (dstp == 0)
                    517:        goto out;
                    518:     /*printf("flushing %d (%x %x %x)\n", wgfx_y, wgfx_linestart, wgfx_min, wgfx_max); */
1.1.1.2 ! root      519:     src = gfxmemory + wgfx_min;
1.1       root      520: 
1.1.1.2 ! root      521:     if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
        !           522:        dstp += wgfx_y * picasso_vidinfo.rowbytes + wgfx_min - wgfx_linestart;
        !           523:        memcpy (dstp, src, wgfx_max - wgfx_min);
        !           524:     } else {
        !           525:        int width = wgfx_max - wgfx_min;
        !           526:        int i;
        !           527:        int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
        !           528: 
        !           529:        if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
        !           530:            abort ();
        !           531: 
        !           532:        dstp += wgfx_y * picasso_vidinfo.rowbytes + (wgfx_min - wgfx_linestart) * psiz;
        !           533:        switch (psiz) {
        !           534:         case 2:
        !           535:            for (i = 0; i < width; i++)
        !           536:                *((uae_u16 *)dstp + i) = picasso_vidinfo.clut[src[i]];
        !           537:            break;
        !           538:         case 4:
        !           539:            for (i = 0; i < width; i++)
        !           540:                *((uae_u32 *)dstp + i) = picasso_vidinfo.clut[src[i]];
        !           541:            break;
        !           542:         default:
        !           543:            abort ();                   
        !           544:        }
        !           545:     }
1.1       root      546: 
                    547:     out:
1.1.1.2 ! root      548:     gfx_unlock_picasso ();
1.1       root      549:     wgfx_linestart = 0xFFFFFFFF;
                    550: }
                    551: 
                    552: static __inline__ void wgfx_flushline (void)
                    553: {
1.1.1.2 ! root      554:     if (wgfx_linestart == 0xFFFFFFFF || ! picasso_on)
1.1       root      555:        return;
                    556:     wgfx_do_flushline ();
                    557: }
                    558: 
                    559: static int renderinfo_is_current_screen (struct RenderInfo *ri)
                    560: {
                    561:     if (! picasso_on)
                    562:        return 0;
                    563:     if (ri->Memory != gfxmemory + (picasso96_state.Address - gfxmem_start)) {
                    564:        return 0;
                    565:     }
                    566:     return 1;
                    567: }
                    568: 
                    569: /* Clear our screen, since we've got a new Picasso screen-mode, and refresh with the proper contents
1.1.1.2 ! root      570:  * This is called on several occasions:
        !           571:  * 1. Amiga-->Picasso transition, via SetSwitch()
        !           572:  * 2. Picasso-->Picasso transition, via SetPanning().
        !           573:  * 3. whenever the graphics code notifies us that the screen contents have been lost.
        !           574:  */
        !           575: void picasso_refresh (void)
1.1       root      576: {
                    577:     struct RenderInfo ri;
                    578: 
                    579:     if (! picasso_on)
                    580:        return;
                    581: 
                    582:     /* Make sure that the first time we show a Picasso video mode, we don't blit any crap.
                    583:      * We can do this by checking if we have an Address yet.  */
                    584:     if (picasso96_state.Address) {
                    585:        /* blit the stuff from our static frame-buffer to the gfx-card */
                    586:        uae_u8 *ptr = gfxmemory + (picasso96_state.Address - gfxmem_start);
                    587:        ri.BytesPerRow = picasso96_state.BytesPerRow;
                    588:        ri.RGBFormat = picasso96_state.RGBFormat;
                    589:        do_blit (ptr, picasso96_state.BytesPerRow, 0, 0, 0, 0,
                    590:                 picasso96_state.Width, picasso96_state.Height, 0);
1.1.1.2 ! root      591:        write_log ("picasso_refresh() successful.\n");
1.1       root      592:     } else
1.1.1.2 ! root      593:        write_log ("ERROR - picasso_refresh() can't refresh!\n");
1.1       root      594: }
                    595: 
                    596: /*
                    597:  * BOOL FindCard(struct BoardInfo *bi);       and
                    598:  *
                    599:  * FindCard is called in the first stage of the board initialisation and
                    600:  * configuration and is used to look if there is a free and unconfigured
                    601:  * board of the type the driver is capable of managing. If it finds one,
                    602:  * it immediately reserves it for use by Picasso96, usually by clearing
                    603:  * the CDB_CONFIGME bit in the flags field of the ConfigDev struct of
                    604:  * this expansion card. But this is only a common example, a driver can
                    605:  * do whatever it wants to mark this card as used by the driver. This
                    606:  * mechanism is intended to ensure that a board is only configured and
                    607:  * used by one driver. FindBoard also usually fills some fields of the
                    608:  * BoardInfo struct supplied by the caller, the rtg.library, for example
                    609:  * the MemoryBase, MemorySize and RegisterBase fields.
                    610:  */
                    611: uae_u32 picasso_FindCard (void)
                    612: {
1.1.1.2 ! root      613:     uaecptr AmigaBoardInfo = m68k_areg (regs, 0);
1.1       root      614:     /* NOTES: See BoardInfo struct definition in Picasso96 dev info */
                    615: 
1.1.1.2 ! root      616:     if (allocated_gfxmem && !picasso96_state.CardFound) {
1.1       root      617:        /* Fill in MemoryBase, MemorySize */
1.1.1.2 ! root      618:        put_long (AmigaBoardInfo + PSSO_BoardInfo_MemoryBase, gfxmem_start);
1.1       root      619:        /* size of memory, minus a 32K chunk: 16K for pattern bitmaps, 16K for resolution list */
1.1.1.2 ! root      620:        put_long (AmigaBoardInfo + PSSO_BoardInfo_MemorySize, allocated_gfxmem - 32768);
1.1       root      621: 
                    622:        picasso96_state.CardFound = 1; /* mark our "card" as being found */
                    623:        return -1;
                    624:     } else
                    625:        return 0;
                    626: }
                    627: 
                    628: static void FillBoardInfo (uaecptr amigamemptr, struct LibResolution *res, struct PicassoResolution *dm)
                    629: {
                    630:     char *uaememptr;
                    631:     switch (dm->depth) {
                    632:     case 1:
                    633:        res->Modes[CHUNKY] = amigamemptr;
                    634:        break;
                    635:     case 2:
                    636:        res->Modes[HICOLOR] = amigamemptr;
                    637:        break;
                    638:     case 3:
                    639:        res->Modes[TRUECOLOR] = amigamemptr;
                    640:        break;
                    641:     default:
                    642:        res->Modes[TRUEALPHA] = amigamemptr;
                    643:        break;
                    644:     }
                    645:     uaememptr = gfxmem_xlate(amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
                    646:     memset(uaememptr, 0, PSSO_ModeInfo_sizeof); /* zero out our ModeInfo struct */
                    647: 
1.1.1.2 ! root      648:     put_word (amigamemptr + PSSO_ModeInfo_Width, dm->res.width);
        !           649:     put_word (amigamemptr + PSSO_ModeInfo_Height, dm->res.height);
        !           650:     put_byte (amigamemptr + PSSO_ModeInfo_Depth, dm->depth * 8);
        !           651:     put_byte (amigamemptr + PSSO_ModeInfo_Flags, 0);
        !           652:     put_word (amigamemptr + PSSO_ModeInfo_HorTotal, dm->res.width);
        !           653:     put_word (amigamemptr + PSSO_ModeInfo_HorBlankSize, 0);
        !           654:     put_word (amigamemptr + PSSO_ModeInfo_HorSyncStart, 0);
        !           655:     put_word (amigamemptr + PSSO_ModeInfo_HorSyncSize, 0);
        !           656:     put_byte (amigamemptr + PSSO_ModeInfo_HorSyncSkew, 0);
        !           657:     put_byte (amigamemptr + PSSO_ModeInfo_HorEnableSkew, 0);
        !           658: 
        !           659:     put_word (amigamemptr + PSSO_ModeInfo_VerTotal, dm->res.height);
        !           660:     put_word (amigamemptr + PSSO_ModeInfo_VerBlankSize, 0);
        !           661:     put_word (amigamemptr + PSSO_ModeInfo_VerSyncStart, 0);
        !           662:     put_word (amigamemptr + PSSO_ModeInfo_VerSyncSize, 0);
1.1       root      663: 
1.1.1.2 ! root      664:     put_byte (amigamemptr + PSSO_ModeInfo_first_union, 98);
        !           665:     put_byte (amigamemptr + PSSO_ModeInfo_second_union, 14);
1.1       root      666: 
1.1.1.2 ! root      667:     put_long (amigamemptr + PSSO_ModeInfo_PixelClock, dm->res.width * dm->res.height * dm->refresh);
1.1       root      668: }
                    669: 
                    670: /****************************************
                    671: * InitCard()
                    672: *
                    673: * a2: BoardInfo structure ptr - Amiga-based address in Intel endian-format
                    674: *
                    675: * Job - fill in the following structure members:
                    676: * gbi_RGBFormats: the pixel formats that the host-OS of UAE supports
                    677: *     If UAE is running in a window, it should ONLY report the pixel format of the host-OS desktop
                    678: *     If UAE is running full-screen, it should report ALL pixel formats that the host-OS can handle in full-screen
                    679: *     NOTE: If full-screen, and the user toggles to windowed-mode, all hell will break loose visually.  Must inform
                    680: *           user that they're doing something stupid (unless their desktop and full-screen colour modes match).
                    681: * gbi_SoftSpriteFlags: should be the same as above for now, until actual cursor support is added
                    682: * gbi_BitsPerCannon: could be 6 or 8 or ???, depending on the host-OS gfx-card
                    683: * gbi_MaxHorResolution: fill this in for all modes (even if you don't support them)
                    684: * gbi_MaxVerResolution: fill this in for all modes (even if you don't support them)
                    685: */
                    686: uae_u32 picasso_InitCard (void)
                    687: {
                    688:     struct LibResolution res;
                    689:     int i;
                    690:     int ModeInfoStructureCount = 1, LibResolutionStructureCount = 0;
                    691:     uaecptr amigamemptr = 0;
1.1.1.2 ! root      692:     uaecptr AmigaBoardInfo = m68k_areg (regs, 2);
        !           693:     put_word (AmigaBoardInfo + PSSO_BoardInfo_BitsPerCannon, DX_BitsPerCannon());
        !           694:     put_word (AmigaBoardInfo + PSSO_BoardInfo_RGBFormats, picasso96_pixel_format);
        !           695:     put_word (AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, picasso96_pixel_format);
        !           696:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 0, planar.width);
        !           697:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 2, chunky.width);
        !           698:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 4, hicolour.width);
        !           699:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 6, truecolour.width);
        !           700:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 8, alphacolour.width);
        !           701:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 0, planar.height);
        !           702:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 2, chunky.height);
        !           703:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 4, hicolour.height);
        !           704:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 6, truecolour.height);
        !           705:     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 8, alphacolour.height);
1.1       root      706: 
                    707:     for (i = 0; i < mode_count;) {
                    708:        int j = i;
                    709:        /* Add a LibResolution structure to the ResolutionsList MinList in our BoardInfo */
                    710:        res.DisplayID = 0x50001000 + LibResolutionStructureCount * 0x10000;
                    711:        res.BoardInfo = AmigaBoardInfo;
                    712:        res.Width = DisplayModes[i].res.width;
                    713:        res.Height = DisplayModes[i].res.height;
                    714:        res.Flags = P96F_PUBLIC;
                    715:        res.P96ID[0] = 'P';
                    716:        res.P96ID[1] = '9';
                    717:        res.P96ID[2] = '6';
                    718:        res.P96ID[3] = '-';
                    719:        res.P96ID[4] = '0';
                    720:        res.P96ID[5] = ':';
                    721:        strcpy (res.Name, "uaegfx:");
                    722:        strncat (res.Name, DisplayModes[i].name, strchr(DisplayModes[i].name, ',') - DisplayModes[i].name);
                    723:        res.Modes[PLANAR] = 0;
                    724:        res.Modes[CHUNKY] = 0;
                    725:        res.Modes[HICOLOR] = 0;
                    726:        res.Modes[TRUECOLOR] = 0;
                    727:        res.Modes[TRUEALPHA] = 0;
                    728: 
                    729:        do {
                    730:            /* Handle this display mode's depth */
1.1.1.2 ! root      731:            amigamemptr = gfxmem_start + allocated_gfxmem - (PSSO_ModeInfo_sizeof * ModeInfoStructureCount++);
1.1       root      732:            FillBoardInfo(amigamemptr, &res, &DisplayModes[i]);
                    733:            i++;
                    734:        } while (i < mode_count
                    735:                 && DisplayModes[i].res.width == DisplayModes[j].res.width
                    736:                 && DisplayModes[i].res.height == DisplayModes[j].res.height);
                    737: 
1.1.1.2 ! root      738:        amigamemptr = gfxmem_start + allocated_gfxmem - 16384 + (PSSO_LibResolution_sizeof * LibResolutionStructureCount++);
1.1       root      739:        CopyLibResolutionStructureU2A (&res, amigamemptr);
                    740:        DumpLibResolutionStructure( amigamemptr);
                    741:        AmigaListAddTail (AmigaBoardInfo + PSSO_BoardInfo_ResolutionsList, amigamemptr);
                    742:     }
                    743: 
                    744:     return 0;
                    745: }
                    746: 
                    747: extern int x_size, y_size;
                    748: 
                    749: /*
                    750:  * SetSwitch:
                    751:  * a0: struct BoardInfo
                    752:  * d0.w:       BOOL state
                    753:  * this function should set a board switch to let the Amiga signal pass
                    754:  * through when supplied with a 0 in d0 and to show the board signal if
                    755:  * a 1 is passed in d0. You should remember the current state of the
                    756:  * switch to avoid unneeded switching. If your board has no switch, then
                    757:  * simply supply a function that does nothing except a RTS.
                    758:  *
                    759:  * NOTE: Return the opposite of the switch-state. BDK
                    760: */
                    761: uae_u32 picasso_SetSwitch (void)
                    762: {
1.1.1.2 ! root      763:     uae_u16 flag = m68k_dreg (regs, 0) & 0xFFFF;
1.1       root      764: 
                    765:     /* Do not switch immediately.  Tell the custom chip emulation about the
                    766:      * desired state, and wait for custom.c to call picasso_enablescreen
                    767:      * whenever it is ready to change the screen state.  */
                    768:     picasso_requested_on = !!flag;
1.1.1.2 ! root      769:     write_log ("SetSwitch() - trying to show %s screen\n", flag ? "picasso96":"amiga");
1.1       root      770: 
                    771:     /* Put old switch-state in D0 */
                    772:     return !flag;
                    773: }
                    774: 
                    775: void picasso_enablescreen (int on)
                    776: {
                    777:     wgfx_linestart = 0xFFFFFFFF;
                    778:     picasso_refresh ();
1.1.1.2 ! root      779:     write_log ("SetSwitch() - showing %s screen\n", on ? "picasso96": "amiga");
1.1       root      780: }
                    781: 
                    782: /*
                    783:  * SetColorArray:
                    784:  * a0: struct BoardInfo
                    785:  * d0.w: startindex
                    786:  * d1.w: count
                    787:  * when this function is called, your driver has to fetch "count" color
                    788:  * values starting at "startindex" from the CLUT field of the BoardInfo
                    789:  * structure and write them to the hardware. The color values are always
                    790:  * between 0 and 255 for each component regardless of the number of bits
                    791:  * per cannon your board has. So you might have to shift the colors
                    792:  * before writing them to the hardware.
                    793:  */
                    794: uae_u32 picasso_SetColorArray (void)
                    795: {
                    796:     /* Fill in some static UAE related structure about this new CLUT setting
                    797:      * We need this for CLUT-based displays, and for mapping CLUT to hi/true colour */
1.1.1.2 ! root      798:     uae_u16 start = m68k_dreg (regs, 0);
        !           799:     uae_u16 count = m68k_dreg (regs, 1);
1.1       root      800:     int i;
1.1.1.2 ! root      801:     uaecptr boardinfo = m68k_areg (regs, 0);
1.1       root      802:     uaecptr clut = boardinfo + PSSO_BoardInfo_CLUT + start * 3;
1.1.1.2 ! root      803:     int changed = 0;
1.1       root      804: 
                    805:     for (i = start; i < start + count; i++) {
1.1.1.2 ! root      806:        int r = get_byte (clut);
        !           807:        int g = get_byte (clut + 1);
        !           808:        int b = get_byte (clut + 2);
        !           809: 
        !           810:        changed |= (picasso96_state.CLUT[i].Red != r 
        !           811:                    || picasso96_state.CLUT[i].Green != g
        !           812:                    || picasso96_state.CLUT[i].Blue != b);
        !           813:        
        !           814:        picasso96_state.CLUT[i].Red = r; 
        !           815:        picasso96_state.CLUT[i].Green = g;
        !           816:        picasso96_state.CLUT[i].Blue = b;
1.1       root      817:        clut += 3;
                    818:     }
1.1.1.2 ! root      819:     if (changed) {
        !           820:        DX_SetPalette (start, count);
1.1       root      821:     }
1.1.1.2 ! root      822:     /*write_log ("SetColorArray(%d,%d)\n", start, count); */
        !           823:     return m68k_dreg (regs, 0);
1.1       root      824: }
                    825: 
                    826: /*
                    827:  * SetDAC:
                    828:  * a0: struct BoardInfo
                    829:  * d7: RGBFTYPE RGBFormat
                    830:  * This function is called whenever the RGB format of the display changes,
                    831:  * e.g. from chunky to TrueColor. Usually, all you have to do is to set
                    832:  * the RAMDAC of your board accordingly.
                    833:  */
                    834: uae_u32 picasso_SetDAC (void)
                    835: {
                    836:     /* Fill in some static UAE related structure about this new DAC setting
                    837:      * Lets us keep track of what pixel format the Amiga is thinking about in our frame-buffer */
                    838: 
1.1.1.2 ! root      839:     write_log ("SetDAC()\n");
        !           840:     return m68k_dreg (regs, 0);
1.1       root      841: }
                    842: 
                    843: /*
                    844:  * SetGC:
                    845:  * a0: struct BoardInfo
                    846:  * a1: struct ModeInfo
                    847:  * d0: BOOL Border
                    848:  * This function is called whenever another ModeInfo has to be set. This
                    849:  * function simply sets up the CRTC and TS registers to generate the
                    850:  * timing used for that screen mode. You should not set the DAC, clocks
                    851:  * or linear start adress. They will be set when appropriate by their
                    852:  * own functions.
                    853:  */
                    854: uae_u32 picasso_SetGC (void)
                    855: {
                    856:     /* Fill in some static UAE related structure about this new ModeInfo setting */
1.1.1.2 ! root      857:     uaecptr modeinfo = m68k_areg (regs, 1);
1.1       root      858: 
                    859:     picasso96_state.Width = get_word (modeinfo + PSSO_ModeInfo_Width);
                    860:     picasso96_state.VirtualWidth = picasso96_state.Width; /* in case SetPanning doesn't get called */
                    861: 
                    862:     picasso96_state.Height = get_word (modeinfo + PSSO_ModeInfo_Height);
                    863:     picasso96_state.VirtualHeight = picasso96_state.Height;
                    864: 
                    865:     picasso96_state.GC_Depth = get_byte (modeinfo + PSSO_ModeInfo_Depth);
                    866:     picasso96_state.GC_Flags = get_byte (modeinfo + PSSO_ModeInfo_Flags);
                    867: 
1.1.1.2 ! root      868:     write_log ("SetGC(%d,%d,%d)\n", picasso96_state.Width, picasso96_state.Height, picasso96_state.GC_Depth);
1.1       root      869: 
                    870:     gfx_set_picasso_modeinfo (picasso96_state.Width, picasso96_state.Height,
1.1.1.2 ! root      871:                              picasso96_state.GC_Depth, picasso96_state.RGBFormat);
1.1       root      872:     wgfx_linestart = 0xFFFFFFFF;
                    873:     picasso_refresh ();
                    874: 
1.1.1.2 ! root      875:     return m68k_dreg (regs, 0);
1.1       root      876: }
                    877: 
                    878: /*
                    879:  * SetPanning:
                    880:  * a0: struct BoardInfo
                    881:  * a1: UBYTE *Memory
                    882:  * d0: uae_u16 Width
                    883:  * d1: WORD XOffset
                    884:  * d2: WORD YOffset
                    885:  * d7: RGBFTYPE RGBFormat
                    886:  * This function sets the view origin of a display which might also be
                    887:  * overscanned. In register a1 you get the start address of the screen
                    888:  * bitmap on the Amiga side. You will have to subtract the starting
                    889:  * address of the board memory from that value to get the memory start
                    890:  * offset within the board. Then you get the offset in pixels of the
                    891:  * left upper edge of the visible part of an overscanned display. From
                    892:  * these values you will have to calculate the LinearStartingAddress
                    893:  * fields of the CRTC registers.
                    894: 
                    895:  * NOTE: SetPanning() can be used to know when a Picasso96 screen is
                    896:  * being opened.  Better to do the appropriate clearing of the
                    897:  * background here than in SetSwitch() derived functions,
                    898:  * because SetSwitch() is not called for subsequent Picasso screens.
                    899:  */
                    900: uae_u32 picasso_SetPanning (void)
                    901: {
1.1.1.2 ! root      902:     uae_u16 Width = m68k_dreg (regs, 0);
        !           903:     uaecptr start_of_screen = m68k_areg (regs, 1);
1.1       root      904: 
                    905:     picasso96_state.Address = start_of_screen; /* Amiga-side address */
1.1.1.2 ! root      906:     picasso96_state.XOffset = (uae_s16)m68k_dreg (regs, 1);
        !           907:     picasso96_state.YOffset = (uae_s16)m68k_dreg (regs, 2);
1.1       root      908:     picasso96_state.VirtualWidth = Width;
1.1.1.2 ! root      909:     picasso96_state.RGBFormat = m68k_dreg (regs, 7);
        !           910:     picasso96_state.BytesPerPixel = GetBytesPerPixel (picasso96_state.RGBFormat);
1.1       root      911:     picasso96_state.BytesPerRow = Width * picasso96_state.BytesPerPixel;
                    912: 
                    913:     /* I assume SetGC() has been called, so I can calculate the Extent */
                    914:     picasso96_state.Extent = picasso96_state.Address + (picasso96_state.BytesPerRow * picasso96_state.Height);
                    915: 
1.1.1.2 ! root      916:     write_log ("SetPanning(%d, %d, %d) Start 0x%x, BPR %d\n",
        !           917:                        Width, picasso96_state.XOffset, picasso96_state.YOffset,
1.1       root      918:                        start_of_screen, picasso96_state.BytesPerRow);
1.1.1.2 ! root      919:     gfx_set_picasso_modeinfo (picasso96_state.Width, picasso96_state.Height,
        !           920:                              picasso96_state.GC_Depth, picasso96_state.RGBFormat);
        !           921:     DX_SetPalette (0, 256);
1.1       root      922: 
                    923:     wgfx_linestart = 0xFFFFFFFF;
                    924:     picasso_refresh ();
                    925: 
1.1.1.2 ! root      926:     return m68k_dreg (regs, 0);
1.1       root      927: }
                    928: 
                    929: static void do_xor8 (uae_u8 *ptr, long len, uae_u32 val)
                    930: {
                    931:     int i;
                    932: #if 0 && defined ALIGN_POINTER_TO32
                    933:     int align_adjust = ALIGN_POINTER_TO32(ptr);
                    934:     int len2;
                    935: 
                    936:     len -= align_adjust;
                    937:     while (align_adjust) {
                    938:        *ptr ^= val;
                    939:        ptr++;
                    940:        align_adjust--;
                    941:     }
                    942:     len2 = len >> 2;
                    943:     len -= len2 << 2;
                    944:     for (i = 0; i < len2; i++, ptr += 4) {
                    945:        *(uae_u32 *)ptr ^= val;
                    946:     }
                    947:     while (len) {
                    948:        *ptr ^= val;
                    949:        ptr++;
                    950:        len--;
                    951:     }
                    952:     return;
                    953: #endif
                    954:     for (i = 0; i < len; i++, ptr++) {
                    955:        do_put_mem_byte (ptr, do_get_mem_byte (ptr) ^ val);
                    956:     }
                    957: }
                    958: 
                    959: /*
                    960:  * InvertRect:
                    961:  * 
                    962:  * Inputs:
                    963:  * a0:struct BoardInfo *bi
                    964:  * a1:struct RenderInfo *ri
                    965:  * d0.w:X
                    966:  * d1.w:Y
                    967:  * d2.w:Width
                    968:  * d3.w:Height
                    969:  * d4.l:Mask
                    970:  * d7.l:RGBFormat
                    971:  * 
                    972:  * This function is used to invert a rectangular area on the board. It is called by BltBitMap,
                    973:  * BltPattern and BltTemplate.
                    974:  */
                    975: uae_u32 picasso_InvertRect (void)
                    976: {
1.1.1.2 ! root      977:     uaecptr renderinfo = m68k_areg (regs, 1);
        !           978:     long X = (uae_u16)m68k_dreg (regs, 0);
        !           979:     long Y = (uae_u16)m68k_dreg (regs, 1);
        !           980:     long Width = (uae_u16)m68k_dreg (regs, 2);
        !           981:     long Height = (uae_u16)m68k_dreg (regs, 3);
        !           982:     uae_u32 mask = m68k_dreg (regs, 4);
        !           983:     int Bpp = GetBytesPerPixel (m68k_dreg (regs, 7));
1.1       root      984:     uae_u32 xorval;
                    985:     int lines;
                    986:     struct RenderInfo ri;
                    987:     uae_u8 *uae_mem, *rectstart;
                    988:     long width_in_bytes;
                    989: 
                    990:     wgfx_flushline ();
                    991: 
1.1.1.2 ! root      992:     if (! CopyRenderInfoStructureA2U (renderinfo, &ri))
1.1       root      993:        return 0;
                    994: 
1.1.1.2 ! root      995:     /*write_log ("InvertRect %d %lx\n", Bpp, (long)mask);*/
1.1       root      996: 
                    997:     /* ??? Brian? mask used to be 32 bit, but it appears that only 8 bit
                    998:      * values are passed to this function.  This code here seems to work
                    999:      * much better... */
                   1000:     if (mask != 0xFF && Bpp > 8) {
1.1.1.2 ! root     1001:        write_log ("InvertRect: not obeying mask 0x%x properly with Bpp %d.\n", mask, Bpp);
1.1       root     1002:        mask = 0xFF;
                   1003:     }
                   1004:     if ((mask & ~0xFF) != 0) {
1.1.1.2 ! root     1005:        write_log ("InvertRect: mask has high bits set!\n");
1.1       root     1006:     }
                   1007:     xorval = 0x01010101 * (mask & 0xFF);
                   1008:     width_in_bytes = Bpp * Width;
                   1009:     rectstart = uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
                   1010: 
1.1.1.2 ! root     1011:     for (lines = 0; lines < Height; lines++, uae_mem += ri.BytesPerRow)
1.1       root     1012:        do_xor8 (uae_mem, width_in_bytes, xorval);
1.1.1.2 ! root     1013: 
1.1       root     1014:     if (renderinfo_is_current_screen (&ri)) {
                   1015:        if (mask == 0xFF)
                   1016:            do_invertrect (rectstart, ri.BytesPerRow, X, Y, Width, Height);
                   1017:        else
                   1018:            do_blit (rectstart, ri.BytesPerRow, 0, 0, X, Y, Width, Height, 0);
                   1019:     }
                   1020: 
                   1021:     return 1; /* 1 if supported, 0 otherwise */
                   1022: }
                   1023: 
                   1024: /***********************************************************
                   1025: FillRect:
                   1026: ***********************************************************
                   1027: * a0:  struct BoardInfo *
                   1028: * a1:  struct RenderInfo *
                   1029: * d0:  WORD X
                   1030: * d1:  WORD Y
                   1031: * d2:  WORD Width
                   1032: * d3:  WORD Height
                   1033: * d4:  uae_u32 Pen
                   1034: * d5:  UBYTE Mask
                   1035: * d7:  uae_u32 RGBFormat
                   1036: ***********************************************************/
                   1037: uae_u32 picasso_FillRect (void)
                   1038: {
1.1.1.2 ! root     1039:     uaecptr renderinfo = m68k_areg (regs, 1);
        !          1040:     unsigned long X = (uae_u16)m68k_dreg (regs, 0);
        !          1041:     unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
        !          1042:     unsigned long Width = (uae_u16)m68k_dreg (regs, 2);
        !          1043:     unsigned long Height = (uae_u16)m68k_dreg (regs, 3);
        !          1044:     uae_u32 Pen = m68k_dreg (regs, 4);
        !          1045:     uae_u8 Mask = (uae_u8)m68k_dreg (regs, 5);
        !          1046:     uae_u32 RGBFormat = m68k_dreg (regs, 7);
1.1       root     1047: 
                   1048:     uae_u8 *src, *dst;
                   1049:     uae_u8 *start, *oldstart;
                   1050:     unsigned long lines, cols;
                   1051:     int Bpp;
                   1052:     struct RenderInfo ri;
                   1053: 
                   1054:     wgfx_flushline ();
                   1055: 
1.1.1.2 ! root     1056:     if (! CopyRenderInfoStructureA2U (renderinfo, &ri) || Y == 0xFFFF)
1.1       root     1057:        return 0;
                   1058: 
                   1059:     if (ri.RGBFormat != RGBFormat)
1.1.1.2 ! root     1060:        write_log ("Weird Stuff!\n");
1.1       root     1061: 
1.1.1.2 ! root     1062:     Bpp = GetBytesPerPixel (RGBFormat);
1.1       root     1063: 
1.1.1.2 ! root     1064:     /*write_log ("FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d Mask 0x%x\n",
1.1       root     1065:                          X, Y, Width, Height, Pen, Bpp, ri.BytesPerRow, Mask); */
                   1066: 
                   1067:     if (Mask == 0xFF) {
                   1068:        /* Do our virtual frame-buffer memory.  First, we do a single line fill by hand */
                   1069:        oldstart = start = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
                   1070:        switch (Bpp) {
                   1071:         case 1:
                   1072:            memset (start, Pen, Width);
                   1073:            break;
                   1074:         case 2:
                   1075:            for (cols = 0; cols < Width; cols++) {
                   1076:                do_put_mem_word ((uae_u16 *)start, Pen);
                   1077:                start += 2;
                   1078:            }
                   1079:            break;
                   1080:         case 3:
                   1081:            for (cols = 0; cols < Width; cols++) {
                   1082:                do_put_mem_byte (start, Pen & 0x000000FF);
                   1083:                start++;
                   1084:                *(uae_u16 *)(start) = (Pen & 0x00FFFF00) >> 8;
                   1085:                start+=2;
                   1086:            }
                   1087:            break;
                   1088:         case 4:
                   1089:            for (cols = 0; cols < Width; cols++) {
                   1090:                /**start = Pen; */
                   1091:                do_put_mem_long ((uae_u32 *)start, Pen);
                   1092:                start += 4;
                   1093:            }
                   1094:            break;
                   1095:        }
                   1096:        src = oldstart;
                   1097:        dst = src + ri.BytesPerRow;
                   1098:        /* next, we do the remaining line fills via memcpy() */
                   1099:        for (lines = 0; lines < (Height - 1); lines++, dst += ri.BytesPerRow)
1.1.1.2 ! root     1100:            memcpy (dst, src, Width * Bpp);
1.1       root     1101: 
1.1.1.2 ! root     1102:        if (renderinfo_is_current_screen (&ri))
1.1       root     1103:            do_fillrect (src, X, Y, Width, Height);
1.1.1.2 ! root     1104: 
1.1       root     1105:        return 1;
                   1106:     }
                   1107: 
                   1108:     /* We get here only if Mask != 0xFF */
                   1109:     if (Bpp != 1) {
                   1110:        write_log ("Picasso: mask != 0xFF in truecolor mode!\n");
                   1111:        return 0;
                   1112:     }
                   1113:     Pen &= Mask;
                   1114:     Mask = ~Mask;
                   1115: 
                   1116:     oldstart = start = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
                   1117:     for (lines = 0; lines < Height; lines++, start += ri.BytesPerRow) {
                   1118:        uae_u8 *p = start;
                   1119:        for (cols = 0; cols < Width; cols++) {
                   1120:            uae_u32 tmpval = do_get_mem_byte (p) & Mask;
                   1121:            do_put_mem_byte (p, Pen | tmpval);
                   1122:            p++;
                   1123:        }
                   1124:     }
                   1125:     if (renderinfo_is_current_screen (&ri))
                   1126:        do_blit (oldstart, ri.BytesPerRow, 0, 0, X, Y, Width, Height, 0);
                   1127: 
                   1128:     return 1;
                   1129: }
                   1130: 
                   1131: /*
                   1132:  * BlitRect() is a generic (any chunky pixel format) rectangle copier
                   1133:  * NOTE: If dstri is NULL, then we're only dealing with one RenderInfo area, and called from picasso_BlitRect()
                   1134:  */
                   1135: static void BlitRect (struct RenderInfo *ri, struct RenderInfo *dstri,
                   1136:                      uae_u16 srcx, uae_u16 srcy, uae_u16 dstx, uae_u16 dsty,
                   1137:                      uae_u16 width, uae_u16 height, uae_u8 mask)
                   1138: {
                   1139:     uae_u8 *src, *dst, *tmp, *tmp2, *tmp3;
                   1140:     int lines;
                   1141:     uae_u8 Bpp = GetBytesPerPixel(ri->RGBFormat);
                   1142:     uae_u8 *blitsrc;
                   1143:     unsigned long total_width = width * Bpp;
                   1144:     unsigned long linewidth = (total_width + 15) & ~15;
                   1145:     int cant_blit = 1;
                   1146: 
                   1147:     /*
                   1148:      * If we have no destination RenderInfo, then we're dealing with a single-buffer action, called
                   1149:      * from picasso_BlitRect().  The code up to the DX_xxxxx() functions deals with the frame-buffer,
                   1150:      * while the DX_ functions actually deal with the visible screen.
                   1151:      *
                   1152:      * If we have a destination RenderInfo, then we've been called from picasso_BlitRectNoMaskComplete()
                   1153:      * and we need to put the results on the screen from the frame-buffer.
                   1154:      */
                   1155:     if (dstri == NULL) {
                   1156:        dstri = ri;
                   1157:        cant_blit = 0;
                   1158:     }
                   1159: 
                   1160:     /* Do our virtual frame-buffer memory first */
                   1161:     src = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow;
                   1162:     dst = dstri->Memory + dstx*Bpp + dsty*dstri->BytesPerRow;
                   1163:     blitsrc = dst;
                   1164:     if (mask != 0xFF && Bpp > 1)
1.1.1.2 ! root     1165:        write_log ("ERROR - not obeying BlitRect() mask 0x%x properly with Bpp %d.\n", mask, Bpp);
1.1       root     1166: 
                   1167:     if (mask == 0xFF || Bpp > 1) {
                   1168:        /* handle normal case efficiently */
                   1169:        if (ri->Memory == dstri->Memory && dsty == srcy) {
                   1170:            int i;
                   1171:            for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
                   1172:                memmove (dst, src, total_width);
                   1173:        } else if (dsty < srcy) {
                   1174:            int i;
                   1175:            for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
                   1176:                memcpy (dst, src, total_width);
                   1177:        } else {
                   1178:            int i;
                   1179:            src += (height-1) * ri->BytesPerRow;
                   1180:            dst += (height-1) * dstri->BytesPerRow;
                   1181:            for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow)
                   1182:                memcpy (dst, src, total_width);
                   1183:        }
                   1184:        if (renderinfo_is_current_screen (dstri))
                   1185:            do_blit (blitsrc, dstri->BytesPerRow, srcx, srcy, dstx, dsty,
                   1186:                     width, height, ! cant_blit);
                   1187:        return;
                   1188:     }
                   1189: 
                   1190:     tmp3 = tmp2 = tmp = xmalloc (linewidth * height); /* allocate enough memory for the src-rect */
                   1191:     if (!tmp)
                   1192:        return;
                   1193: 
                   1194:     /* copy the src-rect into our temporary buffer space */
                   1195:     for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 += linewidth) {
                   1196:        memcpy (tmp2, src, total_width);
                   1197:     }
                   1198: 
                   1199:     /* copy the temporary buffer to the destination */
                   1200:     for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp += linewidth) {
                   1201:        int cols;
                   1202:        for (cols = 0; cols < width; cols++) {
                   1203:            dst[cols] &= ~mask;
                   1204:            dst[cols] |= tmp[cols] & mask;
                   1205:        }
                   1206:     }
                   1207:     if (renderinfo_is_current_screen (dstri))
                   1208:        do_blit (blitsrc, dstri->BytesPerRow, srcx, srcy, dstx, dsty,
                   1209:                 width, height, 0);
                   1210:     /* free the temp-buf */
                   1211:     free (tmp3);
                   1212: 
                   1213: }
                   1214: 
                   1215: /***********************************************************
                   1216: BlitRect:
                   1217: ***********************************************************
                   1218: * a0:  struct BoardInfo
                   1219: * a1:  struct RenderInfo
                   1220: * d0:  WORD SrcX
                   1221: * d1:  WORD SrcY
                   1222: * d2:  WORD DstX
                   1223: * d3:  WORD DstY
                   1224: * d4:   WORD Width
                   1225: * d5:   WORD Height
                   1226: * d6:  UBYTE Mask
                   1227: * d7:  uae_u32 RGBFormat
                   1228: ***********************************************************/
                   1229: uae_u32 picasso_BlitRect (void)
                   1230: {
1.1.1.2 ! root     1231:     uaecptr renderinfo = m68k_areg (regs, 1);
        !          1232:     uae_u16 srcx = (uae_u16)m68k_dreg (regs, 0);
        !          1233:     uae_u16 srcy = (uae_u16)m68k_dreg (regs, 1);
        !          1234:     uae_u16 dstx = (uae_u16)m68k_dreg (regs, 2);
        !          1235:     uae_u16 dsty = (uae_u16)m68k_dreg (regs, 3);
        !          1236:     uae_u16 width = (uae_u16)m68k_dreg (regs, 4);
        !          1237:     uae_u16 height = (uae_u16)m68k_dreg (regs, 5);
        !          1238:     uae_u8  Mask = (uae_u8)m68k_dreg (regs, 6);
1.1       root     1239: 
                   1240:     struct RenderInfo ri;
                   1241: 
                   1242:     wgfx_flushline ();
                   1243: 
1.1.1.2 ! root     1244:     if (! CopyRenderInfoStructureA2U (renderinfo, &ri))
1.1       root     1245:        return 0;
                   1246: 
                   1247:     BlitRect(&ri, NULL, srcx, srcy, dstx, dsty, width, height, Mask);
1.1.1.2 ! root     1248:     /*write_log ("BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy, dstx, dsty, width, height, Mask); */
1.1       root     1249: 
                   1250:     return 1;
                   1251: }
                   1252: 
                   1253: /***********************************************************
                   1254: BlitRectNoMaskComplete:
                   1255: ***********************************************************
                   1256: * a0:  struct BoardInfo
                   1257: * a1:  struct RenderInfo (src)
                   1258: * a2:   struct RenderInfo (dst)
                   1259: * d0:  WORD SrcX
                   1260: * d1:  WORD SrcY
                   1261: * d2:  WORD DstX
                   1262: * d3:  WORD DstY
                   1263: * d4:   WORD Width
                   1264: * d5:   WORD Height
                   1265: * d6:  UBYTE OpCode
                   1266: * d7:  uae_u32 RGBFormat
                   1267: * NOTE: MUST return 0 in D0 if we're not handling this operation
                   1268: *       because the RGBFormat or opcode aren't supported.
                   1269: *       OTHERWISE return 1
                   1270: ***********************************************************/
                   1271: uae_u32 picasso_BlitRectNoMaskComplete (void)
                   1272: {
1.1.1.2 ! root     1273:     uaecptr srcri = m68k_areg (regs, 1);
        !          1274:     uaecptr dstri = m68k_areg (regs, 2);
        !          1275:     uae_u16 srcx = m68k_dreg (regs, 0);
        !          1276:     uae_u16 srcy = m68k_dreg (regs, 1);
        !          1277:     uae_u16 dstx = m68k_dreg (regs, 2);
        !          1278:     uae_u16 dsty = m68k_dreg (regs, 3);
        !          1279:     uae_u16 width = m68k_dreg (regs, 4);
        !          1280:     uae_u16 height = m68k_dreg (regs, 5);
        !          1281:     uae_u8 OpCode = m68k_dreg (regs, 6);
        !          1282:     uae_u32 RGBFmt = m68k_dreg (regs, 7);
1.1       root     1283:     struct RenderInfo src_ri, dst_ri;
                   1284: 
                   1285:     wgfx_flushline ();
                   1286: 
1.1.1.2 ! root     1287:     if (! CopyRenderInfoStructureA2U (srcri, &src_ri)
        !          1288:        || ! CopyRenderInfoStructureA2U (dstri, &dst_ri))
1.1       root     1289:        return 0;
                   1290: 
1.1.1.2 ! root     1291:     /*write_log ("BlitRectNoMaskComplete() op 0x%2x, Bpp %d, xy(%4d,%4d) --> xy(%4d,%4d), wh(%4d,%4d)\n",
1.1       root     1292:                          OpCode, Bpp, srcx, srcy, dstx, dsty, width, height); */
1.1.1.2 ! root     1293:     /*write_log ("-- src mem 0x%x BPR %d, dst mem 0x%x BPR %d, screen-mem 0x%x - 0x%x\n",
1.1       root     1294:                          src_ri.Memory, src_ri.BytesPerRow, dst_ri.Memory, dst_ri.BytesPerRow, picasso96_state.Address, picasso96_state.Extent); */
                   1295: 
                   1296:     switch (OpCode) {
                   1297:      case 0x0C:
1.1.1.2 ! root     1298:        BlitRect (&src_ri, &dst_ri, srcx, srcy, dstx, dsty, width, height, 0xFF);
1.1       root     1299:        return 1;
                   1300: 
                   1301:      default:
                   1302:        /* FOR NOW! */
                   1303:        return 0;
                   1304:     }
                   1305: }
                   1306: 
                   1307: /* This utility function is used both by BlitTemplate() and BlitPattern() */
                   1308: static __inline__ void PixelWrite1(uae_u8 *mem, int bits, uae_u32 fgpen, uae_u32 mask)
                   1309: {
                   1310:     if (mask != 0xFF)
                   1311:        fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
                   1312:     do_put_mem_byte (mem + bits, fgpen);
                   1313: }
                   1314: 
                   1315: static __inline__ void PixelWrite2(uae_u8 *mem, int bits, uae_u32 fgpen)
                   1316: {
                   1317:     do_put_mem_word (((uae_u16 *)mem) + bits, fgpen);
                   1318: }
                   1319: 
                   1320: static __inline__ void PixelWrite3(uae_u8 *mem, int bits, uae_u32 fgpen)
                   1321: {
                   1322:     do_put_mem_byte (mem + bits*3, fgpen & 0x000000FF);
                   1323:     *(uae_u16 *)(mem + bits*3+1) = (fgpen & 0x00FFFF00) >> 8;
                   1324: }
                   1325: 
                   1326: static __inline__ void PixelWrite4(uae_u8 *mem, int bits, uae_u32 fgpen)
                   1327: {
                   1328:     do_put_mem_long (((uae_u32 *)mem) + bits, fgpen);
                   1329: }
                   1330: 
                   1331: static __inline__ void PixelWrite(uae_u8 *mem, int bits, uae_u32 fgpen, uae_u8 Bpp, uae_u32 mask)
                   1332: {
                   1333:     switch (Bpp) {
                   1334:     case 1:
                   1335:        if (mask != 0xFF)
                   1336:            fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
                   1337:        do_put_mem_byte (mem + bits, fgpen);
                   1338:        break;
                   1339:     case 2:
                   1340:        do_put_mem_word (((uae_u16 *)mem) + bits, fgpen);
                   1341:        break;
                   1342:     case 3:
                   1343:        do_put_mem_byte (mem + bits*3, fgpen & 0x000000FF);
                   1344:        *(uae_u16 *)(mem + bits*3+1) = (fgpen & 0x00FFFF00) >> 8;
                   1345:        break;
                   1346:     case 4:
                   1347:        do_put_mem_long (((uae_u32 *)mem) + bits, fgpen);
                   1348:        break;
                   1349:     }
                   1350: }
                   1351: 
                   1352: /*
                   1353:  * BlitPattern:
                   1354:  * 
                   1355:  * Synopsis:BlitPattern(bi, ri, pattern, X, Y, Width, Height, Mask, RGBFormat);
                   1356:  * Inputs:
                   1357:  * a0:struct BoardInfo *bi
                   1358:  * a1:struct RenderInfo *ri
                   1359:  * a2:struct Pattern *pattern
                   1360:  * d0.w:X
                   1361:  * d1.w:Y
                   1362:  * d2.w:Width
                   1363:  * d3.w:Height
                   1364:  * d4.w:Mask
                   1365:  * d7.l:RGBFormat
                   1366:  * 
                   1367:  * This function is used to paint a pattern on the board memory using the blitter. It is called by
                   1368:  * BltPattern, if a AreaPtrn is used with positive AreaPtSz. The pattern consists of a b/w image
                   1369:  * using a single plane of image data which will be expanded repeatedly to the destination RGBFormat
                   1370:  * using ForeGround and BackGround pens as well as draw modes. The width of the pattern data is
                   1371:  * always 16 pixels (one word) and the height is calculated as 2^Size. The data must be shifted up
                   1372:  * and to the left by XOffset and YOffset pixels at the beginning.
                   1373:  */
                   1374: uae_u32 picasso_BlitPattern (void)
                   1375: {
1.1.1.2 ! root     1376:     uaecptr rinf = m68k_areg (regs, 1);
        !          1377:     uaecptr pinf = m68k_areg (regs, 2);
        !          1378:     long X = (uae_u16)m68k_dreg (regs, 0);
        !          1379:     long Y = (uae_u16)m68k_dreg (regs, 1);
        !          1380:     long W = (uae_u16)m68k_dreg (regs, 2);
        !          1381:     long H = (uae_u16)m68k_dreg (regs, 3);
        !          1382:     uae_u8 Mask = (uae_u8)m68k_dreg (regs, 4);
        !          1383:     uae_u32 RGBFmt = m68k_dreg (regs, 7);
1.1       root     1384: 
                   1385:     uae_u8 Bpp = GetBytesPerPixel(RGBFmt);
                   1386:     int inversion = 0;
                   1387:     struct RenderInfo ri;
                   1388:     struct Pattern pattern;
                   1389:     uae_u16 rows;
1.1.1.2 ! root     1390:     uae_u32 fgpen;
1.1       root     1391:     uae_u8 *uae_mem, *frame_buffer_UAM;
                   1392:     int xshift;
1.1.1.2 ! root     1393:     unsigned long ysize_mask;
1.1       root     1394: 
                   1395:     wgfx_flushline ();
                   1396: 
1.1.1.2 ! root     1397:     if (! CopyRenderInfoStructureA2U (rinf, &ri)
        !          1398:        || ! CopyPatternStructureA2U (pinf, &pattern))
1.1       root     1399:        return 0;
                   1400: 
                   1401:     Bpp = GetBytesPerPixel(ri.RGBFormat);
                   1402:     uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset with address */
                   1403: 
                   1404:     if (pattern.DrawMode & INVERS)
                   1405:        inversion = 1;
                   1406: 
                   1407:     pattern.DrawMode &= 0x03;
                   1408:     if (Mask != 0xFF) {
                   1409:        if (Bpp > 1)
1.1.1.2 ! root     1410:            write_log ("ERROR - not obeying BlitPattern() mask 0x%x properly with Bpp %d.\n", Mask, Bpp);
1.1       root     1411:        else if (pattern.DrawMode == COMP) {
1.1.1.2 ! root     1412:            write_log ("ERROR - Unsupported Mask value 0x%x with COMP Draw in BlitPattern(), using fallback method.\n", Mask);
1.1       root     1413:            return 0;
                   1414:        }
                   1415:     }
                   1416: 
1.1.1.2 ! root     1417:     /* write_log ("BlitPattern() xy(%d,%d), wh(%d,%d) draw 0x%x, off(%d,%d), ph %d\n",
        !          1418:                            X, Y, W, H, pattern.DrawMode, pattern.XOffset, pattern.YOffset, 1 << pattern.Size); */
1.1       root     1419: #ifdef _DEBUG
                   1420:     DumpPattern(&pattern);
                   1421: #endif
                   1422:     ysize_mask = (1 << pattern.Size) - 1;
                   1423:     xshift = pattern.XOffset & 15;
                   1424: 
                   1425:     for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow) {
                   1426:        int prow = (rows + pattern.YOffset) & ysize_mask;
                   1427:        unsigned int d = do_get_mem_word (((uae_u16 *)pattern.Memory) + prow);
                   1428:        uae_u8 *uae_mem2 = uae_mem;
                   1429:        long cols;
                   1430: 
                   1431:        if (xshift != 0)
                   1432:            d = (d << xshift) | (d >> (16 - xshift));
                   1433: 
                   1434:        for (cols = 0; cols < W; cols += 16, uae_mem2 += Bpp << 4) {
                   1435:            long bits;
                   1436:            long max = W - cols;
                   1437:            unsigned int data = d;
                   1438: 
                   1439:            if (max > 16)
                   1440:                max = 16;
                   1441:     
                   1442:            for (bits = 0; bits < max; bits++) {
                   1443:                int bit_set = data & 0x8000;
                   1444:                data <<= 1;
                   1445:                switch (pattern.DrawMode) {
                   1446:                 case JAM1:
                   1447:                    if (inversion)
                   1448:                        bit_set = !bit_set;
                   1449:                    if (bit_set)
1.1.1.2 ! root     1450:                        PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
1.1       root     1451:                    break;
                   1452:                 case JAM2:
                   1453:                    if (inversion)
                   1454:                        bit_set = !bit_set;
                   1455:                    if (bit_set)
1.1.1.2 ! root     1456:                        PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
1.1       root     1457:                    else
1.1.1.2 ! root     1458:                        PixelWrite (uae_mem2, bits, pattern.BgPen, Bpp, Mask);
1.1       root     1459:                    break;
                   1460:                 case COMP:
                   1461:                    if (bit_set) {
                   1462:                        fgpen = pattern.FgPen;
                   1463: 
                   1464:                        switch (Bpp) {
                   1465:                         case 1:
                   1466:                            {
                   1467:                                uae_u8 *addr = uae_mem2 + bits;
                   1468:                                do_put_mem_byte (addr, do_get_mem_byte (addr) ^ fgpen);
                   1469:                            }
                   1470:                            break;
                   1471:                         case 2:
                   1472:                            {
                   1473:                                uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
                   1474:                                do_put_mem_word (addr, do_get_mem_word (addr) ^ fgpen);
                   1475:                            }
                   1476:                            break;
                   1477:                         case 3:
                   1478:                            {
                   1479:                                uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
                   1480:                                do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
                   1481:                            }
                   1482:                            break;
                   1483:                         case 4:
                   1484:                            {
                   1485:                                uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
                   1486:                                do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
                   1487:                            }
                   1488:                            break;
                   1489:                        }
                   1490:                    }
                   1491:                    break;
                   1492:                }
                   1493:            }
                   1494:        }
                   1495:     }
                   1496: 
                   1497:     frame_buffer_UAM = ri.Memory + X*picasso96_state.BytesPerPixel + Y*ri.BytesPerRow;
                   1498:     if (renderinfo_is_current_screen (&ri))
                   1499:        do_blit (frame_buffer_UAM, ri.BytesPerRow, 0, 0, X, Y, W, H, 0);
                   1500: 
                   1501:     return 1;
                   1502: }
                   1503: 
                   1504: /*************************************************
                   1505: BlitTemplate:
                   1506: **************************************************
                   1507: * Synopsis: BlitTemplate(bi, ri, template, X, Y, Width, Height, Mask, RGBFormat);
                   1508: * a0: struct BoardInfo *bi
                   1509: * a1: struct RenderInfo *ri
                   1510: * a2: struct Template *template
                   1511: * d0.w: X
                   1512: * d1.w: Y
                   1513: * d2.w: Width
                   1514: * d3.w: Height
                   1515: * d4.w: Mask
                   1516: * d7.l: RGBFormat
                   1517: *
                   1518: * This function is used to paint a template on the board memory using the blitter.
                   1519: * It is called by BltPattern and BltTemplate. The template consists of a b/w image
                   1520: * using a single plane of image data which will be expanded to the destination RGBFormat
                   1521: * using ForeGround and BackGround pens as well as draw modes.
                   1522: ***********************************************************************************/
                   1523: uae_u32 picasso_BlitTemplate (void)
                   1524: {
                   1525:     uae_u8 inversion = 0;
1.1.1.2 ! root     1526:     uaecptr rinf = m68k_areg (regs, 1);
        !          1527:     uaecptr tmpl = m68k_areg (regs, 2);
        !          1528:     uae_u16 X = m68k_dreg (regs, 0);
        !          1529:     uae_u16 Y = m68k_dreg (regs, 1);
        !          1530:     uae_u16 W = m68k_dreg (regs, 2);
        !          1531:     uae_u16 H = m68k_dreg (regs, 3);
        !          1532:     uae_u16 Mask = m68k_dreg (regs, 4);
1.1       root     1533:     struct Template tmp;
                   1534:     struct RenderInfo ri;
                   1535:     long rows;
                   1536:     int bitoffset;
1.1.1.2 ! root     1537:     uae_u32 fgpen;
        !          1538:     uae_u8 *uae_mem, Bpp, *frame_buffer_UAM;
1.1       root     1539:     uae_u8 *tmpl_base;
                   1540: 
                   1541:     wgfx_flushline ();
                   1542: 
1.1.1.2 ! root     1543:     if (! CopyRenderInfoStructureA2U (rinf, &ri)
        !          1544:        || ! CopyTemplateStructureA2U (tmpl, &tmp))
1.1       root     1545:        return 0;
                   1546: 
                   1547:     Bpp = GetBytesPerPixel(ri.RGBFormat);
                   1548:     uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset into address */
                   1549: 
                   1550:     if (tmp.DrawMode & INVERS)
                   1551:        inversion = 1;
                   1552: 
                   1553:     tmp.DrawMode &= 0x03;
                   1554:     if (Mask != 0xFF) {
                   1555:        if (Bpp > 1)
1.1.1.2 ! root     1556:            write_log ("ERROR - not obeying BlitTemplate() mask 0x%x properly with Bpp %d.\n", Mask, Bpp);
1.1       root     1557:        else if (tmp.DrawMode == COMP) {
1.1.1.2 ! root     1558:            write_log ("ERROR - Unsupported Mask value 0x%x with COMP Draw in BlitTemplate(), using fallback method.\n", Mask);
1.1       root     1559:            return 0;
                   1560:        }
                   1561:     }
                   1562: 
1.1.1.2 ! root     1563:     /*write_log ("BlitTemplate() xy(%d,%d), wh(%d,%d) draw 0x%x fg 0x%x bg 0x%x \n",
1.1       root     1564:                          X, Y, W, H, tmp.DrawMode, tmp.FgPen, tmp.BgPen); */
                   1565: 
                   1566:     bitoffset = tmp.XOffset % 8;
                   1567: 
                   1568: #ifdef _DEBUG
                   1569:     DumpTemplate(&tmp, W, H);
                   1570: #endif
                   1571: 
                   1572:     tmpl_base = tmp.Memory + tmp.XOffset/8;
                   1573: 
                   1574:     for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow, tmpl_base += tmp.BytesPerRow) {
                   1575:        long cols;
                   1576:        uae_u8 *tmpl_mem = tmpl_base;
                   1577:        uae_u8 *uae_mem2 = uae_mem;
                   1578:        unsigned int data = *tmpl_mem;
                   1579: 
                   1580:        for (cols = 0; cols < W; cols += 8, uae_mem2 += Bpp << 3) {
                   1581:            unsigned int byte;
                   1582:            long bits;
                   1583:            long max = W - cols;
                   1584: 
                   1585:            if (max > 8)
                   1586:                max = 8;
                   1587: 
                   1588:            data <<= 8;
                   1589:            data |= *++tmpl_mem;
                   1590: 
                   1591:            byte = data >> (8 - bitoffset);
                   1592: 
                   1593:            for (bits = 0; bits < max; bits++) {
                   1594:                int bit_set = (byte & 0x80);
                   1595:                byte <<= 1;
                   1596:                switch (tmp.DrawMode) {
                   1597:                 case JAM1:
                   1598:                    if (inversion)
                   1599:                        bit_set = !bit_set;
                   1600:                    if (bit_set) {
                   1601:                        fgpen = tmp.FgPen;
                   1602:                        PixelWrite(uae_mem2, bits, fgpen, Bpp, Mask);
                   1603:                    }
                   1604:                    break;
                   1605:                 case JAM2:
                   1606:                    if (inversion)
                   1607:                        bit_set = !bit_set;
                   1608:                    fgpen = tmp.BgPen;
                   1609:                    if (bit_set)
                   1610:                        fgpen = tmp.FgPen;
                   1611: 
                   1612:                    PixelWrite(uae_mem2, bits, fgpen, Bpp, Mask);
                   1613:                    break;
                   1614:                 case COMP:
                   1615:                    if (bit_set) {
                   1616:                        fgpen = tmp.FgPen;
                   1617: 
                   1618:                        switch (Bpp) {
                   1619:                         case 1:
                   1620:                            {
                   1621:                                uae_u8 *addr = uae_mem2 + bits;
                   1622:                                do_put_mem_byte (addr, do_get_mem_byte (addr) ^ fgpen);
                   1623:                            }
                   1624:                            break;
                   1625:                         case 2:
                   1626:                            {
                   1627:                                uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
                   1628:                                do_put_mem_word (addr, do_get_mem_word (addr) ^ fgpen);
                   1629:                            }
                   1630:                            break;
                   1631:                         case 3:
                   1632:                            {
                   1633:                                uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
                   1634:                                do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
                   1635:                            }
                   1636:                            break;
                   1637:                         case 4:
                   1638:                            {
                   1639:                                uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
                   1640:                                do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
                   1641:                            }
                   1642:                            break;
                   1643:                        }
                   1644:                    }
                   1645:                    break;
                   1646:                }
                   1647:            }
                   1648:        }
                   1649:     }
                   1650: 
                   1651:     frame_buffer_UAM = ri.Memory + X*picasso96_state.BytesPerPixel + Y*ri.BytesPerRow;
                   1652:     if (renderinfo_is_current_screen (&ri))
                   1653:        do_blit (frame_buffer_UAM, ri.BytesPerRow, 0, 0, X, Y, W, H, 0);
                   1654: 
                   1655:     return 1;
                   1656: }
                   1657: 
                   1658: /*
                   1659:  * CalculateBytesPerRow:
                   1660:  * a0:         struct BoardInfo
                   1661:  * d0:         uae_u16 Width
                   1662:  * d7: RGBFTYPE RGBFormat
                   1663:  * This function calculates the amount of bytes needed for a line of
                   1664:  * "Width" pixels in the given RGBFormat.
                   1665:  */
                   1666: uae_u32 picasso_CalculateBytesPerRow (void)
                   1667: {
1.1.1.2 ! root     1668:     uae_u16 width = m68k_dreg (regs, 0);
        !          1669:     uae_u32 type = m68k_dreg (regs, 7);
1.1       root     1670: 
                   1671:     width = GetBytesPerPixel(type)*width;
1.1.1.2 ! root     1672:     /*write_log ("CalculateBytesPerRow() = %d\n",width); */
1.1       root     1673: 
                   1674:     return width;
                   1675: }
                   1676: 
                   1677: /*
                   1678:  * SetDisplay:
                   1679:  * a0: struct BoardInfo
                   1680:  * d0: BOOL state
                   1681:  * This function enables and disables the video display.
                   1682:  * 
                   1683:  * NOTE: return the opposite of the state
                   1684:  */
                   1685: uae_u32 picasso_SetDisplay (void)
                   1686: {
1.1.1.2 ! root     1687:     uae_u32 state = m68k_dreg (regs, 0);
        !          1688:     write_log ("SetDisplay(%d)\n", state);
1.1       root     1689:     return !state;
                   1690: }
                   1691: 
                   1692: /*
                   1693:  * WaitVerticalSync:
                   1694:  * a0: struct BoardInfo
                   1695:  * This function waits for the next horizontal retrace.
                   1696:  */
                   1697: uae_u32 picasso_WaitVerticalSync (void)
                   1698: {
1.1.1.2 ! root     1699:     /*write_log ("WaitVerticalSync()\n");*/
1.1       root     1700:     return 1;
                   1701: }
                   1702: 
                   1703: /* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
                   1704: static void PlanarToChunky(struct RenderInfo *ri, struct BitMap *bm, long srcx, long srcy,
                   1705:                           long dstx, long dsty, long width, long height, uae_u8 mask)
                   1706: {
1.1.1.2 ! root     1707:     int j;
1.1       root     1708: 
                   1709:     uae_u8 *PLANAR[8], *image = ri->Memory + dstx * GetBytesPerPixel (ri->RGBFormat) + dsty*ri->BytesPerRow;
                   1710:     int Depth = bm->Depth;
1.1.1.2 ! root     1711:     uae_u16 rows, bitoffset = srcx & 7;
1.1       root     1712:     long eol_offset;
                   1713: 
                   1714:     /* if (mask != 0xFF) 
1.1.1.2 ! root     1715:        write_log ("P2C - pixel-width = %d, bit-offset = %d\n", width, bitoffset); */
1.1       root     1716:     
                   1717:     /* Set up our bm->Planes[] pointers to the right horizontal offset */
                   1718:     for (j = 0; j < Depth; j++) {
                   1719:        uae_u8 *p = bm->Planes[j];
                   1720:        if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
                   1721:            p += srcx/8 + srcy*bm->BytesPerRow;
                   1722:        PLANAR[j] = p;
                   1723:        if ((mask & (1 << j)) == 0)
                   1724:            PLANAR[j] = &all_zeros_bitmap;
                   1725:     }
                   1726:     eol_offset = (long)bm->BytesPerRow - ((width + 7) >> 3);
                   1727:     for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
                   1728:        long cols;
                   1729: 
                   1730:        for (cols = 0; cols < width; cols += 8) {
                   1731:            int k;
                   1732:            uae_u32 a = 0, b = 0;
                   1733:            unsigned int msk = 0xFF;
                   1734:            long tmp = cols + 8 - width;
                   1735:            if (tmp > 0) {
                   1736:                msk <<= tmp;
                   1737:                b = do_get_mem_long ((uae_u32 *)(image + cols + 4));
                   1738:                if (tmp < 4)
                   1739:                    b &= 0xFFFFFFFF >> (32 - tmp * 8);
                   1740:                else if (tmp > 4) {
                   1741:                    a = do_get_mem_long ((uae_u32 *)(image + cols));
                   1742:                    a &= 0xFFFFFFFF >> (64 - tmp * 8);
                   1743:                }
                   1744:            }
                   1745:            for (k = 0; k < Depth; k++) {
                   1746:                unsigned int data;
                   1747:                if (PLANAR[k] == &all_zeros_bitmap)
                   1748:                    data = 0;
                   1749:                else if (PLANAR[k] == &all_ones_bitmap)
                   1750:                    data = 0xFF;
                   1751:                else {
                   1752:                    data = (uae_u8)(do_get_mem_word ((uae_u16 *)PLANAR[k]) >> (8 - bitoffset));
                   1753:                    PLANAR[k]++;
                   1754:                }
                   1755:                data &= msk;
                   1756:                a |= p2ctab[data][0] << k;
                   1757:                b |= p2ctab[data][1] << k;
                   1758:            }
                   1759:            do_put_mem_long ((uae_u32 *)(image + cols), a);
                   1760:            do_put_mem_long ((uae_u32 *)(image + cols + 4), b);
                   1761:        }
                   1762:        for (j = 0; j < Depth; j++) {
                   1763:            if (PLANAR[j] != &all_zeros_bitmap && PLANAR[j] != &all_ones_bitmap) {
                   1764:                PLANAR[j] += eol_offset;
                   1765:            }
                   1766:        }
                   1767:     }
                   1768: }
                   1769: 
                   1770: /*
                   1771:  * BlitPlanar2Chunky:
                   1772:  * a0: struct BoardInfo *bi
                   1773:  * a1: struct BitMap *bm - source containing planar information and assorted details
                   1774:  * a2: struct RenderInfo *ri - dest area and its details
                   1775:  * d0.w: SrcX
                   1776:  * d1.w: SrcY
                   1777:  * d2.w: DstX
                   1778:  * d3.w: DstY
                   1779:  * d4.w: SizeX
                   1780:  * d5.w: SizeY
                   1781:  * d6.b: MinTerm - uh oh!
                   1782:  * d7.b: Mask - uh oh!
                   1783:  *
                   1784:  * This function is currently used to blit from planar bitmaps within system memory to chunky bitmaps
                   1785:  * on the board. Watch out for plane pointers that are 0x00000000 (represents a plane with all bits "0")
                   1786:  * or 0xffffffff (represents a plane with all bits "1").
                   1787:  */
                   1788: uae_u32 picasso_BlitPlanar2Chunky (void)
                   1789: {
1.1.1.2 ! root     1790:     uaecptr bm = m68k_areg (regs, 1);
        !          1791:     uaecptr ri = m68k_areg (regs, 2);
        !          1792:     uae_u16 srcx = m68k_dreg (regs, 0) & 0xFFFF;
        !          1793:     uae_u16 srcy = m68k_dreg (regs, 1) & 0xFFFF;
        !          1794:     uae_u16 dstx = m68k_dreg (regs, 2) & 0xFFFF;
        !          1795:     uae_u16 dsty = m68k_dreg (regs, 3) & 0xFFFF;
        !          1796:     uae_u16 width = m68k_dreg (regs, 4) & 0xFFFF;
        !          1797:     uae_u16 height = m68k_dreg (regs, 5) & 0xFFFF;
        !          1798:     uae_u8 minterm = m68k_dreg (regs, 6) & 0xFF;
        !          1799:     uae_u8 mask = m68k_dreg (regs, 7) & 0xFF;
1.1       root     1800:     struct RenderInfo local_ri;
                   1801:     struct BitMap local_bm;
                   1802: 
                   1803:     wgfx_flushline ();
                   1804: 
                   1805:     if (minterm != 0x0C) {
1.1.1.2 ! root     1806:        write_log ("ERROR - BlitPlanar2Chunky() has minterm 0x%x, which I don't handle. Using fall-back routine.\n",
1.1       root     1807:                             minterm);
                   1808:        return 0;
                   1809:     }
1.1.1.2 ! root     1810:     if (! CopyRenderInfoStructureA2U (ri, &local_ri)
        !          1811:        || ! CopyBitMapStructureA2U (bm, &local_bm))
1.1       root     1812:        return 0;
                   1813: 
1.1.1.2 ! root     1814:     /*write_log ("BlitPlanar2Chunky(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
1.1       root     1815:                          srcx, srcy, dstx, dsty, width, height, minterm, mask, local_bm.Depth);
1.1.1.2 ! root     1816:     write_log ("P2C - BitMap has %d BPR, %d rows\n", local_bm.BytesPerRow, local_bm.Rows); */
        !          1817:     PlanarToChunky (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, mask);
1.1       root     1818:     if (renderinfo_is_current_screen (&local_ri))
                   1819:        do_blit (local_ri.Memory + dstx * GetBytesPerPixel (local_ri.RGBFormat) + dsty * local_ri.BytesPerRow,
                   1820:                 local_ri.BytesPerRow,
                   1821:                 0, 0, dstx, dsty, width, height, 0);
                   1822: 
1.1.1.2 ! root     1823:     return m68k_dreg (regs, 0);
1.1       root     1824: }
                   1825: 
                   1826: /* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
                   1827: static void PlanarToDirect(struct RenderInfo *ri, struct BitMap *bm,
                   1828:                           long srcx, long srcy, long dstx, long dsty,
                   1829:                           long width, long height, uae_u8 mask,
                   1830:                           struct ColorIndexMapping *cim)
                   1831: {
                   1832:     int j;
                   1833:     int bpp = GetBytesPerPixel(ri->RGBFormat);
                   1834:     uae_u8 *PLANAR[8];
                   1835:     uae_u8 *image = ri->Memory + dstx * bpp + dsty * ri->BytesPerRow;
                   1836:     int Depth = bm->Depth;
                   1837:     long rows;
                   1838:     long eol_offset;
                   1839: 
                   1840:     /* Set up our bm->Planes[] pointers to the right horizontal offset */
                   1841:     for (j = 0; j < Depth; j++) {
                   1842:        uae_u8 *p = bm->Planes[j];
                   1843:        if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
                   1844:            p += srcx/8 + srcy*bm->BytesPerRow;
                   1845:        PLANAR[j] = p;
                   1846:        if ((mask & (1 << j)) == 0)
                   1847:            PLANAR[j] = &all_zeros_bitmap;
                   1848:     }
                   1849: 
                   1850:     eol_offset = (long)bm->BytesPerRow - ((width + (srcx & 7)) >> 3);
                   1851:     for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
                   1852:        long cols;
                   1853:        uae_u8 *image2 = image;
                   1854:        unsigned int bitoffs = 7 - (srcx & 7);
                   1855:        int i;
                   1856: 
                   1857:        for (cols = 0; cols < width; cols ++) {
                   1858:            int v = 0, k;
                   1859:            for (k = 0; k < Depth; k++) {
                   1860:                if (PLANAR[k] == &all_ones_bitmap)
                   1861:                    v |= 1 << k;
                   1862:                else if (PLANAR[k] != &all_zeros_bitmap) {
                   1863:                    v |= ((*PLANAR[k] >> bitoffs) & 1) << k;
                   1864:                }
                   1865:            }
                   1866: 
                   1867:            switch (bpp) {
                   1868:             case 2:
                   1869:                do_put_mem_word ((uae_u16 *)image2, cim->Colors[v]);
                   1870:                image2 += 2;
                   1871:                break;
                   1872:             case 3:
                   1873:                do_put_mem_byte (image2++, cim->Colors[v] & 0x000000FF);
                   1874:                do_put_mem_word ((uae_u16 *)image2, (cim->Colors[v] & 0x00FFFF00) >> 8);
                   1875:                image2 += 2;
                   1876:                break;
                   1877:             case 4:
                   1878:                do_put_mem_long ((uae_u32 *)image2, cim->Colors[v]);
                   1879:                image2 += 4;
                   1880:                break;
                   1881:            }
                   1882:            bitoffs--;
                   1883:            bitoffs &= 7;
                   1884:            if (bitoffs == 7) {
                   1885:                int k;
                   1886:                for (k = 0; k < Depth; k++) {
                   1887:                    if (PLANAR[k] != &all_zeros_bitmap && PLANAR[k] != &all_ones_bitmap) {
                   1888:                        PLANAR[k]++;
                   1889:                    }
                   1890:                }
                   1891:            }
                   1892:        }
                   1893: 
                   1894:        for (i = 0; i < Depth; i++) {
                   1895:            if (PLANAR[i] != &all_zeros_bitmap && PLANAR[i] != &all_ones_bitmap) {
                   1896:                PLANAR[i] += eol_offset;
                   1897:            }
                   1898:        }
                   1899:     }
                   1900: }
                   1901: 
                   1902: /*
                   1903:  * BlitPlanar2Direct: 
                   1904:  * 
                   1905:  * Synopsis:
                   1906:  * BlitPlanar2Direct(bi, bm, ri, cim, SrcX, SrcY, DstX, DstY, SizeX, SizeY, MinTerm, Mask);
                   1907:  * Inputs:
                   1908:  * a0:struct BoardInfo *bi
                   1909:  * a1:struct BitMap *bm
                   1910:  * a2:struct RenderInfo *ri
                   1911:  * a3:struct ColorIndexMapping *cmi
                   1912:  * d0.w:SrcX
                   1913:  * d1.w:SrcY
                   1914:  * d2.w:DstX
                   1915:  * d3.w:DstY
                   1916:  * d4.w:SizeX
                   1917:  * d5.w:SizeY
                   1918:  * d6.b:MinTerm
                   1919:  * d7.b:Mask
                   1920:  * 
                   1921:  * This function is currently used to blit from planar bitmaps within system memory to direct color
                   1922:  * bitmaps (15, 16, 24 or 32 bit) on the board. Watch out for plane pointers that are 0x00000000 (represents
                   1923:  * a plane with all bits "0") or 0xffffffff (represents a plane with all bits "1"). The ColorIndexMapping is
                   1924:  * used to map the color index of each pixel formed by the bits in the bitmap's planes to a direct color value
                   1925:  * which is written to the destination RenderInfo. The color mask and all colors within the mapping are words,
                   1926:  * triple bytes or longwords respectively similar to the color values used in FillRect(), BlitPattern() or
                   1927:  * BlitTemplate(). 
                   1928:  */
                   1929: uae_u32 picasso_BlitPlanar2Direct (void)
                   1930: {
1.1.1.2 ! root     1931:     uaecptr bm = m68k_areg (regs, 1);
        !          1932:     uaecptr ri = m68k_areg (regs, 2);
        !          1933:     uaecptr cim = m68k_areg (regs, 3);
        !          1934:     uae_u16 srcx = m68k_dreg (regs, 0);
        !          1935:     uae_u16 srcy = m68k_dreg (regs, 1);
        !          1936:     uae_u16 dstx = m68k_dreg (regs, 2);
        !          1937:     uae_u16 dsty = m68k_dreg (regs, 3);
        !          1938:     uae_u16 width = m68k_dreg (regs, 4);
        !          1939:     uae_u16 height = m68k_dreg (regs, 5);
        !          1940:     uae_u8 minterm = m68k_dreg (regs, 6);
        !          1941:     uae_u8 Mask = m68k_dreg (regs, 7);
1.1       root     1942:     struct RenderInfo local_ri;
                   1943:     struct BitMap local_bm;
                   1944:     struct ColorIndexMapping local_cim;
                   1945: 
                   1946:     wgfx_flushline ();
                   1947: 
                   1948:     if (minterm != 0x0C) {
1.1.1.2 ! root     1949:        write_log ("ERROR - BlitPlanar2Direct() has op-code 0x%x, which I don't handle. Using fall-back routine.\n",
        !          1950:                   minterm);
1.1       root     1951:        return 0;
                   1952:     }
                   1953:     if (Mask != 0xFF) {
1.1.1.2 ! root     1954:        write_log ("ERROR - Unsupported Mask value 0x%x in BlitPlanar2Direct(), using fallback method.\n", Mask);
1.1       root     1955:        return 0;
                   1956:     }
1.1.1.2 ! root     1957:     if (! CopyRenderInfoStructureA2U (ri, &local_ri)
        !          1958:        || ! CopyBitMapStructureA2U (bm, &local_bm))
1.1       root     1959:        return 0;
                   1960: 
                   1961:     CopyColorIndexMappingA2U (cim, &local_cim);
1.1.1.2 ! root     1962:     /* write_log ("BlitPlanar2Direct(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
        !          1963:                  srcx, srcy, dstx, dsty, width, height, minterm, Mask, local_bm.Depth); */
        !          1964:     PlanarToDirect (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, Mask, &local_cim);
1.1       root     1965:     if (renderinfo_is_current_screen (&local_ri))
                   1966:        do_blit (local_ri.Memory + dstx * GetBytesPerPixel (local_ri.RGBFormat) + dsty * local_ri.BytesPerRow,
                   1967:                 local_ri.BytesPerRow,
                   1968:                 0, 0, dstx, dsty, width, height, 0);
                   1969:     return 1;
                   1970: }
                   1971: 
                   1972: /* @@@ - Work to be done here!
                   1973:  *
                   1974:  * The address is the offset into our Picasso96 frame-buffer (pointed to by gfxmem_start)
                   1975:  * where the value was put.
                   1976:  *
                   1977:  * Porting work: on some machines you may not need these functions, ie. if the memory for the
                   1978:  * Picasso96 frame-buffer is directly viewable or directly blittable.  On Win32 with DirectX,
                   1979:  * this is not the case.  So I provide some write-through functions (as per Mathias' orders!)
                   1980:  */
                   1981: static void write_gfx_long (uaecptr addr, uae_u32 value)
                   1982: {
                   1983:     uaecptr oldaddr = addr;
                   1984:     int x, xbytes, y;
                   1985:     uae_u8 *dst;
                   1986: 
                   1987:     if (!picasso_on)
                   1988:        return;
                   1989: 
                   1990:     /*
                   1991:      * Several writes to successive memory locations are a common access pattern.
                   1992:      * Try to optimize it.
                   1993:      */
                   1994:     if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
                   1995:        if (addr < wgfx_min)
                   1996:            wgfx_min = addr;
                   1997:        if (addr + 4 > wgfx_max)
                   1998:            wgfx_max = addr + 4;
                   1999:        return;
                   2000:     } else
                   2001:        wgfx_flushline ();
                   2002: 
                   2003:     addr += gfxmem_start;
                   2004:     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
                   2005:     if (addr < picasso96_state.Address || addr + 4 > picasso96_state.Extent)
                   2006:        return;
                   2007: 
                   2008:     addr -= picasso96_state.Address;
                   2009:     y = addr / picasso96_state.BytesPerRow;
                   2010: 
                   2011: #if 0
                   2012:     DX_Invalidate (y, y);
                   2013:     if (! picasso_vidinfo.extra_mem)
                   2014:        return;
                   2015: 
                   2016:     xbytes = addr - y * picasso96_state.BytesPerRow;
                   2017:     x = xbytes / picasso96_state.BytesPerPixel;
                   2018: 
                   2019:     if (x < picasso96_state.Width && y < picasso96_state.Height) {
1.1.1.2 ! root     2020:        dst = gfx_lock_picasso ();
1.1       root     2021:        if (dst) {
                   2022:            do_put_mem_long ((uae_u32 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);
1.1.1.2 ! root     2023:            gfx_unlock_picasso ();
1.1       root     2024:        }
                   2025:     }
                   2026: #else
                   2027:     if (y >= picasso96_state.Height)
                   2028:        return;
                   2029:     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
                   2030:     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
                   2031:     wgfx_y = y;
                   2032:     wgfx_min = oldaddr;
                   2033:     wgfx_max = oldaddr + 4;
                   2034: #endif
                   2035: }
                   2036: 
                   2037: static void write_gfx_word (uaecptr addr, uae_u16 value)
                   2038: {
                   2039:     uaecptr oldaddr = addr;
                   2040:     int x, xbytes, y;
                   2041:     uae_u8 *dst;
                   2042: 
                   2043:     if (!picasso_on)
                   2044:        return;
                   2045: 
                   2046:     /*
                   2047:      * Several writes to successive memory locations are a common access pattern.
                   2048:      * Try to optimize it.
                   2049:      */
                   2050:     if (addr >= wgfx_linestart && addr + 2 <= wgfx_lineend) {
                   2051:        if (addr < wgfx_min)
                   2052:            wgfx_min = addr;
                   2053:        if (addr + 2 > wgfx_max)
                   2054:            wgfx_max = addr + 2;
                   2055:        return;
                   2056:     } else
                   2057:        wgfx_flushline ();
                   2058: 
                   2059:     addr += gfxmem_start;
                   2060:     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
                   2061:     if (addr < picasso96_state.Address || addr + 2 > picasso96_state.Extent)
                   2062:        return;
                   2063: 
                   2064:     addr -= picasso96_state.Address;
                   2065:     y = addr / picasso96_state.BytesPerRow;
                   2066: 
                   2067: #if 0
                   2068:     DX_Invalidate (y, y);
                   2069:     if (! picasso_vidinfo.extra_mem)
                   2070:        return;
                   2071: 
                   2072:     xbytes = addr - y * picasso96_state.BytesPerRow;
                   2073:     x = xbytes / picasso96_state.BytesPerPixel;
                   2074: 
                   2075:     if (x < picasso96_state.Width && y < picasso96_state.Height) {
1.1.1.2 ! root     2076:        dst = gfx_lock_picasso ();
1.1       root     2077:        if (dst) {
                   2078:            do_put_mem_word ((uae_u16 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);
1.1.1.2 ! root     2079:            gfx_unlock_picasso ();
1.1       root     2080:        }
                   2081:     }
                   2082: #else
                   2083:     if (y >= picasso96_state.Height)
                   2084:        return;
                   2085:     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
                   2086:     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
                   2087:     wgfx_y = y;
                   2088:     wgfx_min = oldaddr;
                   2089:     wgfx_max = oldaddr + 2;
                   2090: #endif
                   2091: }
                   2092: 
                   2093: static void write_gfx_byte (uaecptr addr, uae_u8 value)
                   2094: {
                   2095:     uaecptr oldaddr = addr;
                   2096:     int x, xbytes, y;
                   2097:     uae_u8 *dst;
                   2098: 
                   2099:     if (!picasso_on)
                   2100:        return;
                   2101: 
                   2102:     /*
                   2103:      * Several writes to successive memory locations are a common access pattern.
                   2104:      * Try to optimize it.
                   2105:      */
                   2106:     if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
                   2107:        if (addr < wgfx_min)
                   2108:            wgfx_min = addr;
                   2109:        if (addr + 1 > wgfx_max)
                   2110:            wgfx_max = addr + 1;
                   2111:        return;
                   2112:     } else
                   2113:        wgfx_flushline ();
                   2114: 
                   2115:     addr += gfxmem_start;
                   2116:     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
                   2117:     if (addr < picasso96_state.Address || addr + 1 > picasso96_state.Extent)
                   2118:        return;
                   2119: 
                   2120:     addr -= picasso96_state.Address;
                   2121:     y = addr / picasso96_state.BytesPerRow;
                   2122: 
                   2123: #if 0
                   2124:     DX_Invalidate (y, y);
                   2125:     if (! picasso_vidinfo.extra_mem)
                   2126:        return;
                   2127: 
                   2128:     xbytes = addr - y * picasso96_state.BytesPerRow;
                   2129:     x = xbytes / picasso96_state.BytesPerPixel;
                   2130: 
                   2131:     if (x < picasso96_state.Width && y < picasso96_state.Height) {
1.1.1.2 ! root     2132:        dst = gfx_lock_picasso ();
1.1       root     2133:        if (dst) {
                   2134:            *(uae_u8 *)(dst + y * picasso_vidinfo.rowbytes + xbytes) = value;
1.1.1.2 ! root     2135:            gfx_unlock_picasso ();
1.1       root     2136:        }
                   2137:     }
                   2138: #else
                   2139:     if (y >= picasso96_state.Height)
                   2140:        return;
                   2141:     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
                   2142:     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
                   2143:     wgfx_y = y;
                   2144:     wgfx_min = oldaddr;
                   2145:     wgfx_max = oldaddr + 1;
                   2146: #endif
                   2147: }
                   2148: 
                   2149: static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr)
                   2150: {
                   2151:     uae_u32 *m;
                   2152:     addr -= gfxmem_start & gfxmem_mask;
                   2153:     addr &= gfxmem_mask;
                   2154:     m = (uae_u32 *)(gfxmemory + addr);
                   2155:     return do_get_mem_long(m);
                   2156: }
                   2157: 
                   2158: static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr)
                   2159: {
                   2160:     uae_u16 *m;
                   2161:     addr -= gfxmem_start & gfxmem_mask;
                   2162:     addr &= gfxmem_mask;
                   2163:     m = (uae_u16 *)(gfxmemory + addr);
                   2164:     return do_get_mem_word(m);
                   2165: }
                   2166: 
                   2167: static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr)
                   2168: {
                   2169:     addr -= gfxmem_start & gfxmem_mask;
                   2170:     addr &= gfxmem_mask;
                   2171:     return gfxmemory[addr];
                   2172: }
                   2173: 
                   2174: static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l)
                   2175: {
                   2176:     uae_u32 *m;
                   2177:     addr -= gfxmem_start & gfxmem_mask;
                   2178:     addr &= gfxmem_mask;
                   2179:     m = (uae_u32 *)(gfxmemory + addr);
                   2180:     do_put_mem_long(m, l);
                   2181: 
                   2182:     /* write the long-word to our displayable memory */
                   2183:     write_gfx_long(addr, l);
                   2184: }
                   2185: 
                   2186: static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w)
                   2187: {
                   2188:     uae_u16 *m;
                   2189:     addr -= gfxmem_start & gfxmem_mask;
                   2190:     addr &= gfxmem_mask;
                   2191:     m = (uae_u16 *)(gfxmemory + addr);
                   2192:     do_put_mem_word(m, (uae_u16)w);
                   2193: 
                   2194:     /* write the word to our displayable memory */
                   2195:     write_gfx_word(addr, (uae_u16)w);
                   2196: }
                   2197: 
                   2198: static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b)
                   2199: {
                   2200:     addr -= gfxmem_start & gfxmem_mask;
                   2201:     addr &= gfxmem_mask;
                   2202:     gfxmemory[addr] = b;
                   2203: 
                   2204:     /* write the byte to our displayable memory */
                   2205:     write_gfx_byte(addr, (uae_u8)b);
                   2206: }
                   2207: 
                   2208: static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size)
                   2209: {
                   2210:     addr -= gfxmem_start & gfxmem_mask;
                   2211:     addr &= gfxmem_mask;
1.1.1.2 ! root     2212:     return (addr + size) < allocated_gfxmem;
1.1       root     2213: }
                   2214: 
                   2215: static uae_u8 REGPARAM2 *gfxmem_xlate (uaecptr addr)
                   2216: {
                   2217:     addr -= gfxmem_start & gfxmem_mask;
                   2218:     addr &= gfxmem_mask;
                   2219:     return gfxmemory + addr;
                   2220: }
                   2221: 
                   2222: addrbank gfxmem_bank = {
                   2223:     gfxmem_lget, gfxmem_wget, gfxmem_bget,
                   2224:     gfxmem_lput, gfxmem_wput, gfxmem_bput,
                   2225:     gfxmem_xlate, gfxmem_check
                   2226: };
                   2227: 
                   2228: static int resolution_compare (const void *a, const void *b)
                   2229: {
                   2230:     struct PicassoResolution *ma = (struct PicassoResolution *)a;
                   2231:     struct PicassoResolution *mb = (struct PicassoResolution *)b;
                   2232:     if (ma->res.width > mb->res.width)
                   2233:        return -1;
                   2234:     if (ma->res.width < mb->res.width)
                   2235:        return 1;
                   2236:     if (ma->res.height > mb->res.height)
                   2237:        return -1;
                   2238:     if (ma->res.height < mb->res.height)
                   2239:        return 1;
                   2240:     return ma->depth - mb->depth;
                   2241: }
                   2242: /* Call this function first, near the beginning of code flow
                   2243:  * NOTE: Don't stuff it in InitGraphics() which seems reasonable...
                   2244:  * Instead, put it in customreset() for safe-keeping.  */
                   2245: void InitPicasso96 (void)
                   2246: {
                   2247:     static int first_time = 1;
                   2248: 
1.1.1.2 ! root     2249:     memset (&picasso96_state, 0, sizeof(struct picasso96_state_struct));
        !          2250: 
1.1       root     2251:     if (first_time) {
                   2252:        int i;
                   2253: 
                   2254:        for (i = 0; i < 256; i++) {
                   2255:            p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0)
                   2256:                            | ((i & 64) ? 0x010000 : 0)
                   2257:                            | ((i & 32) ? 0x0100 : 0)
                   2258:                            | ((i & 16) ? 0x01 : 0));
                   2259:            p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0)
                   2260:                            | ((i & 4) ? 0x010000 : 0)
                   2261:                            | ((i & 2) ? 0x0100 : 0)
                   2262:                            | ((i & 1) ? 0x01 : 0));
                   2263:        }
                   2264:        mode_count = DX_FillResolutions (&picasso96_pixel_format);
                   2265:        qsort (DisplayModes, mode_count, sizeof (struct PicassoResolution),
                   2266:               resolution_compare);
                   2267: 
                   2268:        for (i = 0; i < mode_count; i++) {
                   2269:            sprintf(DisplayModes[i].name, "%dx%d, %d-bit, %d Hz",
                   2270:                    DisplayModes[i].res.width, DisplayModes[i].res.height,
                   2271:                    DisplayModes[i].depth * 8, DisplayModes[i].refresh);
                   2272:            switch (DisplayModes[i].depth) {
                   2273:             case 1:
                   2274:                if (DisplayModes[i].res.width > chunky.width)
                   2275:                    chunky.width = DisplayModes[i].res.width;
                   2276:                if (DisplayModes[i].res.height > chunky.height)
                   2277:                    chunky.height = DisplayModes[i].res.height;
                   2278:                break;
                   2279:             case 2:
                   2280:                if (DisplayModes[i].res.width > hicolour.width)
                   2281:                    hicolour.width = DisplayModes[i].res.width;
                   2282:                if (DisplayModes[i].res.height > hicolour.height)
                   2283:                    hicolour.height = DisplayModes[i].res.height;
                   2284:                break;
                   2285:             case 3:
                   2286:                if (DisplayModes[i].res.width > truecolour.width)
                   2287:                    truecolour.width = DisplayModes[i].res.width;
                   2288:                if (DisplayModes[i].res.height > truecolour.height)
                   2289:                    truecolour.height = DisplayModes[i].res.height;
                   2290:                break;
                   2291:             case 4:
                   2292:                if (DisplayModes[i].res.width > alphacolour.width)
                   2293:                    alphacolour.width = DisplayModes[i].res.width;
                   2294:                if (DisplayModes[i].res.height > alphacolour.height)
                   2295:                    alphacolour.height = DisplayModes[i].res.height;
                   2296:                break;
                   2297:            }
                   2298:        }
1.1.1.2 ! root     2299:        ShowSupportedResolutions ();
1.1       root     2300: 
                   2301:        first_time = 0;
                   2302:     }
                   2303: }
                   2304: 
                   2305: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.