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,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)