2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-18 10:05:24 +00:00

Implement CGX & migrate usages to CGX/GX

This commit is contained in:
2022-03-12 10:47:20 -05:00
parent 929bb65417
commit a3d0da44e2
31 changed files with 1560 additions and 912 deletions

View File

@@ -4,7 +4,119 @@
#include "common.hpp"
#include <unordered_map>
#include <magic_enum.hpp>
using aurora::gfx::gx::g_gxState;
static logvisor::Module Log("aurora::gx");
void GXSetNumChans(u8 num) noexcept { g_gxState.numChans = num; }
void GXSetNumIndStages(u8 num) noexcept { g_gxState.numIndStages = num; }
void GXSetNumTevStages(u8 num) noexcept { g_gxState.numTevStages = num; }
void GXSetNumTexGens(u8 num) noexcept { g_gxState.numTexGens = num; }
void GXSetTevAlphaIn(GX::TevStageID stageId, GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c,
GX::TevAlphaArg d) noexcept {
g_gxState.tevStages[stageId].alphaPass = {a, b, c, d};
}
void GXSetTevAlphaOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, bool clamp,
GX::TevRegID outReg) noexcept {
g_gxState.tevStages[stageId].alphaOp = {op, bias, scale, outReg, clamp};
}
void GXSetTevColorIn(GX::TevStageID stageId, GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c,
GX::TevColorArg d) noexcept {
g_gxState.tevStages[stageId].colorPass = {a, b, c, d};
}
void GXSetTevColorOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, bool clamp,
GX::TevRegID outReg) noexcept {
g_gxState.tevStages[stageId].colorOp = {op, bias, scale, outReg, clamp};
}
void GXSetCullMode(GX::CullMode mode) noexcept { g_gxState.cullMode = mode; }
void GXSetBlendMode(GX::BlendMode mode, GX::BlendFactor src, GX::BlendFactor dst, GX::LogicOp op) noexcept {
g_gxState.blendMode = mode;
g_gxState.blendFacSrc = src;
g_gxState.blendFacDst = dst;
g_gxState.blendOp = op;
}
void GXSetZMode(bool compare_enable, GX::Compare func, bool update_enable) noexcept {
g_gxState.depthCompare = compare_enable;
g_gxState.depthFunc = func;
g_gxState.depthUpdate = update_enable;
}
void GXSetTevColor(GX::TevRegID id, const zeus::CColor& color) noexcept {
if (id < GX::TEVREG0 || id > GX::TEVREG2) {
Log.report(logvisor::Fatal, FMT_STRING("bad tevreg {}"), id);
unreachable();
}
g_gxState.colorRegs[id - 1] = color;
}
void GXSetTevKColor(GX::TevKColorID id, const zeus::CColor& color) noexcept {
if (id >= GX::MAX_KCOLOR) {
Log.report(logvisor::Fatal, FMT_STRING("bad kcolor {}"), id);
unreachable();
}
g_gxState.kcolors[id] = color;
}
void GXSetAlphaUpdate(bool enabled) noexcept { g_gxState.alphaUpdate = enabled; }
void GXSetDstAlpha(bool enabled, float value) noexcept {
if (enabled) {
g_gxState.dstAlpha = value;
} else {
g_gxState.dstAlpha.reset();
}
}
void GXSetCopyClear(const zeus::CColor& color, float depth) noexcept { g_gxState.clearColor = color; }
void GXSetTevOrder(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept {
auto& stage = g_gxState.tevStages[id];
stage.texCoordId = tcid;
stage.texMapId = tmid;
stage.channelId = cid;
}
void GXSetTevKColorSel(GX::TevStageID id, GX::TevKColorSel sel) noexcept { g_gxState.tevStages[id].kcSel = sel; }
void GXSetTevKAlphaSel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept { g_gxState.tevStages[id].kaSel = sel; }
void GXSetChanAmbColor(GX::ChannelID id, const zeus::CColor& color) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id);
unreachable();
}
g_gxState.colorChannelState[id - GX::COLOR0A0].ambColor = color;
}
void GXSetChanMatColor(GX::ChannelID id, const zeus::CColor& color) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id);
unreachable();
}
g_gxState.colorChannelState[id - GX::COLOR0A0].matColor = color;
}
void GXSetChanCtrl(GX::ChannelID id, bool lightingEnabled, GX::ColorSrc ambSrc, GX::ColorSrc matSrc,
GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id);
unreachable();
}
if (diffFn != GX::DF_NONE && diffFn != GX::DF_CLAMP) {
Log.report(logvisor::Fatal, FMT_STRING("unhandled diffuse fn {}"), diffFn);
unreachable();
}
if (attnFn != GX::AF_NONE && attnFn != GX::AF_SPOT) {
Log.report(logvisor::Fatal, FMT_STRING("unhandled attn fn {}"), attnFn);
unreachable();
}
u32 idx = id - GX::COLOR0A0;
auto& chan = g_gxState.colorChannelConfig[idx];
chan.lightingEnabled = lightingEnabled;
chan.ambSrc = ambSrc;
chan.matSrc = matSrc;
g_gxState.colorChannelState[idx].lightState = lightState;
}
void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept {
if (comp0 == GX::ALWAYS && comp1 == GX::ALWAYS) {
g_gxState.alphaDiscard.reset();
} else if (comp0 == GX::GEQUAL && comp1 == GX::NEVER) {
g_gxState.alphaDiscard = ref0;
} else {
Log.report(logvisor::Fatal, FMT_STRING("GXSetAlphaCompare: unknown operands"));
unreachable();
}
}
void GXSetVtxDescv(GX::VtxDescList* list) noexcept;
namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::gx");
@@ -14,51 +126,13 @@ extern std::mutex g_pipelineMutex;
// GX state
void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept {
gx::g_textures[static_cast<size_t>(id)] = {tex, clamp, lod};
gx::g_gxState.textures[static_cast<size_t>(id)] = {tex, clamp, lod};
}
void unbind_texture(GX::TexMapID id) noexcept { gx::g_textures[static_cast<size_t>(id)].reset(); }
void set_cull_mode(metaforce::ERglCullMode mode) noexcept { gx::g_cullMode = mode; }
void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst,
metaforce::ERglLogicOp op) noexcept {
gx::g_blendMode = mode;
gx::g_blendFacSrc = src;
gx::g_blendFacDst = dst;
gx::g_blendOp = op;
}
void set_depth_mode(bool compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept {
gx::g_depthCompare = compare_enable;
gx::g_depthFunc = func;
gx::g_depthUpdate = update_enable;
}
void set_tev_reg_color(GX::TevRegID id, const zeus::CColor& color) noexcept {
if (id < GX::TEVREG0 || id > GX::TEVREG2) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_reg_color: bad reg {}"), id);
unreachable();
}
gx::g_colorRegs[id - 1] = color;
}
void set_tev_k_color(GX::TevKColorID id, const zeus::CColor& color) noexcept {
if (id >= GX::MAX_KCOLOR) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_color: bad reg {}"), id);
unreachable();
}
gx::g_kcolors[id] = color;
}
void set_alpha_update(bool enabled) noexcept { gx::g_alphaUpdate = enabled; }
void set_dst_alpha(bool enabled, float value) noexcept {
if (enabled) {
gx::g_dstAlpha = value;
} else {
gx::g_dstAlpha.reset();
}
}
void set_clear_color(const zeus::CColor& color) noexcept { gx::g_clearColor = color; }
void set_alpha_discard(bool v) { gx::g_alphaDiscard = v; }
void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast<size_t>(id)].reset(); }
void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept {
gx::g_mv = mv;
gx::g_mvInv = mv_inv;
gx::g_gxState.mv = mv;
gx::g_gxState.mvInv = mv_inv;
}
constexpr zeus::CMatrix4f DepthCorrect{
// clang-format off
@@ -68,133 +142,44 @@ constexpr zeus::CMatrix4f DepthCorrect{
0.f, 0.f, 0.f, 1.f,
// clang-format on
};
void update_projection(const zeus::CMatrix4f& proj) noexcept { gx::g_proj = DepthCorrect * proj; }
void update_fog_state(const metaforce::CFogState& state) noexcept { gx::g_fogState = state; }
void update_projection(const zeus::CMatrix4f& proj) noexcept { gx::g_gxState.proj = DepthCorrect * proj; }
void update_fog_state(const metaforce::CFogState& state) noexcept { gx::g_gxState.fogState = state; }
void disable_tev_stage(metaforce::ERglTevStage stage) noexcept { gx::g_tevStages[static_cast<size_t>(stage)].reset(); }
void update_tev_stage(metaforce::ERglTevStage stage, const metaforce::CTevCombiners::ColorPass& colPass,
const metaforce::CTevCombiners::AlphaPass& alphaPass,
const metaforce::CTevCombiners::CTevOp& colorOp,
const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept {
gx::g_tevStages[static_cast<size_t>(stage)] = {colPass, alphaPass, colorOp, alphaOp};
void load_light(GX::LightID id, const Light& light) noexcept { gx::g_gxState.lights[std::log2<u32>(id)] = light; }
void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept {
gx::g_gxState.lights[std::log2<u32>(id)] = ambient;
}
void set_tev_order(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept {
auto& stage = gx::g_tevStages[id];
if (!stage) {
// Log.report(logvisor::Fatal, FMT_STRING("set_tev_order: disabled stage {}"), id);
// unreachable();
return;
}
stage->texCoordId = tcid;
stage->texMapId = tmid;
stage->channelId = cid;
}
void set_tev_k_color_sel(GX::TevStageID id, GX::TevKColorSel sel) noexcept {
auto& stage = gx::g_tevStages[id];
if (!stage) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_color_sel: disabled stage {}"), id);
unreachable();
}
stage->kcSel = sel;
}
void set_tev_k_alpha_sel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept {
auto& stage = gx::g_tevStages[id];
if (!stage) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_alpha_sel: disabled stage {}"), id);
unreachable();
}
stage->kaSel = sel;
}
void set_chan_amb_color(GX::ChannelID id, const zeus::CColor& color) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("set_chan_amb_color: invalid channel {}"), id);
unreachable();
}
gx::g_colorChannels[id - GX::COLOR0A0].ambColor = color;
}
void set_chan_mat_color(GX::ChannelID id, const zeus::CColor& color) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("set_chan_mat_color: invalid channel {}"), id);
unreachable();
}
gx::g_colorChannels[id - GX::COLOR0A0].matColor = color;
}
void set_chan_mat_src(GX::ChannelID id, GX::ColorSrc src) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("set_chan_mat_src: invalid channel {}"), id);
unreachable();
}
gx::g_colorChannels[id - GX::COLOR0A0].matSrc = src;
}
static inline u8 light_idx(GX::LightID id) {
#ifdef _MSC_VER
unsigned long r = 0;
_BitScanForward(&r, id);
return r;
#else
return __builtin_ctz(id);
#endif
}
void load_light(GX::LightID id, const Light& light) noexcept { gx::g_lights[light_idx(id)] = light; }
void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept { gx::g_lights[light_idx(id)] = ambient; }
void set_light_state(std::bitset<MaxLights> bits) noexcept { gx::g_lightState = bits; }
void set_light_state(GX::LightMask bits) noexcept { gx::g_gxState.lightState = bits; }
namespace gx {
using gpu::g_device;
using gpu::g_graphicsConfig;
zeus::CMatrix4f g_mv;
zeus::CMatrix4f g_mvInv;
zeus::CMatrix4f g_proj;
metaforce::CFogState g_fogState;
metaforce::ERglCullMode g_cullMode;
metaforce::ERglBlendMode g_blendMode;
metaforce::ERglBlendFactor g_blendFacSrc;
metaforce::ERglBlendFactor g_blendFacDst;
metaforce::ERglLogicOp g_blendOp;
bool g_depthCompare;
bool g_depthUpdate;
metaforce::ERglEnum g_depthFunc;
std::array<zeus::CColor, 3> g_colorRegs;
std::array<zeus::CColor, GX::MAX_KCOLOR> g_kcolors;
bool g_alphaUpdate;
std::optional<float> g_dstAlpha;
zeus::CColor g_clearColor = zeus::skClear;
bool g_alphaDiscard;
GXState g_gxState;
std::array<SChannelState, 2> g_colorChannels;
std::array<LightVariant, MaxLights> g_lights;
std::bitset<MaxLights> g_lightState;
const TextureBind& get_texture(GX::TexMapID id) noexcept { return g_gxState.textures[static_cast<size_t>(id)]; }
std::array<std::optional<STevStage>, maxTevStages> g_tevStages;
std::array<TextureBind, maxTextures> g_textures;
const gx::TextureBind& get_texture(GX::TexMapID id) noexcept { return gx::g_textures[static_cast<size_t>(id)]; }
static inline wgpu::BlendFactor to_blend_factor(metaforce::ERglBlendFactor fac) {
static inline wgpu::BlendFactor to_blend_factor(GX::BlendFactor fac) {
switch (fac) {
case metaforce::ERglBlendFactor::Zero:
case GX::BL_ZERO:
return wgpu::BlendFactor::Zero;
case metaforce::ERglBlendFactor::One:
case GX::BL_ONE:
return wgpu::BlendFactor::One;
case metaforce::ERglBlendFactor::SrcColor:
case GX::BL_SRCCLR:
return wgpu::BlendFactor::Src;
case metaforce::ERglBlendFactor::InvSrcColor:
case GX::BL_INVSRCCLR:
return wgpu::BlendFactor::OneMinusSrc;
case metaforce::ERglBlendFactor::SrcAlpha:
case GX::BL_SRCALPHA:
return wgpu::BlendFactor::SrcAlpha;
case metaforce::ERglBlendFactor::InvSrcAlpha:
case GX::BL_INVSRCALPHA:
return wgpu::BlendFactor::OneMinusSrcAlpha;
case metaforce::ERglBlendFactor::DstAlpha:
case GX::BL_DSTALPHA:
return wgpu::BlendFactor::DstAlpha;
case metaforce::ERglBlendFactor::InvDstAlpha:
case GX::BL_INVDSTALPHA:
return wgpu::BlendFactor::OneMinusDstAlpha;
case metaforce::ERglBlendFactor::DstColor:
case GX::BL_DSTCLR:
return wgpu::BlendFactor::Dst;
case metaforce::ERglBlendFactor::InvDstColor:
case GX::BL_INVDSTCLR:
return wgpu::BlendFactor::OneMinusDst;
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid blend factor {}"), fac);
@@ -202,23 +187,23 @@ static inline wgpu::BlendFactor to_blend_factor(metaforce::ERglBlendFactor fac)
}
}
static inline wgpu::CompareFunction to_compare_function(metaforce::ERglEnum func) {
static inline wgpu::CompareFunction to_compare_function(GX::Compare func) {
switch (func) {
case metaforce::ERglEnum::Never:
case GX::NEVER:
return wgpu::CompareFunction::Never;
case metaforce::ERglEnum::Less:
case GX::LESS:
return wgpu::CompareFunction::Less;
case metaforce::ERglEnum::Equal:
case GX::EQUAL:
return wgpu::CompareFunction::Equal;
case metaforce::ERglEnum::LEqual:
case GX::LEQUAL:
return wgpu::CompareFunction::LessEqual;
case metaforce::ERglEnum::Greater:
case GX::GREATER:
return wgpu::CompareFunction::Greater;
case metaforce::ERglEnum::NEqual:
case GX::NEQUAL:
return wgpu::CompareFunction::NotEqual;
case metaforce::ERglEnum::GEqual:
case GX::GEQUAL:
return wgpu::CompareFunction::GreaterEqual;
case metaforce::ERglEnum::Always:
case GX::ALWAYS:
return wgpu::CompareFunction::Always;
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid depth fn {}"), func);
@@ -226,10 +211,10 @@ static inline wgpu::CompareFunction to_compare_function(metaforce::ERglEnum func
}
}
static inline wgpu::BlendState to_blend_state(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor srcFac,
metaforce::ERglBlendFactor dstFac, std::optional<float> dstAlpha) {
if (mode != metaforce::ERglBlendMode::Blend) {
Log.report(logvisor::Fatal, FMT_STRING("How to {}?"), magic_enum::enum_name(mode));
static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFactor srcFac, GX::BlendFactor dstFac,
std::optional<float> dstAlpha) {
if (mode != GX::BM_BLEND) {
Log.report(logvisor::Fatal, FMT_STRING("How to {}?"), mode);
}
const auto colorBlendComponent = wgpu::BlendComponent{
.operation = wgpu::BlendOperation::Add,
@@ -258,7 +243,7 @@ static inline wgpu::ColorWriteMask to_write_mask(bool alphaUpdate) {
return writeMask;
}
static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, metaforce::ERglCullMode e_cullMode) {
static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, GX::CullMode gx_cullMode) {
wgpu::PrimitiveTopology primitive = wgpu::PrimitiveTopology::TriangleList;
switch (gx_prim) {
case GX::TRIANGLES:
@@ -272,14 +257,17 @@ static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, met
}
wgpu::FrontFace frontFace = wgpu::FrontFace::CCW;
wgpu::CullMode cullMode = wgpu::CullMode::None;
switch (e_cullMode) {
case metaforce::ERglCullMode::Front:
switch (gx_cullMode) {
case GX::CULL_FRONT:
frontFace = wgpu::FrontFace::CW;
cullMode = wgpu::CullMode::Front;
break;
case metaforce::ERglCullMode::Back:
case GX::CULL_BACK:
cullMode = wgpu::CullMode::Back;
break;
case GX::CULL_ALL:
Log.report(logvisor::Fatal, FMT_STRING("Unsupported cull mode {}"), gx_cullMode);
unreachable();
default:
break;
}
@@ -345,29 +333,24 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderIn
ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive,
const BindGroupRanges& ranges) noexcept {
for (size_t idx = 0; const auto& item : g_tevStages) {
// Copy until disabled TEV stage (indicating end)
if (!item) {
break;
}
config.shaderConfig.tevStages[idx++] = item;
for (size_t i = 0; i < g_gxState.numTevStages; ++i) {
config.shaderConfig.tevStages[i] = g_gxState.tevStages[i];
}
config.shaderConfig.channelMatSrcs[0] = g_colorChannels[0].matSrc;
config.shaderConfig.channelMatSrcs[1] = g_colorChannels[1].matSrc;
config.shaderConfig.alphaDiscard = g_alphaDiscard;
config.shaderConfig.colorChannels = g_gxState.colorChannelConfig;
config.shaderConfig.alphaDiscard = g_gxState.alphaDiscard;
config = {
.shaderConfig = config.shaderConfig,
.primitive = primitive,
.depthFunc = g_depthFunc,
.cullMode = g_cullMode,
.blendMode = g_blendMode,
.blendFacSrc = g_blendFacSrc,
.blendFacDst = g_blendFacDst,
.blendOp = g_blendOp,
.dstAlpha = g_dstAlpha,
.depthCompare = g_depthCompare,
.depthUpdate = g_depthUpdate,
.alphaUpdate = g_alphaUpdate,
.depthFunc = g_gxState.depthFunc,
.cullMode = g_gxState.cullMode,
.blendMode = g_gxState.blendMode,
.blendFacSrc = g_gxState.blendFacSrc,
.blendFacDst = g_gxState.blendFacDst,
.blendOp = g_gxState.blendOp,
.dstAlpha = g_gxState.dstAlpha,
.depthCompare = g_gxState.depthCompare,
.depthUpdate = g_gxState.depthUpdate,
.alphaUpdate = g_gxState.alphaUpdate,
};
// TODO separate shader info from build_shader for async
{
@@ -381,51 +364,51 @@ ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primit
Range build_uniform(const ShaderInfo& info) noexcept {
auto [buf, range] = map_uniform(info.uniformSize);
{
buf.append(&g_mv, 64);
buf.append(&g_mvInv, 64);
buf.append(&g_proj, 64);
buf.append(&g_gxState.mv, 64);
buf.append(&g_gxState.mvInv, 64);
buf.append(&g_gxState.proj, 64);
}
for (int i = 0; i < info.usesTevReg.size(); ++i) {
if (!info.usesTevReg.test(i)) {
continue;
}
buf.append(&g_colorRegs[i], 16);
}
if (info.sampledColorChannels.any()) {
zeus::CColor ambient = zeus::skClear;
int addedLights = 0;
for (int i = 0; i < g_lightState.size(); ++i) {
if (!g_lightState.test(i)) {
continue;
}
const auto& variant = g_lights[i];
if (std::holds_alternative<zeus::CColor>(variant)) {
ambient += std::get<zeus::CColor>(variant);
} else if (std::holds_alternative<Light>(variant)) {
static_assert(sizeof(Light) == 80);
buf.append(&std::get<Light>(variant), sizeof(Light));
++addedLights;
}
}
constexpr Light emptyLight{};
for (int i = addedLights; i < MaxLights; ++i) {
buf.append(&emptyLight, sizeof(Light));
}
buf.append(&ambient, 16);
// fmt::print(FMT_STRING("Added lights: {}, ambient: {},{},{},{}\n"), addedLights, ambient.r(), ambient.g(), ambient.b(), ambient.a());
buf.append(&g_gxState.colorRegs[i], 16);
}
for (int i = 0; i < info.sampledColorChannels.size(); ++i) {
if (!info.sampledColorChannels.test(i)) {
continue;
}
buf.append(&g_colorChannels[i].ambColor, 16);
buf.append(&g_colorChannels[i].matColor, 16);
buf.append(&g_gxState.colorChannelState[i].ambColor, 16);
buf.append(&g_gxState.colorChannelState[i].matColor, 16);
if (g_gxState.colorChannelConfig[i].lightingEnabled) {
zeus::CColor ambient = zeus::skClear;
int addedLights = 0;
for (int li = 0; li < g_gxState.lightState.size(); ++li) {
if (!g_gxState.lightState.test(li)) {
continue;
}
const auto& variant = g_gxState.lights[li];
if (std::holds_alternative<zeus::CColor>(variant)) {
ambient += std::get<zeus::CColor>(variant);
} else if (std::holds_alternative<Light>(variant)) {
static_assert(sizeof(Light) == 80);
buf.append(&std::get<Light>(variant), sizeof(Light));
++addedLights;
}
}
constexpr Light emptyLight{};
for (int li = addedLights; li < GX::MaxLights; ++li) {
buf.append(&emptyLight, sizeof(Light));
}
buf.append(&ambient, 16);
}
}
for (int i = 0; i < info.sampledKcolors.size(); ++i) {
if (!info.sampledKcolors.test(i)) {
for (int i = 0; i < info.sampledKColors.size(); ++i) {
if (!info.sampledKColors.test(i)) {
continue;
}
buf.append(&g_kcolors[i], 16);
buf.append(&g_gxState.kcolors[i], 16);
}
for (int i = 0; i < info.sampledTextures.size(); ++i) {
if (!info.sampledTextures.test(i)) {
@@ -480,13 +463,13 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
.size = ranges.packedTcDataRange.second - ranges.packedTcDataRange.first,
},
};
std::array<wgpu::BindGroupEntry, maxTextures> samplerEntries;
std::array<wgpu::BindGroupEntry, maxTextures> textureEntries;
std::array<wgpu::BindGroupEntry, MaxTextures> samplerEntries;
std::array<wgpu::BindGroupEntry, MaxTextures> textureEntries;
for (u32 texIdx = 0, i = 0; texIdx < info.sampledTextures.size(); ++texIdx) {
if (!info.sampledTextures.test(texIdx)) {
continue;
}
const auto& tex = g_textures[texIdx];
const auto& tex = g_gxState.textures[texIdx];
if (!tex) {
Log.report(logvisor::Fatal, FMT_STRING("unbound texture {}"), texIdx);
unreachable();
@@ -592,8 +575,8 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader
out.samplerLayout = sl;
out.textureLayout = tl;
} else {
std::array<wgpu::BindGroupLayoutEntry, maxTextures> samplerEntries;
std::array<wgpu::BindGroupLayoutEntry, maxTextures> textureEntries;
std::array<wgpu::BindGroupLayoutEntry, MaxTextures> samplerEntries;
std::array<wgpu::BindGroupLayoutEntry, MaxTextures> textureEntries;
for (u32 i = 0; i < textureCount; ++i) {
samplerEntries[i] = {
.binding = i,
@@ -637,7 +620,7 @@ void shutdown() noexcept {
// TODO we should probably store this all in g_state.gx instead
sUniformBindGroupLayouts.clear();
sTextureBindGroupLayouts.clear();
g_textures.fill({});
g_gxState.textures.fill({});
g_gxCachedShaders.clear();
}

View File

@@ -5,51 +5,36 @@
#include <variant>
namespace aurora::gfx::gx {
extern zeus::CMatrix4f g_mv;
extern zeus::CMatrix4f g_mvInv;
extern zeus::CMatrix4f g_proj;
extern metaforce::CFogState g_fogState;
extern metaforce::ERglCullMode g_cullMode;
extern metaforce::ERglBlendMode g_blendMode;
extern metaforce::ERglBlendFactor g_blendFacSrc;
extern metaforce::ERglBlendFactor g_blendFacDst;
extern metaforce::ERglLogicOp g_blendOp;
extern bool g_depthCompare;
extern bool g_depthUpdate;
extern metaforce::ERglEnum g_depthFunc;
extern std::array<zeus::CColor, 3> g_colorRegs;
extern std::array<zeus::CColor, GX::MAX_KCOLOR> g_kcolors;
extern bool g_alphaUpdate;
extern std::optional<float> g_dstAlpha;
extern zeus::CColor g_clearColor;
extern bool g_alphaDiscard;
constexpr u32 MaxTextures = GX::MAX_TEXMAP;
constexpr u32 MaxTevStages = GX::MAX_TEVSTAGE;
constexpr u32 MaxColorChannels = 2; // COLOR0A0, COLOR1A1
constexpr u32 MaxTevRegs = 3; // TEVREG0-2
constexpr u32 MaxKColors = GX::MAX_KCOLOR;
struct SChannelState {
zeus::CColor matColor;
zeus::CColor ambColor;
GX::ColorSrc matSrc;
template <typename Arg, Arg Default>
struct TevPass {
Arg a = Default;
Arg b = Default;
Arg c = Default;
Arg d = Default;
};
extern std::array<SChannelState, 2> g_colorChannels;
using LightVariant = std::variant<std::monostate, Light, zeus::CColor>;
extern std::array<LightVariant, MaxLights> g_lights;
extern std::bitset<MaxLights> g_lightState;
struct STevStage {
metaforce::CTevCombiners::ColorPass colorPass;
metaforce::CTevCombiners::AlphaPass alphaPass;
metaforce::CTevCombiners::CTevOp colorOp;
metaforce::CTevCombiners::CTevOp alphaOp;
struct TevOp {
GX::TevOp op = GX::TevOp::TEV_ADD;
GX::TevBias bias = GX::TevBias::TB_ZERO;
GX::TevScale scale = GX::TevScale::CS_SCALE_1;
GX::TevRegID outReg = GX::TevRegID::TEVPREV;
bool clamp = true;
};
struct TevStage {
TevPass<GX::TevColorArg, GX::CC_ZERO> colorPass;
TevPass<GX::TevAlphaArg, GX::CA_ZERO> alphaPass;
TevOp colorOp;
TevOp alphaOp;
GX::TevKColorSel kcSel = GX::TEV_KCSEL_1;
GX::TevKAlphaSel kaSel = GX::TEV_KASEL_1;
GX::TexCoordID texCoordId = GX::TEXCOORD_NULL;
GX::TexMapID texMapId = GX::TEXMAP_NULL;
GX::ChannelID channelId = GX::COLOR_NULL;
constexpr STevStage(const metaforce::CTevCombiners::ColorPass& colPass,
const metaforce::CTevCombiners::AlphaPass& alphaPass,
const metaforce::CTevCombiners::CTevOp& colorOp,
const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept
: colorPass(colPass), alphaPass(alphaPass), colorOp(colorOp), alphaOp(alphaOp) {}
};
struct TextureBind {
aurora::gfx::TextureHandle handle;
@@ -63,32 +48,72 @@ struct TextureBind {
[[nodiscard]] wgpu::SamplerDescriptor get_descriptor() const noexcept;
operator bool() const noexcept { return handle; }
};
// For shader generation
struct ColorChannelConfig {
GX::ColorSrc matSrc = GX::SRC_REG;
GX::ColorSrc ambSrc = GX::SRC_REG;
bool lightingEnabled = false;
};
// For uniform generation
struct ColorChannelState {
zeus::CColor matColor = zeus::skClear;
zeus::CColor ambColor = zeus::skClear;
GX::LightMask lightState;
};
using LightVariant = std::variant<std::monostate, Light, zeus::CColor>;
constexpr u32 maxTevStages = GX::MAX_TEVSTAGE;
extern std::array<std::optional<STevStage>, maxTevStages> g_tevStages;
constexpr u32 maxTextures = 8;
extern std::array<TextureBind, maxTextures> g_textures;
struct GXState {
zeus::CMatrix4f mv;
zeus::CMatrix4f mvInv;
zeus::CMatrix4f proj;
metaforce::CFogState fogState;
GX::CullMode cullMode = GX::CULL_BACK;
GX::BlendMode blendMode = GX::BM_NONE;
GX::BlendFactor blendFacSrc = GX::BL_SRCALPHA;
GX::BlendFactor blendFacDst = GX::BL_INVSRCALPHA;
GX::LogicOp blendOp = GX::LO_CLEAR;
GX::Compare depthFunc = GX::LEQUAL;
zeus::CColor clearColor = zeus::skBlack;
std::optional<float> dstAlpha;
std::optional<float> alphaDiscard;
std::array<zeus::CColor, MaxTevRegs> colorRegs;
std::array<zeus::CColor, GX::MAX_KCOLOR> kcolors;
std::array<ColorChannelConfig, MaxColorChannels> colorChannelConfig;
std::array<ColorChannelState, MaxColorChannels> colorChannelState;
std::array<LightVariant, GX::MaxLights> lights;
std::array<TevStage, MaxTevStages> tevStages;
std::array<TextureBind, MaxTextures> textures;
GX::LightMask lightState;
bool depthCompare = true;
bool depthUpdate = true;
bool alphaUpdate = true;
u8 numChans = 0;
u8 numIndStages = 0;
u8 numTevStages = 0;
u8 numTexGens = 0;
};
extern GXState g_gxState;
static inline Mat4x4<float> get_combined_matrix() noexcept { return g_proj * g_mv; }
static inline Mat4x4<float> get_combined_matrix() noexcept { return g_gxState.proj * g_gxState.mv; }
void shutdown() noexcept;
const TextureBind& get_texture(GX::TexMapID id) noexcept;
struct ShaderConfig {
std::array<std::optional<STevStage>, maxTevStages> tevStages;
std::array<GX::ColorSrc, 2> channelMatSrcs;
bool alphaDiscard = false;
std::array<std::optional<TevStage>, MaxTevStages> tevStages;
std::array<ColorChannelConfig, MaxColorChannels> colorChannels;
std::optional<float> alphaDiscard;
bool denormalizedVertexAttributes = false;
bool denormalizedHasNrm = false; // TODO this is a hack
};
struct PipelineConfig {
ShaderConfig shaderConfig;
GX::Primitive primitive;
metaforce::ERglEnum depthFunc;
metaforce::ERglCullMode cullMode;
metaforce::ERglBlendMode blendMode;
metaforce::ERglBlendFactor blendFacSrc, blendFacDst;
metaforce::ERglLogicOp blendOp;
GX::Compare depthFunc;
GX::CullMode cullMode;
GX::BlendMode blendMode;
GX::BlendFactor blendFacSrc, blendFacDst;
GX::LogicOp blendOp;
std::optional<float> dstAlpha;
bool depthCompare, depthUpdate, alphaUpdate;
};
@@ -105,10 +130,10 @@ struct GXBindGroups {
// Output info from shader generation
struct ShaderInfo {
GXBindGroups bindGroups;
std::bitset<maxTextures> sampledTextures;
std::bitset<4> sampledKcolors;
std::bitset<2> sampledColorChannels;
std::bitset<3> usesTevReg;
std::bitset<MaxTextures> sampledTextures;
std::bitset<MaxKColors> sampledKColors;
std::bitset<MaxColorChannels> sampledColorChannels;
std::bitset<MaxTevRegs> usesTevReg;
u32 uniformSize = 0;
bool usesVtxColor : 1 = false;
bool usesNormal : 1 = false;
@@ -143,25 +168,41 @@ struct DlVert {
} // namespace aurora::gfx::gx
namespace aurora {
template <>
inline void xxh3_update(XXH3_state_t& state, const metaforce::CTevCombiners::CTevOp& input) {
XXH3_64bits_update(&state, &input.x0_clamp, sizeof(bool));
XXH3_64bits_update(&state, &input.x4_op, sizeof(metaforce::CTevCombiners::CTevOp::x4_op));
XXH3_64bits_update(&state, &input.x8_bias, sizeof(metaforce::CTevCombiners::CTevOp::x8_bias));
XXH3_64bits_update(&state, &input.xc_scale, sizeof(metaforce::CTevCombiners::CTevOp::xc_scale));
XXH3_64bits_update(&state, &input.x10_regId, sizeof(metaforce::CTevCombiners::CTevOp::x10_regId));
template <typename Arg, Arg Default>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevPass<Arg, Default>& input) {
XXH3_64bits_update(&state, &input.a, sizeof(Arg));
XXH3_64bits_update(&state, &input.b, sizeof(Arg));
XXH3_64bits_update(&state, &input.c, sizeof(Arg));
XXH3_64bits_update(&state, &input.d, sizeof(Arg));
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::STevStage& input) {
XXH3_64bits_update(&state, &input.colorPass, sizeof(gfx::gx::STevStage::colorPass));
XXH3_64bits_update(&state, &input.alphaPass, sizeof(gfx::gx::STevStage::alphaPass));
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevOp& input) {
XXH3_64bits_update(&state, &input.op, sizeof(gfx::gx::TevOp::op));
XXH3_64bits_update(&state, &input.bias, sizeof(gfx::gx::TevOp::bias));
XXH3_64bits_update(&state, &input.scale, sizeof(gfx::gx::TevOp::scale));
XXH3_64bits_update(&state, &input.outReg, sizeof(gfx::gx::TevOp::outReg));
XXH3_64bits_update(&state, &input.clamp, sizeof(bool));
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevStage& input) {
xxh3_update(state, input.colorPass);
xxh3_update(state, input.alphaPass);
xxh3_update(state, input.colorOp);
xxh3_update(state, input.alphaOp);
XXH3_64bits_update(&state, &input.kcSel, sizeof(gfx::gx::STevStage::kcSel));
XXH3_64bits_update(&state, &input.kaSel, sizeof(gfx::gx::STevStage::kaSel));
XXH3_64bits_update(&state, &input.texCoordId, sizeof(gfx::gx::STevStage::texCoordId));
XXH3_64bits_update(&state, &input.texMapId, sizeof(gfx::gx::STevStage::texMapId));
XXH3_64bits_update(&state, &input.channelId, sizeof(gfx::gx::STevStage::channelId));
XXH3_64bits_update(&state, &input.kcSel, sizeof(gfx::gx::TevStage::kcSel));
XXH3_64bits_update(&state, &input.kaSel, sizeof(gfx::gx::TevStage::kaSel));
XXH3_64bits_update(&state, &input.texCoordId, sizeof(gfx::gx::TevStage::texCoordId));
XXH3_64bits_update(&state, &input.texMapId, sizeof(gfx::gx::TevStage::texMapId));
XXH3_64bits_update(&state, &input.channelId, sizeof(gfx::gx::TevStage::channelId));
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ColorChannelConfig& input) {
XXH3_64bits_update(&state, &input.lightingEnabled, sizeof(gfx::gx::ColorChannelConfig::lightingEnabled));
XXH3_64bits_update(&state, &input.matSrc, sizeof(gfx::gx::ColorChannelConfig::matSrc));
if (input.lightingEnabled) {
// Unused when lighting is disabled
XXH3_64bits_update(&state, &input.ambSrc, sizeof(gfx::gx::ColorChannelConfig::ambSrc));
}
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) {
@@ -171,10 +212,12 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input)
}
xxh3_update(state, *item);
}
for (const auto& item : input.channelMatSrcs) {
XXH3_64bits_update(&state, &item, sizeof(GX::ColorSrc));
for (const auto& item : input.colorChannels) {
xxh3_update(state, item);
}
if (input.alphaDiscard) {
XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float));
}
XXH3_64bits_update(&state, &input.alphaDiscard, sizeof(bool));
XXH3_64bits_update(&state, &input.denormalizedVertexAttributes, sizeof(bool));
XXH3_64bits_update(&state, &input.denormalizedHasNrm, sizeof(bool));
}

View File

@@ -12,7 +12,7 @@ static logvisor::Module Log("aurora::gfx::gx");
std::unordered_map<ShaderRef, std::pair<wgpu::ShaderModule, gx::ShaderInfo>> g_gxCachedShaders;
static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STevStage& stage, ShaderInfo& info) {
static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) {
switch (arg) {
case GX::CC_CPREV:
return "prev.rgb";
@@ -105,64 +105,64 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STe
case GX::TEV_KCSEL_1_8:
return "(1.0/8.0)";
case GX::TEV_KCSEL_K0:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.rgb";
case GX::TEV_KCSEL_K1:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.rgb";
case GX::TEV_KCSEL_K2:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.rgb";
case GX::TEV_KCSEL_K3:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.rgb";
case GX::TEV_KCSEL_K0_R:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.r";
case GX::TEV_KCSEL_K1_R:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.r";
case GX::TEV_KCSEL_K2_R:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.r";
case GX::TEV_KCSEL_K3_R:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.r";
case GX::TEV_KCSEL_K0_G:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.g";
case GX::TEV_KCSEL_K1_G:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.g";
case GX::TEV_KCSEL_K2_G:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.g";
case GX::TEV_KCSEL_K3_G:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.g";
case GX::TEV_KCSEL_K0_B:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.b";
case GX::TEV_KCSEL_K1_B:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.b";
case GX::TEV_KCSEL_K2_B:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.b";
case GX::TEV_KCSEL_K3_B:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.b";
case GX::TEV_KCSEL_K0_A:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.a";
case GX::TEV_KCSEL_K1_A:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.a";
case GX::TEV_KCSEL_K2_A:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.a";
case GX::TEV_KCSEL_K3_A:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.a";
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid kcSel {}"), stage.kcSel);
@@ -177,7 +177,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STe
}
}
static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const STevStage& stage, ShaderInfo& info) {
static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) {
switch (arg) {
case GX::CA_APREV:
return "prev.a";
@@ -232,52 +232,52 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const STe
case GX::TEV_KASEL_1_8:
return "(1.0/8.0)";
case GX::TEV_KASEL_K0_R:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.r";
case GX::TEV_KASEL_K1_R:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.r";
case GX::TEV_KASEL_K2_R:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.r";
case GX::TEV_KASEL_K3_R:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.r";
case GX::TEV_KASEL_K0_G:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.g";
case GX::TEV_KASEL_K1_G:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.g";
case GX::TEV_KASEL_K2_G:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.g";
case GX::TEV_KASEL_K3_G:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.g";
case GX::TEV_KASEL_K0_B:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.b";
case GX::TEV_KASEL_K1_B:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.b";
case GX::TEV_KASEL_K2_B:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.b";
case GX::TEV_KASEL_K3_B:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.b";
case GX::TEV_KASEL_K0_A:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.a";
case GX::TEV_KASEL_K1_A:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.a";
case GX::TEV_KASEL_K2_A:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.a";
case GX::TEV_KASEL_K3_A:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.a";
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid kaSel {}"), stage.kaSel);
@@ -352,34 +352,34 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
break;
}
Log.report(logvisor::Info, FMT_STRING(" tevStages[{}]:"), i);
Log.report(logvisor::Info, FMT_STRING(" color_a: {}"), stage->colorPass.x0_a);
Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage->colorPass.x4_b);
Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage->colorPass.x8_c);
Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage->colorPass.xc_d);
Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage->alphaPass.x0_a);
Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage->alphaPass.x4_b);
Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage->alphaPass.x8_c);
Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage->alphaPass.xc_d);
Log.report(logvisor::Info, FMT_STRING(" color_op_clamp: {}"), stage->colorOp.x0_clamp);
Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage->colorOp.x4_op);
Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage->colorOp.x8_bias);
Log.report(logvisor::Info, FMT_STRING(" color_op_scale: {}"), stage->colorOp.xc_scale);
Log.report(logvisor::Info, FMT_STRING(" color_op_reg_id: {}"), stage->colorOp.x10_regId);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_clamp: {}"), stage->alphaOp.x0_clamp);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_op: {}"), stage->alphaOp.x4_op);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_bias: {}"), stage->alphaOp.x8_bias);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_scale: {}"), stage->alphaOp.xc_scale);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_reg_id: {}"), stage->alphaOp.x10_regId);
Log.report(logvisor::Info, FMT_STRING(" color_a: {}"), stage->colorPass.a);
Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage->colorPass.b);
Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage->colorPass.c);
Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage->colorPass.d);
Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage->alphaPass.a);
Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage->alphaPass.b);
Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage->alphaPass.c);
Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage->alphaPass.d);
Log.report(logvisor::Info, FMT_STRING(" color_op_clamp: {}"), stage->colorOp.clamp);
Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage->colorOp.op);
Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage->colorOp.bias);
Log.report(logvisor::Info, FMT_STRING(" color_op_scale: {}"), stage->colorOp.scale);
Log.report(logvisor::Info, FMT_STRING(" color_op_reg_id: {}"), stage->colorOp.outReg);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_clamp: {}"), stage->alphaOp.clamp);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_op: {}"), stage->alphaOp.op);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_bias: {}"), stage->alphaOp.bias);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_scale: {}"), stage->alphaOp.scale);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_reg_id: {}"), stage->alphaOp.outReg);
Log.report(logvisor::Info, FMT_STRING(" kc_sel: {}"), stage->kcSel);
Log.report(logvisor::Info, FMT_STRING(" ka_sel: {}"), stage->kaSel);
Log.report(logvisor::Info, FMT_STRING(" texCoordId: {}"), stage->texCoordId);
Log.report(logvisor::Info, FMT_STRING(" texMapId: {}"), stage->texMapId);
Log.report(logvisor::Info, FMT_STRING(" channelId: {}"), stage->channelId);
}
for (int i = 0; i < config.channelMatSrcs.size(); ++i) {
Log.report(logvisor::Info, FMT_STRING(" channelMatSrcs[{}]: {}"), i, config.channelMatSrcs[i]);
}
Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard);
// for (int i = 0; i < config.channelMatSrcs.size(); ++i) {
// Log.report(logvisor::Info, FMT_STRING(" channelMatSrcs[{}]: {}"), i, config.channelMatSrcs[i]);
// }
// Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard);
Log.report(logvisor::Info, FMT_STRING(" denormalizedVertexAttributes: {}"), config.denormalizedVertexAttributes);
}
@@ -396,14 +396,16 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
if (config.denormalizedVertexAttributes) {
vtxInAttrs += "\n @location(0) in_pos: vec3<f32>";
vtxOutAttrs += "\n @builtin(position) pos: vec4<f32>;";
vtxXfrAttrsPre += "\n var obj_pos = vec4<f32>(in_pos, 1.0);"
vtxXfrAttrsPre +=
"\n var obj_pos = vec4<f32>(in_pos, 1.0);"
"\n var mv_pos = ubuf.mv * obj_pos;"
"\n out.pos = ubuf.proj * mv_pos;";
if (config.denormalizedHasNrm) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3<f32>;"), locIdx);
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_nrm: vec3<f32>"), ++locIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.nrm = in_nrm;"));
vtxXfrAttrsPre += "\n var obj_norm = vec4<f32>(in_nrm, 0.0);"
vtxXfrAttrsPre +=
"\n var obj_norm = vec4<f32>(in_nrm, 0.0);"
"\n var mv_norm = ubuf.mv_inv * obj_norm;";
info.usesNormal = true;
}
@@ -429,7 +431,8 @@ var<storage, read> v_packed_uvs: Vec2Block;
"\n , @location(1) in_uv_0_4_idx: vec4<i32>"
"\n , @location(2) in_uv_5_7_idx: vec4<i32>";
vtxOutAttrs += "\n @builtin(position) pos: vec4<f32>;";
vtxXfrAttrsPre += "\n var obj_pos = vec4<f32>(v_verts.data[in_pos_nrm_idx[0]].xyz, 1.0);"
vtxXfrAttrsPre +=
"\n var obj_pos = vec4<f32>(v_verts.data[in_pos_nrm_idx[0]].xyz, 1.0);"
"\n var obj_norm = vec4<f32>(v_verts.data[in_pos_nrm_idx[1]].xyz, 0.0);"
"\n var mv_pos = ubuf.mv * obj_pos;"
"\n var mv_norm = ubuf.mv_inv * obj_norm;"
@@ -444,7 +447,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
}
{
std::string outReg;
switch (stage->colorOp.x10_regId) {
switch (stage->colorOp.outReg) {
case GX::TevRegID::TEVPREV:
outReg = "prev";
break;
@@ -461,23 +464,21 @@ var<storage, read> v_packed_uvs: Vec2Block;
info.usesTevReg.set(2);
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("TODO: colorOp outReg {}"), stage->colorOp.x10_regId);
Log.report(logvisor::Fatal, FMT_STRING("TODO: colorOp outReg {}"), stage->colorOp.outReg);
}
std::string op =
fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
color_arg_reg(stage->colorPass.x0_a, idx, *stage, info),
color_arg_reg(stage->colorPass.x4_b, idx, *stage, info),
color_arg_reg(stage->colorPass.x8_c, idx, *stage, info),
color_arg_reg(stage->colorPass.xc_d, idx, *stage, info), tev_op(stage->colorOp.x4_op),
tev_bias(stage->colorOp.x8_bias), tev_scale(stage->colorOp.xc_scale));
if (stage->colorOp.x0_clamp) {
std::string op = fmt::format(
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
color_arg_reg(stage->colorPass.a, idx, *stage, info), color_arg_reg(stage->colorPass.b, idx, *stage, info),
color_arg_reg(stage->colorPass.c, idx, *stage, info), color_arg_reg(stage->colorPass.d, idx, *stage, info),
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>({}), vec3<f32>(0.0), vec3<f32>(1.0))"), op);
}
fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4<f32>({1}, {0}.a);"), outReg, op);
}
{
std::string outReg;
switch (stage->alphaOp.x10_regId) {
switch (stage->alphaOp.outReg) {
case GX::TevRegID::TEVPREV:
outReg = "prev.a";
break;
@@ -494,16 +495,14 @@ var<storage, read> v_packed_uvs: Vec2Block;
info.usesTevReg.set(2);
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("TODO: alphaOp outReg {}"), stage->alphaOp.x10_regId);
Log.report(logvisor::Fatal, FMT_STRING("TODO: alphaOp outReg {}"), stage->alphaOp.outReg);
}
std::string op =
fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
alpha_arg_reg(stage->alphaPass.x0_a, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.x4_b, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.x8_c, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.xc_d, idx, *stage, info), tev_op(stage->alphaOp.x4_op),
tev_bias(stage->alphaOp.x8_bias), tev_scale(stage->alphaOp.xc_scale));
if (stage->alphaOp.x0_clamp) {
std::string op = fmt::format(
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
alpha_arg_reg(stage->alphaPass.a, idx, *stage, info), alpha_arg_reg(stage->alphaPass.b, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.c, idx, *stage, info), alpha_arg_reg(stage->alphaPass.d, idx, *stage, info),
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);
}
fragmentFn += fmt::format(FMT_STRING("\n {0} = {1};"), outReg, op);
@@ -518,19 +517,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i);
info.uniformSize += 16;
}
if (info.sampledColorChannels.any()) {
uniformPre += "\n"
"struct Light {\n"
" pos: vec3<f32>;\n"
" dir: vec3<f32>;\n"
" color: vec4<f32>;\n"
" lin_att: vec3<f32>;\n"
" ang_att: vec3<f32>;\n"
"};";
uniBufAttrs += fmt::format(FMT_STRING("\n lights: array<Light, {}>;"), MaxLights);
uniBufAttrs += "\n lighting_ambient: vec4<f32>;";
info.uniformSize += (80 * MaxLights) + 16;
}
bool addedLightStruct = false;
for (int i = 0; i < info.sampledColorChannels.size(); ++i) {
if (!info.sampledColorChannels.test(i)) {
continue;
@@ -540,26 +527,30 @@ var<storage, read> v_packed_uvs: Vec2Block;
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>;"), i);
info.uniformSize += 32;
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx++, i);
if (config.channelMatSrcs[i] == GX::SRC_VTX) {
if (config.denormalizedVertexAttributes) {
if (!info.usesVtxColor) {
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4<f32>"), locIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = in_clr;"), i);
}
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else {
Log.report(logvisor::Fatal, FMT_STRING("SRC_VTX unsupported with normalized vertex attributes"));
if (config.colorChannels[i].lightingEnabled) {
if (!addedLightStruct) {
uniformPre +=
"\n"
"struct Light {\n"
" pos: vec3<f32>;\n"
" dir: vec3<f32>;\n"
" color: vec4<f32>;\n"
" lin_att: vec3<f32>;\n"
" ang_att: vec3<f32>;\n"
"};";
addedLightStruct = true;
}
info.usesVtxColor = true;
} else {
// TODO only perform lighting on CC0 when enabled
uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array<Light, {}>;"), i, GX::MaxLights);
uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4<f32>;"), i);
info.uniformSize += (80 * GX::MaxLights) + 16;
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx++, i);
vtxXfrAttrs += fmt::format(FMT_STRING(R"""(
{{
var lighting = ubuf.lighting_ambient + ubuf.cc{0}_amb;
var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb;
for (var i = 0; i < {1}; i = i + 1) {{
var light = ubuf.lights[i];
var light = ubuf.lights{0}[i];
var delta = mv_pos.xyz - light.pos;
var dist = length(delta);
var delta_norm = delta / dist;
@@ -575,12 +566,27 @@ var<storage, read> v_packed_uvs: Vec2Block;
lighting = lighting + vec4<f32>(this_color, 0.0);
}}
out.cc{0} = clamp(lighting, vec4<f32>(0.0), vec4<f32>(1.0));
}})"""), i, MaxLights);
}})"""),
i, GX::MaxLights);
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else if (config.colorChannels[i].matSrc == GX::SRC_VTX) {
if (config.denormalizedVertexAttributes) {
if (!info.usesVtxColor) {
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4<f32>"), locIdx);
}
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx++, i);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = in_clr;"), i);
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else {
Log.report(logvisor::Fatal, FMT_STRING("SRC_VTX unsupported with normalized vertex attributes"));
}
info.usesVtxColor = true;
} else {
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = ubuf.cc{0}_mat;"), i);
}
}
for (int i = 0; i < info.sampledKcolors.size(); ++i) {
if (!info.sampledKcolors.test(i)) {
for (int i = 0; i < info.sampledKColors.size(); ++i) {
if (!info.sampledKColors.test(i)) {
continue;
}
uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4<f32>;"), i);
@@ -622,6 +628,9 @@ var<storage, read> v_packed_uvs: Vec2Block;
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, in.tex{0}_uv, ubuf.tex{0}_lod);"), i);
locIdx++;
}
if (config.alphaDiscard) {
fragmentFn += fmt::format(FMT_STRING("\n if (prev.a < {}f) {{ discard; }}"), *config.alphaDiscard);
}
const auto shaderSource =
fmt::format(FMT_STRING(R"""({uniformPre}

View File

@@ -54,10 +54,10 @@ static const std::vector<zeus::CVector3f>* nrmData;
static const std::vector<Vec2<float>>* tex0TcData;
static const std::vector<Vec2<float>>* tcData;
void set_vertex_buffer(const std::vector<zeus::CVector3f>* data) noexcept { vtxData = data; }
void set_normal_buffer(const std::vector<zeus::CVector3f>* norm) noexcept { nrmData = norm; }
void set_tex0_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept { tex0TcData = tcs; }
void set_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept { tcData = tcs; }
// void set_vertex_buffer(const std::vector<zeus::CVector3f>* data) noexcept { vtxData = data; }
// void set_normal_buffer(const std::vector<zeus::CVector3f>* norm) noexcept { nrmData = norm; }
// void set_tex0_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept { tex0TcData = tcs; }
// void set_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept { tcData = tcs; }
enum class VertexFormat : u8 {
F32F32,
@@ -233,3 +233,27 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco
pass.DrawIndexed(data.indexCount);
}
} // namespace aurora::gfx::model
void GXSetArray(GX::Attr attr, const void* data, u8 stride) noexcept {
switch (attr) {
case GX::VA_POS:
aurora::gfx::model::vtxData = static_cast<const std::vector<zeus::CVector3f>*>(data);
break;
case GX::VA_NRM:
aurora::gfx::model::nrmData = static_cast<const std::vector<zeus::CVector3f>*>(data);
break;
case GX::VA_TEX0:
aurora::gfx::model::tex0TcData = static_cast<const std::vector<aurora::Vec2<float>>*>(data);
break;
case GX::VA_TEX1:
aurora::gfx::model::tcData = static_cast<const std::vector<aurora::Vec2<float>>*>(data);
break;
default:
aurora::gfx::model::Log.report(logvisor::Fatal, FMT_STRING("GXSetArray: invalid attr {}"), attr);
unreachable();
}
}
void GXCallDisplayList(const void* data, u32 nbytes) noexcept {
aurora::gfx::model::queue_surface(static_cast<const u8*>(data), nbytes);
}