//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
 ////////////////////////////////////////////////////////////////////////////////
 // Blitbps2.cpp - does a blt and a scaled blt  on surfaces in system and video memory
 ////////////////////////////////////////////////////////////////////////////////
#include "main.h"
#include <DDrawUty.h>
#include <QATestUty/WinApp.h>
#include "perfCases.h"
#include <ddraw.h>
#include "perfloggerapi.h"

#define SampleSize 100



using namespace DDrawUty;
using namespace DebugStreamUty;
using namespace com_utilities;

namespace
{
    ////////////////////////////////////////////////////////////////////////////////
    // BasicBlitTest - Runs 10*SampleSize blts, timing each group of 10 and reporting the results
    eTestResult BasicBlitTest(CComPointer<IDirectDrawSurface> *piDDSSource, 
                                                CComPointer<IDirectDrawSurface> *piDDSDest, 
                                                RECT rcSrcRect, 
                                                RECT rcDstRect,
                                                DWORD dwMarker)
    {
        int i;
        eTestResult tr=trPass;
        HRESULT hr=DD_OK;
        
        for(i=0;i<SampleSize; i++)
        {  
            g_pLog->PerfBegin(dwMarker);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);
            hr|=(*piDDSDest)->Blt(&rcDstRect, 
                                                (*piDDSSource).AsInParam(), 
                                                &rcSrcRect, 
                                                DDBLT_WAITNOTBUSY, 
                                                NULL);    
            // endmarker imarker
            g_pLog->PerfEnd(dwMarker);
        }
        
        if(hr!=DD_OK)
            tr=trFail;
        return tr;
    }
    
}

////////////////////////////////////////////////////////////////////////////////
// CDDPerfBps2::Test - does assorted timed blit tests
eTestResult CDDPerfBps2VidVid::Test()
{
    CComPointer<IDirectDrawSurface> piDDSSrc,
                                                         piDDSDst;
    CComPointer<IDirectDraw> piDD;
    eTestResult tr = trPass;
    DDCAPS ddCaps;
    
    RECT  rcScaledSrcRect,
                rcScaledDstRect,
                rcSrcRect,
                rcDstRect;
    int iSourceSizeScaled = 10;
    int iSourceSizeNotScaled = 100;
    int iMinDimension;

    // get the direct draw pointer
    piDD = g_DirectDraw.GetObject();

    memset(&ddCaps, 0x00, sizeof(ddCaps));
    ddCaps.dwSize = sizeof(ddCaps);
    piDD->GetCaps(&ddCaps, NULL);

    if (!(ddCaps.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
    {
        dbgout << "Driver does not support video memory. Skipping." << endl;
        tr = trSkip;
        goto Cleanup;
    }

    // when doing a scaled blt, scale it from 10x10
    // to 100x100, making sure they don't overlap

    iMinDimension = g_BlitPerf.m_dwSurfaceWidth;
    if (iMinDimension > g_BlitPerf.m_dwSurfaceHeight)
    {
        iMinDimension = g_BlitPerf.m_dwSurfaceHeight;
    }

    if (iSourceSizeScaled + iSourceSizeScaled * 10 > iMinDimension)
    {
        dbgout 
            << "Using nonstandard size in scaling perf test: " 
            << iSourceSizeScaled 
            << " scaled to " 
            << 10*iSourceSizeScaled 
            << endl;
        iSourceSizeScaled = iMinDimension / 11;
    }

    if (iSourceSizeNotScaled * 2 > iMinDimension)
    {
        iSourceSizeNotScaled = iMinDimension / 2;
    }
    
    rcScaledSrcRect.left=0;
    rcScaledSrcRect.right=iSourceSizeScaled;
    rcScaledSrcRect.top=0;
    rcScaledSrcRect.bottom=iSourceSizeScaled;

    rcScaledDstRect.left=iSourceSizeScaled;
    rcScaledDstRect.right=iSourceSizeScaled + iSourceSizeScaled * 10;
    rcScaledDstRect.top=iSourceSizeScaled;
    rcScaledDstRect.bottom=iSourceSizeScaled + iSourceSizeScaled * 10;

    // standard blit from 100x100 to 100x100
    // non overlapping
    rcSrcRect.left=0;
    rcSrcRect.right=iSourceSizeNotScaled;
    rcSrcRect.top=0;
    rcSrcRect.bottom=iSourceSizeNotScaled;
    
    rcDstRect.left=iSourceSizeNotScaled;
    rcDstRect.right=iSourceSizeNotScaled * 2;
    rcDstRect.top=iSourceSizeNotScaled;
    rcDstRect.bottom=iSourceSizeNotScaled * 2;
    
    // register markers
    if(!g_pLog->PerfRegister(MARK_BLIT_VIDVID_1SURF, TEXT("BLT Vid-Vid 1 surface")) ||
        !g_pLog->PerfRegister(MARK_SBLIT_VIDVID_1SURF, TEXT("BLT Vid-Vid 1 surface scaled")) ||
        !g_pLog->PerfRegister(MARK_BLIT_VIDVID_2SURF, TEXT("BLT Vid-Vid 2 surfaces")) ||
        !g_pLog->PerfRegister(MARK_SBLIT_VIDVID_2SURF, TEXT("BLT Vid-Vid 2 surfaces scaled")))
    {
        tr=trAbort;
        dbgout << "register mark failed. Aborting." << endl;
        goto Cleanup;
    }

    // run the test on two surfaces in video memory
    tr = InitSurface(
        &piDD, 
        &piDDSSrc, 
        DDSCAPS_VIDEOMEMORY,
        g_BlitPerf.m_dwSurfaceWidth,
        g_BlitPerf.m_dwSurfaceHeight);
    if (trPass != tr)
    {
        dbgout << "InitSurface Source for Video did not succeed. Non-recoverable." << endl;
        goto Cleanup;
    }
    tr = InitSurface(
        &piDD, 
        &piDDSDst, 
        DDSCAPS_VIDEOMEMORY,
        g_BlitPerf.m_dwSurfaceWidth,
        g_BlitPerf.m_dwSurfaceHeight);
    if (trPass != tr)
    {
        dbgout << "InitSurface Destination for Video did not succeed. Non-recoverable." << endl;
        goto Cleanup;        
    }
        
    // Video to video blit with 1 surface 
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSSrc, 
                                rcSrcRect, 
                                rcDstRect, 
                                MARK_BLIT_VIDVID_1SURF);

    // Video to video blit with 1 surface
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSSrc, 
                                rcScaledSrcRect, 
                                rcScaledDstRect, 
                                MARK_SBLIT_VIDVID_1SURF);
   
    // Video to video blit with 2 surfaces
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSDst, 
                                rcSrcRect, 
                                rcDstRect, 
                                MARK_BLIT_VIDVID_2SURF);

    // Video to video blit with 2 surfaces
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSDst, 
                                rcScaledSrcRect, 
                                rcScaledDstRect, 
                                MARK_SBLIT_VIDVID_2SURF);

