8000 Add wgpu multiviewport support by Zelif · Pull Request #7557 · ocornut/imgui · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add wgpu multiviewport support #7557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: docking
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions backends/imgui_impl_wgpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,25 @@ struct ImGui_ImplWGPU_Data
WGPUTextureFormat renderTargetFormat = WGPUTextureFormat_Undefined;
WGPUTextureFormat depthStencilFormat = WGPUTextureFormat_Undefined;
WGPURenderPipeline pipelineState = nullptr;
WGPUPresentMode multiViewPresentMode = {};

RenderResources renderResources;
FrameResources* pFrameResources = nullptr;
unsigned int numFramesInFlight = 0;
unsigned int frameIndex = UINT_MAX;
};

// Forward declarations for multi-viewport support
static void ImGui_ImplWGPU_InitPlatformInterface();
static void ImGui_ImplWGPU_ShutdownPlatformInterface();

// For multi-viewport support:
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
struct ImGui_ImplWGPU_ViewportData
{
WGPUSurface wgpu_surface;
};

// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplWGPU_Data* ImGui_ImplWGPU_GetBackendData()
Expand Down Expand Up @@ -222,6 +234,31 @@ static void SafeRelease(WGPUTexture& res)
wgpuTextureRelease(res);
res = nullptr;
}
static void SafeRelease(WGPURenderPassEncoder& res)
{
if (res)
wgpuRenderPassEncoderRelease(res);
res = nullptr;
}
static void SafeRelease(WGPUCommandBuffer& res)
{
if (res)
wgpuCommandBufferRelease(res);
res = nullptr;
}
static void SafeRelease(WGPUCommandEncoder& res)
{
if (res)
wgpuCommandEncoderRelease(res);
res = nullptr;
}

static void SafeRelease(WGPUSurface& res)
{
if (res)
wgpuSurfaceRelease(res);
res = nullptr;
}

static void SafeRelease(RenderResources& res)
{
Expand Down Expand Up @@ -733,6 +770,9 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info)
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_webgpu";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#ifndef __EMSCRIPTEN__
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // Enable multiviewport on desktop.
#endif

bd->initInfo = *init_info;
bd->wgpuDevice = init_info->Device;
Expand All @@ -741,6 +781,7 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info)
bd->depthStencilFormat = init_info->DepthStencilFormat;
bd->numFramesInFlight = init_info->NumFramesInFlight;
bd->frameIndex = UINT_MAX;
bd->multiViewPresentMode = init_info->ViewportPresentMode;

bd->renderResources.FontTexture = nullptr;
bd->renderResources.FontTextureView = nullptr;
Expand All @@ -764,6 +805,13 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info)
fr->VertexBufferSize = 5000;
}

if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
IM_ASSERT(init_info->CreateViewportWindowFn != nullptr && "Window creation callback required for multi viewport!");
IM_ASSERT(init_info->ViewportPresentMode != ~0 && "WGPUPresentMode required to be set for multi viewport!");
ImGui_ImplWGPU_InitPlatformInterface();
}

return true;
}

Expand All @@ -781,6 +829,10 @@ void ImGui_ImplWGPU_Shutdown()
bd->numFramesInFlight = 0;
bd->frameIndex = UINT_MAX;

// Clean up windows
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplWGPU_ShutdownPlatformInterface();

io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
Expand All @@ -794,6 +846,121 @@ void ImGui_ImplWGPU_NewFrame()
ImGui_ImplWGPU_CreateDeviceObjects();
}

//--------------------------------------------------------------------------------------------------------
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
//--------------------------------------------------------------------------------------------------------


static void ImGui_ImplWGPU_CreateWindow(ImGuiViewport* viewport)
{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
ImGui_ImplWGPU_ViewportData* vd = IM_NEW(ImGui_ImplWGPU_ViewportData)();
viewport->RendererUserData = vd;

vd->wgpu_surface = bd->initInfo.CreateViewportWindowFn(viewport);

WGPUSurfaceConfiguration surfaceConfig = {};
surfaceConfig.device = bd->wgpuDevice;
surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
surfaceConfig.format = bd->renderTargetFormat;
surfaceConfig.width = viewport->Size.x;
surfaceConfig.height = viewport->Size.y;
surfaceConfig.presentMode = bd->multiViewPresentMode;

wgpuSurfaceConfigure(vd->wgpu_surface , &surfaceConfig);
}


