GPU: Only load the relevant color components upon writes to the tev color registers.

The other two components need not be valid upon write, hence loading them results in glitches.

Fixes issue 6783.
This commit is contained in:
Tony Wasserka 2014-09-17 18:46:23 +02:00
parent 6d4fd54683
commit 1d23c2ca8b
6 changed files with 121 additions and 65 deletions

View File

@ -63,7 +63,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 31;
static const u32 STATE_VERSION = 32;
enum
{

View File

@ -145,10 +145,10 @@ void SWBPWritten(int address, int newvalue)
}
break;
case BPMEM_TEV_REGISTER_L: // Reg 1
case BPMEM_TEV_REGISTER_L+2: // Reg 2
case BPMEM_TEV_REGISTER_L+4: // Reg 3
case BPMEM_TEV_REGISTER_L+6: // Reg 4
case BPMEM_TEV_COLOR_RA:
case BPMEM_TEV_COLOR_RA + 2:
case BPMEM_TEV_COLOR_RA + 4:
case BPMEM_TEV_COLOR_RA + 6:
{
int regNum = (address >> 1 ) & 0x3;
TevReg& reg = bpmem.tevregs[regNum];
@ -160,10 +160,10 @@ void SWBPWritten(int address, int newvalue)
break;
}
case BPMEM_TEV_REGISTER_H: // Reg 1
case BPMEM_TEV_REGISTER_H+2: // Reg 2
case BPMEM_TEV_REGISTER_H+4: // Reg 3
case BPMEM_TEV_REGISTER_H+6: // Reg 4
case BPMEM_TEV_COLOR_BG:
case BPMEM_TEV_COLOR_BG + 2:
case BPMEM_TEV_COLOR_BG + 4:
case BPMEM_TEV_COLOR_BG + 6:
{
int regNum = (address >> 1 ) & 0x3;
TevReg& reg = bpmem.tevregs[regNum];

View File

@ -80,8 +80,8 @@
#define BPMEM_TX_SETTLUT_4 0xB8 // 0xB8 + 4
#define BPMEM_TEV_COLOR_ENV 0xC0 // 0xC0 + (2 * 16)
#define BPMEM_TEV_ALPHA_ENV 0xC1 // 0xC1 + (2 * 16)
#define BPMEM_TEV_REGISTER_L 0xE0 // 0xE0 + (2 * 4)
#define BPMEM_TEV_REGISTER_H 0xE1 // 0xE1 + (2 * 4)
#define BPMEM_TEV_COLOR_RA 0xE0 // 0xE0 + (2 * 4)
#define BPMEM_TEV_COLOR_BG 0xE1 // 0xE1 + (2 * 4)
#define BPMEM_FOGRANGE 0xE8 // 0xE8 + 6
#define BPMEM_FOGPARAM0 0xEE
#define BPMEM_FOGBMAGNITUDE 0xEF
@ -853,6 +853,8 @@ union TevReg
BitField< 0, 32,u64> low;
BitField<32, 32,u64> high;
// TODO: Check if Konst uses all 11 bits or just 8
// Low register
BitField< 0,11,s64> red;

View File

@ -480,6 +480,55 @@ static void BPWritten(const BPCmd& bp)
}
}
return;
// ---------------------------------------------------
// Set the TEV Color
// ---------------------------------------------------
//
// NOTE: Each of these registers actually maps to two variables internally.
// There's a bit that specifies which one is currently written to.
//
// NOTE: Some games write only to the RA register (or only to the BG register).
// We may not assume that the unwritten register holds a valid value, hence
// both component pairs need to be loaded individually.
case BPMEM_TEV_COLOR_RA:
case BPMEM_TEV_COLOR_RA + 2:
case BPMEM_TEV_COLOR_RA + 4:
case BPMEM_TEV_COLOR_RA + 6:
{
int num = (bp.address >> 1) & 0x3;
if (bpmem.tevregs[num].type_ra)
{
PixelShaderManager::SetTevKonstColor(num, 0, (s32)bpmem.tevregs[num].red);
PixelShaderManager::SetTevKonstColor(num, 3, (s32)bpmem.tevregs[num].alpha);
}
else
{
PixelShaderManager::SetTevColor(num, 0, (s32)bpmem.tevregs[num].red);
PixelShaderManager::SetTevColor(num, 3, (s32)bpmem.tevregs[num].alpha);
}
return;
}
case BPMEM_TEV_COLOR_BG:
case BPMEM_TEV_COLOR_BG + 2:
case BPMEM_TEV_COLOR_BG + 4:
case BPMEM_TEV_COLOR_BG + 6:
{
int num = (bp.address >> 1) & 0x3;
if (bpmem.tevregs[num].type_bg)
{
PixelShaderManager::SetTevKonstColor(num, 1, (s32)bpmem.tevregs[num].green);
PixelShaderManager::SetTevKonstColor(num, 2, (s32)bpmem.tevregs[num].blue);
}
else
{
PixelShaderManager::SetTevColor(num, 1, (s32)bpmem.tevregs[num].green);
PixelShaderManager::SetTevColor(num, 2, (s32)bpmem.tevregs[num].blue);
}
return;
}
default:
break;
}
@ -548,29 +597,6 @@ static void BPWritten(const BPCmd& bp)
case BPMEM_TX_SETTLUT_4:
return;
// ---------------------------------------------------
// Set the TEV Color
// ---------------------------------------------------
case BPMEM_TEV_REGISTER_L: // Reg 1
case BPMEM_TEV_REGISTER_H:
case BPMEM_TEV_REGISTER_L+2: // Reg 2
case BPMEM_TEV_REGISTER_H+2:
case BPMEM_TEV_REGISTER_L+4: // Reg 3
case BPMEM_TEV_REGISTER_H+4:
case BPMEM_TEV_REGISTER_L+6: // Reg 4
case BPMEM_TEV_REGISTER_H+6:
// some games only send the _L part, so always update
// there actually are 2 register behind each of these
// addresses, selected by the type bit.
{
// don't compare with changes!
int num = (bp.address >> 1) & 0x3;
if ((bp.address & 1) == 0)
PixelShaderManager::SetColorChanged(static_cast<int>(bpmem.tevregs[num].type_ra), num);
else
PixelShaderManager::SetColorChanged(static_cast<int>(bpmem.tevregs[num].type_bg), num);
}
return;
default:
break;
}
@ -1213,19 +1239,19 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
break;
}
case BPMEM_TEV_REGISTER_L: // 0xE0
case BPMEM_TEV_REGISTER_L+2:
case BPMEM_TEV_REGISTER_L+4:
case BPMEM_TEV_REGISTER_L+6:
SetRegName(BPMEM_TEV_REGISTER_L);
case BPMEM_TEV_COLOR_RA: // 0xE0
case BPMEM_TEV_COLOR_RA + 2: // 0xE2
case BPMEM_TEV_COLOR_RA + 4: // 0xE4
case BPMEM_TEV_COLOR_RA + 6: // 0xE6
SetRegName(BPMEM_TEV_COLOR_RA);
// TODO: Description
break;
case BPMEM_TEV_REGISTER_H: // 0xE1
case BPMEM_TEV_REGISTER_H+2:
case BPMEM_TEV_REGISTER_H+4:
case BPMEM_TEV_REGISTER_H+6:
SetRegName(BPMEM_TEV_REGISTER_H);
case BPMEM_TEV_COLOR_BG: // 0xE1
case BPMEM_TEV_COLOR_BG + 2: // 0xE3
case BPMEM_TEV_COLOR_BG + 4: // 0xE5
case BPMEM_TEV_COLOR_BG + 6: // 0xE7
SetRegName(BPMEM_TEV_COLOR_BG);
// TODO: Description
break;

View File

@ -12,8 +12,11 @@
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
static bool s_bFogRangeAdjustChanged;
static bool s_bViewPortChanged;
bool PixelShaderManager::s_bFogRangeAdjustChanged;
bool PixelShaderManager::s_bViewPortChanged;
std::array<int4,4> PixelShaderManager::s_tev_color;
std::array<int4,4> PixelShaderManager::s_tev_konst_color;
PixelShaderConstants PixelShaderManager::constants;
bool PixelShaderManager::dirty;
@ -21,6 +24,9 @@ bool PixelShaderManager::dirty;
void PixelShaderManager::Init()
{
memset(&constants, 0, sizeof(constants));
memset(s_tev_color.data(), 0, sizeof(s_tev_color));
memset(s_tev_konst_color.data(), 0, sizeof(s_tev_konst_color));
Dirty();
}
@ -29,14 +35,15 @@ void PixelShaderManager::Dirty()
s_bFogRangeAdjustChanged = true;
s_bViewPortChanged = true;
SetColorChanged(0, 0);
SetColorChanged(0, 1);
SetColorChanged(0, 2);
SetColorChanged(0, 3);
SetColorChanged(1, 0);
SetColorChanged(1, 1);
SetColorChanged(1, 2);
SetColorChanged(1, 3);
for (unsigned index = 0; index < s_tev_color.size(); ++index)
{
for (int comp = 0; comp < 4; ++comp)
{
SetTevColor(index, comp, s_tev_color[index][comp]);
SetTevKonstColor(index, comp, s_tev_konst_color[index][comp]);
}
}
SetAlpha();
SetDestAlpha();
SetZTextureBias();
@ -107,16 +114,22 @@ void PixelShaderManager::SetConstants()
}
}
void PixelShaderManager::SetColorChanged(int type, int num)
void PixelShaderManager::SetTevColor(int index, int component, s32 value)
{
int4* c = type ? constants.kcolors : constants.colors;
c[num][0] = static_cast<s32>(bpmem.tevregs[num].red);
c[num][3] = static_cast<s32>(bpmem.tevregs[num].alpha);
c[num][2] = static_cast<s32>(bpmem.tevregs[num].blue);
c[num][1] = static_cast<s32>(bpmem.tevregs[num].green);
auto& c = constants.colors[index];
c[component] = s_tev_color[index][component] = value;
dirty = true;
PRIM_LOG("pixel %scolor%d: %d %d %d %d\n", type?"k":"", num, c[num][0], c[num][1], c[num][2], c[num][3]);
PRIM_LOG("tev color%d: %d %d %d %d\n", index, c[0], c[1], c[2], c[3]);
}
void PixelShaderManager::SetTevKonstColor(int index, int component, s32 value)
{
auto& c = constants.kcolors[index];
c[component] = s_tev_konst_color[index][component] = value;
dirty = true;
PRIM_LOG("tev konst color%d: %d %d %d %d\n", index, c[0], c[1], c[2], c[3]);
}
void PixelShaderManager::SetAlpha()
@ -265,11 +278,13 @@ void PixelShaderManager::SetFogRangeAdjustChanged()
void PixelShaderManager::DoState(PointerWrap &p)
{
p.Do(constants);
p.Do(dirty);
p.DoArray(s_tev_color);
p.DoArray(s_tev_konst_color);
if (p.GetMode() == PointerWrap::MODE_READ)
{
// Reload current state from global GPU state
// NOTE: This requires that all GPU memory has been loaded already.
Dirty();
}
}

View File

@ -4,6 +4,8 @@
#pragma once
#include <array>
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/ConstantManager.h"
#include "VideoCommon/PixelShaderGen.h"
@ -24,8 +26,11 @@ public:
static void SetConstants(); // sets pixel shader constants
// constant management, should be called after memory is committed
static void SetColorChanged(int type, int index);
// constant management
// Some of these functions grab the constant values from global state,
// so make sure to call them after memory is committed
static void SetTevColor(int index, int component, s32 value);
static void SetTevKonstColor(int index, int component, s32 value);
static void SetAlpha();
static void SetDestAlpha();
static void SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt);
@ -42,4 +47,12 @@ public:
static PixelShaderConstants constants;
static bool dirty;
static bool s_bFogRangeAdjustChanged;
static bool s_bViewPortChanged;
// These colors aren't available from global BP state,
// hence we keep a copy of them around.
static std::array<int4,4> s_tev_color;
static std::array<int4,4> s_tev_konst_color;
};