5

フレームごとにバックバッファーのみをクリアする DX12 アプリケーションをセットアップします。

それは本当にベアボーンです:PSOもルートもありません...唯一の特殊性は、新しいフレームを開始する前に、Present()で行われるswapChainを待機することです(msdn waitable swap chain)(フレームレイテンシを1に設定しますまあ、2つのバッファしかありません)。

最初のフレームは正常に機能しますが、すぐに 2 番目のフレームの描画を開始します。もちろん、コマンド アロケーターは、コマンドがまだ GPU で実行されている間にリセットされていると不平を言います。

もちろん、新しいフレームに移動する前に GPU が完了するのを待つようにフェンスを設定することもできますが、これは待機可能なスワップ チェーン オブジェクトの仕事だと思いました。

レンダリング ルーチンは次のとおりです。

if (m_command_allocator->Reset() == E_FAIL) { throw; }

HRESULT res = S_OK;
res = m_command_list->Reset(m_command_allocator.Get(), nullptr);
if (res == E_FAIL || res == E_OUTOFMEMORY) { throw; }

m_command_list->ResourceBarrier(1, 
&CD3DX12_RESOURCE_BARRIER::Transition(m_render_targets[m_frame_index].Get(), 
D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

m_command_list->RSSetViewports(1, &m_screen_viewport);
m_command_list->RSSetScissorRects(1, &m_scissor_rect);
m_command_list->ClearRenderTargetView(get_rtv_handle(), 
DirectX::Colors::BlueViolet, 0, nullptr);
m_command_list->OMSetRenderTargets(1, &get_rtv_handle(), true, nullptr);

m_command_list->ResourceBarrier(1, 
&CD3DX12_RESOURCE_BARRIER::Transition(m_render_targets[m_frame_index].Get(), 
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));

tools::throw_if_failed(m_command_list->Close());
ID3D12CommandList* ppCommandLists[] = { m_command_list.Get() };
m_command_queue->ExecuteCommandLists(_countof(ppCommandLists), 
ppCommandLists);

if (m_swap_chain->Present(1, 0) != S_OK) { throw; }
m_frame_index = m_swap_chain->GetCurrentBackBufferIndex();

スワップチェーンから取得した待機可能なオブジェクトを使用して、このルーチンをループします。

while (WAIT_OBJECT_0 == WaitForSingleObjectEx(waitable_renderer, INFINITE, TRUE) && m_alive == true)
{
    m_graphics.render();
}

そして、待機可能なフラグでスワップチェーンを初期化しました:

DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
swap_chain_desc.BufferCount = s_frame_count;
swap_chain_desc.Width = window_width;
swap_chain_desc.Height = window_height;
swap_chain_desc.Format = m_back_buffer_format;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;

ComPtr<IDXGISwapChain1> swap_chain;
tools::throw_if_failed(
    factory->CreateSwapChainForHwnd(m_command_queue.Get(), window_handle, &swap_chain_desc, nullptr, nullptr, &swap_chain));

swapChain を作成した直後に SetFrameLatency を呼び出します。

ComPtr<IDXGISwapChain2> swap_chain2;
tools::throw_if_failed(m_swap_chain.As(&swap_chain2));

tools::throw_if_failed(swap_chain2->SetMaximumFrameLatency(1));

m_waitable_renderer = swap_chain2->GetFrameLatencyWaitableObject();

それに伴う swapChain のサイズ変更:

tools::throw_if_failed(
    m_swap_chain->ResizeBuffers(s_frame_count, window_width, window_height, m_back_buffer_format, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT));

私の質問は次のとおりです。何かを間違って設定していますか? それとも、これが待機可能なスワップ チェーンの仕組みですか (つまり、スワップ チェーンが利用可能になるのを待つ前に、gpu とフェンスを同期する必要もあります) ?

編集: SetFrameLatency 呼び出しの追加 + C++ カラーリング

4

1 に答える 1