Cleanup:
    // release the surfaces
    piDDSSrc.ReleaseInterface();
    piDDSDst.ReleaseInterface();
    // release the DD object
    piDD.ReleaseInterface();
    // Destroy global objects
    g_DirectDraw.ReleaseObject();

    return tr;
}

////////////////////////////////////////////////////////////////////////////////
// CDDPerfBps2::Test - does assorted timed blit tests
eTestResult CDDPerfBps2SysVid::Test()
{
    CComPointer<IDirectDrawSurface> piDDSSrc,
                                                         piDDSDst;
    CComPointer<IDirectDraw> piDD;
    eTestResult tr = trPass;
    DDCAPS ddCaps;
    
    RECT  rcScaledSrcRect,
                rcScaledDstRect,
                rcSrcRect,
                rcDstRect;
    int iSourceSizeScaled = 10;
    int iSourceSizeNotScaled = 100;
    int iMinDimension;

    // get the direct draw pointer
    piDD = g_DirectDraw.GetObject();

    memset(&ddCaps, 0x00, sizeof(ddCaps));
    ddCaps.dwSize = sizeof(ddCaps);
    piDD->GetCaps(&ddCaps, NULL);

    if (!(ddCaps.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
    {
        dbgout << "Driver does not support video memory. Skipping." << endl;
        tr = trSkip;
        goto Cleanup;
    }

    // when doing a scaled blt, scale it from 10x10
    // to 100x100, making sure they don't overlap
    iMinDimension = g_BlitPerf.m_dwSurfaceWidth;
    if (iMinDimension > g_BlitPerf.m_dwSurfaceHeight)
    {
        iMinDimension = g_BlitPerf.m_dwSurfaceHeight;
    }

    if (iSourceSizeScaled + iSourceSizeScaled * 10 > iMinDimension)
    {
        dbgout 
            << "Using nonstandard size in scaling perf test: " 
            << iSourceSizeScaled 
            << " scaled to " 
            << 10*iSourceSizeScaled 
            << endl;
        iSourceSizeScaled = iMinDimension / 11;
    }

    if (iSourceSizeNotScaled * 2 > iMinDimension)
    {
        iSourceSizeNotScaled = iMinDimension / 2;
    }
    
    rcScaledSrcRect.left=0;
    rcScaledSrcRect.right=iSourceSizeScaled;
    rcScaledSrcRect.top=0;
    rcScaledSrcRect.bottom=iSourceSizeScaled;

    rcScaledDstRect.left=iSourceSizeScaled;
    rcScaledDstRect.right=iSourceSizeScaled + iSourceSizeScaled * 10;
    rcScaledDstRect.top=iSourceSizeScaled;
    rcScaledDstRect.bottom=iSourceSizeScaled + iSourceSizeScaled * 10;

    // standard blit from 100x100 to 100x100
    // non overlapping
    rcSrcRect.left=0;
    rcSrcRect.right=iSourceSizeNotScaled;
    rcSrcRect.top=0;
    rcSrcRect.bottom=iSourceSizeNotScaled;
    
    rcDstRect.left=iSourceSizeNotScaled;
    rcDstRect.right=iSourceSizeNotScaled * 2;
    rcDstRect.top=iSourceSizeNotScaled;
    rcDstRect.bottom=iSourceSizeNotScaled * 2;
    
    // register markers
    if(!g_pLog->PerfRegister(MARK_BLIT_SYSVID_2SURF, TEXT("BLT Sys-Vid 2 surfaces")) ||
        !g_pLog->PerfRegister(MARK_SBLIT_SYSVID_2SURF, TEXT("BLT Sys-Vid 2 surfaces scaled")))
    {
        tr=trAbort;
        dbgout << "register mark failed. Aborting." << endl;
        goto Cleanup;
    }

    // run the test on a surfaces in video and system memory
    tr = InitSurface(
        &piDD, 
        &piDDSSrc, 
        DDSCAPS_SYSTEMMEMORY,
        g_BlitPerf.m_dwSurfaceWidth,
        g_BlitPerf.m_dwSurfaceHeight);
    if (trPass != tr)
    {
        dbgout << "InitSurface Source for System did not succeed. Non-recoverable." << endl;
        goto Cleanup;
    }
    tr = InitSurface(
        &piDD, 
        &piDDSDst, 
        DDSCAPS_VIDEOMEMORY,
        g_BlitPerf.m_dwSurfaceWidth,
        g_BlitPerf.m_dwSurfaceHeight);
    if (trPass != tr)
    {
        dbgout << "InitSurface Destination for Video did not succeed. Non-recoverable." << endl;
        goto Cleanup;        
    }
    
    // System to video blit with 2 surfaces 
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSDst, 
                                rcSrcRect, 
                                rcDstRect, 
                                MARK_BLIT_SYSVID_2SURF);

    // System to video blit with 2 surfaces
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSDst, 
                                rcScaledSrcRect, 
                                rcScaledDstRect, 
                                MARK_SBLIT_SYSVID_2SURF);


Cleanup:
    // release the surfaces
    piDDSSrc.ReleaseInterface();
    piDDSDst.ReleaseInterface();
    // release the DD object
    piDD.ReleaseInterface();
    // Destroy global objects
    g_DirectDraw.ReleaseObject();

    return tr;
}


