Update fmtlib

This commit is contained in:
Luke Street 2025-04-03 21:03:08 -06:00
parent 3d53dbed93
commit b07d55f71d
20 changed files with 802 additions and 483 deletions

2
extern/fmt vendored

@ -1 +1 @@
Subproject commit c4ee726532178e556d923372f29163bd206d7732
Subproject commit 123913715afeb8a437e6388b4473fcc4753e1c9a

View File

@ -48,7 +48,7 @@ typedef struct {
typedef struct SDL_Window SDL_Window;
typedef struct AuroraEvent AuroraEvent;
typedef void (*AuroraLogCallback)(AuroraLogLevel level, const char* message, unsigned int len);
typedef void (*AuroraLogCallback)(AuroraLogLevel level, const char* module, const char* message, unsigned int len);
typedef void (*AuroraImGuiInitCallback)(const AuroraWindowSize* size);
typedef struct {

View File

@ -8,15 +8,15 @@
#include "window.hpp"
#include <SDL3/SDL_filesystem.h>
#include <imgui.h>
#include <magic_enum.hpp>
#include <webgpu/webgpu_cpp.h>
namespace aurora {
static Module Log("aurora");
AuroraConfig g_config;
namespace {
Module Log("aurora");
// GPU
using webgpu::g_device;
using webgpu::g_queue;
@ -49,10 +49,11 @@ constexpr std::array PreferredBackendOrder{
#endif
};
static bool g_initialFrame = false;
bool g_initialFrame = false;
static AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config) noexcept {
AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config) noexcept {
g_config = config;
Log.report(LOG_INFO, "Aurora initializing");
if (g_config.appName == nullptr) {
g_config.appName = "Aurora";
}
@ -106,7 +107,7 @@ static AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config)
imgui::create_context();
const auto size = window::get_window_size();
Log.report(LOG_INFO, FMT_STRING("Using framebuffer size {}x{} scale {}"), size.fb_width, size.fb_height, size.scale);
Log.report(LOG_INFO, "Using framebuffer size {}x{} scale {}", size.fb_width, size.fb_height, size.scale);
if (g_config.imGuiInitCallback != nullptr) {
g_config.imGuiInitCallback(&size);
}
@ -122,9 +123,9 @@ static AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config)
};
}
static wgpu::TextureView g_currentView;
wgpu::TextureView g_currentView;
static void shutdown() noexcept {
void shutdown() noexcept {
g_currentView = {};
imgui::shutdown();
gfx::shutdown();
@ -132,7 +133,7 @@ static void shutdown() noexcept {
window::shutdown();
}
static const AuroraEvent* update() noexcept {
const AuroraEvent* update() noexcept {
if (g_initialFrame) {
g_initialFrame = false;
input::initialize();
@ -140,7 +141,7 @@ static const AuroraEvent* update() noexcept {
return window::poll_events();
}
static bool begin_frame() noexcept {
bool begin_frame() noexcept {
wgpu::SurfaceTexture surfaceTexture;
g_surface.GetCurrentTexture(&surfaceTexture);
switch (surfaceTexture.status) {
@ -148,15 +149,14 @@ static bool begin_frame() noexcept {
g_currentView = surfaceTexture.texture.CreateView();
break;
case wgpu::SurfaceGetCurrentTextureStatus::SuccessSuboptimal: {
Log.report(LOG_WARNING, FMT_STRING("Surface texture is suboptimal"));
Log.report(LOG_WARNING, "Surface texture is suboptimal");
// Force swapchain recreation
const auto size = window::get_window_size();
webgpu::resize_swapchain(size.fb_width, size.fb_height, true);
return false;
}
default:
Log.report(LOG_ERROR, FMT_STRING("Failed to get surface texture: {}"),
magic_enum::enum_name(surfaceTexture.status));
Log.report(LOG_ERROR, "Failed to get surface texture: {}", magic_enum::enum_name(surfaceTexture.status));
return false;
}
imgui::new_frame(window::get_window_size());
@ -164,7 +164,7 @@ static bool begin_frame() noexcept {
return true;
}
static void end_frame() noexcept {
void end_frame() noexcept {
const auto encoderDescriptor = wgpu::CommandEncoderDescriptor{
.label = "Redraw encoder",
};
@ -198,6 +198,7 @@ static void end_frame() noexcept {
g_surface.Present();
g_currentView = {};
}
} // namespace
} // namespace aurora
// C API bindings

View File

@ -23,95 +23,6 @@
#endif
namespace aurora::webgpu::utils {
//#if defined(DAWN_ENABLE_BACKEND_OPENGL)
//struct GLUserData {
// SDL_Window* window;
// SDL_GLContext context;
//};
//void GLMakeCurrent(void* userData) {
// auto* data = static_cast<GLUserData*>(userData);
// SDL_GL_MakeCurrent(data->window, data->context);
//}
//void GLDestroy(void* userData) {
// auto* data = static_cast<GLUserData*>(userData);
// SDL_GL_DestroyContext(data->context);
// delete data;
//}
//#endif
//
//bool DiscoverAdapter(dawn::native::Instance* instance, [[maybe_unused]] SDL_Window* window, wgpu::BackendType type) {
// switch (type) {
//#if defined(DAWN_ENABLE_BACKEND_D3D11)
// case wgpu::BackendType::D3D11: {
// dawn::native::d3d11::PhysicalDeviceDiscoveryOptions options;
// return instance->DiscoverPhysicalDevices(&options);
// }
//#endif
//#if defined(DAWN_ENABLE_BACKEND_D3D12)
// case wgpu::BackendType::D3D12: {
// dawn::native::d3d12::PhysicalDeviceDiscoveryOptions options;
// return instance->DiscoverPhysicalDevices(&options);
// }
//#endif
//#if defined(DAWN_ENABLE_BACKEND_METAL)
// case wgpu::BackendType::Metal: {
// dawn::native::metal::PhysicalDeviceDiscoveryOptions options;
// return instance->DiscoverPhysicalDevices(&options);
// }
//#endif
//#if defined(DAWN_ENABLE_BACKEND_VULKAN)
// case wgpu::BackendType::Vulkan: {
// dawn::native::vulkan::PhysicalDeviceDiscoveryOptions options;
// return instance->DiscoverPhysicalDevices(&options);
// }
//#endif
//#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
// case wgpu::BackendType::OpenGL: {
// SDL_GL_ResetAttributes();
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);
// SDL_GLContext context = SDL_GL_CreateContext(window);
// dawn::native::opengl::PhysicalDeviceDiscoveryOptions options{WGPUBackendType_OpenGL};
// options.getProc = reinterpret_cast<void* (*)(const char*)>(SDL_GL_GetProcAddress);
// options.makeCurrent = GLMakeCurrent;
// options.destroy = GLDestroy;
// options.userData = new GLUserData{
// .window = window,
// .context = context,
// };
// return instance->DiscoverPhysicalDevices(&options);
// }
//#endif
//#if defined(DAWN_ENABLE_BACKEND_OPENGLES)
// case wgpu::BackendType::OpenGLES: {
// SDL_GL_ResetAttributes();
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
// SDL_GLContext context = SDL_GL_CreateContext(window);
// dawn::native::opengl::PhysicalDeviceDiscoveryOptions options{WGPUBackendType_OpenGLES};
// options.getProc = reinterpret_cast<void* (*)(const char*)>(SDL_GL_GetProcAddress);
// options.makeCurrent = GLMakeCurrent;
// options.destroy = GLDestroy;
// options.userData = new GLUserData{
// .window = window,
// .context = context,
// };
// return instance->DiscoverPhysicalDevices(&options);
// }
//#endif
//#if defined(DAWN_ENABLE_BACKEND_NULL)
// case wgpu::BackendType::Null:
// instance->DiscoverDefaultPhysicalDevices();
// return true;
//#endif
// default:
// return false;
// }
//}
std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(SDL_Window* window);
std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(SDL_Window* window) {
@ -120,22 +31,20 @@ std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(SDL_Wind
#else
const auto props = SDL_GetWindowProperties(window);
#if defined(SDL_PLATFORM_WIN32)
std::unique_ptr<wgpu::SurfaceSourceWindowsHWND> desc =
std::make_unique<wgpu::SurfaceSourceWindowsHWND>();
desc->hwnd = wmInfo.info.win.window;
desc->hinstance = wmInfo.info.win.hinstance;
std::unique_ptr<wgpu::SurfaceSourceWindowsHWND> desc = std::make_unique<wgpu::SurfaceSourceWindowsHWND>();
desc->hwnd = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
desc->hinstance = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER, nullptr);
return std::move(desc);
#elif defined(SDL_PLATFORM_LINUX)
if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
std::unique_ptr<wgpu::SurfaceSourceWaylandSurface> desc =
std::make_unique<wgpu::SurfaceSourceWaylandSurface>();
const char* driver = SDL_GetCurrentVideoDriver();
if (SDL_strcmp(driver, "wayland") == 0) {
std::unique_ptr<wgpu::SurfaceSourceWaylandSurface> desc = std::make_unique<wgpu::SurfaceSourceWaylandSurface>();
desc->display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr);
desc->surface = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
return std::move(desc);
}
if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
std::unique_ptr<wgpu::SurfaceSourceXlibWindow> desc =
std::make_unique<wgpu::SurfaceSourceXlibWindow>();
if (SDL_strcmp(driver, "x11") == 0) {
std::unique_ptr<wgpu::SurfaceSourceXlibWindow> desc = std::make_unique<wgpu::SurfaceSourceXlibWindow>();
desc->display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr);
desc->window = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
return std::move(desc);

View File

@ -1,6 +1,5 @@
#pragma once
#include <dawn/native/DawnNative.h>
#include <memory>
#include <webgpu/webgpu_cpp.h>
@ -8,7 +7,6 @@ struct SDL_Window;
namespace aurora::webgpu::utils {
bool DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu::BackendType type);
std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(SDL_Window* window);
} // namespace aurora::webgpu::utils

View File

@ -1,37 +0,0 @@
#include "BackendBinding.hpp"
#include <SDL3/SDL_syswm.h>
#include <dawn/native/D3D12Backend.h>
namespace aurora::webgpu::utils {
class D3D12Binding : public BackendBinding {
public:
D3D12Binding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
uint64_t GetSwapChainImplementation() override {
if (m_swapChainImpl.userData == nullptr) {
CreateSwapChainImpl();
}
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
}
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
if (m_swapChainImpl.userData == nullptr) {
CreateSwapChainImpl();
}
return dawn::native::d3d12::GetNativeSwapChainPreferredFormat(&m_swapChainImpl);
}
private:
DawnSwapChainImplementation m_swapChainImpl{};
void CreateSwapChainImpl() {
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(m_window, &wmInfo);
m_swapChainImpl = dawn::native::d3d12::CreateNativeSwapChainImpl(m_device, wmInfo.info.win.window);
}
};
BackendBinding* CreateD3D12Binding(SDL_Window* window, WGPUDevice device) { return new D3D12Binding(window, device); }
} // namespace aurora::webgpu::utils

View File

@ -5,8 +5,7 @@
namespace aurora::webgpu::utils {
std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(SDL_Window* window) {
SDL_MetalView view = SDL_Metal_CreateView(window);
std::unique_ptr<wgpu::SurfaceDescriptorFromMetalLayer> desc =
std::make_unique<wgpu::SurfaceDescriptorFromMetalLayer>();
std::unique_ptr<wgpu::SurfaceSourceMetalLayer> desc = std::make_unique<wgpu::SurfaceSourceMetalLayer>();
desc->layer = SDL_Metal_GetLayer(view);
return std::move(desc);
}

View File

@ -1,26 +0,0 @@
#include "BackendBinding.hpp"
#include <dawn/native/NullBackend.h>
namespace aurora::webgpu::utils {
class NullBinding : public BackendBinding {
public:
NullBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
uint64_t GetSwapChainImplementation() override {
if (m_swapChainImpl.userData == nullptr) {
m_swapChainImpl = dawn::native::null::CreateNativeSwapChainImpl();
}
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
}
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
return WGPUTextureFormat_RGBA8Unorm;
}
private:
DawnSwapChainImplementation m_swapChainImpl{};
};
BackendBinding* CreateNullBinding(SDL_Window* window, WGPUDevice device) { return new NullBinding(window, device); }
} // namespace aurora::webgpu::utils

View File

@ -1,35 +0,0 @@
#include "BackendBinding.hpp"
#include <SDL3/SDL_video.h>
#include <dawn/native/OpenGLBackend.h>
namespace aurora::webgpu::utils {
class OpenGLBinding : public BackendBinding {
public:
OpenGLBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
uint64_t GetSwapChainImplementation() override {
if (m_swapChainImpl.userData == nullptr) {
CreateSwapChainImpl();
}
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
}
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
if (m_swapChainImpl.userData == nullptr) {
CreateSwapChainImpl();
}
return dawn::native::opengl::GetNativeSwapChainPreferredFormat(&m_swapChainImpl);
}
private:
DawnSwapChainImplementation m_swapChainImpl{};
void CreateSwapChainImpl() {
m_swapChainImpl = dawn::native::opengl::CreateNativeSwapChainImpl(
m_device, [](void* userdata) { SDL_GL_SwapWindow(static_cast<SDL_Window*>(userdata)); }, m_window);
}
};
BackendBinding* CreateOpenGLBinding(SDL_Window* window, WGPUDevice device) { return new OpenGLBinding(window, device); }
} // namespace aurora::webgpu::utils

View File

@ -1,41 +0,0 @@
#include "BackendBinding.hpp"
#include "../internal.hpp"
#include <SDL3/SDL_vulkan.h>
#include <dawn/native/VulkanBackend.h>
namespace aurora::webgpu::utils {
static Module Log("aurora::webgpu::utils::VulkanBinding");
class VulkanBinding : public BackendBinding {
public:
VulkanBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
uint64_t GetSwapChainImplementation() override {
if (m_swapChainImpl.userData == nullptr) {
CreateSwapChainImpl();
}
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
}
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
if (m_swapChainImpl.userData == nullptr) {
CreateSwapChainImpl();
}
return dawn::native::vulkan::GetNativeSwapChainPreferredFormat(&m_swapChainImpl);
}
private:
DawnSwapChainImplementation m_swapChainImpl{};
void CreateSwapChainImpl() {
VkSurfaceKHR surface = VK_NULL_HANDLE;
ASSERT(SDL_Vulkan_CreateSurface(m_window, dawn::native::vulkan::GetInstance(m_device), &surface),
"Failed to create Vulkan surface: {}", SDL_GetError());
m_swapChainImpl = dawn::native::vulkan::CreateNativeSwapChainImpl(m_device, surface);
}
};
BackendBinding* CreateVulkanBinding(SDL_Window* window, WGPUDevice device) { return new VulkanBinding(window, device); }
} // namespace aurora::webgpu::utils

View File

@ -113,8 +113,9 @@ void GXInitTexObjTlut(GXTexObj* obj_, u32 tlut) {
void GXLoadTexObj(GXTexObj* obj_, GXTexMapID id) {
auto* obj = reinterpret_cast<GXTexObj_*>(obj_);
if (!obj->ref) {
obj->ref = aurora::gfx::new_dynamic_texture_2d(obj->width, obj->height, u32(obj->maxLod) + 1, obj->fmt,
fmt::format(FMT_STRING("GXLoadTexObj_{}"), obj->fmt).c_str());
const auto name = fmt::format("GXLoadTexObj_{}", obj->fmt);
obj->ref =
aurora::gfx::new_dynamic_texture_2d(obj->width, obj->height, u32(obj->maxLod) + 1, obj->fmt, name.c_str());
}
if (obj->dataInvalidated) {
aurora::gfx::write_texture(*obj->ref, {static_cast<const u8*>(obj->data), UINT32_MAX /* TODO */});

View File

@ -219,7 +219,7 @@ static PipelineRef find_pipeline(ShaderType type, const PipelineConfig& config,
static inline void push_command(CommandType type, const Command::Data& data) {
if (g_currentRenderPass == UINT32_MAX)
UNLIKELY {
Log.report(LOG_WARNING, FMT_STRING("Dropping command {}"), magic_enum::enum_name(type));
Log.report(LOG_WARNING, "Dropping command {}", magic_enum::enum_name(type));
return;
}
g_renderPasses[g_currentRenderPass].commands.push_back({
@ -391,7 +391,7 @@ void load_pipeline_cache() {
find_pipeline(type, config, [=]() { return model::create_pipeline(g_state.model, config); }, true);
} break;
default:
Log.report(LOG_WARNING, FMT_STRING("Unknown pipeline type {}"), static_cast<int>(type));
Log.report(LOG_WARNING, "Unknown pipeline type {}", static_cast<int>(type));
break;
}
offset += size;
@ -445,7 +445,7 @@ void initialize() {
createBuffer(g_storageBuffer, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst, StorageBufferSize,
"Shared Storage Buffer");
for (int i = 0; i < g_stagingBuffers.size(); ++i) {
const auto label = fmt::format(FMT_STRING("Staging Buffer {}"), i);
const auto label = fmt::format("Staging Buffer {}", i);
createBuffer(g_stagingBuffers[i], wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc, StagingBufferSize,
label.c_str());
}
@ -605,7 +605,7 @@ void render(wgpu::CommandEncoder& cmd) {
.depthStoreOp = wgpu::StoreOp::Store,
.depthClearValue = 1.f,
};
const auto label = fmt::format(FMT_STRING("Render pass {}"), i);
const auto label = fmt::format("Render pass {}", i);
const wgpu::RenderPassDescriptor renderPassDescriptor{
.label = label.c_str(),
.colorAttachmentCount = attachments.size(),

526
lib/gfx/gx_fmt.hpp Normal file
View File

@ -0,0 +1,526 @@
#include <dolphin/gx/GXEnum.h>
#include <fmt/format.h>
#include <string>
inline std::string format_as(const GXTevOp& op) {
switch (op) {
case GX_TEV_ADD:
return "GX_TEV_ADD";
case GX_TEV_SUB:
return "GX_TEV_SUB";
case GX_TEV_COMP_R8_GT:
return "GX_TEV_COMP_R8_GT";
case GX_TEV_COMP_R8_EQ:
return "GX_TEV_COMP_R8_EQ";
case GX_TEV_COMP_GR16_GT:
return "GX_TEV_COMP_GR16_GT";
case GX_TEV_COMP_GR16_EQ:
return "GX_TEV_COMP_GR16_EQ";
case GX_TEV_COMP_BGR24_GT:
return "GX_TEV_COMP_BGR24_GT";
case GX_TEV_COMP_BGR24_EQ:
return "GX_TEV_COMP_BGR24_EQ";
case GX_TEV_COMP_RGB8_GT:
return "GX_TEV_COMP_RGB8_GT";
case GX_TEV_COMP_RGB8_EQ:
return "GX_TEV_COMP_RGB8_EQ";
default:
return fmt::format("GXTevOp({})", static_cast<int>(op));
}
}
inline std::string format_as(const GXTevColorArg& arg) {
switch (arg) {
case GX_CC_CPREV:
return "GX_CC_CPREV";
case GX_CC_APREV:
return "GX_CC_APREV";
case GX_CC_C0:
return "GX_CC_C0";
case GX_CC_A0:
return "GX_CC_A0";
case GX_CC_C1:
return "GX_CC_C1";
case GX_CC_A1:
return "GX_CC_A1";
case GX_CC_C2:
return "GX_CC_C2";
case GX_CC_A2:
return "GX_CC_A2";
case GX_CC_TEXC:
return "GX_CC_TEXC";
case GX_CC_TEXA:
return "GX_CC_TEXA";
case GX_CC_RASC:
return "GX_CC_RASC";
case GX_CC_RASA:
return "GX_CC_RASA";
case GX_CC_ONE:
return "GX_CC_ONE";
case GX_CC_HALF:
return "GX_CC_HALF";
case GX_CC_KONST:
return "GX_CC_KONST";
case GX_CC_ZERO:
return "GX_CC_ZERO";
default:
return fmt::format("GXTevColorArg({})", static_cast<int>(arg));
}
}
inline std::string format_as(const GXTevAlphaArg& arg) {
switch (arg) {
case GX_CA_APREV:
return "GX_CA_APREV";
case GX_CA_A0:
return "GX_CA_A0";
case GX_CA_A1:
return "GX_CA_A1";
case GX_CA_A2:
return "GX_CA_A2";
case GX_CA_TEXA:
return "GX_CA_TEXA";
case GX_CA_RASA:
return "GX_CA_RASA";
case GX_CA_KONST:
return "GX_CA_KONST";
case GX_CA_ZERO:
return "GX_CA_ZERO";
default:
return fmt::format("GXTevAlphaArg({})", static_cast<int>(arg));
}
}
inline std::string format_as(const GXTexGenSrc& src) {
switch (src) {
case GX_TG_POS:
return "GX_TG_POS";
case GX_TG_NRM:
return "GX_TG_NRM";
case GX_TG_BINRM:
return "GX_TG_BINRM";
case GX_TG_TANGENT:
return "GX_TG_TANGENT";
case GX_TG_TEX0:
return "GX_TG_TEX0";
case GX_TG_TEX1:
return "GX_TG_TEX1";
case GX_TG_TEX2:
return "GX_TG_TEX2";
case GX_TG_TEX3:
return "GX_TG_TEX3";
case GX_TG_TEX4:
return "GX_TG_TEX4";
case GX_TG_TEX5:
return "GX_TG_TEX5";
case GX_TG_TEX6:
return "GX_TG_TEX6";
case GX_TG_TEX7:
return "GX_TG_TEX7";
default:
return fmt::format("GXTexGenSrc({})", static_cast<int>(src));
}
}
inline std::string format_as(const GXTexGenType& type) {
switch (type) {
case GX_TG_MTX2x4:
return "GX_TG_MTX2x4";
case GX_TG_MTX3x4:
return "GX_TG_MTX3x4";
case GX_TG_BUMP0:
return "GX_TG_BUMP0";
case GX_TG_BUMP1:
return "GX_TG_BUMP1";
default:
return fmt::format("GXTexGenType({})", static_cast<int>(type));
}
}
inline std::string format_as(const GXTevBias& bias) {
switch (bias) {
case GX_TB_ZERO:
return "GX_TB_ZERO";
case GX_TB_ADDHALF:
return "GX_TB_ADDHALF";
case GX_TB_SUBHALF:
return "GX_TB_SUBHALF";
default:
return fmt::format("GXTevBias({})", static_cast<int>(bias));
}
}
inline std::string format_as(const GXTevScale& scale) {
switch (scale) {
case GX_CS_SCALE_1:
return "GX_CS_SCALE_1";
case GX_CS_SCALE_2:
return "GX_CS_SCALE_2";
case GX_CS_SCALE_4:
return "GX_CS_SCALE_4";
case GX_CS_DIVIDE_2:
return "GX_CS_DIVIDE_2";
default:
return fmt::format("GXTevScale({})", static_cast<int>(scale));
}
}
inline std::string format_as(const GXTevRegID& reg) {
switch (reg) {
case GX_TEVPREV:
return "GX_TEVPREV";
case GX_TEVREG0:
return "GX_TEVREG0";
case GX_TEVREG1:
return "GX_TEVREG1";
case GX_TEVREG2:
return "GX_TEVREG2";
default:
return fmt::format("GXTevRegID({})", static_cast<int>(reg));
}
}
inline std::string format_as(const GXTevKColorSel& sel) {
switch (sel) {
case GX_TEV_KCSEL_8_8:
return "GX_TEV_KCSEL_8_8";
case GX_TEV_KCSEL_7_8:
return "GX_TEV_KCSEL_7_8";
case GX_TEV_KCSEL_6_8:
return "GX_TEV_KCSEL_6_8";
case GX_TEV_KCSEL_5_8:
return "GX_TEV_KCSEL_5_8";
case GX_TEV_KCSEL_4_8:
return "GX_TEV_KCSEL_4_8";
case GX_TEV_KCSEL_3_8:
return "GX_TEV_KCSEL_3_8";
case GX_TEV_KCSEL_2_8:
return "GX_TEV_KCSEL_2_8";
case GX_TEV_KCSEL_1_8:
return "GX_TEV_KCSEL_1_8";
case GX_TEV_KCSEL_K0_R:
return "GX_TEV_KCSEL_K0_R";
case GX_TEV_KCSEL_K1_R:
return "GX_TEV_KCSEL_K1_R";
case GX_TEV_KCSEL_K2_R:
return "GX_TEV_KCSEL_K2_R";
case GX_TEV_KCSEL_K3_R:
return "GX_TEV_KCSEL_K3_R";
case GX_TEV_KCSEL_K0_G:
return "GX_TEV_KCSEL_K0_G";
case GX_TEV_KCSEL_K1_G:
return "GX_TEV_KCSEL_K1_G";
case GX_TEV_KCSEL_K2_G:
return "GX_TEV_KCSEL_K2_G";
case GX_TEV_KCSEL_K3_G:
return "GX_TEV_KCSEL_K3_G";
case GX_TEV_KCSEL_K0_B:
return "GX_TEV_KCSEL_K0_B";
case GX_TEV_KCSEL_K1_B:
return "GX_TEV_KCSEL_K1_B";
case GX_TEV_KCSEL_K2_B:
return "GX_TEV_KCSEL_K2_B";
case GX_TEV_KCSEL_K3_B:
return "GX_TEV_KCSEL_K3_B";
case GX_TEV_KCSEL_K0_A:
return "GX_TEV_KCSEL_K0_A";
case GX_TEV_KCSEL_K1_A:
return "GX_TEV_KCSEL_K1_A";
case GX_TEV_KCSEL_K2_A:
return "GX_TEV_KCSEL_K2_A";
case GX_TEV_KCSEL_K3_A:
return "GX_TEV_KCSEL_K3_A";
default:
return fmt::format("GXTevKColorSel({})", static_cast<int>(sel));
}
}
inline std::string format_as(const GXTevKAlphaSel& sel) {
switch (sel) {
case GX_TEV_KASEL_8_8:
return "GX_TEV_KASEL_8_8";
case GX_TEV_KASEL_7_8:
return "GX_TEV_KASEL_7_8";
case GX_TEV_KASEL_6_8:
return "GX_TEV_KASEL_6_8";
case GX_TEV_KASEL_5_8:
return "GX_TEV_KASEL_5_8";
case GX_TEV_KASEL_4_8:
return "GX_TEV_KASEL_4_8";
case GX_TEV_KASEL_3_8:
return "GX_TEV_KASEL_3_8";
case GX_TEV_KASEL_2_8:
return "GX_TEV_KASEL_2_8";
case GX_TEV_KASEL_1_8:
return "GX_TEV_KASEL_1_8";
case GX_TEV_KASEL_K0_R:
return "GX_TEV_KASEL_K0_R";
case GX_TEV_KASEL_K1_R:
return "GX_TEV_KASEL_K1_R";
case GX_TEV_KASEL_K2_R:
return "GX_TEV_KASEL_K2_R";
case GX_TEV_KASEL_K3_R:
return "GX_TEV_KASEL_K3_R";
case GX_TEV_KASEL_K0_G:
return "GX_TEV_KASEL_K0_G";
case GX_TEV_KASEL_K1_G:
return "GX_TEV_KASEL_K1_G";
case GX_TEV_KASEL_K2_G:
return "GX_TEV_KASEL_K2_G";
case GX_TEV_KASEL_K3_G:
return "GX_TEV_KASEL_K3_G";
case GX_TEV_KASEL_K0_B:
return "GX_TEV_KASEL_K0_B";
case GX_TEV_KASEL_K1_B:
return "GX_TEV_KASEL_K1_B";
case GX_TEV_KASEL_K2_B:
return "GX_TEV_KASEL_K2_B";
case GX_TEV_KASEL_K3_B:
return "GX_TEV_KASEL_K3_B";
case GX_TEV_KASEL_K0_A:
return "GX_TEV_KASEL_K0_A";
case GX_TEV_KASEL_K1_A:
return "GX_TEV_KASEL_K1_A";
case GX_TEV_KASEL_K2_A:
return "GX_TEV_KASEL_K2_A";
case GX_TEV_KASEL_K3_A:
return "GX_TEV_KASEL_K3_A";
default:
return fmt::format("GXTevKAlphaSel({})", static_cast<int>(sel));
}
}
inline std::string format_as(const GXTexMapID& id) {
switch (id) {
case GX_TEXMAP0:
return "GX_TEXMAP0";
case GX_TEXMAP1:
return "GX_TEXMAP1";
case GX_TEXMAP2:
return "GX_TEXMAP2";
case GX_TEXMAP3:
return "GX_TEXMAP3";
case GX_TEXMAP4:
return "GX_TEXMAP4";
case GX_TEXMAP5:
return "GX_TEXMAP5";
case GX_TEXMAP6:
return "GX_TEXMAP6";
case GX_TEXMAP7:
return "GX_TEXMAP7";
case GX_TEXMAP_NULL:
return "GX_TEXMAP_NULL";
case GX_TEX_DISABLE:
return "GX_TEX_DISABLE";
default:
return fmt::format("GXTexMapID({})", static_cast<int>(id));
}
}
inline std::string format_as(const GXChannelID& id) {
switch (id) {
case GX_COLOR0:
return "GX_COLOR0";
case GX_COLOR1:
return "GX_COLOR1";
case GX_ALPHA0:
return "GX_ALPHA0";
case GX_ALPHA1:
return "GX_ALPHA1";
case GX_COLOR0A0:
return "GX_COLOR0A0";
case GX_COLOR1A1:
return "GX_COLOR1A1";
case GX_COLOR_ZERO:
return "GX_COLOR_ZERO";
case GX_ALPHA_BUMP:
return "GX_ALPHA_BUMP";
case GX_ALPHA_BUMPN:
return "GX_ALPHA_BUMPN";
case GX_COLOR_NULL:
return "GX_COLOR_NULL";
default:
return fmt::format("GXChannelID({})", static_cast<int>(id));
}
}
inline std::string format_as(const GXColorSrc& src) {
switch (src) {
case GX_SRC_REG:
return "GX_SRC_REG";
case GX_SRC_VTX:
return "GX_SRC_VTX";
default:
return fmt::format("GXColorSrc({})", static_cast<int>(src));
}
}
inline std::string format_as(const GXTexMtx& mtx) {
switch (mtx) {
case GX_TEXMTX0:
return "GX_TEXMTX0";
case GX_TEXMTX1:
return "GX_TEXMTX1";
case GX_TEXMTX2:
return "GX_TEXMTX2";
case GX_TEXMTX3:
return "GX_TEXMTX3";
case GX_TEXMTX4:
return "GX_TEXMTX4";
case GX_TEXMTX5:
return "GX_TEXMTX5";
case GX_TEXMTX6:
return "GX_TEXMTX6";
case GX_TEXMTX7:
return "GX_TEXMTX7";
case GX_TEXMTX8:
return "GX_TEXMTX8";
case GX_TEXMTX9:
return "GX_TEXMTX9";
case GX_IDENTITY:
return "GX_IDENTITY";
default:
return fmt::format("GXTexMtx({})", static_cast<int>(mtx));
}
}
inline std::string format_as(const GXPTTexMtx& mtx) {
switch (mtx) {
case GX_PTTEXMTX0:
return "GX_PTTEXMTX0";
case GX_PTTEXMTX1:
return "GX_PTTEXMTX1";
case GX_PTTEXMTX2:
return "GX_PTTEXMTX2";
case GX_PTTEXMTX3:
return "GX_PTTEXMTX3";
case GX_PTTEXMTX4:
return "GX_PTTEXMTX4";
case GX_PTTEXMTX5:
return "GX_PTTEXMTX5";
case GX_PTTEXMTX6:
return "GX_PTTEXMTX6";
case GX_PTTEXMTX7:
return "GX_PTTEXMTX7";
case GX_PTTEXMTX8:
return "GX_PTTEXMTX8";
case GX_PTTEXMTX9:
return "GX_PTTEXMTX9";
case GX_PTTEXMTX10:
return "GX_PTTEXMTX10";
case GX_PTTEXMTX11:
return "GX_PTTEXMTX11";
case GX_PTTEXMTX12:
return "GX_PTTEXMTX12";
case GX_PTTEXMTX13:
return "GX_PTTEXMTX13";
case GX_PTTEXMTX14:
return "GX_PTTEXMTX14";
case GX_PTTEXMTX15:
return "GX_PTTEXMTX15";
case GX_PTTEXMTX16:
return "GX_PTTEXMTX16";
case GX_PTTEXMTX17:
return "GX_PTTEXMTX17";
case GX_PTTEXMTX18:
return "GX_PTTEXMTX18";
case GX_PTTEXMTX19:
return "GX_PTTEXMTX19";
case GX_PTIDENTITY:
return "GX_PTIDENTITY";
default:
return fmt::format("GXPTTexMtx({})", static_cast<int>(mtx));
}
}
inline std::string format_as(const GXCompare& comp) {
switch (comp) {
case GX_NEVER:
return "GX_NEVER";
case GX_LESS:
return "GX_LESS";
case GX_EQUAL:
return "GX_EQUAL";
case GX_LEQUAL:
return "GX_LEQUAL";
case GX_GREATER:
return "GX_GREATER";
case GX_NEQUAL:
return "GX_NEQUAL";
case GX_GEQUAL:
return "GX_GEQUAL";
case GX_ALWAYS:
return "GX_ALWAYS";
default:
return fmt::format("GXCompare({})", static_cast<int>(comp));
}
}
inline std::string format_as(const GXAlphaOp& op) {
switch (op) {
case GX_AOP_AND:
return "GX_AOP_AND";
case GX_AOP_OR:
return "GX_AOP_OR";
case GX_AOP_XOR:
return "GX_AOP_XOR";
case GX_AOP_XNOR:
return "GX_AOP_XNOR";
default:
return fmt::format("GXAlphaOp({})", static_cast<int>(op));
}
}
inline std::string format_as(const GXFogType& type) {
switch (type) {
case GX_FOG_NONE:
return "GX_FOG_NONE";
case GX_FOG_PERSP_LIN:
return "GX_FOG_PERSP_LIN";
case GX_FOG_PERSP_EXP:
return "GX_FOG_PERSP_EXP";
case GX_FOG_PERSP_EXP2:
return "GX_FOG_PERSP_EXP2";
case GX_FOG_PERSP_REVEXP:
return "GX_FOG_PERSP_REVEXP";
case GX_FOG_PERSP_REVEXP2:
return "GX_FOG_PERSP_REVEXP2";
case GX_FOG_ORTHO_LIN:
return "GX_FOG_ORTHO_LIN";
case GX_FOG_ORTHO_EXP:
return "GX_FOG_ORTHO_EXP";
case GX_FOG_ORTHO_EXP2:
return "GX_FOG_ORTHO_EXP2";
case GX_FOG_ORTHO_REVEXP:
return "GX_FOG_ORTHO_REVEXP";
case GX_FOG_ORTHO_REVEXP2:
return "GX_FOG_ORTHO_REVEXP2";
default:
return fmt::format("GXFogType({})", static_cast<int>(type));
}
}
inline std::string format_as(const GXTexCoordID& id) {
switch (id) {
case GX_TEXCOORD0:
return "GX_TEXCOORD0";
case GX_TEXCOORD1:
return "GX_TEXCOORD1";
case GX_TEXCOORD2:
return "GX_TEXCOORD2";
case GX_TEXCOORD3:
return "GX_TEXCOORD3";
case GX_TEXCOORD4:
return "GX_TEXCOORD4";
case GX_TEXCOORD5:
return "GX_TEXCOORD5";
case GX_TEXCOORD6:
return "GX_TEXCOORD6";
case GX_TEXCOORD7:
return "GX_TEXCOORD7";
case GX_TEXCOORD_NULL:
return "GX_TEXCOORD_NULL";
default:
return fmt::format("GXTexCoordID({})", static_cast<int>(id));
}
}

View File

@ -2,8 +2,13 @@
#include "../webgpu/gpu.hpp"
#include "gx.hpp"
#include "gx_fmt.hpp"
#include <dolphin/gx/GXEnum.h>
#include <absl/container/flat_hash_map.h>
#include <string_view>
#include <utility>
constexpr bool EnableNormalVisualization = false;
constexpr bool EnableDebugPrints = false;
@ -157,15 +162,14 @@ static std::string color_arg_reg(GXTevColorArg arg, size_t stageIdx, const Shade
CHECK(stage.texMapId >= GX_TEXMAP0 && stage.texMapId <= GX_TEXMAP7, "invalid texture {} for stage {}",
static_cast<int>(stage.texMapId), stageIdx);
const auto& swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stageIdx, chan_comp(swap.red), chan_comp(swap.green),
chan_comp(swap.blue));
return fmt::format("sampled{}.{}{}{}", stageIdx, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue));
}
case GX_CC_TEXA: {
CHECK(stage.texMapId != GX_TEXMAP_NULL, "unmapped texture for stage {}", stageIdx);
CHECK(stage.texMapId >= GX_TEXMAP0 && stage.texMapId <= GX_TEXMAP7, "invalid texture {} for stage {}",
static_cast<int>(stage.texMapId), stageIdx);
const auto& swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("vec3<f32>(sampled{}.{})"), stageIdx, chan_comp(swap.alpha));
return fmt::format("vec3<f32>(sampled{}.{})", stageIdx, chan_comp(swap.alpha));
}
case GX_CC_RASC: {
CHECK(stage.channelId != GX_COLOR_NULL, "unmapped color channel for stage {}", stageIdx);
@ -176,8 +180,7 @@ static std::string color_arg_reg(GXTevColorArg arg, size_t stageIdx, const Shade
static_cast<int>(stage.channelId), stageIdx);
u32 idx = stage.channelId - GX_COLOR0A0;
const auto& swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}{}{}"), idx, chan_comp(swap.red), chan_comp(swap.green),
chan_comp(swap.blue));
return fmt::format("rast{}.{}{}{}", idx, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue));
}
case GX_CC_RASA: {
CHECK(stage.channelId != GX_COLOR_NULL, "unmapped color channel for stage {}", stageIdx);
@ -188,7 +191,7 @@ static std::string color_arg_reg(GXTevColorArg arg, size_t stageIdx, const Shade
static_cast<int>(stage.channelId), stageIdx);
u32 idx = stage.channelId - GX_COLOR0A0;
const auto& swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("vec3<f32>(rast{}.{})"), idx, chan_comp(swap.alpha));
return fmt::format("vec3<f32>(rast{}.{})", idx, chan_comp(swap.alpha));
}
case GX_CC_ONE:
return "vec3<f32>(1.0)";
@ -345,7 +348,7 @@ static std::string alpha_arg_reg(GXTevAlphaArg arg, size_t stageIdx, const Shade
CHECK(stage.texMapId >= GX_TEXMAP0 && stage.texMapId <= GX_TEXMAP7, "invalid texture {} for stage {}",
static_cast<int>(stage.texMapId), stageIdx);
const auto& swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("sampled{}.{}"), stageIdx, chan_comp(swap.alpha));
return fmt::format("sampled{}.{}", stageIdx, chan_comp(swap.alpha));
}
case GX_CA_RASA: {
CHECK(stage.channelId != GX_COLOR_NULL, "unmapped color channel for stage {}", stageIdx);
@ -356,7 +359,7 @@ static std::string alpha_arg_reg(GXTevAlphaArg arg, size_t stageIdx, const Shade
static_cast<int>(stage.channelId), stageIdx);
u32 idx = stage.channelId - GX_COLOR0A0;
const auto& swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha));
return fmt::format("rast{}.{}", idx, chan_comp(swap.alpha));
}
case GX_CA_KONST: {
switch (stage.kaSel) {
@ -445,17 +448,17 @@ static std::string alpha_compare(GXCompare comp, u8 ref, bool& valid) {
case GX_NEVER:
return "false"s;
case GX_LESS:
return fmt::format(FMT_STRING("(prev.a < {}f)"), fref);
return fmt::format("(prev.a < {}f)", fref);
case GX_LEQUAL:
return fmt::format(FMT_STRING("(prev.a <= {}f)"), fref);
return fmt::format("(prev.a <= {}f)", fref);
case GX_EQUAL:
return fmt::format(FMT_STRING("(prev.a == {}f)"), fref);
return fmt::format("(prev.a == {}f)", fref);
case GX_NEQUAL:
return fmt::format(FMT_STRING("(prev.a != {}f)"), fref);
return fmt::format("(prev.a != {}f)", fref);
case GX_GEQUAL:
return fmt::format(FMT_STRING("(prev.a >= {}f)"), fref);
return fmt::format("(prev.a >= {}f)", fref);
case GX_GREATER:
return fmt::format(FMT_STRING("(prev.a > {}f)"), fref);
return fmt::format("(prev.a > {}f)", fref);
case GX_ALWAYS:
valid = false;
return "true"s;
@ -493,11 +496,11 @@ static inline std::string vtx_attr(const ShaderConfig& config, GXAttr attr) {
}
if (attr == GX_VA_CLR0 || attr == GX_VA_CLR1) {
const auto idx = attr - GX_VA_CLR0;
return fmt::format(FMT_STRING("in_clr{}"), idx);
return fmt::format("in_clr{}", idx);
}
if (attr >= GX_VA_TEX0 && attr <= GX_VA_TEX7) {
const auto idx = attr - GX_VA_TEX0;
return fmt::format(FMT_STRING("in_tex{}_uv"), idx);
return fmt::format("in_tex{}_uv", idx);
}
UNLIKELY FATAL("unhandled vtx attr {}", static_cast<int>(attr));
}
@ -510,15 +513,14 @@ static inline std::string texture_conversion(const TextureConfig& tex, u32 stage
break;
case GX_TF_RGB565:
// Set alpha channel to 1.0
out += fmt::format(FMT_STRING("\n sampled{0}.a = 1.0;"), stageIdx);
out += fmt::format("\n sampled{0}.a = 1.0;", stageIdx);
break;
case GX_TF_I4:
case GX_TF_I8:
// FIXME HACK
if (!is_palette_format(tex.loadFmt)) {
// Perform intensity conversion
out += fmt::format(FMT_STRING("\n sampled{0} = vec4<f32>(intensityF32(sampled{0}.rgb), 0.f, 0.f, 1.f);"),
stageIdx);
out += fmt::format("\n sampled{0} = vec4<f32>(intensityF32(sampled{0}.rgb), 0.f, 0.f, 1.f);", stageIdx);
}
break;
}
@ -529,7 +531,7 @@ static inline std::string texture_conversion(const TextureConfig& tex, u32 stage
case GX_TF_I8:
case GX_TF_R8_PC:
// Splat R to RGBA
out += fmt::format(FMT_STRING("\n sampled{0} = vec4<f32>(sampled{0}.r);"), stageIdx);
out += fmt::format("\n sampled{0} = vec4<f32>(sampled{0}.r);", stageIdx);
break;
}
return out;
@ -663,52 +665,51 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
}
if (EnableDebugPrints) {
Log.report(LOG_INFO, FMT_STRING("Shader config (hash {:x}):"), hash);
Log.report(LOG_INFO, "Shader config (hash {:x}):", hash);
{
for (int i = 0; i < config.tevStageCount; ++i) {
const auto& stage = config.tevStages[i];
Log.report(LOG_INFO, FMT_STRING(" tevStages[{}]:"), i);
Log.report(LOG_INFO, FMT_STRING(" color_a: {}"), TevColorArgNames[stage.colorPass.a]);
Log.report(LOG_INFO, FMT_STRING(" color_b: {}"), TevColorArgNames[stage.colorPass.b]);
Log.report(LOG_INFO, FMT_STRING(" color_c: {}"), TevColorArgNames[stage.colorPass.c]);
Log.report(LOG_INFO, FMT_STRING(" color_d: {}"), TevColorArgNames[stage.colorPass.d]);
Log.report(LOG_INFO, FMT_STRING(" alpha_a: {}"), TevAlphaArgNames[stage.alphaPass.a]);
Log.report(LOG_INFO, FMT_STRING(" alpha_b: {}"), TevAlphaArgNames[stage.alphaPass.b]);
Log.report(LOG_INFO, FMT_STRING(" alpha_c: {}"), TevAlphaArgNames[stage.alphaPass.c]);
Log.report(LOG_INFO, FMT_STRING(" alpha_d: {}"), TevAlphaArgNames[stage.alphaPass.d]);
Log.report(LOG_INFO, FMT_STRING(" color_op_clamp: {}"), stage.colorOp.clamp);
Log.report(LOG_INFO, FMT_STRING(" color_op_op: {}"), stage.colorOp.op);
Log.report(LOG_INFO, FMT_STRING(" color_op_bias: {}"), stage.colorOp.bias);
Log.report(LOG_INFO, FMT_STRING(" color_op_scale: {}"), stage.colorOp.scale);
Log.report(LOG_INFO, FMT_STRING(" color_op_reg_id: {}"), stage.colorOp.outReg);
Log.report(LOG_INFO, FMT_STRING(" alpha_op_clamp: {}"), stage.alphaOp.clamp);
Log.report(LOG_INFO, FMT_STRING(" alpha_op_op: {}"), stage.alphaOp.op);
Log.report(LOG_INFO, FMT_STRING(" alpha_op_bias: {}"), stage.alphaOp.bias);
Log.report(LOG_INFO, FMT_STRING(" alpha_op_scale: {}"), stage.alphaOp.scale);
Log.report(LOG_INFO, FMT_STRING(" alpha_op_reg_id: {}"), stage.alphaOp.outReg);
Log.report(LOG_INFO, FMT_STRING(" kc_sel: {}"), stage.kcSel);
Log.report(LOG_INFO, FMT_STRING(" ka_sel: {}"), stage.kaSel);
Log.report(LOG_INFO, FMT_STRING(" texCoordId: {}"), stage.texCoordId);
Log.report(LOG_INFO, FMT_STRING(" texMapId: {}"), stage.texMapId);
Log.report(LOG_INFO, FMT_STRING(" channelId: {}"), stage.channelId);
Log.report(LOG_INFO, " tevStages[{}]:", i);
Log.report(LOG_INFO, " color_a: {}", TevColorArgNames[stage.colorPass.a]);
Log.report(LOG_INFO, " color_b: {}", TevColorArgNames[stage.colorPass.b]);
Log.report(LOG_INFO, " color_c: {}", TevColorArgNames[stage.colorPass.c]);
Log.report(LOG_INFO, " color_d: {}", TevColorArgNames[stage.colorPass.d]);
Log.report(LOG_INFO, " alpha_a: {}", TevAlphaArgNames[stage.alphaPass.a]);
Log.report(LOG_INFO, " alpha_b: {}", TevAlphaArgNames[stage.alphaPass.b]);
Log.report(LOG_INFO, " alpha_c: {}", TevAlphaArgNames[stage.alphaPass.c]);
Log.report(LOG_INFO, " alpha_d: {}", TevAlphaArgNames[stage.alphaPass.d]);
Log.report(LOG_INFO, " color_op_clamp: {}", stage.colorOp.clamp);
Log.report(LOG_INFO, " color_op_op: {}", stage.colorOp.op);
Log.report(LOG_INFO, " color_op_bias: {}", stage.colorOp.bias);
Log.report(LOG_INFO, " color_op_scale: {}", stage.colorOp.scale);
Log.report(LOG_INFO, " color_op_reg_id: {}", stage.colorOp.outReg);
Log.report(LOG_INFO, " alpha_op_clamp: {}", stage.alphaOp.clamp);
Log.report(LOG_INFO, " alpha_op_op: {}", stage.alphaOp.op);
Log.report(LOG_INFO, " alpha_op_bias: {}", stage.alphaOp.bias);
Log.report(LOG_INFO, " alpha_op_scale: {}", stage.alphaOp.scale);
Log.report(LOG_INFO, " alpha_op_reg_id: {}", stage.alphaOp.outReg);
Log.report(LOG_INFO, " kc_sel: {}", stage.kcSel);
Log.report(LOG_INFO, " ka_sel: {}", stage.kaSel);
Log.report(LOG_INFO, " texCoordId: {}", stage.texCoordId);
Log.report(LOG_INFO, " texMapId: {}", stage.texMapId);
Log.report(LOG_INFO, " channelId: {}", stage.channelId);
}
for (int i = 0; i < config.colorChannels.size(); ++i) {
const auto& chan = config.colorChannels[i];
Log.report(LOG_INFO, FMT_STRING(" colorChannels[{}]: enabled {} mat {} amb {}"), i, chan.lightingEnabled,
chan.matSrc, chan.ambSrc);
Log.report(LOG_INFO, " colorChannels[{}]: enabled {} mat {} amb {}", i, chan.lightingEnabled, chan.matSrc,
chan.ambSrc);
}
for (int i = 0; i < config.tcgs.size(); ++i) {
const auto& tcg = config.tcgs[i];
if (tcg.src != GX_MAX_TEXGENSRC) {
Log.report(LOG_INFO, FMT_STRING(" tcg[{}]: src {} mtx {} post {} type {} norm {}"), i, tcg.src, tcg.mtx,
tcg.postMtx, tcg.type, tcg.normalize);
Log.report(LOG_INFO, " tcg[{}]: src {} mtx {} post {} type {} norm {}", i, tcg.src, tcg.mtx, tcg.postMtx,
tcg.type, tcg.normalize);
}
}
Log.report(LOG_INFO, FMT_STRING(" alphaCompare: comp0 {} ref0 {} op {} comp1 {} ref1 {}"),
config.alphaCompare.comp0, config.alphaCompare.ref0, config.alphaCompare.op, config.alphaCompare.comp1,
config.alphaCompare.ref1);
Log.report(LOG_INFO, FMT_STRING(" indexedAttributeCount: {}"), config.indexedAttributeCount);
Log.report(LOG_INFO, FMT_STRING(" fogType: {}"), config.fogType);
Log.report(LOG_INFO, " alphaCompare: comp0 {} ref0 {} op {} comp1 {} ref1 {}", config.alphaCompare.comp0,
config.alphaCompare.ref0, config.alphaCompare.op, config.alphaCompare.comp1, config.alphaCompare.ref1);
Log.report(LOG_INFO, " indexedAttributeCount: {}", config.indexedAttributeCount);
Log.report(LOG_INFO, " fogType: {}", config.fogType);
}
}
@ -742,7 +743,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
attrName = VtxAttributeNames[attr];
}
vtxXfrAttrsPre +=
fmt::format(FMT_STRING("\n var {} = v_arr_{}[in_dl{}[{}]];"), vtx_attr(config, attr), attrName, div, rem);
fmt::format("\n var {} = v_arr_{}[in_dl{}[{}]];", vtx_attr(config, attr), attrName, div, rem);
if (addUniformBinding) {
std::string_view arrType;
if (attr == GX_VA_POS || attr == GX_VA_NRM) {
@ -769,7 +770,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
} else {
vtxInAttrs += "\n ";
}
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_dl{}: vec4<i32>"), locIdx++, i);
vtxInAttrs += fmt::format("@location({}) in_dl{}: vec4<i32>", locIdx++, i);
}
for (u32 i = 0; i < num2xAttrArrays; ++i) {
if (locIdx > 0) {
@ -777,7 +778,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
} else {
vtxInAttrs += "\n ";
}
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_dl{}: vec2<i32>"), locIdx++, num4xAttrArrays + i);
vtxInAttrs += fmt::format("@location({}) in_dl{}: vec2<i32>", locIdx++, num4xAttrArrays + i);
}
}
for (GXAttr attr{}; attr < MaxVtxAttr; attr = GXAttr(attr + 1)) {
@ -791,21 +792,22 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
vtxInAttrs += "\n ";
}
if (attr == GX_VA_POS) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_pos: vec3<f32>"), locIdx++);
vtxInAttrs += fmt::format("@location({}) in_pos: vec3<f32>", locIdx++);
} else if (attr == GX_VA_NRM) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_nrm: vec3<f32>"), locIdx++);
vtxInAttrs += fmt::format("@location({}) in_nrm: vec3<f32>", locIdx++);
} else if (attr == GX_VA_CLR0 || attr == GX_VA_CLR1) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_clr{}: vec4<f32>"), locIdx++, attr - GX_VA_CLR0);
vtxInAttrs += fmt::format("@location({}) in_clr{}: vec4<f32>", locIdx++, attr - GX_VA_CLR0);
} else if (attr >= GX_VA_TEX0 && attr <= GX_VA_TEX7) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_tex{}_uv: vec2<f32>"), locIdx++, attr - GX_VA_TEX0);
vtxInAttrs += fmt::format("@location({}) in_tex{}_uv: vec2<f32>", locIdx++, attr - GX_VA_TEX0);
}
}
vtxXfrAttrsPre += fmt::format(FMT_STRING("\n var mv_pos = mul4x3(ubuf.pos_mtx, vec4<f32>({}, 1.0));"
"\n var mv_nrm = normalize(mul4x3(ubuf.nrm_mtx, vec4<f32>({}, 0.0)));"
"\n out.pos = mul4x4(ubuf.proj, vec4<f32>(mv_pos, 1.0));"),
vtx_attr(config, GX_VA_POS), vtx_attr(config, GX_VA_NRM));
vtxXfrAttrsPre += fmt::format(
"\n var mv_pos = mul4x3(ubuf.pos_mtx, vec4<f32>({}, 1.0));"
"\n var mv_nrm = normalize(mul4x3(ubuf.nrm_mtx, vec4<f32>({}, 0.0)));"
"\n out.pos = mul4x4(ubuf.proj, vec4<f32>(mv_pos, 1.0));",
vtx_attr(config, GX_VA_POS), vtx_attr(config, GX_VA_NRM));
if constexpr (EnableNormalVisualization) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3<f32>,"), vtxOutIdx++);
vtxOutAttrs += fmt::format("\n @location({}) nrm: vec3<f32>,", vtxOutIdx++);
vtxXfrAttrsPre += "\n out.nrm = mv_nrm;";
}
@ -831,15 +833,14 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
break;
}
std::string op = fmt::format(
FMT_STRING("(({4}mix({0}, {1}, {2}) + {3}){5}){6}"), color_arg_reg(stage.colorPass.a, idx, config, stage),
"(({4}mix({0}, {1}, {2}) + {3}){5}){6}", color_arg_reg(stage.colorPass.a, idx, config, stage),
color_arg_reg(stage.colorPass.b, idx, config, stage), color_arg_reg(stage.colorPass.c, idx, config, stage),
color_arg_reg(stage.colorPass.d, idx, config, stage), tev_op(stage.colorOp.op), tev_bias(stage.colorOp.bias),
tev_scale(stage.colorOp.scale));
if (stage.colorOp.clamp) {
op = fmt::format(FMT_STRING("clamp({}, vec3<f32>(0.0), vec3<f32>(1.0))"), op);
op = fmt::format("clamp({}, vec3<f32>(0.0), vec3<f32>(1.0))", op);
}
fragmentFn +=
fmt::format(FMT_STRING("\n // TEV stage {2}\n {0} = vec4<f32>({1}, {0}.a);"), outReg, op, idx);
fragmentFn += fmt::format("\n // TEV stage {2}\n {0} = vec4<f32>({1}, {0}.a);", outReg, op, idx);
}
{
std::string outReg;
@ -859,14 +860,14 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
break;
}
std::string op = fmt::format(
FMT_STRING("(({4}mix({0}, {1}, {2}) + {3}){5}){6}"), alpha_arg_reg(stage.alphaPass.a, idx, config, stage),
"(({4}mix({0}, {1}, {2}) + {3}){5}){6}", alpha_arg_reg(stage.alphaPass.a, idx, config, stage),
alpha_arg_reg(stage.alphaPass.b, idx, config, stage), alpha_arg_reg(stage.alphaPass.c, idx, config, stage),
alpha_arg_reg(stage.alphaPass.d, idx, config, stage), tev_op(stage.alphaOp.op), tev_bias(stage.alphaOp.bias),
tev_scale(stage.alphaOp.scale));
if (stage.alphaOp.clamp) {
op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op);
op = fmt::format("clamp({}, 0.0, 1.0)", op);
}
fragmentFn += fmt::format(FMT_STRING("\n {0} = {1};"), outReg, op);
fragmentFn += fmt::format("\n {0} = {1};", outReg, op);
}
}
if (info.loadsTevReg.test(0)) {
@ -877,10 +878,10 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
}
for (int i = 1 /* Skip TEVPREV */; i < info.loadsTevReg.size(); ++i) {
if (info.loadsTevReg.test(i)) {
uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4<f32>,"), i - 1);
fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i - 1);
uniBufAttrs += fmt::format("\n tevreg{}: vec4<f32>,", i - 1);
fragmentFnPre += fmt::format("\n var tevreg{0} = ubuf.tevreg{0};", i - 1);
} else if (info.writesTevReg.test(i)) {
fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0}: vec4<f32>;"), i - 1);
fragmentFnPre += fmt::format("\n var tevreg{0}: vec4<f32>;", i - 1);
}
}
bool addedLightStruct = false;
@ -909,8 +910,8 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
" dist_att: vec3<f32>,\n"
"};";
if (UsePerPixelLighting) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) mv_pos: vec3<f32>,"), vtxOutIdx++);
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) mv_nrm: vec3<f32>,"), vtxOutIdx++);
vtxOutAttrs += fmt::format("\n @location({}) mv_pos: vec3<f32>,", vtxOutIdx++);
vtxOutAttrs += fmt::format("\n @location({}) mv_nrm: vec3<f32>,", vtxOutIdx++);
vtxXfrAttrs += fmt::format(FMT_STRING(R"""(
out.mv_pos = mv_pos;
out.mv_nrm = mv_nrm;)"""));
@ -919,16 +920,16 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
}
if (cc.lightingEnabled && cc.ambSrc == GX_SRC_REG) {
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_amb: vec4<f32>,"), i);
uniBufAttrs += fmt::format("\n cc{0}_amb: vec4<f32>,", i);
}
if (cc.matSrc == GX_SRC_REG) {
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>,"), i);
uniBufAttrs += fmt::format("\n cc{0}_mat: vec4<f32>,", i);
}
if (cca.lightingEnabled && cca.ambSrc == GX_SRC_REG) {
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}a_amb: vec4<f32>,"), i);
uniBufAttrs += fmt::format("\n cc{0}a_amb: vec4<f32>,", i);
}
if (cca.matSrc == GX_SRC_REG) {
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}a_mat: vec4<f32>,"), i);
uniBufAttrs += fmt::format("\n cc{0}a_mat: vec4<f32>,", i);
}
// Output vertex color if necessary
@ -936,8 +937,8 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
if (((cc.lightingEnabled && cc.ambSrc == GX_SRC_VTX) || cc.matSrc == GX_SRC_VTX ||
(cca.lightingEnabled && cca.matSrc == GX_SRC_VTX) || cca.matSrc == GX_SRC_VTX)) {
if (UsePerPixelLighting) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) clr{}: vec4<f32>,"), vtxOutIdx++, vtxColorIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.clr{} = {};"), vtxColorIdx,
vtxOutAttrs += fmt::format("\n @location({}) clr{}: vec4<f32>,", vtxOutIdx++, vtxColorIdx);
vtxXfrAttrs += fmt::format("\n out.clr{} = {};", vtxColorIdx,
vtx_attr(config, static_cast<GXAttr>(GX_VA_CLR0 + vtxColorIdx)));
}
usesVtxColor = true;
@ -948,21 +949,21 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
std::string ambSrc, matSrc, lightAttnFn, lightDiffFn;
if (cc.ambSrc == GX_SRC_VTX) {
if (UsePerPixelLighting) {
ambSrc = fmt::format(FMT_STRING("in.clr{}"), vtxColorIdx);
ambSrc = fmt::format("in.clr{}", vtxColorIdx);
} else {
ambSrc = vtx_attr(config, static_cast<GXAttr>(GX_VA_CLR0 + vtxColorIdx));
}
} else if (cc.ambSrc == GX_SRC_REG) {
ambSrc = fmt::format(FMT_STRING("ubuf.cc{0}_amb"), i);
ambSrc = fmt::format("ubuf.cc{0}_amb", i);
}
if (cc.matSrc == GX_SRC_VTX) {
if (UsePerPixelLighting) {
matSrc = fmt::format(FMT_STRING("in.clr{}"), vtxColorIdx);
matSrc = fmt::format("in.clr{}", vtxColorIdx);
} else {
matSrc = vtx_attr(config, static_cast<GXAttr>(GX_VA_CLR0 + vtxColorIdx));
}
} else if (cc.matSrc == GX_SRC_REG) {
matSrc = fmt::format(FMT_STRING("ubuf.cc{0}_mat"), i);
matSrc = fmt::format("ubuf.cc{0}_mat", i);
}
GXDiffuseFn diffFn = cc.diffFn;
if (cc.attnFn == GX_AF_NONE) {
@ -994,10 +995,10 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
}
std::string outVar, posVar;
if (UsePerPixelLighting) {
outVar = fmt::format(FMT_STRING("rast{}"), i);
outVar = fmt::format("rast{}", i);
posVar = "in.mv_pos";
} else {
outVar = fmt::format(FMT_STRING("out.cc{}"), i);
outVar = fmt::format("out.cc{}", i);
posVar = "mv_pos";
}
auto lightFunc = fmt::format(FMT_STRING(R"""(
@ -1019,25 +1020,24 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
}})"""),
i, GX::MaxLights, lightAttnFn, lightDiffFn, matSrc, ambSrc, outVar, posVar);
if (UsePerPixelLighting) {
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{}: vec4<f32>;"), i);
fragmentFnPre += fmt::format("\n var rast{}: vec4<f32>;", i);
fragmentFnPre += lightFunc;
} else {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>,"), vtxOutIdx++, i);
vtxOutAttrs += fmt::format("\n @location({}) cc{}: vec4<f32>,", vtxOutIdx++, i);
vtxXfrAttrs += lightFunc;
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
fragmentFnPre += fmt::format("\n var rast{0} = in.cc{0};", i);
}
} else if (cc.matSrc == GX_SRC_VTX) {
if (UsePerPixelLighting) {
// Color will already be written to clr{}
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.clr{0};"), vtxColorIdx);
fragmentFnPre += fmt::format("\n var rast{0} = in.clr{0};", vtxColorIdx);
} else {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>,"), vtxOutIdx++, i);
vtxXfrAttrs +=
fmt::format(FMT_STRING("\n out.cc{} = {};"), i, vtx_attr(config, GXAttr(GX_VA_CLR0 + vtxColorIdx)));
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
vtxOutAttrs += fmt::format("\n @location({}) cc{}: vec4<f32>,", vtxOutIdx++, i);
vtxXfrAttrs += fmt::format("\n out.cc{} = {};", i, vtx_attr(config, GXAttr(GX_VA_CLR0 + vtxColorIdx)));
fragmentFnPre += fmt::format("\n var rast{0} = in.cc{0};", i);
}
} else {
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = ubuf.cc{0}_mat;"), i);
fragmentFnPre += fmt::format("\n var rast{0} = ubuf.cc{0}_mat;", i);
}
if (usesVtxColor) {
@ -1046,7 +1046,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
}
for (int i = 0; i < info.sampledKColors.size(); ++i) {
if (info.sampledKColors.test(i)) {
uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4<f32>,"), i);
uniBufAttrs += fmt::format("\n kcolor{}: vec4<f32>,", i);
}
}
for (int i = 0; i < info.sampledTexCoords.size(); ++i) {
@ -1054,34 +1054,34 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
continue;
}
const auto& tcg = config.tcgs[i];
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>,"), vtxOutIdx++, i);
vtxOutAttrs += fmt::format("\n @location({}) tex{}_uv: vec2<f32>,", vtxOutIdx++, i);
if (tcg.src >= GX_TG_TEX0 && tcg.src <= GX_TG_TEX7) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>({}, 0.0, 1.0);"), i,
vtxXfrAttrs += fmt::format("\n var tc{} = vec4<f32>({}, 0.0, 1.0);", i,
vtx_attr(config, GXAttr(GX_VA_TEX0 + (tcg.src - GX_TG_TEX0))));
} else if (tcg.src == GX_TG_POS) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(in_pos, 1.0);"), i);
vtxXfrAttrs += fmt::format("\n var tc{} = vec4<f32>(in_pos, 1.0);", i);
} else if (tcg.src == GX_TG_NRM) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(in_nrm, 1.0);"), i);
vtxXfrAttrs += fmt::format("\n var tc{} = vec4<f32>(in_nrm, 1.0);", i);
} else
UNLIKELY FATAL("unhandled tcg src {}", static_cast<int>(tcg.src));
if (tcg.mtx == GX_IDENTITY) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_tmp = tc{0}.xyz;"), i);
vtxXfrAttrs += fmt::format("\n var tc{0}_tmp = tc{0}.xyz;", i);
} else {
u32 texMtxIdx = (tcg.mtx - GX_TEXMTX0) / 3;
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_tmp = mul{2}(ubuf.texmtx{1}, tc{0});"), i, texMtxIdx,
vtxXfrAttrs += fmt::format("\n var tc{0}_tmp = mul{2}(ubuf.texmtx{1}, tc{0});", i, texMtxIdx,
info.texMtxTypes[texMtxIdx] == GX_TG_MTX3x4 ? "4x3" : "4x2");
}
if (tcg.normalize) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n tc{0}_tmp = normalize(tc{0}_tmp);"), i);
vtxXfrAttrs += fmt::format("\n tc{0}_tmp = normalize(tc{0}_tmp);", i);
}
if (tcg.postMtx == GX_PTIDENTITY) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = tc{0}_tmp;"), i);
vtxXfrAttrs += fmt::format("\n var tc{0}_proj = tc{0}_tmp;", i);
} else {
u32 postMtxIdx = (tcg.postMtx - GX_PTTEXMTX0) / 3;
vtxXfrAttrs += fmt::format(
FMT_STRING("\n var tc{0}_proj = mul4x3(ubuf.postmtx{1}, vec4<f32>(tc{0}_tmp.xyz, 1.0));"), i, postMtxIdx);
vtxXfrAttrs +=
fmt::format("\n var tc{0}_proj = mul4x3(ubuf.postmtx{1}, vec4<f32>(tc{0}_tmp.xyz, 1.0));", i, postMtxIdx);
}
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.tex{0}_uv = tc{0}_proj.xy;"), i);
vtxXfrAttrs += fmt::format("\n out.tex{0}_uv = tc{0}_proj.xy;", i);
}
for (int i = 0; i < config.tevStages.size(); ++i) {
const auto& stage = config.tevStages[i];
@ -1091,7 +1091,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
|| !info.sampledTextures.test(stage.texMapId)) {
continue;
}
std::string uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), stage.texCoordId);
std::string uvIn = fmt::format("in.tex{0}_uv", static_cast<int>(stage.texCoordId));
const auto& texConfig = config.textureConfig[stage.texMapId];
if (is_palette_format(texConfig.loadFmt)) {
std::string_view suffix;
@ -1109,13 +1109,12 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
// break;
}
}
fragmentFnPre +=
fmt::format(FMT_STRING("\n var sampled{0} = textureSamplePalette{3}(tex{1}, tex{1}_samp, {2}, tlut{1});"),
i, stage.texMapId, uvIn, suffix);
fragmentFnPre += fmt::format("\n var sampled{0} = textureSamplePalette{3}(tex{1}, tex{1}_samp, {2}, tlut{1});",
i, static_cast<int>(stage.texMapId), uvIn, suffix);
} else {
fragmentFnPre += fmt::format(
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{1}, tex{1}_samp, {2}, ubuf.tex{1}_lod);"), i,
stage.texMapId, uvIn);
fragmentFnPre +=
fmt::format("\n var sampled{0} = textureSampleBias(tex{1}, tex{1}_samp, {2}, ubuf.tex{1}_lod);", i,
static_cast<int>(stage.texMapId), uvIn);
}
fragmentFnPre += texture_conversion(texConfig, i, stage.texMapId);
}
@ -1124,17 +1123,17 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
switch (info.texMtxTypes[i]) {
DEFAULT_FATAL("unhandled tex mtx type {}", static_cast<int>(info.texMtxTypes[i]));
case GX_TG_MTX2x4:
uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mtx4x2,"), i);
uniBufAttrs += fmt::format("\n texmtx{}: mtx4x2,", i);
break;
case GX_TG_MTX3x4:
uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mtx4x3,"), i);
uniBufAttrs += fmt::format("\n texmtx{}: mtx4x3,", i);
break;
}
}
}
for (int i = 0; i < info.usesPTTexMtx.size(); ++i) {
if (info.usesPTTexMtx.test(i)) {
uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mtx4x3,"), i);
uniBufAttrs += fmt::format("\n postmtx{}: mtx4x3,", i);
}
}
if (info.usesFog) {
@ -1182,7 +1181,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
if (!info.sampledTextures.test(i)) {
continue;
}
uniBufAttrs += fmt::format(FMT_STRING("\n tex{}_lod: f32,"), i);
uniBufAttrs += fmt::format("\n tex{}_lod: f32,", i);
sampBindings += fmt::format(FMT_STRING("\n@group(1) @binding({})\n"
"var tex{}_samp: sampler;"),
@ -1215,16 +1214,16 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
switch (config.alphaCompare.op) {
DEFAULT_FATAL("invalid alpha compare op {}", static_cast<int>(config.alphaCompare.op));
case GX_AOP_AND:
fragmentFn += fmt::format(FMT_STRING("\n if (!({} && {})) {{ discard; }}"), comp0, comp1);
fragmentFn += fmt::format("\n if (!({} && {})) {{ discard; }}", comp0, comp1);
break;
case GX_AOP_OR:
fragmentFn += fmt::format(FMT_STRING("\n if (!({} || {})) {{ discard; }}"), comp0, comp1);
fragmentFn += fmt::format("\n if (!({} || {})) {{ discard; }}", comp0, comp1);
break;
case GX_AOP_XOR:
fragmentFn += fmt::format(FMT_STRING("\n if (!({} ^^ {})) {{ discard; }}"), comp0, comp1);
fragmentFn += fmt::format("\n if (!({} ^^ {})) {{ discard; }}", comp0, comp1);
break;
case GX_AOP_XNOR:
fragmentFn += fmt::format(FMT_STRING("\n if (({} ^^ {})) {{ discard; }}"), comp0, comp1);
fragmentFn += fmt::format("\n if (({} ^^ {})) {{ discard; }}", comp0, comp1);
break;
}
}
@ -1326,12 +1325,12 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {{{8}{7}
uniBufAttrs, sampBindings, texBindings, uniformBindings, vtxOutAttrs,
vtxInAttrs, vtxXfrAttrs, fragmentFn, fragmentFnPre, vtxXfrAttrsPre, uniformPre);
if (EnableDebugPrints) {
Log.report(LOG_INFO, FMT_STRING("Generated shader: {}"), shaderSource);
Log.report(LOG_INFO, "Generated shader: {}", shaderSource);
}
wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{};
wgslDescriptor.code = shaderSource.c_str();
const auto label = fmt::format(FMT_STRING("GX Shader {:x}"), hash);
const auto label = fmt::format("GX Shader {:x}", hash);
const auto shaderDescriptor = wgpu::ShaderModuleDescriptor{
.nextInChain = &wgslDescriptor,
.label = label.c_str(),

View File

@ -83,8 +83,8 @@ TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mi
offset += dataSize;
}
if (data.size() != UINT32_MAX && offset < data.size()) {
Log.report(LOG_WARNING, FMT_STRING("new_static_texture_2d[{}]: texture used {} bytes, but given {} bytes"), label,
offset, data.size());
Log.report(LOG_WARNING, "new_static_texture_2d[{}]: texture used {} bytes, but given {} bytes", label, offset,
data.size());
}
return handle;
}
@ -106,7 +106,7 @@ TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t m
.mipLevelCount = mips,
.sampleCount = 1,
};
const auto viewLabel = fmt::format(FMT_STRING("{} view"), label);
const auto viewLabel = fmt::format("{} view", label);
const wgpu::TextureViewDescriptor textureViewDescriptor{
.label = viewLabel.c_str(),
.format = wgpuFormat,
@ -136,7 +136,7 @@ TextureHandle new_render_texture(uint32_t width, uint32_t height, u32 fmt, const
.mipLevelCount = 1,
.sampleCount = 1,
};
const auto viewLabel = fmt::format(FMT_STRING("{} view"), label);
const auto viewLabel = fmt::format("{} view", label);
const wgpu::TextureViewDescriptor textureViewDescriptor{
.label = viewLabel.c_str(),
.format = wgpuFormat,
@ -196,8 +196,7 @@ void write_texture(const TextureRef& ref, ArrayRef<uint8_t> data) noexcept {
offset += dataSize;
}
if (data.size() != UINT32_MAX && offset < data.size()) {
Log.report(LOG_WARNING, FMT_STRING("write_texture: texture used {} bytes, but given {} bytes"), offset,
data.size());
Log.report(LOG_WARNING, "write_texture: texture used {} bytes, but given {} bytes", offset, data.size());
}
}
} // namespace aurora::gfx

