// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#ifndef DIRECTX_HEADERS_MOCK_DEVICE_HPP
#define DIRECTX_HEADERS_MOCK_DEVICE_HPP
#include <unordered_map>

#ifndef __RPC_FAR
#define __RPC_FAR
#endif

#include <directx/d3d12.h>
#include <directx/dxcore.h>
#include <directx/d3dx12.h>
#include "dxguids/dxguids.h"

class MockDevice : public ID3D12Device
{
public: // Constructors and custom functions
    MockDevice(UINT NodeCount = 1)
    : m_NodeCount(NodeCount)
    , m_TileBasedRenderer(m_NodeCount, false)
    , m_UMA(m_NodeCount, false)
    , m_CacheCoherentUMA(m_NodeCount, false)
    , m_IsolatedMMU(m_NodeCount, false)
    , m_ProtectedResourceSessionSupport(m_NodeCount, D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAG_NONE)
    , m_HeapSerializationTier(m_NodeCount, D3D12_HEAP_SERIALIZATION_TIER_0)
    , m_ProtectedResourceSessionTypeCount(m_NodeCount, 0)
    , m_ProtectedResourceSessionTypes(m_NodeCount)
    {

    }

    virtual ~MockDevice() = default;

    void SetNodeCount(UINT NewCount)
    {
        m_NodeCount = NewCount;
        m_TileBasedRenderer.resize(NewCount);
        m_UMA.resize(NewCount);
        m_CacheCoherentUMA.resize(NewCount);
        m_IsolatedMMU.resize(NewCount);
        m_ProtectedResourceSessionSupport.resize(NewCount);
        m_HeapSerializationTier.resize(NewCount);
        m_ProtectedResourceSessionTypeCount.resize(NewCount);
        m_ProtectedResourceSessionTypes.resize(NewCount);
    }

public: // ID3D12Device
    UINT STDMETHODCALLTYPE GetNodeCount() override
    {
        return m_NodeCount;
    }

