1 change: 1 addition & 0 deletions Source/Core/Common/CMakeLists.txt
Expand Up @@ -42,6 +42,7 @@ add_library(common
DynamicLibrary.h
ENetUtil.cpp
ENetUtil.h
EnumFormatter.h
Event.h
FileSearch.cpp
FileSearch.h
Expand Down
91 changes: 91 additions & 0 deletions Source/Core/Common/EnumFormatter.h
@@ -0,0 +1,91 @@
// Copyright 2021 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <fmt/format.h>
#include <type_traits>

/*
* Helper for using enums with fmt.
*
* Usage example:
*
* enum class Foo
* {
* A = 0,
* B = 1,
* C = 2,
* };
*
* template <>
* struct fmt::formatter<Foo> : EnumFormatter<Foo::C>
* {
* formatter() : EnumFormatter({"A", "B", "C"}) {}
* };
*
* enum class Bar
* {
* D = 0,
* E = 1,
* F = 3,
* };
*
* template <>
* struct fmt::formatter<Bar> : EnumFormatter<Bar::F>
* {
* // using std::array here fails due to nullptr not being const char*, at least in MSVC
* // (but only when a field is used; directly in the constructor is OK)
* static constexpr array_type names = {"D", "E", nullptr, "F"};
* formatter() : EnumFormatter(names) {}
* };
*/
template <auto last_member, typename T = decltype(last_member),
size_t size = static_cast<size_t>(last_member) + 1,
std::enable_if_t<std::is_enum_v<T>, bool> = true>
class EnumFormatter
{
public:
constexpr auto parse(fmt::format_parse_context& ctx)
{
auto it = ctx.begin(), end = ctx.end();
// 'u' for user display, 's' for shader generation
if (it != end && (*it == 'u' || *it == 's'))
formatting_for_shader = (*it++ == 's');
return it;
}

template <typename FormatContext>
auto format(const T& e, FormatContext& ctx)
{
const auto value = static_cast<std::underlying_type_t<T>>(e);

if (!formatting_for_shader)
{
if (value >= 0 && value < size && m_names[value] != nullptr)
return fmt::format_to(ctx.out(), "{} ({})", m_names[value], value);
else
return fmt::format_to(ctx.out(), "Invalid ({})", value);
}
else
{
if (value >= 0 && value < size && m_names[value] != nullptr)
return fmt::format_to(ctx.out(), "{:#x}u /* {} */", value, m_names[value]);
else
return fmt::format_to(ctx.out(), "{:#x}u /* Invalid */",
static_cast<std::make_unsigned_t<T>>(value));
}
}

protected:
// This is needed because std::array deduces incorrectly if nullptr is included in the list
using array_type = std::array<const char*, size>;

constexpr explicit EnumFormatter(const array_type names) : m_names(std::move(names)) {}

private:
const array_type m_names;
bool formatting_for_shader = false;
};
58 changes: 25 additions & 33 deletions Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp
Expand Up @@ -49,21 +49,17 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
const VAT& vtxAttr = cpMem.vtxAttr[vatIndex];

// Colors
const std::array<u64, 2> colDesc{
vtxDesc.Color0,
vtxDesc.Color1,
};
const std::array<u32, 2> colComp{
const std::array<ColorFormat, 2> colComp{
vtxAttr.g0.Color0Comp,
vtxAttr.g0.Color1Comp,
};

const std::array<u32, 8> tcElements{
const std::array<TexComponentCount, 8> tcElements{
vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, vtxAttr.g1.Tex2CoordElements,
vtxAttr.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements,
vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements,
};
const std::array<u32, 8> tcFormat{
const std::array<ComponentFormat, 8> tcFormat{
vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, vtxAttr.g1.Tex2CoordFormat,
vtxAttr.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat,
vtxAttr.g2.Tex6CoordFormat, vtxAttr.g2.Tex7CoordFormat,
Expand All @@ -72,21 +68,20 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
std::array<int, 21> sizes{};

// Add position and texture matrix indices
u64 vtxDescHex = cpMem.vtxDesc.Hex;
for (int i = 0; i < 9; ++i)
sizes[0] = vtxDesc.low.PosMatIdx;
for (size_t i = 0; i < vtxDesc.low.TexMatIdx.Size(); ++i)
{
sizes[i] = vtxDescHex & 1;
vtxDescHex >>= 1;
sizes[i + 1] = vtxDesc.low.TexMatIdx[i];
}

// Position
sizes[9] = VertexLoader_Position::GetSize(vtxDesc.Position, vtxAttr.g0.PosFormat,
sizes[9] = VertexLoader_Position::GetSize(vtxDesc.low.Position, vtxAttr.g0.PosFormat,
vtxAttr.g0.PosElements);

// Normals
if (vtxDesc.Normal != NOT_PRESENT)
if (vtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.Normal, vtxAttr.g0.NormalFormat,
sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.low.Normal, vtxAttr.g0.NormalFormat,
vtxAttr.g0.NormalElements, vtxAttr.g0.NormalIndex3);
}
else
Expand All @@ -95,44 +90,44 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
}

// Colors
for (size_t i = 0; i < colDesc.size(); i++)
for (size_t i = 0; i < vtxDesc.low.Color.Size(); i++)
{
int size = 0;

switch (colDesc[i])
switch (vtxDesc.low.Color[i])
{
case NOT_PRESENT:
case VertexComponentFormat::NotPresent:
break;
case DIRECT:
case VertexComponentFormat::Direct:
switch (colComp[i])
{
case FORMAT_16B_565:
case ColorFormat::RGB565:
size = 2;
break;
case FORMAT_24B_888:
case ColorFormat::RGB888:
size = 3;
break;
case FORMAT_32B_888x:
case ColorFormat::RGB888x:
size = 4;
break;
case FORMAT_16B_4444:
case ColorFormat::RGBA4444:
size = 2;
break;
case FORMAT_24B_6666:
case ColorFormat::RGBA6666:
size = 3;
break;
case FORMAT_32B_8888:
case ColorFormat::RGBA8888:
size = 4;
break;
default:
ASSERT(0);
break;
}
break;
case INDEX8:
case VertexComponentFormat::Index8:
size = 1;
break;
case INDEX16:
case VertexComponentFormat::Index16:
size = 2;
break;
}
Expand All @@ -141,11 +136,10 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
}

// Texture coordinates
vtxDescHex = vtxDesc.Hex >> 17;
for (size_t i = 0; i < tcFormat.size(); i++)
{
sizes[13 + i] = VertexLoader_TextCoord::GetSize(vtxDescHex & 3, tcFormat[i], tcElements[i]);
vtxDescHex >>= 2;
sizes[13 + i] =
VertexLoader_TextCoord::GetSize(vtxDesc.high.TexCoord[i], tcFormat[i], tcElements[i]);
}

return sizes;
Expand Down Expand Up @@ -267,13 +261,11 @@ void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem)
switch (subCmd & 0xF0)
{
case 0x50:
cpMem.vtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
cpMem.vtxDesc.Hex |= value;
cpMem.vtxDesc.low.Hex = value;
break;

case 0x60:
cpMem.vtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
cpMem.vtxDesc.Hex |= (u64)value << 17;
cpMem.vtxDesc.high.Hex = value;
break;

case 0x70:
Expand Down
22 changes: 11 additions & 11 deletions Source/Core/Core/FifoPlayer/FifoPlayer.cpp
Expand Up @@ -467,22 +467,22 @@ void FifoPlayer::LoadRegisters()
}

regs = m_File->GetCPMem();
LoadCPReg(0x30, regs[0x30]);
LoadCPReg(0x40, regs[0x40]);
LoadCPReg(0x50, regs[0x50]);
LoadCPReg(0x60, regs[0x60]);
LoadCPReg(MATINDEX_A, regs[MATINDEX_A]);
LoadCPReg(MATINDEX_B, regs[MATINDEX_B]);
LoadCPReg(VCD_LO, regs[VCD_LO]);
LoadCPReg(VCD_HI, regs[VCD_HI]);

for (int i = 0; i < 8; ++i)
for (int i = 0; i < CP_NUM_VAT_REG; ++i)
{
LoadCPReg(0x70 + i, regs[0x70 + i]);
LoadCPReg(0x80 + i, regs[0x80 + i]);
LoadCPReg(0x90 + i, regs[0x90 + i]);
LoadCPReg(CP_VAT_REG_A + i, regs[CP_VAT_REG_A + i]);
LoadCPReg(CP_VAT_REG_B + i, regs[CP_VAT_REG_B + i]);
LoadCPReg(CP_VAT_REG_C + i, regs[CP_VAT_REG_C + i]);
}

for (int i = 0; i < 16; ++i)
for (int i = 0; i < CP_NUM_ARRAYS; ++i)
{
LoadCPReg(0xa0 + i, regs[0xa0 + i]);
LoadCPReg(0xb0 + i, regs[0xb0 + i]);
LoadCPReg(ARRAY_BASE + i, regs[ARRAY_BASE + i]);
LoadCPReg(ARRAY_STRIDE + i, regs[ARRAY_STRIDE + i]);
}

regs = m_File->GetXFMem();
Expand Down
21 changes: 18 additions & 3 deletions Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp
Expand Up @@ -6,6 +6,7 @@

#include <algorithm>

#include "Common/MsgHandler.h"
#include "Core/FifoPlayer/FifoAnalyzer.h"
#include "Core/FifoPlayer/FifoRecorder.h"
#include "Core/HW/Memmap.h"
Expand Down Expand Up @@ -44,14 +45,28 @@ void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, const u8* vertexData,
int numVertices)
{
// Skip if not indexed array
int arrayType = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3;
if (arrayType < 2)
VertexComponentFormat arrayType;
if (arrayIndex == ARRAY_POSITION)
arrayType = s_CpMem.vtxDesc.low.Position;
else if (arrayIndex == ARRAY_NORMAL)
arrayType = s_CpMem.vtxDesc.low.Normal;
else if (arrayIndex == ARRAY_COLOR || arrayIndex == ARRAY_COLOR2)
arrayType = s_CpMem.vtxDesc.low.Color[arrayIndex - ARRAY_COLOR];
else if (arrayIndex >= ARRAY_POSITION && arrayIndex < ARRAY_POSITION + 8)
arrayType = s_CpMem.vtxDesc.high.TexCoord[arrayIndex - ARRAY_POSITION];
else
{
PanicAlertFmt("Invalid arrayIndex {}", arrayIndex);
return;
}

if (!IsIndexed(arrayType))
return;

int maxIndex = 0;

// Determine min and max indices
if (arrayType == INDEX8)
if (arrayType == VertexComponentFormat::Index8)
{
for (int i = 0; i < numVertices; ++i)
{
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DolphinLib.props
Expand Up @@ -45,6 +45,7 @@
<ClInclude Include="Common\DebugInterface.h" />
<ClInclude Include="Common\DynamicLibrary.h" />
<ClInclude Include="Common\ENetUtil.h" />
<ClInclude Include="Common\EnumFormatter.h" />
<ClInclude Include="Common\Event.h" />
<ClInclude Include="Common\FileSearch.h" />
<ClInclude Include="Common\FileUtil.h" />
Expand Down
8 changes: 7 additions & 1 deletion Source/Core/DolphinNoGUI/PlatformX11.cpp
Expand Up @@ -4,6 +4,12 @@

#include <unistd.h>

// X.h defines None to be 0L, but other parts of Dolphin undef that so that
// None can be used in enums. Work around that here by copying the definition
// before it is undefined.
#include <X11/X.h>
static constexpr auto X_None = None;

#include "DolphinNoGUI/Platform.h"

#include "Common/MsgHandler.h"
Expand Down Expand Up @@ -47,7 +53,7 @@ class PlatformX11 : public Platform

Display* m_display = nullptr;
Window m_window = {};
Cursor m_blank_cursor = None;
Cursor m_blank_cursor = X_None;
#ifdef HAVE_XRANDR
X11Utils::XRRConfiguration* m_xrr_config = nullptr;
#endif
Expand Down
64 changes: 51 additions & 13 deletions Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp
Expand Up @@ -23,7 +23,9 @@
#include "DolphinQt/Settings.h"

#include "VideoCommon/BPMemory.h"
#include "VideoCommon/CPMemory.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/XFStructs.h"

constexpr int FRAME_ROLE = Qt::UserRole;
constexpr int OBJECT_ROLE = Qt::UserRole + 1;
Expand Down Expand Up @@ -224,17 +226,22 @@ void FIFOAnalyzer::UpdateDetails()
u32 cmd2 = *objectdata++;
u32 value = Common::swap32(objectdata);
objectdata += 4;
const auto [name, desc] = GetCPRegInfo(cmd2, value);
ASSERT(!name.empty());

new_label = QStringLiteral("CP %1 %2")
new_label = QStringLiteral("CP %1 %2 %3")
.arg(cmd2, 2, 16, QLatin1Char('0'))
.arg(value, 8, 16, QLatin1Char('0'));
.arg(value, 8, 16, QLatin1Char('0'))
.arg(QString::fromStdString(name));
}
break;

case OpcodeDecoder::GX_LOAD_XF_REG:
{
const auto [name, desc] = GetXFTransferInfo(objectdata);
u32 cmd2 = Common::swap32(objectdata);
objectdata += 4;
ASSERT(!name.empty());

u8 streamSize = ((cmd2 >> 16) & 15) + 1;

Expand All @@ -249,6 +256,8 @@ void FIFOAnalyzer::UpdateDetails()
if (((objectdata - stream_start) % 4) == 0)
new_label += QLatin1Char(' ');
}

new_label += QStringLiteral(" ") + QString::fromStdString(name);
}
break;

Expand Down Expand Up @@ -278,11 +287,17 @@ void FIFOAnalyzer::UpdateDetails()

case OpcodeDecoder::GX_LOAD_BP_REG:
{
u32 cmd2 = Common::swap32(objectdata);
objectdata += 4;
new_label = QStringLiteral("BP %1 %2")
.arg(cmd2 >> 24, 2, 16, QLatin1Char('0'))
.arg(cmd2 & 0xFFFFFF, 6, 16, QLatin1Char('0'));
const u8 cmd2 = *objectdata++;
const u32 cmddata = Common::swap24(objectdata);
objectdata += 3;

const auto [name, desc] = GetBPRegInfo(cmd2, cmddata);
ASSERT(!name.empty());

new_label = QStringLiteral("BP %1 %2 %3")
.arg(cmd2, 2, 16, QLatin1Char('0'))
.arg(cmddata, 6, 16, QLatin1Char('0'))
.arg(QString::fromStdString(name));
}
break;

Expand Down Expand Up @@ -467,14 +482,14 @@ void FIFOAnalyzer::UpdateDescription()
QString text;
if (*cmddata == OpcodeDecoder::GX_LOAD_BP_REG)
{
std::string name;
std::string desc;
GetBPRegInfo(cmddata + 1, &name, &desc);
const u8 cmd = *(cmddata + 1);
const u32 value = Common::swap24(cmddata + 2);

const auto [name, desc] = GetBPRegInfo(cmd, value);
ASSERT(!name.empty());

text = tr("BP register ");
text += name.empty() ?
QStringLiteral("UNKNOWN_%1").arg(*(cmddata + 1), 2, 16, QLatin1Char('0')) :
QString::fromStdString(name);
text += QString::fromStdString(name);
text += QLatin1Char{'\n'};

if (desc.empty())
Expand All @@ -484,11 +499,34 @@ void FIFOAnalyzer::UpdateDescription()
}
else if (*cmddata == OpcodeDecoder::GX_LOAD_CP_REG)
{
const u8 cmd = *(cmddata + 1);
const u32 value = Common::swap32(cmddata + 2);

const auto [name, desc] = GetCPRegInfo(cmd, value);
ASSERT(!name.empty());

text = tr("CP register ");
text += QString::fromStdString(name);
text += QLatin1Char{'\n'};

if (desc.empty())
text += tr("No description available");
else
text += QString::fromStdString(desc);
}
else if (*cmddata == OpcodeDecoder::GX_LOAD_XF_REG)
{
const auto [name, desc] = GetXFTransferInfo(cmddata + 1);
ASSERT(!name.empty());

text = tr("XF register ");
text += QString::fromStdString(name);
text += QLatin1Char{'\n'};

if (desc.empty())
text += tr("No description available");
else
text += QString::fromStdString(desc);
}
else
{
Expand Down
14 changes: 7 additions & 7 deletions Source/Core/VideoBackends/D3D/D3DState.cpp
Expand Up @@ -378,7 +378,7 @@ ID3D11BlendState* StateCache::Get(BlendingState state)
D3D11_LOGIC_OP_COPY_INVERTED, D3D11_LOGIC_OP_OR_INVERTED, D3D11_LOGIC_OP_NAND,
D3D11_LOGIC_OP_SET}};
tdesc.LogicOpEnable = TRUE;
tdesc.LogicOp = logic_ops[state.logicmode];
tdesc.LogicOp = logic_ops[u32(state.logicmode.Value())];

ComPtr<ID3D11BlendState1> res;
HRESULT hr = D3D::device1->CreateBlendState1(&desc, res.GetAddressOf());
Expand Down Expand Up @@ -416,10 +416,10 @@ ID3D11BlendState* StateCache::Get(BlendingState state)
use_dual_source ? D3D11_BLEND_INV_SRC1_ALPHA : D3D11_BLEND_INV_SRC_ALPHA,
D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_INV_DEST_ALPHA}};

