D3D11.1调整窗口大小时内存不足?

时间:2013-02-14 00:53:57

标签: visual-c++ out-of-memory directx-11

我正在努力解决这个问题;使用D3D11.1和标准的Win32桌面窗口,我在调整窗口大小时出现了内存错误,但仅在手动调整大小几秒钟时才会出现内存错误。最大化工作正常,并且非常快速地调整大小工作正常。就好像在手动调整大小期间不断分配某些东西,但我无法弄清楚它是什么。

LRESULT CALLBACK ProcessWindow(HWND hWnd, uint32 nMessage, WPARAM wParam, LPARAM lParam)
{
switch(nMessage)
{
case WM_SIZE:
    OnResize();
    return DefWindowProc(hWnd, nMessage, wParam, lParam);
}

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



void OnResize()
{
    ResizeSwapChain();
    ResetRenderTargets();
    ResetDepthStencil();
}



void ResizeSwapChain()
{
if(m_pD3DSwapChain)
{
    m_D3DDepthStencilView.ReleaseAndGetAddressOf();
    m_pD3DRenderTarget.ReleaseAndGetAddressOf();

    //THE SWAP CHAIN ALREADY EXISTS, RESIZE IT
    DXErrorOnFail(m_pD3DSwapChain->ResizeBuffers(nBufferCount, 0, 0, SwapChainFormat, 0));
} 
}



bool ResetRenderTargets()
{
ComPtr<ID3D11Texture2D> B;
DXErrorOnFail(m_pD3DSwapChain->GetBuffer(0, IID_PPV_ARGS(&B)));

DXErrorOnFail(m_pD3DDevice->CreateRenderTargetView(B.Get(), nullptr, &m_pD3DRenderTarget));

B.ReleaseAndGetAddressOf();

if(!m_pD3DRenderTarget)
{
    return false;
}

return true;
}



bool ResetDepthStencil()
{
D3D11_TEXTURE2D_DESC BBD;

ComPtr<ID3D11Texture2D> B;
DXErrorOnFail(m_pD3DSwapChain->GetBuffer(0, IID_PPV_ARGS(&B)));

B->GetDesc(&BBD);

D3D11_TEXTURE2D_DESC DSD; //DEPTH STENCIL DESC
memset(&DSD, 0, sizeof(D3D11_TEXTURE2D_DESC));

DSD.Width               = BBD.Width;
DSD.Height              = BBD.Height;
DSD.MipLevels           = 1;
DSD.ArraySize           = 1;
DSD.Format              = DXGI_FORMAT_D24_UNORM_S8_UINT;
DSD.SampleDesc.Count    = 1;
DSD.SampleDesc.Quality  = 0;
DSD.Usage               = D3D11_USAGE_DEFAULT;
DSD.BindFlags           = D3D11_BIND_DEPTH_STENCIL;
DSD.CPUAccessFlags      = 0;
DSD.MiscFlags           = 0;

ComPtr<ID3D11Texture2D> DS;
DXErrorOnFail(m_pD3DDevice->CreateTexture2D(&DSD, nullptr, &DS));

D3D11_DEPTH_STENCIL_VIEW_DESC DVD;
memset(&DVD, 0, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));

DVD.Format              = DSD.Format;
DVD.ViewDimension       = D3D11_DSV_DIMENSION_TEXTURE2D;
DVD.Flags               = 0;
DVD.Texture2D.MipSlice  = 0;

DXErrorOnFail(m_pD3DDevice->CreateDepthStencilView(DS.Get(), &DVD, &m_D3DDepthStencilView));

B.ReleaseAndGetAddressOf();
DS.ReleaseAndGetAddressOf();

if(!m_D3DDepthStencilView)
{
    return false;
}

return true;
}


bool ResetViewports()
{
D3D11_TEXTURE2D_DESC BBD; //BACK BUFFER DESC
memset(&BBD, 0, sizeof(D3D11_TEXTURE2D_DESC));

ComPtr<ID3D11Texture2D> B;
DXErrorOnFail(m_pD3DSwapChain->GetBuffer(0, IID_PPV_ARGS(&B)));

B->GetDesc(&BBD);

D3D11_VIEWPORT V;
V.TopLeftX = 0.0f;
V.TopLeftY = 0.0f;
V.Width    = static_cast<float32>(BBD.Width);
V.Height   = static_cast<float32>(BBD.Height);
V.MinDepth = D3D11_MIN_DEPTH;
V.MaxDepth = D3D11_MAX_DEPTH;

m_pD3DDeviceContext->RSSetViewports(1, &V);

return true;
}

我非常感谢您的帮助,谢谢。

1 个答案:

答案 0 :(得分:0)

在调整大小期间重新分配不是一个好主意,原因如下:

  • 你会破坏并重建资源很多(在这种情况下,这是一个简单的例子,想想一个具有大量中间纹理的复杂应用程序)。
  • 当您调用ReleaseAndGetAddressOf时,DX不会立即销毁资源,它会在您下次刷新缓冲区时执行此操作,因为在您调整大小时可能无法渲染,上下文将不会被刷新。

一个更清洁的解决方案是使用Begin / EndResize事件。 WM_ENTERSIZEMOVE WM_EXITSIZEMOVE

在输入消息时设置一个标志,并在退出时应用您的更改。