////////////////////////////////////////////////////////////////////////////////
// CDDPerfBps2::Test - does assorted timed blit tests
eTestResult CDDPerfBps2SysSys::Test()
{
    CComPointer<IDirectDrawSurface> piDDSSrc,
                                                         piDDSDst;
    CComPointer<IDirectDraw> piDD;
    eTestResult tr = trPass;
    
    RECT  rcScaledSrcRect,
                rcScaledDstRect,
                rcSrcRect,
                rcDstRect;
    int iSourceSizeScaled = 10;
    int iSourceSizeNotScaled = 100;
    int iMinDimension;

    // get the direct draw pointer
    piDD = g_DirectDraw.GetObject();

    // when doing a scaled blt, scale it from 10x10
    // to 100x100, making sure they don't overlap
    iMinDimension = g_BlitPerf.m_dwSurfaceWidth;
    if (iMinDimension > g_BlitPerf.m_dwSurfaceHeight)
    {
        iMinDimension = g_BlitPerf.m_dwSurfaceHeight;
    }

    if (iSourceSizeScaled + iSourceSizeScaled * 10 > iMinDimension)
    {
        dbgout 
            << "Using nonstandard size in scaling perf test: " 
            << iSourceSizeScaled 
            << " scaled to " 
            << 10*iSourceSizeScaled 
            << endl;
        iSourceSizeScaled = iMinDimension / 11;
    }

    if (iSourceSizeNotScaled * 2 > iMinDimension)
    {
        iSourceSizeNotScaled = iMinDimension / 2;
    }
    
    rcScaledSrcRect.left=0;
    rcScaledSrcRect.right=iSourceSizeScaled;
    rcScaledSrcRect.top=0;
    rcScaledSrcRect.bottom=iSourceSizeScaled;

    rcScaledDstRect.left=iSourceSizeScaled;
    rcScaledDstRect.right=iSourceSizeScaled + iSourceSizeScaled * 10;
    rcScaledDstRect.top=iSourceSizeScaled;
    rcScaledDstRect.bottom=iSourceSizeScaled + iSourceSizeScaled * 10;

    // standard blit from 100x100 to 100x100
    // non overlapping
    rcSrcRect.left=0;
    rcSrcRect.right=iSourceSizeNotScaled;
    rcSrcRect.top=0;
    rcSrcRect.bottom=iSourceSizeNotScaled;
    
    rcDstRect.left=iSourceSizeNotScaled;
    rcDstRect.right=iSourceSizeNotScaled * 2;
    rcDstRect.top=iSourceSizeNotScaled;
    rcDstRect.bottom=iSourceSizeNotScaled * 2;
    
    // register markers
    if(!g_pLog->PerfRegister(MARK_BLIT_SYSSYS_1SURF, TEXT("BLT Sys-sys 1 surface")) ||
        !g_pLog->PerfRegister(MARK_SBLIT_SYSSYS_1SURF, TEXT("BLT Sys-sys 1 surface scaled")) ||
        !g_pLog->PerfRegister(MARK_BLIT_SYSSYS_2SURF, TEXT("BLT Sys-sys 2 surfaces")) ||
        !g_pLog->PerfRegister(MARK_SBLIT_SYSSYS_2SURF, TEXT("BLT Sys-sys 2 surfaces scaled")))
    {
        tr=trAbort;
        dbgout << "register mark failed. Aborting" << endl;
        goto Cleanup;
    }

    // run the test on two surfaces in system memory
    tr = InitSurface(
        &piDD, 
        &piDDSSrc, 
        DDSCAPS_SYSTEMMEMORY,
        g_BlitPerf.m_dwSurfaceWidth,
        g_BlitPerf.m_dwSurfaceHeight);
    if (trPass != tr)
    {
        dbgout << "InitSurface Source for System did not succeed. Non-recoverable." << endl;
        goto Cleanup;
    }
    tr = InitSurface(
        &piDD, 
        &piDDSDst, 
        DDSCAPS_SYSTEMMEMORY,
        g_BlitPerf.m_dwSurfaceWidth,
        g_BlitPerf.m_dwSurfaceHeight);
    if (trPass != tr)
    {
        dbgout << "InitSurface Destination for Video did not succeed. Non-recoverable." << endl;
        goto Cleanup;        
    }
    
    // System to system blit with 1 surface
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSSrc, 
                                rcSrcRect, 
                                rcDstRect, 
                                MARK_BLIT_SYSSYS_1SURF);

    // System to system blit with 1 surface
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSSrc, 
                                rcScaledSrcRect, 
                                rcScaledDstRect, 
                                MARK_SBLIT_SYSSYS_1SURF);
    
    // System to system blit with 2 surfaces
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSDst, 
                                rcSrcRect, 
                                rcDstRect, 
                                MARK_BLIT_SYSSYS_2SURF);

    // System to system blit with 2 surfaces
    tr|=BasicBlitTest(&piDDSSrc, 
                                &piDDSDst, 
                                rcScaledSrcRect, 
                                rcScaledDstRect, 
                                MARK_SBLIT_SYSSYS_2SURF);

Cleanup:
    // release the surfaces
    piDDSSrc.ReleaseInterface();
    piDDSDst.ReleaseInterface();
    // release the DD object
    piDD.ReleaseInterface();
    // Destroy global objects
    g_DirectDraw.ReleaseObject();

    return tr;
}