tdesc.SrcBlend = src_factors[state.srcfactor];
tdesc.SrcBlendAlpha = src_factors[state.srcfactoralpha];
tdesc.DestBlend = dst_factors[state.dstfactor];
tdesc.DestBlendAlpha = dst_factors[state.dstfactoralpha];
tdesc.SrcBlend = src_factors[u32(state.srcfactor.Value())];
tdesc.SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())];
tdesc.DestBlend = dst_factors[u32(state.dstfactor.Value())];
tdesc.DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())];
tdesc.BlendOp = state.subtract ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD;
tdesc.BlendOpAlpha = state.subtractAlpha ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD;

Expand All @@ -441,7 +441,7 @@ ID3D11RasterizerState* StateCache::Get(RasterizationState state)

D3D11_RASTERIZER_DESC desc = {};
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = cull_modes[state.cullmode];
desc.CullMode = cull_modes[u32(state.cullmode.Value())];
desc.ScissorEnable = TRUE;

ComPtr<ID3D11RasterizerState> res;
Expand Down Expand Up @@ -477,7 +477,7 @@ ID3D11DepthStencilState* StateCache::Get(DepthState state)
depthdc.DepthEnable = TRUE;
depthdc.DepthWriteMask =
state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
depthdc.DepthFunc = d3dCmpFuncs[state.func];
depthdc.DepthFunc = d3dCmpFuncs[u32(state.func.Value())];
}
else
{
Expand Down
22 changes: 11 additions & 11 deletions Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp
Expand Up @@ -66,7 +66,7 @@ static void GetD3DRasterizerDesc(D3D12_RASTERIZER_DESC* desc, const Rasterizatio
{D3D12_CULL_MODE_NONE, D3D12_CULL_MODE_BACK, D3D12_CULL_MODE_FRONT, D3D12_CULL_MODE_FRONT}};

desc->FillMode = D3D12_FILL_MODE_SOLID;
desc->CullMode = cull_modes[rs_state.cullmode];
desc->CullMode = cull_modes[u32(rs_state.cullmode.Value())];
desc->MultisampleEnable = fb_state.samples > 1;
}

Expand All @@ -80,7 +80,7 @@ static void GetD3DDepthDesc(D3D12_DEPTH_STENCIL_DESC* desc, const DepthState& st
D3D12_COMPARISON_FUNC_ALWAYS}};

desc->DepthEnable = state.testenable;
desc->DepthFunc = compare_funcs[state.func];
desc->DepthFunc = compare_funcs[u32(state.func.Value())];
desc->DepthWriteMask =
state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
}
Expand Down Expand Up @@ -135,24 +135,24 @@ static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state)
rtblend->BlendOpAlpha = state.subtractAlpha ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD;
if (state.usedualsrc)
{
rtblend->SrcBlend = src_dual_src_factors[state.srcfactor];
rtblend->SrcBlendAlpha = src_dual_src_factors[state.srcfactoralpha];
rtblend->DestBlend = dst_dual_src_factors[state.dstfactor];
rtblend->DestBlendAlpha = dst_dual_src_factors[state.dstfactoralpha];
rtblend->SrcBlend = src_dual_src_factors[u32(state.srcfactor.Value())];
rtblend->SrcBlendAlpha = src_dual_src_factors[u32(state.srcfactoralpha.Value())];
rtblend->DestBlend = dst_dual_src_factors[u32(state.dstfactor.Value())];
rtblend->DestBlendAlpha = dst_dual_src_factors[u32(state.dstfactoralpha.Value())];
}
else
{
rtblend->SrcBlend = src_factors[state.srcfactor];
rtblend->SrcBlendAlpha = src_factors[state.srcfactoralpha];
rtblend->DestBlend = dst_factors[state.dstfactor];
rtblend->DestBlendAlpha = dst_factors[state.dstfactoralpha];
rtblend->SrcBlend = src_factors[u32(state.srcfactor.Value())];
rtblend->SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())];
rtblend->DestBlend = dst_factors[u32(state.dstfactor.Value())];
rtblend->DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())];
}
}
else
{
rtblend->LogicOpEnable = state.logicopenable;
if (state.logicopenable)
rtblend->LogicOp = logic_ops[state.logicmode];
rtblend->LogicOp = logic_ops[u32(state.logicmode.Value())];
}
}

Expand Down
14 changes: 8 additions & 6 deletions Source/Core/VideoBackends/OGL/OGLRender.cpp
Expand Up @@ -1140,11 +1140,11 @@ void Renderer::ApplyRasterizationState(const RasterizationState state)
return;

// none, ccw, cw, ccw
if (state.cullmode != GenMode::CULL_NONE)
if (state.cullmode != CullMode::None)
{
// TODO: GX_CULL_ALL not supported, yet!
glEnable(GL_CULL_FACE);
glFrontFace(state.cullmode == GenMode::CULL_FRONT ? GL_CCW : GL_CW);
glFrontFace(state.cullmode == CullMode::Front ? GL_CCW : GL_CW);
}
else
{
Expand All @@ -1166,7 +1166,7 @@ void Renderer::ApplyDepthState(const DepthState state)
{
glEnable(GL_DEPTH_TEST);
glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE);
glDepthFunc(glCmpFuncs[state.func]);
glDepthFunc(glCmpFuncs[u32(state.func.Value())]);
}
else
{
Expand Down Expand Up @@ -1229,8 +1229,10 @@ void Renderer::ApplyBlendingState(const BlendingState state)
GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
glBlendEquationSeparate(equation, equationAlpha);
glBlendFuncSeparate(src_factors[state.srcfactor], dst_factors[state.dstfactor],
src_factors[state.srcfactoralpha], dst_factors[state.dstfactoralpha]);
glBlendFuncSeparate(src_factors[u32(state.srcfactor.Value())],
dst_factors[u32(state.dstfactor.Value())],
src_factors[u32(state.srcfactoralpha.Value())],
dst_factors[u32(state.dstfactoralpha.Value())]);
}

const GLenum logic_op_codes[16] = {
Expand All @@ -1244,7 +1246,7 @@ void Renderer::ApplyBlendingState(const BlendingState state)
if (state.logicopenable)
{
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(logic_op_codes[state.logicmode]);
glLogicOp(logic_op_codes[u32(state.logicmode.Value())]);
}
else
{
Expand Down
7 changes: 5 additions & 2 deletions Source/Core/VideoBackends/Software/Clipper.cpp
Expand Up @@ -489,13 +489,16 @@ bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const Outp

backface = normalZDir <= 0.0f;

if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing
// TODO: Are these tests / the definition of backface above backwards?
if ((bpmem.genMode.cullmode == CullMode::Back || bpmem.genMode.cullmode == CullMode::All) &&
!backface) // cull frontfacing
{
INCSTAT(g_stats.this_frame.num_triangles_culled)
return false;
}

if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
if ((bpmem.genMode.cullmode == CullMode::Front || bpmem.genMode.cullmode == CullMode::All) &&
backface) // cull backfacing
{
INCSTAT(g_stats.this_frame.num_triangles_culled)
return false;
Expand Down
156 changes: 75 additions & 81 deletions Source/Core/VideoBackends/Software/EfbInterface.cpp

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions Source/Core/VideoBackends/Software/Rasterizer.cpp
Expand Up @@ -173,7 +173,7 @@ static inline void CalculateLOD(s32* lodp, bool* linear, u32 texmap, u32 texcoor
const TexMode1& tm1 = texUnit.texMode1[subTexmap];

float sDelta, tDelta;
if (tm0.diag_lod)
if (tm0.diag_lod == LODType::Diagonal)
{
float* uv0 = rasterBlock.Pixel[0][0].Uv[texcoord];
float* uv1 = rasterBlock.Pixel[1][1].Uv[texcoord];
Expand All @@ -199,7 +199,8 @@ static inline void CalculateLOD(s32* lodp, bool* linear, u32 texmap, u32 texcoor
bias >>= 1;
lod += bias;

*linear = ((lod > 0 && (tm0.min_filter & 4)) || (lod <= 0 && tm0.mag_filter));
*linear = ((lod > 0 && tm0.min_filter == FilterMode::Linear) ||
(lod <= 0 && tm0.mag_filter == FilterMode::Linear));

// NOTE: The order of comparisons for this clamp check matters.
if (lod > static_cast<s32>(tm1.max_lod))
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/VideoBackends/Software/SWVertexLoader.cpp
Expand Up @@ -183,8 +183,8 @@ static void ParseColorAttributes(InputVertexData* dst, DataReader& src,
const auto set_default_color = [](u8* color, int i) {
// The default alpha channel seems to depend on the number of components in the vertex format.
const auto& g0 = g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0;
const u32 color_elements = i == 0 ? g0.Color0Elements : g0.Color1Elements;
color[0] = color_elements == 0 ? 255 : 0;
const auto color_elements = i == 0 ? g0.Color0Elements.Value() : g0.Color1Elements.Value();
color[0] = color_elements == ColorComponentCount::RGB ? 255 : 0;
color[1] = 255;
color[2] = 255;
color[3] = 255;
Expand Down
329 changes: 152 additions & 177 deletions Source/Core/VideoBackends/Software/Tev.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/Software/Tev.h
Expand Up @@ -57,7 +57,7 @@ class Tev
INDIRECT = 32
};

void SetRasColor(int colorChan, int swaptable);
void SetRasColor(RasColorChan colorChan, int swaptable);

void DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
void DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
Expand Down
28 changes: 14 additions & 14 deletions Source/Core/VideoBackends/Software/TextureEncoder.cpp
Expand Up @@ -504,7 +504,7 @@ static void EncodeRGBA6(u8* dst, const u8* src, EFBCopyFormat format, bool yuv)
break;

default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format);
PanicAlertFmt("Unknown texture copy format: {}\n", format);
break;
}
}
Expand Down Expand Up @@ -743,7 +743,7 @@ static void EncodeRGBA6halfscale(u8* dst, const u8* src, EFBCopyFormat format, b
break;

default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format);
PanicAlertFmt("Unknown texture copy format: {}\n", format);
break;
}
}
Expand Down Expand Up @@ -960,7 +960,7 @@ static void EncodeRGB8(u8* dst, const u8* src, EFBCopyFormat format, bool yuv)
break;

default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format);
PanicAlertFmt("Unknown texture copy format: {}\n", format);
break;
}
}
Expand Down Expand Up @@ -1192,7 +1192,7 @@ static void EncodeRGB8halfscale(u8* dst, const u8* src, EFBCopyFormat format, bo
break;

default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format);
PanicAlertFmt("Unknown texture copy format: {}\n", format);
break;
}
}
Expand Down Expand Up @@ -1300,7 +1300,7 @@ static void EncodeZ24(u8* dst, const u8* src, EFBCopyFormat format)
break;

default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format);
PanicAlertFmt("Unknown texture copy format: {}\n", format);
break;
}
}
Expand Down Expand Up @@ -1414,7 +1414,7 @@ static void EncodeZ24halfscale(u8* dst, const u8* src, EFBCopyFormat format)
break;

default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format);
PanicAlertFmt("Unknown texture copy format: {}\n", format);
break;
}
}
Expand All @@ -1431,16 +1431,16 @@ void EncodeEfbCopy(u8* dst, const EFBCopyParams& params, u32 native_width, u32 b
{
switch (params.efb_format)
{
case PEControl::RGBA6_Z24:
case PixelFormat::RGBA6_Z24:
EncodeRGBA6halfscale(dst, src, params.copy_format, params.yuv);
break;
case PEControl::RGB8_Z24:
case PixelFormat::RGB8_Z24:
EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv);
break;
case PEControl::RGB565_Z16:
case PixelFormat::RGB565_Z16:
EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv);
break;
case PEControl::Z24:
case PixelFormat::Z24:
EncodeZ24halfscale(dst, src, params.copy_format);
break;
default:
Expand All @@ -1451,16 +1451,16 @@ void EncodeEfbCopy(u8* dst, const EFBCopyParams& params, u32 native_width, u32 b
{
switch (params.efb_format)
{
case PEControl::RGBA6_Z24:
case PixelFormat::RGBA6_Z24:
EncodeRGBA6(dst, src, params.copy_format, params.yuv);
break;
case PEControl::RGB8_Z24:
case PixelFormat::RGB8_Z24:
EncodeRGB8(dst, src, params.copy_format, params.yuv);
break;
case PEControl::RGB565_Z16:
case PixelFormat::RGB565_Z16:
EncodeRGB8(dst, src, params.copy_format, params.yuv);
break;
case PEControl::Z24:
case PixelFormat::Z24:
EncodeZ24(dst, src, params.copy_format);
break;
default:
Expand Down
28 changes: 16 additions & 12 deletions Source/Core/VideoBackends/Software/TextureSampler.cpp
Expand Up @@ -8,6 +8,7 @@
#include <cmath>

#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "Core/HW/Memmap.h"

#include "VideoCommon/BPMemory.h"
Expand All @@ -18,27 +19,29 @@

namespace TextureSampler
{
static inline void WrapCoord(int* coordp, int wrapMode, int imageSize)
static inline void WrapCoord(int* coordp, WrapMode wrapMode, int imageSize)
{
int coord = *coordp;
switch (wrapMode)
{
case 0: // clamp
case WrapMode::Clamp:
coord = (coord > imageSize) ? imageSize : (coord < 0) ? 0 : coord;
break;
case 1: // wrap
case WrapMode::Repeat:
coord = coord % (imageSize + 1);
coord = (coord < 0) ? imageSize + coord : coord;
break;
case 2: // mirror
case WrapMode::Mirror:
{
const int sizePlus1 = imageSize + 1;
const int div = coord / sizePlus1;
coord = coord - (div * sizePlus1);
coord = (coord < 0) ? -coord : coord;
coord = (div & 1) ? imageSize - coord : coord;
break;
}
break;
default:
PanicAlertFmt("Invalid wrap mode: {}", wrapMode);
}
*coordp = coord;
}
Expand Down Expand Up @@ -74,10 +77,11 @@ void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8* sample)
{
// use mipmap
baseMip = lod >> 4;
mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR);
mipLinear = (lodFract && tm0.mipmap_filter == MipMode::Linear);

// if using nearest mip filter and lodFract >= 0.5 round up to next mip
baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT);
if (tm0.mipmap_filter == MipMode::Point && lodFract >= 8)
baseMip++;
}

if (mipLinear)
Expand Down Expand Up @@ -111,12 +115,12 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample)
const TexMode0& tm0 = texUnit.texMode0[subTexmap];
const TexImage0& ti0 = texUnit.texImage0[subTexmap];
const TexTLUT& texTlut = texUnit.texTlut[subTexmap];
const TextureFormat texfmt = static_cast<TextureFormat>(ti0.format);
const TLUTFormat tlutfmt = static_cast<TLUTFormat>(texTlut.tlut_format);
const TextureFormat texfmt = ti0.format;
const TLUTFormat tlutfmt = texTlut.tlut_format;

const u8* imageSrc;
const u8* imageSrcOdd = nullptr;
if (texUnit.texImage1[subTexmap].image_type)
if (texUnit.texImage1[subTexmap].cache_manually_managed)
{
imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE];
if (texfmt == TextureFormat::RGBA8)
Expand Down Expand Up @@ -188,7 +192,7 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample)
WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth);
WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight);

if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].image_type))
if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].cache_manually_managed))
{
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, texfmt, tlut,
tlutfmt);
Expand Down Expand Up @@ -240,7 +244,7 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample)
WrapCoord(&imageS, tm0.wrap_s, imageWidth);
WrapCoord(&imageT, tm0.wrap_t, imageHeight);

if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].image_type))
if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].cache_manually_managed))
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, texfmt, tlut, tlutfmt);
else
TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT,
Expand Down
88 changes: 45 additions & 43 deletions Source/Core/VideoBackends/Software/TransformUnit.cpp
Expand Up @@ -80,7 +80,7 @@ void TransformPosition(const InputVertexData* src, OutputVertexData* dst)
const float* mat = &xfmem.posMatrices[src->posMtx * 4];
MultiplyVec3Mat34(src->position, mat, dst->mvPosition);

if (xfmem.projection.type == GX_PERSPECTIVE)
if (xfmem.projection.type == ProjectionType::Perspective)
{
MultipleVec3Perspective(dst->mvPosition, xfmem.projection.rawProjection,
dst->projectedPosition);
Expand Down Expand Up @@ -115,39 +115,42 @@ static void TransformTexCoordRegular(const TexMtxInfo& texinfo, int coordNum,
Vec3 src;
switch (texinfo.sourcerow)
{
case XF_SRCGEOM_INROW:
case SourceRow::Geom:
src = srcVertex->position;
break;
case XF_SRCNORMAL_INROW:
case SourceRow::Normal:
src = srcVertex->normal[0];
break;
case XF_SRCBINORMAL_T_INROW:
case SourceRow::BinormalT:
src = srcVertex->normal[1];
break;
case XF_SRCBINORMAL_B_INROW:
case SourceRow::BinormalB:
src = srcVertex->normal[2];
break;
default:
ASSERT(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW);
src.x = srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW][0];
src.y = srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW][1];
{
ASSERT(texinfo.sourcerow >= SourceRow::Tex0 && texinfo.sourcerow <= SourceRow::Tex7);
u32 texnum = static_cast<u32>(texinfo.sourcerow.Value()) - static_cast<u32>(SourceRow::Tex0);
src.x = srcVertex->texCoords[texnum][0];
src.y = srcVertex->texCoords[texnum][1];
src.z = 1.0f;
break;
}
}

const float* mat = &xfmem.posMatrices[srcVertex->texMtx[coordNum] * 4];
Vec3* dst = &dstVertex->texCoords[coordNum];

if (texinfo.projection == XF_TEXPROJ_ST)
if (texinfo.projection == TexSize::ST)
{
if (texinfo.inputform == XF_TEXINPUT_AB11)
if (texinfo.inputform == TexInputForm::AB11)
MultiplyVec2Mat24(src, mat, *dst);
else
MultiplyVec3Mat24(src, mat, *dst);
}
else // texinfo.projection == XF_TEXPROJ_STQ
else // texinfo.projection == TexSize::STQ
{
if (texinfo.inputform == XF_TEXINPUT_AB11)
if (texinfo.inputform == TexInputForm::AB11)
MultiplyVec2Mat34(src, mat, *dst);
else
MultiplyVec3Mat34(src, mat, *dst);
Expand Down Expand Up @@ -209,28 +212,28 @@ static float CalculateLightAttn(const LightPointer* light, Vec3* _ldir, const Ve

switch (chan.attnfunc)
{
case LIGHTATTN_NONE:
case LIGHTATTN_DIR:
case AttenuationFunc::None:
case AttenuationFunc::Dir:
{
ldir = ldir.Normalized();
if (ldir == Vec3(0.0f, 0.0f, 0.0f))
ldir = normal;
break;
}
case LIGHTATTN_SPEC:
case AttenuationFunc::Spec:
{
ldir = ldir.Normalized();
attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0;
Vec3 attLen = Vec3(1.0, attn, attn * attn);
Vec3 cosAttn = light->cosatt;
Vec3 distAttn = light->distatt;
if (chan.diffusefunc != LIGHTDIF_NONE)
if (chan.diffusefunc != DiffuseFunc::None)
distAttn = distAttn.Normalized();

attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn);
break;
}
case LIGHTATTN_SPOT:
case AttenuationFunc::Spot:
{
float dist2 = ldir.Length2();
float dist = sqrtf(dist2);
Expand All @@ -243,7 +246,7 @@ static float CalculateLightAttn(const LightPointer* light, Vec3* _ldir, const Ve
break;
}
default:
PanicAlertFmt("LightColor");
PanicAlertFmt("Invalid attnfunc: {}", chan.attnfunc);
}

return attn;
Expand All @@ -260,18 +263,18 @@ static void LightColor(const Vec3& pos, const Vec3& normal, u8 lightNum, const L
float difAttn = ldir * normal;
switch (chan.diffusefunc)
{
case LIGHTDIF_NONE:
case DiffuseFunc::None:
AddScaledIntegerColor(light->color, attn, lightCol);
break;
case LIGHTDIF_SIGN:
case DiffuseFunc::Sign:
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
break;
case LIGHTDIF_CLAMP:
case DiffuseFunc::Clamp:
difAttn = std::max(0.0f, difAttn);
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
break;
default:
ASSERT(0);
PanicAlertFmt("Invalid diffusefunc: {}", chan.attnfunc);
}
}

Expand All @@ -286,18 +289,18 @@ static void LightAlpha(const Vec3& pos, const Vec3& normal, u8 lightNum, const L
float difAttn = ldir * normal;
switch (chan.diffusefunc)
{
case LIGHTDIF_NONE:
case DiffuseFunc::None:
lightCol += light->color[0] * attn;
break;
case LIGHTDIF_SIGN:
case DiffuseFunc::Sign:
lightCol += light->color[0] * attn * difAttn;
break;
case LIGHTDIF_CLAMP:
case DiffuseFunc::Clamp:
difAttn = std::max(0.0f, difAttn);
lightCol += light->color[0] * attn * difAttn;
break;
default:
ASSERT(0);
PanicAlertFmt("Invalid diffusefunc: {}", chan.attnfunc);
}
}

Expand All @@ -311,17 +314,16 @@ void TransformColor(const InputVertexData* src, OutputVertexData* dst)

// color
const LitChannel& colorchan = xfmem.color[chan];
if (colorchan.matsource)
matcolor = src->color[chan]; // vertex
if (colorchan.matsource == MatSource::Vertex)
matcolor = src->color[chan];
else
std::memcpy(matcolor.data(), &xfmem.matColor[chan], sizeof(u32));

if (colorchan.enablelighting)
{
Vec3 lightCol;
if (colorchan.ambsource)
if (colorchan.ambsource == AmbSource::Vertex)
{
// vertex
lightCol.x = src->color[chan][1];
lightCol.y = src->color[chan][2];
lightCol.z = src->color[chan][3];
Expand Down Expand Up @@ -355,16 +357,16 @@ void TransformColor(const InputVertexData* src, OutputVertexData* dst)

// alpha
const LitChannel& alphachan = xfmem.alpha[chan];
if (alphachan.matsource)
matcolor[0] = src->color[chan][0]; // vertex
if (alphachan.matsource == MatSource::Vertex)
matcolor[0] = src->color[chan][0];
else
matcolor[0] = xfmem.matColor[chan] & 0xff;

if (xfmem.alpha[chan].enablelighting)
{
float lightCol;
if (alphachan.ambsource)
lightCol = src->color[chan][0]; // vertex
if (alphachan.ambsource == AmbSource::Vertex)
lightCol = src->color[chan][0];
else
lightCol = static_cast<float>(xfmem.ambColor[chan] & 0xff);

Expand Down Expand Up @@ -397,10 +399,10 @@ void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst)

switch (texinfo.texgentype)
{
case XF_TEXGEN_REGULAR:
case TexGenType::Regular:
TransformTexCoordRegular(texinfo, coordNum, src, dst);
break;
case XF_TEXGEN_EMBOSS_MAP:
case TexGenType::EmbossMap:
{
const LightPointer* light = (const LightPointer*)&xfmem.lights[texinfo.embosslightshift];

Expand All @@ -413,22 +415,22 @@ void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst)
dst->texCoords[coordNum].z = dst->texCoords[texinfo.embosssourceshift].z;
}
break;
case XF_TEXGEN_COLOR_STRGBC0:
ASSERT(texinfo.sourcerow == XF_SRCCOLORS_INROW);
ASSERT(texinfo.inputform == XF_TEXINPUT_AB11);
case TexGenType::Color0:
ASSERT(texinfo.sourcerow == SourceRow::Colors);
ASSERT(texinfo.inputform == TexInputForm::AB11);
dst->texCoords[coordNum].x = (float)dst->color[0][0] / 255.0f;
dst->texCoords[coordNum].y = (float)dst->color[0][1] / 255.0f;
dst->texCoords[coordNum].z = 1.0f;
break;
case XF_TEXGEN_COLOR_STRGBC1:
ASSERT(texinfo.sourcerow == XF_SRCCOLORS_INROW);
ASSERT(texinfo.inputform == XF_TEXINPUT_AB11);
case TexGenType::Color1:
ASSERT(texinfo.sourcerow == SourceRow::Colors);
ASSERT(texinfo.inputform == TexInputForm::AB11);
dst->texCoords[coordNum].x = (float)dst->color[1][0] / 255.0f;
dst->texCoords[coordNum].y = (float)dst->color[1][1] / 255.0f;
dst->texCoords[coordNum].z = 1.0f;
break;
default:
ERROR_LOG_FMT(VIDEO, "Bad tex gen type {}", texinfo.texgentype.Value());
ERROR_LOG_FMT(VIDEO, "Bad tex gen type {}", texinfo.texgentype);
break;
}
}
Expand Down
50 changes: 26 additions & 24 deletions Source/Core/VideoBackends/Vulkan/VKPipeline.cpp
Expand Up @@ -52,13 +52,13 @@ GetVulkanRasterizationState(const RasterizationState& state)
depth_clamp, // VkBool32 depthClampEnable
VK_FALSE, // VkBool32 rasterizerDiscardEnable
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
cull_modes[state.cullmode], // VkCullModeFlags cullMode
VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace
VK_FALSE, // VkBool32 depthBiasEnable
0.0f, // float depthBiasConstantFactor
0.0f, // float depthBiasClamp
0.0f, // float depthBiasSlopeFactor
1.0f // float lineWidth
cull_modes[u32(state.cullmode.Value())], // VkCullModeFlags cullMode
VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace
VK_FALSE, // VkBool32 depthBiasEnable
0.0f, // float depthBiasConstantFactor
0.0f, // float depthBiasClamp
0.0f, // float depthBiasSlopeFactor
1.0f // float lineWidth
};
}

Expand All @@ -85,31 +85,32 @@ static VkPipelineDepthStencilStateCreateInfo GetVulkanDepthStencilState(const De
bool inverted_depth = !g_ActiveConfig.backend_info.bSupportsReversedDepthRange;
switch (state.func)
{
case ZMode::NEVER:
case CompareMode::Never:
compare_op = VK_COMPARE_OP_NEVER;
break;
case ZMode::LESS:
case CompareMode::Less:
compare_op = inverted_depth ? VK_COMPARE_OP_GREATER : VK_COMPARE_OP_LESS;
break;
case ZMode::EQUAL:
case CompareMode::Equal:
compare_op = VK_COMPARE_OP_EQUAL;
break;
case ZMode::LEQUAL:
case CompareMode::LEqual:
compare_op = inverted_depth ? VK_COMPARE_OP_GREATER_OR_EQUAL : VK_COMPARE_OP_LESS_OR_EQUAL;
break;
case ZMode::GREATER:
case CompareMode::Greater:
compare_op = inverted_depth ? VK_COMPARE_OP_LESS : VK_COMPARE_OP_GREATER;
break;
case ZMode::NEQUAL:
case CompareMode::NEqual:
compare_op = VK_COMPARE_OP_NOT_EQUAL;
break;
case ZMode::GEQUAL:
case CompareMode::GEqual:
compare_op = inverted_depth ? VK_COMPARE_OP_LESS_OR_EQUAL : VK_COMPARE_OP_GREATER_OR_EQUAL;
break;
case ZMode::ALWAYS:
case CompareMode::Always:
compare_op = VK_COMPARE_OP_ALWAYS;
break;
default:
PanicAlertFmt("Invalid compare mode {}", state.func);
compare_op = VK_COMPARE_OP_ALWAYS;
break;
}
Expand Down Expand Up @@ -150,10 +151,10 @@ static VkPipelineColorBlendAttachmentState GetVulkanAttachmentBlendState(const B
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_DST_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}};

vk_state.srcColorBlendFactor = src_factors[state.srcfactor];
vk_state.srcAlphaBlendFactor = src_factors[state.srcfactoralpha];
vk_state.dstColorBlendFactor = dst_factors[state.dstfactor];
vk_state.dstAlphaBlendFactor = dst_factors[state.dstfactoralpha];
vk_state.srcColorBlendFactor = src_factors[u32(state.srcfactor.Value())];
vk_state.srcAlphaBlendFactor = src_factors[u32(state.srcfactoralpha.Value())];
vk_state.dstColorBlendFactor = dst_factors[u32(state.dstfactor.Value())];
vk_state.dstAlphaBlendFactor = dst_factors[u32(state.dstfactoralpha.Value())];
}
else
{
Expand All @@ -169,10 +170,10 @@ static VkPipelineColorBlendAttachmentState GetVulkanAttachmentBlendState(const B
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_DST_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}};

vk_state.srcColorBlendFactor = src_factors[state.srcfactor];
vk_state.srcAlphaBlendFactor = src_factors[state.srcfactoralpha];
vk_state.dstColorBlendFactor = dst_factors[state.dstfactor];
vk_state.dstAlphaBlendFactor = dst_factors[state.dstfactoralpha];
vk_state.srcColorBlendFactor = src_factors[u32(state.srcfactor.Value())];
vk_state.srcAlphaBlendFactor = src_factors[u32(state.srcfactoralpha.Value())];
vk_state.dstColorBlendFactor = dst_factors[u32(state.dstfactor.Value())];
vk_state.dstAlphaBlendFactor = dst_factors[u32(state.dstfactoralpha.Value())];
}

if (state.colorupdate)
Expand Down Expand Up @@ -211,7 +212,8 @@ GetVulkanColorBlendState(const BlendingState& state,
vk_logic_op_enable = VK_FALSE;
}

VkLogicOp vk_logic_op = vk_logic_op_enable ? vk_logic_ops[state.logicmode] : VK_LOGIC_OP_CLEAR;
VkLogicOp vk_logic_op =
vk_logic_op_enable ? vk_logic_ops[u32(state.logicmode.Value())] : VK_LOGIC_OP_CLEAR;

VkPipelineColorBlendStateCreateInfo vk_state = {
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/VideoBackends/Vulkan/VKRenderer.cpp
Expand Up @@ -166,9 +166,9 @@ void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable

// Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha
// channel to 0xFF. This hopefully allows us to use the fast path in most cases.
if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16 ||
bpmem.zcontrol.pixel_format == PEControl::RGB8_Z24 ||
bpmem.zcontrol.pixel_format == PEControl::Z24)
if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16 ||
bpmem.zcontrol.pixel_format == PixelFormat::RGB8_Z24 ||
bpmem.zcontrol.pixel_format == PixelFormat::Z24)
{
// Force alpha writes, and clear the alpha channel. This is different to the other backends,
// where the existing values of the alpha channel are preserved.
Expand Down
48 changes: 22 additions & 26 deletions Source/Core/VideoCommon/BPFunctions.cpp
Expand Up @@ -184,8 +184,8 @@ void ClearScreen(const MathUtil::Rectangle<int>& rc)
auto pixel_format = bpmem.zcontrol.pixel_format;

// (1): Disable unused color channels
if (pixel_format == PEControl::RGB8_Z24 || pixel_format == PEControl::RGB565_Z16 ||
pixel_format == PEControl::Z24)
if (pixel_format == PixelFormat::RGB8_Z24 || pixel_format == PixelFormat::RGB565_Z16 ||
pixel_format == PixelFormat::Z24)
{
alphaEnable = false;
}
Expand All @@ -196,11 +196,11 @@ void ClearScreen(const MathUtil::Rectangle<int>& rc)
u32 z = bpmem.clearZValue;

// (2) drop additional accuracy
if (pixel_format == PEControl::RGBA6_Z24)
if (pixel_format == PixelFormat::RGBA6_Z24)
{
color = RGBA8ToRGBA6ToRGBA8(color);
}
else if (pixel_format == PEControl::RGB565_Z16)
else if (pixel_format == PixelFormat::RGB565_Z16)
{
color = RGBA8ToRGB565ToRGBA8(color);
z = Z24ToZ16ToZ24(z);
Expand Down Expand Up @@ -228,59 +228,58 @@ void OnPixelFormatChange()
const auto new_format = bpmem.zcontrol.pixel_format;
g_renderer->StorePixelFormat(new_format);

DEBUG_LOG_FMT(VIDEO, "pixelfmt: pixel={}, zc={}", static_cast<int>(new_format),
static_cast<int>(bpmem.zcontrol.zformat));
DEBUG_LOG_FMT(VIDEO, "pixelfmt: pixel={}, zc={}", new_format, bpmem.zcontrol.zformat);

// no need to reinterpret pixel data in these cases
if (new_format == old_format || old_format == PEControl::INVALID_FMT)
if (new_format == old_format || old_format == PixelFormat::INVALID_FMT)
return;

// Check for pixel format changes
switch (old_format)
{
case PEControl::RGB8_Z24:
case PEControl::Z24:
case PixelFormat::RGB8_Z24:
case PixelFormat::Z24:
{
// Z24 and RGB8_Z24 are treated equal, so just return in this case
if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24)
if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24)
return;

if (new_format == PEControl::RGBA6_Z24)
if (new_format == PixelFormat::RGBA6_Z24)
{
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB8ToRGBA6);
return;
}
else if (new_format == PEControl::RGB565_Z16)
else if (new_format == PixelFormat::RGB565_Z16)
{
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB8ToRGB565);
return;
}
}
break;

case PEControl::RGBA6_Z24:
case PixelFormat::RGBA6_Z24:
{
if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24)
if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24)
{
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGBA6ToRGB8);
return;
}
else if (new_format == PEControl::RGB565_Z16)
else if (new_format == PixelFormat::RGB565_Z16)
{
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGBA6ToRGB565);
return;
}
}
break;

case PEControl::RGB565_Z16:
case PixelFormat::RGB565_Z16:
{
if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24)
if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24)
{
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB565ToRGB8);
return;
}
else if (new_format == PEControl::RGBA6_Z24)
else if (new_format == PixelFormat::RGBA6_Z24)
{
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB565ToRGBA6);
return;
Expand All @@ -292,8 +291,7 @@ void OnPixelFormatChange()
break;
}

ERROR_LOG_FMT(VIDEO, "Unhandled EFB format change: {} to {}", static_cast<int>(old_format),
static_cast<int>(new_format));
ERROR_LOG_FMT(VIDEO, "Unhandled EFB format change: {} to {}", old_format, new_format);
}

void SetInterlacingMode(const BPCmd& bp)
Expand All @@ -305,17 +303,15 @@ void SetInterlacingMode(const BPCmd& bp)
{
// SDK always sets bpmem.lineptwidth.lineaspect via BPMEM_LINEPTWIDTH
// just before this cmd
static constexpr std::string_view action[] = {"don't adjust", "adjust"};
DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMODE texLOD:{} lineaspect:{}", action[bpmem.fieldmode.texLOD],
action[bpmem.lineptwidth.lineaspect]);
DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMODE texLOD:{} lineaspect:{}", bpmem.fieldmode.texLOD,
bpmem.lineptwidth.adjust_for_aspect_ratio);
}
break;
case BPMEM_FIELDMASK:
{
// Determines if fields will be written to EFB (always computed)
static constexpr std::string_view action[] = {"skip", "write"};
DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMASK even:{} odd:{}", action[bpmem.fieldmask.even],
action[bpmem.fieldmask.odd]);
DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMASK even:{} odd:{}", bpmem.fieldmask.even,
bpmem.fieldmask.odd);
}
break;
default:
Expand Down
28 changes: 17 additions & 11 deletions Source/Core/VideoCommon/BPMemory.cpp
Expand Up @@ -17,7 +17,7 @@ bool BlendMode::UseLogicOp() const
return false;

// Fast path for Kirby's Return to Dreamland, they use it with dstAlpha.
if (logicmode == BlendMode::NOOP)
if (logicmode == LogicOp::NoOp)
return false;

return true;
Expand Down Expand Up @@ -47,16 +47,26 @@ bool FogParams::IsNaNCase() const
return a.exp == 255 && c_proj_fsel.c_exp == 255;
}

float FogParam0::FloatValue() const
{
// scale mantissa from 11 to 23 bits
const u32 integral = (sign << 31) | (exp << 23) | (mant << 12);
return Common::BitCast<float>(integral);
}

float FogParam3::FloatValue() const
{
// scale mantissa from 11 to 23 bits
const u32 integral = (c_sign << 31) | (c_exp << 23) | (c_mant << 12);
return Common::BitCast<float>(integral);
}

float FogParams::GetA() const
{
if (IsNaNCase())
return 0.0f;

// scale mantissa from 11 to 23 bits
const u32 integral = (static_cast<u32>(a.sign) << 31) | (static_cast<u32>(a.exp) << 23) |
(static_cast<u32>(a.mant) << 12);

return Common::BitCast<float>(integral);
return a.FloatValue();
}

float FogParams::GetC() const
Expand All @@ -67,9 +77,5 @@ float FogParams::GetC() const
return !a.sign && !c_proj_fsel.c_sign ? -inf : inf;
}

// scale mantissa from 11 to 23 bits
const u32 integral = (c_proj_fsel.c_sign.Value() << 31) | (c_proj_fsel.c_exp.Value() << 23) |
(c_proj_fsel.c_mant.Value() << 12);

return Common::BitCast<float>(integral);
return c_proj_fsel.FloatValue();
}
1,776 changes: 1,325 additions & 451 deletions Source/Core/VideoCommon/BPMemory.h

Large diffs are not rendered by default.

715 changes: 274 additions & 441 deletions Source/Core/VideoCommon/BPStructs.cpp

Large diffs are not rendered by default.

45 changes: 44 additions & 1 deletion Source/Core/VideoCommon/CPMemory.cpp
Expand Up @@ -17,7 +17,9 @@ void DoCPState(PointerWrap& p)
p.DoArray(g_main_cp_state.array_strides);
p.Do(g_main_cp_state.matrix_index_a);
p.Do(g_main_cp_state.matrix_index_b);
p.Do(g_main_cp_state.vtx_desc.Hex);
u64 vtx_desc = g_main_cp_state.vtx_desc.GetLegacyHex();
p.Do(vtx_desc);
g_main_cp_state.vtx_desc.SetLegacyHex(vtx_desc);
p.DoArray(g_main_cp_state.vtx_attr);
p.DoMarker("CP Memory");
if (p.mode == PointerWrap::MODE_READ)
Expand All @@ -31,3 +33,44 @@ void CopyPreprocessCPStateFromMain()
{
memcpy(&g_preprocess_cp_state, &g_main_cp_state, sizeof(CPState));
}

std::pair<std::string, std::string> GetCPRegInfo(u8 cmd, u32 value)
{
switch (cmd & CP_COMMAND_MASK)
{
case MATINDEX_A:
return std::make_pair("MATINDEX_A", fmt::to_string(TMatrixIndexA{.Hex = value}));
case MATINDEX_B:
return std::make_pair("MATINDEX_B", fmt::to_string(TMatrixIndexB{.Hex = value}));
case VCD_LO:
return std::make_pair("VCD_LO", fmt::to_string(TVtxDesc::Low{.Hex = value}));
case VCD_HI:
return std::make_pair("VCD_HI", fmt::to_string(TVtxDesc::High{.Hex = value}));
case CP_VAT_REG_A:
if (cmd - CP_VAT_REG_A >= CP_NUM_VAT_REG)
return std::make_pair("CP_VAT_REG_A invalid", "");

return std::make_pair(fmt::format("CP_VAT_REG_A - Format {}", cmd & CP_VAT_MASK),
fmt::to_string(UVAT_group0{.Hex = value}));
case CP_VAT_REG_B:
if (cmd - CP_VAT_REG_B >= CP_NUM_VAT_REG)
return std::make_pair("CP_VAT_REG_B invalid", "");

return std::make_pair(fmt::format("CP_VAT_REG_B - Format {}", cmd & CP_VAT_MASK),
fmt::to_string(UVAT_group1{.Hex = value}));
case CP_VAT_REG_C:
if (cmd - CP_VAT_REG_C >= CP_NUM_VAT_REG)
return std::make_pair("CP_VAT_REG_C invalid", "");

return std::make_pair(fmt::format("CP_VAT_REG_C - Format {}", cmd & CP_VAT_MASK),
fmt::to_string(UVAT_group2{.Hex = value}));
case ARRAY_BASE:
return std::make_pair(fmt::format("ARRAY_BASE Array {}", cmd & CP_ARRAY_MASK),
fmt::format("Base address {:08x}", value));
case ARRAY_STRIDE:
return std::make_pair(fmt::format("ARRAY_STRIDE Array {}", cmd - ARRAY_STRIDE),
fmt::format("Stride {:02x}", value & 0xff));
default:
return std::make_pair(fmt::format("Invalid CP register {:02x} = {:08x}", cmd, value), "");
}
}
580 changes: 429 additions & 151 deletions Source/Core/VideoCommon/CPMemory.h

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions Source/Core/VideoCommon/ConstantManager.h
Expand Up @@ -13,6 +13,9 @@ using float4 = std::array<float, 4>;
using uint4 = std::array<u32, 4>;
using int4 = std::array<s32, 4>;

enum class SrcBlendFactor : u32;
enum class DstBlendFactor : u32;

struct PixelShaderConstants
{
std::array<int4, 4> colors;
Expand Down Expand Up @@ -45,10 +48,10 @@ struct PixelShaderConstants
std::array<int4, 32> konst; // .rgba
// The following are used in ubershaders when using shader_framebuffer_fetch blending
u32 blend_enable;
u32 blend_src_factor;
u32 blend_src_factor_alpha;
u32 blend_dst_factor;
u32 blend_dst_factor_alpha;
SrcBlendFactor blend_src_factor;
SrcBlendFactor blend_src_factor_alpha;
DstBlendFactor blend_dst_factor;
DstBlendFactor blend_dst_factor_alpha;
u32 blend_subtract;
u32 blend_subtract_alpha;
};
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoCommon/GeometryShaderManager.cpp
Expand Up @@ -45,7 +45,7 @@ void GeometryShaderManager::SetConstants()
{
s_projection_changed = false;

if (xfmem.projection.type == GX_PERSPECTIVE)
if (xfmem.projection.type == ProjectionType::Perspective)
{
float offset = (g_ActiveConfig.iStereoDepth / 1000.0f) *
(g_ActiveConfig.iStereoDepthPercentage / 100.0f);
Expand Down
41 changes: 22 additions & 19 deletions Source/Core/VideoCommon/LightingShaderGen.cpp
Expand Up @@ -17,29 +17,32 @@ static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_d
const char* swizzle = alpha ? "a" : "rgb";
const char* swizzle_components = (alpha) ? "" : "3";

const u32 attnfunc = (uid_data.attnfunc >> (2 * litchan_index)) & 0x3;
const u32 diffusefunc = (uid_data.diffusefunc >> (2 * litchan_index)) & 0x3;
const auto attnfunc =
static_cast<AttenuationFunc>((uid_data.attnfunc >> (2 * litchan_index)) & 0x3);
const auto diffusefunc =
static_cast<DiffuseFunc>((uid_data.diffusefunc >> (2 * litchan_index)) & 0x3);

switch (attnfunc)
{
case LIGHTATTN_NONE:
case LIGHTATTN_DIR:
case AttenuationFunc::None:
case AttenuationFunc::Dir:
object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index));
object.Write("attn = 1.0;\n");
object.Write("if (length(ldir) == 0.0)\n\t ldir = _norm0;\n");
break;
case LIGHTATTN_SPEC:
case AttenuationFunc::Spec:
object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index));
object.Write("attn = (dot(_norm0, ldir) >= 0.0) ? max(0.0, dot(_norm0, " LIGHT_DIR
".xyz)) : 0.0;\n",
LIGHT_DIR_PARAMS(index));
object.Write("cosAttn = " LIGHT_COSATT ".xyz;\n", LIGHT_COSATT_PARAMS(index));
object.Write("distAttn = {}(" LIGHT_DISTATT ".xyz);\n",
(diffusefunc == LIGHTDIF_NONE) ? "" : "normalize", LIGHT_DISTATT_PARAMS(index));
(diffusefunc == DiffuseFunc::None) ? "" : "normalize",
LIGHT_DISTATT_PARAMS(index));
object.Write("attn = max(0.0f, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
"float3(1.0, attn, attn*attn));\n");
break;
case LIGHTATTN_SPOT:
case AttenuationFunc::Spot:
object.Write("ldir = " LIGHT_POS ".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(index));
object.Write("dist2 = dot(ldir, ldir);\n"
"dist = sqrt(dist2);\n"
Expand All @@ -56,14 +59,14 @@ static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_d

switch (diffusefunc)
{
case LIGHTDIF_NONE:
case DiffuseFunc::None:
object.Write("lacc.{} += int{}(round(attn * float{}(" LIGHT_COL ")));\n", swizzle,
swizzle_components, swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
break;
case LIGHTDIF_SIGN:
case LIGHTDIF_CLAMP:
case DiffuseFunc::Sign:
case DiffuseFunc::Clamp:
object.Write("lacc.{} += int{}(round(attn * {}dot(ldir, _norm0)) * float{}(" LIGHT_COL ")));\n",
swizzle, swizzle_components, diffusefunc != LIGHTDIF_SIGN ? "max(0.0," : "(",
swizzle, swizzle_components, diffusefunc != DiffuseFunc::Sign ? "max(0.0," : "(",
swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
break;
default:
Expand Down Expand Up @@ -151,23 +154,23 @@ void GetLightingShaderUid(LightingUidData& uid_data)
{
for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++)
{
uid_data.matsource |= xfmem.color[j].matsource << j;
uid_data.matsource |= xfmem.alpha[j].matsource << (j + 2);
uid_data.matsource |= static_cast<u32>(xfmem.color[j].matsource.Value()) << j;
uid_data.matsource |= static_cast<u32>(xfmem.alpha[j].matsource.Value()) << (j + 2);
uid_data.enablelighting |= xfmem.color[j].enablelighting << j;
uid_data.enablelighting |= xfmem.alpha[j].enablelighting << (j + 2);

if ((uid_data.enablelighting & (1 << j)) != 0) // Color lights
{
uid_data.ambsource |= xfmem.color[j].ambsource << j;
uid_data.attnfunc |= xfmem.color[j].attnfunc << (2 * j);
uid_data.diffusefunc |= xfmem.color[j].diffusefunc << (2 * j);
uid_data.ambsource |= static_cast<u32>(xfmem.color[j].ambsource.Value()) << j;
uid_data.attnfunc |= static_cast<u32>(xfmem.color[j].attnfunc.Value()) << (2 * j);
uid_data.diffusefunc |= static_cast<u32>(xfmem.color[j].diffusefunc.Value()) << (2 * j);
uid_data.light_mask |= xfmem.color[j].GetFullLightMask() << (8 * j);
}
if ((uid_data.enablelighting & (1 << (j + 2))) != 0) // Alpha lights
{
uid_data.ambsource |= xfmem.alpha[j].ambsource << (j + 2);
uid_data.attnfunc |= xfmem.alpha[j].attnfunc << (2 * (j + 2));
uid_data.diffusefunc |= xfmem.alpha[j].diffusefunc << (2 * (j + 2));
uid_data.ambsource |= static_cast<u32>(xfmem.alpha[j].ambsource.Value()) << (j + 2);
uid_data.attnfunc |= static_cast<u32>(xfmem.alpha[j].attnfunc.Value()) << (2 * (j + 2));
uid_data.diffusefunc |= static_cast<u32>(xfmem.alpha[j].diffusefunc.Value()) << (2 * (j + 2));
uid_data.light_mask |= xfmem.alpha[j].GetFullLightMask() << (8 * (j + 2));
}
}
Expand Down
313 changes: 163 additions & 150 deletions Source/Core/VideoCommon/PixelShaderGen.cpp

Large diffs are not rendered by default.

41 changes: 25 additions & 16 deletions Source/Core/VideoCommon/PixelShaderGen.h
Expand Up @@ -9,6 +9,15 @@
#include "VideoCommon/ShaderGenCommon.h"

enum class APIType;
enum class AlphaTestResult;
enum class SrcBlendFactor : u32;
enum class DstBlendFactor : u32;
enum class CompareMode : u32;
enum class AlphaTestOp : u32;
enum class RasColorChan : u32;
enum class KonstSel : u32;
enum class FogProjection : u32;
enum class FogType : u32;

#pragma pack(1)
struct pixel_shader_uid_data
Expand All @@ -19,18 +28,18 @@ struct pixel_shader_uid_data
u32 NumValues() const { return num_values; }
u32 pad0 : 4;
u32 useDstAlpha : 1;
u32 Pretest : 2;
AlphaTestResult Pretest : 2;
u32 nIndirectStagesUsed : 4;
u32 genMode_numtexgens : 4;
u32 genMode_numtevstages : 4;
u32 genMode_numindstages : 3;
u32 alpha_test_comp0 : 3;
u32 alpha_test_comp1 : 3;
u32 alpha_test_logic : 2;
CompareMode alpha_test_comp0 : 3;
CompareMode alpha_test_comp1 : 3;
AlphaTestOp alpha_test_logic : 2;
u32 alpha_test_use_zcomploc_hack : 1;
u32 fog_proj : 1;
FogProjection fog_proj : 1;

u32 fog_fsel : 3;
FogType fog_fsel : 3;
u32 fog_RangeBaseEnabled : 1;
u32 ztex_op : 2;
u32 per_pixel_depth : 1;
Expand All @@ -43,13 +52,13 @@ struct pixel_shader_uid_data
u32 rgba6_format : 1;
u32 dither : 1;
u32 uint_output : 1;
u32 blend_enable : 1; // Only used with shader_framebuffer_fetch blend
u32 blend_src_factor : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_src_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_dst_factor : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_dst_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_subtract : 1; // Only used with shader_framebuffer_fetch blend
u32 blend_subtract_alpha : 1; // Only used with shader_framebuffer_fetch blend
u32 blend_enable : 1; // Only used with shader_framebuffer_fetch blend
SrcBlendFactor blend_src_factor : 3; // Only used with shader_framebuffer_fetch blend
SrcBlendFactor blend_src_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend
DstBlendFactor blend_dst_factor : 3; // Only used with shader_framebuffer_fetch blend
DstBlendFactor blend_dst_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_subtract : 1; // Only used with shader_framebuffer_fetch blend
u32 blend_subtract_alpha : 1; // Only used with shader_framebuffer_fetch blend

u32 texMtxInfo_n_projection : 8; // 8x1 bit
u32 tevindref_bi0 : 3;
Expand Down Expand Up @@ -136,7 +145,7 @@ struct pixel_shader_uid_data
u32 tevorders_texmap : 3;
u32 tevorders_texcoord : 3;
u32 tevorders_enable : 1;
u32 tevorders_colorchan : 3;
RasColorChan tevorders_colorchan : 3;
u32 pad1 : 6;

// TODO: Clean up the swapXY mess
Expand All @@ -152,8 +161,8 @@ struct pixel_shader_uid_data
u32 tevksel_swap2c : 2;
u32 tevksel_swap1d : 2;
u32 tevksel_swap2d : 2;
u32 tevksel_kc : 5;
u32 tevksel_ka : 5;
KonstSel tevksel_kc : 5;
KonstSel tevksel_ka : 5;
u32 pad3 : 14;
} stagehash[16];

Expand Down
16 changes: 9 additions & 7 deletions Source/Core/VideoCommon/PixelShaderManager.cpp
Expand Up @@ -182,7 +182,7 @@ void PixelShaderManager::SetConstants()
// Destination alpha is only enabled if alpha writes are enabled. Force entire uniform to zero
// when disabled.
u32 dstalpha = bpmem.blendmode.alphaupdate && bpmem.dstalpha.enable &&
bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 ?
bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24 ?
bpmem.dstalpha.hex :
0;

Expand Down Expand Up @@ -270,7 +270,7 @@ void PixelShaderManager::SetAlphaTestChanged()
// TODO: we could optimize this further and check the actual constants,
// i.e. "a <= 0" and "a >= 255" will always pass.
u32 alpha_test =
bpmem.alpha_test.TestResult() != AlphaTest::PASS ? bpmem.alpha_test.hex | 1 << 31 : 0;
bpmem.alpha_test.TestResult() != AlphaTestResult::Pass ? bpmem.alpha_test.hex | 1 << 31 : 0;
if (constants.alphaTest != alpha_test)
{
constants.alphaTest = alpha_test;
Expand Down Expand Up @@ -362,25 +362,26 @@ void PixelShaderManager::SetZTextureTypeChanged()
{
switch (bpmem.ztex2.type)
{
case TEV_ZTEX_TYPE_U8:
case ZTexFormat::U8:
constants.zbias[0][0] = 0;
constants.zbias[0][1] = 0;
constants.zbias[0][2] = 0;
constants.zbias[0][3] = 1;
break;
case TEV_ZTEX_TYPE_U16:
case ZTexFormat::U16:
constants.zbias[0][0] = 1;
constants.zbias[0][1] = 0;
constants.zbias[0][2] = 0;
constants.zbias[0][3] = 256;
break;
case TEV_ZTEX_TYPE_U24:
case ZTexFormat::U24:
constants.zbias[0][0] = 65536;
constants.zbias[0][1] = 256;
constants.zbias[0][2] = 1;
constants.zbias[0][3] = 0;
break;
default:
PanicAlertFmt("Invalid ztex format {}", bpmem.ztex2.type);
break;
}
dirty = true;
Expand Down Expand Up @@ -457,8 +458,9 @@ void PixelShaderManager::SetZModeControl()
{
u32 late_ztest = bpmem.UseLateDepthTest();
u32 rgba6_format =
(bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor) ? 1 :
0;
(bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor) ?
1 :
0;
u32 dither = rgba6_format && bpmem.blendmode.dither;
if (constants.late_ztest != late_ztest || constants.rgba6_format != rgba6_format ||
constants.dither != dither)
Expand Down
20 changes: 10 additions & 10 deletions Source/Core/VideoCommon/RenderBase.cpp
Expand Up @@ -171,7 +171,7 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,

bool Renderer::EFBHasAlphaChannel() const
{
return m_prev_efb_format == PEControl::RGBA6_Z24;
return m_prev_efb_format == PixelFormat::RGBA6_Z24;
}

void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
Expand All @@ -197,15 +197,15 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
// check what to do with the alpha channel (GX_PokeAlphaRead)
PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode();

if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)
if (bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24)
{
color = RGBA8ToRGBA6ToRGBA8(color);
}
else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16)
else if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16)
{
color = RGBA8ToRGB565ToRGBA8(color);
}
if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24)
if (bpmem.zcontrol.pixel_format != PixelFormat::RGBA6_Z24)
{
color |= 0xFF000000;
}
Expand All @@ -231,7 +231,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
depth = 1.0f - depth;

u32 ret = 0;
if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16)
if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16)
{
// if Z is in 16 bit format you must return a 16 bit integer
ret = std::clamp<u32>(static_cast<u32>(depth * 65536.0f), 0, 0xFFFF);
Expand Down Expand Up @@ -994,10 +994,10 @@ bool Renderer::RecompileImGuiPipeline()
pconfig.depth_state = RenderState::GetNoDepthTestingDepthState();
pconfig.blending_state = RenderState::GetNoBlendingBlendState();
pconfig.blending_state.blendenable = true;
pconfig.blending_state.srcfactor = BlendMode::SRCALPHA;
pconfig.blending_state.dstfactor = BlendMode::INVSRCALPHA;
pconfig.blending_state.srcfactoralpha = BlendMode::ZERO;
pconfig.blending_state.dstfactoralpha = BlendMode::ONE;
pconfig.blending_state.srcfactor = SrcBlendFactor::SrcAlpha;
pconfig.blending_state.dstfactor = DstBlendFactor::InvSrcAlpha;
pconfig.blending_state.srcfactoralpha = SrcBlendFactor::Zero;
pconfig.blending_state.dstfactoralpha = DstBlendFactor::One;
pconfig.framebuffer_state.color_texture_format = m_backbuffer_format;
pconfig.framebuffer_state.depth_texture_format = AbstractTextureFormat::Undefined;
pconfig.framebuffer_state.samples = 1;
Expand Down Expand Up @@ -1697,7 +1697,7 @@ bool Renderer::UseVertexDepthRange() const
return false;

// We need a full depth range if a ztexture is used.
if (bpmem.ztex2.type != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest)
if (bpmem.ztex2.op != ZTexOp::Disabled && !bpmem.zcontrol.early_ztest)
return true;

// If an inverted depth range is unsupported, we also need to check if the range is inverted.
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/VideoCommon/RenderBase.h
Expand Up @@ -232,8 +232,8 @@ class Renderer
// Called when the configuration changes, and backend structures need to be updated.
virtual void OnConfigChanged(u32 bits) {}

PEControl::PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; }
void StorePixelFormat(PEControl::PixelFormat new_format) { m_prev_efb_format = new_format; }
PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; }
void StorePixelFormat(PixelFormat new_format) { m_prev_efb_format = new_format; }
bool EFBHasAlphaChannel() const;
VideoCommon::PostProcessing* GetPostProcessor() const { return m_post_processor.get(); }
// Final surface changing
Expand Down Expand Up @@ -343,7 +343,7 @@ class Renderer
private:
std::tuple<int, int> CalculateOutputDimensions(int width, int height) const;

PEControl::PixelFormat m_prev_efb_format = PEControl::INVALID_FMT;
PixelFormat m_prev_efb_format = PixelFormat::INVALID_FMT;
unsigned int m_efb_scale = 1;

// These will be set on the first call to SetWindowSize.
Expand Down
152 changes: 83 additions & 69 deletions Source/Core/VideoCommon/RenderState.cpp
Expand Up @@ -15,7 +15,7 @@ void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_ty

// Back-face culling should be disabled for points/lines.
if (primitive_type != PrimitiveType::Triangles && primitive_type != PrimitiveType::TriangleStrip)
cullmode = GenMode::CULL_NONE;
cullmode = CullMode::None;
}

RasterizationState& RasterizationState::operator=(const RasterizationState& rhs)
Expand Down Expand Up @@ -47,14 +47,27 @@ DepthState& DepthState::operator=(const DepthState& rhs)
// ONE on blending. As the backends may emulate this framebuffer
// configuration with an alpha channel, we just drop all references
// to the destination alpha channel.
static BlendMode::BlendFactor RemoveDstAlphaUsage(BlendMode::BlendFactor factor)
static SrcBlendFactor RemoveDstAlphaUsage(SrcBlendFactor factor)
{
switch (factor)
{
case BlendMode::DSTALPHA:
return BlendMode::ONE;
case BlendMode::INVDSTALPHA:
return BlendMode::ZERO;
case SrcBlendFactor::DstAlpha:
return SrcBlendFactor::One;
case SrcBlendFactor::InvDstAlpha:
return SrcBlendFactor::Zero;
default:
return factor;
}
}

static DstBlendFactor RemoveDstAlphaUsage(DstBlendFactor factor)
{
switch (factor)
{
case DstBlendFactor::DstAlpha:
return DstBlendFactor::One;
case DstBlendFactor::InvDstAlpha:
return DstBlendFactor::Zero;
default:
return factor;
}
Expand All @@ -64,29 +77,29 @@ static BlendMode::BlendFactor RemoveDstAlphaUsage(BlendMode::BlendFactor factor)
// the alpha component, CLR and ALPHA are indentical. So just always
// use ALPHA as this makes it easier for the backends to use the second
// alpha value of dual source blending.
static BlendMode::BlendFactor RemoveSrcColorUsage(BlendMode::BlendFactor factor)
static DstBlendFactor RemoveSrcColorUsage(DstBlendFactor factor)
{
switch (factor)
{
case BlendMode::SRCCLR:
return BlendMode::SRCALPHA;
case BlendMode::INVSRCCLR:
return BlendMode::INVSRCALPHA;
case DstBlendFactor::SrcClr:
return DstBlendFactor::SrcAlpha;
case DstBlendFactor::InvSrcClr:
return DstBlendFactor::InvSrcAlpha;
default:
return factor;
}
}

// Same as RemoveSrcColorUsage, but because of the overlapping enum,
// this must be written as another function.
static BlendMode::BlendFactor RemoveDstColorUsage(BlendMode::BlendFactor factor)
static SrcBlendFactor RemoveDstColorUsage(SrcBlendFactor factor)
{
switch (factor)
{
case BlendMode::DSTCLR:
return BlendMode::DSTALPHA;
case BlendMode::INVDSTCLR:
return BlendMode::INVDSTALPHA;
case SrcBlendFactor::DstClr:
return SrcBlendFactor::DstAlpha;
case SrcBlendFactor::InvDstClr:
return SrcBlendFactor::InvDstAlpha;
default:
return factor;
}
Expand All @@ -97,11 +110,11 @@ void BlendingState::Generate(const BPMemory& bp)
// Start with everything disabled.
hex = 0;

bool target_has_alpha = bp.zcontrol.pixel_format == PEControl::RGBA6_Z24;
bool alpha_test_may_success = bp.alpha_test.TestResult() != AlphaTest::FAIL;
bool target_has_alpha = bp.zcontrol.pixel_format == PixelFormat::RGBA6_Z24;
bool alpha_test_may_succeed = bp.alpha_test.TestResult() != AlphaTestResult::Fail;

colorupdate = bp.blendmode.colorupdate && alpha_test_may_success;
alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_success;
colorupdate = bp.blendmode.colorupdate && alpha_test_may_succeed;
alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_succeed;
dstalpha = bp.dstalpha.enable && alphaupdate;
usedualsrc = true;

Expand All @@ -110,14 +123,14 @@ void BlendingState::Generate(const BPMemory& bp)
{
blendenable = true;
subtractAlpha = subtract = true;
srcfactoralpha = srcfactor = BlendMode::ONE;
dstfactoralpha = dstfactor = BlendMode::ONE;
srcfactoralpha = srcfactor = SrcBlendFactor::One;
dstfactoralpha = dstfactor = DstBlendFactor::One;

if (dstalpha)
{
subtractAlpha = false;
srcfactoralpha = BlendMode::ONE;
dstfactoralpha = BlendMode::ZERO;
srcfactoralpha = SrcBlendFactor::One;
dstfactoralpha = DstBlendFactor::Zero;
}
}

Expand All @@ -133,22 +146,22 @@ void BlendingState::Generate(const BPMemory& bp)
srcfactor = RemoveDstAlphaUsage(srcfactor);
dstfactor = RemoveDstAlphaUsage(dstfactor);
}
// replaces SRCCLR with SRCALPHA and DSTCLR with DSTALPHA, it is important to
// replaces SrcClr with SrcAlpha and DstClr with DstAlpha, it is important to
// use the dst function for the src factor and vice versa
srcfactoralpha = RemoveDstColorUsage(srcfactor);
dstfactoralpha = RemoveSrcColorUsage(dstfactor);

if (dstalpha)
{
srcfactoralpha = BlendMode::ONE;
dstfactoralpha = BlendMode::ZERO;
srcfactoralpha = SrcBlendFactor::One;
dstfactoralpha = DstBlendFactor::Zero;
}
}

// The logicop bit has the lowest priority
else if (bp.blendmode.logicopenable)
{
if (bp.blendmode.logicmode == BlendMode::NOOP)
if (bp.blendmode.logicmode == LogicOp::NoOp)
{
// Fast path for Kirby's Return to Dreamland, they use it with dstAlpha.
colorupdate = false;
Expand All @@ -169,38 +182,39 @@ void BlendingState::Generate(const BPMemory& bp)

void BlendingState::ApproximateLogicOpWithBlending()
{
// Any of these which use SRC as srcFactor or DST as dstFactor won't be correct.
// This is because the two are aliased to one another (see the enum).
struct LogicOpApproximation
{
bool subtract;
BlendMode::BlendFactor srcfactor;
BlendMode::BlendFactor dstfactor;
SrcBlendFactor srcfactor;
DstBlendFactor dstfactor;
};
// TODO: This previously had a warning about SRC and DST being aliased and not to mix them,
// but INVSRCCLR and INVDSTCLR were also aliased and were mixed.
// Thus, NOR, EQUIV, INVERT, COPY_INVERTED, and OR_INVERTED duplicate(d) other values.
static constexpr std::array<LogicOpApproximation, 16> approximations = {{
{false, BlendMode::ZERO, BlendMode::ZERO}, // CLEAR
{false, BlendMode::DSTCLR, BlendMode::ZERO}, // AND
{true, BlendMode::ONE, BlendMode::INVSRCCLR}, // AND_REVERSE
{false, BlendMode::ONE, BlendMode::ZERO}, // COPY
{true, BlendMode::DSTCLR, BlendMode::ONE}, // AND_INVERTED
{false, BlendMode::ZERO, BlendMode::ONE}, // NOOP
{false, BlendMode::INVDSTCLR, BlendMode::INVSRCCLR}, // XOR
{false, BlendMode::INVDSTCLR, BlendMode::ONE}, // OR
{false, BlendMode::INVSRCCLR, BlendMode::INVDSTCLR}, // NOR
{false, BlendMode::INVSRCCLR, BlendMode::ZERO}, // EQUIV
{false, BlendMode::INVDSTCLR, BlendMode::INVDSTCLR}, // INVERT
{false, BlendMode::ONE, BlendMode::INVDSTALPHA}, // OR_REVERSE
{false, BlendMode::INVSRCCLR, BlendMode::INVSRCCLR}, // COPY_INVERTED
{false, BlendMode::INVSRCCLR, BlendMode::ONE}, // OR_INVERTED
{false, BlendMode::INVDSTCLR, BlendMode::INVSRCCLR}, // NAND
{false, BlendMode::ONE, BlendMode::ONE}, // SET
{false, SrcBlendFactor::Zero, DstBlendFactor::Zero}, // CLEAR
{false, SrcBlendFactor::DstClr, DstBlendFactor::Zero}, // AND
{true, SrcBlendFactor::One, DstBlendFactor::InvSrcClr}, // AND_REVERSE
{false, SrcBlendFactor::One, DstBlendFactor::Zero}, // COPY
{true, SrcBlendFactor::DstClr, DstBlendFactor::One}, // AND_INVERTED
{false, SrcBlendFactor::Zero, DstBlendFactor::One}, // NOOP
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // XOR
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::One}, // OR
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // NOR
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::Zero}, // EQUIV
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // INVERT
{false, SrcBlendFactor::One, DstBlendFactor::InvDstAlpha}, // OR_REVERSE
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // COPY_INVERTED
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::One}, // OR_INVERTED
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // NAND
{false, SrcBlendFactor::One, DstBlendFactor::One}, // SET
}};

