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

More CCubeMaterial, more CGraphics, more aurora::gx

This commit is contained in:
2022-03-06 02:46:42 -05:00
parent 7a61b6cf30
commit cd86dbd6ee
29 changed files with 484 additions and 299 deletions

View File

@@ -1,6 +1,7 @@
#include "shader.hpp"
#include "../../gpu.hpp"
#include "../gx.hpp"
#include <logvisor/logvisor.hpp>
#include <magic_enum.hpp>

View File

@@ -65,24 +65,6 @@ struct Command {
} data;
};
zeus::CMatrix4f g_mv;
zeus::CMatrix4f g_mvInv;
zeus::CMatrix4f g_proj;
metaforce::CFogState g_fogState;
// GX state
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, 4> g_colorRegs;
bool g_alphaUpdate;
std::optional<float> g_dstAlpha;
zeus::CColor g_clearColor;
using NewPipelineCallback = std::function<wgpu::RenderPipeline()>;
static std::mutex g_pipelineMutex;
static std::thread g_pipelineThread;
@@ -135,48 +117,6 @@ static void push_draw_command(ShaderDrawCommand data) { g_commands.push_back({Co
bool get_dxt_compression_supported() noexcept { return g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC); }
// GX state
void set_cull_mode(metaforce::ERglCullMode mode) noexcept { g_cullMode = mode; }
void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst,
metaforce::ERglLogicOp op) noexcept {
g_blendMode = mode;
g_blendFacSrc = src;
g_blendFacDst = dst;
g_blendOp = op;
}
void set_depth_mode(bool compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept {
g_depthCompare = compare_enable;
g_depthFunc = func;
g_depthUpdate = update_enable;
}
void set_gx_reg1_color(const zeus::CColor& color) noexcept { g_colorRegs[1] = color; }
void set_alpha_update(bool enabled) noexcept { g_alphaUpdate = enabled; }
void set_dst_alpha(bool enabled, float value) noexcept {
if (enabled) {
g_dstAlpha = value;
} else {
g_dstAlpha.reset();
}
}
void set_clear_color(const zeus::CColor& color) noexcept { g_clearColor = color; }
// Model state
void set_alpha_discard(bool v) {}
void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept {
g_mv = mv;
g_mvInv = mv_inv;
}
constexpr zeus::CMatrix4f DepthCorrect{
// clang-format off
1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 0.5f, 0.5f,
0.f, 0.f, 0.f, 1.f,
// clang-format on
};
void update_projection(const zeus::CMatrix4f& proj) noexcept { g_proj = DepthCorrect * proj; }
void update_fog_state(const metaforce::CFogState& state) noexcept { g_fogState = state; }
void set_viewport(const zeus::CRectangle& rect, float znear, float zfar) noexcept {
g_commands.push_back({CommandType::SetViewport, {.setViewport = {rect, znear, zfar}}});
}
@@ -243,9 +183,8 @@ PipelineRef pipeline_ref(colored_quad::PipelineConfig config) {
}
void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v,
const zeus::CVector3f& v1, const zeus::CVector3f& v2, const zeus::CVector3f& v3,
const zeus::CVector3f& v4) noexcept {
auto data = movie_player::make_draw_data(g_state.moviePlayer, tex_y, tex_u, tex_v, v1, v2, v3, v4);
float h_pad, float v_pad) noexcept {
auto data = movie_player::make_draw_data(g_state.moviePlayer, tex_y, tex_u, tex_v, h_pad, v_pad);
push_draw_command({.type = ShaderType::MoviePlayer, .moviePlayer = data});
}
template <>

View File

@@ -142,24 +142,6 @@ constexpr Mat4x4<float> Mat4x4_Identity{
} // namespace aurora
namespace aurora::gfx {
extern zeus::CMatrix4f g_mv;
extern zeus::CMatrix4f g_mvInv;
extern zeus::CMatrix4f g_proj;
extern metaforce::CFogState g_fogState;
// GX state
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, 4> g_colorRegs;
extern bool g_alphaUpdate;
extern std::optional<float> g_dstAlpha;
extern zeus::CColor g_clearColor;
extern wgpu::Buffer g_vertexBuffer;
extern wgpu::Buffer g_uniformBuffer;
extern wgpu::Buffer g_indexBuffer;
@@ -232,6 +214,4 @@ const wgpu::BindGroup& find_bind_group(BindGroupRef id);
const wgpu::Sampler& sampler_ref(const wgpu::SamplerDescriptor& descriptor);
uint32_t align_uniform(uint32_t value);
static inline Mat4x4<float> get_combined_matrix() { return g_proj * g_mv; }
} // namespace aurora::gfx

150
aurora/lib/gfx/gx.cpp Normal file
View File

@@ -0,0 +1,150 @@
#include "gx.hpp"
#include "common.hpp"
#include "../gpu.hpp"
#include <magic_enum.hpp>
namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::gx");
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;
std::array<SChannelState, 2> g_colorChannels;
std::array<LightVariant, MaxLights> g_lights;
std::bitset<MaxLights> g_lightState;
std::array<std::optional<STevStage>, maxTevStages> g_tevStages;
// GX state
void set_cull_mode(metaforce::ERglCullMode mode) noexcept { g_cullMode = mode; }
void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst,
metaforce::ERglLogicOp op) noexcept {
g_blendMode = mode;
g_blendFacSrc = src;
g_blendFacDst = dst;
g_blendOp = op;
}
void set_depth_mode(bool compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept {
g_depthCompare = compare_enable;
g_depthFunc = func;
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();
}
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();
}
g_kcolors[id] = color;
}
void set_alpha_update(bool enabled) noexcept { g_alphaUpdate = enabled; }
void set_dst_alpha(bool enabled, float value) noexcept {
if (enabled) {
g_dstAlpha = value;
} else {
g_dstAlpha.reset();
}
}
void set_clear_color(const zeus::CColor& color) noexcept { g_clearColor = color; }
void set_alpha_discard(bool v) {
// TODO
}
void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept {
g_mv = mv;
g_mvInv = mv_inv;
}
constexpr zeus::CMatrix4f DepthCorrect{
// clang-format off
1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 0.5f, 0.5f,
0.f, 0.f, 0.f, 1.f,
// clang-format on
};
void update_projection(const zeus::CMatrix4f& proj) noexcept { g_proj = DepthCorrect * proj; }
void update_fog_state(const metaforce::CFogState& state) noexcept { g_fogState = state; }
void disable_tev_stage(metaforce::ERglTevStage stage) noexcept { 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 {
g_tevStages[static_cast<size_t>(stage)] = {colPass, alphaPass, colorOp, alphaOp};
}
void set_tev_order(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept {
auto& stage = g_tevStages[id];
if (!stage) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_order: disabled stage {}"), id);
unreachable();
}
stage->texCoordId = tcid;
stage->texMapId = tmid;
stage->channelId = cid;
}
void set_tev_k_color_sel(GX::TevStageID id, GX::TevKColorSel sel) noexcept {
auto& stage = 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 = 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();
}
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();
}
g_colorChannels[id - GX::COLOR0A0].matColor = color;
}
void load_light(GX::LightID id, const Light& light) noexcept {
g_lights[id] = light;
}
void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept {
g_lights[id] = ambient;
}
void set_light_state(std::bitset<MaxLights> bits) noexcept {
g_lightState = bits;
}
} // namespace aurora::gfx

60
aurora/lib/gfx/gx.hpp Normal file
View File

@@ -0,0 +1,60 @@
#pragma once
#include "common.hpp"
#include <variant>
namespace aurora::gfx {
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;
struct SChannelState {
zeus::CColor matColor;
zeus::CColor ambColor;
};
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;
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;
STevStage(const metaforce::CTevCombiners::ColorPass& colPass, const metaforce::CTevCombiners::AlphaPass& alphaPass,
const metaforce::CTevCombiners::CTevOp& colorOp, const metaforce::CTevCombiners::CTevOp& alphaOp)
: colorPass(colPass), alphaPass(alphaPass), colorOp(colorOp), alphaOp(alphaOp) {}
};
constexpr u32 maxTevStages = GX::MAX_TEVSTAGE;
extern std::array<std::optional<STevStage>, maxTevStages> g_tevStages;
static inline XXH64_hash_t hash_tev_stages(XXH64_hash_t seed = 0) {
const auto end = std::find_if(g_tevStages.cbegin(), g_tevStages.cend(), [](const auto& a) { return !a; });
return xxh3_hash(g_tevStages.data(), (end - g_tevStages.begin()) * sizeof(STevStage), seed);
}
static inline Mat4x4<float> get_combined_matrix() { return g_proj * g_mv; }
} // namespace aurora::gfx