    HRESULT STDMETHODCALLTYPE CreateCommandQueue(
            _In_  const D3D12_COMMAND_QUEUE_DESC *pDesc,
            REFIID riid,
            _COM_Outptr_  void **ppCommandQueue
    ) override
    {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE CreateCommandAllocator(
        _In_  D3D12_COMMAND_LIST_TYPE type,
        REFIID riid,
        _COM_Outptr_  void **ppCommandAllocator
    ) override
    {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE CreateGraphicsPipelineState(
         _In_  const D3D12_GRAPHICS_PIPELINE_STATE_DESC *pDesc,
        REFIID riid,
        _COM_Outptr_  void **ppPipelineState
    ) override
    {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE CreateComputePipelineState(
        _In_  const D3D12_COMPUTE_PIPELINE_STATE_DESC *pDesc,
        REFIID riid,
        _COM_Outptr_  void **ppPipelineState
    ) override
    {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE CreateCommandList(
        _In_  UINT nodeMask,
        _In_  D3D12_COMMAND_LIST_TYPE type,
        _In_  ID3D12CommandAllocator *pCommandAllocator,
        _In_opt_  ID3D12PipelineState *pInitialState,
        REFIID riid,
        _COM_Outptr_  void **ppCommandList
    ) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE CreateDescriptorHeap(
        _In_  const D3D12_DESCRIPTOR_HEAP_DESC *pDescriptorHeapDesc,
        REFIID riid,
        _COM_Outptr_  void **ppvHeap
    ) override
    {
        return S_OK;
    }

    virtual UINT STDMETHODCALLTYPE GetDescriptorHandleIncrementSize(
        _In_  D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapType
    ) override
    {
        return 0;
    }

    virtual HRESULT STDMETHODCALLTYPE CreateRootSignature(
        _In_  UINT nodeMask,
        _In_reads_(blobLengthInBytes)  const void *pBlobWithRootSignature,
        _In_  SIZE_T blobLengthInBytes,
        REFIID riid,
        _COM_Outptr_  void **ppvRootSignature
    ) override
    {
        return S_OK;
    }

    virtual void STDMETHODCALLTYPE CreateConstantBufferView(
        _In_opt_  const D3D12_CONSTANT_BUFFER_VIEW_DESC *pDesc,
        _In_  D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor
    ) override
    {
        return;
    }

    virtual void STDMETHODCALLTYPE CreateShaderResourceView(
        _In_opt_  ID3D12Resource *pResource,
        _In_opt_  const D3D12_SHADER_RESOURCE_VIEW_DESC *pDesc,
        _In_  D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor
    ) override
    {
        return;
    }

    virtual void STDMETHODCALLTYPE CreateUnorderedAccessView(
        _In_opt_  ID3D12Resource *pResource,
        _In_opt_  ID3D12Resource *pCounterResource,
        _In_opt_  const D3D12_UNORDERED_ACCESS_VIEW_DESC *pDesc,
        _In_  D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor
    ) override
    {
        return;
    }

    virtual void STDMETHODCALLTYPE CreateRenderTargetView(
        _In_opt_  ID3D12Resource *pResource,
        _In_opt_  const D3D12_RENDER_TARGET_VIEW_DESC *pDesc,
        _In_  D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor
    ) override
    {
        return;
    }

    virtual void STDMETHODCALLTYPE CreateDepthStencilView(
        _In_opt_  ID3D12Resource *pResource,
        _In_opt_  const D3D12_DEPTH_STENCIL_VIEW_DESC *pDesc,
        _In_  D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) override
    {
        return;
    }

    virtual void STDMETHODCALLTYPE CreateSampler(
        _In_  const D3D12_SAMPLER_DESC *pDesc,
        _In_  D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) override
    {
        return;
    }

    virtual void STDMETHODCALLTYPE CopyDescriptors(
        _In_  UINT NumDestDescriptorRanges,
        _In_reads_(NumDestDescriptorRanges)  const D3D12_CPU_DESCRIPTOR_HANDLE *pDestDescriptorRangeStarts,
        _In_reads_opt_(NumDestDescriptorRanges)  const UINT *pDestDescriptorRangeSizes,
        _In_  UINT NumSrcDescriptorRanges,
        _In_reads_(NumSrcDescriptorRanges)  const D3D12_CPU_DESCRIPTOR_HANDLE *pSrcDescriptorRangeStarts,
        _In_reads_opt_(NumSrcDescriptorRanges)  const UINT *pSrcDescriptorRangeSizes,
        _In_  D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType) override
    {
        return;
    }

    virtual void STDMETHODCALLTYPE CopyDescriptorsSimple(
        _In_  UINT NumDescriptors,
        _In_  D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptorRangeStart,
        _In_  D3D12_CPU_DESCRIPTOR_HANDLE SrcDescriptorRangeStart,
        _In_  D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType) override
    {
        return;
    }

#if defined(_MSC_VER) || !defined(_WIN32)
    virtual D3D12_RESOURCE_ALLOCATION_INFO STDMETHODCALLTYPE GetResourceAllocationInfo(
        _In_  UINT visibleMask,
        _In_  UINT numResourceDescs,
        _In_reads_(numResourceDescs)  const D3D12_RESOURCE_DESC *pResourceDescs) override
    {
        D3D12_RESOURCE_ALLOCATION_INFO mockInfo = {};
        return mockInfo;
    }
#else
    virtual D3D12_RESOURCE_ALLOCATION_INFO *STDMETHODCALLTYPE GetResourceAllocationInfo(
        D3D12_RESOURCE_ALLOCATION_INFO * RetVal,
        _In_  UINT visibleMask,
        _In_  UINT numResourceDescs,
        _In_reads_(numResourceDescs)  const D3D12_RESOURCE_DESC *pResourceDescs) override
    {
        if (RetVal)
        {
            *RetVal = {};
        }
        return RetVal;
    }
#endif

#if defined(_MSC_VER) || !defined(_WIN32)
    virtual D3D12_HEAP_PROPERTIES STDMETHODCALLTYPE GetCustomHeapProperties(
        _In_  UINT nodeMask,
        D3D12_HEAP_TYPE heapType) override
    {
        D3D12_HEAP_PROPERTIES mockProps = {};
        return mockProps;
    }
#else
    virtual D3D12_HEAP_PROPERTIES *STDMETHODCALLTYPE GetCustomHeapProperties(
        D3D12_HEAP_PROPERTIES * RetVal,
        _In_  UINT nodeMask,
        D3D12_HEAP_TYPE heapType) override
    {
        if (RetVal)
        {
            *RetVal = {};
        }
        return RetVal;
    }
#endif

    virtual HRESULT STDMETHODCALLTYPE CreateCommittedResource(
        _In_  const D3D12_HEAP_PROPERTIES *pHeapProperties,
        D3D12_HEAP_FLAGS HeapFlags,
        _In_  const D3D12_RESOURCE_DESC *pDesc,
        D3D12_RESOURCE_STATES InitialResourceState,
        _In_opt_  const D3D12_CLEAR_VALUE *pOptimizedClearValue,
        REFIID riidResource,
        _COM_Outptr_opt_  void **ppvResource) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE CreateHeap(
        _In_  const D3D12_HEAP_DESC *pDesc,
        REFIID riid,
        _COM_Outptr_opt_  void **ppvHeap) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE CreatePlacedResource(
        _In_  ID3D12Heap *pHeap,
        UINT64 HeapOffset,
        _In_  const D3D12_RESOURCE_DESC *pDesc,
        D3D12_RESOURCE_STATES InitialState,
        _In_opt_  const D3D12_CLEAR_VALUE *pOptimizedClearValue,
        REFIID riid,
        _COM_Outptr_opt_  void **ppvResource) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE CreateReservedResource(
        _In_  const D3D12_RESOURCE_DESC *pDesc,
        D3D12_RESOURCE_STATES InitialState,
        _In_opt_  const D3D12_CLEAR_VALUE *pOptimizedClearValue,
        REFIID riid,
        _COM_Outptr_opt_  void **ppvResource) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE CreateSharedHandle(
        _In_  ID3D12DeviceChild *pObject,
        _In_opt_  const SECURITY_ATTRIBUTES *pAttributes,
        DWORD Access,
        _In_opt_  LPCWSTR Name,
        _Out_  HANDLE *pHandle) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE OpenSharedHandle(
        _In_  HANDLE NTHandle,
        REFIID riid,
        _COM_Outptr_opt_  void **ppvObj) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE OpenSharedHandleByName(
        _In_  LPCWSTR Name,
        DWORD Access,
        /* [annotation][out] */
        _Out_  HANDLE *pNTHandle) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE MakeResident(
        UINT NumObjects,
        _In_reads_(NumObjects)  ID3D12Pageable *const *ppObjects) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE Evict(
        UINT NumObjects,
        _In_reads_(NumObjects)  ID3D12Pageable *const *ppObjects) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE CreateFence(
        UINT64 InitialValue,
        D3D12_FENCE_FLAGS Flags,
        REFIID riid,
        _COM_Outptr_  void **ppFence) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE GetDeviceRemovedReason( void) override
    {
        return S_OK;
    }

    virtual void STDMETHODCALLTYPE GetCopyableFootprints(
        _In_  const D3D12_RESOURCE_DESC *pResourceDesc,
        _In_range_(0,D3D12_REQ_SUBRESOURCES)  UINT FirstSubresource,
        _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource)  UINT NumSubresources,
        UINT64 BaseOffset,
        _Out_writes_opt_(NumSubresources)  D3D12_PLACED_SUBRESOURCE_FOOTPRINT *pLayouts,
        _Out_writes_opt_(NumSubresources)  UINT *pNumRows,
        _Out_writes_opt_(NumSubresources)  UINT64 *pRowSizeInBytes,
        _Out_opt_  UINT64 *pTotalBytes) override
    {
        return;
    }

    virtual HRESULT STDMETHODCALLTYPE CreateQueryHeap(
        _In_  const D3D12_QUERY_HEAP_DESC *pDesc,
        REFIID riid,
        _COM_Outptr_opt_  void **ppvHeap) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE SetStablePowerState(
        BOOL Enable) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE CreateCommandSignature(
        _In_  const D3D12_COMMAND_SIGNATURE_DESC *pDesc,
        _In_opt_  ID3D12RootSignature *pRootSignature,
        REFIID riid,
        _COM_Outptr_opt_  void **ppvCommandSignature) override
    {
        return S_OK;
    }

    virtual void STDMETHODCALLTYPE GetResourceTiling(
        _In_  ID3D12Resource *pTiledResource,
        _Out_opt_  UINT *pNumTilesForEntireResource,
        _Out_opt_  D3D12_PACKED_MIP_INFO *pPackedMipDesc,
        _Out_opt_  D3D12_TILE_SHAPE *pStandardTileShapeForNonPackedMips,
        _Inout_opt_  UINT *pNumSubresourceTilings,
        _In_  UINT FirstSubresourceTilingToGet,
        _Out_writes_(*pNumSubresourceTilings)  D3D12_SUBRESOURCE_TILING *pSubresourceTilingsForNonPackedMips) override
    {
        return;
    }

#if defined(_MSC_VER) || !defined(_WIN32)
    virtual LUID STDMETHODCALLTYPE GetAdapterLuid( void) override
    {
        LUID mockLuid = {};
        return mockLuid;
    }
#else
    virtual LUID *STDMETHODCALLTYPE GetAdapterLuid(
        LUID * RetVal) override
    {
        if (RetVal)
        {
            *RetVal = {};
        }
        return RetVal;
    }
#endif

public: // ID3D12Object
    virtual HRESULT STDMETHODCALLTYPE GetPrivateData(
        _In_  REFGUID guid,
        _Inout_  UINT *pDataSize,
        _Out_writes_bytes_opt_( *pDataSize )  void *pData) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE SetPrivateData(
        _In_  REFGUID guid,
        _In_  UINT DataSize,
        _In_reads_bytes_opt_( DataSize )  const void *pData) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
        _In_  REFGUID guid,
        _In_opt_  const IUnknown *pData) override
    {
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE SetName(
        _In_z_  LPCWSTR Name) override
    {
        return S_OK;
    }

public: // IUnknown
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
        /* [in] */ REFIID riid,
        /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) override
    {
        *ppvObject = this;
        return S_OK;
    }

    virtual ULONG STDMETHODCALLTYPE AddRef() override
    {
        // Casual implementation. No actual actions
        return 0;
    }

    virtual ULONG STDMETHODCALLTYPE Release() override
    {
        return 0;
    }


    // Major function we need to work with
    virtual HRESULT STDMETHODCALLTYPE CheckFeatureSupport(
        D3D12_FEATURE Feature,
        _Inout_updates_bytes_(FeatureSupportDataSize)  void *pFeatureSupportData,
        UINT FeatureSupportDataSize
    ) override
    {
        switch( Feature )
        {
            case D3D12_FEATURE_D3D12_OPTIONS:
            {
                D3D12_FEATURE_DATA_D3D12_OPTIONS* pD3D12Options = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS))
                {
                    return E_INVALIDARG;
                }
                pD3D12Options->DoublePrecisionFloatShaderOps       = m_DoublePrecisionFloatShaderOps;
                pD3D12Options->OutputMergerLogicOp                 = m_OutputMergerLogicOp;
                pD3D12Options->MinPrecisionSupport                 = m_ShaderMinPrecisionSupport10Bit | m_ShaderMinPrecisionSupport16Bit;
                pD3D12Options->TiledResourcesTier                  = m_TiledResourcesTier;
                pD3D12Options->ResourceBindingTier                 = m_ResourceBindingTier;
                pD3D12Options->PSSpecifiedStencilRefSupported      = (m_FeatureLevel >= D3D_FEATURE_LEVEL_11_1) && m_PSSpecifiedStencilRefSupported;
                pD3D12Options->TypedUAVLoadAdditionalFormats       = (m_FeatureLevel >= D3D_FEATURE_LEVEL_11_0) && m_TypedUAVLoadAdditionalFormats;
                pD3D12Options->ROVsSupported                       = (m_FeatureLevel >= D3D_FEATURE_LEVEL_11_0) && m_ROVsSupported;
                pD3D12Options->ConservativeRasterizationTier       = (m_FeatureLevel >= D3D_FEATURE_LEVEL_11_1) ? m_ConservativeRasterizationTier : D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED;
                pD3D12Options->MaxGPUVirtualAddressBitsPerResource = m_MaxGPUVirtualAddressBitsPerResource;
                pD3D12Options->StandardSwizzle64KBSupported        = m_StandardSwizzle64KBSupported;
    #ifdef DX_ASTC_PROTOTYPE_ENABLED
                pD3D12Options->ASTCProfile                         = ASTCProfile();
    #endif
                pD3D12Options->CrossNodeSharingTier                = m_CrossNodeSharingTier;
                pD3D12Options->CrossAdapterRowMajorTextureSupported = m_CrossAdapterRowMajorTextureSupported;
                pD3D12Options->VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation = m_VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation;
                pD3D12Options->ResourceHeapTier                    = m_ResourceHeapTier;
            } return S_OK;

        case D3D12_FEATURE_D3D12_OPTIONS1:
        {
            if (!m_Options1Available)
            {
                return E_INVALIDARG;
            }
            D3D12_FEATURE_DATA_D3D12_OPTIONS1* pD3D12Options1 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS1*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS1))
            {
                return E_INVALIDARG;
            }
            pD3D12Options1->WaveOps = m_WaveOpsSupported;
            pD3D12Options1->WaveLaneCountMin = m_WaveLaneCountMin;
            pD3D12Options1->WaveLaneCountMax = m_WaveLaneCountMax;
            pD3D12Options1->TotalLaneCount = m_TotalLaneCount;
            pD3D12Options1->ExpandedComputeResourceStates = m_ExpandedComputeResourceStates;
            pD3D12Options1->Int64ShaderOps = m_Int64ShaderOpsSupported;
        } return S_OK;


