home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * CPUBLIT.C
- *
- * (C) Copyright Eddy Carroll, 1991. Freely distributable.
- *
- * CpuBlit replaces the BltBitMap function in graphics.library with
- * a version that uses the CPU where practical. This is up to 2.8
- * times faster on a 68030 system.
- *
- * This moudle installs the new blit routine, handles parsing the
- * command line options etc. Scroll.s does the actual blitting.
- *
- ***************************************************************************/
-
- #ifndef LATTICE_50
- #include "system.h"
- typedef void (*__fptr)(); /* The sort of thing returned by SetFunction */
- #endif
-
- #include "scroll.h"
-
- #define NAME "CpuBlit V0.96"
- #define PORTNAME NAME
- #define SIGNON NAME " \251 1991 Eddy Carroll.\n"
-
- #define print(s) Write(Output(), s, strlen(s))
- #define BltBitMap_LVO (-30) /* Offset of BltBitMap in graphics.library */
-
- char HelpMsg[] =
- NAME " \251 Eddy Carroll, Feb 1991. Replaces blitter with 68020/68030.\n"
- "Usage: CpuBlit {option}\n"
- "\n"
- " -a Always use CPU to do blits (default setting)\n"
- " -1 Use CPU for blits unless another task is ready to run\n"
- " -2 Use CPU for blits unless more than one task is ready to run\n"
- " -b Use CPU even if bitmap isn't initialised correctly\n"
- " -o Use CPU only when a single bitmap is involved\n"
- " -s Use CPU for blits unless a blit is already in progress\n"
- " -q Remove CpuBlit from the system\n"
- "\n";
-
- /****************************************************************************
- *
- * Globals
- *
- ***************************************************************************/
-
- struct Gfxbase *GfxBase;
-
- struct MyMsg {
- struct Message msg; /* Standard message structure */
- int opt; /* Requested mode of operation */
- int result; /* True if succesfully terminated */
- } MyMsg, *msg;
-
- #define MSG_OKAY 0 /* Message was handled correctly */
- #define MSG_QUIT 1 /* CpuBlit was removed safely */
- #define MSG_FAILED 2 /* CpuBlit couldn't be removed */
-
-
- /****************************************************************************
- *
- * Sets the blitter function to be executed according to the character
- * option specified. Returns 1 if QUIT was requested, else zero.
- *
- ***************************************************************************/
-
- int setopt(int opt)
- {
- switch (opt) {
- case 'a': BlitFunc = StartBlit;
- OnlySingle = 0;
- Broken = 0; return (0);
- case 'b': Broken = 1; return (0);
- case 'o': OnlySingle = 1; return (0);
- case 's': BlitFunc = ShareBlit; return (0);
- case '1': BlitFunc = Friend1; return (0);
- case '2': BlitFunc = Friend2; return (0);
- case 'q': BlitFunc = ExitBlit; return (1);
- default:
- print(HelpMsg);
- exit(5);
- }
- }
-
- /****************************************************************************
- *
- * This is the main event loop. It sits waiting for a message from
- * other invocations of CpuBlit, which tell it to either change the
- * current settings or to remove itself.
- *
- ***************************************************************************/
-
- void mainloop(void)
- {
- struct MsgPort *MyPort;
- int installed = 1;
-
- /*
- * We have to create our rendezvous port here rather than in the
- * mainline, since the message port depends on task information etc.
- * This is not altogether satisfactory since if it fails, there is
- * no way to tell the user (as a background task, we have no stdin
- * or stdout). But since port creation is unlikely to fail anyway,
- * it's not a big problem.
- */
- MyPort = CreatePort(PORTNAME, 0);
- if (!MyPort)
- return;
-
- /*
- * Now have to open graphics.library, so that we can add in our
- * new patch. As above, if this fails there is no easy way to
- * tell the user. However, at least it won't crash the system.
- */
- GfxBase = OpenLibrary("graphics.library", 0);
- if (!GfxBase)
- return;
-
- BltBitMapAddress = SetFunction(GfxBase, BltBitMap_LVO, NewBltBitMap);
-
- /*
- * Now wait a message from another copy of CpuBlit. This will
- * either contain an updated command line argument or else a
- * request to quit.
- */
- do {
- __fptr oldptr;
-
- WaitPort(MyPort);
- while ((msg = (struct MyMsg *)GetMsg(MyPort)) != NULL) {
- if (setopt(msg->opt) == 0) {
- /*
- * Received a valid command line argument and
- * handled it.
- */
- msg->result = MSG_OKAY;
- } else {
- /*
- * Try and remove ourselves. We have to surround this
- * with Forbid() to make sure that no other tasks manage
- * to call BltBitMap() in the case where we restore the
- * original vector and then realise that its current
- * replacement actually pointed to something other than
- * CpuBlit.
- */
- Forbid();
- oldptr = SetFunction(GfxBase, BltBitMap_LVO, BltBitMapAddress);
- if (oldptr == NewBltBitMap) {
- installed = 0;
- msg->result = MSG_QUIT;
- } else {
- SetFunction(GfxBase, BltBitMap_LVO, oldptr);
- msg->result = MSG_FAILED;
- }
- Permit();
- }
- ReplyMsg(msg);
- }
- } while (installed);
-
- /*
- * Now our patch has been removed, it only remains to free up the
- * code. It is possible that someone is still in our blitter code.
- * We can determine this fairly safely by looking at UsageCount;
- * if this is -1, nobody is in our code. Otherwise, we wait until
- * it is -1 (delaying for a little while inbetween to give programs
- * a chance to run).
- *
- * We also set the blitter test function to ExitBlit, so that if
- * someone does slip through our test and end up inside our code,
- * they will get rerouted back to the normal blitter code almost
- * immediately.
- */
- DeletePort(MyPort);
- BlitFunc = ExitBlit;
-
- while (UsageCount != -1)
- Delay(10); /* Wait 0.2 seconds */
-
- /*
- * Now we're completely finished so we can close the libraries
- * and exit.
- */
- CloseLibrary(GfxBase);
- }
-
-
- /****************************************************************************
- *
- * Mainline
- *
- ***************************************************************************/
-
- void main(int argc, char **argv)
- {
- struct MsgPort *BlitPort, *MyPort;
- int i;
-
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-')
- setopt(argv[i][1]); /* Check for valid command line option */
- else {
- print(HelpMsg);
- exit(5);
- }
- }
-
- BlitPort = FindPort(PORTNAME);
- if (BlitPort) {
- /*
- * The new blit routine has already been installed. So, send
- * it a message giving the command line options (if any)
- * to the remote routine, telling it to update its own options.
- */
- MyPort = CreatePort(NULL, 0);
- if (!MyPort) {
- print("CpuBlit: couldn't create local message port.\n");
- exit(10);
- }
- for (i = 1; i < argc; i++) {
- MyMsg.opt = argv[i][1];
- MyMsg.msg.mn_Length = sizeof(MyMsg);
- MyMsg.msg.mn_ReplyPort = MyPort;
- PutMsg(BlitPort, &MyMsg);
- WaitPort(MyPort);
- switch (MyMsg.result) {
- case MSG_OKAY:
- break;
-
- case MSG_QUIT:
- print("CpuBlit removed successfully.\n");
- i = argc; /* Force exit from loop */
- break;
-
- case MSG_FAILED:
- print(
- "Couldn't remove CpuBlit; someone else has patched BltBitMap. Please remove\n"
- "any other utilities you have installed and then try again.\n");
- break;
- }
- }
- DeletePort(MyPort);
- exit(5);
- }
-
- /*
- * This is the first time we are being run, so parse the
- * command line and then detach ourselves from the CLI to run
- * in the background.
- */
- for (i = 1; i < argc; i++) {
- if (setopt(argv[i][1])) {
- print("CpuBlit hasn't been installed yet.\n");
- exit(5);
- }
- }
-
- if (!res(NAME, 5, mainloop, 4000)) {
- print("Couldn't spawn background CpuBlit task.\n");
- exit(10);
- }
- print(SIGNON);
- }
-