////----------------------------------------------------------------------------------
// File:        VSRDemoNGX.cpp
// SDK Version: 1.0.2
//
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: LicenseRef-NvidiaProprietary
//
// NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
// property and proprietary rights in and to this material, related
// documentation and any modifications thereto. Any use, reproduction,
// disclosure or distribution of this material and related documentation
// without an express license agreement from NVIDIA CORPORATION or
// its affiliates is strictly prohibited.
//
//----------------------------------------------------------------------------------

///////////////////////////////////////////
// VSRDemoNGX.cpp
//
// This is a desktop app the creates windows and calls the VSRDemo classes
// to provide a sample of how to an app can use the NGX wrapper classes.
//

#include "framework.h"
#include <shellapi.h>
#include "VSRDemoNGX.h"
#include "CDX11VSRDemo.h"
#include "CDX12VSRDemo.h"

#include <string>
using namespace std;
#pragma comment( lib, "winmm.lib" )

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
WCHAR szWindowClassAlt[MAX_LOADSTRING] = L"alt";

HWND                    g_hWndDisplay = nullptr;
HWND                    g_hWndDisplayAlt = nullptr;
HWND                    g_hWndControlBar = nullptr;
bool                    g_bDx11 = true;
int                     g_iQuality = 1;
CDX11VSRDemo*           g_pCDX11VSRDemo = nullptr;
CDX12VSRDemo*           g_pCDX12VSRDemo = nullptr;

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, UINT, bool*);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
void                SizeAndShowWindow(UINT, UINT, int);

