Extending the GRADD Architecture to Exploit Hardware Support for Video Acceleration

From EDM2
Jump to: navigation, search

by Joseph Celi

In Volume 7 of The Developer Connection News, I wrote about the new Graphics Adapter Device Driver (GRADD) architecture for OS/2 Warp Connect (PowerPC Edition). One of the most powerful aspects of the GRADD architecture is its inherent ability to be extended to take advantage of new graphics and video hardware. In this article, we'll explore how hardware video acceleration is exploited under the GRADD architecture using the GRADD extension mechanism.

Creating a Function Class for Video Acceleration

The first step in creating a GRADD extension is to come up with a function class name. The function class name is the link that allows a translation layer to communicate with an extension GRADD. The function class name is typically defined in a header file that is shared by the translation layer and the extension GRADD. The function class name for video acceleration is defined in ENDIVE.H as follows:

#define VA1_FUNCTION_CLASS    "Video Acceleration 1"

Note: ENDIVE stands for enhanced direct interface video extension.

A GRADD can support one or more function classes. The GRADD returns the number of function classes it supports by updating the cFunctionClasses field of the GDDINITOUT output data packet on the GHI_CMD_INIT command:

typedef struct _GDDINITOUT {        /* gddinitout */
   ULONG        ulLength;
   ULONG        cFunctionClasses;
} GDDINITOUT;
typedef GDDINITOUT  *PGDDINITOUT;

Figure 1. The GDDINITOUT data structure

The GRADD receives one GHI_CMD_QUERYCAPS command for every function class it supports. The function class name is returned by the GRADD in the pszFunctionClassID field of the CAPSINFO data structure:

typedef struct _CAPSINFO {          /* capsinfo                     */
   ULONG        ulLength;           /* sizeof CAPSINFO structure    */
   PSZ          pszFunctionClassID; /* Function set name            */
   ULONG        ulFCFlags;          /* Function class specific flags*/
} CAPSINFO;
typedef CAPSINFO  *PCAPSINFO;

Figure 2. The CAPSINFO data structure

A translation layer calls the video manager with a VMI_CMD_QUERYCHAININFO command to find out information about all GRADDs currently installed in the system. The video manager returns a pointer to a CHAININFO data structure:

typedef struct _CHAININFO {       /* chaininfo */
        CID                   cid;
        PSZ                   pszChainName;
        PFNHWENTRY            pChainHWEntry;
        PGRADDINFO            pGraddList;
        struct _CHAININFO *   pNextChainInfo;
} CHAININFO ;
typedef CHAININFO *PCHAININFO;

Figure 3. The CHAININFO data structure

There is one CHAININFO data structure for every GRADD chain installed on the system. The pNextChainInfo field contains a pointer to the next CHAININFO data structure, if one exists. The pGraddList field of the CHAININFO data structure contains a pointer to a linked list of GRADDINFO data structures. Once again, there is one GRADDINFO data structure for every GRADD installed in the system:

to the next typedef struct _GRADDINFO {       /* graddinfo */
       GID                   gid;
       PSZ                   pszGraddName;
       PFNHWENTRY            pGraddEntry;
       PFNHWENTRY            pChainEntry;
       ULONG                 cModes;
       struct _GDDMODEINFO * pModeInfo;
       struct _CAPSINFO *    pCapsInfo;
       struct _GRADDINFO *   pNextGraddInfo;
} GRADDINFO ;
typedef GRADDINFO *PGRADDINFO;

Figure 4. The GRADDINFO data structure

The GRE2VMAN translation layer searches all GRADDINFO data structures looking for a GRADD that supports the VA1_FUNCTION_CLASS when support for video acceleration is requested. Sample Code 1 shows the routine in GRE2VMAN that performs this search:

/****************************************************************
*
*  FUNCTION NAME:    FindMMExtension()
*
*  FUNCTION:
*    This routine will check all CHAININFO data structures
*    looking for a GRADD that supports the VA1_FUNCTION_CLASS.
*    If found it will update gidAccel and init the driver.
*
*  RETURN CODE
*                  TRUE - An extension GRADD has been found that
*                         supports the VA1_FUNCTION_CLASS
*
*                  FALSE - No accelerator GRADDs found
*
*****************************************************************/
BOOL FindMMExtension(VOID)
{
  PCHAININFO  pci;
  PGRADDINFO  pgi;
  ULONG       rc;
  VMIQCI      vmiQCI;
  /*
  ** If we already found the video accelerator extension
  ** GRADD, simply return.
  */
  if(gidAccel ]= GID_DONTCARE)
     return(TRUE);

  rc = VMIEntry(GID_DONTCARE, VMI_CMD_QUERYCHAININFO, NULL, &vmiQCI);
  if(rc != RC_SUCCESS)
  {
     return(FALSE);
  }

  pci = vmiQCI.pciHead;

  do
  {
     pgi = pci->pGraddList;
     do
     {
        if(]strcmp(pgi->pCapsInfo->pszFunctionClassID,
                   VA1_FUNCTION_CLASS))
        {
           gidAccel = pgi->gid;
           return(TRUE);
        }
     } while(pgi = pgi->pNextGraddInfo);

  } while(pci = pci->pNextChainInfo);
  return(FALSE);
}
/* end of FindMMExtension */

Sample Code 1.

Calling an Extension GRADD

When a translation layer calls an extension GRADD with one of the extension defined commands, it uses the VMI_CMD_EXTENSION video manager command. As is the case for all VMI commands, the translation layer calls VMIEntry using the following function prototype:

ULONG EXPENTRY VMIEntry(GID gid, 
                        ULONG ulFun,
                        PVOID pInput,
                        PVOID pOutput)

The gid field contains the GRADD ID of the extension GRADD. The ulFun field always contains VMI_CMD_EXTENSION. The pInput field contains a pointer to a HWEXTENSION data structure. The pOutput field contains a pointer to an output packet that is extension command specific:

typedef struct _HWEXTENSION {          /* hwextension */
   ULONG  ulLength;
   ULONG  ulXSubFunction;
   ULONG  cScrChangeRects;
   PRECTL arectlScreen;
   ULONG  ulXFlags;
   PVOID  pXP1;
} HWEXTENSION;
typedef HWEXTENSION *PHWEXTENSION;

Figure 5. The HWEXTENSION data structure

In Figure 5, the ulXSubFunction field contains the extension commands. The extension commands vary from extension to extension. We never have to worry about command clashes among different extensions because the GRADD is assigned a unique ID for every function class that it supports.

The cScrChangeRects field of the HWEXTENSION data structure is the count of screen change rectangles. The arectlScreen is the array of screen change rectangles. The video manager needs this information so it can exclude the pointer if a software pointer is in use. The screen change rectangles are also important to filter GRADDs, which need to be aware of all changing areas on the screen.

The ulXFlags field of the HWEXTENSION data structure is a flags field. Currently there is only one possible flag (as shown below). If this flag is set, the video manager knows that it must serialize this command with other drawing VMI commands.

/*
**  Defines for the ulXFlags field of the HWEXTENSION structure.
*/
#define X_REQUESTHW  1

The pXP1 field of the HWEXTENSION data structure is a pointer to an input data structure unique to each extension command.

VA1_FUNCTION_CLASS Commands

The VA1_FUNCTION_CLASS defines a set of commands that allow multimedia software to take advantage of underlying video acceleration hardware. Figure 6 lists the extension commands for the VA1_FUNCTION_CLASS (defined in ENDIVE.H).

/*
** Subfunctions for the VA1_FUNCTION_CLASS.
*/
#define VA1_INIT      1   /* Initialize accelerator      */
#define VA1_TERM      2   /* Terminate accelerator       */
#define VA1_QUERY     3   /* Query the accelerators caps */
#define VA1_PUT       4   /* Put a frame to the screen   */
#define VA1_GET       5   /* Get a frame from the screen */

Figure 6. VA1_FUNCTION_CLASS commands

The GRADD receives the above commands in the same manner it receives any of the commands defined by the BASE_FUNCTION_CLASS. The GHI command will always be GHI_CMD_EXTENSION. Sample Code 2 shows a sample HWEntry routine of a GRADD that supports the VA1_FUNCTION_CLASS:

