
 
 
  TAKING A DIVE
  _____________
 
  Software motion video implementation under OS/2 has attained
  sizable performance advantages by enabling video decompressors to
  directly write to video memory.  While this technique provides good
  performance, it has the disadvantage that each decompressor must
  deal with the pel format of the display in various modes, clipping
  the output to visible regions, and any scaling that is to be
  performed. Additionally, on bank-switched video displays, the
  decompressor must return on partial frames to enable the video
  stream handler to switch banks.
 
  The Direct Interface Video Extensions (DIVE) consolidate the
  complexities of dealing with direct video frame buffer access
  (sometimes referred to as "direct access" or "black hole") into a
  single API DLL that enables efficient transfer to video memory with
  clipping, scaling, and color space conversion.  The optimized
  screen access functionality provided by DIVE can be used for motion
  video display, fast image updates for interactive games, and fast
  screen display by 3-D graphics libraries.
 
 
  ALL ABOUT DIVE
  ______________
 
  DIVE is a DLL that provides optimized blitting performance for
  motion video subsystems and applications that perform rapid screen
  updates in the OS/2 PM and full-screen environments.  Using DIVE
  functions, applications can either write directly to video memory
  or use the DIVE blitter to get a high level of screen update
  performance, image scaling, color space conversion, and bank-switch
  display support.  The DIVE blitter utilizes acceleration hardware
  when present and applicable to the function being performed.
 
 
  DIVE DISPLAY ENGINE FUNCTION CHARACTERISTICS
  ____________________________________________
 
  The DIVE system-level interface abstracts the low-level device
  driver DIVE interface to a higher level and adds software emulation
  for operations that all DIVE users have had to do.  This
  system-level interface is referred to as the DIVE engine.
 
  The DIVE engine consists of a single, stand-alone DLL that exports
  the following functions:
 
   o  Query for display capabilities
   o  Open instance
   o  Visible region specification
   o  Allocation of image data buffers
   o  Buffer-to-screen/buffer-to-buffer transfer (blitter) setup
   o  8-bit CLUT color palette simulation/specification
   o  Transfer buffer to image display/transfer buffer to buffer
   o  Utility functions useful for direct access, including
      window starting-address calculation
   o  Frame buffer acquire/de-acquire
   o  VRAM bank selection (for bank-switched displays)
   o  Close instance
 
  The display engine enables subsystem components (for example, video
  CODECs) and applications to either directly access the video buffer
  or to use the display engine screen transfer functions.  If direct
  access is used, the using component or application is responsible
  for writing to the frame buffer format for the current display mode
  and correctly clipping the output.  In addition, the component is
  responsible for acquiring and bank switching the display apertures.
  If display engine screen transfer functions are used, the display
  engine handles clipping, pel format and color space conversions,
  and any necessary hardware serialization.  The input formats and
  their corresponding color encoding specification values are:
 
   o  CLUT 8 (256 color) - "LUT8"
   o  8-bit greyscale - "GREY"
   o  RGB 16 (5-6-5, 5-5-5) - "R565", "R555", "R664"
   o  RGB 24 (R-G-B, B-G-R) - "RGB3", "BGR3"
   o  RGB 32 (R-G-B, B-G-R) - "RGB4", "BGR4"
   o  YUV 9 - DVI/Indeo three-plane color subsampled - "YUV9"
   o  YUV 411 - "YUV411"
   o  YUV 422 -  "YUV422"
   o  YUV CCIR601 - three-plane 2x2 color subsampled (MJPEG,
      MPEG) - "Y2X2"
   o  YUV CCIR601 - three-plane 4x4 color subsampled  - "Y4X4"
 
  The output formats are:
 
   o  CLUT 8 (256 color)
   o  RGB 16 (5-6-5, 5-5-5, 6-6-4)
   o  RGB 24 (R-G-B, B-G-R)
   o  RGB 32 (R-G-B-x,  B-G-R-x)
   o  Blitter Operation
 
  There are two main ways to use DIVE:  using the DIVE blitter and
  using direct-frame buffer access.  DIVE applications gain access to
  DIVE functions by obtaining a DIVE handle:
 
        ULONG       ulErrorCode;
        HDIVE       *phDiveInst;
        BOOL        fNonScreenInstance;
        PPVOID      ppFrameBuffer;
 
        ulErrorCode = DiveOpen( *phDiveInst, fNonScreenInstance, ppFrameBuffer );
 
  A corresponding DiveClose function must be called at application
  termination.  If DIVE is to be used for blitting to the screen, set
  fNonScreenInstance to FALSE.  Otherwise, if DIVE is to be used only
  for off-screen sizing or color format conversion, set
  fNonScreenInstance to TRUE.  If fNonScreenInstance is FALSE, a
  pointer to the frame buffer is returned in ppFrameBuffer.
 
 
  DIVE IMAGE BUFFER
  _________________
 
  Because DIVE will use off-screen VRAM where available for
  acceleration of blitting operations, the application should
  allocate all source blitting buffers from DIVE whenever possible.
  To allocate a buffer, the application would make the following
  call:
 
 
        ULONG   ulBufNum;
        FOURCC  fccColorSpace;
        ULONG   ulWidth, ulHeight, ulLineSizeBytes;
        PBYTE   pbImageBuffer;
 
        ulErrorCode = DiveAllocImageBuffer(
                hDive,                   /* DIVE handle             */
                &ulBufNum,               /* Buffer number (output)  */
                fccColorSpace,           /* Color format            */
                ulWidth, ulHeight,       /* Size of maximum image   */
                ulLineSizeBytes,
                &pbImageBuffer);
 
  A corresponding DiveFreeImageBuffer function call is used to
  deallocate the buffer when it is no longer needed.  The color
  format of the image buffer is described by fccColorSpace.  The DIVE
  interface defines constants for a variety of 8-, 16-, and 24-bit
  color encoding schemes.  After a buffer is allocated and before it
  can be used for blitting, it must be accessed as shown in the
  following example:
 
        PBYTE   pbImageBuffer;
        ULONG   ulBufferScanLineBytes, ulBufferScanLines;
 
        ulErrorCode = DiveBeginImageBufferAccess(
                hDiveInst,                /* DIVE handle                  */
                ulBufferNumber,           /* Buffer number                */
                &pbImageBuffer,           /* Ptr to image buffer (output) */
                &ulBufferScanLineBytes);  /* Scan line length (output)    */
                &ulBufferScanLines);      /* Scan lines (output)          */
 
  DIVE calculates the number of bytes per scan line for the image
  buffer (based on the color format) and returns the value in
  ulBufferScanLineBytes.  The application can now write color data
  into pbImageBuffer.  For example, the application could open a
  bit-map file and read the bit-map data directly into the image
  buffer.  After the data has been written, the application calls
  DiveEndImageBufferAccess to deaccess the buffer.  Be sure to use
  scan line bytes (you might have to read a line at a time).
 
 
  DIVE PALETTE
  ____________
 
  Applications must inform DIVE of the state of the physical palette
  upon initialization and whenever the physical palette changes.  At
  application initialization, and in response to a WM_REALIZEPALETTE
  message, the application calls the following sequence:
 
 
        BYTE       pbPal1024;
 
        /* Query the physical palette from PM   */
        GpiQueryRealColors( hps, 0, 0, 256, (PLONG)pbPal);
 
        /* Pass it to DIVE                      */
        DiveSetDestinationPalette( hDive, (PBYTE)pbPal);
 
 
  If the application itself is using palettes, these palettes must
  also be communicated to DIVE through the DiveSetSourcePalette
  function. For example, if the application is using DIVE to blit
  256-color palettized images to the screen, the application must
  send the image palette with a call to DiveSetSourcePalette.  If a
  sequence of images is being used for animation and the palette
  remains constant through the series, it is necessary to call
  DiveSetSourcePalette only once before blitting the first image in
  the series.
 
  DIVE provides high-speed screen updates by bypassing PM.  In order
  to maintain the integrity of the PM desktop, DIVE applications must
  notify DIVE whenever the visible region of the application window
  changes so that output may be clipped accordingly.
 
  Every DIVE application will request visible region notification at
  window initialization time with the following call:
 
        WinSetVisibleRegionNotify( hwnd, TRUE);
 
  The first parameter is the handle of the window where the graphics
  operations will appear, and the second parameter turns on
  notification for that window.  (A corresponding
  WinSetVisibleRegionNotify(hwnd, FALSE) call should be made to turn
  notification off at window termination time.)
 
  Whenever the window's visible region begins to change, either
  because the window is being moved or sized or another window or
  icon overlaying the window is being moved or sized, the window will
  receive a WM_VRNDISABLED message.  In response to this message,
  the DIVE application will call DiveSetupBlitter (hDiveInst, 0).
  After the movement is complete, the window will receive a
  WM_VRNENABLED message.  In response to this message, the DIVE
  application will query the new visible region, using
  WinQueryVisibleRegion as follows:
 
        hps = WinGetPS( hwnd );
        hrgn = GpiCreateRegion( hps, 0, NULL);
        WinQueryVisibleRegion( hwnd, hrgn);
 
  Whenever the visible region, source color format, or image source
  or destination size changes, the DIVE application must pass the
  changes to DIVE with a call to DiveSetupBlitter.  Note that it is
  necessary to pass the rectangles for the region in window
  coordinates and the position of the window in desktop coordinates.
 
  First, get the rectangles and window coordinates:
 
        RECTL   rctls50;      /* Rectangles for visible rgn   */
        RGNRECT rgnCtl;         /* Region control struct        */
        SETUP_BLITTER   SetupBlitter;   /* DiveSetupBlitter struct      */
        POINTL  pointl;
        SWP     swp;
        HPS     hps;
        HRGN    hrgn;
 
        rgnCtl.ircStart = 0;    /* Enumerate rectangles */
        rgnCtl.crc = 50;        /* Starting with first  */
        rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT;
 
        /* Get rectangles for the visible region        */
        GpiQueryRegionRects( hps, hrgn, NULL, &rgnCtl, rctls);
 
        /* Find the window position relative to its parent.     */
        WinQueryWindowPos( hwnd, &swp );
 
        /* Map window position to the desktop.  */
        pointl.x = swp.x;
        pointl.y = swp.y;
        WinMapWindowPoints( WinQueryWindow( hwnd, QW_PARENT ),
                HWND_DESKTOP, &pointl, 1);
 
  Then, pass the information to DIVE:
 
        /* Tell DIVE about the new settings.  */
        SIZEL   sizlSrcImg;     /* Size of source image */
        FOURCC  fccSrcColors;   /* Source image format  */
 
        SetupBlitter.ulStructLen = sizeof ( SETUP_BLITTER );
        SetupBlitter.fInvert = 0;
        SetupBlitter.fccSrcColorFormat = fccSrcColors;
        SetupBlitter.ulSrcLineSizeBytes = ulScanLineBytes;
        SetupBlitter.ulSrcWidth = sizlSrcImg.cx;
        SetupBlitter.ulSrcHeight = sizlSrcImg.cy;
        SetupBlitter.ulSrcPosX = 0;
        SetupBlitter.ulSrcPosY = 0;
        SetupBlitter.fccDstColorFormat = FOURCC_SCRN;
        SetupBlitter.ulDstLineSizeBytes = 0;
        SetupBlitter.ulDstWidth = swp.cx;
        SetupBlitter.ulDstHeight = swp.cy;
        SetupBlitter.ulDstPosX = 0;
        SetupBlitter.ulDstPosY = 0;
        SetupBlitter.lScreenPosX = pointl.x;
        SetupBlitter.lScreenPosY = pointl.y;
        SetupBlitter.ulNumDstRects = rgnCtl.crcReturned;
        SetupBlitter.pVisDstRects = rctls;
        DiveSetupBlitter ( hDive, &SetupBlitter );
 
  The color format of the source image is described by fccSrcColors.
 
  Note that, in this example, the DIVE blitter is set up to blit to
  the screen, but that need not be the case.  DIVE could also be used
  to perform color conversion and/or stretch blitting to a
  destination image.  The destination color-encoding format would be
  indicated in fccDstColorFormat; ulDstWidth and ulDstHeight would be
  set to the size of the destination image; ulNumDstRects would be
  set to 1; and pVisDstRects would point to a single rectangle with
  xLeft=yBottom=0 xRight=ulDstWidth and yTop=ulDstHeight.
 
 
  DIRECT FRAME-BUFFER ACCESS
  __________________________
 
  As mentioned earlier, *ppFrameBuffer returned by DiveOpen gives
  direct addressability to the frame buffer.  In order to write
  directly to the frame buffer, the DIVE application must perform its
  own clipping, color conversion, and bank switching. The following
  functions are provided for direct-frame buffer access:
 
   o  DiveAcquireFrameBuffer
   o  DiveDeacquireFrameBuffer
   o  DiveSwitchBank
   o  DiveCalcFrameBufferAddress
 
  The DiveQueryCaps function returns whether the display subsystem is
  bank-switched. DIVE provides another function called
  DiveCalcFrameBufferAddress to get to a location in the frame buffer
  that corresponds to a rectangle in desktop  coordinates:
 
        PRECTL prectlDest;           /* Image rectangle in desktop coors  */
        PVOID pDestinationAddress;   /* Frame buffer address - output     */
        PULONG pulBankNumber;        /* Display h/w bank number - output  */
        PULONG pulRemlinesInBank;    /* Lines left in bank - output       */
 
        ulErrorCode = DiveCalcFrameBufferAddress(
                hDiveInst, &prectlDest, &pDestinationAddress,
                &pulBankNumber, &pulRemlinesInBank);
 
  To accomplish correct clipping, prectlDest must be in the
  application window's visible region.  If the display hardware is
  bank-switched, then the application must not write more than
  pulRemlinesInBank lines of output before switching banks.  The data
  written to pDestinationAddress must be in the color-encoding scheme
  of the screen (also provided by DiveQueryCaps).  (Of course, DIVE
  can be used to convert to the correct screen color-encoding prior
  to writing to the frame buffer by doing a DiveBlitImage to a
  destination buffer with the same color-encoding.)  Additionally, if
  the screen supports only 256 colors, the data must match the
  current physical palette.
 
  All write access to the frame buffer must be bracketed by calls to
  DiveAcquireFrameBuffer and DiveDeacquireFrameBuffer.  Also, the
  application must not attempt to access the frame buffer between
  receipt of a WM_VRNDISABLED message and a WM_VRNENABLED message.
 
  This method works only on even bank breaks; indirect access through
  Dive BlitImage is recommended on displays with bank breaks that are
  not aligned on scan-line boundaries.
 
  In the next example, the application spins off a separate thread to
  perform blitting.  The procedure for this thread contains a nested
  loop that switches display banks for each image blitted as long as
  blitting is needed.  The flag fFBAccessOK is turned off when ever
  the application window received WM_VRNDISABLED and is turned on
  whenever WM_VRNENABLED is received.
 
  A typical application would do the following:
 
 
        BOOL  fKeepBlitting = TRUE;
        BOOL  fFBAccessOK;
        RECTL rectlOutput;           /* Image rectangle in desktop coors  */
        RECTL rectlDest;             /* Portion to blit in this bank      */
        ULONG ulMoreLines;           /* Lines in image left to blit       */
        LONG  lBlitTop;              /* Top of next blit                  */
        PVOID pDestinationAddress;   /* Frame buffer address - output     */
        ULONG ulBankNumber;          /* Display h/w bank number - output  */
        ULONG ulRemlinesInAperature; /* Lines left in bank - output       */
        BOOL  fAcquired = FALSE;     /* Acquired frame buffer yet         */
 
        while (fKeepBlitting)
          {
          /* ... Call DiveSetupBlitter as before ...    */
 
          /********************************************************/
          /* Calculate total number of lines to blit.  Then blit  */
          /* only those lines that will fit in the current bank.  */
          /* Switch to successive banks until the entire image is */
          /* blitted.                                             */
          /********************************************************/
          ulMoreLines = rectlDest.yTop - rectlDest.yBottom;
          memcpy( &rectlDest, &rectlOutput, sizeof(RECTL));
          while (ulMoreLines && fFBAccessOK)
            {
            ulErrorCode = DiveCalcFrameBufferAddress(
                hDive, rectlDest, &pDestinationAddress,
                &ulBankNumber, &ulRemlinesInAperture);
            if (!fAcquired)
              if (!DiveAcquireFrameBuffer( hDive, ulBankNumber))
                fAcquired = TRUE;
              else break;
            DiveSwitchBank( hDive, ulBankNumber);
              {
              /* ... write data for (ulRemlinesInAperture) top lines of */
              /* rectlDest to pDestinationAddress ...   */
              if (ulRemlinesInAperture < ulMoreLines)
                {               /* if need next bank    */
                rectlDest.yTop -= ulRemlinesInAperture;
                ulMoreLines -= ulRemlinesInAperture;
                }
              else ulMoreLines = 0;
              }
            if (fAcquired)
              DiveDeacquireFrameBuffer( hDive);
            }           /* end: while more lines to blit */
          }             /* end: blitter loop    */

