/******************************Module*Header**********************************\
*
*                           *******************
*                           * GDI SAMPLE CODE *
*                           *******************
*
* Module Name: sync.c
*
* Surface synchronization support.
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation.  All rights reserved.
\*****************************************************************************/
#include "precomp.h"
#include "gdi.h"

//-----------------------------Public*Routine----------------------------------
//
// VOID DrvSynchronizeSurface(pso, prcl, fl)
//
// DrvSynchronizeSurface allows drawing operations performed on the specified
// surface by a device's coprocessor to be coordinated with GDI.
//
// Parameters
//  pso---------Points to a SURFOBJ that identifies the surface on which the
//              drawing synchronization is to occur. 
//  prcl--------Specifies a rectangle on the surface that GDI will draw into, or
//              NULL. If this does not collide with the drawing operation in
//              progress, the driver can elect to let GDI draw without waiting
//              for the coprocessor to complete. 
//  fl----------Flag 
//
// Comments
//  DrvSynchronize can be optionally implemented in graphics drivers. It is
//  intended to support devices that use a coprocessor for drawing. Such a
//  device can start a long drawing operation and return to GDI while the
//  operation continues. If the device driver does not perform all drawing
//  operations to the surface, it is possible that a subsequent drawing
//  operation will be handled by GDI. In this case, it is necessary for GDI
//  to wait for the coprocessor to complete its work before drawing on the
//  surface. DrvSynchronize is not an output function.
//
//  This function is only called if it is hooked by EngAssociateSurface.
//  GDI will call DrvSynchronizeSurface()
//   1. before rendering to any device managed surface
//   2. when at timer event occurs and GCAPS2_SYNCTIMER was specified passing
//      the desktop surface and specifying DSS_TIMER_EVENT
//   3. when a flush evern occurs and GCAPS2_SYNCFLUSH was specified passing
//      the desktip surface and specifying DSS_FLUSH_EVENT
//
//  The function should return when it is safe for GDI to draw on the surface.
//
//  Per surface synchronization enables hardware which uses a graphics
//  acceleration queue model to flush the acceleration queue only to the extent
//  that is neccessary.  That is, it only has to flush up to the last
//  queue entry that references the given surface.
//
//  GDI will call DrvSynchronizeSurface instead of DrvSynchronize in drivers
//  that implement both of these functions. DrvSynchronize is called (and
//  shouuld be provided) only if DrvSyncrhoizeSurface is not provided.
//
//-----------------------------------------------------------------------------
VOID
DrvSynchronizeSurface(SURFOBJ*  pso,
                      RECTL*    prcl,
                      FLONG     fl)
{
    Surf  *psurf;
    PDev   *ppdev = (PDev *) pso->dhpdev;
    
    ASSERTDD(pso->dhsurf != NULL,
                "DrvSynchronizeSurface: called with GDI managed surface");

    
    psurf = (Surf *) pso->dhsurf;

    if ( fl & (DSS_FLUSH_EVENT | DSS_TIMER_EVENT) )
    {
        if(ppdev->bGdiContext && ppdev->bNeedSync)
        {
            if(ppdev->bForceSwap)
            {
                ppdev->bForceSwap = FALSE;
                InputBufferSwap(ppdev);
            }
            else
                InputBufferFlush(ppdev);
        }
        goto done;
    }
    else if ( psurf->flags & SF_VM )
    {
        // If we only had a hardware acceleration queue with per surface
        // reference counting perhaps we could sync to this passed in surface

        // for now just fall through to below
    }

    // we don't have per surface synchronization ... always sync the entire
    // dma buffer

    if(ppdev->bGdiContext)
    {
        InputBufferSync(ppdev);
    }
    else
    {
        vSyncWithPermedia(ppdev->pP2dma);
    }

done:


    return;
}



