HRESULT DX12Framework::CreateDeviceDependentStateInternal()

in TechniqueDemos/D3D12MemoryManagement/src/Framework.cpp [334:687]


HRESULT DX12Framework::CreateDeviceDependentStateInternal()
{
    HRESULT hr;

    {
        //
        // Have the user select the desired graphics adapter.
        //
        IDXGIAdapter* pTempAdapter;
        UINT AdapterOrdinal = 0;

        printf("Available Adapters:\n");
        while (m_pDXGIFactory->EnumAdapters(AdapterOrdinal, &pTempAdapter) != DXGI_ERROR_NOT_FOUND)
        {
            DXGI_ADAPTER_DESC Desc;
            pTempAdapter->GetDesc(&Desc);

            printf("  [%d] %ls\n", AdapterOrdinal, Desc.Description);

            pTempAdapter->Release();
            ++AdapterOrdinal;
        }

        for (;;)
        {
            printf("\nSelect Adapter: ");

            AdapterOrdinal = m_NewAdapterIndex;
            if (AdapterOrdinal == 0xFFFFFFFF)
            {
                if (scanf_s("%d", &AdapterOrdinal) == 0)
                {
                    //
                    // If the user did not specify valid input, just use adapter 0.
                    //
                    AdapterOrdinal = 0;
                }
            }

            hr = m_pDXGIFactory->EnumAdapters(AdapterOrdinal, &pTempAdapter);
            if (hr == DXGI_ERROR_NOT_FOUND)
            {
                LOG_WARNING("Invalid adapter ordinal");
                continue;
            }

            hr = pTempAdapter->QueryInterface(&m_pDXGIAdapter);
            pTempAdapter->Release();

            if (FAILED(hr))
            {
                LOG_ERROR("Failed to query IDXGIAdapter3 interface from selected adapter.");
                return hr;
            }

            break;
        }
    }

    //
    // Obtain the default video memory information for the local and non-local segment groups.
    //
    hr = m_pDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &m_LocalVideoMemoryInfo);
    if (FAILED(hr))
    {
        LOG_ERROR("Failed to query initial video memory info for local segment group");
        return hr;
    }

    hr = m_pDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &m_NonLocalVideoMemoryInfo);
    if (FAILED(hr))
    {
        LOG_ERROR("Failed to query initial video memory info for non-local segment group");
        return hr;
    }

    hr = D3D12CreateDevice(m_pDXGIAdapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_pDevice));
    if (FAILED(hr))
    {
        LOG_ERROR("Failed to create D3D12 device, hr=0x%.8x", hr);
        return hr;
    }

#if _DEBUG
    ID3D12InfoQueue* pInfoQueue = nullptr;
    if (SUCCEEDED(m_pDevice->QueryInterface(IID_PPV_ARGS(&pInfoQueue))))
    {
        // Suppress whole categories of messages.
        //D3D12_MESSAGE_CATEGORY Categories[] = {};

        // Suppress messages based on their severity level.
        D3D12_MESSAGE_SEVERITY Severities[] =
        {
            D3D12_MESSAGE_SEVERITY_INFO
        };

        // Suppress individual messages by their ID.
        D3D12_MESSAGE_ID DenyIds[] =
        {
            // The 11On12 implementation does not use optimized clearing yet.
            D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE
        };

        D3D12_INFO_QUEUE_FILTER NewFilter = {};
        //NewFilter.DenyList.NumCategories = _countof(Categories);
        //NewFilter.DenyList.pCategoryList = Categories;
        NewFilter.DenyList.NumSeverities = _countof(Severities);
        NewFilter.DenyList.pSeverityList = Severities;
        NewFilter.DenyList.NumIDs = _countof(DenyIds);
        NewFilter.DenyList.pIDList = DenyIds;

        pInfoQueue->PushStorageFilter(&NewFilter);
        pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
        pInfoQueue->Release();
    }
#endif

    //
    // Cache the descriptor sizes.
    //
    m_DescriptorInfo.RtvDescriptorSize = m_pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
    m_DescriptorInfo.SamplerDescriptorSize = m_pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
    m_DescriptorInfo.SrvUavCbvDescriptorSize = m_pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

    hr = QueryCaps();
    if (FAILED(hr))
    {
        LOG_WARNING("Failed to query device caps");
        return hr;
    }

    hr = m_RenderContext.CreateDeviceDependentState(SWAPCHAIN_BUFFER_COUNT);
    if (FAILED(hr))
    {
        LOG_WARNING("Failed to initialize render context");
        return hr;
    }

    hr = m_PagingContext.CreateDeviceDependentState();
    if (FAILED(hr))
    {
        LOG_WARNING("Failed to initialize paging context");
        return hr;
    }

    hr = m_TextureShader.CreateDeviceDependentState(m_pDevice, L"Assets\\Shaders\\Texture.hlsl");
    if (FAILED(hr))
    {
        LOG_WARNING("Failed to initialize texture shader");
        return hr;
    }

    hr = m_ColorShader.CreateDeviceDependentState(m_pDevice, L"Assets\\Shaders\\Color.hlsl");
    if (FAILED(hr))
    {
        LOG_WARNING("Failed to initialize color shader");
        return hr;
    }

    //
    // Create a basic Flip-Discard swapchain.
    //
    DXGI_SWAP_CHAIN_DESC1 SwapChainDesc = {};
    SwapChainDesc.BufferCount = SWAPCHAIN_BUFFER_COUNT;
    SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    SwapChainDesc.SampleDesc.Count = 1;
    SwapChainDesc.Format = SWAPCHAIN_BACK_BUFFER_FORMAT;
    SwapChainDesc.Height = m_WindowHeight;
    SwapChainDesc.Scaling = DXGI_SCALING_NONE;
    SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    SwapChainDesc.Width = m_WindowWidth;
    SwapChainDesc.Flags = 0;

    //
    // The swap chain is created as an IDXGISwapChain1 interface, but we then query
    // the IDXGISwapchain3 interface from it.
    //
    IDXGISwapChain1* pSwapChain;
    hr = m_pDXGIFactory->CreateSwapChainForHwnd(m_RenderContext.GetCommandQueue(), m_Hwnd, &SwapChainDesc, nullptr, nullptr, &pSwapChain);
    if (FAILED(hr))
    {
        LOG_ERROR("Failed to create swap chain for hwnd, hr=0x%.8x", hr);
        return hr;
    }

    hr = pSwapChain->QueryInterface(&m_pDXGISwapChain);
    pSwapChain->Release();
    if (FAILED(hr))
    {
        LOG_ERROR("Failed to query IDXGISwapChain3 interface, hr=0x%.8x", hr);
        return hr;
    }

    //
    // Create RTV heap for render target.
    //
    {
        D3D12_DESCRIPTOR_HEAP_DESC HeapDesc = {};

        HeapDesc.NumDescriptors = SWAPCHAIN_BUFFER_COUNT;
        HeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
        HeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
        hr = m_pDevice->CreateDescriptorHeap(&HeapDesc, IID_PPV_ARGS(&m_pRtvHeap));
        if (FAILED(hr))
        {
            LOG_ERROR("Failed to create RTV descriptor heap, hr=0x%.8x", hr);
            return hr;
        }
    }

    //
    // If enabled, create the shared staging resource used for transfers.
    //
    if (m_bUseSharedStagingSurface)
    {
        hr = m_pDevice->CreateCommittedResource(
            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
            D3D12_HEAP_FLAG_NONE,
            &CD3DX12_RESOURCE_DESC::Buffer(MAX_TRANSFER_SIZE),
            D3D12_RESOURCE_STATE_GENERIC_READ,
            nullptr,
            IID_PPV_ARGS(&m_pStagingSurface));
        if (FAILED(hr))
        {
            LOG_ERROR("Failed to create staging upload buffer, hr=0x%.8x", hr);
            return hr;
        }

        CD3DX12_RANGE readRange(0, 0);
        hr = m_pStagingSurface->Map(0, &readRange, &m_pStagingSurfaceData);
        if (FAILED(hr))
        {
            LOG_ERROR("Failed to map upload buffer data, hr=0x%.8x", hr);
            return hr;
        }
    }

    //
    // Create 11On12 state to enable D2D rendering on D3D12.
    //
    IUnknown* pRenderCommandQueue = m_RenderContext.GetCommandQueue();
    hr = D3D11On12CreateDevice(m_pDevice, D3D11_CREATE_DEVICE_BGRA_SUPPORT, nullptr, 0, &pRenderCommandQueue, 1, 0, &m_p11Device, &m_p11Context, nullptr);
    if (FAILED(hr))
    {
        LOG_ERROR("Failed to create D3D11On12 device, hr=0x%.8x", hr);
        return hr;
    }

    hr = m_p11Device->QueryInterface(&m_p11On12Device);
    if (FAILED(hr))
    {
        LOG_ERROR("Failed to query 11On12 device interface, hr=0x%.8x", hr);
        return hr;
    }

    //
    // Create D2D/DWrite components.
    //
    {
        D2D1_DEVICE_CONTEXT_OPTIONS DeviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
        IDXGIDevice* pDxgiDevice;
        hr = m_p11On12Device->QueryInterface(&pDxgiDevice);
        if (FAILED(hr))
        {
            LOG_ERROR("Failed to query IDXGIDevice interface, hr=0x%.8x", hr);
            return hr;
        }

        hr = m_pD2DFactory->CreateDevice(pDxgiDevice, &m_pD2DDevice);
        pDxgiDevice->Release();
        if (FAILED(hr))
        {
            LOG_ERROR("Failed to create D2D device, hr=0x%.8x", hr);
            return hr;
        }

        hr = m_pD2DDevice->CreateDeviceContext(DeviceOptions, &m_pD2DContext);
        if (FAILED(hr))
        {
            LOG_ERROR("Failed to create D2D context, hr=0x%.8x", hr);
            return hr;
        }
    }

    //
    // Create the resources to enable D2D to access the swap chain.
    //
    hr = CreateSwapChainResources();
    if (FAILED(hr))
    {
        LOG_WARNING("Failed to create swap chain resources");
        return hr;
    }

    //
    // Initialize our paging worker thread. The worker thread will be used for streaming
    // resource mipmaps asynchronously from the rendering thread.
    //
    try
    {
        m_pWorkerThread = new PagingWorkerThread(this);
    }
    catch (std::bad_alloc&)
    {
        LOG_ERROR("Failed to allocate paging worker thread instance");
        return E_OUTOFMEMORY;
    }

    hr = m_pWorkerThread->Init();
    if (FAILED(hr))
    {
        LOG_WARNING("Failed to initialize paging worker thread");
        return hr;
    }

    //
    // If we are reinitializing from a device removed state, the application may have
    // resources already which need to be reinitialized. Do this now.
    //
    {
        LIST_ENTRY* pResourceEntry = m_ResourceListHead.Flink;
        while (pResourceEntry != &m_ResourceListHead)
        {
            Resource* pResource = CONTAINING_RECORD(pResourceEntry, Resource, ListEntry);
            pResourceEntry = pResourceEntry->Flink;

            UINT NumMips;
            UINT Width;
            UINT Height;
            DXGI_FORMAT Format;

            hr = GetResourceInformation(pResource->pDecoder, NumMips, Format, Width, Height);
            if (FAILED(hr))
            {
                LOG_ERROR("Failed to get resource information, hr=0x%.8x", hr);
                return hr;
            }

            hr = CreateResourceDeviceState(pResource, NumMips, Format, Width, Height);
            if (FAILED(hr))
            {
                return hr;
            }
        }
    }

    hr = CreateDeviceDependentState();
    if (FAILED(hr))
    {
        return hr;
    }

    return S_OK;
}