Backends, Examples: Added support for WebGPU and corresponding example. Amend 5853fbd (#3632)

This commit is contained in:
ocornut 2021-01-28 12:11:26 +01:00
parent 5853fbd68b
commit dff0044d4e
12 changed files with 114 additions and 157 deletions

1
.gitignore vendored
View File

@ -35,6 +35,7 @@ examples/*.o.tmp
examples/*.out.js examples/*.out.js
examples/*.out.wasm examples/*.out.wasm
examples/example_emscripten_opengl3/web/* examples/example_emscripten_opengl3/web/*
examples/example_emscripten_wgpu/web/*
## JetBrains IDE artifacts ## JetBrains IDE artifacts
.idea .idea

View File

@ -1,5 +1,5 @@
// dear imgui: Platform Backend for GLFW // dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+) // (Requires: GLFW 3.1+)
@ -63,7 +63,8 @@ enum GlfwClientApi
{ {
GlfwClientApi_Unknown, GlfwClientApi_Unknown,
GlfwClientApi_OpenGL, GlfwClientApi_OpenGL,
GlfwClientApi_Vulkan GlfwClientApi_Vulkan,
GlfwClientApi_WebGPU
}; };
static GLFWwindow* g_Window = NULL; // Main window static GLFWwindow* g_Window = NULL; // Main window
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown; static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
@ -231,6 +232,11 @@ bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
} }
bool ImGui_ImplGlfw_InitForWebGPU(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_WebGPU);
}
void ImGui_ImplGlfw_Shutdown() void ImGui_ImplGlfw_Shutdown()
{ {
if (g_InstalledCallbacks) if (g_InstalledCallbacks)

View File

@ -1,5 +1,5 @@
// dear imgui: Platform Backend for GLFW // dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// Implemented features: // Implemented features:
@ -23,6 +23,7 @@ struct GLFWwindow;
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForWebGPU(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();

View File

@ -1,5 +1,6 @@
// dear imgui: Renderer for WebGPU // dear imgui: Renderer for WebGPU
// This needs to be used along with a Platform Binding (e.g. GLFW) // This needs to be used along with a Platform Binding (e.g. GLFW)
// (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
@ -11,18 +12,15 @@
// 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)
// 2021-01-28: Initial version.
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_wgpu.h" #include "imgui_impl_wgpu.h"
// CRT
#include <limits.h> #include <limits.h>
// WebGPU
#include <webgpu/webgpu.h> #include <webgpu/webgpu.h>
// ImGui prototypes // Dear ImGui prototypes from imgui_internal.h
ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0); extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0);
// WebGPU data // WebGPU data
static WGPUDevice g_wgpuDevice = NULL; static WGPUDevice g_wgpuDevice = NULL;
@ -31,29 +29,14 @@ static WGPURenderPipeline g_pipelineState = NULL;
struct RenderResources struct RenderResources
{ {
// Font texture WGPUTexture FontTexture; // Font texture
WGPUTexture FontTexture; WGPUTextureView FontTextureView; // Texture view for font texture
WGPUSampler Sampler; // Sampler for the font texture
// Texture view for font texture WGPUBuffer Uniforms; // Shader uniforms
WGPUTextureView FontTextureView; WGPUBindGroup CommonBindGroup; // Resources bind-group to bind the common resources to pipeline
WGPUBindGroupLayout ImageBindGroupLayout; // Bind group layout for image textures
// Sampler for the font texture ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map)
WGPUSampler Sampler; WGPUBindGroup ImageBindGroup; // Default font-resource of Dear ImGui
// Shader uniforms
WGPUBuffer Uniforms;
// Resources bind-group to bind the common resources to pipeline
WGPUBindGroup CommonBindGroup;
// Bind group layout for image textures
WGPUBindGroupLayout ImageBindGroupLayout;
// Resources bind-group to bind the font/image resources to pipeline
ImGuiStorage ImageBindGroups;
// Default font-resource of ImGui
WGPUBindGroup ImageBindGroup;
}; };
static RenderResources g_resources; static RenderResources g_resources;
@ -285,9 +268,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(uint32_
static WGPUBindGroup ImGui_ImplWGPU_CreateImageBindGroup(WGPUBindGroupLayout layout, WGPUTextureView texture) static WGPUBindGroup ImGui_ImplWGPU_CreateImageBindGroup(WGPUBindGroupLayout layout, WGPUTextureView texture)
{ {
WGPUBindGroupEntry image_bg_entries[] = { WGPUBindGroupEntry image_bg_entries[] = { { 0, 0, 0, 0, 0, texture } };
{ 0, 0, 0, 0, 0, texture },
};
WGPUBindGroupDescriptor image_bg_descriptor = {}; WGPUBindGroupDescriptor image_bg_descriptor = {};
image_bg_descriptor.layout = layout; image_bg_descriptor.layout = layout;
@ -339,7 +320,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return; return;
// FIXME: I'm assuming that this only gets called once per frame! // FIXME: Assuming that this only gets called once per frame!
// If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator. // If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator.
g_frameIndex = g_frameIndex + 1; g_frameIndex = g_frameIndex + 1;
FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight]; FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight];
@ -351,9 +332,10 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
SafeRelease(fr->VertexBufferHost); SafeRelease(fr->VertexBufferHost);
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000; fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
WGPUBufferDescriptor vb_desc = { WGPUBufferDescriptor vb_desc =
nullptr, {
"IMGUI Vertex buffer", NULL,
"Dear ImGui Vertex buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex, WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex,
fr->VertexBufferSize * sizeof(ImDrawVert), fr->VertexBufferSize * sizeof(ImDrawVert),
false false
@ -370,9 +352,10 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
SafeRelease(fr->IndexBufferHost); SafeRelease(fr->IndexBufferHost);
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000; fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
WGPUBufferDescriptor ib_desc = { WGPUBufferDescriptor ib_desc =
nullptr, {
"IMGUI Index buffer", NULL,
"Dear ImGui Index buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index, WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index,
fr->IndexBufferSize * sizeof(ImDrawIdx), fr->IndexBufferSize * sizeof(ImDrawIdx),
false false
@ -427,13 +410,14 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
{ {
// Bind custom texture // Bind custom texture
auto bind_group = g_resources.ImageBindGroups.GetVoidPtr(ImHashData(&pcmd->TextureId, sizeof(ImTextureID))); auto bind_group = g_resources.ImageBindGroups.GetVoidPtr(ImHashData(&pcmd->TextureId, sizeof(ImTextureID)));
if (bind_group) { if (bind_group)
{
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, NULL); wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, NULL);
} }
else { else
{
WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(g_resources.ImageBindGroupLayout, (WGPUTextureView)pcmd->TextureId); WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(g_resources.ImageBindGroupLayout, (WGPUTextureView)pcmd->TextureId);
g_resources.ImageBindGroups.SetVoidPtr(ImHashData(&pcmd->TextureId, sizeof(ImTextureID)), image_bind_group); g_resources.ImageBindGroups.SetVoidPtr(ImHashData(&pcmd->TextureId, sizeof(ImTextureID)), image_bind_group);
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL); wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL);
} }
@ -464,7 +448,6 @@ static WGPUBuffer ImGui_ImplWGPU_CreateBufferFromData(const WGPUDevice& device,
return buffer; return buffer;
} }
static void ImGui_ImplWGPU_CreateFontsTexture() static void ImGui_ImplWGPU_CreateFontsTexture()
{ {
// Build texture atlas // Build texture atlas
@ -476,7 +459,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
// Upload texture to graphics system // Upload texture to graphics system
{ {
WGPUTextureDescriptor tex_desc = {}; WGPUTextureDescriptor tex_desc = {};
tex_desc.label = "IMGUI Font Texture"; tex_desc.label = "Dear ImGui Font Texture";
tex_desc.dimension = WGPUTextureDimension_2D; tex_desc.dimension = WGPUTextureDimension_2D;
tex_desc.size.width = width; tex_desc.size.width = width;
tex_desc.size.height = height; tex_desc.size.height = height;
@ -500,7 +483,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
// Upload texture data // Upload texture data
{ {
WGPUBuffer staging_buffer = ImGui_ImplWGPU_CreateBufferFromData(g_wgpuDevice, pixels, static_cast<uint32_t>(width * size_pp * height), WGPUBufferUsage_CopySrc); WGPUBuffer staging_buffer = ImGui_ImplWGPU_CreateBufferFromData(g_wgpuDevice, pixels, (uint32_t)(width * size_pp * height), WGPUBufferUsage_CopySrc);
WGPUBufferCopyView bufferCopyView = {}; WGPUBufferCopyView bufferCopyView = {};
bufferCopyView.buffer = staging_buffer; bufferCopyView.buffer = staging_buffer;
@ -516,7 +499,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
textureCopyView.aspect = WGPUTextureAspect_All; textureCopyView.aspect = WGPUTextureAspect_All;
#endif #endif
WGPUExtent3D copySize = { static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1 }; WGPUExtent3D copySize = { (uint32_t)width, (uint32_t)height, 1 };
WGPUCommandEncoderDescriptor enc_desc = {}; WGPUCommandEncoderDescriptor enc_desc = {};
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(g_wgpuDevice, &enc_desc); WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(g_wgpuDevice, &enc_desc);
@ -549,9 +532,10 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
static void ImGui_ImplWGPU_CreateUniformBuffer() static void ImGui_ImplWGPU_CreateUniformBuffer()
{ {
WGPUBufferDescriptor ub_desc = { WGPUBufferDescriptor ub_desc =
nullptr, {
"IMGUI Uniform buffer", NULL,
"Dear ImGui Uniform buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform, WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform,
sizeof(Uniforms), sizeof(Uniforms),
false false
@ -568,12 +552,10 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
// Create render pipeline // Create render pipeline
WGPURenderPipelineDescriptor graphics_pipeline_desc = {}; WGPURenderPipelineDescriptor graphics_pipeline_desc = {};
graphics_pipeline_desc.primitiveTopology = WGPUPrimitiveTopology_TriangleList; graphics_pipeline_desc.primitiveTopology = WGPUPrimitiveTopology_TriangleList;
graphics_pipeline_desc.sampleCount = 1; graphics_pipeline_desc.sampleCount = 1;
graphics_pipeline_desc.sampleMask = UINT_MAX; graphics_pipeline_desc.sampleMask = UINT_MAX;
WGPUBindGroupLayoutEntry common_bg_layout_entries[2] = {}; WGPUBindGroupLayoutEntry common_bg_layout_entries[2] = {};
common_bg_layout_entries[0].binding = 0; common_bg_layout_entries[0].binding = 0;
common_bg_layout_entries[0].visibility = WGPUShaderStage_Vertex; common_bg_layout_entries[0].visibility = WGPUShaderStage_Vertex;
@ -609,7 +591,8 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
graphics_pipeline_desc.vertexStage = vertex_shader_desc; graphics_pipeline_desc.vertexStage = vertex_shader_desc;
// Vertex input configuration // Vertex input configuration
WGPUVertexAttributeDescriptor attribute_binding_desc[] = { WGPUVertexAttributeDescriptor attribute_binding_desc[] =
{
{ WGPUVertexFormat_Float2, (uint64_t)IM_OFFSETOF(ImDrawVert, pos), 0 }, { WGPUVertexFormat_Float2, (uint64_t)IM_OFFSETOF(ImDrawVert, pos), 0 },
{ WGPUVertexFormat_Float2, (uint64_t)IM_OFFSETOF(ImDrawVert, uv), 1 }, { WGPUVertexFormat_Float2, (uint64_t)IM_OFFSETOF(ImDrawVert, uv), 1 },
{ WGPUVertexFormat_UChar4Norm, (uint64_t)IM_OFFSETOF(ImDrawVert, col), 2 }, { WGPUVertexFormat_UChar4Norm, (uint64_t)IM_OFFSETOF(ImDrawVert, col), 2 },
@ -665,7 +648,6 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
{ {
// Configure disabled state // Configure disabled state
depth_desc.format = WGPUTextureFormat_Undefined; depth_desc.format = WGPUTextureFormat_Undefined;
depth_desc.depthWriteEnabled = true; depth_desc.depthWriteEnabled = true;
depth_desc.depthCompare = WGPUCompareFunction_Always; depth_desc.depthCompare = WGPUCompareFunction_Always;
depth_desc.stencilReadMask = 0; depth_desc.stencilReadMask = 0;
@ -680,7 +662,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
depth_desc.stencilFront.passOp = WGPUStencilOperation_Keep; depth_desc.stencilFront.passOp = WGPUStencilOperation_Keep;
// No depth buffer corresponds to no configuration // No depth buffer corresponds to no configuration
graphics_pipeline_desc.depthStencilState = nullptr; graphics_pipeline_desc.depthStencilState = NULL;
} }
g_pipelineState = wgpuDeviceCreateRenderPipeline(g_wgpuDevice, &graphics_pipeline_desc); g_pipelineState = wgpuDeviceCreateRenderPipeline(g_wgpuDevice, &graphics_pipeline_desc);
@ -689,7 +671,8 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
ImGui_ImplWGPU_CreateUniformBuffer(); ImGui_ImplWGPU_CreateUniformBuffer();
// Create resource bind group // Create resource bind group
WGPUBindGroupEntry common_bg_entries[] = { WGPUBindGroupEntry common_bg_entries[] =
{
{ 0, g_resources.Uniforms, 0, sizeof(Uniforms), 0, 0 }, { 0, g_resources.Uniforms, 0, sizeof(Uniforms), 0, 0 },
{ 1, 0, 0, 0, g_resources.Sampler, 0 }, { 1, 0, 0, 0, g_resources.Sampler, 0 },
}; };
@ -724,10 +707,8 @@ void ImGui_ImplWGPU_InvalidateDeviceObjects()
io.Fonts->TexID = NULL; // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. io.Fonts->TexID = NULL; // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
for (unsigned int i = 0; i < g_numFramesInFlight; i++) for (unsigned int i = 0; i < g_numFramesInFlight; i++)
{
SafeRelease(g_pFrameResources[i]); SafeRelease(g_pFrameResources[i]);
} }
}
bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format) bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format)
{ {

View File

@ -1,5 +1,6 @@
// dear imgui: Renderer for WebGPU // dear imgui: Renderer for WebGPU
// This needs to be used along with a Platform Binding (e.g. GLFW) // This needs to be used along with a Platform Binding (e.g. GLFW)
// (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
@ -11,11 +12,8 @@
#pragma once #pragma once
#include "imgui.h" // IMGUI_IMPL_API #include "imgui.h" // IMGUI_IMPL_API
// WebGPU
#include <webgpu/webgpu.h> #include <webgpu/webgpu.h>
// cmd_list is the command list that the implementation will use to render imgui draw lists.
IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format); IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format);
IMGUI_IMPL_API void ImGui_ImplWGPU_Shutdown(); IMGUI_IMPL_API void ImGui_ImplWGPU_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame(); IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame();

View File

@ -80,35 +80,7 @@ The [example_emscripten_opengl3](https://github.com/ocornut/imgui/tree/master/ex
### Backends for third-party frameworks, graphics API or other languages ### Backends for third-party frameworks, graphics API or other languages
See https://github.com/ocornut/imgui/wiki/Bindings See https://github.com/ocornut/imgui/wiki/Bindings for the full list.
- AGS/Adventure Game Studio
- Amethyst
- bsf
- Cinder
- Cocos2d-x
- Diligent Engine
- Flexium,
- GML/Game Maker Studio2
- GTK3+OpenGL3
- Irrlicht Engine
- LÖVE+LUA
- Magnum
- NanoRT
- Nim Game Lib,
- Ogre
- openFrameworks
- OSG/OpenSceneGraph
- Orx
- px_render
- Qt/QtDirect3D
- SFML
- Sokol
- Unity
- Unreal Engine 4
- vtk
- Win32 GDI
etc.
### Recommended Backends ### Recommended Backends

View File

@ -59,6 +59,12 @@ Other Changes:
User needs to call ImGui_ImplVulkan_LoadFunctions() with their custom loader prior to other functions. User needs to call ImGui_ImplVulkan_LoadFunctions() with their custom loader prior to other functions.
- Backends: Metal: Fixed texture storage mode when building on Mac Catalyst. (#3748) [@Belinsky-L-V] - Backends: Metal: Fixed texture storage mode when building on Mac Catalyst. (#3748) [@Belinsky-L-V]
- Backends: OSX: Fixed mouse position not being reported when mouse buttons other than left one are down. (#3762) [@rokups] - Backends: OSX: Fixed mouse position not being reported when mouse buttons other than left one are down. (#3762) [@rokups]
- Backends: WebGPU: Added enderer backend for WebGPU support (imgui_impl_wgpu.cpp) (#3632) [@bfierz]
Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.
- Examples: WebGPU: Added Emscripten+WebGPU example. (#3632) [@bfierz]
- Backends: GLFW: Added ImGui_ImplGlfw_InitForWebGPU() init point. It currently has strictly no effect on anything,
but because some multi-viewport renderers require knowledge of the render stack in the Platform back-end, we're
adding it for consistency. (#3632)
----------------------------------------------------------------------- -----------------------------------------------------------------------
@ -94,7 +100,6 @@ Breaking Changes:
confusion with Tables API. Keep redirection enums (will obsolete). (#125, #513, #913, #1204, #1444, #2142, #2707) confusion with Tables API. Keep redirection enums (will obsolete). (#125, #513, #913, #1204, #1444, #2142, #2707)
- Renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature now applies - Renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature now applies
to other data structures. (#2636) to other data structures. (#2636)
- Backends: WebGPU: Added backend for WebGPU support in imgui_impl_wgpu [@bfierz]
Other Changes: Other Changes:

View File

@ -115,13 +115,13 @@ On most platforms and when using C++, **you should be able to use a combination
Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading one texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that. If you are an experienced programmer at ease with those concepts, it should take you less than two hours to integrate Dear ImGui in your custom engine. **Make sure to spend time reading the [FAQ](https://www.dearimgui.org/faq), comments, and some of the examples/ application!** Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading one texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that. If you are an experienced programmer at ease with those concepts, it should take you less than two hours to integrate Dear ImGui in your custom engine. **Make sure to spend time reading the [FAQ](https://www.dearimgui.org/faq), comments, and some of the examples/ application!**
Officially maintained backends/bindings (in repository): Officially maintained backends/bindings (in repository):
- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, OpenGL (legacy), OpenGL3/ES/ES2 (modern), Vulkan, Metal. - Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL (legacy), OpenGL3/ES/ES2 (modern), Vulkan, WebGPU.
- Platforms: GLFW, SDL2, Win32, Glut, OSX. - Platforms: GLFW, SDL2, Win32, Glut, OSX.
- Frameworks: Emscripten, Allegro5, Marmalade. - Frameworks: Emscripten, Allegro5, Marmalade.
[Third-party backends/bindings](https://github.com/ocornut/imgui/wiki/Bindings) wiki page: [Third-party backends/bindings](https://github.com/ocornut/imgui/wiki/Bindings) wiki page:
- Languages: C, C# and: Beef, ChaiScript, Crystal, D, Go, Haskell, Haxe/hxcpp, Java, JavaScript, Julia, Kotlin, Lobster, Lua, Odin, Pascal, PureBasic, Python, Ruby, Rust, Swift... - Languages: C, C# and: Beef, ChaiScript, Crystal, D, Go, Haskell, Haxe/hxcpp, Java, JavaScript, Julia, Kotlin, Lobster, Lua, Odin, Pascal, PureBasic, Python, Ruby, Rust, Swift...
- Frameworks: AGS/Adventure Game Studio, Amethyst, bsf, Cinder, Cocos2d-x, Diligent Engine, Flexium, GML/Game Maker Studio2, Godot, GTK3+OpenGL3, Irrlicht Engine, LÖVE+LUA, Magnum, NanoRT, nCine, Nim Game Lib, Ogre, openFrameworks, OSG/OpenSceneGraph, Orx, Photoshop, px_render, Qt/QtDirect3D, SFML, Sokol, Unity, Unreal Engine 4, vtk, Win32 GDI, WxWidgets. - Frameworks: AGS/Adventure Game Studio, Amethyst, Blender, bsf, Cinder, Cocos2d-x, Diligent Engine, Flexium, GML/Game Maker Studio2, GLEQ, Godot, GTK3+OpenGL3, Irrlicht Engine, LÖVE+LUA, Magnum, Monogame, NanoRT, nCine, Nim Game Lib, Nintendo 3DS & Switch (homebrew), Ogre, openFrameworks, OSG/OpenSceneGraph, Orx, Photoshop, px_render, Qt/QtDirect3D, SDL_Renderer, SFML, Sokol, Unity, Unreal Engine 4, vtk, VulkanHpp, VulkanSceneGraph, Win32 GDI, WxWidgets.
- Note that C bindings ([cimgui](https://github.com/cimgui/cimgui)) are auto-generated, you can use its json/lua output to generate bindings for other languages. - Note that C bindings ([cimgui](https://github.com/cimgui/cimgui)) are auto-generated, you can use its json/lua output to generate bindings for other languages.
[Useful widgets and extensions](https://github.com/ocornut/imgui/wiki/Useful-Widgets) wiki page: [Useful widgets and extensions](https://github.com/ocornut/imgui/wiki/Useful-Widgets) wiki page:

View File

@ -21,7 +21,7 @@ SDL_Window* g_Window = NULL;
SDL_GLContext g_GLContext = NULL; SDL_GLContext g_GLContext = NULL;
// For clarity, our main loop code is declared at the end. // For clarity, our main loop code is declared at the end.
void main_loop(void*); static void main_loop(void*);
int main(int, char**) int main(int, char**)
{ {
@ -99,7 +99,7 @@ int main(int, char**)
emscripten_set_main_loop_arg(main_loop, NULL, 0, true); emscripten_set_main_loop_arg(main_loop, NULL, 0, true);
} }
void main_loop(void* arg) static void main_loop(void* arg)
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
IM_UNUSED(arg); // We can pass this argument as the second parameter of emscripten_set_main_loop_arg(), but we don't use that. IM_UNUSED(arg); // We can pass this argument as the second parameter of emscripten_set_main_loop_arg(), but we don't use that.

View File

@ -6,18 +6,20 @@
# This Makefile assumes you have loaded emscripten's environment. # This Makefile assumes you have loaded emscripten's environment.
# (On Windows, you may need to execute emsdk_env.bat or encmdprompt.bat ahead) # (On Windows, you may need to execute emsdk_env.bat or encmdprompt.bat ahead)
# #
# Running `make` will produce two files: # Running `make` will produce three files:
# - example_emscripten_wgpu.js # - web/index.html (current stored in the repository)
# - example_emscripten_wgpu.wasm # - web/index.js
# - web/index.wasm
# #
# All three are needed to run the demo. # All three are needed to run the demo.
CC = emcc CC = emcc
CXX = em++ CXX = em++
EXE = example_emscripten_wgpu.js WEB_DIR = web
EXE = $(WEB_DIR)/index.js
IMGUI_DIR = ../.. IMGUI_DIR = ../..
SOURCES = main.cpp SOURCES = main.cpp
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s) UNAME_S := $(shell uname -s)
@ -47,7 +49,7 @@ endif
## FINAL BUILD FLAGS ## FINAL BUILD FLAGS
##--------------------------------------------------------------------- ##---------------------------------------------------------------------
CPPFLAGS += -I$(IMGUI_DIR)/ -I$(IMGUI_DIR)/backends CPPFLAGS = -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
#CPPFLAGS += -g #CPPFLAGS += -g
CPPFLAGS += -Wall -Wformat -Os CPPFLAGS += -Wall -Wformat -Os
CPPFLAGS += $(EMS) CPPFLAGS += $(EMS)
@ -61,9 +63,6 @@ LIBS += $(EMS)
%.o:%.cpp %.o:%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
%.o:../%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/%.cpp %.o:$(IMGUI_DIR)/%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
@ -73,8 +72,14 @@ LIBS += $(EMS)
all: $(EXE) all: $(EXE)
@echo Build complete for $(EXE) @echo Build complete for $(EXE)
$(EXE): $(OBJS) $(WEB_DIR):
$(CXX) -o $@ $^ $(LIBS) $(LDFLAGS) mkdir $@
serve: all
python3 -m http.server -d $(WEB_DIR)
$(EXE): $(OBJS) $(WEB_DIR)
$(CXX) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
clean: clean:
rm -f $(EXE) $(OBJS) *.js *.wasm *.wasm.pre rm -f $(EXE) $(OBJS) $(WEB_DIR)/*.js $(WEB_DIR)/*.wasm $(WEB_DIR)/*.wasm.pre

View File

@ -3,10 +3,6 @@
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs // Read online: https://github.com/ocornut/imgui/tree/master/docs
// This is mostly the same code as the SDL2 + OpenGL3 example, simply with the modifications needed to run on Emscripten.
// It is possible to combine both code into a single source file that will compile properly on Desktop and using Emscripten.
// See https://github.com/ocornut/imgui/pull/2492 as an example on how to do just that.
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "imgui_impl_wgpu.h" #include "imgui_impl_wgpu.h"
@ -22,7 +18,6 @@
static WGPUDevice wgpu_device = NULL; static WGPUDevice wgpu_device = NULL;
static WGPUSurface wgpu_surface = NULL; static WGPUSurface wgpu_surface = NULL;
static WGPUSwapChain wgpu_swap_chain = NULL; static WGPUSwapChain wgpu_swap_chain = NULL;
static int wgpu_swap_chain_width = 0; static int wgpu_swap_chain_width = 0;
static int wgpu_swap_chain_height = 0; static int wgpu_swap_chain_height = 0;
@ -31,11 +26,11 @@ static bool show_demo_window = true;
static bool show_another_window = false; static bool show_another_window = false;
static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Forward declartions // Forward declarations
bool init_wgpu(); static bool init_wgpu();
void main_loop(void* window); static void main_loop(void* window);
void print_glfw_error(int error, const char* description); static void print_glfw_error(int error, const char* description);
void print_wgpu_error(WGPUErrorType error_type, const char* message, void*); static void print_wgpu_error(WGPUErrorType error_type, const char* message, void*);
int main(int, char**) int main(int, char**)
{ {
@ -48,13 +43,15 @@ int main(int, char**)
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+WebGPU example", NULL, NULL); GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+WebGPU example", NULL, NULL);
if (!window) { if (!window)
{
glfwTerminate(); glfwTerminate();
return 1; return 1;
} }
// Initialize the WebGPU environment // Initialize the WebGPU environment
if (!init_wgpu()) { if (!init_wgpu())
{
if (window) if (window)
glfwDestroyWindow(window); glfwDestroyWindow(window);
glfwTerminate(); glfwTerminate();
@ -99,7 +96,7 @@ int main(int, char**)
//IM_ASSERT(font != NULL); //IM_ASSERT(font != NULL);
#endif #endif
// This function will directly return and extit he main function. // This function will directly return and exit the main function.
// Make sure that no required objects get cleaned up. // Make sure that no required objects get cleaned up.
// This way we can use the browsers 'requestAnimationFrame' to control the rendering. // This way we can use the browsers 'requestAnimationFrame' to control the rendering.
emscripten_set_main_loop_arg(main_loop, window, 0, false); emscripten_set_main_loop_arg(main_loop, window, 0, false);
@ -107,31 +104,31 @@ int main(int, char**)
return 0; return 0;
} }
bool init_wgpu() static bool init_wgpu()
{ {
wgpu_device = emscripten_webgpu_get_device(); wgpu_device = emscripten_webgpu_get_device();
if (!wgpu_device) if (!wgpu_device)
return false; return false;
wgpuDeviceSetUncapturedErrorCallback(wgpu_device, print_wgpu_error, nullptr); wgpuDeviceSetUncapturedErrorCallback(wgpu_device, print_wgpu_error, NULL);
// Use C++ wrapper due to malbehaviour in Emscripten. // Use C++ wrapper due to misbehavior in Emscripten.
// Some offset computation for wgpuInstanceCreateSurface in JavaScript // Some offset computation for wgpuInstanceCreateSurface in JavaScript
// seem to be inline with struct alignments in the C++ structure // seem to be inline with struct alignments in the C++ structure
wgpu::SurfaceDescriptorFromCanvasHTMLSelector html_surface_desc{}; wgpu::SurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {};
html_surface_desc.selector = "#canvas"; html_surface_desc.selector = "#canvas";
wgpu::SurfaceDescriptor surface_desc{}; wgpu::SurfaceDescriptor surface_desc = {};
surface_desc.nextInChain = &html_surface_desc; surface_desc.nextInChain = &html_surface_desc;
// Use 'null' instance // Use 'null' instance
wgpu::Instance instance{}; wgpu::Instance instance = {};
wgpu_surface = instance.CreateSurface(&surface_desc).Release(); wgpu_surface = instance.CreateSurface(&surface_desc).Release();
return true; return true;
} }
void main_loop(void* window) static void main_loop(void* window)
{ {
glfwPollEvents(); glfwPollEvents();
@ -202,7 +199,7 @@ void main_loop(void* window)
ImGui::End(); ImGui::End();
} }
// Render the generated ImGui frame // Rendering
ImGui::Render(); ImGui::Render();
WGPURenderPassColorAttachmentDescriptor color_attachments = {}; WGPURenderPassColorAttachmentDescriptor color_attachments = {};
@ -213,7 +210,7 @@ void main_loop(void* window)
WGPURenderPassDescriptor render_pass_desc = {}; WGPURenderPassDescriptor render_pass_desc = {};
render_pass_desc.colorAttachmentCount = 1; render_pass_desc.colorAttachmentCount = 1;
render_pass_desc.colorAttachments = &color_attachments; render_pass_desc.colorAttachments = &color_attachments;
render_pass_desc.depthStencilAttachment = nullptr; render_pass_desc.depthStencilAttachment = NULL;
WGPUCommandEncoderDescriptor enc_desc = {}; WGPUCommandEncoderDescriptor enc_desc = {};
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(wgpu_device, &enc_desc); WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(wgpu_device, &enc_desc);
@ -228,30 +225,21 @@ void main_loop(void* window)
wgpuQueueSubmit(queue, 1, &cmd_buffer); wgpuQueueSubmit(queue, 1, &cmd_buffer);
} }
void print_glfw_error(int error, const char* description) static void print_glfw_error(int error, const char* description)
{ {
printf("Glfw Error %d: %s\n", error, description); printf("Glfw Error %d: %s\n", error, description);
} }
void print_wgpu_error(WGPUErrorType error_type, const char* message, void*) static void print_wgpu_error(WGPUErrorType error_type, const char* message, void*)
{ {
const char* error_type_lbl = ""; const char* error_type_lbl = "";
switch (error_type) { switch (error_type)
case WGPUErrorType_Validation: {
error_type_lbl = "Validation"; case WGPUErrorType_Validation: error_type_lbl = "Validation"; break;
break; case WGPUErrorType_OutOfMemory: error_type_lbl = "Out of memory"; break;
case WGPUErrorType_OutOfMemory: case WGPUErrorType_Unknown: error_type_lbl = "Unknown"; break;
error_type_lbl = "Out of memory"; case WGPUErrorType_DeviceLost: error_type_lbl = "Device lost"; break;
break; default: error_type_lbl = "Unknown";
case WGPUErrorType_Unknown:
error_type_lbl = "Unknown";
break;
case WGPUErrorType_DeviceLost:
error_type_lbl = "Device lost";
break;
default:
error_type_lbl = "Unknown";
} }
printf("%s error: %s\n", error_type_lbl, message); printf("%s error: %s\n", error_type_lbl, message);
} }

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
<title>Dear ImGui Emscripten example</title> <title>Dear ImGui Emscripten+WebGPU example</title>
<style> <style>
body { margin: 0; background-color: black } body { margin: 0; background-color: black }
.emscripten { .emscripten {
@ -71,7 +71,7 @@
{ {
const js = document.createElement('script'); const js = document.createElement('script');
js.async = true; js.async = true;
js.src = "example_emscripten_wgpu.js"; js.src = "index.js";
document.body.appendChild(js); document.body.appendChild(js);
} }
})(); })();