#define NEXT_ARG if (iarg < iArgC - 1) { iarg++; pCmd = pArgV[iarg]; } else { fwprintf(stdout, UsageTxt); return 0; }

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    WCHAR UsageTxt[] = L"\n\
    -i <file>           // required: use <input file> name: 4cc_width_height_pitch_frames_xxxx.xxx\n\
    -dx12               // use dx12 (default dx11)\n\
    -size w h           // display at this size\n\
    -nativeSize         // display at source size\n\
    -fps n              // frames per second (1-60)\n\
    -head n             // head on display adapter (default 0)\n\
    -?                  // usage\n";

    // This will open stdout to a console if running from a command line.
    FILE* consoleOut;
    if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()) {
        freopen_s(&consoleOut, "CONOUT$", "w", stdout);
    }
    //ShowWindow(GetConsoleWindow(), SW_HIDE);

    Configuration_s Configuration = {};
    Configuration.DisplayWidth = 1280;
    Configuration.DisplayHeight = 720;
    UINT uFPS = 30;
    UINT uHead = 0;

    char szInput[MAX_PATH] = "NV12_1280_720_1280_120_star_sky.yuv";
    Configuration.pSzInputFile = szInput;
    bool bInputSet = false;

    int iArgC = 0;
    LPWSTR* pArgV = CommandLineToArgvW(lpCmdLine, &iArgC);

    for (int iarg = 0; iarg < iArgC; iarg++)
    {
        WCHAR* pCmd = pArgV[iarg];
        if (!wcscmp(pCmd, L"-?"))
        {
            fwprintf(stdout, UsageTxt);
            return 0;
        }
        else if (!wcscmp(pCmd, L"-dx12"))
        {
            g_bDx11 = false;
        }
        else if (!wcscmp(pCmd, L"-nativeSize"))
        {
            Configuration.bUseNativeSize = true;
        }
        else if (!wcscmp(pCmd, L"-i"))
        {
            NEXT_ARG;
            size_t origsize = wcslen(pCmd) + 1;
            size_t convertedChars = 0;
            wcstombs_s(&convertedChars, szInput, origsize, pCmd, _TRUNCATE);
            bInputSet = true;
        }
        else if (!wcscmp(pCmd, L"-size"))
        {
            NEXT_ARG;
            Configuration.DisplayWidth = _wtoi(pCmd);
            NEXT_ARG;
            Configuration.DisplayHeight = _wtoi(pCmd);
        }
        else if (!wcscmp(pCmd, L"-fps"))
        {
            NEXT_ARG;
            int iFPS = _wtoi(pCmd);
            if (iFPS >= 1 && iFPS <= 60)
                uFPS = iFPS;
        }
        else if (!wcscmp(pCmd, L"-head"))
        {
            NEXT_ARG;
            uHead = _wtoi(pCmd);
        }
        else
        {
            fwprintf(stdout, L"\n\n    Error: unsupported parameter: %s\n", pCmd);
            fwprintf(stdout, UsageTxt);
            return 0;
        }
    }
    if (!bInputSet)
    {
        fwprintf(stdout, UsageTxt);
        return 0;
    }

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    wsprintf(szTitle, L"%s DX1%s", szTitle, g_bDx11 ? L"1" : L"2");
    LoadStringW(hInstance, IDC_VSRDEMONGX, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance(hInstance, uHead, &Configuration.bMonitorIsNotNV))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_VSRDEMONGX));

    // initialize the dx device
    HRESULT hr = S_OK;
    if (g_bDx11)
    {
        g_pCDX11VSRDemo = new CDX11VSRDemo;
        hr = g_pCDX11VSRDemo->Init(g_hWndDisplay, g_hWndDisplayAlt, &Configuration);
        if (FAILED(hr)) g_pCDX11VSRDemo->Shutdown();
    }
    else
    {
        g_pCDX12VSRDemo = new CDX12VSRDemo;
        hr = g_pCDX12VSRDemo->Init(g_hWndDisplay, g_hWndDisplayAlt, &Configuration);
        if (FAILED(hr)) g_pCDX12VSRDemo->Shutdown();
    }

    if (FAILED(hr)) 
    {
        fprintf(stdout, "\nDemo Init Failed with Result:%x\n", hr);
        switch (hr)
        {
        case E_INVALIDARG:
            fprintf(stdout, "\nVerify input file exists and file name is valid (see readme for file name requirements).\n");
            break;
        case E_OUTOFMEMORY:
            fprintf(stdout, "\nSystem has run out of memory.\n");
        case E_FAIL:
            fprintf(stdout, "\nGeneric error. Make sure NV device is working, drivers are up to date, and the feature DLL is in the current working directory.\n");
            break;
        }
        return -1;
    }
    SizeAndShowWindow(Configuration.WidthInUse, Configuration.HeightInUse, nCmdShow);

    // set timer for how often to refresh - remove lean_and_mean to get timeBeginPeriod, link winmm.lib
    timeBeginPeriod(1);
    UINT uMS = 1000 / uFPS;
    SetTimer(g_hWndDisplay, 1, uMS, (TIMERPROC)NULL);            // this ms between frames

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    timeEndPeriod(1);
    if (g_bDx11 && g_pCDX11VSRDemo)
    {
        g_pCDX11VSRDemo->Shutdown();
        delete g_pCDX11VSRDemo;
    }
    else if (g_pCDX12VSRDemo)
    {
        g_pCDX12VSRDemo->Shutdown();
        delete g_pCDX12VSRDemo;
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    {
        WNDCLASSEXW wcexAlt = {};
        wcexAlt.cbSize = sizeof(WNDCLASSEX);
        wcexAlt.style = CS_HREDRAW | CS_VREDRAW;
        wcexAlt.lpfnWndProc = WndProc;
        wcexAlt.cbClsExtra = 0;
        wcexAlt.cbWndExtra = 0;
        wcexAlt.hInstance = hInstance;
        wcexAlt.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wcexAlt.lpszClassName = szWindowClassAlt;
        RegisterClassExW(&wcexAlt);
    }
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_VSRDEMONGX));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_VSRDEMONGX);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, UINT uHead, bool* pbMonitorIsNotNV)
{
   hInst = hInstance; // Store instance handle in our global variable

   LONG iLeft = CW_USEDEFAULT;
   LONG iTop = CW_USEDEFAULT;

   RECT rcMonitor = {};
   CDx1xCommon cCDx1xCommon = {};

   if (cCDx1xCommon.FindMonitorRect(uHead, &rcMonitor))
   {
       iLeft = rcMonitor.left + 60;
       iTop = rcMonitor.top + 60;
   }
   else
   {
       fwprintf(stdout, L"Did not find specified monitor (%s adapter, head %d).\nUsing default adapter for display.\n", L"Nvidia", uHead);
       *pbMonitorIsNotNV = true;
   }

   g_hWndDisplay = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
       iLeft, iTop, 0, 0, nullptr, nullptr, hInstance, nullptr);

   if (!g_hWndDisplay)
   {
       return FALSE;
   }
   g_hWndDisplayAlt = CreateWindowW(szWindowClassAlt, L"Compare", WS_POPUP,
           iLeft, iTop + 60, 0, 0, nullptr, nullptr, hInstance, nullptr);
   g_hWndControlBar = CreateWindowW(szWindowClassAlt, L"Control", WS_POPUP,
           iLeft, iTop + 60, 0, 0, nullptr, nullptr, hInstance, nullptr);

   return TRUE;
}