static void ImGui_ImplWGPU_DestroyWindow(ImGuiViewport* viewport)
{
if (ImGui_ImplWGPU_ViewportData* vd = (ImGui_ImplWGPU_ViewportData*)viewport->RendererUserData)
{
SafeRelease(vd->wgpu_surface);
IM_DELETE(vd);
}
viewport->RendererUserData = nullptr;
}


static void ImGui_ImplWGPU_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
ImGui_ImplWGPU_ViewportData* vd = (ImGui_ImplWGPU_ViewportData*)viewport->RendererUserData;

WGPUSurfaceConfiguration surfaceConfig = {};
surfaceConfig.device = bd->wgpuDevice;
surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
surfaceConfig.format = bd->renderTargetFormat;
surfaceConfig.width = viewport->Size.x;
surfaceConfig.height = viewport->Size.y;
surfaceConfig.presentMode = bd->multiViewPresentMode;

wgpuSurfaceConfigure(vd->wgpu_surface , &surfaceConfig);
}

static void ImGui_ImplWGPU_RenderWindow(ImGuiViewport* viewport, void*)
{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
ImGui_ImplWGPU_ViewportData* vd = (ImGui_ImplWGPU_ViewportData*)viewport->RendererUserData;

ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
WGPUSurfaceTexture surfaceTexture;
wgpuSurfaceGetCurrentTexture(vd->wgpu_surface, &surfaceTexture);
WGPURenderPassColorAttachment color_attachments = {};
color_attachments.view = wgpuTextureCreateView(surfaceTexture.texture, nullptr);
color_attachments.loadOp = WGPULoadOp_Clear;
color_attachments.storeOp = WGPUStoreOp_Store;
color_attachments.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
color_attachments.clearValue = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w };

WGPURenderPassDescriptor render_pass_desc = {};
render_pass_desc.colorAttachmentCount = 1;
render_pass_desc.colorAttachments = &color_attachments;
render_pass_desc.depthStencilAttachment = nullptr;

WGPUCommandEncoderDescriptor enc_desc = {};
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(bd->wgpuDevice, &enc_desc);

WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &render_pass_desc);
ImGui_ImplWGPU_RenderDrawData(viewport->DrawData, pass);
wgpuRenderPassEncoderEnd(pass);

WGPUCommandBufferDescriptor cmd_buffer_desc = {};
WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish(encoder, &cmd_buffer_desc);
WGPUQueue queue = wgpuDeviceGetQueue(bd->wgpuDevice);
wgpuQueueSubmit(queue, 1, &cmd_buffer);

SafeRelease(surfaceTexture.texture);
SafeRelease(color_attachments.view);
SafeRelease(pass);
SafeRelease(encoder);
SafeRelease(cmd_buffer);
}


static void ImGui_ImplWGPU_SwapBuffers(ImGuiViewport* viewport, void*)
{
ImGui_ImplWGPU_ViewportData* vd = (ImGui_ImplWGPU_ViewportData*)viewport->RendererUserData;
wgpuSurfacePresent(vd->wgpu_surface);
}

void ImGui_ImplWGPU_InitPlatformInterface()
{
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO( ED4F );
platform_io.Renderer_CreateWindow = ImGui_ImplWGPU_CreateWindow;
platform_io.Renderer_DestroyWindow = ImGui_ImplWGPU_DestroyWindow;
platform_io.Renderer_SetWindowSize = ImGui_ImplWGPU_SetWindowSize;
platform_io.Renderer_RenderWindow = ImGui_ImplWGPU_RenderWindow;
platform_io.Renderer_SwapBuffers = ImGui_ImplWGPU_SwapBuffers;
}

