From fc742782a8138f126d67d438f69c5e2c7cbd376e Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 1 Jul 2022 00:00:29 -0400 Subject: [PATCH] aurora: Blend mode & palette fixes More complete thermal visor rendering --- Runtime/Character/CModelData.cpp | 9 +++-- Runtime/Character/CModelData.hpp | 3 +- Runtime/Graphics/CCubeRenderer.cpp | 23 +++++------- aurora/lib/gfx/common.cpp | 4 +-- aurora/lib/gfx/gx.cpp | 33 ++++-------------- aurora/lib/gfx/gx.hpp | 4 +-- aurora/lib/gfx/gx_shader.cpp | 56 ++++++++++++++++++------------ aurora/lib/gfx/texture.cpp | 8 +++-- 8 files changed, 65 insertions(+), 75 deletions(-) diff --git a/Runtime/Character/CModelData.cpp b/Runtime/Character/CModelData.cpp index 6e8ccaf45..7c5e5c51d 100644 --- a/Runtime/Character/CModelData.cpp +++ b/Runtime/Character/CModelData.cpp @@ -294,7 +294,7 @@ void CModelData::RenderThermal(const zeus::CTransform& xf, const zeus::CColor& m if (x10_animData) { CSkinnedModel& model = PickAnimatedModel(EWhichModel::ThermalHot); x10_animData->SetupRender(model, nullptr, nullptr); - ThermalDraw(mulColor, addColor, flags); + ThermalDraw(model, mulColor, addColor, flags); } else { auto& model = PickStaticModel(EWhichModel::ThermalHot); g_Renderer->DrawThermalModel(*model, mulColor, addColor, {}, {}, flags); @@ -444,6 +444,11 @@ void CModelData::DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, } } -void CModelData::ThermalDraw(const zeus::CColor& mulColor, const zeus::CColor& addColor, const CModelFlags& flags) {} +void CModelData::ThermalDraw(CSkinnedModel& model, const zeus::CColor& mulColor, const zeus::CColor& addColor, + const CModelFlags& flags) { + model.DoDrawCallback([&](auto positions, auto normals) { + g_Renderer->DrawThermalModel(*model.GetModel(), mulColor, addColor, positions, normals, flags); + }); +} } // namespace metaforce diff --git a/Runtime/Character/CModelData.hpp b/Runtime/Character/CModelData.hpp index bb56ab2d8..46f37b511 100644 --- a/Runtime/Character/CModelData.hpp +++ b/Runtime/Character/CModelData.hpp @@ -130,7 +130,8 @@ public: const zeus::CColor& addColor, float t); void DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, CTexture& tex, const zeus::CColor& addColor, float t); - void ThermalDraw(const zeus::CColor& mulColor, const zeus::CColor& addColor, const CModelFlags& flags); + static void ThermalDraw(CSkinnedModel& model, const zeus::CColor& mulColor, const zeus::CColor& addColor, + const CModelFlags& flags); CAnimData* GetAnimationData() { return x10_animData.get(); } const CAnimData* GetAnimationData() const { return x10_animData.get(); } diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index 9e41ad8b8..41f8e9625 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -222,24 +222,17 @@ void CCubeRenderer::GenerateFogVolumeRampTex() { void CCubeRenderer::GenerateSphereRampTex() { u8* data = x220_sphereRamp.Lock(); - u32 offset = 0; - for (u32 y = 0; y < 32; ++y) { - s32 iVar3 = y >> 0x1f; - u8* row = data + offset; - for (u32 x = 0; x < 32; ++x) { - // TODO actually figure out what this is doing - const u32 vx = - ((static_cast(y) >> 2) + static_cast(y < 0 && (y & 3) != 0)) * 4 + (static_cast(x) >> 3); - const u32 vy = ((iVar3 * 4 | (y * 0x40000000 + iVar3) >> 0x1e) - iVar3) * 8 + (x & 7); + const size_t height = x220_sphereRamp.GetHeight(); + const size_t width = x220_sphereRamp.GetWidth(); + const float halfRes = height / 2.f; + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { const zeus::CVector2f vec{ - static_cast(vx) / 15.5f - 1.f, - static_cast(vy) / 15.5f - 1.f, + (static_cast(x) - halfRes) / halfRes, + (static_cast(y) - halfRes) / halfRes, }; - const auto mag = vec.magnitude(); - *row = static_cast(255.f * std::clamp(-(mag * mag - 1.f), 0.f, 1.f)); - ++row; + data[y * height + x] = 255 - zeus::clamp(0.f, vec.canBeNormalized() ? vec.magnitude() : 0.f, 1.f) * 255; } - offset += 32; } x220_sphereRamp.UnLock(); } diff --git a/aurora/lib/gfx/common.cpp b/aurora/lib/gfx/common.cpp index e28777973..791dc25ab 100644 --- a/aurora/lib/gfx/common.cpp +++ b/aurora/lib/gfx/common.cpp @@ -572,8 +572,8 @@ void render(wgpu::CommandEncoder& cmd) { }; const wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{ .view = gpu::g_depthBuffer.view, - .depthLoadOp = wgpu::LoadOp::Clear, - .depthStoreOp = wgpu::StoreOp::Discard, + .depthLoadOp = passInfo.clear ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load, + .depthStoreOp = wgpu::StoreOp::Store, .depthClearValue = 1.f, }; const auto label = fmt::format(FMT_STRING("Render pass {}"), i); diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index 6e2985ebf..ab1766bf2 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -695,7 +695,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto case GX::BM_NONE: colorBlendComponent = { .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Src, + .srcFactor = wgpu::BlendFactor::One, .dstFactor = wgpu::BlendFactor::Zero, }; break; @@ -709,8 +709,8 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto case GX::BM_SUBTRACT: colorBlendComponent = { .operation = wgpu::BlendOperation::ReverseSubtract, - .srcFactor = wgpu::BlendFactor::Src, - .dstFactor = wgpu::BlendFactor::Dst, + .srcFactor = wgpu::BlendFactor::One, + .dstFactor = wgpu::BlendFactor::One, }; break; case GX::BM_LOGIC: @@ -725,7 +725,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto case GX::LO_COPY: colorBlendComponent = { .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Src, + .srcFactor = wgpu::BlendFactor::One, .dstFactor = wgpu::BlendFactor::Zero, }; break; @@ -733,28 +733,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto colorBlendComponent = { .operation = wgpu::BlendOperation::Add, .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::Dst, - }; - break; - case GX::LO_INV: - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::OneMinusDst, - }; - break; - case GX::LO_INVCOPY: - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::OneMinusSrc, - .dstFactor = wgpu::BlendFactor::Zero, - }; - break; - case GX::LO_SET: - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::One, - .dstFactor = wgpu::BlendFactor::Zero, + .dstFactor = wgpu::BlendFactor::One, }; break; default: @@ -768,7 +747,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto } wgpu::BlendComponent alphaBlendComponent{ .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::SrcAlpha, + .srcFactor = wgpu::BlendFactor::One, .dstFactor = wgpu::BlendFactor::Zero, }; if (dstAlpha != UINT32_MAX) { diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index 56f0c27db..1b3df6e9b 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -253,7 +253,7 @@ static inline bool is_palette_format(GX::TextureFormat fmt) { struct TextureConfig { GX::TextureFormat copyFmt = InvalidTextureFormat; // Underlying texture format GX::TextureFormat loadFmt = InvalidTextureFormat; // Texture format being bound - bool renderTex = false; // Perform conversion / flip UVs + bool renderTex = false; // Perform conversion u8 _p1 = 0; u8 _p2 = 0; u8 _p3 = 0; @@ -312,7 +312,7 @@ struct ShaderInfo { std::bitset writesTevReg; std::bitset usesTexMtx; std::bitset usesPTTexMtx; - std::array texMtxTypes; + std::array texMtxTypes{}; u32 uniformSize = 0; bool usesFog : 1 = false; }; diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index 1d9d11819..6b191d7ac 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -160,8 +160,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx); unreachable(); } - const auto swap = config.tevSwapTable[stage.tevSwapTex]; - // TODO check for CH_ALPHA + config.texHasAlpha + 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)); } @@ -173,7 +172,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx); unreachable(); } - const auto swap = config.tevSwapTable[stage.tevSwapTex]; + const auto& swap = config.tevSwapTable[stage.tevSwapTex]; return fmt::format(FMT_STRING("vec3(sampled{}.{})"), stageIdx, chan_comp(swap.alpha)); } case GX::CC_RASC: { @@ -187,7 +186,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha unreachable(); } u32 idx = stage.channelId - GX::COLOR0A0; - const auto swap = config.tevSwapTable[stage.tevSwapRas]; + 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)); } @@ -202,7 +201,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha unreachable(); } u32 idx = stage.channelId - GX::COLOR0A0; - const auto swap = config.tevSwapTable[stage.tevSwapRas]; + const auto& swap = config.tevSwapTable[stage.tevSwapRas]; return fmt::format(FMT_STRING("vec3(rast{}.{})"), idx, chan_comp(swap.alpha)); } case GX::CC_ONE: @@ -371,7 +370,7 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx); unreachable(); } - const auto swap = config.tevSwapTable[stage.tevSwapTex]; + const auto& swap = config.tevSwapTable[stage.tevSwapTex]; return fmt::format(FMT_STRING("sampled{}.{}"), stageIdx, chan_comp(swap.alpha)); } case GX::CA_RASA: { @@ -385,7 +384,7 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha unreachable(); } u32 idx = stage.channelId - GX::COLOR0A0; - const auto swap = config.tevSwapTable[stage.tevSwapRas]; + const auto& swap = config.tevSwapTable[stage.tevSwapRas]; return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha)); } case GX::CA_KONST: { @@ -560,7 +559,7 @@ static inline std::string texture_conversion(const TextureConfig& tex, u32 stage case GX::TF_I4: case GX::TF_I8: // FIXME HACK - if (tex.loadFmt != GX::TF_C4 && tex.loadFmt != GX::TF_C8 && tex.loadFmt != GX::TF_C14X2) { + if (!is_palette_format(tex.loadFmt)) { // Perform intensity conversion out += fmt::format(FMT_STRING("\n sampled{0} = vec4(intensityF32(sampled{0}.rgb), 0.f, 0.f, 1.f);"), stageIdx); @@ -1076,18 +1075,29 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in || !info.sampledTextures.test(stage.texMapId)) { continue; } - std::string uvIn; + std::string uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), stage.texCoordId); const auto& texConfig = config.textureConfig[stage.texMapId]; - // TODO - // if (texConfig.flipUV) { - // uvIn = fmt::format(FMT_STRING("vec2(in.tex{0}_uv.x, -in.tex{0}_uv.y)"), stage.texCoordId); - // } else { - uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), stage.texCoordId); - // } if (is_palette_format(texConfig.loadFmt)) { + std::string_view suffix; + if (!is_palette_format(texConfig.copyFmt)) { + switch (texConfig.loadFmt) { + case GX::TF_C4: + suffix = "I4"sv; + break; +// case GX::TF_C8: +// suffix = "I8"; +// break; +// case GX::TF_C14X2: +// suffix = "I14X2"; +// break; + default: + Log.report(logvisor::Fatal, FMT_STRING("Unsupported palette format {}"), texConfig.loadFmt); + unreachable(); + } + } fragmentFnPre += fmt::format(FMT_STRING("\n var sampled{0} = textureSamplePalette{3}(tex{1}, tex{1}_samp, {2}, tlut{1});"), - i, stage.texMapId, uvIn, is_palette_format(texConfig.copyFmt) ? ""sv : "RGB"sv); + i, 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, @@ -1233,8 +1243,8 @@ fn intensityF32(rgb: vec3) -> f32 {{ // https://github.com/dolphin-emu/dolphin/blob/4cd48e609c507e65b95bca5afb416b59eaf7f683/Source/Core/VideoCommon/TextureConverterShaderGen.cpp#L237-L241 return dot(rgb, vec3(0.257, 0.504, 0.098)) + 16.0 / 255.0; }} -fn intensityI32(rgb: vec3) -> i32 {{ - return i32(dot(rgb, vec3(0.257, 0.504, 0.098)) * 255.f); +fn intensityI4(rgb: vec3) -> i32 {{ + return i32(intensityF32(rgb) * 16.f); }} fn textureSamplePalette(tex: texture_2d, samp: sampler, uv: vec2, tlut: texture_2d) -> vec4 {{ // Gather index values @@ -1250,16 +1260,16 @@ fn textureSamplePalette(tex: texture_2d, samp: sampler, uv: vec2, tlut var t1 = mix(c0, c1, f.x); return mix(t0, t1, f.y); }} -fn textureSamplePaletteRGB(tex: texture_2d, samp: sampler, uv: vec2, tlut: texture_2d) -> vec4 {{ +fn textureSamplePaletteI4(tex: texture_2d, samp: sampler, uv: vec2, tlut: texture_2d) -> vec4 {{ // Gather RGB channels var iR = textureGather(0, tex, samp, uv); var iG = textureGather(1, tex, samp, uv); var iB = textureGather(2, tex, samp, uv); // Perform intensity conversion - var i0 = intensityI32(vec3(iR[0], iG[0], iB[0])); - var i1 = intensityI32(vec3(iR[1], iG[1], iB[1])); - var i2 = intensityI32(vec3(iR[2], iG[2], iB[2])); - var i3 = intensityI32(vec3(iR[3], iG[3], iB[3])); + var i0 = intensityI4(vec3(iR[0], iG[0], iB[0])); + var i1 = intensityI4(vec3(iR[1], iG[1], iB[1])); + var i2 = intensityI4(vec3(iR[2], iG[2], iB[2])); + var i3 = intensityI4(vec3(iR[3], iG[3], iB[3])); // Load palette colors var c0 = textureLoad(tlut, vec2(i0, 0), 0); var c1 = textureLoad(tlut, vec2(i1, 0), 0); diff --git a/aurora/lib/gfx/texture.cpp b/aurora/lib/gfx/texture.cpp index d9def0ae2..e55885e80 100644 --- a/aurora/lib/gfx/texture.cpp +++ b/aurora/lib/gfx/texture.cpp @@ -75,13 +75,15 @@ TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mi .texture = ref.texture, .mipLevel = mip, }; - const auto range = push_texture_data(data.data() + offset, dataSize, bytesPerRow, heightBlocks); +// const auto range = push_texture_data(data.data() + offset, dataSize, bytesPerRow, heightBlocks); const auto dataLayout = wgpu::TextureDataLayout{ - .offset = range.offset, +// .offset = range.offset, .bytesPerRow = bytesPerRow, .rowsPerImage = heightBlocks, }; - g_textureUploads.emplace_back(dataLayout, std::move(dstView), physicalSize); + // TODO +// g_textureUploads.emplace_back(dataLayout, std::move(dstView), physicalSize); + g_queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize); offset += dataSize; } if (data.size() != UINT32_MAX && offset < data.size()) {