mirror of
https://github.com/ocornut/imgui.git
synced 2025-10-16 15:06:04 +00:00
Backends: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002)
This commit is contained in:
@@ -20,6 +20,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-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)
|
||||||
// 2025-09-29: DirectX12: Reuse a command list and allocator for texture uploads instead of recreating them each time. (#8963)
|
// 2025-09-29: DirectX12: Reuse a command list and allocator for texture uploads instead of recreating them each time. (#8963)
|
||||||
@@ -108,6 +109,9 @@ struct ImGui_ImplDX12_Data
|
|||||||
|
|
||||||
ID3D12CommandAllocator* pTexCmdAllocator;
|
ID3D12CommandAllocator* pTexCmdAllocator;
|
||||||
ID3D12GraphicsCommandList* pTexCmdList;
|
ID3D12GraphicsCommandList* pTexCmdList;
|
||||||
|
ID3D12Resource* pTexUploadBuffer;
|
||||||
|
UINT pTexUploadBufferSize;
|
||||||
|
void* pTexUploadBufferMapped;
|
||||||
|
|
||||||
ImGui_ImplDX12_RenderBuffers* pFrameResources;
|
ImGui_ImplDX12_RenderBuffers* pFrameResources;
|
||||||
UINT frameIndex;
|
UINT frameIndex;
|
||||||
@@ -438,44 +442,53 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
|||||||
UINT upload_pitch_dst = (upload_pitch_src + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
|
UINT upload_pitch_dst = (upload_pitch_src + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
|
||||||
UINT upload_size = upload_pitch_dst * upload_h;
|
UINT upload_size = upload_pitch_dst * upload_h;
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC desc;
|
if (bd->pTexUploadBuffer == nullptr || upload_size > bd->pTexUploadBufferSize)
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
{
|
||||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
if (bd->pTexUploadBufferMapped)
|
||||||
desc.Alignment = 0;
|
{
|
||||||
desc.Width = upload_size;
|
D3D12_RANGE range = { 0, bd->pTexUploadBufferSize };
|
||||||
desc.Height = 1;
|
bd->pTexUploadBuffer->Unmap(0, &range);
|
||||||
desc.DepthOrArraySize = 1;
|
bd->pTexUploadBufferMapped = nullptr;
|
||||||
desc.MipLevels = 1;
|
}
|
||||||
desc.Format = DXGI_FORMAT_UNKNOWN;
|
SafeRelease(bd->pTexUploadBuffer);
|
||||||
desc.SampleDesc.Count = 1;
|
|
||||||
desc.SampleDesc.Quality = 0;
|
|
||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
||||||
|
|
||||||
D3D12_HEAP_PROPERTIES props;
|
D3D12_RESOURCE_DESC desc;
|
||||||
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
desc.Alignment = 0;
|
||||||
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
desc.Width = upload_size;
|
||||||
|
desc.Height = 1;
|
||||||
|
desc.DepthOrArraySize = 1;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.SampleDesc.Quality = 0;
|
||||||
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
// FIXME-OPT: Could upload buffer be kept around, reused, and grown only when needed? Would that be worth it?
|
D3D12_HEAP_PROPERTIES props;
|
||||||
ID3D12Resource* uploadBuffer = nullptr;
|
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
|
||||||
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadBuffer));
|
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
|
||||||
|
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
|
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&bd->pTexUploadBuffer));
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
D3D12_RANGE range = {0, upload_size};
|
||||||
|
hr = bd->pTexUploadBuffer->Map(0, &range, &bd->pTexUploadBufferMapped);
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
bd->pTexUploadBufferSize = upload_size;
|
||||||
|
}
|
||||||
|
|
||||||
bd->pTexCmdAllocator->Reset();
|
bd->pTexCmdAllocator->Reset();
|
||||||
bd->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr);
|
bd->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr);
|
||||||
ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList;
|
ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList;
|
||||||
|
|
||||||
// Copy to upload buffer
|
// Copy to upload buffer
|
||||||
void* mapped = nullptr;
|
|
||||||
D3D12_RANGE range = { 0, upload_size };
|
|
||||||
hr = uploadBuffer->Map(0, &range, &mapped);
|
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
|
||||||
for (int y = 0; y < upload_h; y++)
|
for (int y = 0; y < upload_h; y++)
|
||||||
memcpy((void*)((uintptr_t)mapped + y * upload_pitch_dst), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch_src);
|
memcpy((void*)((uintptr_t)bd->pTexUploadBufferMapped + y * upload_pitch_dst), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch_src);
|
||||||
uploadBuffer->Unmap(0, &range);
|
|
||||||
|
|
||||||
if (need_barrier_before_copy)
|
if (need_barrier_before_copy)
|
||||||
{
|
{
|
||||||
@@ -492,7 +505,7 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
|||||||
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
|
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
|
||||||
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
|
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
|
||||||
{
|
{
|
||||||
srcLocation.pResource = uploadBuffer;
|
srcLocation.pResource = bd->pTexUploadBuffer;
|
||||||
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||||
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
srcLocation.PlacedFootprint.Footprint.Width = upload_w;
|
srcLocation.PlacedFootprint.Footprint.Width = upload_w;
|
||||||
@@ -516,9 +529,8 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
|||||||
cmdList->ResourceBarrier(1, &barrier);
|
cmdList->ResourceBarrier(1, &barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = cmdList->Close();
|
HRESULT hr = cmdList->Close();
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(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);
|
||||||
@@ -531,7 +543,6 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
|||||||
bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
||||||
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
||||||
|
|
||||||
uploadBuffer->Release();
|
|
||||||
tex->SetStatus(ImTextureStatus_OK);
|
tex->SetStatus(ImTextureStatus_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,6 +815,13 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
|
|||||||
bd->commandQueueOwned = false;
|
bd->commandQueueOwned = false;
|
||||||
SafeRelease(bd->pRootSignature);
|
SafeRelease(bd->pRootSignature);
|
||||||
SafeRelease(bd->pPipelineState);
|
SafeRelease(bd->pPipelineState);
|
||||||
|
if (bd->pTexUploadBufferMapped)
|
||||||
|
{
|
||||||
|
D3D12_RANGE range = { 0, bd->pTexUploadBufferSize };
|
||||||
|
bd->pTexUploadBuffer->Unmap(0, &range);
|
||||||
|
bd->pTexUploadBufferMapped = nullptr;
|
||||||
|
}
|
||||||
|
SafeRelease(bd->pTexUploadBuffer);
|
||||||
SafeRelease(bd->pTexCmdList);
|
SafeRelease(bd->pTexCmdList);
|
||||||
SafeRelease(bd->pTexCmdAllocator);
|
SafeRelease(bd->pTexCmdAllocator);
|
||||||
SafeRelease(bd->Fence);
|
SafeRelease(bd->Fence);
|
||||||
|
@@ -99,6 +99,8 @@ Other Changes:
|
|||||||
of recreating them each time. (#8963, #8465) [@RT2Code]
|
of recreating them each time. (#8963, #8465) [@RT2Code]
|
||||||
- Backends: DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
|
- Backends: DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
|
||||||
(presumably fixes old hard-to-repro crash issues such as #3463, #5018)
|
(presumably fixes old hard-to-repro crash issues such as #3463, #5018)
|
||||||
|
- Backends: DirectX12: Reuse texture upload buffer and grow it only when
|
||||||
|
necessary. (#9002) [@RT2Code]
|
||||||
- Backends: DirectX12: Enable swapchain tearing if available. (#8965) [@RT2Code]
|
- Backends: DirectX12: Enable swapchain tearing if available. (#8965) [@RT2Code]
|
||||||
- Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support
|
- Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support
|
||||||
`RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes]
|
`RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes]
|
||||||
|
Reference in New Issue
Block a user