aurora: Blend mode & palette fixes

More complete thermal visor rendering
This commit is contained in:
Luke Street 2022-07-01 00:00:29 -04:00
parent ee3902db58
commit fc742782a8
8 changed files with 65 additions and 75 deletions

View File

@ -294,7 +294,7 @@ void CModelData::RenderThermal(const zeus::CTransform& xf, const zeus::CColor& m
if (x10_animData) { if (x10_animData) {
CSkinnedModel& model = PickAnimatedModel(EWhichModel::ThermalHot); CSkinnedModel& model = PickAnimatedModel(EWhichModel::ThermalHot);
x10_animData->SetupRender(model, nullptr, nullptr); x10_animData->SetupRender(model, nullptr, nullptr);
ThermalDraw(mulColor, addColor, flags); ThermalDraw(model, mulColor, addColor, flags);
} else { } else {
auto& model = PickStaticModel(EWhichModel::ThermalHot); auto& model = PickStaticModel(EWhichModel::ThermalHot);
g_Renderer->DrawThermalModel(*model, mulColor, addColor, {}, {}, flags); 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 } // namespace metaforce

View File

@ -130,7 +130,8 @@ public:
const zeus::CColor& addColor, float t); const zeus::CColor& addColor, float t);
void DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, CTexture& tex, const zeus::CColor& addColor, void DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, CTexture& tex, const zeus::CColor& addColor,
float t); 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(); } CAnimData* GetAnimationData() { return x10_animData.get(); }
const CAnimData* GetAnimationData() const { return x10_animData.get(); } const CAnimData* GetAnimationData() const { return x10_animData.get(); }

View File

@ -222,24 +222,17 @@ void CCubeRenderer::GenerateFogVolumeRampTex() {
void CCubeRenderer::GenerateSphereRampTex() { void CCubeRenderer::GenerateSphereRampTex() {
u8* data = x220_sphereRamp.Lock(); u8* data = x220_sphereRamp.Lock();
u32 offset = 0; const size_t height = x220_sphereRamp.GetHeight();
for (u32 y = 0; y < 32; ++y) { const size_t width = x220_sphereRamp.GetWidth();
s32 iVar3 = y >> 0x1f; const float halfRes = height / 2.f;
u8* row = data + offset; for (size_t y = 0; y < height; ++y) {
for (u32 x = 0; x < 32; ++x) { for (size_t x = 0; x < width; ++x) {
// TODO actually figure out what this is doing
const u32 vx =
((static_cast<s32>(y) >> 2) + static_cast<u32>(y < 0 && (y & 3) != 0)) * 4 + (static_cast<s32>(x) >> 3);
const u32 vy = ((iVar3 * 4 | (y * 0x40000000 + iVar3) >> 0x1e) - iVar3) * 8 + (x & 7);
const zeus::CVector2f vec{ const zeus::CVector2f vec{
static_cast<float>(vx) / 15.5f - 1.f, (static_cast<float>(x) - halfRes) / halfRes,
static_cast<float>(vy) / 15.5f - 1.f, (static_cast<float>(y) - halfRes) / halfRes,
}; };
const auto mag = vec.magnitude(); data[y * height + x] = 255 - zeus::clamp(0.f, vec.canBeNormalized() ? vec.magnitude() : 0.f, 1.f) * 255;
*row = static_cast<u8>(255.f * std::clamp(-(mag * mag - 1.f), 0.f, 1.f));
++row;
} }
offset += 32;
} }
x220_sphereRamp.UnLock(); x220_sphereRamp.UnLock();
} }

View File

@ -572,8 +572,8 @@ void render(wgpu::CommandEncoder& cmd) {
}; };
const wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{ const wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
.view = gpu::g_depthBuffer.view, .view = gpu::g_depthBuffer.view,
.depthLoadOp = wgpu::LoadOp::Clear, .depthLoadOp = passInfo.clear ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load,
.depthStoreOp = wgpu::StoreOp::Discard, .depthStoreOp = wgpu::StoreOp::Store,
.depthClearValue = 1.f, .depthClearValue = 1.f,
}; };
const auto label = fmt::format(FMT_STRING("Render pass {}"), i); const auto label = fmt::format(FMT_STRING("Render pass {}"), i);

View File

@ -695,7 +695,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto
case GX::BM_NONE: case GX::BM_NONE:
colorBlendComponent = { colorBlendComponent = {
.operation = wgpu::BlendOperation::Add, .operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Src, .srcFactor = wgpu::BlendFactor::One,
.dstFactor = wgpu::BlendFactor::Zero, .dstFactor = wgpu::BlendFactor::Zero,
}; };
break; break;
@ -709,8 +709,8 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto
case GX::BM_SUBTRACT: case GX::BM_SUBTRACT:
colorBlendComponent = { colorBlendComponent = {
.operation = wgpu::BlendOperation::ReverseSubtract, .operation = wgpu::BlendOperation::ReverseSubtract,
.srcFactor = wgpu::BlendFactor::Src, .srcFactor = wgpu::BlendFactor::One,
.dstFactor = wgpu::BlendFactor::Dst, .dstFactor = wgpu::BlendFactor::One,
}; };
break; break;
case GX::BM_LOGIC: case GX::BM_LOGIC:
@ -725,7 +725,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto
case GX::LO_COPY: case GX::LO_COPY:
colorBlendComponent = { colorBlendComponent = {
.operation = wgpu::BlendOperation::Add, .operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Src, .srcFactor = wgpu::BlendFactor::One,
.dstFactor = wgpu::BlendFactor::Zero, .dstFactor = wgpu::BlendFactor::Zero,
}; };
break; break;
@ -733,28 +733,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto
colorBlendComponent = { colorBlendComponent = {
.operation = wgpu::BlendOperation::Add, .operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Zero, .srcFactor = wgpu::BlendFactor::Zero,
.dstFactor = wgpu::BlendFactor::Dst, .dstFactor = wgpu::BlendFactor::One,
};
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,
}; };
break; break;
default: default:
@ -768,7 +747,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto
} }
wgpu::BlendComponent alphaBlendComponent{ wgpu::BlendComponent alphaBlendComponent{
.operation = wgpu::BlendOperation::Add, .operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::SrcAlpha, .srcFactor = wgpu::BlendFactor::One,
.dstFactor = wgpu::BlendFactor::Zero, .dstFactor = wgpu::BlendFactor::Zero,
}; };
if (dstAlpha != UINT32_MAX) { if (dstAlpha != UINT32_MAX) {

View File

@ -253,7 +253,7 @@ static inline bool is_palette_format(GX::TextureFormat fmt) {
struct TextureConfig { struct TextureConfig {
GX::TextureFormat copyFmt = InvalidTextureFormat; // Underlying texture format GX::TextureFormat copyFmt = InvalidTextureFormat; // Underlying texture format
GX::TextureFormat loadFmt = InvalidTextureFormat; // Texture format being bound GX::TextureFormat loadFmt = InvalidTextureFormat; // Texture format being bound
bool renderTex = false; // Perform conversion / flip UVs bool renderTex = false; // Perform conversion
u8 _p1 = 0; u8 _p1 = 0;
u8 _p2 = 0; u8 _p2 = 0;
u8 _p3 = 0; u8 _p3 = 0;
@ -312,7 +312,7 @@ struct ShaderInfo {
std::bitset<MaxTevRegs> writesTevReg; std::bitset<MaxTevRegs> writesTevReg;
std::bitset<MaxTexMtx> usesTexMtx; std::bitset<MaxTexMtx> usesTexMtx;
std::bitset<MaxPTTexMtx> usesPTTexMtx; std::bitset<MaxPTTexMtx> usesPTTexMtx;
std::array<GX::TexGenType, MaxTexMtx> texMtxTypes; std::array<GX::TexGenType, MaxTexMtx> texMtxTypes{};
u32 uniformSize = 0; u32 uniformSize = 0;
bool usesFog : 1 = false; bool usesFog : 1 = false;
}; };

View File

@ -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); Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx);
unreachable(); unreachable();
} }
const auto swap = config.tevSwapTable[stage.tevSwapTex]; const auto& swap = config.tevSwapTable[stage.tevSwapTex];
// TODO check for CH_ALPHA + config.texHasAlpha
return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stageIdx, chan_comp(swap.red), chan_comp(swap.green), return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stageIdx, chan_comp(swap.red), chan_comp(swap.green),
chan_comp(swap.blue)); 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); Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx);
unreachable(); unreachable();
} }
const auto swap = config.tevSwapTable[stage.tevSwapTex]; const auto& swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("vec3<f32>(sampled{}.{})"), stageIdx, chan_comp(swap.alpha)); return fmt::format(FMT_STRING("vec3<f32>(sampled{}.{})"), stageIdx, chan_comp(swap.alpha));
} }
case GX::CC_RASC: { case GX::CC_RASC: {
@ -187,7 +186,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha
unreachable(); unreachable();
} }
u32 idx = stage.channelId - GX::COLOR0A0; 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), return fmt::format(FMT_STRING("rast{}.{}{}{}"), idx, chan_comp(swap.red), chan_comp(swap.green),
chan_comp(swap.blue)); chan_comp(swap.blue));
} }
@ -202,7 +201,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha
unreachable(); unreachable();
} }
u32 idx = stage.channelId - GX::COLOR0A0; 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<f32>(rast{}.{})"), idx, chan_comp(swap.alpha)); return fmt::format(FMT_STRING("vec3<f32>(rast{}.{})"), idx, chan_comp(swap.alpha));
} }
case GX::CC_ONE: 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); Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx);
unreachable(); 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)); return fmt::format(FMT_STRING("sampled{}.{}"), stageIdx, chan_comp(swap.alpha));
} }
case GX::CA_RASA: { case GX::CA_RASA: {
@ -385,7 +384,7 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha
unreachable(); unreachable();
} }
u32 idx = stage.channelId - GX::COLOR0A0; 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)); return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha));
} }
case GX::CA_KONST: { 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_I4:
case GX::TF_I8: case GX::TF_I8:
// FIXME HACK // 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 // Perform intensity conversion
out += fmt::format(FMT_STRING("\n sampled{0} = vec4<f32>(intensityF32(sampled{0}.rgb), 0.f, 0.f, 1.f);"), out += fmt::format(FMT_STRING("\n sampled{0} = vec4<f32>(intensityF32(sampled{0}.rgb), 0.f, 0.f, 1.f);"),
stageIdx); stageIdx);
@ -1076,18 +1075,29 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
|| !info.sampledTextures.test(stage.texMapId)) { || !info.sampledTextures.test(stage.texMapId)) {
continue; continue;
} }
std::string uvIn; std::string uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), stage.texCoordId);
const auto& texConfig = config.textureConfig[stage.texMapId]; const auto& texConfig = config.textureConfig[stage.texMapId];
// TODO
// if (texConfig.flipUV) {
// uvIn = fmt::format(FMT_STRING("vec2<f32>(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)) { 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 += fragmentFnPre +=
fmt::format(FMT_STRING("\n var sampled{0} = textureSamplePalette{3}(tex{1}, tex{1}_samp, {2}, tlut{1});"), 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 { } else {
fragmentFnPre += fmt::format( fragmentFnPre += fmt::format(
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{1}, tex{1}_samp, {2}, ubuf.tex{1}_lod);"), i, 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>) -> f32 {{
// https://github.com/dolphin-emu/dolphin/blob/4cd48e609c507e65b95bca5afb416b59eaf7f683/Source/Core/VideoCommon/TextureConverterShaderGen.cpp#L237-L241 // 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; return dot(rgb, vec3(0.257, 0.504, 0.098)) + 16.0 / 255.0;
}} }}
fn intensityI32(rgb: vec3<f32>) -> i32 {{ fn intensityI4(rgb: vec3<f32>) -> i32 {{
return i32(dot(rgb, vec3(0.257, 0.504, 0.098)) * 255.f); return i32(intensityF32(rgb) * 16.f);
}} }}
fn textureSamplePalette(tex: texture_2d<i32>, samp: sampler, uv: vec2<f32>, tlut: texture_2d<f32>) -> vec4<f32> {{ fn textureSamplePalette(tex: texture_2d<i32>, samp: sampler, uv: vec2<f32>, tlut: texture_2d<f32>) -> vec4<f32> {{
// Gather index values // Gather index values
@ -1250,16 +1260,16 @@ fn textureSamplePalette(tex: texture_2d<i32>, samp: sampler, uv: vec2<f32>, tlut
var t1 = mix(c0, c1, f.x); var t1 = mix(c0, c1, f.x);
return mix(t0, t1, f.y); return mix(t0, t1, f.y);
}} }}
fn textureSamplePaletteRGB(tex: texture_2d<f32>, samp: sampler, uv: vec2<f32>, tlut: texture_2d<f32>) -> vec4<f32> {{ fn textureSamplePaletteI4(tex: texture_2d<f32>, samp: sampler, uv: vec2<f32>, tlut: texture_2d<f32>) -> vec4<f32> {{
// Gather RGB channels // Gather RGB channels
var iR = textureGather(0, tex, samp, uv); var iR = textureGather(0, tex, samp, uv);
var iG = textureGather(1, tex, samp, uv); var iG = textureGather(1, tex, samp, uv);
var iB = textureGather(2, tex, samp, uv); var iB = textureGather(2, tex, samp, uv);
// Perform intensity conversion // Perform intensity conversion
var i0 = intensityI32(vec3<f32>(iR[0], iG[0], iB[0])); var i0 = intensityI4(vec3<f32>(iR[0], iG[0], iB[0]));
var i1 = intensityI32(vec3<f32>(iR[1], iG[1], iB[1])); var i1 = intensityI4(vec3<f32>(iR[1], iG[1], iB[1]));
var i2 = intensityI32(vec3<f32>(iR[2], iG[2], iB[2])); var i2 = intensityI4(vec3<f32>(iR[2], iG[2], iB[2]));
var i3 = intensityI32(vec3<f32>(iR[3], iG[3], iB[3])); var i3 = intensityI4(vec3<f32>(iR[3], iG[3], iB[3]));
// Load palette colors // Load palette colors
var c0 = textureLoad(tlut, vec2<i32>(i0, 0), 0); var c0 = textureLoad(tlut, vec2<i32>(i0, 0), 0);
var c1 = textureLoad(tlut, vec2<i32>(i1, 0), 0); var c1 = textureLoad(tlut, vec2<i32>(i1, 0), 0);

View File

@ -75,13 +75,15 @@ TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mi
.texture = ref.texture, .texture = ref.texture,
.mipLevel = mip, .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{ const auto dataLayout = wgpu::TextureDataLayout{
.offset = range.offset, // .offset = range.offset,
.bytesPerRow = bytesPerRow, .bytesPerRow = bytesPerRow,
.rowsPerImage = heightBlocks, .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; offset += dataSize;
} }
if (data.size() != UINT32_MAX && offset < data.size()) { if (data.size() != UINT32_MAX && offset < data.size()) {