View File

@ -101,13 +101,13 @@ static std::optional<std::string> remap_controller_layout(std::string mapping) {
idx++;
}
if (entries.contains("rightshoulder") && !entries.contains("leftshoulder")) {
Log.report(LOG_INFO, FMT_STRING("Remapping GameCube controller layout"));
Log.report(LOG_INFO, "Remapping GameCube controller layout");
entries.insert_or_assign("back", entries["rightshoulder"]);
// TODO trigger buttons may differ per platform
entries.insert_or_assign("leftshoulder", "b11");
entries.insert_or_assign("rightshoulder", "b10");
} else if (entries.contains("leftshoulder") && entries.contains("rightshoulder") && entries.contains("back")) {
Log.report(LOG_INFO, FMT_STRING("Controller has standard layout"));
Log.report(LOG_INFO, "Controller has standard layout");
#if 0
auto a = entries["a"sv];
entries.insert_or_assign("a"sv, entries["b"sv]);
@ -117,7 +117,7 @@ static std::optional<std::string> remap_controller_layout(std::string mapping) {
entries.insert_or_assign("x", entries["y"]);
entries.insert_or_assign("y", x);
} else {
Log.report(LOG_ERROR, FMT_STRING("Controller has unsupported layout: {}"), mapping);
Log.report(LOG_ERROR, "Controller has unsupported layout: {}", mapping);
return {};
}
for (auto [k, v] : entries) {
@ -139,11 +139,11 @@ SDL_JoystickID add_controller(SDL_JoystickID which) noexcept {
SDL_free(mapping);
if (newMapping) {
if (SDL_AddGamepadMapping(newMapping->c_str()) == -1) {
Log.report(LOG_ERROR, FMT_STRING("Failed to update controller mapping: {}"), SDL_GetError());
Log.report(LOG_ERROR, "Failed to update controller mapping: {}", SDL_GetError());
}
}
} else {
Log.report(LOG_ERROR, FMT_STRING("Failed to retrieve mapping for controller"));
Log.report(LOG_ERROR, "Failed to retrieve mapping for controller");
}
}
GameController controller;
@ -329,7 +329,7 @@ void __PADLoadMapping(aurora::input::GameController* controller) {
controller->m_mappingLoaded = true;
auto path = fmt::format(FMT_STRING("{}/{}_{:04X}_{:04X}.controller"), basePath, PADGetName(playerIndex),
auto path = fmt::format("{}/{}_{:04X}_{:04X}.controller", basePath, PADGetName(playerIndex),
controller->m_vid, controller->m_pid);
FILE* file = fopen(path.c_str(), "rb");
if (file == nullptr) {
@ -339,14 +339,14 @@ void __PADLoadMapping(aurora::input::GameController* controller) {
uint32_t magic = 0;
fread(&magic, 1, sizeof(uint32_t), file);
if (magic != SBIG('CTRL')) {
fmt::print(FMT_STRING("Invalid controller mapping magic!\n"));
aurora::input::Log.report(LOG_WARNING, "Invalid controller mapping magic!");
return;
}
uint32_t version = 0;
fread(&version, 1, sizeof(uint32_t), file);
if (version != 1) {
fmt::print(FMT_STRING("Invalid controller mapping version!\n"));
aurora::input::Log.report(LOG_WARNING, "Invalid controller mapping version!");
return;
}
@ -724,7 +724,7 @@ void PADSerializeMappings() {
if (!controller.second.m_mappingLoaded) {
__PADLoadMapping(&controller.second);
}
FILE* file = fopen(fmt::format(FMT_STRING("{}/{}_{:04X}_{:04X}.controller"), basePath,
FILE* file = fopen(fmt::format("{}/{}_{:04X}_{:04X}.controller", basePath,
aurora::input::controller_name(controller.second.m_index), controller.second.m_vid,
controller.second.m_pid)
.c_str(),

View File

@ -1,12 +1,11 @@
#pragma once
#include <aurora/aurora.h>
#include <fmt/base.h>
#include <fmt/format.h>
#include <string>
#include <string_view>
#include <vector>
#include <cassert>
#include <vector>
using namespace std::string_view_literals;
@ -43,7 +42,7 @@ using namespace std::string_view_literals;
#endif
#define FATAL(msg, ...) \
{ \
Log.report(LOG_FATAL, FMT_STRING(msg), ##__VA_ARGS__); \
Log.report(LOG_FATAL, msg, ##__VA_ARGS__); \
unreachable(); \
}
#define ASSERT(cond, msg, ...) \
@ -58,12 +57,12 @@ using namespace std::string_view_literals;
#define TRY(cond, msg, ...) \
if (!(cond)) \
UNLIKELY { \
Log.report(LOG_ERROR, FMT_STRING(msg), ##__VA_ARGS__); \
Log.report(LOG_ERROR, msg, ##__VA_ARGS__); \
return false; \
}
#define TRY_WARN(cond, msg, ...) \
if (!(cond)) \
UNLIKELY { Log.report(LOG_WARNING, FMT_STRING(msg), ##__VA_ARGS__); }
UNLIKELY { Log.report(LOG_WARNING, msg, ##__VA_ARGS__); }
namespace aurora {
extern AuroraConfig g_config;
@ -73,10 +72,10 @@ struct Module {
explicit Module(const char* name) noexcept : name(name) {}
template <typename... T>
inline void report(AuroraLogLevel level, fmt::format_string<T...> fmt, T&&... args) noexcept {
void report(AuroraLogLevel level, fmt::format_string<T...> fmt, T&&... args) noexcept {
auto message = fmt::format(fmt, std::forward<T>(args)...);
if (g_config.logCallback != nullptr) {
g_config.logCallback(level, message.c_str(), message.size());
g_config.logCallback(level, name, message.c_str(), message.size());
}
}
};

View File

@ -287,7 +287,7 @@ static wgpu::BackendType to_wgpu_backend(AuroraBackend backend) {
bool initialize(AuroraBackend auroraBackend) {
if (!g_instance) {
Log.report(LOG_INFO, FMT_STRING("Creating WGPU instance"));
Log.report(LOG_INFO, "Creating WGPU instance");
wgpu::InstanceDescriptor instanceDescriptor{
.capabilities =
{
@ -301,18 +301,18 @@ bool initialize(AuroraBackend auroraBackend) {
#endif
g_instance = wgpu::CreateInstance(&instanceDescriptor);
if (!g_instance) {
Log.report(LOG_ERROR, FMT_STRING("Failed to create WGPU instance"));
Log.report(LOG_ERROR, "Failed to create WGPU instance");
return false;
}
}
const wgpu::BackendType backend = to_wgpu_backend(auroraBackend);
#ifdef EMSCRIPTEN
if (backend != wgpu::BackendType::WebGPU) {
Log.report(LOG_WARNING, FMT_STRING("Backend type {} unsupported"), magic_enum::enum_name(backend));
Log.report(LOG_WARNING, "Backend type {} unsupported", magic_enum::enum_name(backend));
return false;
}
#endif
Log.report(LOG_INFO, FMT_STRING("Attempting to initialize {}"), magic_enum::enum_name(backend));
Log.report(LOG_INFO, "Attempting to initialize {}", magic_enum::enum_name(backend));
#if 0
// D3D12's debug layer is very slow
g_dawnInstance->EnableBackendValidation(backend != WGPUBackendType::D3D12);
@ -333,7 +333,7 @@ bool initialize(AuroraBackend auroraBackend) {
};
g_surface = g_instance.CreateSurface(&surfaceDescriptor);
if (!g_surface) {
Log.report(LOG_ERROR, FMT_STRING("Failed to create surface"));
Log.report(LOG_ERROR, "Failed to create surface");
return false;
}
{
@ -348,16 +348,16 @@ bool initialize(AuroraBackend auroraBackend) {
if (status == wgpu::RequestAdapterStatus::Success) {
g_adapter = std::move(adapter);
} else {
Log.report(LOG_WARNING, FMT_STRING("Adapter request failed: {}"), message);
Log.report(LOG_WARNING, "Adapter request failed: {}", message);
}
});
const auto status = g_instance.WaitAny(future, 5000000000);
if (status != wgpu::WaitStatus::Success) {
Log.report(LOG_ERROR, FMT_STRING("Failed to create adapter: {}"), magic_enum::enum_name(status));
Log.report(LOG_ERROR, "Failed to create adapter: {}", magic_enum::enum_name(status));
return false;
}
if (!g_adapter) {
Log.report(LOG_ERROR, FMT_STRING("Failed to create adapter"));
Log.report(LOG_ERROR, "Failed to create adapter");
return false;
}
}
@ -372,8 +372,9 @@ bool initialize(AuroraBackend auroraBackend) {
if (description.IsUndefined()) {
description = wgpu::StringView("Unknown");
}
Log.report(LOG_INFO, FMT_STRING("Graphics adapter information\n API: {}\n Device: {} ({})\n Driver: {}"),
backendName, adapterName, magic_enum::enum_name(g_adapterInfo.adapterType), description);
Log.report(LOG_INFO, "Graphics adapter information\n API: {}\n Device: {} ({})\n Driver: {}",
backendName, adapterName, magic_enum::enum_name(g_adapterInfo.adapterType),
description);
{
wgpu::Limits supportedLimits{};
@ -433,20 +434,20 @@ bool initialize(AuroraBackend auroraBackend) {
deviceDescriptor.SetDeviceLostCallback(
wgpu::CallbackMode::AllowSpontaneous,
[](const wgpu::Device& device, wgpu::DeviceLostReason reason, wgpu::StringView message) {
Log.report(LOG_WARNING, FMT_STRING("Device lost: {}"), message);
Log.report(LOG_WARNING, "Device lost: {}", message);
});
const auto future = g_adapter.RequestDevice(
&deviceDescriptor, wgpu::CallbackMode::WaitAnyOnly,
[](wgpu::RequestDeviceStatus status, wgpu::Device device, wgpu::StringView message) {
if (status == wgpu::RequestDeviceStatus::Success) {
g_device = std::move(device);
} else {
Log.report(LOG_WARNING, "Device request failed: {}", message);
}
});
const auto future =
g_adapter.RequestDevice(&deviceDescriptor, wgpu::CallbackMode::WaitAnyOnly,
[](wgpu::RequestDeviceStatus status, wgpu::Device device, wgpu::StringView message) {
if (status == wgpu::RequestDeviceStatus::Success) {
g_device = std::move(device);
} else {
Log.report(LOG_WARNING, FMT_STRING("Device request failed: {}"), message);
}
});
const auto status = g_instance.WaitAny(future, 5000000000);
if (status != wgpu::WaitStatus::Success) {
Log.report(LOG_ERROR, FMT_STRING("Failed to create device: {}"), magic_enum::enum_name(status));
Log.report(LOG_ERROR, "Failed to create device: {}", magic_enum::enum_name(status));
return false;
}
if (!g_device) {
@ -470,7 +471,7 @@ bool initialize(AuroraBackend auroraBackend) {
default:
break;
}
Log.report(level, FMT_STRING("WebGPU message: {}"), message);
Log.report(level, "WebGPU message: {}", message);
});
}
g_queue = g_device.GetQueue();
@ -478,15 +479,15 @@ bool initialize(AuroraBackend auroraBackend) {
wgpu::SurfaceCapabilities surfaceCapabilities;
const wgpu::Status status = g_surface.GetCapabilities(g_adapter, &surfaceCapabilities);
if (status != wgpu::Status::Success) {
Log.report(LOG_ERROR, FMT_STRING("Failed to get surface capabilities: {}"), magic_enum::enum_name(status));
Log.report(LOG_ERROR, "Failed to get surface capabilities: {}", magic_enum::enum_name(status));
return false;
}
if (surfaceCapabilities.formatCount == 0) {
Log.report(LOG_ERROR, FMT_STRING("Surface has no formats"));
Log.report(LOG_ERROR, "Surface has no formats");
return false;
}
if (surfaceCapabilities.presentModeCount == 0) {
Log.report(LOG_ERROR, FMT_STRING("Surface has no present modes"));
Log.report(LOG_ERROR, "Surface has no present modes");
return false;
}
auto surfaceFormat = surfaceCapabilities.formats[0];
@ -496,7 +497,7 @@ bool initialize(AuroraBackend auroraBackend) {
} else if (surfaceFormat == wgpu::TextureFormat::BGRA8UnormSrgb) {
surfaceFormat = wgpu::TextureFormat::BGRA8Unorm;
}
Log.report(LOG_INFO, FMT_STRING("Using surface format {}, present mode {}"), magic_enum::enum_name(surfaceFormat),
Log.report(LOG_INFO, "Using surface format {}, present mode {}", magic_enum::enum_name(surfaceFormat),
magic_enum::enum_name(presentMode));
const auto size = window::get_window_size();
g_graphicsConfig = GraphicsConfig{

View File

@ -3,7 +3,13 @@
#include <emscripten.h>
#endif
#include <string_view>
static inline bool operator==(const wgpu::Extent3D& lhs, const wgpu::Extent3D& rhs) {
return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depthOrArrayLayers == rhs.depthOrArrayLayers;
}
static inline bool operator!=(const wgpu::Extent3D& lhs, const wgpu::Extent3D& rhs) { return !(lhs == rhs); }
namespace wgpu {
inline std::string_view format_as(wgpu::StringView str) { return str; }
} // namespace wgpu

View File

@ -5,41 +5,69 @@
#include "input.hpp"
#include "internal.hpp"
#include <aurora/aurora.h>
#include <aurora/event.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_properties.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_video.h>
#include <SDL3/SDL_init.h>
#include <SDL3/SDL_hints.h>
#include <SDL3/SDL_stdinc.h>
#include <SDL3/SDL_pixels.h>
#include <cstdint>
#include <vector>
namespace aurora::window {
static Module Log("aurora::window");
namespace {
Module Log("aurora::window");
static SDL_Window* g_window;
static SDL_Renderer* g_renderer;
static AuroraWindowSize g_windowSize;
static std::vector<AuroraEvent> g_events;
SDL_Window* g_window;
SDL_Renderer* g_renderer;
AuroraWindowSize g_windowSize;
std::vector<AuroraEvent> g_events;
static inline bool operator==(const AuroraWindowSize& lhs, const AuroraWindowSize& rhs) {
inline bool operator==(const AuroraWindowSize& lhs, const AuroraWindowSize& rhs) {
return lhs.width == rhs.width && lhs.height == rhs.height && lhs.fb_width == rhs.fb_width &&
lhs.fb_height == rhs.fb_height && lhs.scale == rhs.scale;
}
static void resize_swapchain(bool force) noexcept {
void resize_swapchain() noexcept {
const auto size = get_window_size();
if (!force && size == g_windowSize) {
if (size == g_windowSize) {
return;
}
if (size.scale != g_windowSize.scale) {
if (g_windowSize.scale > 0.f) {
Log.report(LOG_INFO, FMT_STRING("Display scale changed to {}"), size.scale);
Log.report(LOG_INFO, "Display scale changed to {}", size.scale);
}
}
g_windowSize = size;
webgpu::resize_swapchain(size.fb_width, size.fb_height);
}
void set_window_icon() noexcept {
if (g_config.iconRGBA8 == nullptr) {
return;
}
auto* iconSurface =
SDL_CreateSurfaceFrom(static_cast<int>(g_config.iconWidth), static_cast<int>(g_config.iconHeight),
SDL_GetPixelFormatForMasks(32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
g_config.iconRGBA8, static_cast<int>(4 * g_config.iconWidth));
ASSERT(iconSurface != nullptr, "Failed to create icon surface: {}", SDL_GetError());
TRY_WARN(SDL_SetWindowIcon(g_window, iconSurface), "Failed to set window icon: {}", SDL_GetError());
SDL_DestroySurface(iconSurface);
}
} // namespace
const AuroraEvent* poll_events() {
g_events.clear();
SDL_Event event;
while (SDL_PollEvent(&event) != 0) {
while (SDL_PollEvent(&event)) {
imgui::process_event(event);
switch (event.type) {
@ -65,7 +93,7 @@ const AuroraEvent* poll_events() {
break;
}
case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: {
resize_swapchain(false);
resize_swapchain();
g_events.push_back(AuroraEvent{
.type = AURORA_DISPLAY_SCALE_CHANGED,
.windowSize = get_window_size(),
@ -73,7 +101,7 @@ const AuroraEvent* poll_events() {
break;
}
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: {
resize_swapchain(false);
resize_swapchain();
g_events.push_back(AuroraEvent{
.type = AURORA_WINDOW_RESIZED,
.windowSize = get_window_size(),
@ -100,6 +128,8 @@ const AuroraEvent* poll_events() {
g_events.push_back(AuroraEvent{
.type = AURORA_EXIT,
});
default:
break;
}
g_events.push_back(AuroraEvent{
@ -113,21 +143,8 @@ const AuroraEvent* poll_events() {
return g_events.data();
}
static void set_window_icon() noexcept {
if (g_config.iconRGBA8 == nullptr) {
return;
}
auto* iconSurface =
SDL_CreateSurfaceFrom(g_config.iconWidth, g_config.iconHeight,
SDL_GetPixelFormatForMasks(32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
g_config.iconRGBA8, 4 * g_config.iconWidth);
ASSERT(iconSurface != nullptr, "Failed to create icon surface: {}", SDL_GetError());
TRY_WARN(SDL_SetWindowIcon(g_window, iconSurface), "Failed to set window icon: {}", SDL_GetError());
SDL_DestroySurface(iconSurface);
}
bool create_window(AuroraBackend backend) {
Uint32 flags = SDL_WINDOW_HIGH_PIXEL_DENSITY;
SDL_WindowFlags flags = SDL_WINDOW_HIGH_PIXEL_DENSITY;
#if TARGET_OS_IOS || TARGET_OS_TV
flags |= SDL_WINDOW_FULLSCREEN;
#else
@ -157,30 +174,30 @@ bool create_window(AuroraBackend backend) {
break;
}
#ifdef __SWITCH__
uint32_t width = 1280;
uint32_t height = 720;
Sint32 width = 1280;
Sint32 height = 720;
#else
uint32_t width = g_config.windowWidth;
uint32_t height = g_config.windowHeight;
auto width = static_cast<Sint32>(g_config.windowWidth);
auto height = static_cast<Sint32>(g_config.windowHeight);
if (width == 0 || height == 0) {
width = 1280;
height = 960;
}
int32_t x = g_config.windowPosX;
int32_t y = g_config.windowPosY;
if (x < 0 || y < 0) {
x = SDL_WINDOWPOS_UNDEFINED;
y = SDL_WINDOWPOS_UNDEFINED;
Sint32 posX = g_config.windowPosX;
Sint32 posY = g_config.windowPosY;
if (posX < 0 || posY < 0) {
posX = SDL_WINDOWPOS_UNDEFINED;
posY = SDL_WINDOWPOS_UNDEFINED;
}
#endif
const auto props = SDL_CreateProperties();
TRY(SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, g_config.appName), "Failed to set {}: {}",
SDL_PROP_WINDOW_CREATE_TITLE_STRING, SDL_GetError());
TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x), "Failed to set {}: {}",
TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, posX), "Failed to set {}: {}",
SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_GetError());
TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y), "Failed to set {}: {}",
TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, posY), "Failed to set {}: {}",
SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_GetError());
TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width), "Failed to set {}: {}",
SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, SDL_GetError());
@ -190,7 +207,7 @@ bool create_window(AuroraBackend backend) {
SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, SDL_GetError());
g_window = SDL_CreateWindowWithProperties(props);
if (g_window == nullptr) {
Log.report(LOG_ERROR, FMT_STRING("Failed to create window: {}"), SDL_GetError());
Log.report(LOG_ERROR, "Failed to create window: {}", SDL_GetError());
return false;
}
set_window_icon();
@ -208,7 +225,7 @@ bool create_renderer() {
"Failed to set {}: {}", SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, SDL_GetError());
g_renderer = SDL_CreateRendererWithProperties(props);
if (g_renderer == nullptr) {
Log.report(LOG_ERROR, FMT_STRING("Failed to create renderer: {}"), SDL_GetError());
Log.report(LOG_ERROR, "Failed to create renderer: {}", SDL_GetError());
return false;
}
return true;
@ -260,10 +277,13 @@ void shutdown() {
}
AuroraWindowSize get_window_size() {
int width, height, fb_w, fb_h;
int width = 0;
int height = 0;
int fb_w = 0;
int fb_h = 0;
ASSERT(SDL_GetWindowSize(g_window, &width, &height), "Failed to get window size: {}", SDL_GetError());
ASSERT(SDL_GetWindowSizeInPixels(g_window, &fb_w, &fb_h), "Failed to get window size in pixels: {}", SDL_GetError());
float scale = SDL_GetWindowDisplayScale(g_window);
const float scale = SDL_GetWindowDisplayScale(g_window);
return {
.width = static_cast<uint32_t>(width),
.height = static_cast<uint32_t>(height),