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

View File

@ -1,5 +1,5 @@
// 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.)
// (Requires: GLFW 3.1+)
@ -63,7 +63,8 @@ enum GlfwClientApi
{
GlfwClientApi_Unknown,
GlfwClientApi_OpenGL,
GlfwClientApi_Vulkan
GlfwClientApi_Vulkan,
GlfwClientApi_WebGPU
};
static GLFWwindow* g_Window = NULL; // Main window
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);
}
bool ImGui_ImplGlfw_InitForWebGPU(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_WebGPU);
}
void ImGui_ImplGlfw_Shutdown()
{
if (g_InstalledCallbacks)

View File

@ -1,5 +1,5 @@
// 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.)
// 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_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_NewFrame();

View File

@ -1,5 +1,6 @@
// dear imgui: Renderer for WebGPU
// 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:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
@ -11,51 +12,33 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-01-28: Initial version.
#include "imgui.h"
#include "imgui_impl_wgpu.h"
// CRT
#include <limits.h>
// WebGPU
#include <webgpu/webgpu.h>
// ImGui prototypes
ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0);
// Dear ImGui prototypes from imgui_internal.h
extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0);
// WebGPU data
static WGPUDevice g_wgpuDevice = NULL;
static WGPUTextureFormat g_renderTargetFormat = WGPUTextureFormat_Undefined;
static WGPURenderPipeline g_pipelineState = NULL;
static WGPUDevice g_wgpuDevice = NULL;
static WGPUTextureFormat g_renderTargetFormat = WGPUTextureFormat_Undefined;
static WGPURenderPipeline g_pipelineState = NULL;
struct RenderResources
{
// Font texture
WGPUTexture FontTexture;
// Texture view for font texture
WGPUTextureView FontTextureView;
// Sampler for the font texture
WGPUSampler Sampler;
// 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;
WGPUTexture FontTexture; // Font texture
WGPUTextureView FontTextureView; // Texture view for font texture
WGPUSampler Sampler; // Sampler for the font texture
WGPUBuffer Uniforms; // Shader uniforms
WGPUBindGroup CommonBindGroup; // Resources bind-group to bind the common resources to pipeline
WGPUBindGroupLayout ImageBindGroupLayout; // Bind group layout for image textures
ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map)
WGPUBindGroup ImageBindGroup; // Default font-resource of Dear ImGui
};
static RenderResources g_resources;
static RenderResources g_resources;
struct FrameResources
{
@ -285,9 +268,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(uint32_
static WGPUBindGroup ImGui_ImplWGPU_CreateImageBindGroup(WGPUBindGroupLayout layout, WGPUTextureView texture)
{
WGPUBindGroupEntry image_bg_entries[] = {
{ 0, 0, 0, 0, 0, texture },
};
WGPUBindGroupEntry image_bg_entries[] = { { 0, 0, 0, 0, 0, texture } };
WGPUBindGroupDescriptor image_bg_descriptor = {};
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)
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.
g_frameIndex = g_frameIndex + 1;
FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight];
@ -351,9 +332,10 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
SafeRelease(fr->VertexBufferHost);
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
WGPUBufferDescriptor vb_desc = {
nullptr,
"IMGUI Vertex buffer",
WGPUBufferDescriptor vb_desc =
{
NULL,
"Dear ImGui Vertex buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex,
fr->VertexBufferSize * sizeof(ImDrawVert),
false
@ -370,9 +352,10 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
SafeRelease(fr->IndexBufferHost);
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
WGPUBufferDescriptor ib_desc = {
nullptr,
"IMGUI Index buffer",
WGPUBufferDescriptor ib_desc =
{
NULL,
"Dear ImGui Index buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index,
fr->IndexBufferSize * sizeof(ImDrawIdx),
false
@ -427,13 +410,14 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
{
// Bind custom texture
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);
}
else {
WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(g_resources.ImageBindGroupLayout, (WGPUTextureView) pcmd->TextureId);
else
{
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);
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL);
}
@ -464,7 +448,6 @@ static WGPUBuffer ImGui_ImplWGPU_CreateBufferFromData(const WGPUDevice& device,
return buffer;
}
static void ImGui_ImplWGPU_CreateFontsTexture()
{
// Build texture atlas
@ -476,7 +459,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
// Upload texture to graphics system
{
WGPUTextureDescriptor tex_desc = {};
tex_desc.label = "IMGUI Font Texture";
tex_desc.label = "Dear ImGui Font Texture";
tex_desc.dimension = WGPUTextureDimension_2D;
tex_desc.size.width = width;
tex_desc.size.height = height;
@ -500,7 +483,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
// 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 = {};
bufferCopyView.buffer = staging_buffer;
@ -516,7 +499,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
textureCopyView.aspect = WGPUTextureAspect_All;
#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 = {};
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(g_wgpuDevice, &enc_desc);
@ -549,9 +532,10 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
static void ImGui_ImplWGPU_CreateUniformBuffer()
{
WGPUBufferDescriptor ub_desc = {
nullptr,
"IMGUI Uniform buffer",
WGPUBufferDescriptor ub_desc =
{
NULL,
"Dear ImGui Uniform buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform,
sizeof(Uniforms),
false
@ -568,12 +552,10 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
// Create render pipeline
WGPURenderPipelineDescriptor graphics_pipeline_desc = {};
graphics_pipeline_desc.primitiveTopology = WGPUPrimitiveTopology_TriangleList;
graphics_pipeline_desc.sampleCount = 1;
graphics_pipeline_desc.sampleMask = UINT_MAX;
WGPUBindGroupLayoutEntry common_bg_layout_entries[2] = {};
common_bg_layout_entries[0].binding = 0;
common_bg_layout_entries[0].visibility = WGPUShaderStage_Vertex;
@ -609,7 +591,8 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
graphics_pipeline_desc.vertexStage = vertex_shader_desc;
// 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, uv), 1 },
{ WGPUVertexFormat_UChar4Norm, (uint64_t)IM_OFFSETOF(ImDrawVert, col), 2 },
@ -665,7 +648,6 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
{
// Configure disabled state
depth_desc.format = WGPUTextureFormat_Undefined;
depth_desc.depthWriteEnabled = true;
depth_desc.depthCompare = WGPUCompareFunction_Always;
depth_desc.stencilReadMask = 0;
@ -680,7 +662,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
depth_desc.stencilFront.passOp = WGPUStencilOperation_Keep;
// 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);
@ -689,7 +671,8 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
ImGui_ImplWGPU_CreateUniformBuffer();
// Create resource bind group
WGPUBindGroupEntry common_bg_entries[] = {
WGPUBindGroupEntry common_bg_entries[] =
{
{ 0, g_resources.Uniforms, 0, sizeof(Uniforms), 0, 0 },
{ 1, 0, 0, 0, g_resources.Sampler, 0 },
};
@ -724,9 +707,7 @@ void ImGui_ImplWGPU_InvalidateDeviceObjects()
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++)
{
SafeRelease(g_pFrameResources[i]);
}
}
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
// 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:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
@ -10,12 +11,9 @@
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
// WebGPU
#include "imgui.h" // IMGUI_IMPL_API
#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 void ImGui_ImplWGPU_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame();