mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-09-27 07:15:32 -04:00
6f14bde26a
* Preserve interrupted registers and unwind alarm guards before rescheduling Adapt the RFL interrupt-context and alarm reschedule fixes from KartPad ed8e4ca and 0c9bff0. Keep caller registers private and release the recursion guard before a woken fiber can pump callbacks. * Keep local Wii identity services available when networking is disabled Adapt KartPad a0f3fb5. Only IP and SSL devices require network access; KD request/time and NCD management remain available for offline save and license initialization. * Share repeated LR continuation dispatch in translated functions Adapt KartPad be91d8f/a3f90eb without its floating-point ABI changes. Preserve upstream continuation discovery and all resume labels. Validation: 640 translator tests passed. * Reject inconsistent GPU cache sizes before allocation or copying Adapt KartPad runtime 70951022. Validate raw lengths, compression tags and Zstd frame lengths on the size probe as well as the fetch. Tested against malformed SQLite rows and valid raw/compressed round trips. * Wake compiler workers when pipeline work becomes runnable Adapt KartPad runtime 956d811e. Wake all consumers of the shared condition variable after queue insertion or promotion; retain upstream desktop prewarm policy. A blocked-compiler probe verified progress by an idle worker. * Reuse and release one Metal view per SDL window Adapt KartPad 3606741. Surface recreation reuses the existing view and window property cleanup owns its lifetime. Reviewed against SDL3 cleanup semantics; Apple hardware validation remains outstanding. * Avoid overreading packed three-byte vertex attributes Adapt KartPad 0f6b274. Do not read a second storage word when all three requested bytes fit in the first. Preserve upstream depth and fog corrections. * Keep interpolation history within each split-screen viewport Adapt KartPad d6299b5. Scope exact, material and sibling-palette matching to the logical viewport so identical meshes from different cameras cannot share transforms. * Report graphics startup failures and safely clean up partial ImGui initialization Adapt KartPad runtime 70dc9380 and c4566e50 using the existing WiiCompiled exception/reporting path. A dummy-video-driver probe verified error return and repeated partial shutdown without aborting. * Preserve GX draw boundaries and GPU staging and readback state Adapt the validated renderer fixes from KartPad runtime 31add0c3, 7393dafe, b7f515de, cf46a9c7, fad42a7b, 7cd09b69, 9feea6b2 and Android 2505ae22 to current upstream. Preserve complete primitives and fresh vertex layouts, split staging batches before overflow, retain offscreen state, scope asynchronous callbacks and frame state, and complete texture-copy sources. Add unit regressions and an optional ROM-free GPU pixel test. Validation: 250 GX tests and actual D3D12 pixel/readback, capacity, interpolation and frame-worker checks passed with Dawn validation enabled.
267 lines
8.5 KiB
C++
267 lines
8.5 KiB
C++
#include "imgui.hpp"
|
|
|
|
#include <cstddef>
|
|
#include <cmath>
|
|
#include <filesystem>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <webgpu/webgpu_cpp.h>
|
|
#include <SDL3/SDL_events.h>
|
|
#include <SDL3/SDL_render.h>
|
|
|
|
#include "fs_helper.hpp"
|
|
#include "internal.hpp"
|
|
#include "webgpu/gpu.hpp"
|
|
#include "window.hpp"
|
|
|
|
#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN
|
|
#include "backends/imgui_impl_sdl3.h"
|
|
#include "backends/imgui_impl_sdlrenderer3.h"
|
|
#include "backends/imgui_impl_wgpu.h"
|
|
#include "tracy/Tracy.hpp"
|
|
|
|
namespace aurora::imgui {
|
|
static float g_scale;
|
|
static std::string g_imguiLog{};
|
|
static bool g_useSdlRenderer = false;
|
|
// Set once ImGui::Render() has produced this frame's draw data. Interpolation encodes up to four
|
|
// ImGui passes per frame, and every one of them used to rebuild the draw lists from scratch.
|
|
static bool g_frameDataBuilt = false;
|
|
|
|
static std::vector<SDL_Texture*> g_sdlTextures;
|
|
static std::vector<wgpu::Texture> g_wgpuTextures;
|
|
|
|
void remove_legacy_ini_file(const char* basePath) noexcept {
|
|
if (basePath == nullptr || *basePath == '\0') {
|
|
return;
|
|
}
|
|
|
|
std::error_code ec;
|
|
std::filesystem::remove(fs_path_from_string(basePath) / "imgui.ini", ec);
|
|
}
|
|
|
|
void create_context() noexcept {
|
|
IMGUI_CHECKVERSION();
|
|
ImGui::CreateContext();
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
|
remove_legacy_ini_file(g_config.userPath);
|
|
remove_legacy_ini_file(g_config.cachePath);
|
|
g_imguiLog = std::string{g_config.cachePath} + "/imgui.log";
|
|
io.IniFilename = nullptr;
|
|
io.LogFilename = g_imguiLog.c_str();
|
|
ImGui::LoadIniSettingsFromMemory("", 0);
|
|
io.WantSaveIniSettings = false;
|
|
}
|
|
|
|
void initialize() noexcept {
|
|
ZoneScoped;
|
|
SDL_Renderer* renderer = window::get_sdl_renderer();
|
|
ImGui_ImplSDL3_InitForSDLRenderer(window::get_sdl_window(), renderer);
|
|
g_useSdlRenderer = renderer != nullptr;
|
|
if (g_useSdlRenderer) {
|
|
ImGui_ImplSDLRenderer3_Init(renderer);
|
|
} else {
|
|
ImGui_ImplWGPU_InitInfo info;
|
|
info.Device = webgpu::g_device.Get();
|
|
info.RenderTargetFormat = static_cast<WGPUTextureFormat>(webgpu::g_graphicsConfig.surfaceConfiguration.format);
|
|
// Interpolation records up to four ImGui passes in one command buffer, so keep three logical
|
|
// frames of renderer resources to stop them overwriting each other's vertex/index buffers.
|
|
info.NumFramesInFlight = 12;
|
|
ImGui_ImplWGPU_Init(&info);
|
|
}
|
|
}
|
|
|
|
void shutdown() noexcept {
|
|
ZoneScoped;
|
|
// Startup can fail before either backend initializes. A context alone does
|
|
// not mean its renderer/platform backend owns resources to release.
|
|
if (ImGui::GetCurrentContext() != nullptr) {
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
if (io.BackendRendererUserData != nullptr) {
|
|
if (g_useSdlRenderer) {
|
|
ImGui_ImplSDLRenderer3_Shutdown();
|
|
} else {
|
|
ImGui_ImplWGPU_Shutdown();
|
|
}
|
|
}
|
|
if (io.BackendPlatformUserData != nullptr) {
|
|
ImGui_ImplSDL3_Shutdown();
|
|
}
|
|
ImGui::DestroyContext();
|
|
}
|
|
for (const auto& texture : g_sdlTextures) {
|
|
SDL_DestroyTexture(texture);
|
|
}
|
|
g_sdlTextures.clear();
|
|
g_wgpuTextures.clear();
|
|
g_useSdlRenderer = false;
|
|
g_scale = 0.f;
|
|
g_frameDataBuilt = false;
|
|
}
|
|
|
|
void process_event(const SDL_Event& event) noexcept {
|
|
auto renderEvent = event;
|
|
if (g_useSdlRenderer) {
|
|
if (SDL_Renderer* renderer = window::get_sdl_renderer()) {
|
|
SDL_ConvertEventToRenderCoordinates(renderer, &renderEvent);
|
|
}
|
|
}
|
|
ImGui_ImplSDL3_ProcessEvent(&renderEvent);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
void new_frame(const AuroraWindowSize& size) noexcept {
|
|
ZoneScoped;
|
|
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)};
|
|
|
|
if (g_useSdlRenderer) {
|
|
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};
|
|
}
|
|
}
|
|
ImGui_ImplSDLRenderer3_NewFrame();
|
|
g_scale = size.scale;
|
|
} else {
|
|
if (g_scale != size.scale) {
|
|
if (g_scale > 0.f) {
|
|
ImGui_ImplWGPU_CreateDeviceObjects();
|
|
}
|
|
g_scale = size.scale;
|
|
}
|
|
if (!ImGui::GetIO().Fonts->IsBuilt()) {
|
|
ImGui_ImplWGPU_CreateDeviceObjects();
|
|
}
|
|
ImGui_ImplWGPU_NewFrame();
|
|
}
|
|
ImGui_ImplSDL3_NewFrame();
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
io.DisplayFramebufferScale = framebufferScale;
|
|
ImGui::GetIO().DisplaySize = displaySize;
|
|
ImGui::NewFrame();
|
|
g_frameDataBuilt = false;
|
|
}
|
|
|
|
void render_frame_data() noexcept {
|
|
ZoneScoped;
|
|
if (g_frameDataBuilt) {
|
|
return;
|
|
}
|
|
ImGui::Render();
|
|
auto* data = ImGui::GetDrawData();
|
|
data->FramebufferScale = ImGui::GetIO().DisplayFramebufferScale;
|
|
g_frameDataBuilt = true;
|
|
}
|
|
|
|
void render(const wgpu::RenderPassEncoder& pass) noexcept {
|
|
ZoneScoped;
|
|
render_frame_data();
|
|
|
|
auto* data = ImGui::GetDrawData();
|
|
if (g_useSdlRenderer) {
|
|
SDL_Renderer* renderer = window::get_sdl_renderer();
|
|
SDL_RenderClear(renderer);
|
|
ImGui_ImplSDLRenderer3_RenderDrawData(data, renderer);
|
|
SDL_RenderPresent(renderer);
|
|
} else {
|
|
pass.PushDebugGroup("Aurora: Dear Imgui");
|
|
ImGui_ImplWGPU_RenderDrawData(data, pass.Get());
|
|
pass.PopDebugGroup();
|
|
}
|
|
}
|
|
|
|
ImTextureID add_texture(uint32_t width, uint32_t height, const uint8_t* data) noexcept {
|
|
if (SDL_Renderer* renderer = window::get_sdl_renderer()) {
|
|
SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height);
|
|
SDL_UpdateTexture(texture, nullptr, data, width * 4);
|
|
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_LINEAR);
|
|
g_sdlTextures.push_back(texture);
|
|
return reinterpret_cast<ImTextureID>(texture);
|
|
}
|
|
const wgpu::Extent3D size{
|
|
.width = width,
|
|
.height = height,
|
|
.depthOrArrayLayers = 1,
|
|
};
|
|
const wgpu::TextureDescriptor textureDescriptor{
|
|
.label = "imgui texture",
|
|
.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst,
|
|
.dimension = wgpu::TextureDimension::e2D,
|
|
.size = size,
|
|
.format = wgpu::TextureFormat::RGBA8Unorm,
|
|
.mipLevelCount = 1,
|
|
.sampleCount = 1,
|
|
};
|
|
const wgpu::TextureViewDescriptor textureViewDescriptor{
|
|
.label = "imgui texture view",
|
|
.format = wgpu::TextureFormat::RGBA8Unorm,
|
|
.dimension = wgpu::TextureViewDimension::e2D,
|
|
.mipLevelCount = WGPU_MIP_LEVEL_COUNT_UNDEFINED,
|
|
.arrayLayerCount = WGPU_ARRAY_LAYER_COUNT_UNDEFINED,
|
|
};
|
|
auto texture = webgpu::g_device.CreateTexture(&textureDescriptor);
|
|
auto textureView = texture.CreateView(&textureViewDescriptor);
|
|
{
|
|
const wgpu::TexelCopyTextureInfo dstView{
|
|
.texture = texture,
|
|
};
|
|
const wgpu::TexelCopyBufferLayout dataLayout{
|
|
.bytesPerRow = 4 * width,
|
|
.rowsPerImage = height,
|
|
};
|
|
webgpu::g_queue.WriteTexture(&dstView, data, width * height * 4, &dataLayout, &size);
|
|
}
|
|
g_wgpuTextures.push_back(texture);
|
|
return reinterpret_cast<ImTextureID>(textureView.MoveToCHandle());
|
|
}
|
|
} // 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));
|
|
}
|
|
}
|