logicopenable = false;
blendenable = true;
subtract = approximations[logicmode].subtract;
srcfactor = approximations[logicmode].srcfactor;
dstfactor = approximations[logicmode].dstfactor;
subtract = approximations[u32(logicmode.Value())].subtract;
srcfactor = approximations[u32(logicmode.Value())].srcfactor;
dstfactor = approximations[u32(logicmode.Value())].dstfactor;
}

BlendingState& BlendingState::operator=(const BlendingState& rhs)
Expand All @@ -217,20 +231,20 @@ void SamplerState::Generate(const BPMemory& bp, u32 index)

// GX can configure the mip filter to none. However, D3D and Vulkan can't express this in their
// sampler states. Therefore, we set the min/max LOD to zero if this option is used.
min_filter = (tm0.min_filter & 4) != 0 ? Filter::Linear : Filter::Point;
mipmap_filter = (tm0.min_filter & 3) == TexMode0::TEXF_LINEAR ? Filter::Linear : Filter::Point;
mag_filter = tm0.mag_filter != 0 ? Filter::Linear : Filter::Point;
min_filter = tm0.min_filter == FilterMode::Linear ? Filter::Linear : Filter::Point;
mipmap_filter = tm0.mipmap_filter == MipMode::Linear ? Filter::Linear : Filter::Point;
mag_filter = tm0.mag_filter == FilterMode::Linear ? Filter::Linear : Filter::Point;

// If mipmaps are disabled, clamp min/max lod
max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0;
max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod.Value() : 0;
min_lod = std::min(max_lod.Value(), static_cast<u64>(tm1.min_lod));
lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias * (256 / 32) : 0;

// Address modes
static constexpr std::array<AddressMode, 4> address_modes = {
{AddressMode::Clamp, AddressMode::Repeat, AddressMode::MirroredRepeat, AddressMode::Repeat}};
wrap_u = address_modes[tm0.wrap_s];
wrap_v = address_modes[tm0.wrap_t];
wrap_u = address_modes[u32(tm0.wrap_s.Value())];
wrap_v = address_modes[u32(tm0.wrap_t.Value())];
anisotropic_filtering = 0;
}

Expand All @@ -252,15 +266,15 @@ RasterizationState GetInvalidRasterizationState()
RasterizationState GetNoCullRasterizationState(PrimitiveType primitive)
{
RasterizationState state = {};
state.cullmode = GenMode::CULL_NONE;
state.cullmode = CullMode::None;
state.primitive = primitive;
return state;
}

RasterizationState GetCullBackFaceRasterizationState(PrimitiveType primitive)
{
RasterizationState state = {};
state.cullmode = GenMode::CULL_BACK;
state.cullmode = CullMode::Back;
state.primitive = primitive;
return state;
}
Expand All @@ -277,7 +291,7 @@ DepthState GetNoDepthTestingDepthState()
DepthState state = {};
state.testenable = false;
state.updateenable = false;
state.func = ZMode::ALWAYS;
state.func = CompareMode::Always;
return state;
}

Expand All @@ -286,7 +300,7 @@ DepthState GetAlwaysWriteDepthState()
DepthState state = {};
state.testenable = true;
state.updateenable = true;
state.func = ZMode::ALWAYS;
state.func = CompareMode::Always;
return state;
}

Expand All @@ -302,10 +316,10 @@ BlendingState GetNoBlendingBlendState()
BlendingState state = {};
state.usedualsrc = false;
state.blendenable = false;
state.srcfactor = BlendMode::ONE;
state.srcfactoralpha = BlendMode::ONE;
state.dstfactor = BlendMode::ZERO;
state.dstfactoralpha = BlendMode::ZERO;
state.srcfactor = SrcBlendFactor::One;
state.srcfactoralpha = SrcBlendFactor::One;
state.dstfactor = DstBlendFactor::Zero;
state.dstfactoralpha = DstBlendFactor::Zero;
state.logicopenable = false;
state.colorupdate = true;
state.alphaupdate = true;
Expand All @@ -317,10 +331,10 @@ BlendingState GetNoColorWriteBlendState()
BlendingState state = {};
state.usedualsrc = false;
state.blendenable = false;
state.srcfactor = BlendMode::ONE;
state.srcfactoralpha = BlendMode::ONE;
state.dstfactor = BlendMode::ZERO;
state.dstfactoralpha = BlendMode::ZERO;
state.srcfactor = SrcBlendFactor::One;
state.srcfactoralpha = SrcBlendFactor::One;
state.dstfactor = DstBlendFactor::Zero;
state.dstfactoralpha = DstBlendFactor::Zero;
state.logicopenable = false;
state.colorupdate = false;
state.alphaupdate = false;
Expand Down
14 changes: 7 additions & 7 deletions Source/Core/VideoCommon/RenderState.h
Expand Up @@ -28,7 +28,7 @@ union RasterizationState
bool operator==(const RasterizationState& rhs) const { return hex == rhs.hex; }
bool operator!=(const RasterizationState& rhs) const { return hex != rhs.hex; }
bool operator<(const RasterizationState& rhs) const { return hex < rhs.hex; }
BitField<0, 2, GenMode::CullMode> cullmode;
BitField<0, 2, CullMode> cullmode;
BitField<3, 2, PrimitiveType> primitive;

u32 hex;
Expand Down Expand Up @@ -59,7 +59,7 @@ union DepthState
bool operator<(const DepthState& rhs) const { return hex < rhs.hex; }
BitField<0, 1, u32> testenable;
BitField<1, 1, u32> updateenable;
BitField<2, 3, ZMode::CompareMode> func;
BitField<2, 3, CompareMode> func;

u32 hex;
};
Expand All @@ -85,11 +85,11 @@ union BlendingState
BitField<5, 1, u32> subtract;
BitField<6, 1, u32> subtractAlpha;
BitField<7, 1, u32> usedualsrc;
BitField<8, 3, BlendMode::BlendFactor> dstfactor;
BitField<11, 3, BlendMode::BlendFactor> srcfactor;
BitField<14, 3, BlendMode::BlendFactor> dstfactoralpha;
BitField<17, 3, BlendMode::BlendFactor> srcfactoralpha;
BitField<20, 4, BlendMode::LogicOp> logicmode;
BitField<8, 3, DstBlendFactor> dstfactor;
BitField<11, 3, SrcBlendFactor> srcfactor;
BitField<14, 3, DstBlendFactor> dstfactoralpha;
BitField<17, 3, SrcBlendFactor> srcfactoralpha;
BitField<20, 4, LogicOp> logicmode;

u32 hex;
};
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/VideoCommon/SamplerCommon.h
Expand Up @@ -16,13 +16,13 @@ namespace SamplerCommon
template <class T>
constexpr bool IsBpTexMode0PointFiltering(const T& tm0)
{
return tm0.min_filter < 4 && !tm0.mag_filter;
return tm0.min_filter == FilterMode::Near && tm0.mag_filter == FilterMode::Near;
}

// Check if the minification filter has mipmap based filtering modes enabled.
template <class T>
constexpr bool AreBpTexMode0MipmapsEnabled(const T& tm0)
{
return (tm0.min_filter & 3) != 0;
return tm0.mipmap_filter != MipMode::None;
}
} // namespace SamplerCommon
2 changes: 1 addition & 1 deletion Source/Core/VideoCommon/ShaderCache.cpp
Expand Up @@ -1115,7 +1115,7 @@ void ShaderCache::QueueUberShaderPipelines()
{
// uint_output is only ever enabled when logic ops are enabled.
config.blending_state.logicopenable = true;
config.blending_state.logicmode = BlendMode::AND;
config.blending_state.logicmode = LogicOp::And;
}

auto iter = m_gx_uber_pipeline_cache.find(config);
Expand Down
8 changes: 4 additions & 4 deletions Source/Core/VideoCommon/TextureCacheBase.cpp
Expand Up @@ -1187,12 +1187,12 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage)
const u32 address = (tex.texImage3[id].image_base /* & 0x1FFFFF*/) << 5;
u32 width = tex.texImage0[id].width + 1;
u32 height = tex.texImage0[id].height + 1;
const TextureFormat texformat = static_cast<TextureFormat>(tex.texImage0[id].format);
const TextureFormat texformat = tex.texImage0[id].format;
const u32 tlutaddr = tex.texTlut[id].tmem_offset << 9;
const TLUTFormat tlutfmt = static_cast<TLUTFormat>(tex.texTlut[id].tlut_format);
const TLUTFormat tlutfmt = tex.texTlut[id].tlut_format;
const bool use_mipmaps = SamplerCommon::AreBpTexMode0MipmapsEnabled(tex.texMode0[id]);
u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1;
const bool from_tmem = tex.texImage1[id].image_type != 0;
const bool from_tmem = tex.texImage1[id].cache_manually_managed != 0;
const u32 tmem_address_even = from_tmem ? tex.texImage1[id].tmem_even * TMEM_LINE_SIZE : 0;
const u32 tmem_address_odd = from_tmem ? tex.texImage2[id].tmem_odd * TMEM_LINE_SIZE : 0;

