调整窗口大小后交换渲染缓冲区会导致问题

Posted

技术标签:

【中文标题】调整窗口大小后交换渲染缓冲区会导致问题【英文标题】:Swapping render buffers after resizing window causes problems 【发布时间】:2015-03-06 15:34:01 【问题描述】:

我正在尝试处理窗口大小调整消息WM_SIZE。 当我收到它时:

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    switch (message)
    
    case WM_SIZE:
    
        int nWidth = LOWORD(lParam);
        int nHeight = HIWORD(lParam);
        renderer->Resize(nWidth, nHeight);
        return 1;
        break;
    
    case WM_DESTROY:
    
        PostQuitMessage(0);
        return 0;
     break;
    

    return DefWindowProc(hWnd, message, wParam, lParam);

我使用新的高度和宽度参数来重新创建渲染目标视口并调整缓冲区的大小:

void Renderer::Resize(int w, int h)

    m_devContext->OMSetRenderTargets(0, 0, 0);

    m_renderTargetView->Release();

    HRESULT hr;
    hr = m_swapchain->ResizeBuffers(1, w, h, DXGI_FORMAT_UNKNOWN, 0);

    ID3D11Texture2D* pBuffer;
    hr = m_swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D),
        (void**)&pBuffer);

    hr = m_device->CreateRenderTargetView(pBuffer, NULL,
        &m_renderTargetView);

    pBuffer->Release();

    m_devContext->OMSetRenderTargets(1, &m_renderTargetView, NULL);

    // Set up the viewport.
    D3D11_VIEWPORT vp;
    vp.Width = w;
    vp.Height = h;
    m_devContext->RSSetViewports(1, &vp);


尽管如此,在 resize 事件之后渲染的第一帧会导致错误:

void Renderer::Render() const


    m_devContext->ClearRenderTargetView(m_renderTargetView, m_clearCol);
    HRESULT ret = m_swapchain->Present(0, 0); //triggered exception here, only the first frame after resize

Visual Studio 弹出错误是:

ApplicationName.exe 已触发异常

。没有其他信息,也没有可捕获的异常。根据网络上的一些研究,我猜这可能与一些未释放的资源或堆损坏有关。

有什么提示吗?我究竟做错了什么?


编辑:我错过了控制台输出。以下是确认这是堆更正问题的消息:

HEAP: Free Heap block 44aa468 在被释放后修改为 44aa4e8 application.exe 已触发断点。

我遵循的文档来自MSDN article。

【问题讨论】:

你在使用first-chance exceptions吗?这些通常是良性的。 @MooseBoys: 不..似乎我在某处搞砸了堆..仍然不知道在哪里,但这与调整窗口大小有关。 在黑暗中射击:检查pBuffer 的引用计数(打印Release() 调用的结果)?如果这是问题所在,我不知道为什么;需要对 DirectX一无所知的人来回答。 你在m_swapchain->ResizeBuffer() 通话后检查过小时吗?是S_OK吗? 同样在每个hr = somefunction() 之后放入代码if(FAILED(hr))return 1; 在directx 中不检查directx 函数的返回值是错误的方法,代码可能在任何地方都失败,你不知道在哪里 【参考方案1】:

不要返回 1,在您的 WM_SIZE 消息中使用此 return DefWindowProc(blah..)。完成调整大小说明后,windows 需要自行处理

【讨论】:

【参考方案2】:

不要在WindowProc()

中实现Resizing代码

代替这个,在渲染代码中实现它:

void Renderer::Render() const

    if (Resizingoccur) // In WindowProc() When the Resizing happen change the value of Resizingoccur to be true
        
            Resize(nWidth, nHeight);
            Resizingoccur = false;
        

    m_devContext->ClearRenderTargetView(m_renderTargetView, m_clearCol);
    HRESULT ret = m_swapchain->Present(0, 0); 

【讨论】:

渲染代码是否与 WindowProc() 在同一线程中工作? 我试图重现同样的错误,但你的代码仍然在我身边工作,所以只需在释放渲染目标指针后尝试使其无效 m_renderTargetView= NULL;

以上是关于调整窗口大小后交换渲染缓冲区会导致问题的主要内容,如果未能解决你的问题,请参考以下文章

调整 OpenGL 窗口的大小会导致它崩溃

当 QML 滚动条位于底部并且窗口高度被调整大小时,它不会更新

OpenGL窗口大小渲染问题

调整窗口大小时是不是可以完全消除闪烁?

重新渲染 HTML 元素定位在 Javascript 幻灯片动画内的窗口调整大小

MFC 网格是绝对布局,在调整窗口大小时会被剪裁