View File

@@ -12,13 +12,7 @@ using gpu::utils::make_vertex_state;
State construct_state() {
wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{};
wgslDescriptor.source = R"""(
struct Uniform {
xf: mat4x4<f32>;
color: vec4<f32>;
};
@group(0) @binding(0)
var<uniform> ubuf: Uniform;
@group(0) @binding(1)
var tex_sampler: sampler;
@group(1) @binding(0)
var tex_y: texture_2d<f32>;
@@ -35,7 +29,7 @@ struct VertexOutput {
@stage(vertex)
fn vs_main(@location(0) in_pos: vec3<f32>, @location(1) in_uv: vec2<f32>) -> VertexOutput {
var out: VertexOutput;
out.pos = ubuf.xf * vec4<f32>(in_pos, 1.0);
out.pos = vec4<f32>(in_pos, 1.0);
out.uv = in_uv;
return out;
}
@@ -47,7 +41,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
textureSample(tex_u, tex_sampler, in.uv).x - 0.5,
textureSample(tex_v, tex_sampler, in.uv).x - 0.5
);
return ubuf.color * vec4<f32>(
return vec4<f32>(
yuv.x + 1.5958 * yuv.z,
yuv.x - 0.39173 * yuv.y - 0.8129 * yuv.z,
yuv.x + 2.017 * yuv.y,
@@ -61,24 +55,9 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
};
auto shader = g_device.CreateShaderModule(&shaderDescriptor);
wgpu::SupportedLimits limits;
g_device.GetLimits(&limits);
const auto uniform_alignment = limits.limits.minUniformBufferOffsetAlignment;
const auto uniform_size = ALIGN(sizeof(Uniform), uniform_alignment);
const std::array uniformLayoutEntries{
wgpu::BindGroupLayoutEntry{
.binding = 0,
.visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment,
.buffer =
wgpu::BufferBindingLayout{
.type = wgpu::BufferBindingType::Uniform,
.hasDynamicOffset = true,
.minBindingSize = uniform_size,
},
},
wgpu::BindGroupLayoutEntry{
.binding = 1,
.visibility = wgpu::ShaderStage::Fragment,
.sampler =
wgpu::SamplerBindingLayout{
@@ -107,11 +86,6 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
const std::array uniformBindGroupEntries{
wgpu::BindGroupEntry{
.binding = 0,
.buffer = g_uniformBuffer,
.size = uniform_size,
},
wgpu::BindGroupEntry{
.binding = 1,
.sampler = sampler,
},
};
@@ -219,24 +193,17 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli
}
DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const TextureHandle& tex_u,
const TextureHandle& tex_v, const zeus::CVector3f& v1, const zeus::CVector3f& v2,
const zeus::CVector3f& v3, const zeus::CVector3f& v4) {
const TextureHandle& tex_v, float h_pad, float v_pad) {
auto pipeline = pipeline_ref(PipelineConfig{});
const std::array verts{
Vert{{v1.x(), v1.z(), v1.y()}, {0.0, 0.0}},
Vert{{v2.x(), v2.z(), v2.y()}, {0.0, 1.0}},
Vert{{v3.x(), v3.z(), v3.y()}, {1.0, 0.0}},
Vert{{v4.x(), v4.z(), v4.y()}, {1.0, 1.0}},
Vert{{-h_pad, v_pad, 0.f}, {0.0, 0.0}},
Vert{{-h_pad, -v_pad, 0.f}, {0.0, 1.0}},
Vert{{h_pad, v_pad, 0.f}, {1.0, 0.0}},
Vert{{h_pad, -v_pad, 0.f}, {1.0, 1.0}},
};
const auto vertRange = push_verts(ArrayRef{verts});
const auto uniform = Uniform{
.xf = Mat4x4_Identity,
.color = zeus::skWhite,
};
const auto uniformRange = push_uniform(uniform);
const std::array entries{
wgpu::BindGroupEntry{
.binding = 0,
@@ -261,7 +228,6 @@ DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const Te
return {
.pipeline = pipeline,
.vertRange = vertRange,
.uniformRange = uniformRange,
.textureBindGroup = textureBindGroup,
};
}
@@ -271,8 +237,7 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco
return;
}
const std::array offsets{data.uniformRange.first};
pass.SetBindGroup(0, state.uniformBindGroup, offsets.size(), offsets.data());
pass.SetBindGroup(0, state.uniformBindGroup);
pass.SetBindGroup(1, find_bind_group(data.textureBindGroup));
pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.first, data.vertRange.second);
pass.Draw(4);

View File

@@ -30,15 +30,10 @@ struct alignas(4) Vert {
Vec3<float> pos;
Vec2<float> uv;
};
struct alignas(4) Uniform {
Mat4x4<float> xf;
Vec4<float> color;
};
State construct_state();
wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config);
DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const TextureHandle& tex_u,
const TextureHandle& tex_v, const zeus::CVector3f& v1, const zeus::CVector3f& v2,
const zeus::CVector3f& v3, const zeus::CVector3f& v4);
const TextureHandle& tex_v, float h_pad, float v_pad);
void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass);
} // namespace aurora::gfx::movie_player

View File

@@ -2,6 +2,7 @@
#include "../gpu.hpp"
#include "common.hpp"
#include "gx.hpp"
#include <utility>
@@ -12,28 +13,6 @@ using namespace fmt::literals;
static logvisor::Module Log("aurora::gfx::stream");
struct STevStage {
metaforce::CTevCombiners::ColorPass colorPass;
metaforce::CTevCombiners::AlphaPass alphaPass;
metaforce::CTevCombiners::CTevOp colorOp;
metaforce::CTevCombiners::CTevOp alphaOp;
STevStage(const metaforce::CTevCombiners::ColorPass& colPass, const metaforce::CTevCombiners::AlphaPass& alphaPass,
const metaforce::CTevCombiners::CTevOp& colorOp, const metaforce::CTevCombiners::CTevOp& alphaOp)
: colorPass(colPass), alphaPass(alphaPass), colorOp(colorOp), alphaOp(alphaOp) {}
};
constexpr u32 maxTevStages = 2;
static std::array<std::optional<STevStage>, maxTevStages> sTevStages;
void disable_tev_stage(metaforce::ERglTevStage stage) noexcept { sTevStages[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 {
sTevStages[static_cast<size_t>(stage)] = {colPass, alphaPass, colorOp, alphaOp};
}
struct SStreamState {
GX::Primitive primitive;
metaforce::EStreamFlags flags;
@@ -218,7 +197,7 @@ std::unordered_map<ShaderRef, wgpu::ShaderModule> g_streamCachedShaders;
static ShaderRef generate_shader() {
auto flags = sStreamState->flags;
const auto hash = xxh3_hash(sTevStages, static_cast<metaforce::EStreamFlags::MaskType>(flags));
const auto hash = hash_tev_stages(static_cast<metaforce::EStreamFlags::MaskType>(flags));
if (g_streamCachedShaders.contains(hash)) {
return hash;
}
@@ -264,7 +243,7 @@ static ShaderRef generate_shader() {
}
std::string fragmentFn;
bool hasRast = false;
for (size_t idx = 0; const auto& stage : sTevStages) {
for (size_t idx = 0; const auto& stage : g_tevStages) {
if (!stage) {
idx++;
continue;
@@ -288,7 +267,7 @@ static ShaderRef generate_shader() {
}
idx++;
}
for (size_t idx = 0; const auto& stage : sTevStages) {
for (size_t idx = 0; const auto& stage : g_tevStages) {
if (!stage) {
idx++;
continue;

View File

@@ -1,5 +1,6 @@
#include "shader.hpp"
#include "../gx.hpp"
#include "../../gpu.hpp"
#include <logvisor/logvisor.hpp>