UINT g_uCompareLeftOffset = 0;
UINT g_uCompareFrameWidth = 0;
UINT g_uCompareFrameHeight = 0;
UINT g_uControlBarHeight = 40;
UINT g_uControlBarWidth = 550;
#define ID_PLAY 1
#define ID_STEP_FWD 2
#define ID_STEP_BK 3
#define ID_QUALITY_0 4
#define ID_QUALITY_1 5
#define ID_QUALITY_2 6
#define ID_QUALITY_3 7
#define ID_QUALITY_4 8
bool g_bPaused = false;
HWND g_hwndButtonPlay = nullptr;
HWND g_hwndButtonStepFwd = nullptr;
HWND g_hwndButtonStepBk = nullptr;
HWND g_hwndButton0 = nullptr;
HWND g_hwndButton1 = nullptr;
HWND g_hwndButton2 = nullptr;
HWND g_hwndButton3 = nullptr;
HWND g_hwndButton4 = nullptr;
#include "windowsx.h"

void SetUpControlBar()
{
    RECT rcClient;
    GetClientRect(g_hWndControlBar, &rcClient);
    g_hwndButtonPlay = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed 
        L"Playing",      // Button text 
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
        00,         // x position 
        00,         // y position 
        100,        // Button width
        g_uControlBarHeight - 00,        // Button height
        g_hWndControlBar,     // Parent window
        (HMENU)ID_PLAY,
        NULL,
        NULL);      // Pointer not needed.
    g_hwndButtonStepBk = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed 
        L"Step Back",      // Button text 
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
        100,         // x position 
        00,         // y position 
        100,        // Button width
        g_uControlBarHeight - 00,        // Button height
        g_hWndControlBar,     // Parent window
        (HMENU)ID_STEP_BK,
        NULL,
        NULL);      // Pointer not needed.
    g_hwndButtonStepFwd = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed 
        L"Step Fwd",      // Button text 
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
        200,         // x position 
        00,         // y position 
        100,        // Button width
        g_uControlBarHeight - 00,        // Button height
        g_hWndControlBar,     // Parent window
        (HMENU)ID_STEP_FWD,
        NULL,
        NULL);      // Pointer not needed.
    Button_Enable(g_hwndButtonStepBk, false);
    Button_Enable(g_hwndButtonStepFwd, false);
    g_hwndButton0 = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed 
        L"0",      // Button text 
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
        300,         // x position 
        00,         // y position 
        50,        // Button width
        g_uControlBarHeight - 00,        // Button height
        g_hWndControlBar,     // Parent window
        (HMENU)ID_QUALITY_0,
        NULL,
        NULL);      // Pointer not needed.
    g_hwndButton1 = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed 
        L"1",      // Button text 
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
        350,         // x position 
        00,         // y position 
        50,        // Button width
        g_uControlBarHeight - 00,        // Button height
        g_hWndControlBar,     // Parent window
        (HMENU)ID_QUALITY_1,
        NULL,
        NULL);      // Pointer not needed.
    g_hwndButton2 = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed 
        L"2",      // Button text 
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
        400,         // x position 
        00,         // y position 
        50,        // Button width
        g_uControlBarHeight - 00,        // Button height
        g_hWndControlBar,     // Parent window
        (HMENU)ID_QUALITY_2,
        NULL,
        NULL);      // Pointer not needed.
    g_hwndButton3 = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed 
        L"3",      // Button text 
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
        450,         // x position 
        00,         // y position 
        50,        // Button width
        g_uControlBarHeight - 00,        // Button height
        g_hWndControlBar,     // Parent window
        (HMENU)ID_QUALITY_3,
        NULL,
        NULL);      // Pointer not needed.
    g_hwndButton4 = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed 
        L"4",      // Button text 
        WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
        500,         // x position 
        00,         // y position 
        50,        // Button width
        g_uControlBarHeight - 00,        // Button height
        g_hWndControlBar,     // Parent window
        (HMENU)ID_QUALITY_4,
        NULL,
        NULL);      // Pointer not needed.
}

