home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / diveex.zip / direct.c < prev    next >
Text File  |  1994-04-06  |  21KB  |  504 lines

  1. #define INCL_DEV
  2. #define INCL_DOS
  3. #define INCL_WIN
  4. #define INCL_32
  5. #include <os2.h>
  6. #include <memory.h>
  7. #include <stdio.h>               /* Used for printf only.                    */
  8. #include "direct.h"
  9.  
  10.  
  11. /* Global information about the current video device driver.                 */
  12. struct {
  13.        ULONG ulPhysicalAddress;  /* Physical address                         */
  14.        ULONG ulApertureSize;     /* 1 Meg, 4 Meg or 64k                      */
  15.        ULONG ulScanLineSize;     /* This is >= the screen width in bytes.    */
  16.        RECTL rctlScreen;         /* Device independant co-ordinates          */
  17.        } ApertureInfo;
  18. HAB   hab;                     /* Need a handle to an allocation block.      */
  19. HDC   hdc;                     /* Need a device context for the DecEsc's     */
  20. PBYTE pbLinearAddress;         /* Holds the linear address to the video card.*/
  21. ULONG ulTotalScreenColors= 0L; /* Holds the total number of colors.          */
  22. HFILE hDeviceDriver;           /* Handle to the device driver to do mapping. */
  23.  
  24.  
  25.  
  26.  
  27. /* This is the code to move data in memory directly to the video card.       */
  28. /* Note that pbSrc initially points to the bottom of the image, so as we     */
  29. /* work down the screen scan lines, we will work up the image.               */
  30. /* At this point, it's as simple as writing to any other memory location,    */
  31. /* excepting that there must be extra logic to check for bank switches.      */
  32. /* In your code, you may want to have two routines: 1 for machines that will */
  33. /* have full addressability to the video card (this is becomming more common */
  34. /* since VESA and PCI give 32-bit addresses now), and 1 for machines that    */
  35. /* have only 64KB apertures (for machines with video cards in ISA slots      */
  36. /* -- only 24 address lines-- and 16MB+ RAM, or cards that don't support     */
  37. /* apertures like 8514 or cards emulating 8514).                             */
  38. /* Note that the below routines are not optimized.  Clearly, if you take     */
  39. /* out color conversion or put the display logic right in your image         */
  40. /* generation routine it will save a bunch of time.                          */
  41.  
  42. ULONG DirectScreenDisplay ( PBYTE pbSrc, PBYTE pbPal, ULONG ulWidth, ULONG ulHeight )
  43.    {
  44.    #define DEVESC_ACQUIREFB   33010L
  45.    #define DEVESC_DEACQUIREFB 33020L
  46.    #define DEVESC_SWITCHBANK  33030L
  47.    ULONG ulNumBytes;
  48.    ULONG rc = 0L;
  49.    struct {
  50.           ULONG  fAFBFlags;
  51.           ULONG  ulBankNumber;
  52.           RECTL  rctlXRegion;
  53.           } acquireFb;
  54.  
  55.    /* Acquire the frame buffer, and switch the bank.                         */
  56.    /* If you do not acquire the frame buffer, some other thread might snatch */
  57.    /* the aperture away from you.  When you regain control, there's no       */
  58.    /* telling where you'll continue blitting.                                */
  59.    /* WARNING!  Make extra sure that you release the frame buffer!!!         */
  60.    /* If you do not, no application will be able to update the screen again! */
  61.    /* Note that you can not debug inside this devescape call (because you    */
  62.    /* have the screen locked).  However, you may find it usefull to comment  */
  63.    /* out the acquire/release calls for debugging purposes only.             */
  64.    acquireFb.rctlXRegion.xLeft   = 0L;
  65.    acquireFb.rctlXRegion.xRight  = 0L;
  66.    acquireFb.rctlXRegion.yTop    = 0L;
  67.    acquireFb.rctlXRegion.yBottom = 0L;
  68.    acquireFb.ulBankNumber        = 0L;
  69.    acquireFb.fAFBFlags           = 1L;  /* Acquire and switch simultaneously.*/
  70.    if ( DevEscape ( hdc, DEVESC_ACQUIREFB, sizeof (acquireFb),
  71.             (PBYTE) &acquireFb, (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  72.       return ( 1L );
  73.  
  74.    /* Check what the output screen color space is for the blit.              */
  75.    switch ( ulTotalScreenColors )
  76.       {
  77.  
  78.       /* 256 color mode routine.                                             */
  79.       /* Note that this routine assumes the OS/2 2.x palette.  If some other */
  80.       /* application has changed the palette, the colors will be incorrect.  */
  81.       /* Your PM application will have to process the WM_REALIZE_PALETTE     */
  82.       /* message to generate some sort of conversion table.  I don't do this.*/
  83.       case 256L:
  84.          {
  85.          ULONG X, Y, ulAperture = ApertureInfo.ulApertureSize;
  86.          PBYTE pbDst = pbLinearAddress;
  87.  
  88.          Y = ulHeight;
  89.          while ( Y-- )
  90.             {
  91.             /* Check if this line will pass through an aperture switch.      */
  92.             if ( ulAperture < ulWidth )
  93.                {
  94.                /* Move the rest of bytes for this aperture to the screen.    */
  95.                memcpy ( pbDst, pbSrc, ulAperture );
  96.                pbDst += ulWidth;
  97.                pbSrc += ulWidth;
  98.  
  99.                /* Now I need to do a bank switch.                            */
  100.                acquireFb.ulBankNumber++;
  101.                if ( DevEscape ( hdc, DEVESC_SWITCHBANK, 4L,
  102.                        (PBYTE) &acquireFb.ulBankNumber,
  103.                        (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  104.                   {
  105.                   rc = 1L;
  106.                   break;
  107.                   }
  108.  
  109.                /* Set up the rest of the line to move to the screen.         */
  110.                X = ulWidth - ulAperture;
  111.  
  112.                /* Reset the linear address to the begining of the bank.      */
  113.                pbDst = pbLinearAddress;
  114.                ulAperture = ApertureInfo.ulApertureSize + ulAperture;
  115.                }
  116.             else
  117.                /* There's room on this aperture for the whole line, so do it.*/
  118.                X = ulWidth;
  119.  
  120.             /* Move the pixels to the screen.                                */
  121.             memcpy ( pbDst, pbSrc, X );
  122.             pbSrc += X;
  123.             pbDst += X;
  124.  
  125.             /* Adjust the output line destination.                           */
  126.             pbDst += ApertureInfo.ulScanLineSize - ulWidth;
  127.             ulAperture -= ApertureInfo.ulScanLineSize;
  128.  
  129.             /* Adjust the input pointer to the previous line.                */
  130.             pbSrc -= ulWidth * 2;
  131.  
  132.             /* If aperture size is non-positive, then we do a switch banks.  */
  133.             if ( (LONG)ulAperture <= 0 )
  134.                {
  135.                ulAperture += ApertureInfo.ulApertureSize;
  136.                pbDst -= ApertureInfo.ulApertureSize;
  137.                acquireFb.ulBankNumber++;
  138.                if ( DevEscape ( hdc, DEVESC_SWITCHBANK, 4L,
  139.                        (PBYTE) &acquireFb.ulBankNumber,
  140.                        (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  141.                   {
  142.                   rc = 1L;
  143.                   break;
  144.                   }
  145.                }
  146.             }
  147.          }
  148.          break;
  149.  
  150.  
  151.       /* 64K color mode routine.                                             */
  152.       case 65536L:
  153.          {
  154.          ULONG X, Y, ulAperture = ApertureInfo.ulApertureSize;
  155.          PUSHORT pusDst = (PUSHORT) pbLinearAddress;
  156.          USHORT usColor;
  157.  
  158.          Y = ulHeight;
  159.          while ( Y-- )
  160.             {
  161.             /* Check if this line will pass through an aperture switch.      */
  162.             if ( ulAperture < ulWidth * 2 )
  163.                {
  164.                /* Move the rest of bytes for this aperture to the screen.    */
  165.                X = ulAperture >> 1;    /* Remember, ulAperture is in bytes.  */
  166.                while ( X-- )
  167.                   {
  168.                   /* First move blue into position 0000 0000 000b bbbb.      */
  169.                   usColor = * ( pbPal + *pbSrc * 4 ) >> 3;
  170.                   /* Now or in green into position 0000 0ggg gggb bbbb.      */
  171.                   usColor += ( * ( pbPal + *pbSrc * 4 + 1 ) >> 2 ) << 5;
  172.                   /* Finally or red into position rrrr rggg gggb bbbb.       */
  173.                   usColor += ( * ( pbPal + *pbSrc * 4 + 2 ) >> 3 ) << 11;
  174.                   /* Output the color and update the pointers.               */
  175.                   *pusDst ++= usColor;
  176.                   pbSrc++;
  177.                   }
  178.  
  179.                /* Now I need to do a bank switch.                            */
  180.                acquireFb.ulBankNumber++;
  181.                if ( DevEscape ( hdc, DEVESC_SWITCHBANK, 4L,
  182.                        (PBYTE) &acquireFb.ulBankNumber,
  183.                        (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  184.                   {
  185.                   rc = 1L;
  186.                   break;
  187.                   }
  188.  
  189.                /* Set up the rest of the line to move to the screen.         */
  190.                X = ulWidth - ( ulAperture >> 1 );
  191.  
  192.                /* Reset the linear address to the begining of the bank.      */
  193.                pusDst = (PUSHORT) pbLinearAddress;
  194.                ulAperture = ApertureInfo.ulApertureSize + ulAperture;
  195.                }
  196.             else
  197.                /* There's room on this aperture for the whole line, so do it.*/
  198.                X = ulWidth;
  199.  
  200.             /* Move the pixels to the screen.                                */
  201.             while ( X-- )
  202.                {
  203.                usColor = * ( pbPal + *pbSrc * 4 ) >> 3;
  204.                usColor += ( * ( pbPal + *pbSrc * 4 + 1 ) >> 2 ) << 5;
  205.                usColor += ( * ( pbPal + *pbSrc * 4 + 2 ) >> 3 ) << 11;
  206.                *pusDst ++= usColor;
  207.                pbSrc++;
  208.                }
  209.  
  210.             /* Adjust the output line destination.                           */
  211.             pusDst += ( ApertureInfo.ulScanLineSize >> 1 ) - ulWidth;
  212.             ulAperture -= ApertureInfo.ulScanLineSize;
  213.  
  214.             /* Adjust the input pointer to the previous line.                */
  215.             pbSrc -= ulWidth * 2;
  216.  
  217.             /* If aperture size is non-positive, then we do a switch banks.  */
  218.             if ( (LONG)ulAperture <= 0 )
  219.                {
  220.                ulAperture += ApertureInfo.ulApertureSize;
  221.                pusDst -= ( ApertureInfo.ulApertureSize ) >> 1;
  222.                acquireFb.ulBankNumber++;
  223.                if ( DevEscape ( hdc, DEVESC_SWITCHBANK, 4L,
  224.                        (PBYTE) &acquireFb.ulBankNumber,
  225.                        (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  226.                   {
  227.                   rc = 1L;
  228.                   break;
  229.                   }
  230.                }
  231.             }
  232.          }
  233.          break;
  234.  
  235.  
  236.       /* 16M color routine.                                                  */
  237.       case 16777216L:
  238.          {
  239.          ULONG X, Y, ulAperture = ApertureInfo.ulApertureSize;
  240.          PBYTE pbDst = pbLinearAddress;
  241.  
  242.          Y = ulHeight;
  243.          while ( Y-- )
  244.             {
  245.             /* Check if this line will pass through an aperture switch.      */
  246.             if ( ulAperture / 3 < ulWidth )
  247.                {
  248.                /* Move the pixels for the rest of the aperture to the screen.*/
  249.                X= ulAperture / 3;
  250.                while ( X-- )
  251.                   {
  252.                   /* Write out the blue byte.                                */
  253.                   *pbDst ++= * ( pbPal + *pbSrc * 4 );
  254.                   /* Write out the green byte.                               */
  255.                   *pbDst ++= * ( pbPal + *pbSrc * 4 + 1 );
  256.                   /* Write out the red byte.                                 */
  257.                   *pbDst ++= * ( pbPal + *pbSrc * 4 + 2 );
  258.                   /* Update the source pointer.                              */
  259.                   pbSrc++;
  260.                   }
  261.  
  262.                /* Now I need to do a bank switch.                            */
  263.                acquireFb.ulBankNumber++;
  264.                if ( DevEscape ( hdc, DEVESC_SWITCHBANK, 4L,
  265.                        (PBYTE) &acquireFb.ulBankNumber,
  266.                        (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  267.                   {
  268.                   rc= 1L;
  269.                   break;
  270.                   }
  271.  
  272.                /* Set up the rest of the line to move to the screen.         */
  273.                X= ulWidth - ( ulAperture / 3 );
  274.  
  275.                /* Reset the linear address to the begining of the bank.      */
  276.                pbDst= pbLinearAddress;
  277.                ulAperture= ApertureInfo.ulApertureSize + ulAperture;
  278.                }
  279.             else
  280.                /* There's room on this aperture for the whole line, so do it.*/
  281.                X= ulWidth;
  282.  
  283.             /* Move the pixels to the screen.                                */
  284.             while ( X-- )
  285.                {
  286.                *pbDst ++= * ( pbPal + *pbSrc * 4 );
  287.                *pbDst ++= * ( pbPal + *pbSrc * 4 + 1 );
  288.                *pbDst ++= * ( pbPal + *pbSrc * 4 + 2 );
  289.                pbSrc++;
  290.                }
  291.  
  292.             /* Adjust the output line destination.                           */
  293.             pbDst+= ApertureInfo.ulScanLineSize - ulWidth - ulWidth - ulWidth;
  294.             ulAperture-= ApertureInfo.ulScanLineSize;
  295.  
  296.             /* Adjust the input pointer to the previous line.                */
  297.             pbSrc -= ulWidth * 2;
  298.  
  299.             /* If aperture size is non-positive, then we do a switch banks.  */
  300.             if ( (LONG)ulAperture <= 0 )
  301.                {
  302.                ulAperture+= ApertureInfo.ulApertureSize;
  303.                pbDst-= ApertureInfo.ulApertureSize;
  304.                acquireFb.ulBankNumber++;
  305.                if ( DevEscape ( hdc, DEVESC_SWITCHBANK, 4L,
  306.                        (PBYTE) &acquireFb.ulBankNumber,
  307.                        (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  308.                   {
  309.                   rc= 1L;
  310.                   break;
  311.                   }
  312.                }
  313.             }
  314.          }
  315.          break;
  316.  
  317.  
  318.       default:
  319.          rc= 2L;        /* Bad mode or incorrect initialization.             */
  320.       }
  321.  
  322.    /* Release the frame buffer... this is important.                         */
  323.    if ( DevEscape ( hdc, DEVESC_DEACQUIREFB, (ULONG)0L, (PBYTE) NULL,
  324.                     (PLONG)0L, (PBYTE) NULL ) !=DEV_OK )
  325.       return ( 3L );
  326.  
  327.    return ( rc );
  328.    }
  329.  
  330.  
  331.  
  332. /* This routine will open up a handle to a device driver with the service    */
  333. /* to map physical ram to a linear address (specifically SMVDD.SYS).         */
  334. /* You can find SMVDD.SYS on the MMPM/2 diskettes.                           */
  335.  
  336. ULONG MapPhysicalToLinear ( ULONG ulPhysicalAddress )
  337.    {
  338.    ULONG  ulActionTaken;
  339.    ULONG  ulDLength;
  340.    ULONG  ulPLength;
  341.    struct {
  342.           ULONG   hstream;
  343.           ULONG   hid;
  344.           ULONG   ulFlag;
  345.           ULONG   ulPhysAddr;
  346.           ULONG   ulVram_length;
  347.           } parameter;
  348.    #pragma pack (1)
  349.    struct {
  350.           USHORT usXga_rng3_selector;
  351.           ULONG  ulLinear_address;
  352.           } ddstruct;
  353.    #pragma pack ()
  354.  
  355.    /* Attempt to open up the device driver.                                  */
  356.    if ( DosOpen( (PSZ)"\\DEV\\SMVDD01$", (PHFILE) &hDeviceDriver,
  357.             (PULONG) &ulActionTaken, (ULONG)  0L, (ULONG) FILE_SYSTEM,
  358.             OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE  |
  359.             OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READONLY, (ULONG) 0L)   )
  360.       return ( 3L );
  361.  
  362.    /* Set up the parameters for the IOCtl to map the vram to linear addr.    */
  363.    parameter.hstream       = 0L;
  364.    parameter.hid           = 0L;
  365.    parameter.ulFlag        = 1L;     /* Meaning MapRam. */
  366.    parameter.ulPhysAddr    = ulPhysicalAddress;
  367.    parameter.ulVram_length = ApertureInfo.ulApertureSize;
  368.    ulPLength               = sizeof (parameter);
  369.    ulDLength               = 0L;
  370.  
  371.    /* Call the IOCtl to do the map.                                          */
  372.    if ( DosDevIOCtl ( hDeviceDriver, (ULONG)0x81,
  373.                       (ULONG)0x42L, (PVOID)¶meter,
  374.                       (ULONG)ulPLength, (PULONG)&ulPLength,
  375.                       (PVOID)&ddstruct, (ULONG)6, (PULONG)&ulDLength ) )
  376.       return ( 4L );
  377.  
  378.    /* Set the variable to the linear address, and return.                    */
  379.    pbLinearAddress= (PBYTE) ddstruct.ulLinear_address;
  380.  
  381.    return ( 0L );
  382.    }
  383.  
  384.  
  385.  
  386. /* This routine will make a call to the video device driver to see if it     */
  387. /* supports direct video, and if it does, gets information about the card    */
  388. /* and maps the physical address to a linear address (addressabel by ring 3).*/
  389.  
  390. ULONG DirectScreenInit ( VOID )
  391.    {
  392.    #define DEVESC_GETAPERTURE 33000L
  393.    ULONG          rc;
  394.    ULONG          ulFunction;
  395.    LONG           lOutCount;
  396.    HPS            hps;
  397.    DEVOPENSTRUC   dop= {0L,(PSZ)"DISPLAY",NULL,0L,0L,0L,0L,0L,0L};
  398.  
  399.    /* Check to see that we are not already initialized.                      */
  400.    if ( ulTotalScreenColors )
  401.       return ( 0xffffffff );
  402.  
  403.    /* Open a presentation space so we can query the number of screen colors. */
  404.    hab= WinInitialize ( 0L );
  405.    hps= WinGetPS ( HWND_DESKTOP );
  406.    hdc= DevOpenDC ( hab, OD_MEMORY, (PSZ)"*", 5L,
  407.                                        (PDEVOPENDATA)&dop, (HDC)NULL);
  408.    DevQueryCaps ( hdc, CAPS_COLORS, 1L, (PLONG)&ulTotalScreenColors);
  409.  
  410.    /* Determine if the devescape calls are supported DCR96 implemented.      */
  411.    ulFunction = DEVESC_GETAPERTURE;
  412.    if ( DevEscape( hdc, DEVESC_QUERYESCSUPPORT, 4L,
  413.                   (PBYTE)&ulFunction, NULL, (PBYTE)NULL ) == DEV_OK )
  414.       {
  415.       /* The devescape calls are okay, so lets find out the aperture info.   */
  416.       lOutCount= sizeof (ApertureInfo);
  417.       if ( DevEscape ( hdc, DEVESC_GETAPERTURE, 0L, (PBYTE) NULL,
  418.             &lOutCount, (PBYTE)&ApertureInfo) != DEV_OK )
  419.          {
  420.          ulTotalScreenColors= 0L;
  421.          rc= 2L;
  422.          }
  423.       else
  424.          {
  425.          /* Let's take the ulScanLineSize value and change it from pixels    */
  426.          /* to number of bytes per scan line.                                */
  427.          if ( ulTotalScreenColors==16L )
  428.             ApertureInfo.ulScanLineSize= ApertureInfo.ulScanLineSize >> 1;
  429.          else if ( ulTotalScreenColors==65536L )
  430.             ApertureInfo.ulScanLineSize= ApertureInfo.ulScanLineSize << 1;
  431.          else if ( ulTotalScreenColors==16777216L )
  432.             ApertureInfo.ulScanLineSize= ApertureInfo.ulScanLineSize +
  433.             ( ApertureInfo.ulScanLineSize << 1 );
  434.          /* else it's 256, and already the correct size.                     */
  435.          rc= 0L;
  436.          }
  437.       }
  438.  
  439.    else /* DCR96 aperture calls not suppoted.                                */
  440.       {
  441.       ulTotalScreenColors= 0L;
  442.       rc= 1L;
  443.       }
  444.  
  445.    /* Release the presentation space, but keep the device contect and hab.   */
  446.    WinReleasePS ( hps );
  447.  
  448.    /* If no error, then map the address to a ring 3 addressable one.         */
  449.    if ( !rc )
  450.       rc= MapPhysicalToLinear ( ApertureInfo.ulPhysicalAddress );
  451.  
  452.    return ( rc );
  453.    }
  454.  
  455.  
  456.  
  457.  
  458. /* This routine will terminate the instance of the device driver.            */
  459.  
  460. ULONG DirectScreenTerm ( VOID )
  461.    {
  462.    /* Check to see if we are actually initialized.                           */
  463.    if ( !ulTotalScreenColors )
  464.       return ( 1L );
  465.  
  466.    /* Reset our number of screen colors to show deinitialization.            */
  467.    ulTotalScreenColors= 0L;
  468.  
  469.    /* Close up our device context and allocation block.                      */
  470.    DevCloseDC ( hdc );
  471.    WinTerminate ( hab );
  472.  
  473.    /* Close up the device driver that did the mapping to linear address.     */
  474.    return ( DosClose ( hDeviceDriver ) );
  475.    }
  476.  
  477.  
  478.  
  479. /* You can nail this routine, it's for printing aperture information only.   */
  480.  
  481. ULONG DirectPrintInfo ( VOID )
  482.    {
  483.    printf ( "Aperture information specific to your hardware:\n" );
  484.    printf ( "      ulScanLineSize= %u bytes\n", ApertureInfo.ulScanLineSize );
  485.    printf ( "   rctlScreen.xRight= %u pels\n", ApertureInfo.rctlScreen.xRight );
  486.    printf ( "  rctlScreen.yBottom= %u pels\n", ApertureInfo.rctlScreen.yBottom );
  487.    printf ( "    rctlScreen.xLeft= %u pels\n", ApertureInfo.rctlScreen.xLeft );
  488.    printf ( "     rctlScreen.yTop= %u pels\n", ApertureInfo.rctlScreen.yTop );
  489.    printf ( "          ulPhysAddr= 0x%8.8x\n", ApertureInfo.ulPhysicalAddress );
  490.    printf ( "      ulApertureSize= %u bytes, ", ApertureInfo.ulApertureSize );
  491.    if ( ApertureInfo.ulApertureSize >= 1048576L )
  492.       printf ( "%u MB\n", ApertureInfo.ulApertureSize >> 20 );
  493.    else
  494.       printf ( "%u KB\n", ApertureInfo.ulApertureSize >> 10 );
  495.    printf ( "         ulNumColors= %u", ulTotalScreenColors );
  496.    if ( ulTotalScreenColors >= 1048576L )
  497.       printf ( ", %u M\n", ulTotalScreenColors >> 20 );
  498.    else if ( ulTotalScreenColors >= 1024L )
  499.       printf ( ", %u K\n", ulTotalScreenColors >> 10 );
  500.    else
  501.       printf ( "\n" );
  502.    return ( 0 );
  503.    }
  504.