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
|
||||
// (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: 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)
|
||||
@@ -108,6 +109,9 @@ struct ImGui_ImplDX12_Data
|
||||
|
||||
ID3D12CommandAllocator* pTexCmdAllocator;
|
||||
ID3D12GraphicsCommandList* pTexCmdList;
|
||||
ID3D12Resource* pTexUploadBuffer;
|
||||
UINT pTexUploadBufferSize;
|
||||
void* pTexUploadBufferMapped;
|
||||
|
||||
ImGui_ImplDX12_RenderBuffers* pFrameResources;
|
||||
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_size = upload_pitch_dst * upload_h;
|
||||
|
||||
D3D12_RESOURCE_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
desc.Alignment = 0;
|
||||
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;
|
||||
if (bd->pTexUploadBuffer == nullptr || upload_size > bd->pTexUploadBufferSize)
|
||||
{
|
||||
if (bd->pTexUploadBufferMapped)
|
||||
{
|
||||
D3D12_RANGE range = { 0, bd->pTexUploadBufferSize };
|
||||
bd->pTexUploadBuffer->Unmap(0, &range);
|
||||
bd->pTexUploadBufferMapped = nullptr;
|
||||
}
|
||||
SafeRelease(bd->pTexUploadBuffer);
|
||||
|
||||
D3D12_HEAP_PROPERTIES props;
|
||||
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
|
||||
props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
D3D12_RESOURCE_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
desc.Alignment = 0;
|
||||
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?
|
||||
ID3D12Resource* uploadBuffer = nullptr;
|
||||
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadBuffer));
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
D3D12_HEAP_PROPERTIES props;
|
||||
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
|
||||
props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
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->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr);
|
||||
ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList;
|
||||
|
||||
// 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++)
|
||||
memcpy((void*)((uintptr_t)mapped + y * upload_pitch_dst), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch_src);
|
||||
uploadBuffer->Unmap(0, &range);
|
||||
memcpy((void*)((uintptr_t)bd->pTexUploadBufferMapped + y * upload_pitch_dst), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch_src);
|
||||
|
||||
if (need_barrier_before_copy)
|
||||
{
|
||||
@@ -492,7 +505,7 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
||||
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
|
||||
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
|
||||
{
|
||||
srcLocation.pResource = uploadBuffer;
|
||||
srcLocation.pResource = bd->pTexUploadBuffer;
|
||||
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
srcLocation.PlacedFootprint.Footprint.Width = upload_w;
|
||||
@@ -516,9 +529,8 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
||||
cmdList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
hr = cmdList->Close();
|
||||
HRESULT hr = cmdList->Close();
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
ID3D12CommandQueue* cmdQueue = bd->pCommandQueue;
|
||||
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
|
||||
hr = cmdQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
||||
@@ -531,7 +543,6 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
||||
bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
||||
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
||||
|
||||
uploadBuffer->Release();
|
||||
tex->SetStatus(ImTextureStatus_OK);
|
||||
}
|
||||
|
||||
@@ -804,6 +815,13 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
|
||||
bd->commandQueueOwned = false;
|
||||
SafeRelease(bd->pRootSignature);
|
||||
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->pTexCmdAllocator);
|
||||
SafeRelease(bd->Fence);
|
||||
|
@@ -99,6 +99,8 @@ Other Changes:
|
||||
of recreating them each time. (#8963, #8465) [@RT2Code]
|
||||
- Backends: DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
|
||||
(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: OpenGL3: fixed GL loader to work on Haiku OS which does not support
|
||||
`RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes]
|
||||
|
Reference in New Issue
Block a user