Fer*_*Fer 1 resize directx-11 direct3d11 uwp
当我的窗口发生变化时,我正在努力调整缓冲区的大小。除了这一部分之外,该过程的每个部分都按预期工作。
// in MyGame.h -
private:
ComPtr<ID3D11RenderTargetView> gRenderTarget;
...
// handle resize method:
void MyGame::UpdateBackbufferSize(UINT pWidth, UINT pHeight) {
/* 1. Clear render targets from device context */
gDeviceContext->OMSetRenderTargets(0, 0, 0);
/* 2. Release Rendering Target */
gRenderTarget->Release(); // ! CANNOT ACCESS client.h private Release()
/* 3. Resize buffer */
gSwapchain->ResizeBuffers(
0,
pWidth,
pHeight,
DXGI_FORMAT_UNKNOWN,
0
);
/* 4. Reset the buffer as target view */
ComPtr<ID3D11Texture2D> backBuffer;
gSwapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), &backBuffer);
gDevice->CreateRenderTargetView(backBuffer.Get(), nullptr, &gRenderTarget);
backBuffer.Get()->Release();
/* 5. Set the new render target
gDeviceContext->OMSetRenderTargets(1, gRenderTarget.GetAddressOf(), nullptr);
/* 6. Reset view port */
D3D11_VIEWPORT vp = { 0 };
vp.Width = pWidth;
vp.Height = pHeight;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
gDeviceContext->RSSetViewports(1, &vp);
}
Run Code Online (Sandbox Code Playgroud)
如果我尝试
gRenderTarget->Release();
Run Code Online (Sandbox Code Playgroud)
我会收到“无法从“RemoveIUnknownBase”访问 Release()...无法访问...
我也尝试过
ID3D11RenderTargetView* rtv = gRenderTarget.Get();
rtv->Release();
Run Code Online (Sandbox Code Playgroud)
但我遇到了某种访问冲突......我不明白。
这就是正在发生的事情:
启动后立即:
调整大小后:
查看端口发生变化,但缓冲区保持不变。
除了@Chuck建议之外,我还得到了一个用于后台缓冲区的全局ComPtr,以便在其上调用.Reset(),以防万一,在gRenderTarget上调用.Reset()之后立即调用。
谢谢。
首先,如果您启用了Direct3D 调试设备,您将收到一条调试器消息,指出问题在于您的后台缓冲区上有未完成的引用计数。它们应该全部被释放,以便在调整交换链大小之前计数为零。
其次,您无法检查返回它们的 COM 函数的 HRESULT。其中一个失败了,并且您没有检查它,因此后面的指针为空。
始终检查 HRESULT 值!如果忽略它是安全的,该函数将返回 void。您可以使用SUCCEEDED宏来执行此操作FAILED,或者对于启用了 C++ 异常处理 ( /EHsc) 的程序中的致命快速失败(如通用 Windows 应用程序中的典型情况),您可以使用DX::ThrowIfFailed等帮助程序。另请参见COM 中的错误处理。
第三,您遵循最佳实践,使用智能指针而不是手动调用的原始指针Release。Microsoft::WRL::ComPtr是通用 Windows 应用程序的自然选择。然而,你从来没有打电话Release给他们,你当然也永远不会打电话给他们Get()->Release。如果您想手动释放 ComPtr,请使用Reset.
问题的真正核心是gDeviceContext->OMSetRenderTargets(0, 0, 0);不解除渲染目标的绑定。该函数采用渲染目标数组来处理多个渲染目标。您基本上是在告诉它“将深度模板视图更改为空,但保留渲染目标”。
因此,考虑到这一点,您可能想要更多类似的东西:
/* 1. Clear render targets from device context */
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews [] = { nullptr };
gDeviceContext->OMSetRenderTargets(_countof(nullViews), nullViews, nullptr);
/* 2. Release Rendering Target */
gRenderTarget.Reset();
gDeviceContext->Flush();
/* 3. Resize buffer */
HRESULT hr = gSwapchain->ResizeBuffers(
0,
pWidth,
pHeight,
DXGI_FORMAT_UNKNOWN,
0
);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
// If the device was removed for any reason, a new device and swap chain will need to be created.
// TODO!
}
else
{
DX::ThrowIfFailed(hr);
}
/* 4. Reset the buffer as target view */
ComPtr<ID3D11Texture2D> backBuffer;
DX::ThrowIfFailed(gSwapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), &backBuffer));
DX::ThrowIfFailed(gDevice->CreateRenderTargetView(backBuffer.Get(), nullptr, &gRenderTarget));
/* 5. Set the new render target
gDeviceContext->OMSetRenderTargets(1, gRenderTarget.GetAddressOf(), nullptr);
/* 6. Reset view port */
D3D11_VIEWPORT vp = { 0 };
vp.Width = pWidth;
vp.Height = pHeight;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
gDeviceContext->RSSetViewports(1, &vp);
Run Code Online (Sandbox Code Playgroud)
我建议您查看Direct3D UWP Game VS 模板和DirectX Tool Kit 教程。
Flush请注意,您需要在包含 Direct2D 等引用之前释放所有对后台缓冲区的使用。
| 归档时间: |
|
| 查看次数: |
2214 次 |
| 最近记录: |