Files
XCEngine/editor/src/UI/ImGuiBackendBridge.h

176 lines
5.3 KiB
C++

#pragma once
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <d3d12.h>
#include <dxgi1_6.h>
#include <imgui.h>
#include <imgui_impl_dx12.h>
#include <imgui_impl_win32.h>
#include <vector>
#include <windows.h>
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
namespace XCEngine {
namespace Editor {
namespace UI {
class ImGuiBackendBridge {
public:
static void EnableDpiAwareness() {
ImGui_ImplWin32_EnableDpiAwareness();
}
static float GetDpiScaleForHwnd(HWND hwnd) {
return hwnd ? ImGui_ImplWin32_GetDpiScaleForHwnd(hwnd) : 1.0f;
}
void Initialize(
HWND hwnd,
ID3D12Device* device,
ID3D12CommandQueue* commandQueue,
ID3D12DescriptorHeap* srvHeap,
UINT srvDescriptorSize,
UINT srvDescriptorCount,
int frameCount = 3,
DXGI_FORMAT backBufferFormat = DXGI_FORMAT_R8G8B8A8_UNORM) {
m_srvHeap = srvHeap;
m_srvDescriptorSize = srvDescriptorSize;
m_srvCpuStart = srvHeap->GetCPUDescriptorHandleForHeapStart();
m_srvGpuStart = srvHeap->GetGPUDescriptorHandleForHeapStart();
m_srvUsage.assign(srvDescriptorCount, false);
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX12_InitInfo initInfo = {};
initInfo.Device = device;
initInfo.CommandQueue = commandQueue;
initInfo.NumFramesInFlight = frameCount;
initInfo.RTVFormat = backBufferFormat;
initInfo.DSVFormat = DXGI_FORMAT_UNKNOWN;
initInfo.UserData = this;
initInfo.SrvDescriptorHeap = srvHeap;
initInfo.SrvDescriptorAllocFn = &ImGuiBackendBridge::AllocateSrvDescriptor;
initInfo.SrvDescriptorFreeFn = &ImGuiBackendBridge::FreeSrvDescriptor;
ImGui_ImplDX12_Init(&initInfo);
m_initialized = true;
}
void Shutdown() {
if (!m_initialized) {
return;
}
ImGui_ImplDX12_Shutdown();
ImGui_ImplWin32_Shutdown();
m_srvUsage.clear();
m_srvHeap = nullptr;
m_srvDescriptorSize = 0;
m_srvCpuStart.ptr = 0;
m_srvGpuStart.ptr = 0;
m_initialized = false;
}
void BeginFrame() const {
ImGui_ImplDX12_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
}
void RenderDrawData(ID3D12GraphicsCommandList* commandList) const {
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), commandList);
}
void AllocateTextureDescriptor(
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
AllocateSrvDescriptorInternal(outCpuHandle, outGpuHandle);
}
void FreeTextureDescriptor(
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle) {
FreeSrvDescriptorInternal(cpuHandle, gpuHandle);
}
static bool HandleWindowMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
return ImGui_ImplWin32_WndProcHandler(hwnd, msg, wParam, lParam) != 0;
}
private:
static void AllocateSrvDescriptor(
ImGui_ImplDX12_InitInfo* info,
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
ImGuiBackendBridge* bridge = static_cast<ImGuiBackendBridge*>(info->UserData);
IM_ASSERT(bridge != nullptr);
bridge->AllocateSrvDescriptorInternal(outCpuHandle, outGpuHandle);
}
static void FreeSrvDescriptor(
ImGui_ImplDX12_InitInfo* info,
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE) {
ImGuiBackendBridge* bridge = static_cast<ImGuiBackendBridge*>(info->UserData);
IM_ASSERT(bridge != nullptr);
bridge->FreeSrvDescriptorInternal(cpuHandle, {});
}
void AllocateSrvDescriptorInternal(
D3D12_CPU_DESCRIPTOR_HANDLE* outCpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE* outGpuHandle) {
IM_ASSERT(outCpuHandle != nullptr && outGpuHandle != nullptr);
for (size_t i = 0; i < m_srvUsage.size(); ++i) {
if (m_srvUsage[i]) {
continue;
}
m_srvUsage[i] = true;
outCpuHandle->ptr = m_srvCpuStart.ptr + static_cast<SIZE_T>(i) * m_srvDescriptorSize;
outGpuHandle->ptr = m_srvGpuStart.ptr + static_cast<UINT64>(i) * m_srvDescriptorSize;
return;
}
IM_ASSERT(false && "ImGui SRV descriptor heap is exhausted.");
*outCpuHandle = m_srvCpuStart;
*outGpuHandle = m_srvGpuStart;
}
void FreeSrvDescriptorInternal(
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,
D3D12_GPU_DESCRIPTOR_HANDLE) {
if (m_srvDescriptorSize == 0 || cpuHandle.ptr < m_srvCpuStart.ptr) {
return;
}
const SIZE_T offset = cpuHandle.ptr - m_srvCpuStart.ptr;
const size_t index = static_cast<size_t>(offset / m_srvDescriptorSize);
if (index < m_srvUsage.size()) {
m_srvUsage[index] = false;
}
}
bool m_initialized = false;
ID3D12DescriptorHeap* m_srvHeap = nullptr;
UINT m_srvDescriptorSize = 0;
D3D12_CPU_DESCRIPTOR_HANDLE m_srvCpuStart = {};
D3D12_GPU_DESCRIPTOR_HANDLE m_srvGpuStart = {};
std::vector<bool> m_srvUsage;
};
} // namespace UI
} // namespace Editor
} // namespace XCEngine