        case D3D12_FEATURE_D3D12_OPTIONS2:
        {
            if (!m_Options2Available)
            {
                return E_INVALIDARG;
            }

            D3D12_FEATURE_DATA_D3D12_OPTIONS2* pD3D12Options2 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS2*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS2))
            {
                return E_INVALIDARG;
            }
            pD3D12Options2->DepthBoundsTestSupported = m_DepthBoundsTestSupport;
            pD3D12Options2->ProgrammableSamplePositionsTier = m_ProgrammableSamplePositionsTier;
        } return S_OK;

        case D3D12_FEATURE_ROOT_SIGNATURE:
        {
            if (!m_RootSignatureAvailable)
            {
                return E_INVALIDARG;
            }
            D3D12_FEATURE_DATA_ROOT_SIGNATURE* pRootSig = static_cast<D3D12_FEATURE_DATA_ROOT_SIGNATURE*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(D3D12_FEATURE_DATA_ROOT_SIGNATURE))
            {
                return E_INVALIDARG;
            }
            switch (pRootSig->HighestVersion)
            {
            case D3D_ROOT_SIGNATURE_VERSION_1_0:
            case D3D_ROOT_SIGNATURE_VERSION_1_1:
                break;
            default:
                return E_INVALIDARG;
            }
            pRootSig->HighestVersion = static_cast<D3D_ROOT_SIGNATURE_VERSION>(std::min<int>(pRootSig->HighestVersion, m_RootSignatureHighestVersion));
        } return S_OK;


        case D3D12_FEATURE_ARCHITECTURE:
            {
                D3D12_FEATURE_DATA_ARCHITECTURE* pFData =
                    static_cast< D3D12_FEATURE_DATA_ARCHITECTURE* >( pFeatureSupportData );
                if (FeatureSupportDataSize != sizeof( *pFData ))
                {
                    return E_INVALIDARG;
                }

                // Testing only
                // If Architecture1 is available, use data from architecture1
                if (m_Architecture1Available)
                {
                    D3D12_FEATURE_DATA_ARCHITECTURE1 CurFData;
                    CurFData.NodeIndex = pFData->NodeIndex;

                    HRESULT hr;
                    if (FAILED( hr = CheckFeatureSupport( D3D12_FEATURE_ARCHITECTURE1, &CurFData, sizeof( CurFData ) ) ))
                    {
                        return hr;
                    }

                    pFData->TileBasedRenderer = CurFData.TileBasedRenderer;
                    pFData->UMA = CurFData.UMA;
                    pFData->CacheCoherentUMA = CurFData.CacheCoherentUMA;
                }
                else // Otherwise, load the data directly
                {
                    // The original procedure will generate and return an E_INVALIDARG error if the NodeIndex is out of scope
                    // Mocking the behavior here by returning the rror
                    if (!(pFData->NodeIndex < m_NodeCount))
                    {
                        return E_INVALIDARG;
                    }
                    pFData->TileBasedRenderer = m_TileBasedRenderer[pFData->NodeIndex];
                    pFData->UMA = m_UMA[pFData->NodeIndex];
                    pFData->CacheCoherentUMA = m_CacheCoherentUMA[pFData->NodeIndex];
                    // Note that Architecture doesn't have the IsolatedMMU field.
                }
            } return S_OK;
        case D3D12_FEATURE_ARCHITECTURE1:
            {
                // Mocking the case where ARCHITECTURE1 is not supported
                if (!m_Architecture1Available || !m_ArchitectureSucceed) {
                    return E_INVALIDARG;
                }

                D3D12_FEATURE_DATA_ARCHITECTURE1* pFData =
                    static_cast< D3D12_FEATURE_DATA_ARCHITECTURE1* >( pFeatureSupportData );
                if (FeatureSupportDataSize != sizeof( *pFData ))
                {
                    return E_INVALIDARG;
                }

                // The original procedure will generate and return an E_INVALIDARG error if the NodeIndex is out of scope
                // Mocking the behavior here by returning the rror
                if (!(pFData->NodeIndex < m_NodeCount))
                {
                    return E_INVALIDARG;
                }

                UINT localIndex = pFData->NodeIndex;
                pFData->TileBasedRenderer = m_TileBasedRenderer[localIndex];
                pFData->UMA = m_UMA[localIndex];
                pFData->CacheCoherentUMA = m_CacheCoherentUMA[localIndex];
                pFData->IsolatedMMU = m_IsolatedMMU[localIndex];

            } return S_OK;

        case D3D12_FEATURE_FEATURE_LEVELS:
            {
                D3D12_FEATURE_DATA_FEATURE_LEVELS* pFData =
                    static_cast< D3D12_FEATURE_DATA_FEATURE_LEVELS* >( pFeatureSupportData );
                if (FeatureSupportDataSize != sizeof( *pFData ))
                {
                    return E_INVALIDARG;
                }

                if (pFData->NumFeatureLevels == 0 || pFData->pFeatureLevelsRequested == nullptr)
                {
                    return E_INVALIDARG;
                }

                pFData->MaxSupportedFeatureLevel = D3D_FEATURE_LEVEL(0);
                for (UINT i = 0; i < pFData->NumFeatureLevels; ++i)
                {
                    if (pFData->pFeatureLevelsRequested[i] <= m_FeatureLevel &&
                        pFData->pFeatureLevelsRequested[i] > pFData->MaxSupportedFeatureLevel)
                    {
                        pFData->MaxSupportedFeatureLevel = pFData->pFeatureLevelsRequested[i];
                    }
                }
                return pFData->MaxSupportedFeatureLevel == D3D_FEATURE_LEVEL(0) ?
                    DXGI_ERROR_UNSUPPORTED : S_OK;
            }

        case D3D12_FEATURE_FORMAT_SUPPORT:
            {
                D3D12_FEATURE_DATA_FORMAT_SUPPORT* pFData =
                    static_cast< D3D12_FEATURE_DATA_FORMAT_SUPPORT* >( pFeatureSupportData );
                if (FeatureSupportDataSize != sizeof( *pFData ))
                {
                    return E_INVALIDARG;
                }
                m_FormatReceived = pFData->Format;
                pFData->Support1 = m_FormatSupport1;
                pFData->Support2 = m_FormatSupport2;
                // Based on the original implementation, if there's no support for the format, return an E_FAIL
                if (m_FormatSupport1 == D3D12_FORMAT_SUPPORT1_NONE && m_FormatSupport2 == D3D12_FORMAT_SUPPORT2_NONE)
                {
                    return E_FAIL;
                }
            } return S_OK;

        case D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS:
            {
                D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS* pFData =
                    static_cast< D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS* >( pFeatureSupportData );
                if (FeatureSupportDataSize != sizeof( *pFData ))
                {
                    return E_INVALIDARG;
                }

                m_FormatReceived = pFData->Format;
                m_SampleCountReceived = pFData->SampleCount;
                m_MultisampleQualityLevelFlagsReceived = pFData->Flags;

                // The original check implementation may return E_FAIL
                // Valid results are non-negative values including 0, smaller than D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT
                if (!m_MultisampleQualityLevelsSucceed)
                {
                    // NumQualityLevels will be set to 0 should the check fails
                    pFData->NumQualityLevels = 0;
                    return E_FAIL;
                }

                pFData->NumQualityLevels = m_NumQualityLevels;
            } return S_OK;
        case D3D12_FEATURE_FORMAT_INFO:
            {
                D3D12_FEATURE_DATA_FORMAT_INFO* pFData =
                    static_cast< D3D12_FEATURE_DATA_FORMAT_INFO* > ( pFeatureSupportData );
                if (FeatureSupportDataSize != sizeof( *pFData ))
                {
                    return E_INVALIDARG;
                }

                m_FormatReceived = pFData->Format;

                // If the format is not supported, an E_INVALIDARG will be returned
                if (!m_DXGIFormatSupported)
                {
                    return E_INVALIDARG;
                }

                pFData->PlaneCount = m_PlaneCount;

            } return S_OK;
        case D3D12_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT:
            {
                D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT* pFData =
                    static_cast< D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT* >( pFeatureSupportData );
                if (FeatureSupportDataSize != sizeof( *pFData ))
                {
                    return E_INVALIDARG;
                }
                pFData->MaxGPUVirtualAddressBitsPerProcess = m_MaxGPUVirtualAddressBitsPerProcess;
                pFData->MaxGPUVirtualAddressBitsPerResource = m_MaxGPUVirtualAddressBitsPerResource;

            } return S_OK;
        case D3D12_FEATURE_SHADER_MODEL:
            {
                D3D12_FEATURE_DATA_SHADER_MODEL* pSM =
                    static_cast<D3D12_FEATURE_DATA_SHADER_MODEL*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pSM))
                {
                    return E_INVALIDARG;
                }
                switch (pSM->HighestShaderModel)
                {
                case D3D_SHADER_MODEL_5_1:
                case D3D_SHADER_MODEL_6_0:
                case D3D_SHADER_MODEL_6_1:
                case D3D_SHADER_MODEL_6_2:
                case D3D_SHADER_MODEL_6_3:
                case D3D_SHADER_MODEL_6_4:
                case D3D_SHADER_MODEL_6_5:
                case D3D_SHADER_MODEL_6_6:
                case D3D_SHADER_MODEL_6_7:
                    break;
                default:
                    return E_INVALIDARG;
                }
                pSM->HighestShaderModel = static_cast<D3D_SHADER_MODEL>(std::min<int>(pSM->HighestShaderModel,m_HighestSupportedShaderModel));
            } return S_OK;
        case D3D12_FEATURE_SHADER_CACHE:
            {
                if (!m_ShaderCacheAvailable)
                {
                    return E_INVALIDARG;
                }
                D3D12_FEATURE_DATA_SHADER_CACHE* pFlags =
                    static_cast<D3D12_FEATURE_DATA_SHADER_CACHE*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pFlags))
                {
                    return E_INVALIDARG;
                }
               pFlags->SupportFlags = m_ShaderCacheSupportFlags;
            } return S_OK;
        case D3D12_FEATURE_COMMAND_QUEUE_PRIORITY:
            {
                if (!m_CommandQueuePriorityAvailable)
                {
                    return E_INVALIDARG;
                }
                D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY* pFlags =
                    static_cast<D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pFlags))
                {
                    return E_INVALIDARG;
                }

                if (pFlags->CommandListType >= D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE+1)
                {
                    return E_INVALIDARG;
                }

                if (pFlags->Priority == D3D12_COMMAND_QUEUE_PRIORITY_NORMAL || pFlags->Priority == D3D12_COMMAND_QUEUE_PRIORITY_HIGH)
                {
                    pFlags->PriorityForTypeIsSupported = TRUE;
                }
                else if (pFlags->Priority == D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME)
                {
                    pFlags->PriorityForTypeIsSupported = m_GlobalRealtimeCommandQueueSupport; // Simplified
                }
                else
                {
                    return E_INVALIDARG;
                }

            } return S_OK;

        case D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_SUPPORT:
            {
                if (!m_ProtectedResourceSessionAvailable)
                {
                    return E_INVALIDARG;
                }
                D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_SUPPORT* pProtectedResourceSessionSupport =
                    static_cast<D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_SUPPORT*>(pFeatureSupportData);
                if (   FeatureSupportDataSize != sizeof(*pProtectedResourceSessionSupport)
                    || pProtectedResourceSessionSupport->NodeIndex >= GetNodeCount())
                {
                    return E_INVALIDARG;
                }

                pProtectedResourceSessionSupport->Support = m_ContentProtectionSupported ?
                    m_ProtectedResourceSessionSupport[pProtectedResourceSessionSupport->NodeIndex]
                    : D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAG_NONE;

            } return S_OK;

        case D3D12_FEATURE_D3D12_OPTIONS3:
        {
            if (!m_Options3Available)
            {
                return E_INVALIDARG;
            }
            D3D12_FEATURE_DATA_D3D12_OPTIONS3* pD3D12Options3 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS3*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS3))
            {
                return E_INVALIDARG;
            }
            pD3D12Options3->CopyQueueTimestampQueriesSupported = m_CopyQueueTimestampQueriesSupported;
            pD3D12Options3->CastingFullyTypedFormatSupported = m_CastingFullyTypedFormatsSupported;
            pD3D12Options3->WriteBufferImmediateSupportFlags = m_GetCachedWriteBufferImmediateSupportFlags;
            pD3D12Options3->ViewInstancingTier = m_ViewInstancingTier;
            pD3D12Options3->BarycentricsSupported = m_BarycentricsSupported;

        } return S_OK;
        case D3D12_FEATURE_EXISTING_HEAPS:
            {
                if (!m_ExistingHeapsAvailable)
                {
                    return E_INVALIDARG;
                }
                auto* pSupport = static_cast<D3D12_FEATURE_DATA_EXISTING_HEAPS*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pSupport))
                {
                    return E_INVALIDARG;
                }
                pSupport->Supported = m_ExistingHeapCaps;
            } return S_OK;
        case D3D12_FEATURE_D3D12_OPTIONS4:
            {
                if (!m_Options4Available)
                {
                    return E_INVALIDARG;
                }
                auto* pD3D12Options4 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS4*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pD3D12Options4))
                {
                    return E_INVALIDARG;
                }

                // Reserved Buffer Placement was cut, except for 64KB Aligned MSAA Textures
                pD3D12Options4->MSAA64KBAlignedTextureSupported = m_MSAA64KBAlignedTextureSupported;
                pD3D12Options4->SharedResourceCompatibilityTier = m_SharedResourceCompatibilityTier; // Simplified
                pD3D12Options4->Native16BitShaderOpsSupported = m_Native16BitShaderOpsSupported;
            } return S_OK;
        case D3D12_FEATURE_SERIALIZATION:
            {
                if (!m_SerializationAvailable)
                {
                    return E_INVALIDARG;
                }
                auto* pSerialization = static_cast<D3D12_FEATURE_DATA_SERIALIZATION*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pSerialization))
                {
                    return E_INVALIDARG;
                }

                const UINT NodeIndex = pSerialization->NodeIndex;
                if (NodeIndex >= m_NodeCount)
                {
                    return E_INVALIDARG;
                }
                pSerialization->HeapSerializationTier = m_HeapSerializationTier[NodeIndex];
            } return S_OK;
        case D3D12_FEATURE_CROSS_NODE:
            {
                if (!m_CrossNodeAvailable)
                {
                    return E_INVALIDARG;
                }
                auto* pCrossNode = static_cast<D3D12_FEATURE_DATA_CROSS_NODE*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pCrossNode))
                {
                    return E_INVALIDARG;
                }

                pCrossNode->SharingTier = m_CrossNodeSharingTier;
                pCrossNode->AtomicShaderInstructions = m_AtomicShaderInstructions;
            } return S_OK;
        case D3D12_FEATURE_D3D12_OPTIONS5:
            {
                if (!m_Options5Available)
                {
                    return E_INVALIDARG;
                }
                auto* pD3D12Options5 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS5*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pD3D12Options5))
                {
                    return E_INVALIDARG;
                }

                pD3D12Options5->RaytracingTier = m_RaytracingTier;
                pD3D12Options5->RenderPassesTier = m_RenderPassesTier;
                pD3D12Options5->SRVOnlyTiledResourceTier3 = m_SRVOnlyTiledResourceTier3;
            } return S_OK;
        case D3D12_FEATURE_DISPLAYABLE:
            {
                if (!m_DisplayableAvailable)
                {
                    return E_INVALIDARG;
                }
                auto* pD3D12Displayable = static_cast<D3D12_FEATURE_DATA_DISPLAYABLE*>(pFeatureSupportData);
                if (FeatureSupportDataSize != sizeof(*pD3D12Displayable)) // Feature_D3D1XDisplayable
                {
                    return E_INVALIDARG;
                }

                pD3D12Displayable->DisplayableTexture = m_DisplayableTexture;
                pD3D12Displayable->SharedResourceCompatibilityTier = m_SharedResourceCompatibilityTier;
            } return S_OK;

        case D3D12_FEATURE_D3D12_OPTIONS6:
        {
            if (!m_Options6Available)
            {
                return E_INVALIDARG;
            }

            auto* pD3D12Options6 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS6*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(*pD3D12Options6))
            {
                return E_INVALIDARG;
            }
            pD3D12Options6->AdditionalShadingRatesSupported = m_AdditionalShadingRatesSupported;
            pD3D12Options6->BackgroundProcessingSupported = m_BackgroundProcessingSupported;
            pD3D12Options6->PerPrimitiveShadingRateSupportedWithViewportIndexing = m_PerPrimitiveShadingRateSupportedWithViewportIndexing;
            pD3D12Options6->ShadingRateImageTileSize = m_ShadingRateImageTileSize;
            pD3D12Options6->VariableShadingRateTier = m_VariableShadingRateTier;
        } return S_OK;
        case D3D12_FEATURE_QUERY_META_COMMAND:
        {
            if (m_QueryMetaCommandAvailable)
            {
                if (FeatureSupportDataSize != sizeof(D3D12_FEATURE_DATA_QUERY_META_COMMAND))
                {
                    return E_INVALIDARG;
                }

                // Only checks inputs and outputs
                auto* pQueryData = static_cast<D3D12_FEATURE_DATA_QUERY_META_COMMAND*>(pFeatureSupportData);
                m_CommandID = pQueryData->CommandId;
                m_pQueryInputData = pQueryData->pQueryInputData;
                m_NodeMask = pQueryData->NodeMask;
                m_QueryInputDataSizeInBytes = pQueryData->QueryInputDataSizeInBytes;

                pQueryData->QueryOutputDataSizeInBytes = m_QueryOutputDataSizeInBytes;
                pQueryData->pQueryOutputData = m_pQueryOutputData;
            }
            else
            {
                return E_INVALIDARG;
            }
        } return S_OK;
        case D3D12_FEATURE_D3D12_OPTIONS7:
        {
            if (!m_Options7Available)
            {
                return E_INVALIDARG;
            }
            auto* pD3D12Options7 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS7*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(*pD3D12Options7))
            {
                return E_INVALIDARG;
            }

            pD3D12Options7->MeshShaderTier = m_MeshShaderTier;
            pD3D12Options7->SamplerFeedbackTier = m_SamplerFeedbackTier;
        } return S_OK;
        case D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_TYPE_COUNT:
            {
                if (!m_ProtectedResourceSessionTypeCountAvailable)
                {
                    return E_INVALIDARG;
                }
                auto* pProtectedResourceSessionTypesCount =
                    static_cast<D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPE_COUNT*>(pFeatureSupportData);
                if (   FeatureSupportDataSize != sizeof(*pProtectedResourceSessionTypesCount)
                    || pProtectedResourceSessionTypesCount->NodeIndex >= GetNodeCount())
                {
                    return E_INVALIDARG;
                }

                pProtectedResourceSessionTypesCount->Count = m_ProtectedResourceSessionTypeCount[pProtectedResourceSessionTypesCount->NodeIndex];
            } return S_OK;
        case D3D12_FEATURE_PROTECTED_RESOURCE_SESSION_TYPES:
            {
                if (!m_ProtectedResourceSessionTypesAvailable)
                {
                    return E_INVALIDARG;
                }
                auto* pProtectedResourceSessionTypes =
                    static_cast<D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPES*>(pFeatureSupportData);
                if (   FeatureSupportDataSize != sizeof(*pProtectedResourceSessionTypes)
                    || pProtectedResourceSessionTypes->NodeIndex >= GetNodeCount())
                {
                    return E_INVALIDARG;
                }
                UINT ExpectedCount = m_ProtectedResourceSessionTypeCount[pProtectedResourceSessionTypes->NodeIndex];
                if (pProtectedResourceSessionTypes->Count != ExpectedCount)
                {
                    return E_INVALIDARG;
                }

                if (ExpectedCount > 0)
                {
                    memcpy(pProtectedResourceSessionTypes->pTypes, m_ProtectedResourceSessionTypes[pProtectedResourceSessionTypes->NodeIndex].data(), ExpectedCount * sizeof(*pProtectedResourceSessionTypes->pTypes));
                }

            } return S_OK;

        case D3D12_FEATURE_D3D12_OPTIONS8:
        {
            if (!m_Options8Available)
            {
                return E_INVALIDARG;
            }
            D3D12_FEATURE_DATA_D3D12_OPTIONS8 *pD3D12Options8 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS8*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(*pD3D12Options8))
            {
                return E_INVALIDARG;
            }

            pD3D12Options8->UnalignedBlockTexturesSupported = m_UnalignedBlockTexturesSupported;
        } return S_OK;
        case D3D12_FEATURE_D3D12_OPTIONS9:
        {
            if (!m_Options9Available)
            {
                return E_INVALIDARG;
            }
            D3D12_FEATURE_DATA_D3D12_OPTIONS9 *pD3D12Options9 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS9*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(*pD3D12Options9))
            {
                return E_INVALIDARG;
            }

            pD3D12Options9->AtomicInt64OnGroupSharedSupported = m_AtomicInt64OnGroupSharedSupported;
            pD3D12Options9->AtomicInt64OnTypedResourceSupported = m_AtomicInt64OnTypedResourceSupported;
            pD3D12Options9->DerivativesInMeshAndAmplificationShadersSupported = m_DerivativesInMeshAndAmplificationShadersSupported;
            pD3D12Options9->MeshShaderPipelineStatsSupported = m_MeshShaderPipelineStatsSupported;
            pD3D12Options9->MeshShaderSupportsFullRangeRenderTargetArrayIndex = m_MeshShaderSupportsFullRangeRenderTargetArrayIndex;
            pD3D12Options9->WaveMMATier = m_WaveMMATier;
        } return S_OK;
        case D3D12_FEATURE_D3D12_OPTIONS10:
        {
            if (!m_Options10Available)
            {
                return E_INVALIDARG;
            }
            D3D12_FEATURE_DATA_D3D12_OPTIONS10* pD3D12Options10 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS10*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(*pD3D12Options10))
            {
                return E_INVALIDARG;
            }

            pD3D12Options10->MeshShaderPerPrimitiveShadingRateSupported = m_MeshShaderPerPrimitiveShadingRateSupported;
            pD3D12Options10->VariableRateShadingSumCombinerSupported = m_VariableRateShadingSumCombinerSupported;
        } return S_OK;
        case D3D12_FEATURE_D3D12_OPTIONS11:
        {
            if (!m_Options11Available)
            {
                return E_INVALIDARG;
            }
            D3D12_FEATURE_DATA_D3D12_OPTIONS11* pD3D12Options11 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS11*>(pFeatureSupportData);
            if (FeatureSupportDataSize != sizeof(*pD3D12Options11))
            {
                return E_INVALIDARG;
            }

            pD3D12Options11->AtomicInt64OnDescriptorHeapResourceSupported = m_AtomicInt64OnDescriptorHeapResourceSupported;
        } return S_OK;
        case D3D12_FEATURE_D3D12_OPTIONS12:
        {
            if (!m_Options12Available)
            {
                return E_INVALIDARG;
            }
			D3D12_FEATURE_DATA_D3D12_OPTIONS12* pD3D12Options12 = static_cast<D3D12_FEATURE_DATA_D3D12_OPTIONS12*>(pFeatureSupportData);
			if (FeatureSupportDataSize != sizeof(*pD3D12Options12))
			{
				return E_INVALIDARG;
			}

            pD3D12Options12->MSPrimitivesPipelineStatisticIncludesCulledPrimitives = m_MSPrimitivesPipelineStatisticIncludesCulledPrimitives;
            pD3D12Options12->EnhancedBarriersSupported = m_EnhancedBarriersSupported;
        } return S_OK;

        default:
            return E_INVALIDARG;
        }
    }

