//----------------------------------------------------------------------------------
// File:        CDx11NGXTrueHDR.h
// SDK Version: 1.0.2
//
// SPDX-FileCopyrightText: Copyright (c) 2023 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.
//
//----------------------------------------------------------------------------------

///////////////////////////////////////////
// CDx11NGXTrueHDR.h
// This is a wrapper class to simplify adding NGX TrueHDR to a DX11 app

// This class can be used as is or the code can be incorporated into the app.
// 
// Unzip the RTX_Video_SDK. SDK files are in Include and Lib
// In the SDK Samples it uses ../../Include, and ../../Lib/X64 to access the SDK
// 
// 
// normal dxgi present and direct composition present
// video decode->vpblt to RGB->TrueHDR to HDR swap back buffer->Present
// app render RGB->TrueHDR to HDR swap back buffer->Present
// 
// presentAT 
//      instead of providing decode RT or RGB to presentationManager, 
//      provide HDR texture array with ALLOW_UNORDERED_ACCESS
// 
//      video decode->vpblt to RGB->TrueHDR to HDR texture->PresentationMgr present index
//      app render RGB->TrueHDR to HDR texture->PresentationMgr present index
//
// dx11 sync requirements are handled in EvaluateFeature

#pragma once

#include "CDx1xNGX_common.h"

class CDx11NGXTrueHDR
{
public:
    CDx11NGXTrueHDR() {}

    HRESULT     CreateFeature(ID3D11Device* pD3DDevice);
    HRESULT     EvaluateFeature(ID3D11Texture2D* Output, RECT RectOutput, 
                                ID3D11Texture2D* Input,  RECT RectInput,
                                UINT Contrast,      // 0 to 200 for HDR Contrast   (default 100)
                                UINT Saturation,    // 0 to 200 for HDR Saturation (default 100)
                                UINT MiddleGray,    // 10 to 100 for HDR MiddleGray (default  50)
                                UINT MaxLuminance); // 400 to 2000 for Monitor MaxLuminance (default 1000)
    void        ReleaseFeature();

private:
    ID3D11Device*               m_pD3D11Device          = nullptr;
    ID3D11DeviceContext*        m_pD3D11DeviceContext   = nullptr;
    ID3D10Multithread*          m_pMultiThread          = nullptr;

    bool                        m_bNGXInitialized       = false;
    NVSDK_NGX_Parameter*        m_ngxParameters         = nullptr;
    NVSDK_NGX_Handle*           m_TrueHDRFeature        = nullptr;
    RECT                        m_NGXSrcRect            = {};
    RECT                        m_NGXDstRect            = {};

    bool                        m_bNGXInitializedDstTmp = false;
    ID3D11Texture2D*            m_pDstTmpNGX            = nullptr;
    UINT                        m_uDstTmpWidth          = 0;
    UINT                        m_uDstTmpHeight         = 0;
};

/////////////////////////////////////////////////////////////////
// Sample App for DX11 DXGI Present, DirectComposition Present
//
// Initialization:
//      Create ID3D11Device and ID3D11Context
//      Call CreateFeature to verify it is supported
//      Create DXGI_FORMAT_R8G8B8A8_UNORM ID3D11Texture2D for source input to feature
//          For an array, create one resource for each entry in the array (array of textures)
//          Set an input rect to define you source size.
//      Create a swap chain in HDR, either in DXGI_FORMAT_R10G10B10A2_UNORM or DXGI_FORMAT_R16G16B16A16_FLOAT.
//          Have several backbuffers, use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL or DXGI_SWAP_EFFECT_FLIP_DISCARD.
//          Set an output rect to define you destination size.
//      If possible create output buffers with D3D11_BIND_UNORDERED_ACCESS.
//
// Execution:
//      Render into source RGB.
//          For Video apps with YUV surfaces, use VPBlt from the YUV to the source RGB
//      Call EvaluateFeature with DX11 pointers, 
//          source RGB, source rect, 
//          dest HDR, dest rect,
//          other TrueHDR parameters,
//          NOTE: EvaluateFeature uses ID3D10Multithread Enter/Leave for the device's critical section to ensure thread safety.
//      Present dest HDR back buffer.
//
// Shutdown:
//      Call ReleaseFeature from a shut down function, not the class destructor.
//          There is a critical section used by NGX that the runtime deletes in a destructor.
/////////////////////////////////////////////////////////////////
// Sample App for DX11 PresentationManager
//   PresentationManager works similarly except there is no swapchain.
//   Instead of passing in decode render target array do this. 
//      Create an array of HDR textures at the size you want to present. Use D3D11_BIND_UNORDERED_ACCESS.
//          Create one resource for each entry in the array (array of textures)
//      Pass that array to create of the presentationManger to use for add buffers and presentation surfaces.
/////////////////////////////////////////////////////////////////
// Using both DLVSR and TrueHDR
//      DLVSR and TrueHDR can be run sequentially in that order.
//      TrueHDR must be last as it outputs to HDR.
//      Create an array of RGB textures for output of DLVSR and input to TrueHDR
/////////////////////////////////////////////////////////////////

