2022-07-27 11:25:25 -04:00
|
|
|
#include "imgui.hpp"
|
|
|
|
|
|
2025-04-03 00:12:22 -06:00
|
|
|
#include <cstddef>
|
2026-05-11 19:48:15 -06:00
|
|
|
#include <cmath>
|
2026-06-04 23:43:13 -06:00
|
|
|
#include <cstring>
|
|
|
|
|
#include <memory>
|
2025-04-03 00:12:22 -06:00
|
|
|
#include <string>
|
2026-06-04 23:43:13 -06:00
|
|
|
#include <utility>
|
2025-04-03 00:12:22 -06:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include <webgpu/webgpu_cpp.h>
|
2026-05-01 21:52:55 -06:00
|
|
|
#include <SDL3/SDL_events.h>
|
2025-04-04 22:01:52 -06:00
|
|
|
#include <SDL3/SDL_render.h>
|
2025-04-03 00:12:22 -06:00
|
|
|
|
2022-07-27 11:25:25 -04:00
|
|
|
#include "internal.hpp"
|
2026-06-04 23:43:13 -06:00
|
|
|
#include "gfx/render_worker.hpp"
|
2025-04-03 00:12:22 -06:00
|
|
|
#include "webgpu/gpu.hpp"
|
2022-07-27 11:25:25 -04:00
|
|
|
#include "window.hpp"
|
|
|
|
|
|
2025-04-03 00:12:22 -06:00
|
|
|
#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN
|
2025-04-04 22:01:52 -06:00
|
|
|
#include "backends/imgui_impl_sdl3.h"
|
|
|
|
|
#include "backends/imgui_impl_sdlrenderer3.h"
|
|
|
|
|
#include "backends/imgui_impl_wgpu.h"
|
2026-04-09 03:19:58 +02:00
|
|
|
#include "tracy/Tracy.hpp"
|
2022-07-27 11:25:25 -04:00
|
|
|
|
|
|
|
|
namespace aurora::imgui {
|
|
|
|
|
static float g_scale;
|
|
|
|
|
static std::string g_imguiSettings{};
|
|
|
|
|
static std::string g_imguiLog{};
|
|
|
|
|
static bool g_useSdlRenderer = false;
|
|
|
|
|
|
|
|
|
|
static std::vector<SDL_Texture*> g_sdlTextures;
|
2022-08-02 16:37:56 -04:00
|
|
|
static std::vector<wgpu::Texture> g_wgpuTextures;
|
2022-07-27 11:25:25 -04:00
|
|
|
|
2026-06-04 23:43:13 -06:00
|
|
|
struct DrawData::Impl {
|
|
|
|
|
ImDrawData drawData;
|
|
|
|
|
std::vector<std::unique_ptr<ImDrawList>> drawLists;
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-27 11:25:25 -04:00
|
|
|
void create_context() noexcept {
|
|
|
|
|
IMGUI_CHECKVERSION();
|
|
|
|
|
ImGui::CreateContext();
|
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
2026-05-13 00:45:19 -06:00
|
|
|
g_imguiSettings = std::string{g_config.userPath} + "/imgui.ini";
|
|
|
|
|
g_imguiLog = std::string{g_config.cachePath} + "/imgui.log";
|
2022-07-27 11:25:25 -04:00
|
|
|
io.IniFilename = g_imguiSettings.c_str();
|
|
|
|
|
io.LogFilename = g_imguiLog.c_str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initialize() noexcept {
|
2026-04-09 03:19:58 +02:00
|
|
|
ZoneScoped;
|
2022-07-27 11:25:25 -04:00
|
|
|
SDL_Renderer* renderer = window::get_sdl_renderer();
|
2025-04-04 22:01:52 -06:00
|
|
|
ImGui_ImplSDL3_InitForSDLRenderer(window::get_sdl_window(), renderer);
|
2022-07-27 11:25:25 -04:00
|
|
|
g_useSdlRenderer = renderer != nullptr;
|
|
|
|
|
if (g_useSdlRenderer) {
|
2025-04-02 19:57:16 -06:00
|
|
|
ImGui_ImplSDLRenderer3_Init(renderer);
|
2022-07-27 11:25:25 -04:00
|
|
|
} else {
|
2025-04-03 00:12:22 -06:00
|
|
|
ImGui_ImplWGPU_InitInfo info;
|
|
|
|
|
info.Device = webgpu::g_device.Get();
|
|
|
|
|
info.RenderTargetFormat = static_cast<WGPUTextureFormat>(webgpu::g_graphicsConfig.surfaceConfiguration.format);
|
|
|
|
|
ImGui_ImplWGPU_Init(&info);
|
2022-07-27 11:25:25 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void shutdown() noexcept {
|
2026-04-09 03:19:58 +02:00
|
|
|
ZoneScoped;
|
2022-07-27 11:25:25 -04:00
|
|
|
if (g_useSdlRenderer) {
|
2025-04-02 19:57:16 -06:00
|
|
|
ImGui_ImplSDLRenderer3_Shutdown();
|
2022-07-27 11:25:25 -04:00
|
|
|
} else {
|
|
|
|
|
ImGui_ImplWGPU_Shutdown();
|
|
|
|
|
}
|
2025-04-02 19:57:16 -06:00
|
|
|
ImGui_ImplSDL3_Shutdown();
|
2022-07-27 11:25:25 -04:00
|
|
|
ImGui::DestroyContext();
|
|
|
|
|
for (const auto& texture : g_sdlTextures) {
|
|
|
|
|
SDL_DestroyTexture(texture);
|
|
|
|
|
}
|
|
|
|
|
g_sdlTextures.clear();
|
|
|
|
|
g_wgpuTextures.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void process_event(const SDL_Event& event) noexcept {
|
2026-05-11 19:48:15 -06:00
|
|
|
auto renderEvent = event;
|
|
|
|
|
if (g_useSdlRenderer) {
|
|
|
|
|
if (SDL_Renderer* renderer = window::get_sdl_renderer()) {
|
|
|
|
|
SDL_ConvertEventToRenderCoordinates(renderer, &renderEvent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ImGui_ImplSDL3_ProcessEvent(&renderEvent);
|
2022-07-27 11:25:25 -04:00
|
|
|
}
|
|
|
|
|
|
2026-05-01 21:52:55 -06:00
|
|
|
bool wants_capture_event(const SDL_Event& event) noexcept {
|
|
|
|
|
if (ImGui::GetCurrentContext() == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ImGuiIO& io = ImGui::GetIO();
|
|
|
|
|
switch (event.type) {
|
|
|
|
|
case SDL_EVENT_MOUSE_MOTION:
|
|
|
|
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
|
|
|
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
|
|
|
|
case SDL_EVENT_MOUSE_WHEEL:
|
|
|
|
|
case SDL_EVENT_FINGER_DOWN:
|
|
|
|
|
case SDL_EVENT_FINGER_MOTION:
|
|
|
|
|
case SDL_EVENT_FINGER_UP:
|
|
|
|
|
case SDL_EVENT_FINGER_CANCELED:
|
|
|
|
|
return io.WantCaptureMouse;
|
|
|
|
|
case SDL_EVENT_KEY_DOWN:
|
|
|
|
|
case SDL_EVENT_KEY_UP:
|
|
|
|
|
case SDL_EVENT_TEXT_INPUT:
|
|
|
|
|
return io.WantCaptureKeyboard || io.WantTextInput;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-27 11:25:25 -04:00
|
|
|
void new_frame(const AuroraWindowSize& size) noexcept {
|
2026-04-09 03:19:58 +02:00
|
|
|
ZoneScoped;
|
2026-05-11 19:48:15 -06:00
|
|
|
ImVec2 framebufferScale{
|
|
|
|
|
size.width > 0 ? static_cast<float>(size.native_fb_width) / static_cast<float>(size.width) : 1.0f,
|
|
|
|
|
size.height > 0 ? static_cast<float>(size.native_fb_height) / static_cast<float>(size.height) : 1.0f,
|
|
|
|
|
};
|
|
|
|
|
ImVec2 displaySize{static_cast<float>(size.width), static_cast<float>(size.height)};
|
2026-04-05 19:35:52 +02:00
|
|
|
|
2022-07-27 11:25:25 -04:00
|
|
|
if (g_useSdlRenderer) {
|
2026-05-11 19:48:15 -06:00
|
|
|
if (SDL_Renderer* renderer = window::get_sdl_renderer()) {
|
|
|
|
|
float renderScaleX = 1.0f;
|
|
|
|
|
float renderScaleY = 1.0f;
|
|
|
|
|
SDL_GetRenderScale(renderer, &renderScaleX, &renderScaleY);
|
|
|
|
|
if (renderScaleX > 0.0f && renderScaleY > 0.0f &&
|
|
|
|
|
(std::fabs(renderScaleX - 1.0f) > 0.0001f || std::fabs(renderScaleY - 1.0f) > 0.0001f)) {
|
|
|
|
|
int outputWidth = static_cast<int>(size.native_fb_width);
|
|
|
|
|
int outputHeight = static_cast<int>(size.native_fb_height);
|
|
|
|
|
SDL_GetRenderOutputSize(renderer, &outputWidth, &outputHeight);
|
|
|
|
|
displaySize = {
|
|
|
|
|
static_cast<float>(outputWidth) / renderScaleX,
|
|
|
|
|
static_cast<float>(outputHeight) / renderScaleY,
|
|
|
|
|
};
|
|
|
|
|
framebufferScale = {renderScaleX, renderScaleY};
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-02 19:57:16 -06:00
|
|
|
ImGui_ImplSDLRenderer3_NewFrame();
|
2023-05-27 11:44:36 -04:00
|
|
|
g_scale = size.scale;
|
2022-07-27 11:25:25 -04:00
|
|
|
} else {
|
|
|
|
|
if (g_scale != size.scale) {
|
|
|
|
|
if (g_scale > 0.f) {
|
|
|
|
|
ImGui_ImplWGPU_CreateDeviceObjects();
|
|
|
|
|
}
|
|
|
|
|
g_scale = size.scale;
|
|
|
|
|
}
|
2026-05-11 01:22:44 +02:00
|
|
|
if (!ImGui::GetIO().Fonts->IsBuilt()) {
|
|
|
|
|
ImGui_ImplWGPU_CreateDeviceObjects();
|
|
|
|
|
}
|
2022-07-27 11:25:25 -04:00
|
|
|
ImGui_ImplWGPU_NewFrame();
|
|
|
|
|
}
|
2025-04-02 19:57:16 -06:00
|
|
|
ImGui_ImplSDL3_NewFrame();
|
2022-07-27 11:25:25 -04:00
|
|
|
|
2026-04-05 19:35:52 +02:00
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
2026-05-11 19:48:15 -06:00
|
|
|
io.DisplayFramebufferScale = framebufferScale;
|
|
|
|
|
ImGui::GetIO().DisplaySize = displaySize;
|
2022-07-27 11:25:25 -04:00
|
|
|
ImGui::NewFrame();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-04 23:43:13 -06:00
|
|
|
DrawData freeze() noexcept {
|
2026-04-09 03:19:58 +02:00
|
|
|
ZoneScoped;
|
2022-07-27 11:25:25 -04:00
|
|
|
ImGui::Render();
|
|
|
|
|
|
|
|
|
|
auto* data = ImGui::GetDrawData();
|
2026-04-05 19:35:52 +02:00
|
|
|
data->FramebufferScale = ImGui::GetIO().DisplayFramebufferScale;
|
2026-06-04 23:43:13 -06:00
|
|
|
auto frozen = std::make_shared<DrawData::Impl>();
|
|
|
|
|
frozen->drawData = *data;
|
|
|
|
|
frozen->drawLists.reserve(data->CmdListsCount);
|
|
|
|
|
frozen->drawData.CmdLists.resize(data->CmdListsCount);
|
|
|
|
|
for (int i = 0; i < data->CmdListsCount; ++i) {
|
|
|
|
|
frozen->drawLists.emplace_back(data->CmdLists[i]->CloneOutput());
|
|
|
|
|
frozen->drawData.CmdLists[i] = frozen->drawLists.back().get();
|
|
|
|
|
}
|
|
|
|
|
return DrawData{std::move(frozen)};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void render(const wgpu::RenderPassEncoder& pass, const DrawData& drawData) noexcept {
|
|
|
|
|
ZoneScoped;
|
|
|
|
|
|
|
|
|
|
if (!drawData.m_impl) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto* data = &drawData.m_impl->drawData;
|
|
|
|
|
if (data->CmdListsCount == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-07-27 11:25:25 -04:00
|
|
|
if (g_useSdlRenderer) {
|
2025-04-04 22:01:52 -06:00
|
|
|
SDL_Renderer* renderer = window::get_sdl_renderer();
|
2022-07-27 11:25:25 -04:00
|
|
|
SDL_RenderClear(renderer);
|
2025-04-02 19:57:16 -06:00
|
|
|
ImGui_ImplSDLRenderer3_RenderDrawData(data, renderer);
|
2022-07-27 11:25:25 -04:00
|
|
|
SDL_RenderPresent(renderer);
|
|
|
|
|
} else {
|
2026-03-11 01:45:08 +01:00
|
|
|
pass.PushDebugGroup("Aurora: Dear Imgui");
|
2022-08-02 16:37:56 -04:00
|
|
|
ImGui_ImplWGPU_RenderDrawData(data, pass.Get());
|
2026-03-11 01:45:08 +01:00
|
|
|
pass.PopDebugGroup();
|
2022-07-27 11:25:25 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-04 23:43:13 -06:00
|
|
|
static wgpu::Buffer create_texture_upload_buffer(uint32_t width, uint32_t height, const uint8_t* data,
|
|
|
|
|
uint32_t copyBytesPerRow) {
|
|
|
|
|
const uint32_t rowBytes = width * 4;
|
|
|
|
|
const uint64_t uploadSize = static_cast<uint64_t>(copyBytesPerRow) * height;
|
|
|
|
|
const wgpu::BufferDescriptor desc{
|
|
|
|
|
.label = "imgui texture upload buffer",
|
|
|
|
|
.usage = wgpu::BufferUsage::CopySrc,
|
|
|
|
|
.size = uploadSize,
|
|
|
|
|
.mappedAtCreation = true,
|
|
|
|
|
};
|
|
|
|
|
auto buffer = webgpu::g_device.CreateBuffer(&desc);
|
|
|
|
|
auto* dst = static_cast<uint8_t*>(buffer.GetMappedRange(0, uploadSize));
|
|
|
|
|
for (uint32_t row = 0; row < height; ++row) {
|
|
|
|
|
std::memcpy(dst, data, rowBytes);
|
|
|
|
|
dst += copyBytesPerRow;
|
|
|
|
|
data += rowBytes;
|
|
|
|
|
}
|
|
|
|
|
buffer.Unmap();
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void enqueue_texture_upload(wgpu::Buffer buffer, wgpu::TexelCopyTextureInfo dst,
|
|
|
|
|
wgpu::TexelCopyBufferLayout layout, wgpu::Extent3D size) {
|
|
|
|
|
gfx::render_worker::enqueue_work([buffer = std::move(buffer), dst = std::move(dst), layout, size] {
|
|
|
|
|
const wgpu::CommandEncoderDescriptor encoderDesc{
|
|
|
|
|
.label = "imgui texture upload encoder",
|
|
|
|
|
};
|
|
|
|
|
auto encoder = webgpu::g_device.CreateCommandEncoder(&encoderDesc);
|
|
|
|
|
const wgpu::TexelCopyBufferInfo src{
|
|
|
|
|
.layout = layout,
|
|
|
|
|
.buffer = buffer,
|
|
|
|
|
};
|
|
|
|
|
encoder.CopyBufferToTexture(&src, &dst, &size);
|
|
|
|
|
const wgpu::CommandBufferDescriptor commandBufferDesc{
|
|
|
|
|
.label = "imgui texture upload command buffer",
|
|
|
|
|
};
|
|
|
|
|
auto commandBuffer = encoder.Finish(&commandBufferDesc);
|
|
|
|
|
webgpu::g_queue.Submit(1, &commandBuffer);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-27 11:25:25 -04:00
|
|
|
ImTextureID add_texture(uint32_t width, uint32_t height, const uint8_t* data) noexcept {
|
2026-05-06 16:35:38 -06:00
|
|
|
if (SDL_Renderer* renderer = window::get_sdl_renderer()) {
|
2022-07-27 11:25:25 -04:00
|
|
|
SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height);
|
|
|
|
|
SDL_UpdateTexture(texture, nullptr, data, width * 4);
|
2025-04-02 19:57:16 -06:00
|
|
|
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_LINEAR);
|
2022-07-27 11:25:25 -04:00
|
|
|
g_sdlTextures.push_back(texture);
|
2025-04-02 19:57:16 -06:00
|
|
|
return reinterpret_cast<ImTextureID>(texture);
|
2022-07-27 11:25:25 -04:00
|
|
|
}
|
2022-08-02 16:37:56 -04:00
|
|
|
const wgpu::Extent3D size{
|
2022-07-27 11:25:25 -04:00
|
|
|
.width = width,
|
|
|
|
|
.height = height,
|
|
|
|
|
.depthOrArrayLayers = 1,
|
|
|
|
|
};
|
2022-08-02 16:37:56 -04:00
|
|
|
const wgpu::TextureDescriptor textureDescriptor{
|
2022-07-27 11:25:25 -04:00
|
|
|
.label = "imgui texture",
|
2022-08-02 16:37:56 -04:00
|
|
|
.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst,
|
|
|
|
|
.dimension = wgpu::TextureDimension::e2D,
|
2022-07-27 11:25:25 -04:00
|
|
|
.size = size,
|
2022-08-02 16:37:56 -04:00
|
|
|
.format = wgpu::TextureFormat::RGBA8Unorm,
|
2022-07-27 11:25:25 -04:00
|
|
|
.mipLevelCount = 1,
|
|
|
|
|
.sampleCount = 1,
|
|
|
|
|
};
|
2022-08-02 16:37:56 -04:00
|
|
|
const wgpu::TextureViewDescriptor textureViewDescriptor{
|
2022-07-27 11:25:25 -04:00
|
|
|
.label = "imgui texture view",
|
2022-08-02 16:37:56 -04:00
|
|
|
.format = wgpu::TextureFormat::RGBA8Unorm,
|
|
|
|
|
.dimension = wgpu::TextureViewDimension::e2D,
|
2022-07-27 11:25:25 -04:00
|
|
|
.mipLevelCount = WGPU_MIP_LEVEL_COUNT_UNDEFINED,
|
|
|
|
|
.arrayLayerCount = WGPU_ARRAY_LAYER_COUNT_UNDEFINED,
|
|
|
|
|
};
|
2022-08-02 16:37:56 -04:00
|
|
|
auto texture = webgpu::g_device.CreateTexture(&textureDescriptor);
|
|
|
|
|
auto textureView = texture.CreateView(&textureViewDescriptor);
|
2022-07-27 11:25:25 -04:00
|
|
|
{
|
2025-04-03 00:12:22 -06:00
|
|
|
const wgpu::TexelCopyTextureInfo dstView{
|
2022-07-27 11:25:25 -04:00
|
|
|
.texture = texture,
|
|
|
|
|
};
|
2026-06-04 23:43:13 -06:00
|
|
|
const uint32_t copyBytesPerRow = AURORA_ALIGN(width * 4, 256);
|
2025-04-03 00:12:22 -06:00
|
|
|
const wgpu::TexelCopyBufferLayout dataLayout{
|
2026-06-04 23:43:13 -06:00
|
|
|
.bytesPerRow = copyBytesPerRow,
|
2022-07-27 11:25:25 -04:00
|
|
|
.rowsPerImage = height,
|
|
|
|
|
};
|
2026-06-04 23:43:13 -06:00
|
|
|
enqueue_texture_upload(create_texture_upload_buffer(width, height, data, copyBytesPerRow), dstView, dataLayout, size);
|
2022-07-27 11:25:25 -04:00
|
|
|
}
|
|
|
|
|
g_wgpuTextures.push_back(texture);
|
2025-04-03 00:12:22 -06:00
|
|
|
return reinterpret_cast<ImTextureID>(textureView.MoveToCHandle());
|
2022-07-27 11:25:25 -04:00
|
|
|
}
|
|
|
|
|
} // namespace aurora::imgui
|
|
|
|
|
|
|
|
|
|
// C bindings
|
|
|
|
|
extern "C" {
|
|
|
|
|
ImTextureID aurora_imgui_add_texture(uint32_t width, uint32_t height, const void* rgba8) {
|
|
|
|
|
return aurora::imgui::add_texture(width, height, static_cast<const uint8_t*>(rgba8));
|
|
|
|
|
}
|
|
|
|
|
}
|