public: // For simplicity, allow tests to set the internal state values for this mock class
    // General
    UINT m_NodeCount; // Simulated number of computing nodes

    // 0: Options
    bool m_D3D12OptionsAvailable = true;
    BOOL m_DoublePrecisionFloatShaderOps = false;
    BOOL m_OutputMergerLogicOp = false;
    D3D12_SHADER_MIN_PRECISION_SUPPORT m_ShaderMinPrecisionSupport10Bit = D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE;
    D3D12_SHADER_MIN_PRECISION_SUPPORT m_ShaderMinPrecisionSupport16Bit = D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE;
    D3D12_TILED_RESOURCES_TIER m_TiledResourcesTier = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED;
    D3D12_RESOURCE_BINDING_TIER m_ResourceBindingTier = (D3D12_RESOURCE_BINDING_TIER)0;
    BOOL m_PSSpecifiedStencilRefSupported = false;
    BOOL m_TypedUAVLoadAdditionalFormats = false;
    BOOL m_ROVsSupported = false;
    D3D12_CONSERVATIVE_RASTERIZATION_TIER m_ConservativeRasterizationTier = D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED;
    UINT m_MaxGPUVirtualAddressBitsPerResource = 0;
    BOOL m_StandardSwizzle64KBSupported = false;
    D3D12_CROSS_NODE_SHARING_TIER m_CrossNodeSharingTier = D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED;
    BOOL m_CrossAdapterRowMajorTextureSupported = false;
    BOOL m_VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation = false;
    D3D12_RESOURCE_HEAP_TIER m_ResourceHeapTier = (D3D12_RESOURCE_HEAP_TIER)0;

    // 1: Architecture & 16: Architecture1
    bool m_ArchitectureSucceed = true;
    bool m_Architecture1Available = false; // Mock the case where Architecture1 is not supported
    std::vector<BOOL> m_TileBasedRenderer;
    std::vector<BOOL> m_UMA;
    std::vector<BOOL> m_CacheCoherentUMA;
    std::vector<BOOL> m_IsolatedMMU;

    // 2: Feature Levels
    bool m_FeatureLevelsAvailable = true;
    D3D_FEATURE_LEVEL m_FeatureLevel = D3D_FEATURE_LEVEL_12_0; // Set higher to allow other tests to pass correctly

    // 3: Feature Format Support
    // Forwarding call only. Make sure that the input parameters are correctly forwarded
    bool m_FormatSupportAvailable = true;
    DXGI_FORMAT m_FormatReceived;
    D3D12_FORMAT_SUPPORT1 m_FormatSupport1 = D3D12_FORMAT_SUPPORT1_NONE;
    D3D12_FORMAT_SUPPORT2 m_FormatSupport2 = D3D12_FORMAT_SUPPORT2_NONE;

    // 4: Multisample Quality Levels
    bool m_MultisampleQualityLevelsSucceed = true;
    UINT m_SampleCountReceived;
    D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS m_MultisampleQualityLevelFlagsReceived;
    UINT m_NumQualityLevels = 0;

    // 5: Format Info
    bool m_DXGIFormatSupported = true;
    UINT m_PlaneCount = 0;

    // 6: GPU Virtual Address Support
    bool m_GPUVASupportAvailable = true;
    UINT m_MaxGPUVirtualAddressBitsPerProcess = 0;

    // 7: Shader Model
    D3D_SHADER_MODEL m_HighestSupportedShaderModel = D3D_SHADER_MODEL_5_1;

    // 8: Options1
    bool m_Options1Available = true;
    bool m_WaveOpsSupported = false;
    UINT m_WaveLaneCountMin = 0;
    UINT m_WaveLaneCountMax = 0;
    UINT m_TotalLaneCount = 0;
    bool m_ExpandedComputeResourceStates = false;
    bool m_Int64ShaderOpsSupported = false;

    // 10: Protected Resource Session Support
    bool m_ProtectedResourceSessionAvailable = true;
    bool m_ContentProtectionSupported = true;
    std::vector<D3D12_PROTECTED_RESOURCE_SESSION_SUPPORT_FLAGS> m_ProtectedResourceSessionSupport;

    // 12: Root Signature
    bool m_RootSignatureAvailable = true;
    D3D_ROOT_SIGNATURE_VERSION m_RootSignatureHighestVersion = (D3D_ROOT_SIGNATURE_VERSION)0;

    // 18: D3D12 Options2
    bool m_Options2Available = true;
    bool m_DepthBoundsTestSupport = false;
    D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER m_ProgrammableSamplePositionsTier = D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED;

    // 19: Shader Cache
    bool m_ShaderCacheAvailable = true;
    D3D12_SHADER_CACHE_SUPPORT_FLAGS m_ShaderCacheSupportFlags = D3D12_SHADER_CACHE_SUPPORT_NONE; // Lazy implementation

    // 20: Command Queue Priority
    bool m_CommandQueuePriorityAvailable = true;
    bool m_GlobalRealtimeCommandQueueSupport = false;

    // 21: Options3
    bool m_Options3Available = true;
    bool m_CopyQueueTimestampQueriesSupported = false;
    bool m_CastingFullyTypedFormatsSupported = false;
    D3D12_COMMAND_LIST_SUPPORT_FLAGS m_GetCachedWriteBufferImmediateSupportFlags = D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE;
    D3D12_VIEW_INSTANCING_TIER m_ViewInstancingTier = D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
    bool m_BarycentricsSupported = false;

    // 22: Existing Heaps
    bool m_ExistingHeapsAvailable = true;
    bool m_ExistingHeapCaps = false;

    // 23: Options4
    bool m_Options4Available = true;
    bool m_MSAA64KBAlignedTextureSupported = false;
    D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER m_SharedResourceCompatibilityTier = D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_0;
    bool m_Native16BitShaderOpsSupported = false;

    // 24: Serialization
    bool m_SerializationAvailable = true;
    std::vector<D3D12_HEAP_SERIALIZATION_TIER> m_HeapSerializationTier;

    // 25: Cross Node
    bool m_CrossNodeAvailable = true;
    bool m_AtomicShaderInstructions = false;

    // 27: Options5
    bool m_Options5Available = true;
    bool m_SRVOnlyTiledResourceTier3 = false;
    D3D12_RENDER_PASS_TIER m_RenderPassesTier = D3D12_RENDER_PASS_TIER_0;
    D3D12_RAYTRACING_TIER m_RaytracingTier = D3D12_RAYTRACING_TIER_NOT_SUPPORTED;

    // 28: Displayable
    bool m_DisplayableAvailable = true;
    bool m_DisplayableTexture = false;
    // SharedResourceCompatibilityTier is located in Options4

    // 30: Options6
    bool m_Options6Available = true;
    bool m_AdditionalShadingRatesSupported = false;
    bool m_PerPrimitiveShadingRateSupportedWithViewportIndexing = false;
    D3D12_VARIABLE_SHADING_RATE_TIER m_VariableShadingRateTier = D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
    UINT m_ShadingRateImageTileSize = 0;
    bool m_BackgroundProcessingSupported = false;

    // 31: Query Meta Command
    bool m_QueryMetaCommandAvailable = true;
    GUID m_CommandID = {};
    UINT m_NodeMask = 0;
    const void* m_pQueryInputData = nullptr;
    SIZE_T m_QueryInputDataSizeInBytes = 0;
    void* m_pQueryOutputData = nullptr;
    SIZE_T m_QueryOutputDataSizeInBytes = 0;

    // 32: Options7
    bool m_Options7Available = true;
    D3D12_MESH_SHADER_TIER m_MeshShaderTier = D3D12_MESH_SHADER_TIER_NOT_SUPPORTED;
    D3D12_SAMPLER_FEEDBACK_TIER m_SamplerFeedbackTier = D3D12_SAMPLER_FEEDBACK_TIER_NOT_SUPPORTED;

    // 33: Protected Resource Session Type Count
    bool m_ProtectedResourceSessionTypeCountAvailable = true;
    std::vector<UINT> m_ProtectedResourceSessionTypeCount;

    // 34: Protected Resource Session Types
    bool m_ProtectedResourceSessionTypesAvailable = true;
    std::vector<std::vector<GUID>> m_ProtectedResourceSessionTypes;

    // 36: Options8
    bool m_Options8Available = true;
    bool m_UnalignedBlockTexturesSupported = false;

    // 37: Options9
    bool m_Options9Available = true;
    bool m_MeshShaderPipelineStatsSupported = false;
    bool m_MeshShaderSupportsFullRangeRenderTargetArrayIndex = false;
    bool m_AtomicInt64OnTypedResourceSupported = false;
    bool m_AtomicInt64OnGroupSharedSupported = false;
    bool m_DerivativesInMeshAndAmplificationShadersSupported = false;
    D3D12_WAVE_MMA_TIER m_WaveMMATier = D3D12_WAVE_MMA_TIER_NOT_SUPPORTED;

    // 39: Options10
    bool m_Options10Available = true;
    bool m_VariableRateShadingSumCombinerSupported = false;
    bool m_MeshShaderPerPrimitiveShadingRateSupported = false;

    // 40: Options11
    bool m_Options11Available = true;
    bool m_AtomicInt64OnDescriptorHeapResourceSupported = false;

    // 41: Options12
    bool m_Options12Available = true;
    D3D12_TRI_STATE m_MSPrimitivesPipelineStatisticIncludesCulledPrimitives = D3D12_TRI_STATE_UNKNOWN;
    bool m_EnhancedBarriersSupported = false;
};

#endif