home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 487.lha / CpuBlit_v0.96 / src / cpublit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-11  |  7.5 KB  |  266 lines

  1. /****************************************************************************
  2.  *
  3.  *        CPUBLIT.C
  4.  *
  5.  *        (C) Copyright Eddy Carroll, 1991. Freely distributable.
  6.  * 
  7.  *        CpuBlit replaces the BltBitMap function in graphics.library with
  8.  *        a version that uses the CPU where practical. This is up to 2.8
  9.  *        times faster on a 68030 system.
  10.  *
  11.  *        This moudle installs the new blit routine, handles parsing the
  12.  *        command line options etc. Scroll.s does the actual blitting.
  13.  *
  14.  ***************************************************************************/
  15.  
  16. #ifndef LATTICE_50
  17. #include "system.h"
  18. typedef void (*__fptr)(); /* The sort of thing returned by SetFunction */
  19. #endif
  20.  
  21. #include "scroll.h"
  22.  
  23. #define NAME            "CpuBlit V0.96"
  24. #define PORTNAME        NAME
  25. #define SIGNON            NAME " \251 1991 Eddy Carroll.\n"
  26.  
  27. #define print(s)        Write(Output(), s, strlen(s))
  28. #define BltBitMap_LVO    (-30)    /* Offset of BltBitMap in graphics.library    */
  29.  
  30. char HelpMsg[] =
  31. NAME " \251 Eddy Carroll, Feb 1991. Replaces blitter with 68020/68030.\n"
  32. "Usage: CpuBlit {option}\n"
  33. "\n"
  34. "    -a    Always use CPU to do blits (default setting)\n"
  35. "    -1    Use CPU for blits unless another task is ready to run\n"
  36. "    -2    Use CPU for blits unless more than one task is ready to run\n"
  37. "    -b    Use CPU even if bitmap isn't initialised correctly\n"
  38. "    -o    Use CPU only when a single bitmap is involved\n"
  39. "    -s    Use CPU for blits unless a blit is already in progress\n"
  40. "    -q    Remove CpuBlit from the system\n"
  41. "\n";
  42.  
  43. /****************************************************************************
  44.  *
  45.  *        Globals
  46.  * 
  47.  ***************************************************************************/
  48.  
  49. struct Gfxbase *GfxBase;
  50.  
  51. struct MyMsg {
  52.     struct    Message msg;    /* Standard message structure        */
  53.     int        opt;            /* Requested mode of operation        */
  54.     int        result;            /* True if succesfully terminated    */
  55. } MyMsg, *msg;
  56.  
  57. #define MSG_OKAY    0        /* Message was handled correctly    */
  58. #define MSG_QUIT    1        /* CpuBlit was removed safely        */
  59. #define MSG_FAILED    2        /* CpuBlit couldn't be removed        */
  60.  
  61.  
  62. /****************************************************************************
  63.  *
  64.  *        Sets the blitter function to be executed according to the character
  65.  *        option specified. Returns 1 if QUIT was requested, else zero.
  66.  *
  67.  ***************************************************************************/
  68.  
  69. int setopt(int opt)
  70. {
  71.     switch (opt) {
  72.         case 'a':    BlitFunc   = StartBlit;
  73.                     OnlySingle = 0;
  74.                     Broken       = 0;            return (0);
  75.         case 'b':    Broken       = 1;            return (0);
  76.         case 'o':   OnlySingle = 1;            return (0);
  77.         case 's':    BlitFunc   = ShareBlit; return (0);
  78.         case '1':    BlitFunc   = Friend1;   return (0);
  79.         case '2':    BlitFunc   = Friend2;   return (0);
  80.         case 'q':    BlitFunc   = ExitBlit;  return (1);
  81.         default:
  82.             print(HelpMsg);
  83.             exit(5);
  84.     }
  85. }
  86.  
  87. /****************************************************************************
  88.  *
  89.  *        This is the main event loop. It sits waiting for a message from
  90.  *        other invocations of CpuBlit, which tell it to either change the
  91.  *        current settings or to remove itself.
  92.  *
  93.  ***************************************************************************/
  94.  
  95. void mainloop(void)
  96. {
  97.     struct MsgPort *MyPort;
  98.     int installed = 1;
  99.  
  100.     /*
  101.      *        We have to create our rendezvous port here rather than in the
  102.      *        mainline, since the message port depends on task information etc.
  103.      *        This is not altogether satisfactory since if it fails, there is
  104.      *        no way to tell the user (as a background task, we have no stdin
  105.      *        or stdout). But since port creation is unlikely to fail anyway,
  106.      *        it's not a big problem.
  107.      */
  108.     MyPort = CreatePort(PORTNAME, 0);
  109.     if (!MyPort)
  110.         return;
  111.  
  112.     /*
  113.      *        Now have to open graphics.library, so that we can add in our
  114.      *        new patch. As above, if this fails there is no easy way to
  115.      *        tell the user. However, at least it won't crash the system.
  116.      */
  117.     GfxBase = OpenLibrary("graphics.library", 0);
  118.     if (!GfxBase)
  119.         return;
  120.  
  121.     BltBitMapAddress = SetFunction(GfxBase, BltBitMap_LVO, NewBltBitMap);
  122.  
  123.     /*
  124.      *        Now wait a message from another copy of CpuBlit. This will
  125.      *        either contain an updated command line argument or else a
  126.      *        request to quit.
  127.      */
  128.     do {
  129.         __fptr oldptr;
  130.  
  131.         WaitPort(MyPort);
  132.         while ((msg = (struct MyMsg *)GetMsg(MyPort)) != NULL) {
  133.             if (setopt(msg->opt) == 0) {
  134.                 /*
  135.                  *        Received a valid command line argument and
  136.                  *        handled it.
  137.                  */
  138.                 msg->result = MSG_OKAY;
  139.             } else {
  140.                 /*
  141.                  *        Try and remove ourselves. We have to surround this
  142.                  *        with Forbid() to make sure that no other tasks manage
  143.                  *        to call BltBitMap() in the case where we restore the
  144.                  *        original vector and then realise that its current
  145.                  *        replacement actually pointed to something other than
  146.                  *        CpuBlit.
  147.                  */
  148.                 Forbid();
  149.                 oldptr = SetFunction(GfxBase, BltBitMap_LVO, BltBitMapAddress);
  150.                 if (oldptr == NewBltBitMap) {
  151.                     installed = 0;
  152.                     msg->result = MSG_QUIT;
  153.                 } else {
  154.                     SetFunction(GfxBase, BltBitMap_LVO, oldptr);
  155.                     msg->result = MSG_FAILED;
  156.                 }
  157.                 Permit();
  158.             }
  159.             ReplyMsg(msg);
  160.         }
  161.     } while (installed);
  162.  
  163.     /*
  164.      *        Now our patch has been removed, it only remains to free up the
  165.      *        code. It is possible that someone is still in our blitter code.
  166.      *        We can determine this fairly safely by looking at UsageCount;
  167.      *        if this is -1, nobody is in our code. Otherwise, we wait until
  168.      *        it is -1 (delaying for a little while inbetween to give programs
  169.      *        a chance to run).
  170.      *
  171.      *        We also set the blitter test function to ExitBlit, so that if
  172.      *        someone does slip through our test and end up inside our code,
  173.      *        they will get rerouted back to the normal blitter code almost
  174.      *        immediately.
  175.      */
  176.     DeletePort(MyPort);
  177.     BlitFunc = ExitBlit;
  178.  
  179.     while (UsageCount != -1)
  180.         Delay(10);                /* Wait 0.2 seconds */
  181.  
  182.     /*
  183.      *        Now we're completely finished so we can close the libraries
  184.      *        and exit.
  185.      */
  186.     CloseLibrary(GfxBase);
  187. }
  188.  
  189.  
  190. /****************************************************************************
  191.  *
  192.  *        Mainline 
  193.  *
  194.  ***************************************************************************/
  195.  
  196. void main(int argc, char **argv)
  197. {
  198.     struct MsgPort *BlitPort, *MyPort;
  199.     int i;
  200.  
  201.     for (i = 1; i < argc; i++) {
  202.         if (argv[i][0] == '-')
  203.             setopt(argv[i][1]);        /* Check for valid command line option */
  204.         else {
  205.             print(HelpMsg);
  206.             exit(5);
  207.         }
  208.     }
  209.  
  210.     BlitPort = FindPort(PORTNAME);
  211.     if (BlitPort) {
  212.         /*
  213.          *        The new blit routine has already been installed. So, send
  214.          *        it a message giving the command line options (if any)
  215.          *        to the remote routine, telling it to update its own options.
  216.          */
  217.         MyPort = CreatePort(NULL, 0);
  218.         if (!MyPort) {
  219.             print("CpuBlit: couldn't create local message port.\n");
  220.             exit(10);
  221.         }
  222.         for (i = 1; i < argc; i++) {
  223.             MyMsg.opt                = argv[i][1];
  224.             MyMsg.msg.mn_Length        = sizeof(MyMsg);
  225.             MyMsg.msg.mn_ReplyPort    = MyPort;
  226.             PutMsg(BlitPort, &MyMsg);
  227.             WaitPort(MyPort);
  228.             switch (MyMsg.result) {
  229.                 case MSG_OKAY:
  230.                     break;
  231.  
  232.                 case MSG_QUIT:
  233.                     print("CpuBlit removed successfully.\n");
  234.                     i = argc;    /* Force exit from loop */
  235.                     break;
  236.  
  237.                 case MSG_FAILED:
  238.                     print(
  239. "Couldn't remove CpuBlit; someone else has patched BltBitMap. Please remove\n"
  240. "any other utilities you have installed and then try again.\n");
  241.                     break;
  242.             }
  243.         }
  244.         DeletePort(MyPort);
  245.         exit(5);
  246.     }
  247.  
  248.     /*
  249.      *        This is the first time we are being run, so parse the
  250.      *        command line and then detach ourselves from the CLI to run
  251.      *        in the background.
  252.      */
  253.     for (i = 1; i < argc; i++) {
  254.         if (setopt(argv[i][1])) {
  255.             print("CpuBlit hasn't been installed yet.\n");
  256.             exit(5);
  257.         }
  258.     }
  259.  
  260.     if (!res(NAME, 5, mainloop, 4000)) {
  261.         print("Couldn't spawn background CpuBlit task.\n");
  262.         exit(10);
  263.     }
  264.     print(SIGNON);
  265. }
  266.