void SizeAndShowWindow(UINT clientWidth, UINT clientHeight, int nCmdShow)
{
    RECT rcWindow;
    RECT rcClient;
    GetWindowRect(g_hWndDisplay, &rcWindow);
    GetClientRect(g_hWndDisplay, &rcClient);
    UINT frameWidth = (rcWindow.right - rcWindow.left) - (rcClient.right - rcClient.left);
    UINT frameHeight = (rcWindow.bottom - rcWindow.top) - (rcClient.bottom - rcClient.top);
    UINT uWidth = clientWidth + frameWidth;
    UINT uHeight = clientHeight + frameHeight;

    SetWindowPos(g_hWndDisplay, HWND_TOP, 0, 0, uWidth, uHeight, SWP_NOMOVE);
    ShowWindow(g_hWndDisplay, nCmdShow);
    GetWindowRect(g_hWndDisplay, &rcWindow);
    UINT uWidthMain = (rcWindow.right - rcWindow.left);

    if (g_hWndDisplayAlt)
    {
        RECT rcWindowAlt;
        GetWindowRect(g_hWndDisplayAlt, &rcWindowAlt);
        GetClientRect(g_hWndDisplayAlt, &rcClient);
        g_uCompareFrameWidth = (rcWindowAlt.right - rcWindowAlt.left) - (rcClient.right - rcClient.left);
        g_uCompareFrameHeight = (rcWindowAlt.bottom - rcWindowAlt.top) - (rcClient.bottom - rcClient.top);
        uWidth = clientWidth + g_uCompareFrameWidth;
        uHeight = clientHeight + g_uCompareFrameHeight;
        SetWindowPos(g_hWndDisplayAlt, HWND_TOP, rcWindow.left, rcWindow.bottom + 20, uWidth, uHeight, 0);
        GetWindowRect(g_hWndDisplayAlt, &rcWindowAlt);
        g_uCompareLeftOffset = (uWidthMain - (rcWindowAlt.right - rcWindowAlt.left)) / 2;
        SetWindowPos(g_hWndDisplayAlt, HWND_TOP, rcWindow.left + g_uCompareLeftOffset, rcWindow.bottom + g_uControlBarHeight + 10, uWidth, uHeight, 0);
        ShowWindow(g_hWndDisplayAlt, nCmdShow);
    }
    if (g_hWndControlBar)
    {
        SetWindowPos(g_hWndControlBar, HWND_TOP, rcWindow.left + 10, rcWindow.bottom, g_uControlBarWidth, g_uControlBarHeight, 0);
        ShowWindow(g_hWndControlBar, nCmdShow);
        SetUpControlBar();
    }

    BringWindowToTop(g_hWndDisplayAlt);
    BringWindowToTop(g_hWndControlBar);
    BringWindowToTop(g_hWndDisplay);
}