/*****************************************************************
*  FUNCTION NAME:    HWEntry()
*
*  FUNCTION:
*    This routine is the main GRADD entry point.  VMAN calls
*    this routine directly.  Since we are an extension GRADD
*    we must call the next GRADD in the chain if the command
*    was not directed to our GRADD ID.
*
*  RETURN CODE
*              RC_SUCCESS     - Operation completed successfully
*              RC_UNSUPPORTED - Command is not supported
*              RC_ERROR       - Error encountered
*
*****************************************************************/
ULONG EXPENTRY HWEntry(GID gid, ULONG ulFun, PVOID pIn, PVOID pOut)
{
  ULONG    rc;
  P91PARMS P91Parms;

  if(ulFun == GHI_CMD_INIT)
  {
     gidVP = gid;
     pfnNextGRADD = ((PGDDINITIN)pIn)->pfnChainedHWEntry;
     if(((PGDDINITOUT)pOut)->ulLength >= sizeof(GDDINITOUT))
     {
        ((PGDDINITOUT)pOut)->cFunctionClasses = 1;
     }
     return(RC_SUCCESS);
  }

  if(gid == gidVP)
  {
     switch(ulFun)
     {
        case GHI_CMD_QUERYCAPS:
           return(BaseQCaps((PCAPSINFO)pOut));

        case GHI_CMD_QUERYMODES:
           return(BaseQModes((PULONG)pIn, (PULONG)pOut));

        case GHI_CMD_EVENT:
           return(BaseEvent((PHWEVENTIN)pIn));

        case GHI_CMD_EXTENSION:
           switch(((PHWEXTENSION)pIn)->ulXSubFunction)
           {
              case VA1_INIT:
                rc = VPInit((PFBINFO)((PHWEXTENSION)pIn)->pXP1);
                 if(rc == RC_SUCCESS)
                     f9130Ready = TRUE;
                 return(rc);

              case VA1_TERM:
                 f9130Ready = FALSE;
                 return(VPTerm());

              case VA1_QUERY:
                 return(VPQCaps((PIMAGECAPS)pOut));

              case VA1_PUT:
                 return(PutImage(((PHWEXTENSION)pIn)->pXP1));

              case VA1_GET:
                 return(RC_UNSUPPORTED);

              default:
                 return(RC_ERROR);
           }

         default:
           return(RC_ERROR);
     }
  }
  else if(gid == gidParent)
  {
     switch(ulFun)
     {
        case GHI_CMD_INITPROC:
          /*
          ** If the INITPROCESS is going to the P91GRADD, we will
          ** call it so we can get a copy of the virtual vram ptr.
          */
           rc = pfnNextGRADD(gid, ulFun, pIn, pOut);
           if(P91QueryParms(&P91Parms) ]= RC_SUCCESS)
              return(RC_ERROR);

           pulMMVirt = (PULONG)P91Parms.pbMM;
           pbScrVirt = P91Parms.pbScr;
           pulID = (PULONG)((PBYTE)pulMMVirt + VP1_ID);
           pulQAR = (PULONG)((PBYTE)pulMMVirt + VP1_QUEUE_ADDRESS);
           pulQPtr = (PULONG)((PBYTE)pulMMVirt + VP1_QUEUE_POINTER);
           return(rc);

        case GHI_CMD_REQUESTHW:
           /*
           ** The application level software will wrap a request
           ** and release HW around all PutImage's.  If it is a release
           ** we must make sure the 9130 has finished all operations.
           */
           WaitFor9130();
           ResetQueue();
     }
  }
  return(pfnNextGRADD(gid, ulFun, pIn, pOut));
} /* end of HWEntry */

Sample Code 2.

Compatibility with OS/2 Warp

When we designed video acceleration support for OS/2 Warp (sometimes referred to as ENDIVE support), we were already working on the GRADD architecture for OS/2 Warp Connect (PowerPC Edition). The ENDIVE video driver for OS/2 Warp was designed as an extension GRADD. The commands that make up the VA1_FUNCTION_CLASS are similar to the commands handled by an ENDIVE video driver. In fact, if you have written an OS/2 Warp ENDIVE video driver, it will be easy for you to convert your video driver into a video acceleration extension GRADD for OS/2 Warp Connect (PowerPC Edition).

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation