1

我正在尝试实现一个具有超过 1 个后备缓冲区的交换链,但是我在为第零个缓冲区之后的任何缓冲区创建渲染目标视图时遇到了麻烦。

我像这样创建我的交换链:

IDXGIFactory1* idxgiFactory;
// D3D_CALL is just a macro that throws exception with info on error
D3D_CALL(CreateDXGIFactory1(__uuidof(IDXGIFactory1), &idxgiFactory));

DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = BUFFER_COUNT; // currently 2
sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 0;
sd.BufferDesc.RefreshRate.Denominator = 0;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | D3D11_BIND_RENDER_TARGET;
sd.OutputWindow = window.GetHandle(); // wrapper for my window
sd.SampleDesc.Count = 4;
sd.SampleDesc.Quality = 1;
sd.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
sd.Windowed = TRUE;

D3D_CALL(idxgiFactory->CreateSwapChain(
    m_HWDevice, // ptr to ID3D11Device
    &sd,
    &m_HWSwapChain));

到目前为止,它一直在使用具有交换效果 DISCARD 的单帧缓冲区,根据 MSDN,它已经过时并且性能不佳。

创建交换链后,我得到了后备缓冲区并创建如下视图:

// this is called with buffer index from 0 till BUFFER_COUNT - 1
// 'm_RenderTarget' is simply an array of ID3D11Texture2D, where the size matches BUFFER_COUNT
D3D_CALL(m_HWSwapChain->GetBuffer(bufferIndex, __uuidof(ID3D11Texture2D), (LPVOID*)&m_RenderTarget[bufferIndex]));

// I then attempt to create the RTV like so:
ID3D11RenderTargetView* rtv = NULL;
D3D_CALL(m_HWDevice->CreateRenderTargetView(m_RenderTarget[bufferIndex], NULL, &rtv));

关于创建渲染目标视图的代码适用于“bufferIndex”0,但在索引 1 上出现以下错误:

D3D11 ERROR: ID3D11Device::CreateRenderTargetView: A render-target view cannot be made on a read-only resource. (Perhaps a DXGI_SWAP_CHAIN buffer other than buffer 0?) [ STATE_CREATION ERROR #135: CREATERENDERTARGETVIEW_INVALIDDESC]

我假设我必须使用 D3D11_RENDER_TARGET_VIEW_DESC 并在里面填充 D3D11_BUFFER_RTV 结构?不知道如何设置它,也找不到任何示例。

我试图用这样的描述符创建 RTV:

D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
ZeroMemory(&rtvDesc, sizeof(rtvDesc));
rtvDesc.Buffer.NumElements = BUFFER_COUNT;
rtvDesc.Buffer.FirstElement = 0;
rtvDesc.Buffer.ElementOffset = size.x * size.y * 4; // dimensions of my back buffer * 4 bytes per pixel
rtvDesc.Buffer.ElementWidth = 4; // 4 bytes per pixel in DXGI_FORMAT_B8G8R8A8_UNORM

这给出了错误:

D3D11 ERROR: ID3D11Device::CreateRenderTargetView: The ViewDimension in the View Desc incompatible with the type of the Resource. [ STATE_CREATION ERROR #129: CREATESHADERRESOURCEVIEW_INVALIDRESOURCE]

不知道我在这里缺少什么。

4

1 回答 1

1

我有点误解这是如何工作的。我缺少的一些关键信息:

*

如果交换链的交换效果是 DXGI_SWAP_EFFECT_SEQUENTIAL 或 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,则只能读取和写入交换链的零索引缓冲区。索引大于零的交换链缓冲区只能从中读取;因此,如果您为此类缓冲区调用 IDXGIResource::GetUsage 方法,它们将设置 DXGI_USAGE_READ_ONLY 标志。

来源:https ://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-getbuffer

另一个关键点是 dx11 自动管理帧缓冲区。我试图获取所有帧缓冲区并相应地写入它们。显然我只需要第 0 个帧缓冲区一次,创建一个视图并只关心它。其余的将由 dx11 在幕后自动管理。dx12 并非如此。

相关问题:RenderTargetView 指向的后缓冲区是否会在 Present 之后自动更改?

于 2022-02-17T09:35:53.057 回答