285 changes: 45 additions & 240 deletions Source/Core/VideoCommon/VertexShaderManager.cpp

Large diffs are not rendered by default.

27 changes: 3 additions & 24 deletions Source/Core/VideoCommon/VertexShaderManager.h
Expand Up @@ -15,28 +15,18 @@

class PointerWrap;
struct PortableVertexDeclaration;
class XFStateManager;

// The non-API dependent parts.
class alignas(16) VertexShaderManager
{
public:
void Init();
void Dirty();
void DoState(PointerWrap& p);

// constant management
void SetProjectionMatrix();
void SetConstants(const std::vector<std::string>& textures);

void InvalidateXFRange(int start, int end);
void SetTexMatrixChangedA(u32 value);
void SetTexMatrixChangedB(u32 value);
void SetViewportChanged();
void SetProjectionChanged();
void SetMaterialColorChanged(int index);

void SetTexMatrixInfoChanged(int index);
void SetLightingConfigChanged();
void SetProjectionMatrix(XFStateManager& xf_state_manager);
void SetConstants(const std::vector<std::string>& textures, XFStateManager& xf_state_manager);

// data: 3 floats representing the X, Y and Z vertex model coordinates and the posmatrix index.
// out: 4 floats which will be initialized with the corresponding clip space coordinates
Expand Down Expand Up @@ -92,18 +82,7 @@ class alignas(16) VertexShaderManager
alignas(16) std::array<float, 16> m_projection_matrix;

// track changes
std::array<bool, 2> m_tex_matrices_changed{};
bool m_pos_normal_matrix_changed = false;
bool m_projection_changed = false;
bool m_viewport_changed = false;
bool m_tex_mtx_info_changed = false;
bool m_lighting_config_changed = false;
bool m_projection_graphics_mod_change = false;
BitSet32 m_materials_changed;
std::array<int, 2> m_minmax_transform_matrices_changed{};
std::array<int, 2> m_minmax_normal_matrices_changed{};
std::array<int, 2> m_minmax_post_transform_matrices_changed{};
std::array<int, 2> m_minmax_lights_changed{};

Common::Matrix44 m_viewport_correction{};

Expand Down
2 changes: 2 additions & 0 deletions Source/Core/VideoCommon/VideoBackendBase.cpp
Expand Up @@ -66,6 +66,7 @@
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/VideoState.h"
#include "VideoCommon/Widescreen.h"
#include "VideoCommon/XFStateManager.h"

VideoBackendBase* g_video_backend = nullptr;

Expand Down Expand Up @@ -385,6 +386,7 @@ bool VideoBackendBase::InitializeShared(std::unique_ptr<AbstractGfx> gfx,
system.GetVertexShaderManager().Init();
system.GetGeometryShaderManager().Init();
system.GetPixelShaderManager().Init();
system.GetXFStateManager().Init();
TMEM::Init();

g_Config.VerifyValidity();
Expand Down
4 changes: 4 additions & 0 deletions Source/Core/VideoCommon/VideoState.cpp
Expand Up @@ -27,6 +27,7 @@
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/Widescreen.h"
#include "VideoCommon/XFMemory.h"
#include "VideoCommon/XFStateManager.h"

void VideoCommon_DoState(PointerWrap& p)
{
Expand Down Expand Up @@ -105,6 +106,9 @@ void VideoCommon_DoState(PointerWrap& p)
g_widescreen->DoState(p);
p.DoMarker("Widescreen");

system.GetXFStateManager().DoState(p);
p.DoMarker("XFStateManager");

// Refresh state.
if (p.IsReadMode())
{
Expand Down
279 changes: 279 additions & 0 deletions Source/Core/VideoCommon/XFStateManager.cpp
@@ -0,0 +1,279 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "VideoCommon/XFStateManager.h"

#include "Common/ChunkFile.h"

#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/XFMemory.h"

void XFStateManager::Init()
{
// Initialize state tracking variables
ResetTexMatrixAChange();
ResetTexMatrixBChange();
ResetPosNormalChange();
ResetProjection();
ResetViewportChange();
ResetTexMatrixInfoChange();
ResetLightingConfigChange();
ResetLightsChanged();
ResetMaterialChanges();
ResetPerVertexTransformMatrixChanges();
ResetPerVertexNormalMatrixChanges();
ResetPostTransformMatrixChanges();

std::memset(static_cast<void*>(&xfmem), 0, sizeof(xfmem));
}

void XFStateManager::DoState(PointerWrap& p)
{
p.DoArray(m_minmax_transform_matrices_changed);
p.DoArray(m_minmax_normal_matrices_changed);
p.DoArray(m_minmax_post_transform_matrices_changed);
p.DoArray(m_minmax_lights_changed);

p.Do(m_materials_changed);
p.DoArray(m_tex_matrices_changed);
p.Do(m_pos_normal_matrix_changed);
p.Do(m_projection_changed);
p.Do(m_viewport_changed);
p.Do(m_tex_mtx_info_changed);
p.Do(m_lighting_config_changed);

if (p.IsReadMode())
{
// This is called after a savestate is loaded.
// Any constants that can changed based on settings should be re-calculated
m_projection_changed = true;
}
}

void XFStateManager::InvalidateXFRange(int start, int end)
{
if (((u32)start >= (u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4 + 12) ||
((u32)start >=
XFMEM_NORMALMATRICES + ((u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx & 31) * 3 &&
(u32)start < XFMEM_NORMALMATRICES +
((u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx & 31) * 3 + 9))
{
m_pos_normal_matrix_changed = true;
}

if (((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex0MtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_a.Tex0MtxIdx * 4 + 12) ||
((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex1MtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_a.Tex1MtxIdx * 4 + 12) ||
((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex2MtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_a.Tex2MtxIdx * 4 + 12) ||
((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex3MtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_a.Tex3MtxIdx * 4 + 12))
{
m_tex_matrices_changed[0] = true;
}

if (((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex4MtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_b.Tex4MtxIdx * 4 + 12) ||
((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex5MtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_b.Tex5MtxIdx * 4 + 12) ||
((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex6MtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_b.Tex6MtxIdx * 4 + 12) ||
((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex7MtxIdx * 4 &&
(u32)start < (u32)g_main_cp_state.matrix_index_b.Tex7MtxIdx * 4 + 12))
{
m_tex_matrices_changed[1] = true;
}

if (start < XFMEM_POSMATRICES_END)
{
if (m_minmax_transform_matrices_changed[0] == -1)
{
m_minmax_transform_matrices_changed[0] = start;
m_minmax_transform_matrices_changed[1] =
end > XFMEM_POSMATRICES_END ? XFMEM_POSMATRICES_END : end;
}
else
{
if (m_minmax_transform_matrices_changed[0] > start)
m_minmax_transform_matrices_changed[0] = start;

if (m_minmax_transform_matrices_changed[1] < end)
m_minmax_transform_matrices_changed[1] =
end > XFMEM_POSMATRICES_END ? XFMEM_POSMATRICES_END : end;
}
}

if (start < XFMEM_NORMALMATRICES_END && end > XFMEM_NORMALMATRICES)
{
int _start = start < XFMEM_NORMALMATRICES ? 0 : start - XFMEM_NORMALMATRICES;
int _end = end < XFMEM_NORMALMATRICES_END ? end - XFMEM_NORMALMATRICES :
XFMEM_NORMALMATRICES_END - XFMEM_NORMALMATRICES;

if (m_minmax_normal_matrices_changed[0] == -1)
{
m_minmax_normal_matrices_changed[0] = _start;
m_minmax_normal_matrices_changed[1] = _end;
}
else
{
if (m_minmax_normal_matrices_changed[0] > _start)
m_minmax_normal_matrices_changed[0] = _start;

if (m_minmax_normal_matrices_changed[1] < _end)
m_minmax_normal_matrices_changed[1] = _end;
}
}

if (start < XFMEM_POSTMATRICES_END && end > XFMEM_POSTMATRICES)
{
int _start = start < XFMEM_POSTMATRICES ? XFMEM_POSTMATRICES : start - XFMEM_POSTMATRICES;
int _end = end < XFMEM_POSTMATRICES_END ? end - XFMEM_POSTMATRICES :
XFMEM_POSTMATRICES_END - XFMEM_POSTMATRICES;

if (m_minmax_post_transform_matrices_changed[0] == -1)
{
m_minmax_post_transform_matrices_changed[0] = _start;
m_minmax_post_transform_matrices_changed[1] = _end;
}
else
{
if (m_minmax_post_transform_matrices_changed[0] > _start)
m_minmax_post_transform_matrices_changed[0] = _start;

if (m_minmax_post_transform_matrices_changed[1] < _end)
m_minmax_post_transform_matrices_changed[1] = _end;
}
}

if (start < XFMEM_LIGHTS_END && end > XFMEM_LIGHTS)
{
int _start = start < XFMEM_LIGHTS ? XFMEM_LIGHTS : start - XFMEM_LIGHTS;
int _end = end < XFMEM_LIGHTS_END ? end - XFMEM_LIGHTS : XFMEM_LIGHTS_END - XFMEM_LIGHTS;

if (m_minmax_lights_changed[0] == -1)
{
m_minmax_lights_changed[0] = _start;
m_minmax_lights_changed[1] = _end;
}
else
{
if (m_minmax_lights_changed[0] > _start)
m_minmax_lights_changed[0] = _start;

if (m_minmax_lights_changed[1] < _end)
m_minmax_lights_changed[1] = _end;
}
}
}

void XFStateManager::SetTexMatrixChangedA(u32 Value)
{
if (g_main_cp_state.matrix_index_a.Hex != Value)
{
g_vertex_manager->Flush();
if (g_main_cp_state.matrix_index_a.PosNormalMtxIdx != (Value & 0x3f))
m_pos_normal_matrix_changed = true;
m_tex_matrices_changed[0] = true;
g_main_cp_state.matrix_index_a.Hex = Value;
}
}

void XFStateManager::ResetTexMatrixAChange()
{
m_tex_matrices_changed[0] = false;
}

void XFStateManager::SetTexMatrixChangedB(u32 Value)
{
if (g_main_cp_state.matrix_index_b.Hex != Value)
{
g_vertex_manager->Flush();
m_tex_matrices_changed[1] = true;
g_main_cp_state.matrix_index_b.Hex = Value;
}
}

void XFStateManager::ResetTexMatrixBChange()
{
m_tex_matrices_changed[1] = false;
}

void XFStateManager::ResetPosNormalChange()
{
m_pos_normal_matrix_changed = false;
}

void XFStateManager::SetProjectionChanged()
{
m_projection_changed = true;
}

void XFStateManager::ResetProjection()
{
m_projection_changed = false;
}

void XFStateManager::SetViewportChanged()
{
m_viewport_changed = true;
}

void XFStateManager::ResetViewportChange()
{
m_viewport_changed = false;
}

void XFStateManager::SetTexMatrixInfoChanged(int index)
{
// TODO: Should we track this with more precision, like which indices changed?
// The whole vertex constants are probably going to be uploaded regardless.
m_tex_mtx_info_changed = true;
}

void XFStateManager::ResetTexMatrixInfoChange()
{
m_tex_mtx_info_changed = false;
}

void XFStateManager::SetLightingConfigChanged()
{
m_lighting_config_changed = true;
}

void XFStateManager::ResetLightingConfigChange()
{
m_lighting_config_changed = false;
}

void XFStateManager::ResetLightsChanged()
{
m_minmax_lights_changed.fill(-1);
}

void XFStateManager::SetMaterialColorChanged(int index)
{
m_materials_changed[index] = true;
}

void XFStateManager::ResetMaterialChanges()
{
m_materials_changed = BitSet32(0);
}

void XFStateManager::ResetPerVertexTransformMatrixChanges()
{
m_minmax_transform_matrices_changed.fill(-1);
}

void XFStateManager::ResetPerVertexNormalMatrixChanges()
{
m_minmax_normal_matrices_changed.fill(-1);
}

void XFStateManager::ResetPostTransformMatrixChanges()
{
m_minmax_post_transform_matrices_changed.fill(-1);
}
87 changes: 87 additions & 0 deletions Source/Core/VideoCommon/XFStateManager.h
@@ -0,0 +1,87 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

#include "Common/BitSet.h"

class PointerWrap;

// This class manages how XF state changes over
// a period of time (typically a single draw call)
class XFStateManager
{
public:
void Init();
void DoState(PointerWrap& p);

void InvalidateXFRange(int start, int end);

void SetTexMatrixChangedA(u32 value);
bool DidTexMatrixAChange() const { return m_tex_matrices_changed[0]; }
void ResetTexMatrixAChange();

void SetTexMatrixChangedB(u32 value);
bool DidTexMatrixBChange() const { return m_tex_matrices_changed[1]; }
void ResetTexMatrixBChange();

bool DidPosNormalChange() const { return m_pos_normal_matrix_changed; }
void ResetPosNormalChange();

void SetProjectionChanged();
bool DidProjectionChange() const { return m_projection_changed; }
void ResetProjection();

void SetViewportChanged();
bool DidViewportChange() const { return m_viewport_changed; }
void ResetViewportChange();

void SetTexMatrixInfoChanged(int index);
bool DidTexMatrixInfoChange() const { return m_tex_mtx_info_changed; }
void ResetTexMatrixInfoChange();

void SetLightingConfigChanged();
bool DidLightingConfigChange() const { return m_lighting_config_changed; }
void ResetLightingConfigChange();

const std::array<int, 2>& GetLightsChanged() const { return m_minmax_lights_changed; }
void ResetLightsChanged();

void SetMaterialColorChanged(int index);
const BitSet32& GetMaterialChanges() const { return m_materials_changed; }
void ResetMaterialChanges();

const std::array<int, 2>& GetPerVertexTransformMatrixChanges() const
{
return m_minmax_transform_matrices_changed;
}
void ResetPerVertexTransformMatrixChanges();

const std::array<int, 2>& GetPerVertexNormalMatrixChanges() const
{
return m_minmax_normal_matrices_changed;
}
void ResetPerVertexNormalMatrixChanges();

const std::array<int, 2>& GetPostTransformMatrixChanges() const
{
return m_minmax_post_transform_matrices_changed;
}
void ResetPostTransformMatrixChanges();

private:
// track changes
std::array<bool, 2> m_tex_matrices_changed{};
bool m_pos_normal_matrix_changed = false;
bool m_projection_changed = false;
bool m_viewport_changed = false;
bool m_tex_mtx_info_changed = false;
bool m_lighting_config_changed = false;
BitSet32 m_materials_changed;
std::array<int, 2> m_minmax_transform_matrices_changed{};
std::array<int, 2> m_minmax_normal_matrices_changed{};
std::array<int, 2> m_minmax_post_transform_matrices_changed{};
std::array<int, 2> m_minmax_lights_changed{};
};
43 changes: 21 additions & 22 deletions Source/Core/VideoCommon/XFStructs.cpp
Expand Up @@ -18,18 +18,17 @@
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/XFMemory.h"
#include "VideoCommon/XFStateManager.h"

static void XFMemWritten(VertexShaderManager& vertex_shader_manager, u32 transferSize,
u32 baseAddress)
static void XFMemWritten(XFStateManager& xf_state_manager, u32 transferSize, u32 baseAddress)
{
g_vertex_manager->Flush();
vertex_shader_manager.InvalidateXFRange(baseAddress, baseAddress + transferSize);
xf_state_manager.InvalidateXFRange(baseAddress, baseAddress + transferSize);
}

static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shader_manager,
u32 address, u32 value)
static void XFRegWritten(Core::System& system, XFStateManager& xf_state_manager, u32 address,
u32 value)
{
if (address >= XFMEM_REGISTERS_START && address < XFMEM_REGISTERS_END)
{
Expand Down Expand Up @@ -63,7 +62,7 @@ static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shade
case XFMEM_SETNUMCHAN:
if (xfmem.numChan.numColorChans != (value & 3))
g_vertex_manager->Flush();
vertex_shader_manager.SetLightingConfigChanged();
xf_state_manager.SetLightingConfigChanged();
break;

case XFMEM_SETCHAN0_AMBCOLOR: // Channel Ambient Color
Expand All @@ -73,7 +72,7 @@ static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shade
if (xfmem.ambColor[chan] != value)
{
g_vertex_manager->Flush();
vertex_shader_manager.SetMaterialColorChanged(chan);
xf_state_manager.SetMaterialColorChanged(chan);
}
break;
}
Expand All @@ -85,7 +84,7 @@ static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shade
if (xfmem.matColor[chan] != value)
{
g_vertex_manager->Flush();
vertex_shader_manager.SetMaterialColorChanged(chan + 2);
xf_state_manager.SetMaterialColorChanged(chan + 2);
}
break;
}
Expand All @@ -96,21 +95,21 @@ static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shade
case XFMEM_SETCHAN1_ALPHA:
if (((u32*)&xfmem)[address] != (value & 0x7fff))
g_vertex_manager->Flush();
vertex_shader_manager.SetLightingConfigChanged();
xf_state_manager.SetLightingConfigChanged();
break;

case XFMEM_DUALTEX:
if (xfmem.dualTexTrans.enabled != bool(value & 1))
g_vertex_manager->Flush();
vertex_shader_manager.SetTexMatrixInfoChanged(-1);
xf_state_manager.SetTexMatrixInfoChanged(-1);
break;

case XFMEM_SETMATRIXINDA:
vertex_shader_manager.SetTexMatrixChangedA(value);
xf_state_manager.SetTexMatrixChangedA(value);
VertexLoaderManager::g_needs_cp_xf_consistency_check = true;
break;
case XFMEM_SETMATRIXINDB:
vertex_shader_manager.SetTexMatrixChangedB(value);
xf_state_manager.SetTexMatrixChangedB(value);
VertexLoaderManager::g_needs_cp_xf_consistency_check = true;
break;

Expand All @@ -121,7 +120,7 @@ static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shade
case XFMEM_SETVIEWPORT + 4:
case XFMEM_SETVIEWPORT + 5:
g_vertex_manager->Flush();
vertex_shader_manager.SetViewportChanged();
xf_state_manager.SetViewportChanged();
system.GetPixelShaderManager().SetViewportChanged();
system.GetGeometryShaderManager().SetViewportChanged();
break;
Expand All @@ -134,7 +133,7 @@ static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shade
case XFMEM_SETPROJECTION + 5:
case XFMEM_SETPROJECTION + 6:
g_vertex_manager->Flush();
vertex_shader_manager.SetProjectionChanged();
xf_state_manager.SetProjectionChanged();
system.GetGeometryShaderManager().SetProjectionChanged();
break;

Expand All @@ -152,7 +151,7 @@ static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shade
case XFMEM_SETTEXMTXINFO + 6:
case XFMEM_SETTEXMTXINFO + 7:
g_vertex_manager->Flush();
vertex_shader_manager.SetTexMatrixInfoChanged(address - XFMEM_SETTEXMTXINFO);
xf_state_manager.SetTexMatrixInfoChanged(address - XFMEM_SETTEXMTXINFO);
break;

case XFMEM_SETPOSTMTXINFO:
Expand All @@ -164,7 +163,7 @@ static void XFRegWritten(Core::System& system, VertexShaderManager& vertex_shade
case XFMEM_SETPOSTMTXINFO + 6:
case XFMEM_SETPOSTMTXINFO + 7:
g_vertex_manager->Flush();
vertex_shader_manager.SetTexMatrixInfoChanged(address - XFMEM_SETPOSTMTXINFO);
xf_state_manager.SetTexMatrixInfoChanged(address - XFMEM_SETPOSTMTXINFO);
break;

// --------------
Expand Down Expand Up @@ -218,7 +217,7 @@ void LoadXFReg(u16 base_address, u8 transfer_size, const u8* data)
}

auto& system = Core::System::GetInstance();
auto& vertex_shader_manager = system.GetVertexShaderManager();
auto& xf_state_manager = system.GetXFStateManager();

// write to XF mem
if (base_address < XFMEM_REGISTERS_START)
Expand All @@ -232,7 +231,7 @@ void LoadXFReg(u16 base_address, u8 transfer_size, const u8* data)
base_address = XFMEM_REGISTERS_START;
}

XFMemWritten(vertex_shader_manager, xf_mem_transfer_size, xf_mem_base);
XFMemWritten(xf_state_manager, xf_mem_transfer_size, xf_mem_base);
for (u32 i = 0; i < xf_mem_transfer_size; i++)
{
((u32*)&xfmem)[xf_mem_base + i] = Common::swap32(data);
Expand All @@ -247,7 +246,7 @@ void LoadXFReg(u16 base_address, u8 transfer_size, const u8* data)
{
const u32 value = Common::swap32(data);

XFRegWritten(system, vertex_shader_manager, address, value);
XFRegWritten(system, xf_state_manager, address, value);
((u32*)&xfmem)[address] = value;

data += 4;
Expand Down Expand Up @@ -275,14 +274,14 @@ void LoadIndexedXF(CPArray array, u32 index, u16 address, u8 size)
g_main_cp_state.array_strides[array] * index);
}

auto& vertex_shader_manager = system.GetVertexShaderManager();
auto& xf_state_manager = system.GetXFStateManager();
bool changed = false;
for (u32 i = 0; i < size; ++i)
{
if (currData[i] != Common::swap32(newData[i]))
{
changed = true;
XFMemWritten(vertex_shader_manager, size, address);
XFMemWritten(xf_state_manager, size, address);
break;
}
}
Expand Down