mirror of
https://github.com/ocornut/imgui.git
synced 2026-01-11 00:04:24 +00:00
Merge branch 'docking' into dx12-unthrottle-viewport-framerate
This commit is contained in:
commit
acf436ab29
11 changed files with 135 additions and 138 deletions
|
|
@ -101,9 +101,15 @@ struct ImGui_ImplDX12_Data
|
|||
DXGI_FORMAT RTVFormat;
|
||||
DXGI_FORMAT DSVFormat;
|
||||
ID3D12DescriptorHeap* pd3dSrvDescHeap;
|
||||
ID3D12Fence* Fence;
|
||||
UINT64 FenceLastSignaledValue;
|
||||
HANDLE FenceEvent;
|
||||
UINT numFramesInFlight;
|
||||
bool tearingSupport;
|
||||
|
||||
ID3D12CommandAllocator* pTexCmdAllocator;
|
||||
ID3D12GraphicsCommandList* pTexCmdList;
|
||||
|
||||
ImGui_ImplDX12_RenderBuffers* pFrameResources;
|
||||
UINT frameIndex;
|
||||
|
||||
|
|
@ -131,6 +137,7 @@ struct ImGui_ImplDX12_RenderBuffers
|
|||
// Buffers used for secondary viewports created by the multi-viewports systems
|
||||
struct ImGui_ImplDX12_FrameContext
|
||||
{
|
||||
UINT64 FenceValue;
|
||||
ID3D12CommandAllocator* CommandAllocator;
|
||||
ID3D12Resource* RenderTarget;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors;
|
||||
|
|
@ -146,9 +153,7 @@ struct ImGui_ImplDX12_ViewportData
|
|||
ID3D12GraphicsCommandList* CommandList;
|
||||
ID3D12DescriptorHeap* RtvDescHeap;
|
||||
IDXGISwapChain3* SwapChain;
|
||||
ID3D12Fence* Fence;
|
||||
UINT64 FenceSignaledValue;
|
||||
HANDLE FenceEvent;
|
||||
HANDLE SwapChainWaitableObject;
|
||||
UINT NumFramesInFlight;
|
||||
ImGui_ImplDX12_FrameContext* FrameCtx;
|
||||
|
||||
|
|
@ -162,16 +167,15 @@ struct ImGui_ImplDX12_ViewportData
|
|||
CommandList = nullptr;
|
||||
RtvDescHeap = nullptr;
|
||||
SwapChain = nullptr;
|
||||
Fence = nullptr;
|
||||
FenceSignaledValue = 0;
|
||||
FenceEvent = nullptr;
|
||||
SwapChainWaitableObject = nullptr;
|
||||
NumFramesInFlight = num_frames_in_flight;
|
||||
FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight];
|
||||
FrameIndex = UINT_MAX;
|
||||
FrameIndex = 0;
|
||||
FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight];
|
||||
|
||||
for (UINT i = 0; i < NumFramesInFlight; ++i)
|
||||
{
|
||||
FrameCtx[i].FenceValue = 0;
|
||||
FrameCtx[i].CommandAllocator = nullptr;
|
||||
FrameCtx[i].RenderTarget = nullptr;
|
||||
|
||||
|
|
@ -187,8 +191,7 @@ struct ImGui_ImplDX12_ViewportData
|
|||
IM_ASSERT(CommandQueue == nullptr && CommandList == nullptr);
|
||||
IM_ASSERT(RtvDescHeap == nullptr);
|
||||
IM_ASSERT(SwapChain == nullptr);
|
||||
IM_ASSERT(Fence == nullptr);
|
||||
IM_ASSERT(FenceEvent == nullptr);
|
||||
IM_ASSERT(SwapChainWaitableObject == nullptr);
|
||||
|
||||
for (UINT i = 0; i < NumFramesInFlight; ++i)
|
||||
{
|
||||
|
|
@ -533,29 +536,15 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
|||
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
|
||||
// FIXME-OPT: Can upload buffer be reused?
|
||||
// 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));
|
||||
|
||||
// Create temporary command list and execute immediately
|
||||
ID3D12Fence* fence = nullptr;
|
||||
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
HANDLE event = ::CreateEvent(0, 0, 0, 0);
|
||||
IM_ASSERT(event != nullptr);
|
||||
|
||||
// FIXME-OPT: Create once and reuse?
|
||||
ID3D12CommandAllocator* cmdAlloc = nullptr;
|
||||
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
// FIXME-OPT: Can be use the one from user? (pass ID3D12GraphicsCommandList* to ImGui_ImplDX12_UpdateTextures)
|
||||
ID3D12GraphicsCommandList* cmdList = nullptr;
|
||||
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList));
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
bd->pTexCmdAllocator->Reset();
|
||||
bd->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr);
|
||||
ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList;
|
||||
|
||||
// Copy to upload buffer
|
||||
void* mapped = nullptr;
|
||||
|
|
@ -610,20 +599,16 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
|
|||
|
||||
ID3D12CommandQueue* cmdQueue = bd->pCommandQueue;
|
||||
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
|
||||
hr = cmdQueue->Signal(fence, 1);
|
||||
hr = cmdQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
// FIXME-OPT: Suboptimal?
|
||||
// - 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?
|
||||
// - Where do cmdList and cmdAlloc fit?
|
||||
fence->SetEventOnCompletion(1, event);
|
||||
::WaitForSingleObject(event, INFINITE);
|
||||
bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
||||
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
||||
|
||||
cmdList->Release();
|
||||
cmdAlloc->Release();
|
||||
::CloseHandle(event);
|
||||
fence->Release();
|
||||
uploadBuffer->Release();
|
||||
tex->SetStatus(ImTextureStatus_OK);
|
||||
}
|
||||
|
|
@ -861,6 +846,20 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
|||
if (result_pipeline_state != S_OK)
|
||||
return false;
|
||||
|
||||
// Create command allocator and command list for ImGui_ImplDX12_UpdateTexture()
|
||||
HRESULT hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&bd->pTexCmdAllocator));
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, bd->pTexCmdAllocator, nullptr, IID_PPV_ARGS(&bd->pTexCmdList));
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
hr = bd->pTexCmdList->Close();
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
// Create fence.
|
||||
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&bd->Fence));
|
||||
IM_ASSERT(hr == S_OK);
|
||||
bd->FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
IM_ASSERT(bd->FenceEvent != nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -882,6 +881,11 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
|
|||
bd->commandQueueOwned = false;
|
||||
SafeRelease(bd->pRootSignature);
|
||||
SafeRelease(bd->pPipelineState);
|
||||
SafeRelease(bd->pTexCmdList);
|
||||
SafeRelease(bd->pTexCmdAllocator);
|
||||
SafeRelease(bd->Fence);
|
||||
CloseHandle(bd->FenceEvent);
|
||||
bd->FenceEvent = nullptr;
|
||||
|
||||
// Destroy all textures
|
||||
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
|
||||
|
|
@ -1039,18 +1043,12 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||
IM_ASSERT(hwnd != 0);
|
||||
|
||||
vd->FrameIndex = UINT_MAX;
|
||||
|
||||
// Create command queue.
|
||||
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
|
||||
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
|
||||
HRESULT res = S_OK;
|
||||
res = bd->pd3dDevice->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&vd->CommandQueue));
|
||||
IM_ASSERT(res == S_OK);
|
||||
// Use shared command queue from init info
|
||||
vd->FrameIndex = 0;
|
||||
vd->CommandQueue = bd->pCommandQueue;
|
||||
|
||||
// Create command allocator.
|
||||
HRESULT res = S_OK;
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; ++i)
|
||||
{
|
||||
res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator));
|
||||
|
|
@ -1062,13 +1060,6 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||
IM_ASSERT(res == S_OK);
|
||||
vd->CommandList->Close();
|
||||
|
||||
// Create fence.
|
||||
res = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&vd->Fence));
|
||||
IM_ASSERT(res == S_OK);
|
||||
|
||||
vd->FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
IM_ASSERT(vd->FenceEvent != nullptr);
|
||||
|
||||
// Create swap chain
|
||||
// FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application.
|
||||
DXGI_SWAP_CHAIN_DESC1 sd1;
|
||||
|
|
@ -1084,6 +1075,7 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||
sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||
sd1.Scaling = DXGI_SCALING_NONE;
|
||||
sd1.Stereo = FALSE;
|
||||
sd1.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
|
||||
|
||||
IDXGIFactory5* dxgi_factory = nullptr;
|
||||
res = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory));
|
||||
|
|
@ -1108,7 +1100,7 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||
swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain));
|
||||
swap_chain->Release();
|
||||
|
||||
// Create the render targets
|
||||
// Create the render targets and waitable object
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
||||
|
|
@ -1136,6 +1128,10 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
||||
vd->FrameCtx[i].RenderTarget = back_buffer;
|
||||
}
|
||||
|
||||
hr = vd->SwapChain->SetMaximumFrameLatency(bd->numFramesInFlight);
|
||||
IM_ASSERT(hr == S_OK);
|
||||
vd->SwapChainWaitableObject = vd->SwapChain->GetFrameLatencyWaitableObject();
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
|
|
@ -1144,16 +1140,31 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
|||
|
||||
static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd)
|
||||
{
|
||||
HRESULT hr = S_FALSE;
|
||||
if (vd && vd->CommandQueue && vd->Fence && vd->FenceEvent)
|
||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
||||
IM_ASSERT(hr == S_OK);
|
||||
|
||||
hr = bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
|
||||
IM_ASSERT(hr == S_OK);
|
||||
::WaitForSingleObject(bd->FenceEvent, INFINITE);
|
||||
}
|
||||
|
||||
static ImGui_ImplDX12_FrameContext* ImGui_WaitForNextFrameContext(ImGui_ImplDX12_ViewportData* vd)
|
||||
{
|
||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % vd->NumFramesInFlight];
|
||||
if (bd->Fence->GetCompletedValue() < frame_context->FenceValue)
|
||||
{
|
||||
hr = vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue);
|
||||
HRESULT hr = bd->Fence->SetEventOnCompletion(frame_context->FenceValue, bd->FenceEvent);
|
||||
IM_ASSERT(hr == S_OK);
|
||||
::WaitForSingleObject(vd->FenceEvent, 0); // Reset any forgotten waits
|
||||
hr = vd->Fence->SetEventOnCompletion(vd->FenceSignaledValue, vd->FenceEvent);
|
||||
IM_ASSERT(hr == S_OK);
|
||||
::WaitForSingleObject(vd->FenceEvent, INFINITE);
|
||||
HANDLE waitableObjects[] = { vd->SwapChainWaitableObject, bd->FenceEvent };
|
||||
::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
::WaitForSingleObject(vd->SwapChainWaitableObject, INFINITE);
|
||||
}
|
||||
return frame_context;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
|
||||
|
|
@ -1164,13 +1175,12 @@ static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
|
|||
{
|
||||
ImGui_WaitForPendingOperations(vd);
|
||||
|
||||
SafeRelease(vd->CommandQueue);
|
||||
vd->CommandQueue = nullptr;
|
||||
::CloseHandle(vd->SwapChainWaitableObject);
|
||||
vd->SwapChainWaitableObject = nullptr;
|
||||
SafeRelease(vd->CommandList);
|
||||
SafeRelease(vd->SwapChain);
|
||||
SafeRelease(vd->RtvDescHeap);
|
||||
SafeRelease(vd->Fence);
|
||||
::CloseHandle(vd->FenceEvent);
|
||||
vd->FenceEvent = nullptr;
|
||||
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
{
|
||||
|
|
@ -1213,7 +1223,7 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
|||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||
|
||||
ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % bd->numFramesInFlight];
|
||||
ImGui_ImplDX12_FrameContext* frame_context = ImGui_WaitForNextFrameContext(vd);
|
||||
UINT back_buffer_idx = vd->SwapChain->GetCurrentBackBufferIndex();
|
||||
|
||||
const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
|
@ -1243,9 +1253,11 @@ static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
|||
cmd_list->ResourceBarrier(1, &barrier);
|
||||
cmd_list->Close();
|
||||
|
||||
vd->CommandQueue->Wait(vd->Fence, vd->FenceSignaledValue);
|
||||
vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
|
||||
vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue);
|
||||
|
||||
HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
|
||||
IM_ASSERT(hr == S_OK);
|
||||
frame_context->FenceValue = bd->FenceLastSignaledValue;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
|
|
@ -1254,8 +1266,7 @@ static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
|||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||
|
||||
vd->SwapChain->Present(0, bd->tearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0);
|
||||
while (vd->Fence->GetCompletedValue() < vd->FenceSignaledValue)
|
||||
::SwitchToThread();
|
||||
vd->FrameIndex++;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX12_InitMultiViewportSupport()
|
||||
|
|
|
|||
|
|
@ -116,6 +116,11 @@
|
|||
#endif
|
||||
|
||||
// GLFW
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||
#define GLFW_HAS_X11_OR_WAYLAND 1
|
||||
#else
|
||||
#define GLFW_HAS_X11_OR_WAYLAND 0
|
||||
#endif
|
||||
#include <GLFW/glfw3.h>
|
||||
#ifdef _WIN32
|
||||
#undef APIENTRY
|
||||
|
|
@ -128,8 +133,8 @@
|
|||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
#endif
|
||||
#include <GLFW/glfw3native.h>
|
||||
#elif !defined(__EMSCRIPTEN__)
|
||||
#ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Window() on Freedesktop (Linux, BSD, etc.)
|
||||
#elif GLFW_HAS_X11_OR_WAYLAND
|
||||
#ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Display(), glfwGetX11Window() on Freedesktop (Linux, BSD, etc.)
|
||||
#define GLFW_EXPOSE_NATIVE_X11
|
||||
#include <X11/Xatom.h>
|
||||
#endif
|
||||
|
|
@ -184,11 +189,6 @@
|
|||
#define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName()
|
||||
#define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError()
|
||||
#define GLFW_HAS_GETPLATFORM (GLFW_VERSION_COMBINED >= 3400) // 3.4+ glfwGetPlatform()
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||
#define GLFW_HAS_X11_OR_WAYLAND 1
|
||||
#else
|
||||
#define GLFW_HAS_X11_OR_WAYLAND 0
|
||||
#endif
|
||||
|
||||
// Map GLFWWindow* to ImGuiContext*.
|
||||
// - Would be simpler if we could use glfwSetWindowUserPointer()/glfwGetWindowUserPointer(), but this is a single and shared resource.
|
||||
|
|
|
|||
|
|
@ -1322,8 +1322,6 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
|
|||
IM_ASSERT(info->DescriptorPoolSize > 0);
|
||||
if (info->UseDynamicRendering)
|
||||
IM_ASSERT(info->PipelineInfoMain.RenderPass == VK_NULL_HANDLE && info->PipelineInfoForViewports.RenderPass == VK_NULL_HANDLE);
|
||||
else if (info->PipelineInfoForViewports.RenderPass == NULL)
|
||||
info->PipelineInfoForViewports.RenderPass = info->PipelineInfoMain.RenderPass;
|
||||
|
||||
bd->VulkanInitInfo = *info;
|
||||
|
||||
|
|
@ -1683,7 +1681,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
|
|||
info.imageFormat = wd->SurfaceFormat.format;
|
||||
info.imageColorSpace = wd->SurfaceFormat.colorSpace;
|
||||
info.imageArrayLayers = 1;
|
||||
info.imageUsage = (image_usage != 0) ? image_usage : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | image_usage;
|
||||
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; // Assume that graphics family == present family
|
||||
info.preTransform = (cap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : cap.currentTransform;
|
||||
info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
|
|
@ -2014,7 +2012,7 @@ static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport)
|
|||
}
|
||||
else
|
||||
{
|
||||
IM_ASSERT(pipeline_info->RenderPass != VK_NULL_HANDLE && "Did you set ImGui_ImplVulkan_InitInfo::PipelineInfoForViewports.RenderPass?"); // Since 1.92.4 it is required.
|
||||
pipeline_info->RenderPass = wd->RenderPass;
|
||||
}
|
||||
#endif
|
||||
bd->PipelineForViewports = ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, VK_NULL_HANDLE, &v->PipelineInfoForViewports);
|
||||
|
|
|
|||
|
|
@ -69,8 +69,10 @@
|
|||
// Specify settings to create pipeline and swapchain
|
||||
struct ImGui_ImplVulkan_PipelineInfo
|
||||
{
|
||||
// For Main and Secondary viewports
|
||||
// For Main viewport only
|
||||
VkRenderPass RenderPass; // Ignored if using dynamic rendering
|
||||
|
||||
// For Main and Secondary viewports
|
||||
uint32_t Subpass; //
|
||||
VkSampleCountFlagBits MSAASamples = {}; // 0 defaults to VK_SAMPLE_COUNT_1_BIT
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
|
|
@ -78,7 +80,7 @@ struct ImGui_ImplVulkan_PipelineInfo
|
|||
#endif
|
||||
|
||||
// For Secondary viewports only (created/managed by backend)
|
||||
VkImageUsageFlags SwapChainImageUsage; // 0 defaults to VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT. Add e.g. VK_IMAGE_USAGE_TRANSFER_SRC_BIT if you need to capture from viewports.
|
||||
VkImageUsageFlags SwapChainImageUsage; // Extra flags for vkCreateSwapchainKHR() calls for secondary viewports. We automatically add VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT. You can add e.g. VK_IMAGE_USAGE_TRANSFER_SRC_BIT if you need to capture from viewports.
|
||||
};
|
||||
|
||||
// Initialization data, for ImGui_ImplVulkan_Init()
|
||||
|
|
|
|||
|
|
@ -56,16 +56,18 @@ Breaking Changes:
|
|||
(introduced very recently and only used by `ImGui_ImplVulkan_CreateMainPipeline()`
|
||||
so it should not affect many users). (#8110, #8111)
|
||||
- Backends: Vulkan: helper ImGui_ImplVulkanH_CreateOrResizeWindow() added a
|
||||
`VkImageUsageFlags image_usage` argument.
|
||||
It was previously hardcoded to `VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT` and defaults
|
||||
to that when the value is 0. In theory the function is an internal helper but
|
||||
since it's used by our examples some may have used it. (#8946, #8111, #8686)
|
||||
`VkImageUsageFlags image_usage` argument to specific extra flags for calls to
|
||||
vkCreateSwapchainKHR() done for secondary viewports. We automatically add
|
||||
`VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT`. In theory the function is an internal
|
||||
helper but since it's used by our examples some may have used it. (#8946, #8111, #8686)
|
||||
|
||||
Other Changes:
|
||||
|
||||
- Windows: added lower-right resize grip on child windows using both
|
||||
ImGuiChildFlags_ResizeX and ImGuiChildFlags_ResizeY flags. (#8501) [@aleksijuvani]
|
||||
The grip is not visible before hovering to reduce clutter.
|
||||
- InputText: fixed single-line InputText() not applying fine character clipping
|
||||
properly (regression in 1.92.3). (#8967) [@Cyphall]
|
||||
- IO: added ImGuiPlatformIO::ClearPlatformHandlers(), ClearRendererHandlers()
|
||||
helpers to null all handlers. (#8945, #2769)
|
||||
- Misc: Debuggers: added type formatters for the LLDB debuggers (e.g. Xcode,
|
||||
|
|
@ -75,8 +77,13 @@ Other Changes:
|
|||
- Backends: all backends call ImGuiPlatformIO::ClearPlatformHandlers() and
|
||||
ClearRendererHandlers() on shutdown, so as not to leave function pointers
|
||||
which may be dangling when using backend in e.g. DLL. (#8945, #2769)
|
||||
- Backends: DirectX12: reuse a command list and allocator for texture uploads instead
|
||||
of recreating them each time. (#8963, #8465) [@RT2Code]
|
||||
- Backends: DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
|
||||
- Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support
|
||||
`RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes]
|
||||
- Backends: GLFW: fixed build on platform that are neither Windows, macOS or
|
||||
known Unixes (Regression in 1.92.3). (#8969, #8920, #8921) [@oktonion]
|
||||
- Backends: SDL2,SDL3: avoid using the SDL_GetGlobalMouseState() path when one of our
|
||||
window is hovered, as the event data is reliable and enough in this case.
|
||||
- Fix mouse coordinates issue in fullscreen apps with macOS notch. (#7919, #7786)
|
||||
|
|
@ -89,6 +96,7 @@ Other Changes:
|
|||
- Examples: SDL2+DirectX11: Try WARP software driver if hardware driver is
|
||||
not available. (#5924, #5562)
|
||||
- Examples: SDL3+DirectX11: Added SDL3+DirectX11 example. (#8956, #8957) [@tomaz82]
|
||||
- Examples: Win32+DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
|
||||
- Examples: made examples's main.cpp consistent with returning 1 on error.
|
||||
|
||||
Docking+Viewports Branch:
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
|
|||
static ImGui_ImplVulkanH_Window g_MainWindowData;
|
||||
static uint32_t g_MinImageCount = 2;
|
||||
static bool g_SwapChainRebuild = false;
|
||||
static VkImageUsageFlags g_SwapChainImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
static void glfw_error_callback(int error, const char* description)
|
||||
{
|
||||
|
|
@ -240,7 +239,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface
|
|||
|
||||
// Create SwapChain, RenderPass, Framebuffer, etc.
|
||||
IM_ASSERT(g_MinImageCount >= 2);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, g_SwapChainImageUsage);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, 0);
|
||||
}
|
||||
|
||||
static void CleanupVulkan()
|
||||
|
|
@ -470,7 +469,7 @@ int main(int, char**)
|
|||
if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
|
||||
{
|
||||
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, g_SwapChainImageUsage);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, 0);
|
||||
g_MainWindowData.FrameIndex = 0;
|
||||
g_SwapChainRebuild = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
|
|||
static ImGui_ImplVulkanH_Window g_MainWindowData;
|
||||
static uint32_t g_MinImageCount = 2;
|
||||
static bool g_SwapChainRebuild = false;
|
||||
static VkImageUsageFlags g_SwapChainImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
static void check_vk_result(VkResult err)
|
||||
{
|
||||
|
|
@ -231,7 +230,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface
|
|||
|
||||
// Create SwapChain, RenderPass, Framebuffer, etc.
|
||||
IM_ASSERT(g_MinImageCount >= 2);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, g_SwapChainImageUsage);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, 0);
|
||||
}
|
||||
|
||||
static void CleanupVulkan()
|
||||
|
|
@ -490,7 +489,7 @@ int main(int, char**)
|
|||
if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
|
||||
{
|
||||
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, g_SwapChainImageUsage);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, 0);
|
||||
g_MainWindowData.FrameIndex = 0;
|
||||
g_SwapChainRebuild = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
|
|||
static ImGui_ImplVulkanH_Window g_MainWindowData;
|
||||
static uint32_t g_MinImageCount = 2;
|
||||
static bool g_SwapChainRebuild = false;
|
||||
static VkImageUsageFlags g_SwapChainImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
static void check_vk_result(VkResult err)
|
||||
{
|
||||
|
|
@ -233,7 +232,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface
|
|||
|
||||
// Create SwapChain, RenderPass, Framebuffer, etc.
|
||||
IM_ASSERT(g_MinImageCount >= 2);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, g_SwapChainImageUsage);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, 0);
|
||||
}
|
||||
|
||||
static void CleanupVulkan()
|
||||
|
|
@ -492,7 +491,7 @@ int main(int, char**)
|
|||
if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
|
||||
{
|
||||
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, fb_height, fb_height, g_MinImageCount, g_SwapChainImageUsage);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, fb_height, fb_height, g_MinImageCount, 0);
|
||||
g_MainWindowData.FrameIndex = 0;
|
||||
g_SwapChainRebuild = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,8 +103,8 @@ bool CreateDeviceD3D(HWND hWnd);
|
|||
void CleanupDeviceD3D();
|
||||
void CreateRenderTarget();
|
||||
void CleanupRenderTarget();
|
||||
void WaitForLastSubmittedFrame();
|
||||
FrameContext* WaitForNextFrameResources();
|
||||
void WaitForPendingOperations();
|
||||
FrameContext* WaitForNextFrameContext();
|
||||
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
// Main code
|
||||
|
|
@ -270,7 +270,7 @@ int main(int, char**)
|
|||
// Rendering
|
||||
ImGui::Render();
|
||||
|
||||
FrameContext* frameCtx = WaitForNextFrameResources();
|
||||
FrameContext* frameCtx = WaitForNextFrameContext();
|
||||
UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex();
|
||||
frameCtx->CommandAllocator->Reset();
|
||||
|
||||
|
|
@ -304,18 +304,17 @@ int main(int, char**)
|
|||
ImGui::RenderPlatformWindowsDefault();
|
||||
}
|
||||
|
||||
g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
|
||||
frameCtx->FenceValue = g_fenceLastSignaledValue;
|
||||
|
||||
// Present
|
||||
HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
|
||||
//HRESULT hr = g_pSwapChain->Present(0, g_tearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0); // Present without vsync
|
||||
g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
|
||||
|
||||
UINT64 fenceValue = g_fenceLastSignaledValue + 1;
|
||||
g_pd3dCommandQueue->Signal(g_fence, fenceValue);
|
||||
g_fenceLastSignaledValue = fenceValue;
|
||||
frameCtx->FenceValue = fenceValue;
|
||||
g_frameIndex++;
|
||||
}
|
||||
|
||||
WaitForLastSubmittedFrame();
|
||||
WaitForPendingOperations();
|
||||
|
||||
// Cleanup
|
||||
ImGui_ImplDX12_Shutdown();
|
||||
|
|
@ -496,49 +495,33 @@ void CreateRenderTarget()
|
|||
|
||||
void CleanupRenderTarget()
|
||||
{
|
||||
WaitForLastSubmittedFrame();
|
||||
WaitForPendingOperations();
|
||||
|
||||
for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++)
|
||||
if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] = nullptr; }
|
||||
}
|
||||
|
||||
void WaitForLastSubmittedFrame()
|
||||
void WaitForPendingOperations()
|
||||
{
|
||||
FrameContext* frameCtx = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT];
|
||||
g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
|
||||
|
||||
UINT64 fenceValue = frameCtx->FenceValue;
|
||||
if (fenceValue == 0)
|
||||
return; // No fence was signaled
|
||||
|
||||
frameCtx->FenceValue = 0;
|
||||
if (g_fence->GetCompletedValue() >= fenceValue)
|
||||
return;
|
||||
|
||||
g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent);
|
||||
WaitForSingleObject(g_fenceEvent, INFINITE);
|
||||
g_fence->SetEventOnCompletion(g_fenceLastSignaledValue, g_fenceEvent);
|
||||
::WaitForSingleObject(g_fenceEvent, INFINITE);
|
||||
}
|
||||
|
||||
FrameContext* WaitForNextFrameResources()
|
||||
FrameContext* WaitForNextFrameContext()
|
||||
{
|
||||
UINT nextFrameIndex = g_frameIndex + 1;
|
||||
g_frameIndex = nextFrameIndex;
|
||||
|
||||
HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, nullptr };
|
||||
DWORD numWaitableObjects = 1;
|
||||
|
||||
FrameContext* frameCtx = &g_frameContext[nextFrameIndex % APP_NUM_FRAMES_IN_FLIGHT];
|
||||
UINT64 fenceValue = frameCtx->FenceValue;
|
||||
if (fenceValue != 0) // means no fence was signaled
|
||||
FrameContext* frame_context = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT];
|
||||
if (g_fence->GetCompletedValue() < frame_context->FenceValue)
|
||||
{
|
||||
frameCtx->FenceValue = 0;
|
||||
g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent);
|
||||
waitableObjects[1] = g_fenceEvent;
|
||||
numWaitableObjects = 2;
|
||||
g_fence->SetEventOnCompletion(frame_context->FenceValue, g_fenceEvent);
|
||||
HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, g_fenceEvent };
|
||||
::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
|
||||
}
|
||||
else
|
||||
::WaitForSingleObject(g_hSwapChainWaitableObject, INFINITE);
|
||||
|
||||
WaitForMultipleObjects(numWaitableObjects, waitableObjects, TRUE, INFINITE);
|
||||
|
||||
return frameCtx;
|
||||
return frame_context;
|
||||
}
|
||||
|
||||
// Forward declare message handler from imgui_impl_win32.cpp
|
||||
|
|
@ -559,7 +542,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
case WM_SIZE:
|
||||
if (g_pd3dDevice != nullptr && wParam != SIZE_MINIMIZED)
|
||||
{
|
||||
WaitForLastSubmittedFrame();
|
||||
CleanupRenderTarget();
|
||||
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
||||
g_pSwapChain->GetDesc1(&desc);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
|
|||
static ImGui_ImplVulkanH_Window g_MainWindowData;
|
||||
static uint32_t g_MinImageCount = 2;
|
||||
static bool g_SwapChainRebuild = false;
|
||||
static VkImageUsageFlags g_SwapChainImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
static void check_vk_result(VkResult err)
|
||||
{
|
||||
|
|
@ -229,7 +228,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface
|
|||
|
||||
// Create SwapChain, RenderPass, Framebuffer, etc.
|
||||
IM_ASSERT(g_MinImageCount >= 2);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, g_SwapChainImageUsage);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, 0);
|
||||
}
|
||||
|
||||
static void CleanupVulkan()
|
||||
|
|
@ -583,7 +582,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
|
||||
{
|
||||
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, g_SwapChainImageUsage);
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, 0);
|
||||
g_MainWindowData.FrameIndex = 0;
|
||||
g_SwapChainRebuild = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5531,7 +5531,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|||
text_col, clip_rect.AsVec4(),
|
||||
line_index->get_line_begin(buf_display, line_visible_n0),
|
||||
line_index->get_line_end(buf_display, line_visible_n1 - 1),
|
||||
wrap_width, ImDrawTextFlags_WrapKeepBlanks);
|
||||
wrap_width, ImDrawTextFlags_WrapKeepBlanks | ImDrawTextFlags_CpuFineClip);
|
||||
|
||||
// Render blinking cursor
|
||||
if (render_cursor)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue