mirror of
https://github.com/ocornut/imgui.git
synced 2026-01-11 00:04:24 +00:00
Backends: DX12: Let user specifies an optional custom error handling function and fix missing error checks
This commit is contained in:
parent
28dabdcb9e
commit
c1d6e4b795
3 changed files with 196 additions and 107 deletions
|
|
@ -23,6 +23,7 @@
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||||
|
// 2025-10-20: DirectX12: Let user specifies an optional custom error handling function by setting ImGui_ImplDX12_InitInfo::CheckHrResultFn.
|
||||||
// 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002)
|
// 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002)
|
||||||
// 2025-09-29: DirectX12: Rework synchronization logic. (#8961)
|
// 2025-09-29: DirectX12: Rework synchronization logic. (#8961)
|
||||||
// 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965)
|
// 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965)
|
||||||
|
|
@ -210,6 +211,16 @@ struct VERTEX_CONSTANT_BUFFER_DX12
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void check_hr_result(HRESULT hr)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
if (!bd)
|
||||||
|
return;
|
||||||
|
ImGui_ImplDX12_InitInfo* v = &bd->InitInfo;
|
||||||
|
if (v->CheckHrResultFn)
|
||||||
|
v->CheckHrResultFn(hr);
|
||||||
|
}
|
||||||
|
|
||||||
// Forward Declarations
|
// Forward Declarations
|
||||||
static void ImGui_ImplDX12_InitMultiViewportSupport();
|
static void ImGui_ImplDX12_InitMultiViewportSupport();
|
||||||
static void ImGui_ImplDX12_ShutdownMultiViewportSupport();
|
static void ImGui_ImplDX12_ShutdownMultiViewportSupport();
|
||||||
|
|
@ -316,8 +327,8 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
|
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->VertexBuffer));
|
||||||
return;
|
check_hr_result(hr);
|
||||||
}
|
}
|
||||||
if (fr->IndexBuffer == nullptr || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
if (fr->IndexBuffer == nullptr || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
|
|
@ -337,18 +348,18 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
|
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->IndexBuffer));
|
||||||
return;
|
check_hr_result(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload vertex/index data into a single contiguous GPU buffer
|
// Upload vertex/index data into a single contiguous GPU buffer
|
||||||
// During Map() we specify a null read range (as per DX12 API, this is informational and for tooling only)
|
// During Map() we specify a null read range (as per DX12 API, this is informational and for tooling only)
|
||||||
void* vtx_resource, *idx_resource;
|
void* vtx_resource, *idx_resource;
|
||||||
D3D12_RANGE range = { 0, 0 };
|
D3D12_RANGE range = { 0, 0 };
|
||||||
if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK)
|
HRESULT hr = fr->VertexBuffer->Map(0, &range, &vtx_resource);
|
||||||
return;
|
check_hr_result(hr);
|
||||||
if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK)
|
hr = fr->IndexBuffer->Map(0, &range, &idx_resource);
|
||||||
return;
|
check_hr_result(hr);
|
||||||
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource;
|
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource;
|
||||||
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource;
|
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource;
|
||||||
for (const ImDrawList* draw_list : draw_data->CmdLists)
|
for (const ImDrawList* draw_list : draw_data->CmdLists)
|
||||||
|
|
@ -475,8 +486,9 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
ID3D12Resource* pTexture = nullptr;
|
ID3D12Resource* pTexture = nullptr;
|
||||||
bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture));
|
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture));
|
||||||
|
check_hr_result(hr);
|
||||||
|
|
||||||
// Create SRV
|
// Create SRV
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||||
|
|
@ -549,16 +561,18 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
||||||
|
|
||||||
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&bd->pTexUploadBuffer));
|
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&bd->pTexUploadBuffer));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
check_hr_result(hr);
|
||||||
|
|
||||||
D3D12_RANGE range = {0, upload_size};
|
D3D12_RANGE range = {0, upload_size};
|
||||||
hr = bd->pTexUploadBuffer->Map(0, &range, &bd->pTexUploadBufferMapped);
|
hr = bd->pTexUploadBuffer->Map(0, &range, &bd->pTexUploadBufferMapped);
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
check_hr_result(hr);
|
||||||
bd->pTexUploadBufferSize = upload_size;
|
bd->pTexUploadBufferSize = upload_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bd->pTexCmdAllocator->Reset();
|
HRESULT hr = bd->pTexCmdAllocator->Reset();
|
||||||
bd->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr);
|
check_hr_result(hr);
|
||||||
|
hr = bd->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr);
|
||||||
|
check_hr_result(hr);
|
||||||
ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList;
|
ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList;
|
||||||
|
|
||||||
// Copy to upload buffer
|
// Copy to upload buffer
|
||||||
|
|
@ -604,18 +618,19 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
||||||
cmdList->ResourceBarrier(1, &barrier);
|
cmdList->ResourceBarrier(1, &barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT hr = cmdList->Close();
|
hr = cmdList->Close();
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
check_hr_result(hr);
|
||||||
ID3D12CommandQueue* cmdQueue = bd->pCommandQueue;
|
ID3D12CommandQueue* cmdQueue = bd->pCommandQueue;
|
||||||
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
|
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
|
||||||
hr = cmdQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
hr = cmdQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
check_hr_result(hr);
|
||||||
|
|
||||||
// FIXME-OPT: Suboptimal?
|
// FIXME-OPT: Suboptimal?
|
||||||
// - To remove this may need to create NumFramesInFlight x ImGui_ImplDX12_FrameContext in backend data (mimick docking version)
|
// - To remove this may need to create NumFramesInFlight x ImGui_ImplDX12_FrameContext in backend data (mimick docking version)
|
||||||
// - Store per-frame in flight: upload buffer?
|
// - Store per-frame in flight: upload buffer?
|
||||||
// - Where do cmdList and cmdAlloc fit?
|
// - Where do cmdList and cmdAlloc fit?
|
||||||
bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
hr = bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
||||||
|
check_hr_result(hr);
|
||||||
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
||||||
|
|
||||||
tex->SetStatus(ImTextureStatus_OK);
|
tex->SetStatus(ImTextureStatus_OK);
|
||||||
|
|
@ -634,10 +649,11 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
ImGui_ImplDX12_InvalidateDeviceObjects();
|
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
|
|
||||||
HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&bd->pdxgiFactory));
|
HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&bd->pdxgiFactory));
|
||||||
IM_ASSERT(hr == S_OK);
|
check_hr_result(hr);
|
||||||
|
|
||||||
BOOL allow_tearing = FALSE;
|
BOOL allow_tearing = FALSE;
|
||||||
bd->pdxgiFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing));
|
hr = bd->pdxgiFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing));
|
||||||
|
check_hr_result(hr);
|
||||||
bd->tearingSupport = (allow_tearing == TRUE);
|
bd->tearingSupport = (allow_tearing == TRUE);
|
||||||
|
|
||||||
// Create the root signature
|
// Create the root signature
|
||||||
|
|
@ -719,7 +735,8 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK)
|
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature));
|
hr = bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature));
|
||||||
|
check_hr_result(hr);
|
||||||
blob->Release();
|
blob->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -773,8 +790,8 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
return output;\
|
return output;\
|
||||||
}";
|
}";
|
||||||
|
|
||||||
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_5_0", 0, 0, &vertexShaderBlob, nullptr)))
|
hr = D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_5_0", 0, 0, &vertexShaderBlob, nullptr);
|
||||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
check_hr_result(hr); // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
|
psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
|
||||||
|
|
||||||
// Create the input layout
|
// Create the input layout
|
||||||
|
|
@ -805,10 +822,11 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
return out_col; \
|
return out_col; \
|
||||||
}";
|
}";
|
||||||
|
|
||||||
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr)))
|
hr = D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr);
|
||||||
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
vertexShaderBlob->Release();
|
vertexShaderBlob->Release();
|
||||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
check_hr_result(hr); // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
}
|
}
|
||||||
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
|
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
|
||||||
}
|
}
|
||||||
|
|
@ -855,23 +873,22 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
|
hr = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
|
||||||
vertexShaderBlob->Release();
|
vertexShaderBlob->Release();
|
||||||
pixelShaderBlob->Release();
|
pixelShaderBlob->Release();
|
||||||
if (result_pipeline_state != S_OK)
|
check_hr_result(hr);
|
||||||
return false;
|
|
||||||
|
|
||||||
// Create command allocator and command list for ImGui_ImplDX12_UpdateTexture()
|
// Create command allocator and command list for ImGui_ImplDX12_UpdateTexture()
|
||||||
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&bd->pTexCmdAllocator));
|
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&bd->pTexCmdAllocator));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
check_hr_result(hr);
|
||||||
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, bd->pTexCmdAllocator, nullptr, IID_PPV_ARGS(&bd->pTexCmdList));
|
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, bd->pTexCmdAllocator, nullptr, IID_PPV_ARGS(&bd->pTexCmdList));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
check_hr_result(hr);
|
||||||
hr = bd->pTexCmdList->Close();
|
hr = bd->pTexCmdList->Close();
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
check_hr_result(hr);
|
||||||
|
|
||||||
// Create fence.
|
// Create fence.
|
||||||
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&bd->Fence));
|
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&bd->Fence));
|
||||||
IM_ASSERT(hr == S_OK);
|
check_hr_result(hr);
|
||||||
bd->FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
bd->FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
IM_ASSERT(bd->FenceEvent != nullptr);
|
IM_ASSERT(bd->FenceEvent != nullptr);
|
||||||
|
|
||||||
|
|
@ -999,7 +1016,7 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO
|
||||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||||
queueDesc.NodeMask = 1;
|
queueDesc.NodeMask = 1;
|
||||||
HRESULT hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&init_info.CommandQueue));
|
HRESULT hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&init_info.CommandQueue));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
check_hr_result(hr);
|
||||||
|
|
||||||
bool ret = ImGui_ImplDX12_Init(&init_info);
|
bool ret = ImGui_ImplDX12_Init(&init_info);
|
||||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
|
@ -1071,17 +1088,18 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
||||||
vd->CommandQueue = bd->pCommandQueue;
|
vd->CommandQueue = bd->pCommandQueue;
|
||||||
|
|
||||||
// Create command allocator.
|
// Create command allocator.
|
||||||
HRESULT res = S_OK;
|
HRESULT hr = S_OK;
|
||||||
for (UINT i = 0; i < bd->numFramesInFlight; ++i)
|
for (UINT i = 0; i < bd->numFramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator));
|
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator));
|
||||||
IM_ASSERT(res == S_OK);
|
check_hr_result(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create command list.
|
// Create command list.
|
||||||
res = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vd->FrameCtx[0].CommandAllocator, nullptr, IID_PPV_ARGS(&vd->CommandList));
|
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vd->FrameCtx[0].CommandAllocator, nullptr, IID_PPV_ARGS(&vd->CommandList));
|
||||||
IM_ASSERT(res == S_OK);
|
check_hr_result(hr);
|
||||||
vd->CommandList->Close();
|
hr = vd->CommandList->Close();
|
||||||
|
check_hr_result(hr);
|
||||||
|
|
||||||
// Create swap chain
|
// Create swap chain
|
||||||
// FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application.
|
// FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application.
|
||||||
|
|
@ -1104,14 +1122,15 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
||||||
sd1.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
sd1.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||||
|
|
||||||
IDXGISwapChain1* swap_chain = nullptr;
|
IDXGISwapChain1* swap_chain = nullptr;
|
||||||
res = bd->pdxgiFactory->CreateSwapChainForHwnd(vd->CommandQueue, hwnd, &sd1, nullptr, nullptr, &swap_chain);
|
hr = bd->pdxgiFactory->CreateSwapChainForHwnd(vd->CommandQueue, hwnd, &sd1, nullptr, nullptr, &swap_chain);
|
||||||
IM_ASSERT(res == S_OK);
|
check_hr_result(hr);
|
||||||
res = bd->pdxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); // Disable e.g. Alt+Enter
|
hr = bd->pdxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); // Disable e.g. Alt+Enter
|
||||||
IM_ASSERT(res == S_OK);
|
check_hr_result(hr);
|
||||||
|
|
||||||
// Or swapChain.As(&mSwapChain)
|
// Or swapChain.As(&mSwapChain)
|
||||||
IM_ASSERT(vd->SwapChain == nullptr);
|
IM_ASSERT(vd->SwapChain == nullptr);
|
||||||
swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain));
|
hr = swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain));
|
||||||
|
check_hr_result(hr);
|
||||||
swap_chain->Release();
|
swap_chain->Release();
|
||||||
|
|
||||||
// Create the render targets and waitable object
|
// Create the render targets and waitable object
|
||||||
|
|
@ -1123,8 +1142,8 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
||||||
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||||
desc.NodeMask = 1;
|
desc.NodeMask = 1;
|
||||||
|
|
||||||
HRESULT hr = bd->pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&vd->RtvDescHeap));
|
hr = bd->pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&vd->RtvDescHeap));
|
||||||
IM_ASSERT(hr == S_OK);
|
check_hr_result(hr);
|
||||||
|
|
||||||
SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
||||||
|
|
@ -1138,13 +1157,14 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
||||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
{
|
{
|
||||||
IM_ASSERT(vd->FrameCtx[i].RenderTarget == nullptr);
|
IM_ASSERT(vd->FrameCtx[i].RenderTarget == nullptr);
|
||||||
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
hr = vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
||||||
|
check_hr_result(hr);
|
||||||
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
||||||
vd->FrameCtx[i].RenderTarget = back_buffer;
|
vd->FrameCtx[i].RenderTarget = back_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = vd->SwapChain->SetMaximumFrameLatency(bd->numFramesInFlight);
|
hr = vd->SwapChain->SetMaximumFrameLatency(bd->numFramesInFlight);
|
||||||
IM_ASSERT(hr == S_OK);
|
check_hr_result(hr);
|
||||||
vd->SwapChainWaitableObject = vd->SwapChain->GetFrameLatencyWaitableObject();
|
vd->SwapChainWaitableObject = vd->SwapChain->GetFrameLatencyWaitableObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1156,10 +1176,10 @@ static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd)
|
||||||
{
|
{
|
||||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
||||||
IM_ASSERT(hr == S_OK);
|
check_hr_result(hr);
|
||||||
|
|
||||||
hr = bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
hr = bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
||||||
IM_ASSERT(hr == S_OK);
|
check_hr_result(hr);
|
||||||
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1170,7 +1190,7 @@ static ImGui_ImplDX12_FrameContext* ImGui_WaitForNextFrameContext(ImGui_ImplDX12
|
||||||
if (bd->Fence->GetCompletedValue() < frame_context->FenceValue)
|
if (bd->Fence->GetCompletedValue() < frame_context->FenceValue)
|
||||||
{
|
{
|
||||||
HRESULT hr = bd->Fence->SetEventOnCompletion(frame_context->FenceValue, bd->FenceEvent);
|
HRESULT hr = bd->Fence->SetEventOnCompletion(frame_context->FenceValue, bd->FenceEvent);
|
||||||
IM_ASSERT(hr == S_OK);
|
check_hr_result(hr);
|
||||||
HANDLE waitableObjects[] = { vd->SwapChainWaitableObject, bd->FenceEvent };
|
HANDLE waitableObjects[] = { vd->SwapChainWaitableObject, bd->FenceEvent };
|
||||||
::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
|
::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
@ -1221,11 +1241,14 @@ static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||||
{
|
{
|
||||||
ID3D12Resource* back_buffer = nullptr;
|
ID3D12Resource* back_buffer = nullptr;
|
||||||
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
||||||
vd->SwapChain->GetDesc1(&desc);
|
HRESULT hr = vd->SwapChain->GetDesc1(&desc);
|
||||||
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, desc.Format, desc.Flags);
|
check_hr_result(hr);
|
||||||
|
hr = vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, desc.Format, desc.Flags);
|
||||||
|
check_hr_result(hr);
|
||||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
{
|
{
|
||||||
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
hr = vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
||||||
|
check_hr_result(hr);
|
||||||
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
||||||
vd->FrameCtx[i].RenderTarget = back_buffer;
|
vd->FrameCtx[i].RenderTarget = back_buffer;
|
||||||
}
|
}
|
||||||
|
|
@ -1252,8 +1275,10 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
||||||
// Draw
|
// Draw
|
||||||
ID3D12GraphicsCommandList* cmd_list = vd->CommandList;
|
ID3D12GraphicsCommandList* cmd_list = vd->CommandList;
|
||||||
|
|
||||||
frame_context->CommandAllocator->Reset();
|
HRESULT hr = frame_context->CommandAllocator->Reset();
|
||||||
cmd_list->Reset(frame_context->CommandAllocator, nullptr);
|
check_hr_result(hr);
|
||||||
|
hr = cmd_list->Reset(frame_context->CommandAllocator, nullptr);
|
||||||
|
check_hr_result(hr);
|
||||||
cmd_list->ResourceBarrier(1, &barrier);
|
cmd_list->ResourceBarrier(1, &barrier);
|
||||||
cmd_list->OMSetRenderTargets(1, &vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr);
|
cmd_list->OMSetRenderTargets(1, &vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr);
|
||||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||||
|
|
@ -1265,12 +1290,13 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
cmd_list->ResourceBarrier(1, &barrier);
|
cmd_list->ResourceBarrier(1, &barrier);
|
||||||
cmd_list->Close();
|
hr = cmd_list->Close();
|
||||||
|
check_hr_result(hr);
|
||||||
|
|
||||||
vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
|
vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
|
||||||
|
|
||||||
HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
||||||
IM_ASSERT(hr == S_OK);
|
check_hr_result(hr);
|
||||||
frame_context->FenceValue = bd->FenceLastSignaledValue;
|
frame_context->FenceValue = bd->FenceLastSignaledValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1279,7 +1305,8 @@ static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||||
|
|
||||||
vd->SwapChain->Present(0, bd->tearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0);
|
HRESULT hr = vd->SwapChain->Present(0, bd->tearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0);
|
||||||
|
check_hr_result(hr);
|
||||||
vd->FrameIndex++;
|
vd->FrameIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@ struct ImGui_ImplDX12_InitInfo
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE LegacySingleSrvGpuDescriptor;
|
D3D12_GPU_DESCRIPTOR_HANDLE LegacySingleSrvGpuDescriptor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// (Optional) Debugging
|
||||||
|
void (*CheckHrResultFn)(HRESULT hr);
|
||||||
|
|
||||||
ImGui_ImplDX12_InitInfo() { memset((void*)this, 0, sizeof(*this)); }
|
ImGui_ImplDX12_InitInfo() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include <dxgi1_5.h>
|
#include <dxgi1_5.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <comdef.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define DX12_ENABLE_DEBUG_LAYER
|
#define DX12_ENABLE_DEBUG_LAYER
|
||||||
|
|
@ -98,10 +101,24 @@ static HANDLE g_hSwapChainWaitableObject = nullptr;
|
||||||
static ID3D12Resource* g_mainRenderTargetResource[APP_NUM_BACK_BUFFERS] = {};
|
static ID3D12Resource* g_mainRenderTargetResource[APP_NUM_BACK_BUFFERS] = {};
|
||||||
static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[APP_NUM_BACK_BUFFERS] = {};
|
static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[APP_NUM_BACK_BUFFERS] = {};
|
||||||
|
|
||||||
|
static void check_hr_result(HRESULT hr)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
return;
|
||||||
|
_com_error err(hr);
|
||||||
|
const wchar_t* wmsg = err.ErrorMessage();
|
||||||
|
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wmsg, -1, nullptr, 0, nullptr, nullptr);
|
||||||
|
std::string msg(size_needed, 0);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, wmsg, -1, &msg.front(), size_needed, nullptr, nullptr);
|
||||||
|
fprintf(stderr, "[d3d12] Error: HRESULT = %s\n", msg.c_str());
|
||||||
|
if (FAILED(hr))
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
// Forward declarations of helper functions
|
// Forward declarations of helper functions
|
||||||
bool CreateDeviceD3D(HWND hWnd);
|
HRESULT CreateDeviceD3D(HWND hWnd);
|
||||||
void CleanupDeviceD3D();
|
void CleanupDeviceD3D();
|
||||||
void CreateRenderTarget();
|
HRESULT CreateRenderTarget();
|
||||||
void CleanupRenderTarget();
|
void CleanupRenderTarget();
|
||||||
void WaitForPendingOperations();
|
void WaitForPendingOperations();
|
||||||
FrameContext* WaitForNextFrameContext();
|
FrameContext* WaitForNextFrameContext();
|
||||||
|
|
@ -120,11 +137,12 @@ int main(int, char**)
|
||||||
HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX12 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr);
|
HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX12 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr);
|
||||||
|
|
||||||
// Initialize Direct3D
|
// Initialize Direct3D
|
||||||
if (!CreateDeviceD3D(hwnd))
|
HRESULT hr = CreateDeviceD3D(hwnd);
|
||||||
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
CleanupDeviceD3D();
|
CleanupDeviceD3D();
|
||||||
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
||||||
return 1;
|
check_hr_result(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show the window
|
// Show the window
|
||||||
|
|
@ -174,6 +192,7 @@ int main(int, char**)
|
||||||
init_info.SrvDescriptorHeap = g_pd3dSrvDescHeap;
|
init_info.SrvDescriptorHeap = g_pd3dSrvDescHeap;
|
||||||
init_info.SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) { return g_pd3dSrvDescHeapAlloc.Alloc(out_cpu_handle, out_gpu_handle); };
|
init_info.SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) { return g_pd3dSrvDescHeapAlloc.Alloc(out_cpu_handle, out_gpu_handle); };
|
||||||
init_info.SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle) { return g_pd3dSrvDescHeapAlloc.Free(cpu_handle, gpu_handle); };
|
init_info.SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle) { return g_pd3dSrvDescHeapAlloc.Free(cpu_handle, gpu_handle); };
|
||||||
|
init_info.CheckHrResultFn = check_hr_result;
|
||||||
ImGui_ImplDX12_Init(&init_info);
|
ImGui_ImplDX12_Init(&init_info);
|
||||||
|
|
||||||
// Before 1.91.6: our signature was using a single descriptor. From 1.92, specifying SrvDescriptorAllocFn/SrvDescriptorFreeFn will be required to benefit from new features.
|
// Before 1.91.6: our signature was using a single descriptor. From 1.92, specifying SrvDescriptorAllocFn/SrvDescriptorFreeFn will be required to benefit from new features.
|
||||||
|
|
@ -272,7 +291,8 @@ int main(int, char**)
|
||||||
|
|
||||||
FrameContext* frameCtx = WaitForNextFrameContext();
|
FrameContext* frameCtx = WaitForNextFrameContext();
|
||||||
UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex();
|
UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex();
|
||||||
frameCtx->CommandAllocator->Reset();
|
hr = frameCtx->CommandAllocator->Reset();
|
||||||
|
check_hr_result(hr);
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier = {};
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
|
@ -281,7 +301,8 @@ int main(int, char**)
|
||||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
g_pd3dCommandList->Reset(frameCtx->CommandAllocator, nullptr);
|
hr = g_pd3dCommandList->Reset(frameCtx->CommandAllocator, nullptr);
|
||||||
|
check_hr_result(hr);
|
||||||
g_pd3dCommandList->ResourceBarrier(1, &barrier);
|
g_pd3dCommandList->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
// Render Dear ImGui graphics
|
// Render Dear ImGui graphics
|
||||||
|
|
@ -293,7 +314,8 @@ int main(int, char**)
|
||||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
g_pd3dCommandList->ResourceBarrier(1, &barrier);
|
g_pd3dCommandList->ResourceBarrier(1, &barrier);
|
||||||
g_pd3dCommandList->Close();
|
hr = g_pd3dCommandList->Close();
|
||||||
|
check_hr_result(hr);
|
||||||
|
|
||||||
g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&g_pd3dCommandList);
|
g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&g_pd3dCommandList);
|
||||||
|
|
||||||
|
|
@ -304,12 +326,14 @@ int main(int, char**)
|
||||||
ImGui::RenderPlatformWindowsDefault();
|
ImGui::RenderPlatformWindowsDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
|
hr = g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
|
||||||
|
check_hr_result(hr);
|
||||||
frameCtx->FenceValue = g_fenceLastSignaledValue;
|
frameCtx->FenceValue = g_fenceLastSignaledValue;
|
||||||
|
|
||||||
// Present
|
// Present
|
||||||
HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
|
hr = g_pSwapChain->Present(1, 0); // Present with vsync
|
||||||
//HRESULT hr = g_pSwapChain->Present(0, g_SwapChainTearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0); // Present without vsync
|
//hr = g_pSwapChain->Present(0, g_SwapChainTearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0); // Present without vsync
|
||||||
|
check_hr_result(hr);
|
||||||
g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
|
g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
|
||||||
g_frameIndex++;
|
g_frameIndex++;
|
||||||
}
|
}
|
||||||
|
|
@ -329,7 +353,7 @@ int main(int, char**)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
bool CreateDeviceD3D(HWND hWnd)
|
HRESULT CreateDeviceD3D(HWND hWnd)
|
||||||
{
|
{
|
||||||
// Setup swap chain
|
// Setup swap chain
|
||||||
DXGI_SWAP_CHAIN_DESC1 sd;
|
DXGI_SWAP_CHAIN_DESC1 sd;
|
||||||
|
|
@ -358,15 +382,18 @@ bool CreateDeviceD3D(HWND hWnd)
|
||||||
|
|
||||||
// Create device
|
// Create device
|
||||||
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
|
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
|
||||||
if (D3D12CreateDevice(nullptr, featureLevel, IID_PPV_ARGS(&g_pd3dDevice)) != S_OK)
|
HRESULT hr = D3D12CreateDevice(nullptr, featureLevel, IID_PPV_ARGS(&g_pd3dDevice));
|
||||||
return false;
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
// [DEBUG] Setup debug interface to break on any warnings/errors
|
// [DEBUG] Setup debug interface to break on any warnings/errors
|
||||||
#ifdef DX12_ENABLE_DEBUG_LAYER
|
#ifdef DX12_ENABLE_DEBUG_LAYER
|
||||||
if (pdx12Debug != nullptr)
|
if (pdx12Debug != nullptr)
|
||||||
{
|
{
|
||||||
ID3D12InfoQueue* pInfoQueue = nullptr;
|
ID3D12InfoQueue* pInfoQueue = nullptr;
|
||||||
g_pd3dDevice->QueryInterface(IID_PPV_ARGS(&pInfoQueue));
|
hr = g_pd3dDevice->QueryInterface(IID_PPV_ARGS(&pInfoQueue));
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
|
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
|
||||||
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
|
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
|
||||||
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true);
|
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true);
|
||||||
|
|
@ -381,8 +408,9 @@ bool CreateDeviceD3D(HWND hWnd)
|
||||||
desc.NumDescriptors = APP_NUM_BACK_BUFFERS;
|
desc.NumDescriptors = APP_NUM_BACK_BUFFERS;
|
||||||
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||||
desc.NodeMask = 1;
|
desc.NodeMask = 1;
|
||||||
if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap)) != S_OK)
|
hr = g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap));
|
||||||
return false;
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
||||||
|
|
@ -398,8 +426,9 @@ bool CreateDeviceD3D(HWND hWnd)
|
||||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||||
desc.NumDescriptors = APP_SRV_HEAP_SIZE;
|
desc.NumDescriptors = APP_SRV_HEAP_SIZE;
|
||||||
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||||
if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)) != S_OK)
|
hr = g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap));
|
||||||
return false;
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
g_pd3dSrvDescHeapAlloc.Create(g_pd3dDevice, g_pd3dSrvDescHeap);
|
g_pd3dSrvDescHeapAlloc.Create(g_pd3dDevice, g_pd3dSrvDescHeap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -408,52 +437,74 @@ bool CreateDeviceD3D(HWND hWnd)
|
||||||
desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||||
desc.NodeMask = 1;
|
desc.NodeMask = 1;
|
||||||
if (g_pd3dDevice->CreateCommandQueue(&desc, IID_PPV_ARGS(&g_pd3dCommandQueue)) != S_OK)
|
hr = g_pd3dDevice->CreateCommandQueue(&desc, IID_PPV_ARGS(&g_pd3dCommandQueue));
|
||||||
return false;
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (UINT i = 0; i < APP_NUM_FRAMES_IN_FLIGHT; i++)
|
for (UINT i = 0; i < APP_NUM_FRAMES_IN_FLIGHT; i++)
|
||||||
if (g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_frameContext[i].CommandAllocator)) != S_OK)
|
{
|
||||||
return false;
|
hr = g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_frameContext[i].CommandAllocator));
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, g_frameContext[0].CommandAllocator, nullptr, IID_PPV_ARGS(&g_pd3dCommandList)) != S_OK ||
|
hr = g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, g_frameContext[0].CommandAllocator, nullptr, IID_PPV_ARGS(&g_pd3dCommandList));
|
||||||
g_pd3dCommandList->Close() != S_OK)
|
if (FAILED(hr))
|
||||||
return false;
|
return hr;
|
||||||
|
hr = g_pd3dCommandList->Close();
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
if (g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&g_fence)) != S_OK)
|
hr = g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&g_fence));
|
||||||
return false;
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
g_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
g_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
if (g_fenceEvent == nullptr)
|
if (g_fenceEvent == nullptr)
|
||||||
return false;
|
return E_FAIL;
|
||||||
|
|
||||||
{
|
{
|
||||||
IDXGIFactory5* dxgiFactory = nullptr;
|
IDXGIFactory5* dxgiFactory = nullptr;
|
||||||
IDXGISwapChain1* swapChain1 = nullptr;
|
IDXGISwapChain1* swapChain1 = nullptr;
|
||||||
if (CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)) != S_OK)
|
hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
|
||||||
return false;
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
BOOL allow_tearing = FALSE;
|
BOOL allow_tearing = FALSE;
|
||||||
dxgiFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing));
|
hr = dxgiFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing));
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
g_SwapChainTearingSupport = (allow_tearing == TRUE);
|
g_SwapChainTearingSupport = (allow_tearing == TRUE);
|
||||||
if (g_SwapChainTearingSupport)
|
if (g_SwapChainTearingSupport)
|
||||||
sd.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
sd.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||||
|
|
||||||
if (dxgiFactory->CreateSwapChainForHwnd(g_pd3dCommandQueue, hWnd, &sd, nullptr, nullptr, &swapChain1) != S_OK)
|
hr = dxgiFactory->CreateSwapChainForHwnd(g_pd3dCommandQueue, hWnd, &sd, nullptr, nullptr, &swapChain1);
|
||||||
return false;
|
if (FAILED(hr))
|
||||||
if (swapChain1->QueryInterface(IID_PPV_ARGS(&g_pSwapChain)) != S_OK)
|
return hr;
|
||||||
return false;
|
hr = swapChain1->QueryInterface(IID_PPV_ARGS(&g_pSwapChain));
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
if (g_SwapChainTearingSupport)
|
if (g_SwapChainTearingSupport)
|
||||||
dxgiFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
|
{
|
||||||
|
hr = dxgiFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
swapChain1->Release();
|
swapChain1->Release();
|
||||||
dxgiFactory->Release();
|
dxgiFactory->Release();
|
||||||
g_pSwapChain->SetMaximumFrameLatency(APP_NUM_BACK_BUFFERS);
|
hr = g_pSwapChain->SetMaximumFrameLatency(APP_NUM_BACK_BUFFERS);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject();
|
g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateRenderTarget();
|
hr = CreateRenderTarget();
|
||||||
return true;
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CleanupDeviceD3D()
|
void CleanupDeviceD3D()
|
||||||
|
|
@ -481,15 +532,18 @@ void CleanupDeviceD3D()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateRenderTarget()
|
HRESULT CreateRenderTarget()
|
||||||
{
|
{
|
||||||
for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++)
|
for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++)
|
||||||
{
|
{
|
||||||
ID3D12Resource* pBackBuffer = nullptr;
|
ID3D12Resource* pBackBuffer = nullptr;
|
||||||
g_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer));
|
HRESULT hr = g_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer));
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, g_mainRenderTargetDescriptor[i]);
|
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, g_mainRenderTargetDescriptor[i]);
|
||||||
g_mainRenderTargetResource[i] = pBackBuffer;
|
g_mainRenderTargetResource[i] = pBackBuffer;
|
||||||
}
|
}
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CleanupRenderTarget()
|
void CleanupRenderTarget()
|
||||||
|
|
@ -502,9 +556,11 @@ void CleanupRenderTarget()
|
||||||
|
|
||||||
void WaitForPendingOperations()
|
void WaitForPendingOperations()
|
||||||
{
|
{
|
||||||
g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
|
HRESULT hr = g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
|
||||||
|
check_hr_result(hr);
|
||||||
|
|
||||||
g_fence->SetEventOnCompletion(g_fenceLastSignaledValue, g_fenceEvent);
|
hr = g_fence->SetEventOnCompletion(g_fenceLastSignaledValue, g_fenceEvent);
|
||||||
|
check_hr_result(hr);
|
||||||
::WaitForSingleObject(g_fenceEvent, INFINITE);
|
::WaitForSingleObject(g_fenceEvent, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -513,7 +569,8 @@ FrameContext* WaitForNextFrameContext()
|
||||||
FrameContext* frame_context = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT];
|
FrameContext* frame_context = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT];
|
||||||
if (g_fence->GetCompletedValue() < frame_context->FenceValue)
|
if (g_fence->GetCompletedValue() < frame_context->FenceValue)
|
||||||
{
|
{
|
||||||
g_fence->SetEventOnCompletion(frame_context->FenceValue, g_fenceEvent);
|
HRESULT hr = g_fence->SetEventOnCompletion(frame_context->FenceValue, g_fenceEvent);
|
||||||
|
check_hr_result(hr);
|
||||||
HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, g_fenceEvent };
|
HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, g_fenceEvent };
|
||||||
::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
|
::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
@ -543,10 +600,12 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
CleanupRenderTarget();
|
CleanupRenderTarget();
|
||||||
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
||||||
g_pSwapChain->GetDesc1(&desc);
|
HRESULT hr = g_pSwapChain->GetDesc1(&desc);
|
||||||
HRESULT result = g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), desc.Format, desc.Flags);
|
check_hr_result(hr);
|
||||||
assert(SUCCEEDED(result) && "Failed to resize swapchain.");
|
hr = g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), desc.Format, desc.Flags);
|
||||||
CreateRenderTarget();
|
check_hr_result(hr);
|
||||||
|
hr = CreateRenderTarget();
|
||||||
|
check_hr_result(hr);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
case WM_SYSCOMMAND:
|
case WM_SYSCOMMAND:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue