2015-05-24 04:55:12 +00:00
|
|
|
// Copyright 2009 Dolphin Emulator Project
|
2021-07-05 01:22:19 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2019-07-17 00:18:48 +00:00
|
|
|
#include "VideoBackends/Software/Tev.h"
|
|
|
|
|
2017-12-25 23:38:44 +00:00
|
|
|
#include <algorithm>
|
2014-02-17 10:18:15 +00:00
|
|
|
#include <cmath>
|
2021-04-09 01:10:13 +00:00
|
|
|
#include <cstring>
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2014-07-30 00:55:07 +00:00
|
|
|
#include "Common/ChunkFile.h"
|
2014-09-08 01:06:58 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "VideoBackends/Software/DebugUtil.h"
|
|
|
|
#include "VideoBackends/Software/EfbInterface.h"
|
2021-06-09 11:42:21 +00:00
|
|
|
#include "VideoBackends/Software/SWBoundingBox.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "VideoBackends/Software/TextureSampler.h"
|
2015-10-09 18:50:36 +00:00
|
|
|
|
2016-01-17 21:54:31 +00:00
|
|
|
#include "VideoCommon/PerfQueryBase.h"
|
2016-03-06 10:03:45 +00:00
|
|
|
#include "VideoCommon/PixelShaderManager.h"
|
2015-10-09 18:50:36 +00:00
|
|
|
#include "VideoCommon/Statistics.h"
|
2019-07-17 00:18:48 +00:00
|
|
|
#include "VideoCommon/VideoCommon.h"
|
2015-10-09 18:50:36 +00:00
|
|
|
#include "VideoCommon/VideoConfig.h"
|
|
|
|
#include "VideoCommon/XFMemory.h"
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2010-12-02 05:38:48 +00:00
|
|
|
#ifdef _DEBUG
|
|
|
|
#define ALLOW_TEV_DUMPS 1
|
|
|
|
#else
|
|
|
|
#define ALLOW_TEV_DUMPS 0
|
|
|
|
#endif
|
|
|
|
|
2014-08-11 01:51:05 +00:00
|
|
|
static inline s16 Clamp255(s16 in)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-12-22 02:23:39 +00:00
|
|
|
return std::clamp<s16>(in, 0, 255);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2014-08-11 01:51:05 +00:00
|
|
|
static inline s16 Clamp1024(s16 in)
|
2009-10-28 03:01:07 +00:00
|
|
|
{
|
2021-12-22 02:23:39 +00:00
|
|
|
return std::clamp<s16>(in, -1024, 1023);
|
2009-10-28 03:01:07 +00:00
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
void Tev::SetRasColor(RasColorChan colorChan, int swaptable)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2014-03-10 11:30:55 +00:00
|
|
|
switch (colorChan)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case RasColorChan::Color0:
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2017-09-03 18:02:57 +00:00
|
|
|
const u8* color = Color[0];
|
2021-12-22 00:43:38 +00:00
|
|
|
RasColor.r = color[bpmem.tevksel[swaptable].swap1];
|
|
|
|
RasColor.g = color[bpmem.tevksel[swaptable].swap2];
|
2009-10-12 00:48:24 +00:00
|
|
|
swaptable++;
|
2021-12-22 00:43:38 +00:00
|
|
|
RasColor.b = color[bpmem.tevksel[swaptable].swap1];
|
|
|
|
RasColor.a = color[bpmem.tevksel[swaptable].swap2];
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case RasColorChan::Color1:
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2017-09-03 18:02:57 +00:00
|
|
|
const u8* color = Color[1];
|
2021-12-22 00:43:38 +00:00
|
|
|
RasColor.r = color[bpmem.tevksel[swaptable].swap1];
|
|
|
|
RasColor.g = color[bpmem.tevksel[swaptable].swap2];
|
2009-10-12 00:48:24 +00:00
|
|
|
swaptable++;
|
2021-12-22 00:43:38 +00:00
|
|
|
RasColor.b = color[bpmem.tevksel[swaptable].swap1];
|
|
|
|
RasColor.a = color[bpmem.tevksel[swaptable].swap2];
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case RasColorChan::AlphaBump:
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-12-22 00:43:38 +00:00
|
|
|
RasColor = TevColor::All(AlphaBump);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case RasColorChan::NormalizedAlphaBump:
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2017-09-03 18:02:57 +00:00
|
|
|
const u8 normalized = AlphaBump | AlphaBump >> 5;
|
2021-12-22 00:43:38 +00:00
|
|
|
RasColor = TevColor::All(normalized);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
default:
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
if (colorChan != RasColorChan::Zero)
|
|
|
|
PanicAlertFmt("Invalid ras color channel: {}", colorChan);
|
|
|
|
|
2021-12-22 00:43:38 +00:00
|
|
|
RasColor = TevColor::All(0);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2017-09-03 18:02:57 +00:00
|
|
|
void Tev::DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4])
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
for (int i = BLU_C; i <= RED_C; i++)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
const InputRegType& InputReg = inputs[i];
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2017-09-03 18:02:57 +00:00
|
|
|
const u16 c = InputReg.c + (InputReg.c >> 7);
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
|
2021-12-22 02:15:25 +00:00
|
|
|
temp <<= s_ScaleLShiftLUT[cc.scale];
|
2021-02-11 02:11:31 +00:00
|
|
|
temp += (cc.scale == TevScale::Divide2) ? 0 : (cc.op == TevOp::Sub) ? 127 : 128;
|
2014-04-15 21:01:22 +00:00
|
|
|
temp >>= 8;
|
2021-02-11 02:11:31 +00:00
|
|
|
temp = cc.op == TevOp::Sub ? -temp : temp;
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-12-22 02:15:25 +00:00
|
|
|
s32 result = ((InputReg.d + s_BiasLUT[cc.bias]) << s_ScaleLShiftLUT[cc.scale]) + temp;
|
|
|
|
result = result >> s_ScaleRShiftLUT[cc.scale];
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[cc.dest][i] = result;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2017-09-03 18:02:57 +00:00
|
|
|
void Tev::DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4])
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2014-04-15 21:05:12 +00:00
|
|
|
for (int i = BLU_C; i <= RED_C; i++)
|
2014-03-24 13:42:04 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
u32 a, b;
|
|
|
|
switch (cc.compare_mode)
|
2014-03-24 13:42:04 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case TevCompareMode::R8:
|
|
|
|
a = inputs[RED_C].a;
|
|
|
|
b = inputs[RED_C].b;
|
2014-03-24 13:42:04 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
case TevCompareMode::GR16:
|
|
|
|
a = (inputs[GRN_C].a << 8) | inputs[RED_C].a;
|
|
|
|
b = (inputs[GRN_C].b << 8) | inputs[RED_C].b;
|
2014-03-24 13:42:04 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
case TevCompareMode::BGR24:
|
|
|
|
a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
|
|
|
|
b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
|
2014-03-24 13:42:04 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
case TevCompareMode::RGB8:
|
|
|
|
a = inputs[i].a;
|
|
|
|
b = inputs[i].b;
|
2014-03-24 13:42:04 +00:00
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
PanicAlertFmt("Invalid compare mode {}", cc.compare_mode);
|
|
|
|
continue;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2021-02-11 02:11:31 +00:00
|
|
|
|
|
|
|
if (cc.comparison == TevComparison::GT)
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0);
|
2021-02-11 02:11:31 +00:00
|
|
|
else
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2017-09-03 18:02:57 +00:00
|
|
|
void Tev::DrawAlphaRegular(const TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4])
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2014-03-24 13:42:04 +00:00
|
|
|
const InputRegType& InputReg = inputs[ALP_C];
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2017-09-03 18:02:57 +00:00
|
|
|
const u16 c = InputReg.c + (InputReg.c >> 7);
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
|
2021-12-22 02:15:25 +00:00
|
|
|
temp <<= s_ScaleLShiftLUT[ac.scale];
|
2022-01-25 06:05:31 +00:00
|
|
|
temp += (ac.scale == TevScale::Divide2) ? 0 : (ac.op == TevOp::Sub) ? 127 : 128;
|
2021-02-11 02:11:31 +00:00
|
|
|
temp = ac.op == TevOp::Sub ? (-temp >> 8) : (temp >> 8);
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-12-22 02:15:25 +00:00
|
|
|
s32 result = ((InputReg.d + s_BiasLUT[ac.bias]) << s_ScaleLShiftLUT[ac.scale]) + temp;
|
|
|
|
result = result >> s_ScaleRShiftLUT[ac.scale];
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[ac.dest].a = result;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2017-09-03 18:02:57 +00:00
|
|
|
void Tev::DrawAlphaCompare(const TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4])
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
u32 a, b;
|
|
|
|
switch (ac.compare_mode)
|
2014-03-24 13:42:04 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case TevCompareMode::R8:
|
|
|
|
a = inputs[RED_C].a;
|
|
|
|
b = inputs[RED_C].b;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
case TevCompareMode::GR16:
|
|
|
|
a = (inputs[GRN_C].a << 8) | inputs[RED_C].a;
|
|
|
|
b = (inputs[GRN_C].b << 8) | inputs[RED_C].b;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
case TevCompareMode::BGR24:
|
|
|
|
a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
|
|
|
|
b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
case TevCompareMode::A8:
|
|
|
|
a = inputs[ALP_C].a;
|
|
|
|
b = inputs[ALP_C].b;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
PanicAlertFmt("Invalid compare mode {}", ac.compare_mode);
|
|
|
|
return;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2021-02-11 02:11:31 +00:00
|
|
|
|
|
|
|
if (ac.comparison == TevComparison::GT)
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[ac.dest].a = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0);
|
2021-02-11 02:11:31 +00:00
|
|
|
else
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[ac.dest].a = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
static bool AlphaCompare(int alpha, int ref, CompareMode comp)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2014-08-11 01:18:38 +00:00
|
|
|
switch (comp)
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case CompareMode::Always:
|
2014-03-24 19:21:34 +00:00
|
|
|
return true;
|
2021-02-11 02:11:31 +00:00
|
|
|
case CompareMode::Never:
|
2014-03-24 19:21:34 +00:00
|
|
|
return false;
|
2021-02-11 02:11:31 +00:00
|
|
|
case CompareMode::LEqual:
|
2014-03-24 19:21:34 +00:00
|
|
|
return alpha <= ref;
|
2021-02-11 02:11:31 +00:00
|
|
|
case CompareMode::Less:
|
2014-03-24 19:21:34 +00:00
|
|
|
return alpha < ref;
|
2021-02-11 02:11:31 +00:00
|
|
|
case CompareMode::GEqual:
|
2014-03-24 19:21:34 +00:00
|
|
|
return alpha >= ref;
|
2021-02-11 02:11:31 +00:00
|
|
|
case CompareMode::Greater:
|
2014-03-24 19:21:34 +00:00
|
|
|
return alpha > ref;
|
2021-02-11 02:11:31 +00:00
|
|
|
case CompareMode::Equal:
|
2014-03-24 19:21:34 +00:00
|
|
|
return alpha == ref;
|
2021-02-11 02:11:31 +00:00
|
|
|
case CompareMode::NEqual:
|
2014-03-24 19:21:34 +00:00
|
|
|
return alpha != ref;
|
2014-12-03 00:20:52 +00:00
|
|
|
default:
|
2021-02-11 02:11:31 +00:00
|
|
|
PanicAlertFmt("Invalid compare mode {}", comp);
|
2014-12-03 00:20:52 +00:00
|
|
|
return true;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2013-01-31 21:29:29 +00:00
|
|
|
static bool TevAlphaTest(int alpha)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2017-09-03 18:02:57 +00:00
|
|
|
const bool comp0 = AlphaCompare(alpha, bpmem.alpha_test.ref0, bpmem.alpha_test.comp0);
|
|
|
|
const bool comp1 = AlphaCompare(alpha, bpmem.alpha_test.ref1, bpmem.alpha_test.comp1);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2013-01-08 16:18:45 +00:00
|
|
|
switch (bpmem.alpha_test.logic)
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case AlphaTestOp::And:
|
|
|
|
return comp0 && comp1;
|
|
|
|
case AlphaTestOp::Or:
|
|
|
|
return comp0 || comp1;
|
|
|
|
case AlphaTestOp::Xor:
|
|
|
|
return comp0 ^ comp1;
|
|
|
|
case AlphaTestOp::Xnor:
|
|
|
|
return !(comp0 ^ comp1);
|
2014-12-03 00:20:52 +00:00
|
|
|
default:
|
2021-02-11 02:11:31 +00:00
|
|
|
PanicAlertFmt("Invalid AlphaTestOp {}", bpmem.alpha_test.logic);
|
2014-12-03 00:20:52 +00:00
|
|
|
return true;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
static inline s32 WrapIndirectCoord(s32 coord, IndTexWrap wrapMode)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
|
|
|
switch (wrapMode)
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexWrap::ITW_OFF:
|
2009-10-12 00:48:24 +00:00
|
|
|
return coord;
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexWrap::ITW_256:
|
2016-01-13 15:57:01 +00:00
|
|
|
return (coord & ((256 << 7) - 1));
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexWrap::ITW_128:
|
2016-01-13 15:57:01 +00:00
|
|
|
return (coord & ((128 << 7) - 1));
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexWrap::ITW_64:
|
2016-01-13 15:57:01 +00:00
|
|
|
return (coord & ((64 << 7) - 1));
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexWrap::ITW_32:
|
2016-01-13 15:57:01 +00:00
|
|
|
return (coord & ((32 << 7) - 1));
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexWrap::ITW_16:
|
2016-01-13 15:57:01 +00:00
|
|
|
return (coord & ((16 << 7) - 1));
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexWrap::ITW_0:
|
2009-10-12 00:48:24 +00:00
|
|
|
return 0;
|
2014-12-03 00:20:52 +00:00
|
|
|
default:
|
2021-02-11 02:11:31 +00:00
|
|
|
PanicAlertFmt("Invalid indirect wrap mode {}", wrapMode);
|
2014-12-03 00:20:52 +00:00
|
|
|
return 0;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2010-03-09 04:38:07 +00:00
|
|
|
void Tev::Indirect(unsigned int stageNum, s32 s, s32 t)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2017-09-03 18:02:57 +00:00
|
|
|
const TevStageIndirect& indirect = bpmem.tevind[stageNum];
|
|
|
|
const u8* indmap = IndirectTex[indirect.bt];
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2010-03-09 04:38:07 +00:00
|
|
|
s32 indcoord[3];
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
// alpha bump select
|
|
|
|
switch (indirect.bs)
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexBumpAlpha::Off:
|
2009-10-12 00:48:24 +00:00
|
|
|
AlphaBump = 0;
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexBumpAlpha::S:
|
2010-12-31 06:45:18 +00:00
|
|
|
AlphaBump = indmap[TextureSampler::ALP_SMP];
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexBumpAlpha::T:
|
2010-12-31 06:45:18 +00:00
|
|
|
AlphaBump = indmap[TextureSampler::BLU_SMP];
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexBumpAlpha::U:
|
2010-12-31 06:45:18 +00:00
|
|
|
AlphaBump = indmap[TextureSampler::GRN_SMP];
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
default:
|
|
|
|
PanicAlertFmt("Invalid alpha bump {}", indirect.bs);
|
|
|
|
return;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
// bias select
|
2021-02-11 02:11:31 +00:00
|
|
|
const s16 biasValue = indirect.fmt == IndTexFormat::ITF_8 ? -128 : 1;
|
2009-10-12 00:48:24 +00:00
|
|
|
s16 bias[3];
|
2021-02-11 02:11:31 +00:00
|
|
|
bias[0] = indirect.bias_s ? biasValue : 0;
|
|
|
|
bias[1] = indirect.bias_t ? biasValue : 0;
|
|
|
|
bias[2] = indirect.bias_u ? biasValue : 0;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
// format
|
2014-03-10 11:30:55 +00:00
|
|
|
switch (indirect.fmt)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexFormat::ITF_8:
|
2010-12-31 06:45:18 +00:00
|
|
|
indcoord[0] = indmap[TextureSampler::ALP_SMP] + bias[0];
|
|
|
|
indcoord[1] = indmap[TextureSampler::BLU_SMP] + bias[1];
|
|
|
|
indcoord[2] = indmap[TextureSampler::GRN_SMP] + bias[2];
|
2009-10-12 00:48:24 +00:00
|
|
|
AlphaBump = AlphaBump & 0xf8;
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexFormat::ITF_5:
|
2021-07-07 23:35:50 +00:00
|
|
|
indcoord[0] = (indmap[TextureSampler::ALP_SMP] >> 3) + bias[0];
|
|
|
|
indcoord[1] = (indmap[TextureSampler::BLU_SMP] >> 3) + bias[1];
|
|
|
|
indcoord[2] = (indmap[TextureSampler::GRN_SMP] >> 3) + bias[2];
|
|
|
|
AlphaBump = AlphaBump << 5;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexFormat::ITF_4:
|
2021-07-07 23:35:50 +00:00
|
|
|
indcoord[0] = (indmap[TextureSampler::ALP_SMP] >> 4) + bias[0];
|
|
|
|
indcoord[1] = (indmap[TextureSampler::BLU_SMP] >> 4) + bias[1];
|
|
|
|
indcoord[2] = (indmap[TextureSampler::GRN_SMP] >> 4) + bias[2];
|
|
|
|
AlphaBump = AlphaBump << 4;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case IndTexFormat::ITF_3:
|
2021-07-07 23:35:50 +00:00
|
|
|
indcoord[0] = (indmap[TextureSampler::ALP_SMP] >> 5) + bias[0];
|
|
|
|
indcoord[1] = (indmap[TextureSampler::BLU_SMP] >> 5) + bias[1];
|
|
|
|
indcoord[2] = (indmap[TextureSampler::GRN_SMP] >> 5) + bias[2];
|
|
|
|
AlphaBump = AlphaBump << 3;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2010-05-26 21:03:42 +00:00
|
|
|
default:
|
2021-02-11 02:11:31 +00:00
|
|
|
PanicAlertFmt("Invalid indirect format {}", indirect.fmt);
|
2010-05-26 21:03:42 +00:00
|
|
|
return;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2013-11-02 10:42:30 +00:00
|
|
|
s32 indtevtrans[2] = {0, 0};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2013-11-02 10:42:30 +00:00
|
|
|
// matrix multiply - results might overflow, but we don't care since we only use the lower 24 bits
|
|
|
|
// of the result.
|
2021-04-11 00:41:06 +00:00
|
|
|
if (indirect.matrix_index != IndMtxIndex::Off)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-04-11 00:41:06 +00:00
|
|
|
const IND_MTX& indmtx = bpmem.indmtx[static_cast<u32>(indirect.matrix_index.Value()) - 1];
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-04-11 00:41:06 +00:00
|
|
|
const int shift = 17 - indmtx.GetScale();
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-04-11 00:41:06 +00:00
|
|
|
switch (indirect.matrix_id)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-04-11 00:41:06 +00:00
|
|
|
case IndMtxId::Indirect:
|
2013-10-10 19:09:00 +00:00
|
|
|
// matrix values are S0.10, output format is S17.7, so divide by 8
|
|
|
|
indtevtrans[0] = (indmtx.col0.ma * indcoord[0] + indmtx.col1.mc * indcoord[1] +
|
|
|
|
indmtx.col2.me * indcoord[2]) >>
|
|
|
|
3;
|
|
|
|
indtevtrans[1] = (indmtx.col0.mb * indcoord[0] + indmtx.col1.md * indcoord[1] +
|
|
|
|
indmtx.col2.mf * indcoord[2]) >>
|
|
|
|
3;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2021-04-11 00:41:06 +00:00
|
|
|
case IndMtxId::S:
|
2013-10-10 19:09:00 +00:00
|
|
|
// s is S17.7, matrix elements are divided by 256, output is S17.7, so divide by 256. - TODO:
|
|
|
|
// Maybe, since s is actually stored as S24, we should divide by 256*64?
|
|
|
|
indtevtrans[0] = s * indcoord[0] / 256;
|
|
|
|
indtevtrans[1] = t * indcoord[0] / 256;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2021-04-11 00:41:06 +00:00
|
|
|
case IndMtxId::T:
|
2013-10-10 19:09:00 +00:00
|
|
|
indtevtrans[0] = s * indcoord[1] / 256;
|
|
|
|
indtevtrans[1] = t * indcoord[1] / 256;
|
2009-10-12 00:48:24 +00:00
|
|
|
break;
|
2010-05-26 21:03:42 +00:00
|
|
|
default:
|
2021-04-11 00:41:06 +00:00
|
|
|
PanicAlertFmt("Invalid indirect matrix ID {}", indirect.matrix_id);
|
2010-05-26 21:03:42 +00:00
|
|
|
return;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2010-03-09 04:38:07 +00:00
|
|
|
indtevtrans[0] = shift >= 0 ? indtevtrans[0] >> shift : indtevtrans[0] << -shift;
|
|
|
|
indtevtrans[1] = shift >= 0 ? indtevtrans[1] >> shift : indtevtrans[1] << -shift;
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2021-04-11 00:41:06 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// If matrix_index is Off (0), matrix_id should be Indirect (0)
|
|
|
|
ASSERT(indirect.matrix_id == IndMtxId::Indirect);
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2010-03-09 04:38:07 +00:00
|
|
|
if (indirect.fb_addprev)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2010-03-09 04:38:07 +00:00
|
|
|
TexCoord.s += (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]);
|
|
|
|
TexCoord.t += (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-09 04:38:07 +00:00
|
|
|
TexCoord.s = (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]);
|
|
|
|
TexCoord.t = (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
void Tev::Draw()
|
|
|
|
{
|
2020-03-23 06:09:41 +00:00
|
|
|
ASSERT(Position[0] >= 0 && Position[0] < s32(EFB_WIDTH));
|
|
|
|
ASSERT(Position[1] >= 0 && Position[1] < s32(EFB_HEIGHT));
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2019-07-11 03:34:50 +00:00
|
|
|
INCSTAT(g_stats.this_frame.tev_pixels_in);
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2016-03-06 10:03:45 +00:00
|
|
|
// initial color values
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[static_cast<TevOutput>(i)].r = PixelShaderManager::constants.colors[i][0];
|
|
|
|
Reg[static_cast<TevOutput>(i)].g = PixelShaderManager::constants.colors[i][1];
|
|
|
|
Reg[static_cast<TevOutput>(i)].b = PixelShaderManager::constants.colors[i][2];
|
|
|
|
Reg[static_cast<TevOutput>(i)].a = PixelShaderManager::constants.colors[i][3];
|
2016-03-06 10:03:45 +00:00
|
|
|
}
|
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
|
|
|
|
{
|
2017-09-03 18:02:57 +00:00
|
|
|
const int stageNum2 = stageNum >> 1;
|
|
|
|
const int stageOdd = stageNum & 1;
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-04-09 01:10:13 +00:00
|
|
|
u32 texcoordSel = bpmem.tevindref.getTexCoord(stageNum);
|
2017-09-03 18:02:57 +00:00
|
|
|
const u32 texmap = bpmem.tevindref.getTexMap(stageNum);
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-04-09 01:10:13 +00:00
|
|
|
// Quirk: when the tex coord is not less than the number of tex gens (i.e. the tex coord does
|
|
|
|
// not exist), then tex coord 0 is used (though sometimes glitchy effects happen on console).
|
|
|
|
// This affects the Mario portrait in Luigi's Mansion, where the developers forgot to set
|
|
|
|
// the number of tex gens to 2 (bug 11462).
|
|
|
|
if (texcoordSel >= bpmem.genMode.numtexgens)
|
|
|
|
texcoordSel = 0;
|
|
|
|
|
2010-03-09 04:38:07 +00:00
|
|
|
const TEXSCALE& texscale = bpmem.texscale[stageNum2];
|
2017-09-03 18:02:57 +00:00
|
|
|
const s32 scaleS = stageOdd ? texscale.ss1 : texscale.ss0;
|
|
|
|
const s32 scaleT = stageOdd ? texscale.ts1 : texscale.ts0;
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2010-03-09 04:38:07 +00:00
|
|
|
TextureSampler::Sample(Uv[texcoordSel].s >> scaleS, Uv[texcoordSel].t >> scaleT,
|
|
|
|
IndirectLod[stageNum], IndirectLinear[stageNum], texmap,
|
|
|
|
IndirectTex[stageNum]);
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2010-12-02 05:38:48 +00:00
|
|
|
#if ALLOW_TEV_DUMPS
|
2015-10-09 18:50:36 +00:00
|
|
|
if (g_ActiveConfig.bDumpTevStages)
|
2014-02-16 20:30:18 +00:00
|
|
|
{
|
|
|
|
u8 stage[4] = {IndirectTex[stageNum][TextureSampler::ALP_SMP],
|
|
|
|
IndirectTex[stageNum][TextureSampler::BLU_SMP],
|
|
|
|
IndirectTex[stageNum][TextureSampler::GRN_SMP], 255};
|
2010-12-02 05:38:48 +00:00
|
|
|
DebugUtil::DrawTempBuffer(stage, INDIRECT + stageNum);
|
2009-12-02 04:17:18 +00:00
|
|
|
}
|
|
|
|
#endif
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
|
|
|
|
{
|
2017-09-03 18:02:57 +00:00
|
|
|
const int stageNum2 = stageNum >> 1;
|
|
|
|
const int stageOdd = stageNum & 1;
|
|
|
|
const TwoTevStageOrders& order = bpmem.tevorders[stageNum2];
|
|
|
|
const TevKSel& kSel = bpmem.tevksel[stageNum2];
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
// stage combiners
|
2017-09-03 18:02:57 +00:00
|
|
|
const TevStageCombiner::ColorCombiner& cc = bpmem.combiners[stageNum].colorC;
|
|
|
|
const TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[stageNum].alphaC;
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-04-09 01:10:13 +00:00
|
|
|
u32 texcoordSel = order.getTexCoord(stageOdd);
|
|
|
|
const u32 texmap = order.getTexMap(stageOdd);
|
|
|
|
|
|
|
|
// Quirk: when the tex coord is not less than the number of tex gens (i.e. the tex coord does
|
|
|
|
// not exist), then tex coord 0 is used (though sometimes glitchy effects happen on console).
|
|
|
|
if (texcoordSel >= bpmem.genMode.numtexgens)
|
|
|
|
texcoordSel = 0;
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2010-03-09 04:38:07 +00:00
|
|
|
Indirect(stageNum, Uv[texcoordSel].s, Uv[texcoordSel].t);
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
// sample texture
|
|
|
|
if (order.getEnable(stageOdd))
|
|
|
|
{
|
2010-12-31 06:45:18 +00:00
|
|
|
// RGBA
|
|
|
|
u8 texel[4];
|
2013-04-14 03:54:02 +00:00
|
|
|
|
2021-04-09 01:10:13 +00:00
|
|
|
if (bpmem.genMode.numtexgens > 0)
|
|
|
|
{
|
|
|
|
TextureSampler::Sample(TexCoord.s, TexCoord.t, TextureLod[stageNum],
|
|
|
|
TextureLinear[stageNum], texmap, texel);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// It seems like the result is always black when no tex coords are enabled, but further
|
|
|
|
// hardware testing is needed.
|
|
|
|
std::memset(texel, 0, 4);
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2010-12-02 05:38:48 +00:00
|
|
|
#if ALLOW_TEV_DUMPS
|
2015-10-09 18:50:36 +00:00
|
|
|
if (g_ActiveConfig.bDumpTevTextureFetches)
|
2010-12-02 05:38:48 +00:00
|
|
|
DebugUtil::DrawTempBuffer(texel, DIRECT_TFETCH + stageNum);
|
|
|
|
#endif
|
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
int swaptable = ac.tswap * 2;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-12-22 00:43:38 +00:00
|
|
|
TexColor.r = texel[bpmem.tevksel[swaptable].swap1];
|
|
|
|
TexColor.g = texel[bpmem.tevksel[swaptable].swap2];
|
2009-10-12 00:48:24 +00:00
|
|
|
swaptable++;
|
2021-12-22 00:43:38 +00:00
|
|
|
TexColor.b = texel[bpmem.tevksel[swaptable].swap1];
|
|
|
|
TexColor.a = texel[bpmem.tevksel[swaptable].swap2];
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
// set konst for this stage
|
2021-12-22 00:43:38 +00:00
|
|
|
const auto kc = kSel.getKC(stageOdd);
|
|
|
|
const auto ka = kSel.getKA(stageOdd);
|
|
|
|
StageKonst.r = m_KonstLUT[kc].r;
|
|
|
|
StageKonst.g = m_KonstLUT[kc].g;
|
|
|
|
StageKonst.b = m_KonstLUT[kc].b;
|
|
|
|
StageKonst.a = m_KonstLUT[ka].a;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
// set color
|
2009-10-28 03:01:07 +00:00
|
|
|
SetRasColor(order.getColorChan(stageOdd), ac.rswap * 2);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
// combine inputs
|
2014-03-24 13:42:04 +00:00
|
|
|
InputRegType inputs[4];
|
2021-12-22 00:43:38 +00:00
|
|
|
inputs[BLU_C].a = m_ColorInputLUT[cc.a].b;
|
|
|
|
inputs[BLU_C].b = m_ColorInputLUT[cc.b].b;
|
|
|
|
inputs[BLU_C].c = m_ColorInputLUT[cc.c].b;
|
|
|
|
inputs[BLU_C].d = m_ColorInputLUT[cc.d].b;
|
|
|
|
inputs[GRN_C].a = m_ColorInputLUT[cc.a].g;
|
|
|
|
inputs[GRN_C].b = m_ColorInputLUT[cc.b].g;
|
|
|
|
inputs[GRN_C].c = m_ColorInputLUT[cc.c].g;
|
|
|
|
inputs[GRN_C].d = m_ColorInputLUT[cc.d].g;
|
|
|
|
inputs[RED_C].a = m_ColorInputLUT[cc.a].r;
|
|
|
|
inputs[RED_C].b = m_ColorInputLUT[cc.b].r;
|
|
|
|
inputs[RED_C].c = m_ColorInputLUT[cc.c].r;
|
|
|
|
inputs[RED_C].d = m_ColorInputLUT[cc.d].r;
|
|
|
|
inputs[ALP_C].a = m_AlphaInputLUT[ac.a].a;
|
|
|
|
inputs[ALP_C].b = m_AlphaInputLUT[ac.b].a;
|
|
|
|
inputs[ALP_C].c = m_AlphaInputLUT[ac.c].a;
|
|
|
|
inputs[ALP_C].d = m_AlphaInputLUT[ac.d].a;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
if (cc.bias != TevBias::Compare)
|
2014-03-24 13:42:04 +00:00
|
|
|
DrawColorRegular(cc, inputs);
|
2009-10-12 00:48:24 +00:00
|
|
|
else
|
2014-03-24 13:42:04 +00:00
|
|
|
DrawColorCompare(cc, inputs);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
if (cc.clamp)
|
|
|
|
{
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[cc.dest].r = Clamp255(Reg[cc.dest].r);
|
|
|
|
Reg[cc.dest].g = Clamp255(Reg[cc.dest].g);
|
|
|
|
Reg[cc.dest].b = Clamp255(Reg[cc.dest].b);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2009-10-28 03:01:07 +00:00
|
|
|
else
|
|
|
|
{
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[cc.dest].r = Clamp1024(Reg[cc.dest].r);
|
|
|
|
Reg[cc.dest].g = Clamp1024(Reg[cc.dest].g);
|
|
|
|
Reg[cc.dest].b = Clamp1024(Reg[cc.dest].b);
|
2009-10-28 03:01:07 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
if (ac.bias != TevBias::Compare)
|
2014-03-24 13:42:04 +00:00
|
|
|
DrawAlphaRegular(ac, inputs);
|
2009-10-12 00:48:24 +00:00
|
|
|
else
|
2014-03-24 13:42:04 +00:00
|
|
|
DrawAlphaCompare(ac, inputs);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
if (ac.clamp)
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[ac.dest].a = Clamp255(Reg[ac.dest].a);
|
2009-10-28 03:01:07 +00:00
|
|
|
else
|
2021-12-22 02:03:47 +00:00
|
|
|
Reg[ac.dest].a = Clamp1024(Reg[ac.dest].a);
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2010-12-02 05:38:48 +00:00
|
|
|
#if ALLOW_TEV_DUMPS
|
2015-10-09 18:50:36 +00:00
|
|
|
if (g_ActiveConfig.bDumpTevStages)
|
2009-10-28 03:01:07 +00:00
|
|
|
{
|
2021-12-22 02:03:47 +00:00
|
|
|
u8 stage[4] = {(u8)Reg[cc.dest].r, (u8)Reg[cc.dest].g, (u8)Reg[cc.dest].b,
|
|
|
|
(u8)Reg[ac.dest].a};
|
2010-12-02 05:38:48 +00:00
|
|
|
DebugUtil::DrawTempBuffer(stage, DIRECT + stageNum);
|
2009-10-28 03:01:07 +00:00
|
|
|
}
|
|
|
|
#endif
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2013-04-07 14:50:58 +00:00
|
|
|
// convert to 8 bits per component
|
|
|
|
// the results of the last tev stage are put onto the screen,
|
|
|
|
// regardless of the used destination register - TODO: Verify!
|
2021-12-22 02:03:47 +00:00
|
|
|
const auto& color_index = bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest;
|
|
|
|
const auto& alpha_index = bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest;
|
|
|
|
u8 output[4] = {(u8)Reg[alpha_index].a, (u8)Reg[color_index].b, (u8)Reg[color_index].g,
|
|
|
|
(u8)Reg[color_index].r};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2013-01-31 21:29:29 +00:00
|
|
|
if (!TevAlphaTest(output[ALP_C]))
|
2009-10-12 00:48:24 +00:00
|
|
|
return;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2022-01-25 06:48:43 +00:00
|
|
|
// Hardware testing indicates that an alpha of 1 can pass an alpha test,
|
|
|
|
// but doesn't do anything in blending
|
|
|
|
// This situation is important for Mario Kart Wii's menus (they will render incorrectly if the
|
|
|
|
// alpha test for the FMV in the background fails, since they depend on depth for drawing a yellow
|
|
|
|
// border) and Fortune Street's gameplay (where a rectangle with an alpha value of 1 is drawn over
|
|
|
|
// the center of the screen several times, but those rectangles shouldn't be visible).
|
|
|
|
// Blending seems to result in no changes to the output with an alpha of 1, even if the input
|
|
|
|
// color is white.
|
|
|
|
// TODO: Investigate this further: we might be handling blending incorrectly in general (though
|
|
|
|
// there might not be any good way of changing blending behavior)
|
|
|
|
if (output[ALP_C] == 1)
|
|
|
|
output[ALP_C] = 0;
|
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
// z texture
|
2021-02-11 02:11:31 +00:00
|
|
|
if (bpmem.ztex2.op != ZTexOp::Disabled)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2015-09-17 16:19:47 +00:00
|
|
|
u32 ztex = bpmem.ztex1.bias;
|
|
|
|
switch (bpmem.ztex2.type)
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case ZTexFormat::U8:
|
2015-09-17 16:19:47 +00:00
|
|
|
ztex += TexColor[ALP_C];
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case ZTexFormat::U16:
|
2015-09-17 16:19:47 +00:00
|
|
|
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case ZTexFormat::U24:
|
2015-09-17 16:19:47 +00:00
|
|
|
ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C];
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
default:
|
|
|
|
PanicAlertFmt("Invalid ztex format {}", bpmem.ztex2.type);
|
2009-10-12 00:48:24 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
if (bpmem.ztex2.op == ZTexOp::Add)
|
2015-09-17 16:19:47 +00:00
|
|
|
ztex += Position[2];
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
Position[2] = ztex & 0x00ffffff;
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
// fog
|
2021-02-11 02:11:31 +00:00
|
|
|
if (bpmem.fog.c_proj_fsel.fsel != FogType::Off)
|
2015-09-17 16:19:47 +00:00
|
|
|
{
|
|
|
|
float ze;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
if (bpmem.fog.c_proj_fsel.proj == FogProjection::Perspective)
|
2015-09-17 16:19:47 +00:00
|
|
|
{
|
|
|
|
// perspective
|
|
|
|
// ze = A/(B - (Zs >> B_SHF))
|
2017-09-03 18:02:57 +00:00
|
|
|
const s32 denom = bpmem.fog.b_magnitude - (Position[2] >> bpmem.fog.b_shift);
|
2015-09-17 16:19:47 +00:00
|
|
|
// in addition downscale magnitude and zs to 0.24 bits
|
2018-02-01 07:36:30 +00:00
|
|
|
ze = (bpmem.fog.GetA() * 16777215.0f) / static_cast<float>(denom);
|
2015-09-17 16:19:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// orthographic
|
|
|
|
// ze = a*Zs
|
|
|
|
// in addition downscale zs to 0.24 bits
|
2018-02-01 07:36:30 +00:00
|
|
|
ze = bpmem.fog.GetA() * (static_cast<float>(Position[2]) / 16777215.0f);
|
2015-09-17 16:19:47 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
if (bpmem.fogRange.Base.Enabled)
|
|
|
|
{
|
|
|
|
// TODO: This is untested and should definitely be checked against real hw.
|
|
|
|
// - No idea if offset is really normalized against the viewport width or against the
|
|
|
|
// projection matrix or yet something else
|
|
|
|
// - scaling of the "k" coefficient isn't clear either.
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
// First, calculate the offset from the viewport center (normalized to 0..1)
|
2017-09-03 18:02:57 +00:00
|
|
|
const float offset =
|
|
|
|
(Position[0] - (static_cast<s32>(bpmem.fogRange.Base.Center.Value()) - 342)) /
|
|
|
|
static_cast<float>(xfmem.viewport.wd);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
// Based on that, choose the index such that points which are far away from the z-axis use the
|
|
|
|
// 10th "k" value and such that central points use the first value.
|
|
|
|
float floatindex = 9.f - std::abs(offset) * 9.f;
|
2017-12-25 23:38:44 +00:00
|
|
|
floatindex = std::clamp(floatindex, 0.f, 9.f); // TODO: This shouldn't be necessary!
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
// Get the two closest integer indices, look up the corresponding samples
|
2018-09-19 03:30:31 +00:00
|
|
|
const int indexlower = (int)floatindex;
|
2017-09-03 18:02:57 +00:00
|
|
|
const int indexupper = indexlower + 1;
|
2015-09-17 16:19:47 +00:00
|
|
|
// Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog
|
|
|
|
// is too strong without the factor)
|
2017-09-03 18:02:57 +00:00
|
|
|
const float klower = bpmem.fogRange.K[indexlower / 2].GetValue(indexlower % 2) * 4.f;
|
|
|
|
const float kupper = bpmem.fogRange.K[indexupper / 2].GetValue(indexupper % 2) * 4.f;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
// linearly interpolate the samples and multiple ze by the resulting adjustment factor
|
2017-09-03 18:02:57 +00:00
|
|
|
const float factor = indexupper - floatindex;
|
|
|
|
const float k = klower * factor + kupper * (1.f - factor);
|
|
|
|
const float x_adjust = sqrt(offset * offset + k * k) / k;
|
2015-09-17 16:19:47 +00:00
|
|
|
ze *= x_adjust; // NOTE: This is basically dividing by a cosine (hidden behind
|
|
|
|
// GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2018-02-01 07:36:30 +00:00
|
|
|
ze -= bpmem.fog.GetC();
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
// clamp 0 to 1
|
2017-12-25 23:38:44 +00:00
|
|
|
float fog = std::clamp(ze, 0.f, 1.f);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
switch (bpmem.fog.c_proj_fsel.fsel)
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case FogType::Exp:
|
2015-09-17 16:19:47 +00:00
|
|
|
fog = 1.0f - pow(2.0f, -8.0f * fog);
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case FogType::ExpSq:
|
2015-09-17 16:19:47 +00:00
|
|
|
fog = 1.0f - pow(2.0f, -8.0f * fog * fog);
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case FogType::BackwardsExp:
|
2015-09-17 16:19:47 +00:00
|
|
|
fog = 1.0f - fog;
|
|
|
|
fog = pow(2.0f, -8.0f * fog);
|
|
|
|
break;
|
2021-02-11 02:11:31 +00:00
|
|
|
case FogType::BackwardsExpSq:
|
2015-09-17 16:19:47 +00:00
|
|
|
fog = 1.0f - fog;
|
|
|
|
fog = pow(2.0f, -8.0f * fog * fog);
|
|
|
|
break;
|
2021-10-14 06:54:06 +00:00
|
|
|
default:
|
|
|
|
break;
|
2010-04-14 03:27:45 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
// lerp from output to fog color
|
2017-09-03 18:02:57 +00:00
|
|
|
const u32 fogInt = (u32)(fog * 256);
|
|
|
|
const u32 invFog = 256 - fogInt;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
output[RED_C] = (output[RED_C] * invFog + fogInt * bpmem.fog.color.r) >> 8;
|
|
|
|
output[GRN_C] = (output[GRN_C] * invFog + fogInt * bpmem.fog.color.g) >> 8;
|
|
|
|
output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8;
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2022-06-12 02:03:09 +00:00
|
|
|
if (bpmem.GetEmulatedZ() == EmulatedZ::Late)
|
2015-09-17 16:19:47 +00:00
|
|
|
{
|
|
|
|
// TODO: Check against hw if these values get incremented even if depth testing is disabled
|
|
|
|
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
|
|
|
|
return;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-09-17 16:19:47 +00:00
|
|
|
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT);
|
2010-04-14 03:27:45 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-05-29 03:30:22 +00:00
|
|
|
// The GC/Wii GPU rasterizes in 2x2 pixel groups, so bounding box values will be rounded to the
|
|
|
|
// extents of these groups, rather than the exact pixel.
|
2021-06-09 11:42:21 +00:00
|
|
|
BBoxManager::Update(static_cast<u16>(Position[0] & ~1), static_cast<u16>(Position[0] | 1),
|
2021-05-29 03:30:22 +00:00
|
|
|
static_cast<u16>(Position[1] & ~1), static_cast<u16>(Position[1] | 1));
|
2013-03-01 00:07:34 +00:00
|
|
|
|
2010-12-02 05:38:48 +00:00
|
|
|
#if ALLOW_TEV_DUMPS
|
2015-10-09 18:50:36 +00:00
|
|
|
if (g_ActiveConfig.bDumpTevStages)
|
2010-12-02 05:38:48 +00:00
|
|
|
{
|
|
|
|
for (u32 i = 0; i < bpmem.genMode.numindstages; ++i)
|
|
|
|
DebugUtil::CopyTempBuffer(Position[0], Position[1], INDIRECT, i, "Indirect");
|
|
|
|
for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i)
|
|
|
|
DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT, i, "Stage");
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-10-09 18:50:36 +00:00
|
|
|
if (g_ActiveConfig.bDumpTevTextureFetches)
|
2010-12-02 05:38:48 +00:00
|
|
|
{
|
|
|
|
for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i)
|
|
|
|
{
|
|
|
|
TwoTevStageOrders& order = bpmem.tevorders[i >> 1];
|
|
|
|
if (order.getEnable(i & 1))
|
|
|
|
DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT_TFETCH, i, "TFetch");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-07-11 03:34:50 +00:00
|
|
|
INCSTAT(g_stats.this_frame.tev_pixels_out);
|
2014-03-29 02:22:15 +00:00
|
|
|
EfbInterface::IncPerfCounterQuadCount(PQ_BLEND_INPUT);
|
2012-06-17 17:49:48 +00:00
|
|
|
|
2009-10-12 00:48:24 +00:00
|
|
|
EfbInterface::BlendTev(Position[0], Position[1], output);
|
|
|
|
}
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2021-12-26 21:24:47 +00:00
|
|
|
void Tev::SetKonstColors()
|
2009-10-12 00:48:24 +00:00
|
|
|
{
|
2021-12-26 21:24:47 +00:00
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
KonstantColors[i].r = PixelShaderManager::constants.kcolors[i][0];
|
|
|
|
KonstantColors[i].g = PixelShaderManager::constants.kcolors[i][1];
|
|
|
|
KonstantColors[i].b = PixelShaderManager::constants.kcolors[i][2];
|
|
|
|
KonstantColors[i].a = PixelShaderManager::constants.kcolors[i][3];
|
|
|
|
}
|
2009-10-28 03:01:07 +00:00
|
|
|
}
|