dolphin/Source/Core/VideoCommon/XFMemory.h

472 lines
13 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// X.h defines None to be 0, which causes problems with some of the enums
#undef None
#include <array>
#include "Common/BitField.h"
#include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"
#include "VideoCommon/CPMemory.h"
constexpr size_t NUM_XF_COLOR_CHANNELS = 2;
// Lighting
// Projection
enum class TexSize : u32
{
ST = 0,
STQ = 1
};
template <>
struct fmt::formatter<TexSize> : EnumFormatter<TexSize::STQ>
{
constexpr formatter() : EnumFormatter({"ST (2x4 matrix)", "STQ (3x4 matrix)"}) {}
};
// Input form
enum class TexInputForm : u32
{
AB11 = 0,
ABC1 = 1
};
template <>
struct fmt::formatter<TexInputForm> : EnumFormatter<TexInputForm::ABC1>
{
constexpr formatter() : EnumFormatter({"AB11", "ABC1"}) {}
};
enum class NormalCount : u32
{
None = 0,
Normal = 1,
NormalTangentBinormal = 2,
// Hardware testing indicates that this beahves the same as NormalTangentBinormal.
// Call of Duty: Black Ops uses this in some cases; see https://bugs.dolphin-emu.org/issues/13070
Invalid = 3,
};
template <>
struct fmt::formatter<NormalCount> : EnumFormatter<NormalCount::Invalid>
{
static constexpr array_type names = {
"None",
"Normal only",
"Normal, tangent, and binormal",
"Invalid (Normal, tangent, and binormal)",
};
constexpr formatter() : EnumFormatter(names) {}
};
// Texture generation type
enum class TexGenType : u32
{
Regular = 0,
EmbossMap = 1, // Used when bump mapping
Color0 = 2,
Color1 = 3
};
template <>
struct fmt::formatter<TexGenType> : EnumFormatter<TexGenType::Color1>
{
static constexpr array_type names = {
"Regular",
"Emboss map (used when bump mapping)",
"Color channel 0",
"Color channel 1",
};
constexpr formatter() : EnumFormatter(names) {}
};
// Source row
enum class SourceRow : u32
{
Geom = 0, // Input is abc
Normal = 1, // Input is abc
Colors = 2,
BinormalT = 3, // Input is abc
BinormalB = 4, // Input is abc
Tex0 = 5,
Tex1 = 6,
Tex2 = 7,
Tex3 = 8,
Tex4 = 9,
Tex5 = 10,
Tex6 = 11,
Tex7 = 12
};
template <>
struct fmt::formatter<SourceRow> : EnumFormatter<SourceRow::Tex7>
{
static constexpr array_type names = {
"Geometry (input is ABC1)",
"Normal (input is ABC1)",
"Colors",
"Binormal T (input is ABC1)",
"Binormal B (input is ABC1)",
"Tex 0",
"Tex 1",
"Tex 2",
"Tex 3",
"Tex 4",
"Tex 5",
"Tex 6",
"Tex 7",
};
constexpr formatter() : EnumFormatter(names) {}
};
enum class MatSource : u32
{
MatColorRegister = 0,
Vertex = 1,
};
template <>
struct fmt::formatter<MatSource> : EnumFormatter<MatSource::Vertex>
{
constexpr formatter() : EnumFormatter({"Material color register", "Vertex color"}) {}
};
enum class AmbSource : u32
{
AmbColorRegister = 0,
Vertex = 1,
};
template <>
struct fmt::formatter<AmbSource> : EnumFormatter<AmbSource::Vertex>
{
constexpr formatter() : EnumFormatter({"Ambient color register", "Vertex color"}) {}
};
// Light diffuse attenuation function
enum class DiffuseFunc : u32
{
None = 0,
Sign = 1,
Clamp = 2
};
template <>
struct fmt::formatter<DiffuseFunc> : EnumFormatter<DiffuseFunc::Clamp>
{
constexpr formatter() : EnumFormatter({"None", "Sign", "Clamp"}) {}
};
// Light attenuation function
enum class AttenuationFunc : u32
{
None = 0, // No attenuation
Spec = 1, // Point light attenuation
Dir = 2, // Directional light attenuation
Spot = 3 // Spot light attenuation
};
template <>
struct fmt::formatter<AttenuationFunc> : EnumFormatter<AttenuationFunc::Spot>
{
static constexpr array_type names = {
"No attenuation",
"Point light attenuation",
"Directional light attenuation",
"Spot light attenuation",
};
constexpr formatter() : EnumFormatter(names) {}
};
// Projection type
enum class ProjectionType : u32
{
Perspective = 0,
Orthographic = 1
};
template <>
struct fmt::formatter<ProjectionType> : EnumFormatter<ProjectionType::Orthographic>
{
constexpr formatter() : EnumFormatter({"Perspective", "Orthographic"}) {}
};
// Registers and register ranges
enum
{
XFMEM_POSMATRICES = 0x000,
XFMEM_POSMATRICES_END = 0x100,
XFMEM_NORMALMATRICES = 0x400,
XFMEM_NORMALMATRICES_END = 0x460,
XFMEM_POSTMATRICES = 0x500,
XFMEM_POSTMATRICES_END = 0x600,
XFMEM_LIGHTS = 0x600,
XFMEM_LIGHTS_END = 0x680,
XFMEM_REGISTERS_START = 0x1000,
XFMEM_ERROR = 0x1000,
XFMEM_DIAG = 0x1001,
XFMEM_STATE0 = 0x1002,
XFMEM_STATE1 = 0x1003,
XFMEM_CLOCK = 0x1004,
XFMEM_CLIPDISABLE = 0x1005,
XFMEM_SETGPMETRIC = 0x1006, // Perf0 according to YAGCD
XFMEM_UNKNOWN_1007 = 0x1007, // Perf1 according to YAGCD
XFMEM_VTXSPECS = 0x1008,
XFMEM_SETNUMCHAN = 0x1009,
XFMEM_SETCHAN0_AMBCOLOR = 0x100a,
XFMEM_SETCHAN1_AMBCOLOR = 0x100b,
XFMEM_SETCHAN0_MATCOLOR = 0x100c,
XFMEM_SETCHAN1_MATCOLOR = 0x100d,
XFMEM_SETCHAN0_COLOR = 0x100e,
XFMEM_SETCHAN1_COLOR = 0x100f,
XFMEM_SETCHAN0_ALPHA = 0x1010,
XFMEM_SETCHAN1_ALPHA = 0x1011,
XFMEM_DUALTEX = 0x1012,
XFMEM_UNKNOWN_GROUP_1_START = 0x1013,
XFMEM_UNKNOWN_GROUP_1_END = 0x1017,
XFMEM_SETMATRIXINDA = 0x1018,
XFMEM_SETMATRIXINDB = 0x1019,
XFMEM_SETVIEWPORT = 0x101a,
XFMEM_SETZSCALE = 0x101c,
XFMEM_SETZOFFSET = 0x101f,
XFMEM_SETPROJECTION = 0x1020,
// XFMEM_SETPROJECTIONB = 0x1021,
// XFMEM_SETPROJECTIONC = 0x1022,
// XFMEM_SETPROJECTIOND = 0x1023,
// XFMEM_SETPROJECTIONE = 0x1024,
// XFMEM_SETPROJECTIONF = 0x1025,
// XFMEM_SETPROJECTIONORTHO = 0x1026,
XFMEM_UNKNOWN_GROUP_2_START = 0x1027,
XFMEM_UNKNOWN_GROUP_2_END = 0x103e,
XFMEM_SETNUMTEXGENS = 0x103f,
XFMEM_SETTEXMTXINFO = 0x1040,
XFMEM_UNKNOWN_GROUP_3_START = 0x1048,
XFMEM_UNKNOWN_GROUP_3_END = 0x104f,
XFMEM_SETPOSTMTXINFO = 0x1050,
XFMEM_REGISTERS_END = 0x1058,
};
union LitChannel
{
BitField<0, 1, MatSource> matsource;
BitField<1, 1, bool, u32> enablelighting;
BitField<2, 4, u32> lightMask0_3;
BitField<6, 1, AmbSource> ambsource;
BitField<7, 2, DiffuseFunc> diffusefunc;
BitField<9, 2, AttenuationFunc> attnfunc;
BitField<11, 4, u32> lightMask4_7;
u32 hex;
unsigned int GetFullLightMask() const
{
return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0;
}
};
template <>
struct fmt::formatter<LitChannel>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const LitChannel& chan, FormatContext& ctx) const
{
return fmt::format_to(
ctx.out(),
"Material source: {0}\nEnable lighting: {1}\nLight mask: {2:x} ({2:08b})\n"
"Ambient source: {3}\nDiffuse function: {4}\nAttenuation function: {5}",
chan.matsource, chan.enablelighting ? "Yes" : "No", chan.GetFullLightMask(), chan.ambsource,
chan.diffusefunc, chan.attnfunc);
}
};
union ClipDisable
{
BitField<0, 1, bool, u32> disable_clipping_detection;
BitField<1, 1, bool, u32> disable_trivial_rejection;
BitField<2, 1, bool, u32> disable_cpoly_clipping_acceleration;
u32 hex;
};
template <>
struct fmt::formatter<ClipDisable>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const ClipDisable& cd, FormatContext& ctx) const
{
return fmt::format_to(ctx.out(),
"Disable clipping detection: {}\n"
"Disable trivial rejection: {}\n"
"Disable cpoly clipping acceleration: {}",
cd.disable_clipping_detection ? "Yes" : "No",
cd.disable_trivial_rejection ? "Yes" : "No",
cd.disable_cpoly_clipping_acceleration ? "Yes" : "No");
}
};
union INVTXSPEC
{
BitField<0, 2, u32> numcolors;
BitField<2, 2, NormalCount> numnormals;
BitField<4, 4, u32> numtextures;
u32 hex;
};
template <>
struct fmt::formatter<INVTXSPEC>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const INVTXSPEC& spec, FormatContext& ctx) const
{
return fmt::format_to(ctx.out(), "Num colors: {}\nNum normals: {}\nNum textures: {}",
spec.numcolors, spec.numnormals, spec.numtextures);
}
};
union TexMtxInfo
{
BitField<0, 1, u32> unknown;
BitField<1, 1, TexSize> projection;
BitField<2, 1, TexInputForm> inputform;
BitField<3, 1, u32> unknown2;
BitField<4, 3, TexGenType> texgentype;
BitField<7, 5, SourceRow> sourcerow;
BitField<12, 3, u32> embosssourceshift; // what generated texcoord to use
BitField<15, 3, u32> embosslightshift; // light index that is used
u32 hex;
};
template <>
struct fmt::formatter<TexMtxInfo>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TexMtxInfo& i, FormatContext& ctx) const
{
return fmt::format_to(ctx.out(),
"Projection: {}\nInput form: {}\nTex gen type: {}\n"
"Source row: {}\nEmboss source shift: {}\nEmboss light shift: {}",
i.projection, i.inputform, i.texgentype, i.sourcerow, i.embosssourceshift,
i.embosslightshift);
}
};
union PostMtxInfo
{
BitField<0, 6, u32> index; // base row of dual transform matrix
BitField<6, 2, u32> unused; //
BitField<8, 1, bool, u32> normalize; // normalize before send operation
u32 hex;
};
template <>
struct fmt::formatter<PostMtxInfo>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PostMtxInfo& i, FormatContext& ctx) const
{
return fmt::format_to(ctx.out(), "Index: {}\nNormalize before send operation: {}", i.index,
i.normalize ? "Yes" : "No");
}
};
union NumColorChannel
{
BitField<0, 2, u32> numColorChans;
u32 hex;
};
union NumTexGen
{
BitField<0, 4, u32> numTexGens;
u32 hex;
};
union DualTexInfo
{
BitField<0, 1, bool, u32> enabled;
u32 hex;
};
struct Light
{
u32 useless[3];
u8 color[4];
float cosatt[3]; // cos attenuation
float distatt[3]; // dist attenuation
union
{
struct
{
float dpos[3];
float ddir[3]; // specular lights only
};
struct
{
float sdir[3];
float shalfangle[3]; // specular lights only
};
};
};
struct Viewport
{
float wd;
float ht;
float zRange;
float xOrig;
float yOrig;
float farZ;
};
struct Projection
{
using Raw = std::array<float, 6>;
Raw rawProjection;
ProjectionType type;
};
struct alignas(16) XFMemory
{
float posMatrices[256]; // 0x0000 - 0x00ff
u32 unk0[768]; // 0x0100 - 0x03ff
float normalMatrices[96]; // 0x0400 - 0x045f
u32 unk1[160]; // 0x0460 - 0x04ff
float postMatrices[256]; // 0x0500 - 0x05ff
Light lights[8]; // 0x0600 - 0x067f
u32 unk2[2432]; // 0x0680 - 0x0fff
u32 error; // 0x1000
u32 diag; // 0x1001
u32 state0; // 0x1002
u32 state1; // 0x1003
u32 xfClock; // 0x1004
ClipDisable clipDisable; // 0x1005
u32 perf0; // 0x1006
u32 perf1; // 0x1007
INVTXSPEC invtxspec; // 0x1008
NumColorChannel numChan; // 0x1009
u32 ambColor[NUM_XF_COLOR_CHANNELS]; // 0x100a, 0x100b
u32 matColor[NUM_XF_COLOR_CHANNELS]; // 0x100c, 0x100d
LitChannel color[NUM_XF_COLOR_CHANNELS]; // 0x100e, 0x100f
LitChannel alpha[NUM_XF_COLOR_CHANNELS]; // 0x1010, 0x1011
DualTexInfo dualTexTrans; // 0x1012
u32 unk3; // 0x1013
u32 unk4; // 0x1014
u32 unk5; // 0x1015
u32 unk6; // 0x1016
u32 unk7; // 0x1017
TMatrixIndexA MatrixIndexA; // 0x1018
TMatrixIndexB MatrixIndexB; // 0x1019
Viewport viewport; // 0x101a - 0x101f
Projection projection; // 0x1020 - 0x1026
u32 unk8[24]; // 0x1027 - 0x103e
NumTexGen numTexGen; // 0x103f
TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047
u32 unk9[8]; // 0x1048 - 0x104f
PostMtxInfo postMtxInfo[8]; // 0x1050 - 0x1057
};
static_assert(sizeof(XFMemory) == sizeof(u32) * XFMEM_REGISTERS_END);
extern XFMemory xfmem;
void LoadXFReg(u16 base_address, u8 transfer_size, const u8* data);
void LoadIndexedXF(CPArray array, u32 index, u16 address, u8 size);
void PreprocessIndexedXF(CPArray array, u32 index, u16 address, u8 size);