void ImGui_ImplWGPU_ShutdownPlatformInterface()
{
ImGui::DestroyPlatformWindows();
}

//-----------------------------------------------------------------------------

#endif // #ifndef IMGUI_DISABLE
2 changes: 2 additions & 0 deletions backends/imgui_impl_wgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct ImGui_ImplWGPU_InitInfo
WGPUTextureFormat RenderTargetFormat = WGPUTextureFormat_Undefined;
WGPUTextureFormat DepthStencilFormat = WGPUTextureFormat_Undefined;
WGPUMultisampleState PipelineMultisampleState = {};
WGPUPresentMode ViewportPresentMode = {};
WGPUSurface (*CreateViewportWindowFn)(ImGuiViewport* viewport) = nullptr;

ImGui_ImplWGPU_InitInfo()
{
Expand Down
20 changes: 18 additions & 2 deletions examples/example_glfw_wgpu/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static WGPUInstance wgpu_instance = nullptr;
static WGPUDevice wgpu_device = nullptr;
static WGPUSurface wgpu_surface = nullptr;
static WGPUTextureFormat wgpu_preferred_fmt = WGPUTextureFormat_RGBA8Unorm;
static WGPUPresentMode wgpu_present_mode = WGPUPresentMode_Fifo;
static WGPUSwapChain wgpu_swap_chain = nullptr;
static int wgpu_swap_chain_width = 1280;
static int wgpu_swap_chain_height = 720;
Expand Down Expand Up @@ -93,6 +94,8 @@ int main(int, char**)
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;

// Setup Dear ImGui style
ImGui::StyleColorsDark();
Expand All @@ -108,6 +111,10 @@ int main(int, char**)
init_info.NumFramesInFlight = 3;
init_info.RenderTargetFormat = wgpu_preferred_fmt;
init_info.DepthStencilFormat = WGPUTextureFormat_Undefined;
init_info.ViewportPresentMode = wgpu_present_mode;
init_info.CreateViewportWindowFn = [](ImGuiViewport* viewport) {
return wgpu::glfw::CreateSurfaceForWindow(wgpu_instance, (GLFWwindow*) viewport->PlatformHandle).MoveToCHandle();
};
ImGui_ImplWGPU_Init(&init_info);

// Load Fonts
Expand Down Expand Up @@ -236,6 +243,12 @@ int main(int, char**)
WGPUQueue queue = wgpuDeviceGetQueue(wgpu_device);
wgpuQueueSubmit(queue, 1, &cmd_buffer);

if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}

#ifndef __EMSCRIPTEN__
wgpuSwapChainPresent(wgpu_swap_chain);
#endif
Expand Down Expand Up @@ -269,7 +282,7 @@ static WGPUAdapter RequestAdapter(WGPUInstance instance)
*(WGPUAdapter*)(pUserData) = adapter;
else
printf("Could not get WebGPU adapter: %s\n", message);
};
};
WGPUAdapter adapter;
wgpuInstanceRequestAdapter(instance, nullptr, onAdapterRequestEnded, (void*)&adapter);
return adapter;
Expand Down Expand Up @@ -318,7 +331,10 @@ static bool InitWGPU(GLFWwindow* window)
wgpu::Surface surface = wgpu::glfw::CreateSurfaceForWindow(instance, window);
if (!surface)
return false;
wgpu_preferred_fmt = WGPUTextureFormat_BGRA8Unorm;
wgpu::SurfaceCapabilities capabilities;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be questioned, so I will explain this.
This gets the first available texture format and presentation mode for the surface, on linux current with dawn since there is no FiFo presentation mode for vulkan the example will not work for linux.
This solves it, it will get the first available presentation mode which in most system the first one is FiFo and on linux will be Mailbox.

surface.GetCapabilities(adapter, &capabilities);
wgpu_preferred_fmt = (WGPUTextureFormat) capabilities.formats[0];
wgpu_present_mode = (WGPUPresentMode) capabilities.presentModes[0];
#endif

wgpu_instance = instance.MoveToCHandle();
Expand Down
0