Expand Down Expand Up @@ -2204,7 +2204,7 @@ void TextureCacheBase::CopyRenderTargetToTexture(
if (copy_to_ram)
{
EFBCopyFilterCoefficients coefficients = GetRAMCopyFilterCoefficients(filter_coefficients);
PEControl::PixelFormat srcFormat = bpmem.zcontrol.pixel_format;
PixelFormat srcFormat = bpmem.zcontrol.pixel_format;
EFBCopyParams format(srcFormat, dstFormat, is_depth_copy, isIntensity,
NeedsCopyFilterInShader(coefficients));

Expand Down
6 changes: 3 additions & 3 deletions Source/Core/VideoCommon/TextureCacheBase.h
Expand Up @@ -50,8 +50,8 @@ struct TextureAndTLUTFormat

struct EFBCopyParams
{
EFBCopyParams(PEControl::PixelFormat efb_format_, EFBCopyFormat copy_format_, bool depth_,
bool yuv_, bool copy_filter_)
EFBCopyParams(PixelFormat efb_format_, EFBCopyFormat copy_format_, bool depth_, bool yuv_,
bool copy_filter_)
: efb_format(efb_format_), copy_format(copy_format_), depth(depth_), yuv(yuv_),
copy_filter(copy_filter_)
{
Expand All @@ -63,7 +63,7 @@ struct EFBCopyParams
std::tie(rhs.efb_format, rhs.copy_format, rhs.depth, rhs.yuv, rhs.copy_filter);
}

PEControl::PixelFormat efb_format;
PixelFormat efb_format;
EFBCopyFormat copy_format;
bool depth;
bool yuv;
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/VideoCommon/TextureConversionShader.cpp
Expand Up @@ -127,13 +127,13 @@ static void WriteSampleFunction(ShaderCode& code, const EFBCopyParams& params, A
{
switch (params.efb_format)
{
case PEControl::RGB8_Z24:
case PixelFormat::RGB8_Z24:
code.Write("RGBA8ToRGB8(");
break;
case PEControl::RGBA6_Z24:
case PixelFormat::RGBA6_Z24:
code.Write("RGBA8ToRGBA6(");
break;
case PEControl::RGB565_Z16:
case PixelFormat::RGB565_Z16:
code.Write("RGBA8ToRGB565(");
break;
default:
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoCommon/TextureConverterShaderGen.cpp
Expand Up @@ -19,7 +19,7 @@ TCShaderUid GetShaderUid(EFBCopyFormat dst_format, bool is_depth_copy, bool is_i

UidData* const uid_data = out.GetUidData();
uid_data->dst_format = dst_format;
uid_data->efb_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24;
uid_data->efb_has_alpha = bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24;
uid_data->is_depth_copy = is_depth_copy;
uid_data->is_intensity = is_intensity;
uid_data->scale_by_half = scale_by_half;
Expand Down
27 changes: 27 additions & 0 deletions Source/Core/VideoCommon/TextureDecoder.h
Expand Up @@ -6,6 +6,7 @@

#include <tuple>
#include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"

enum
{
Expand All @@ -32,8 +33,17 @@ enum class TextureFormat
// Special texture format used to represent YUVY xfb copies.
// They aren't really textures, but they share so much hardware and usecases that it makes sense
// to emulate them as part of texture cache.
// This isn't a real value that can be used on console; it only exists for ease of implementation.
XFB = 0xF,
};
template <>
struct fmt::formatter<TextureFormat> : EnumFormatter<TextureFormat::CMPR>
{
static constexpr array_type names = {"I4", "I8", "IA4", "IA8", "RGB565",
"RGB5A3", "RGBA8", nullptr, "C4", "C8",
"C14X2", nullptr, nullptr, nullptr, "CMPR"};
formatter() : EnumFormatter(names) {}
};

static inline bool IsColorIndexed(TextureFormat format)
{
Expand Down Expand Up @@ -82,8 +92,20 @@ enum class EFBCopyFormat
// Special texture format used to represent YUVY xfb copies.
// They aren't really textures, but they share so much hardware and usecases that it makes sense
// to emulate them as part of texture cache.
// This isn't a real value that can be used on console; it only exists for ease of implementation.
XFB = 0xF,
};
template <>
struct fmt::formatter<EFBCopyFormat> : EnumFormatter<EFBCopyFormat::GB8>
{
static constexpr array_type names = {
"R4/I4/Z4", "R8/I8/Z8H (?)", "RA4/IA4", "RA8/IA8 (Z16 too?)",
"RGB565", "RGB5A3", "RGBA8", "A8",
"R8/I8/Z8H", "G8/Z8M", "B8/Z8L", "RG8/Z16R (Note: G and R are reversed)",
"GB8/Z16L",
};
formatter() : EnumFormatter(names) {}
};

enum class TLUTFormat
{
Expand All @@ -92,6 +114,11 @@ enum class TLUTFormat
RGB565 = 0x1,
RGB5A3 = 0x2,
};
template <>
struct fmt::formatter<TLUTFormat> : EnumFormatter<TLUTFormat::RGB5A3>
{
formatter() : EnumFormatter({"IA8", "RGB565", "RGB5A3"}) {}
};

static inline bool IsValidTLUTFormat(TLUTFormat tlutfmt)
{
Expand Down
16 changes: 8 additions & 8 deletions Source/Core/VideoCommon/UberShaderCommon.cpp
Expand Up @@ -39,26 +39,26 @@ void WriteLightingFunction(ShaderCode& out)
" float dist, dist2, attn;\n"
"\n"
" switch (attnfunc) {{\n");
out.Write(" case {}u: // LIGNTATTN_NONE\n", LIGHTATTN_NONE);
out.Write(" case {}u: // LIGHTATTN_DIR\n", LIGHTATTN_DIR);
out.Write(" case {:s}:\n", AttenuationFunc::None);
out.Write(" case {:s}:\n", AttenuationFunc::Dir);
out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
" attn = 1.0;\n"
" if (length(ldir) == 0.0)\n"
" ldir = normal;\n"
" break;\n\n");
out.Write(" case {}u: // LIGHTATTN_SPEC\n", LIGHTATTN_SPEC);
out.Write(" case {:s}:\n", AttenuationFunc::Spec);
out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
" attn = (dot(normal, ldir) >= 0.0) ? max(0.0, dot(normal, " I_LIGHTS
"[index].dir.xyz)) : 0.0;\n"
" cosAttn = " I_LIGHTS "[index].cosatt.xyz;\n");
out.Write(" if (diffusefunc == {}u) // LIGHTDIF_NONE\n", LIGHTDIF_NONE);
out.Write(" if (diffusefunc == {:s})\n", DiffuseFunc::None);
out.Write(" distAttn = " I_LIGHTS "[index].distatt.xyz;\n"
" else\n"
" distAttn = normalize(" I_LIGHTS "[index].distatt.xyz);\n"
" attn = max(0.0, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
"float3(1.0, attn, attn*attn));\n"
" break;\n\n");
out.Write(" case {}u: // LIGHTATTN_SPOT\n", LIGHTATTN_SPOT);
out.Write(" case {:s}:\n", AttenuationFunc::Spot);
out.Write(" ldir = " I_LIGHTS "[index].pos.xyz - pos.xyz;\n"
" dist2 = dot(ldir, ldir);\n"
" dist = sqrt(dist2);\n"
Expand All @@ -75,12 +75,12 @@ void WriteLightingFunction(ShaderCode& out)
" }}\n"
"\n"
" switch (diffusefunc) {{\n");
out.Write(" case {}u: // LIGHTDIF_NONE\n", LIGHTDIF_NONE);
out.Write(" case {:s}:\n", DiffuseFunc::None);
out.Write(" return int4(round(attn * float4(" I_LIGHTS "[index].color)));\n\n");
out.Write(" case {}u: // LIGHTDIF_SIGN\n", LIGHTDIF_SIGN);
out.Write(" case {:s}:\n", DiffuseFunc::Sign);
out.Write(" return int4(round(attn * dot(ldir, normal) * float4(" I_LIGHTS
"[index].color)));\n\n");
out.Write(" case {}u: // LIGHTDIF_CLAMP\n", LIGHTDIF_CLAMP);
out.Write(" case {:s}:\n", DiffuseFunc::Clamp);
out.Write(" return int4(round(attn * max(0.0, dot(ldir, normal)) * float4(" I_LIGHTS
"[index].color)));\n\n");
out.Write(" default:\n"
Expand Down
82 changes: 43 additions & 39 deletions Source/Core/VideoCommon/UberShaderPixel.cpp
Expand Up @@ -22,12 +22,12 @@ PixelShaderUid GetPixelShaderUid()

pixel_ubershader_uid_data* const uid_data = out.GetUidData();
uid_data->num_texgens = xfmem.numTexGen.numTexGens;
uid_data->early_depth =
bpmem.UseEarlyDepthTest() &&
(g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) &&
!(bpmem.zmode.testenable && bpmem.genMode.zfreeze);
uid_data->early_depth = bpmem.UseEarlyDepthTest() &&
(g_ActiveConfig.bFastDepthCalc ||
bpmem.alpha_test.TestResult() == AlphaTestResult::Undetermined) &&
!(bpmem.zmode.testenable && bpmem.genMode.zfreeze);
uid_data->per_pixel_depth =
(bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) ||
(bpmem.ztex2.op != ZTexOp::Disabled && bpmem.UseLateDepthTest()) ||
(!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !uid_data->early_depth) ||
(bpmem.zmode.testenable && bpmem.genMode.zfreeze);
uid_data->uint_output = bpmem.blendmode.UseLogicOp();
Expand Down Expand Up @@ -367,21 +367,21 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
"// which are common to both color and alpha channels\n"
"bool tevCompare(uint op, int3 color_A, int3 color_B) {{\n"
" switch (op) {{\n"
" case 0u: // TEVCMP_R8_GT\n"
" case 0u: // TevCompareMode::R8, TevComparison::GT\n"
" return (color_A.r > color_B.r);\n"
" case 1u: // TEVCMP_R8_EQ\n"
" case 1u: // TevCompareMode::R8, TevComparison::EQ\n"
" return (color_A.r == color_B.r);\n"
" case 2u: // TEVCMP_GR16_GT\n"
" case 2u: // TevCompareMode::GR16, TevComparison::GT\n"
" int A_16 = (color_A.r | (color_A.g << 8));\n"
" int B_16 = (color_B.r | (color_B.g << 8));\n"
" return A_16 > B_16;\n"
" case 3u: // TEVCMP_GR16_EQ\n"
" case 3u: // TevCompareMode::GR16, TevComparison::EQ\n"
" return (color_A.r == color_B.r && color_A.g == color_B.g);\n"
" case 4u: // TEVCMP_BGR24_GT\n"
" case 4u: // TevCompareMode::BGR24, TevComparison::GT\n"
" int A_24 = (color_A.r | (color_A.g << 8) | (color_A.b << 16));\n"
" int B_24 = (color_B.r | (color_B.g << 8) | (color_B.b << 16));\n"
" return A_24 > B_24;\n"
" case 5u: // TEVCMP_BGR24_EQ\n"
" case 5u: // TevCompareMode::BGR24, TevComparison::EQ\n"
" return (color_A.r == color_B.r && color_A.g == color_B.g && color_A.b == color_B.b);\n"
" default:\n"
" return false;\n"
Expand Down Expand Up @@ -814,29 +814,29 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
" s.AlphaBump = indcoord[bs - 1u];\n"
" switch(fmt)\n"
" {{\n"
" case {}u:\n",
ITF_8);
" case {:s}:\n",
IndTexFormat::ITF_8);
out.Write(" indcoord.x = indcoord.x + ((bias & 1u) != 0u ? -128 : 0);\n"
" indcoord.y = indcoord.y + ((bias & 2u) != 0u ? -128 : 0);\n"
" indcoord.z = indcoord.z + ((bias & 4u) != 0u ? -128 : 0);\n"
" s.AlphaBump = s.AlphaBump & 0xf8;\n"
" break;\n"
" case {}u:\n",
ITF_5);
" case {:s}:\n",
IndTexFormat::ITF_5);
out.Write(" indcoord.x = (indcoord.x & 0x1f) + ((bias & 1u) != 0u ? 1 : 0);\n"
" indcoord.y = (indcoord.y & 0x1f) + ((bias & 2u) != 0u ? 1 : 0);\n"
" indcoord.z = (indcoord.z & 0x1f) + ((bias & 4u) != 0u ? 1 : 0);\n"
" s.AlphaBump = s.AlphaBump & 0xe0;\n"
" break;\n"
" case {}u:\n",
ITF_4);
" case {:s}:\n",
IndTexFormat::ITF_4);
out.Write(" indcoord.x = (indcoord.x & 0x0f) + ((bias & 1u) != 0u ? 1 : 0);\n"
" indcoord.y = (indcoord.y & 0x0f) + ((bias & 2u) != 0u ? 1 : 0);\n"
" indcoord.z = (indcoord.z & 0x0f) + ((bias & 4u) != 0u ? 1 : 0);\n"
" s.AlphaBump = s.AlphaBump & 0xf0;\n"
" break;\n"
" case {}u:\n",
ITF_3);
" case {:s}:\n",
IndTexFormat::ITF_3);
out.Write(" indcoord.x = (indcoord.x & 0x07) + ((bias & 1u) != 0u ? 1 : 0);\n"
" indcoord.y = (indcoord.y & 0x07) + ((bias & 2u) != 0u ? 1 : 0);\n"
" indcoord.z = (indcoord.z & 0x07) + ((bias & 4u) != 0u ? 1 : 0);\n"
Expand Down Expand Up @@ -924,7 +924,7 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
out.Write(" bool color_clamp = bool({});\n",
BitfieldExtract("ss.cc", TevStageCombiner().colorC.clamp));
out.Write(" uint color_shift = {};\n",
BitfieldExtract("ss.cc", TevStageCombiner().colorC.shift));
BitfieldExtract("ss.cc", TevStageCombiner().colorC.scale));
out.Write(" uint color_dest = {};\n",
BitfieldExtract("ss.cc", TevStageCombiner().colorC.dest));

Expand All @@ -949,12 +949,12 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
" }} else {{ // Compare mode\n"
" // op 6 and 7 do a select per color channel\n"
" if (color_compare_op == 6u) {{\n"
" // TEVCMP_RGB8_GT\n"
" // TevCompareMode::RGB8, TevComparison::GT\n"
" color.r = (color_A.r > color_B.r) ? color_C.r : 0;\n"
" color.g = (color_A.g > color_B.g) ? color_C.g : 0;\n"
" color.b = (color_A.b > color_B.b) ? color_C.b : 0;\n"
" }} else if (color_compare_op == 7u) {{\n"
" // TEVCMP_RGB8_EQ\n"
" // TevCompareMode::RGB8, TevComparison::EQ\n"
" color.r = (color_A.r == color_B.r) ? color_C.r : 0;\n"
" color.g = (color_A.g == color_B.g) ? color_C.g : 0;\n"
" color.b = (color_A.b == color_B.b) ? color_C.b : 0;\n"
Expand Down Expand Up @@ -990,7 +990,7 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
out.Write(" bool alpha_clamp = bool({});\n",
BitfieldExtract("ss.ac", TevStageCombiner().alphaC.clamp));
out.Write(" uint alpha_shift = {};\n",
BitfieldExtract("ss.ac", TevStageCombiner().alphaC.shift));
BitfieldExtract("ss.ac", TevStageCombiner().alphaC.scale));
out.Write(" uint alpha_dest = {};\n",
BitfieldExtract("ss.ac", TevStageCombiner().alphaC.dest));

Expand All @@ -1016,10 +1016,10 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
"true, alpha_shift);\n"
" }} else {{ // Compare mode\n"
" if (alpha_compare_op == 6u) {{\n"
" // TEVCMP_A8_GT\n"
" // TevCompareMode::A8, TevComparison::GT\n"
" alpha = (alpha_A > alpha_B) ? alpha_C : 0;\n"
" }} else if (alpha_compare_op == 7u) {{\n"
" // TEVCMP_A8_EQ\n"
" // TevCompareMode::A8, TevComparison::EQ\n"
" alpha = (alpha_A == alpha_B) ? alpha_C : 0;\n"
" }} else {{\n"
" // All remaining alpha compare ops actually compare the color channels\n"
Expand Down Expand Up @@ -1157,8 +1157,8 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
out.Write(" // Fog\n"
" uint fog_function = {};\n",
BitfieldExtract("bpmem_fogParam3", FogParam3().fsel));
out.Write(" if (fog_function != 0u) {{\n"
" // TODO: This all needs to be converted from float to fixed point\n"
out.Write(" if (fog_function != {:s}) {{\n", FogType::Off);
out.Write(" // TODO: This all needs to be converted from float to fixed point\n"
" float ze;\n"
" if ({} == 0u) {{\n",
BitfieldExtract("bpmem_fogParam3", FogParam3().proj));
Expand Down Expand Up @@ -1188,23 +1188,27 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
" }}\n"
"\n"
" float fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n"
"\n"
" if (fog_function > 3u) {{\n"
" switch (fog_function) {{\n"
" case 4u:\n"
"\n");
out.Write(" if (fog_function >= {:s}) {{\n", FogType::Exp);
out.Write(" switch (fog_function) {{\n"
" case {:s}:\n"
" fog = 1.0 - exp2(-8.0 * fog);\n"
" break;\n"
" case 5u:\n"
" break;\n",
FogType::Exp);
out.Write(" case {:s}:\n"
" fog = 1.0 - exp2(-8.0 * fog * fog);\n"
" break;\n"
" case 6u:\n"
" break;\n",
FogType::ExpSq);
out.Write(" case {:s}:\n"
" fog = exp2(-8.0 * (1.0 - fog));\n"
" break;\n"
" case 7u:\n"
" break;\n",
FogType::BackwardsExp);
out.Write(" case {:s}:\n"
" fog = 1.0 - fog;\n"
" fog = exp2(-8.0 * fog * fog);\n"
" break;\n"
" }}\n"
" break;\n",
FogType::BackwardsExpSq);
out.Write(" }}\n"
" }}\n"
"\n"
" int ifog = iround(fog * 256.0);\n"
Expand Down