#if 0
/////////////////////////////////////////////////////////////////
// Examples of code to use
// 
//////////////////////
// In .h
class CDx11NGXTrueHDR*          m_pCNGXTrueHDR      = nullptr;
RECT                            m_rcNGXInput        = {};
RECT                            m_rcNGXOutput       = {};
ID3D11Texture2D*                m_pNGXInputBuffer   = nullptr;
 
 
//////////////////////
// In Initialization:
// create feature after creating your D3D11Device
m_pCNGXTrueHDR = new CDx11NGXTrueHDR;
hr = m_pCNGXTrueHDR->CreateFeature(m_pD3D11Device);
if (FAILED(hr))
{
    SafeDelete(m_pCNGXTrueHDR);
    return hr;
}

// create swap chain with HDR format
scd.Format = (bUseABGR10) ? DXGI_FORMAT_R10G10B10A2_UNORM : DXGI_FORMAT_R16G16B16A16_FLOAT;
// set swap chain color space
if (scd.Format == DXGI_FORMAT_R16G16B16A16_FLOAT) m_pSwapChain->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709);
if (scd.Format == DXGI_FORMAT_R10G10B10A2_UNORM) m_pSwapChain->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);

// set input size for NGX
m_rcNGXInput = { 0, 0, (LONG)scd.Width, (LONG)scd.Height };
// set output size for NGX
m_rcNGXOutput = { 0, 0, (LONG)scd.Width, (LONG)scd.Height };
// set vpBlt output size to input size of NGX 
m_rcVpOutput = m_rcNGXInput;
// set vpBlt output format to DXGI_FORMAT_R8G8B8A8_UNORM 
m_FmtVpOutput = DXGI_FORMAT_R8G8B8A8_UNORM;

// create a texture2d for output from vpBlt for input to NGX. Use format DXGI_FORMAT_R8G8B8A8_UNORM and D3D11_BIND_UNORDERED_ACCESS
hr = CreateTexture2D(m_rcNGXInput.right, m_rcNGXInput.bottom, 1, DXGI_FORMAT_R8G8B8A8_UNORM, &m_pNGXInputBuffer);

// optionally get monitor max luminance and verify it is in hdr mode
DXGI_OUTPUT_DESC1 DxgiOutputDesc = {};
pDXGIOutput6->GetDesc1(&DxgiOutputDesc);
m_uMaxLuminance = (UINT)((DxgiOutputDesc.MaxLuminance >= 400.0f) ? DxgiOutputDesc.MaxLuminance : 1000);
if (DxgiOutputDesc.ColorSpace != DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
   return E_FAIL; //MonitorNotInHDRMode



//////////////////////
// In Update BackBuffer for Present
// VpBlt from decode output to NGX input buffer, RGB apps skip this.
hr = VpBlt(pDecodeRTInUse, m_pNGXInputBuffer);
hr = m_pCNGXTrueHDR->EvaluateFeature(pSwapBackBuffer, m_rcNGXOutput,
                                     m_pNGXInputBuffer, m_rcNGXInput,
                                     Contrast, Saturation, MiddleGray, MaxLuminance);

//////////////////////
// In Deinitialization (call prior to destructor):
if (m_pCNGXTrueHDR)
{
    m_pCNGXTrueHDR->ReleaseFeature();
    SafeDelete(m_pCNGXTrueHDR);
}
/////////////////////////////////////////////////////////////////
#endif