Home > Back-end >  D3D11CreateDeviceAndSwapChain Fails With E_ACCESSDENIED When Using Same HWND
D3D11CreateDeviceAndSwapChain Fails With E_ACCESSDENIED When Using Same HWND

Time:03-18

If I create a window and pass the HWND to D3D11CreateDeviceAndSwapChain, it works. However, after I release the device, context, swapchain, etc and try to repeat the process using the same HWND, D3D11CreateDeviceAndSwapChain fails with E_ACCESSDENIED. This tells me something must be holding onto the HWND, but what? I release all my global variables in the destructor of the class. Anyone have an idea what the problem is?

~decoder()
    {
        m_VertexShader->Release();
        m_VertexShader = nullptr;

        m_PixelShader->Release();
        m_PixelShader = nullptr;

        m_InputLayout->Release();
        m_InputLayout = nullptr;

        device->Release();
        device = nullptr;

        context->Release();
        context = nullptr;

        swapchain->Release();
        swapchain = nullptr;

        rendertargetview->Release();
        rendertargetview = nullptr;

        m_SamplerLinear->Release();
        m_SamplerLinear = nullptr;

        HRESULT hr = S_OK;
        hr = decoder_transform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, NULL);
        hr = decoder_transform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, NULL);
        hr = decoder_transform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, NULL);

        decoder_transform.Release();
        color_transform.Release();

        hr = MFShutdown();
    }
HRESULT init_dxgi(ID3D11Device* out_device, ID3D11DeviceContext* in_context)
    {
        HRESULT hr = S_OK;

        // create a struct to hold information about the swap chain
        DXGI_SWAP_CHAIN_DESC scd;

        // clear out the struct for use
        ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

        // fill the swap chain description struct
        scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
        scd.BufferCount = 2;                                    // one back buffer
        scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;     // use 32-bit color
        scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;      // how swap chain is to be used
        scd.SampleDesc.Count = 1;                               // how many multisamples
        scd.SampleDesc.Quality = 0;
        scd.OutputWindow = hWnd;                                // the window to be used                           
        scd.Windowed = TRUE;                                    // windowed/full-screen mode

        DWORD flags = 0;
#if !defined(NDEBUG)
        flags |= D3D11_CREATE_DEVICE_DEBUG; // https://stackoverflow.com/a/19122012/868014
#endif

        // create a device, device context and swap chain using the information in the scd struct
        hr = D3D11CreateDeviceAndSwapChain(NULL,
            D3D_DRIVER_TYPE_HARDWARE,
            NULL,
            flags,
            NULL,
            NULL,
            D3D11_SDK_VERSION,
            &scd,
            &swapchain,
            &device,
            NULL,
            &context);

        CComQIPtr<ID3D10Multithread>(device)->SetMultithreadProtected(TRUE); // https://stackoverflow.com/a/59760070/868014

        // get the address of the back buffer
        swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

        // use the back buffer address to create the render target
        device->CreateRenderTargetView(pBackBuffer, NULL, &rendertargetview);

        pBackBuffer->Release();

        // set the render target as the back buffer
        context->OMSetRenderTargets(1, &rendertargetview, NULL);

        // Set the viewport
        D3D11_VIEWPORT viewport;
        ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

        viewport.TopLeftX = 0;
        viewport.TopLeftY = 0;
        viewport.Width = 1280;
        viewport.Height = 720;

        context->RSSetViewports(1, &viewport);

        // Create the sample state
        D3D11_SAMPLER_DESC SampDesc;
        RtlZeroMemory(&SampDesc, sizeof(SampDesc));
        SampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
        SampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
        SampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
        SampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
        SampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
        SampDesc.MinLOD = 0;
        SampDesc.MaxLOD = D3D11_FLOAT32_MAX;

        if (FAILED(hr = device->CreateSamplerState(&SampDesc, &m_SamplerLinear)))
            return hr;

        std::cout << "- Initialized DXGI" << std::endl;

        return hr;
    }

CodePudding user response:

While D3D11CreateDeviceAbdSwapChain does not mention why this is happening in the documentation, it is essentially just a wrapper around creating a D3D11Device and swap chain. The documentation for IDXGIFactory2::CreateSwapChainForHwnd does go into detail on why this is happening.

Because you can associate only one flip presentation model swap chain at a time with an HWND, the Microsoft Direct3D 11 policy of deferring the destruction of objects can cause problems if you attempt to destroy a flip presentation model swap chain and replace it with another swap chain. For more info about this situation, see Deferred Destruction Issues with Flip Presentation Swap Chains.

The documentation regarding Deferred Destruction Issues with Flip Presentation Swap Chains advises calling ID3D11DeviceContext::ClearState followed by ID3D11DeviceContext::Flush.

However, if an application must actually destroy an old swap chain and create a new swap chain, the application must force the destruction of all objects that the application freed. To force the destruction, call ID3D11DeviceContext::ClearState (or otherwise ensure no views are bound to pipeline state), and then call Flush on the immediate context. You must force destruction before you call IDXGIFactory2::CreateSwapChainForHwnd, IDXGIFactory2::CreateSwapChainForCoreWindow, or IDXGIFactory2::CreateSwapChainForComposition again to create a new swap chain.

  • Related