void UpdateCompareWindow()
{
    RECT rcWindow;
    GetWindowRect(g_hWndDisplay, &rcWindow);
    if (g_hWndDisplayAlt)
    {
        RECT rcClient;
        GetClientRect(g_hWndDisplay, &rcClient);
        UINT uWidth = (rcClient.right - rcClient.left) + g_uCompareFrameWidth;
        UINT uHeight = (rcClient.bottom - rcClient.top) + g_uCompareFrameHeight;
        SetWindowPos(g_hWndDisplayAlt, HWND_TOP, rcWindow.left + g_uCompareLeftOffset, rcWindow.bottom + g_uControlBarHeight + 10, uWidth, uHeight, 0);
    }
    if (g_hWndControlBar)
    {
        SetWindowPos(g_hWndControlBar, HWND_TOP, rcWindow.left + 10, rcWindow.bottom, g_uControlBarWidth, g_uControlBarHeight, 0);
    }
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            case ID_PLAY:
            {
                if (hWnd == g_hWndControlBar)
                {
                    g_bPaused = !g_bPaused;
                    if (g_bPaused)
                    {
                        SetWindowTextW(g_hwndButtonPlay, L"Paused");
                        Button_Enable(g_hwndButtonStepBk, true);
                        Button_Enable(g_hwndButtonStepFwd, true);
                    }
                    else
                    {
                        SetWindowTextW(g_hwndButtonPlay, L"Playing");
                        Button_Enable(g_hwndButtonStepBk, false);
                        Button_Enable(g_hwndButtonStepFwd, false);
                    }
                }

            }
            break;
            case ID_STEP_FWD:
            {
                if (hWnd == g_hWndControlBar && g_bPaused)
                {
                    HRESULT hr;
                    if (g_bDx11)
                    {
                        hr = g_pCDX11VSRDemo->NextFrame(g_iQuality);
                    }
                    else
                    {
                        hr = g_pCDX12VSRDemo->NextFrame(g_iQuality);
                    }
                    if (FAILED(hr))
                    {
                        fprintf(stdout, "\nDemo Evaluate Failed with Result:%x\n", hr);
                    }
                }
            }
            break;
            case ID_STEP_BK:
            {
                if (hWnd == g_hWndControlBar && g_bPaused)
                {
                    HRESULT hr;
                    if (g_bDx11)
                    {
                        hr = g_pCDX11VSRDemo->NextFrame(g_iQuality, true);
                    }
                    else
                    {
                        hr = g_pCDX12VSRDemo->NextFrame(g_iQuality, true);
                    }
                    if (FAILED(hr))
                    {
                        fprintf(stdout, "\nDemo Evaluate Failed with Result:%x\n", hr);
                    }
                }
            }
            break;
            case ID_QUALITY_0:
            {
                g_iQuality = 0;
            }
            break;
            case ID_QUALITY_1:
            {
                g_iQuality = 1;
            }
            break;
            case ID_QUALITY_2:
            {
                g_iQuality = 2;
            }
            break;
            case ID_QUALITY_3:
            {
                g_iQuality = 3;
            }
            break;
            case ID_QUALITY_4:
            {
                g_iQuality = 4;
            }
            break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_MOVE:
        if (hWnd == g_hWndDisplay)
        {
            int left = (int)(short)LOWORD(lParam);
            int top = (int)(short)HIWORD(lParam);
            UpdateCompareWindow();

        }
        return DefWindowProc(hWnd, message, wParam, lParam);

    case WM_SIZE:
        if (hWnd == g_hWndDisplay)
        {
            int right = (int)(short)LOWORD(lParam);
            int bottom = (int)(short)HIWORD(lParam);
            UpdateCompareWindow();
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_TIMER:
        switch (wParam)
        {
        case 1:
            if (g_bPaused)
                break;
            // next frame timer
            HRESULT hr;
            if (g_bDx11)
            {
                hr = g_pCDX11VSRDemo->NextFrame(g_iQuality);
            }
            else
            {
                hr = g_pCDX12VSRDemo->NextFrame(g_iQuality);
            }
            if (FAILED(hr)) 
            {
                fprintf(stdout, "\nDemo Evaluate Failed with Result:%x\n", hr);
                PostQuitMessage(-2);
            }
            return 0;
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
