Convert OpcodeDecoder::Opcode and OpcodeDecoder::Primitive to enum class
This commit is contained in:
parent
3fc12431c5
commit
3aaeb2b9ef
|
@ -150,18 +150,19 @@ FifoAnalyzer::CPMemory s_CpMem;
|
|||
|
||||
u32 AnalyzeCommand(const u8* data, DecodeMode mode)
|
||||
{
|
||||
using OpcodeDecoder::Opcode;
|
||||
const u8* dataStart = data;
|
||||
|
||||
int cmd = ReadFifo8(data);
|
||||
|
||||
switch (cmd)
|
||||
switch (static_cast<Opcode>(cmd))
|
||||
{
|
||||
case OpcodeDecoder::GX_NOP:
|
||||
case OpcodeDecoder::GX_CMD_UNKNOWN_METRICS:
|
||||
case OpcodeDecoder::GX_CMD_INVL_VC:
|
||||
case Opcode::GX_NOP:
|
||||
case Opcode::GX_CMD_UNKNOWN_METRICS:
|
||||
case Opcode::GX_CMD_INVL_VC:
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_LOAD_CP_REG:
|
||||
case Opcode::GX_LOAD_CP_REG:
|
||||
{
|
||||
s_DrawingObject = false;
|
||||
|
||||
|
@ -171,7 +172,7 @@ u32 AnalyzeCommand(const u8* data, DecodeMode mode)
|
|||
break;
|
||||
}
|
||||
|
||||
case OpcodeDecoder::GX_LOAD_XF_REG:
|
||||
case Opcode::GX_LOAD_XF_REG:
|
||||
{
|
||||
s_DrawingObject = false;
|
||||
|
||||
|
@ -182,14 +183,14 @@ u32 AnalyzeCommand(const u8* data, DecodeMode mode)
|
|||
break;
|
||||
}
|
||||
|
||||
case OpcodeDecoder::GX_LOAD_INDX_A:
|
||||
case OpcodeDecoder::GX_LOAD_INDX_B:
|
||||
case OpcodeDecoder::GX_LOAD_INDX_C:
|
||||
case OpcodeDecoder::GX_LOAD_INDX_D:
|
||||
case Opcode::GX_LOAD_INDX_A:
|
||||
case Opcode::GX_LOAD_INDX_B:
|
||||
case Opcode::GX_LOAD_INDX_C:
|
||||
case Opcode::GX_LOAD_INDX_D:
|
||||
{
|
||||
s_DrawingObject = false;
|
||||
|
||||
int array = 0xc + (cmd - OpcodeDecoder::GX_LOAD_INDX_A) / 8;
|
||||
int array = 0xc + (cmd - static_cast<u8>(Opcode::GX_LOAD_INDX_A)) / 8;
|
||||
u32 value = ReadFifo32(data);
|
||||
|
||||
if (mode == DecodeMode::Record)
|
||||
|
@ -197,7 +198,7 @@ u32 AnalyzeCommand(const u8* data, DecodeMode mode)
|
|||
break;
|
||||
}
|
||||
|
||||
case OpcodeDecoder::GX_CMD_CALL_DL:
|
||||
case Opcode::GX_CMD_CALL_DL:
|
||||
// The recorder should have expanded display lists into the fifo stream and skipped the call to
|
||||
// start them
|
||||
// That is done to make it easier to track where memory is updated
|
||||
|
@ -205,7 +206,7 @@ u32 AnalyzeCommand(const u8* data, DecodeMode mode)
|
|||
data += 8;
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_LOAD_BP_REG:
|
||||
case Opcode::GX_LOAD_BP_REG:
|
||||
{
|
||||
s_DrawingObject = false;
|
||||
ReadFifo32(data);
|
||||
|
|
|
@ -173,17 +173,13 @@ static std::string GetPrimitiveName(u8 cmd)
|
|||
const u8 vat = cmd & OpcodeDecoder::GX_VAT_MASK; // Vertex loader index (0 - 7)
|
||||
const u8 primitive =
|
||||
(cmd & OpcodeDecoder::GX_PRIMITIVE_MASK) >> OpcodeDecoder::GX_PRIMITIVE_SHIFT;
|
||||
static constexpr std::array<const char*, 8> names = {
|
||||
"GX_DRAW_QUADS", "GX_DRAW_QUADS_2 (nonstandard)",
|
||||
"GX_DRAW_TRIANGLES", "GX_DRAW_TRIANGLE_STRIP",
|
||||
"GX_DRAW_TRIANGLE_FAN", "GX_DRAW_LINES",
|
||||
"GX_DRAW_LINE_STRIP", "GX_DRAW_POINTS",
|
||||
};
|
||||
return fmt::format("{} VAT {}", names[primitive], vat);
|
||||
return fmt::format("{} VAT {}", static_cast<OpcodeDecoder::Primitive>(primitive), vat);
|
||||
}
|
||||
|
||||
void FIFOAnalyzer::UpdateDetails()
|
||||
{
|
||||
using OpcodeDecoder::Opcode;
|
||||
|
||||
// Clearing the detail list can update the selection, which causes UpdateDescription to be called
|
||||
// immediately. However, the object data offsets have not been recalculated yet, which can cause
|
||||
// the wrong data to be used, potentially leading to out of bounds data or other bad things.
|
||||
|
@ -223,14 +219,14 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
const u32 start_offset = object_offset;
|
||||
m_object_data_offsets.push_back(start_offset);
|
||||
|
||||
const u8 command = object[object_offset++];
|
||||
switch (command)
|
||||
const Opcode opcode = static_cast<Opcode>(object[object_offset++]);
|
||||
switch (opcode)
|
||||
{
|
||||
case OpcodeDecoder::GX_NOP:
|
||||
if (object[object_offset] == OpcodeDecoder::GX_NOP)
|
||||
case Opcode::GX_NOP:
|
||||
if (object[object_offset] == static_cast<u8>(Opcode::GX_NOP))
|
||||
{
|
||||
u32 nop_count = 2;
|
||||
while (object[++object_offset] == OpcodeDecoder::GX_NOP)
|
||||
while (object[++object_offset] == static_cast<u8>(Opcode::GX_NOP))
|
||||
nop_count++;
|
||||
|
||||
new_label = QStringLiteral("NOP (%1x)").arg(nop_count);
|
||||
|
@ -241,15 +237,15 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
}
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_CMD_UNKNOWN_METRICS:
|
||||
case Opcode::GX_CMD_UNKNOWN_METRICS:
|
||||
new_label = QStringLiteral("GX_CMD_UNKNOWN_METRICS");
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_CMD_INVL_VC:
|
||||
case Opcode::GX_CMD_INVL_VC:
|
||||
new_label = QStringLiteral("GX_CMD_INVL_VC");
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_LOAD_CP_REG:
|
||||
case Opcode::GX_LOAD_CP_REG:
|
||||
{
|
||||
const u8 cmd2 = object[object_offset++];
|
||||
const u32 value = Common::swap32(&object[object_offset]);
|
||||
|
@ -265,7 +261,7 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
}
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_LOAD_XF_REG:
|
||||
case Opcode::GX_LOAD_XF_REG:
|
||||
{
|
||||
const auto [name, desc] = GetXFTransferInfo(&object[object_offset]);
|
||||
const u32 cmd2 = Common::swap32(&object[object_offset]);
|
||||
|
@ -288,7 +284,7 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
}
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_LOAD_INDX_A:
|
||||
case Opcode::GX_LOAD_INDX_A:
|
||||
{
|
||||
const auto [desc, written] =
|
||||
GetXFIndexedLoadInfo(ARRAY_XF_A, Common::swap32(&object[object_offset]));
|
||||
|
@ -296,7 +292,7 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
new_label = QStringLiteral("LOAD INDX A %1").arg(QString::fromStdString(desc));
|
||||
}
|
||||
break;
|
||||
case OpcodeDecoder::GX_LOAD_INDX_B:
|
||||
case Opcode::GX_LOAD_INDX_B:
|
||||
{
|
||||
const auto [desc, written] =
|
||||
GetXFIndexedLoadInfo(ARRAY_XF_B, Common::swap32(&object[object_offset]));
|
||||
|
@ -304,7 +300,7 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
new_label = QStringLiteral("LOAD INDX B %1").arg(QString::fromStdString(desc));
|
||||
}
|
||||
break;
|
||||
case OpcodeDecoder::GX_LOAD_INDX_C:
|
||||
case Opcode::GX_LOAD_INDX_C:
|
||||
{
|
||||
const auto [desc, written] =
|
||||
GetXFIndexedLoadInfo(ARRAY_XF_C, Common::swap32(&object[object_offset]));
|
||||
|
@ -312,7 +308,7 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
new_label = QStringLiteral("LOAD INDX C %1").arg(QString::fromStdString(desc));
|
||||
}
|
||||
break;
|
||||
case OpcodeDecoder::GX_LOAD_INDX_D:
|
||||
case Opcode::GX_LOAD_INDX_D:
|
||||
{
|
||||
const auto [desc, written] =
|
||||
GetXFIndexedLoadInfo(ARRAY_XF_D, Common::swap32(&object[object_offset]));
|
||||
|
@ -321,7 +317,7 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
}
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_CMD_CALL_DL:
|
||||
case Opcode::GX_CMD_CALL_DL:
|
||||
// The recorder should have expanded display lists into the fifo stream and skipped the
|
||||
// call to start them
|
||||
// That is done to make it easier to track where memory is updated
|
||||
|
@ -330,7 +326,7 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
new_label = QStringLiteral("CALL DL");
|
||||
break;
|
||||
|
||||
case OpcodeDecoder::GX_LOAD_BP_REG:
|
||||
case Opcode::GX_LOAD_BP_REG:
|
||||
{
|
||||
const u8 cmd2 = object[object_offset++];
|
||||
const u32 cmddata = Common::swap24(&object[object_offset]);
|
||||
|
@ -347,6 +343,8 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
const u8 command = static_cast<u8>(opcode);
|
||||
if ((command & 0xC0) == 0x80)
|
||||
{
|
||||
// Object primitive data
|
||||
|
@ -392,6 +390,7 @@ void FIFOAnalyzer::UpdateDetails()
|
|||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_label = QStringLiteral("%1: ").arg(object_start + start_offset, 8, 16, QLatin1Char('0')) +
|
||||
new_label;
|
||||
m_detail_list->addItem(new_label);
|
||||
|
@ -539,6 +538,8 @@ void FIFOAnalyzer::ShowSearchResult(size_t index)
|
|||
|
||||
void FIFOAnalyzer::UpdateDescription()
|
||||
{
|
||||
using OpcodeDecoder::Opcode;
|
||||
|
||||
m_entry_detail_browser->clear();
|
||||
|
||||
if (!FifoPlayer::GetInstance().IsPlaying())
|
||||
|
@ -563,11 +564,12 @@ void FIFOAnalyzer::UpdateDescription()
|
|||
const u32 entry_start = m_object_data_offsets[entry_nr];
|
||||
|
||||
const u8* cmddata = &fifo_frame.fifoData[object_start + entry_start];
|
||||
const Opcode opcode = static_cast<Opcode>(*cmddata);
|
||||
|
||||
// TODO: Not sure whether we should bother translating the descriptions
|
||||
|
||||
QString text;
|
||||
if (*cmddata == OpcodeDecoder::GX_LOAD_BP_REG)
|
||||
if (opcode == Opcode::GX_LOAD_BP_REG)
|
||||
{
|
||||
const u8 cmd = *(cmddata + 1);
|
||||
const u32 value = Common::swap24(cmddata + 2);
|
||||
|
@ -584,7 +586,7 @@ void FIFOAnalyzer::UpdateDescription()
|
|||
else
|
||||
text += QString::fromStdString(desc);
|
||||
}
|
||||
else if (*cmddata == OpcodeDecoder::GX_LOAD_CP_REG)
|
||||
else if (opcode == Opcode::GX_LOAD_CP_REG)
|
||||
{
|
||||
const u8 cmd = *(cmddata + 1);
|
||||
const u32 value = Common::swap32(cmddata + 2);
|
||||
|
@ -601,7 +603,7 @@ void FIFOAnalyzer::UpdateDescription()
|
|||
else
|
||||
text += QString::fromStdString(desc);
|
||||
}
|
||||
else if (*cmddata == OpcodeDecoder::GX_LOAD_XF_REG)
|
||||
else if (opcode == Opcode::GX_LOAD_XF_REG)
|
||||
{
|
||||
const auto [name, desc] = GetXFTransferInfo(cmddata + 1);
|
||||
ASSERT(!name.empty());
|
||||
|
@ -615,7 +617,7 @@ void FIFOAnalyzer::UpdateDescription()
|
|||
else
|
||||
text += QString::fromStdString(desc);
|
||||
}
|
||||
else if (*cmddata == OpcodeDecoder::GX_LOAD_INDX_A)
|
||||
else if (opcode == Opcode::GX_LOAD_INDX_A)
|
||||
{
|
||||
const auto [desc, written] = GetXFIndexedLoadInfo(ARRAY_XF_A, Common::swap32(cmddata + 1));
|
||||
|
||||
|
@ -625,7 +627,7 @@ void FIFOAnalyzer::UpdateDescription()
|
|||
text += QLatin1Char{'\n'};
|
||||
text += QString::fromStdString(written);
|
||||
}
|
||||
else if (*cmddata == OpcodeDecoder::GX_LOAD_INDX_B)
|
||||
else if (opcode == Opcode::GX_LOAD_INDX_B)
|
||||
{
|
||||
const auto [desc, written] = GetXFIndexedLoadInfo(ARRAY_XF_B, Common::swap32(cmddata + 1));
|
||||
|
||||
|
@ -637,7 +639,7 @@ void FIFOAnalyzer::UpdateDescription()
|
|||
text += QLatin1Char{'\n'};
|
||||
text += QString::fromStdString(written);
|
||||
}
|
||||
else if (*cmddata == OpcodeDecoder::GX_LOAD_INDX_C)
|
||||
else if (opcode == Opcode::GX_LOAD_INDX_C)
|
||||
{
|
||||
const auto [desc, written] = GetXFIndexedLoadInfo(ARRAY_XF_C, Common::swap32(cmddata + 1));
|
||||
|
||||
|
@ -648,7 +650,7 @@ void FIFOAnalyzer::UpdateDescription()
|
|||
text += QLatin1Char{'\n'};
|
||||
text += QString::fromStdString(written);
|
||||
}
|
||||
else if (*cmddata == OpcodeDecoder::GX_LOAD_INDX_D)
|
||||
else if (opcode == Opcode::GX_LOAD_INDX_D)
|
||||
{
|
||||
const auto [desc, written] = GetXFIndexedLoadInfo(ARRAY_XF_D, Common::swap32(cmddata + 1));
|
||||
|
||||
|
|
|
@ -36,20 +36,21 @@ void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_
|
|||
{
|
||||
DebugUtil::OnObjectBegin();
|
||||
|
||||
u8 primitiveType = 0;
|
||||
using OpcodeDecoder::Primitive;
|
||||
Primitive primitive_type = Primitive::GX_DRAW_QUADS;
|
||||
switch (m_current_primitive_type)
|
||||
{
|
||||
case PrimitiveType::Points:
|
||||
primitiveType = OpcodeDecoder::GX_DRAW_POINTS;
|
||||
primitive_type = Primitive::GX_DRAW_POINTS;
|
||||
break;
|
||||
case PrimitiveType::Lines:
|
||||
primitiveType = OpcodeDecoder::GX_DRAW_LINES;
|
||||
primitive_type = Primitive::GX_DRAW_LINES;
|
||||
break;
|
||||
case PrimitiveType::Triangles:
|
||||
primitiveType = OpcodeDecoder::GX_DRAW_TRIANGLES;
|
||||
primitive_type = Primitive::GX_DRAW_TRIANGLES;
|
||||
break;
|
||||
case PrimitiveType::TriangleStrip:
|
||||
primitiveType = OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP;
|
||||
primitive_type = Primitive::GX_DRAW_TRIANGLE_STRIP;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -57,7 +58,7 @@ void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_
|
|||
if (g_renderer->IsBBoxEnabled())
|
||||
g_renderer->BBoxFlush();
|
||||
|
||||
m_setup_unit.Init(primitiveType);
|
||||
m_setup_unit.Init(primitive_type);
|
||||
|
||||
// set all states with are stored within video sw
|
||||
for (int i = 0; i < 4; i++)
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#include "VideoBackends/Software/Clipper.h"
|
||||
#include "VideoCommon/OpcodeDecoding.h"
|
||||
|
||||
void SetupUnit::Init(u8 primitiveType)
|
||||
void SetupUnit::Init(OpcodeDecoder::Primitive primitive_type)
|
||||
{
|
||||
m_PrimType = primitiveType;
|
||||
m_PrimType = primitive_type;
|
||||
|
||||
m_VertexCounter = 0;
|
||||
m_VertPointer[0] = &m_Vertices[0];
|
||||
|
@ -28,31 +28,32 @@ OutputVertexData* SetupUnit::GetVertex()
|
|||
|
||||
void SetupUnit::SetupVertex()
|
||||
{
|
||||
using OpcodeDecoder::Primitive;
|
||||
switch (m_PrimType)
|
||||
{
|
||||
case OpcodeDecoder::GX_DRAW_QUADS:
|
||||
case Primitive::GX_DRAW_QUADS:
|
||||
SetupQuad();
|
||||
break;
|
||||
case OpcodeDecoder::GX_DRAW_QUADS_2:
|
||||
case Primitive::GX_DRAW_QUADS_2:
|
||||
WARN_LOG_FMT(VIDEO, "Non-standard primitive drawing command GL_DRAW_QUADS_2");
|
||||
SetupQuad();
|
||||
break;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLES:
|
||||
case Primitive::GX_DRAW_TRIANGLES:
|
||||
SetupTriangle();
|
||||
break;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP:
|
||||
case Primitive::GX_DRAW_TRIANGLE_STRIP:
|
||||
SetupTriStrip();
|
||||
break;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLE_FAN:
|
||||
case Primitive::GX_DRAW_TRIANGLE_FAN:
|
||||
SetupTriFan();
|
||||
break;
|
||||
case OpcodeDecoder::GX_DRAW_LINES:
|
||||
case Primitive::GX_DRAW_LINES:
|
||||
SetupLine();
|
||||
break;
|
||||
case OpcodeDecoder::GX_DRAW_LINE_STRIP:
|
||||
case Primitive::GX_DRAW_LINE_STRIP:
|
||||
SetupLineStrip();
|
||||
break;
|
||||
case OpcodeDecoder::GX_DRAW_POINTS:
|
||||
case Primitive::GX_DRAW_POINTS:
|
||||
SetupPoint();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,14 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/Software/NativeVertexFormat.h"
|
||||
|
||||
namespace OpcodeDecoder
|
||||
{
|
||||
enum class Primitive : u8;
|
||||
}
|
||||
|
||||
class SetupUnit
|
||||
{
|
||||
u8 m_PrimType = 0;
|
||||
OpcodeDecoder::Primitive m_PrimType{};
|
||||
int m_VertexCounter = 0;
|
||||
|
||||
OutputVertexData m_Vertices[3];
|
||||
|
@ -24,7 +29,7 @@ class SetupUnit
|
|||
void SetupPoint();
|
||||
|
||||
public:
|
||||
void Init(u8 primitiveType);
|
||||
void Init(OpcodeDecoder::Primitive primitive_type);
|
||||
|
||||
OutputVertexData* GetVertex();
|
||||
|
||||
|
|
|
@ -202,25 +202,27 @@ u16* AddPoints(u16* index_ptr, u32 num_verts, u32 index)
|
|||
|
||||
void IndexGenerator::Init()
|
||||
{
|
||||
using OpcodeDecoder::Primitive;
|
||||
|
||||
if (g_Config.backend_info.bSupportsPrimitiveRestart)
|
||||
{
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_QUADS] = AddQuads<true>;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_QUADS_2] = AddQuads_nonstandard<true>;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLES] = AddList<true>;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP] = AddStrip<true>;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLE_FAN] = AddFan<true>;
|
||||
m_primitive_table[Primitive::GX_DRAW_QUADS] = AddQuads<true>;
|
||||
m_primitive_table[Primitive::GX_DRAW_QUADS_2] = AddQuads_nonstandard<true>;
|
||||
m_primitive_table[Primitive::GX_DRAW_TRIANGLES] = AddList<true>;
|
||||
m_primitive_table[Primitive::GX_DRAW_TRIANGLE_STRIP] = AddStrip<true>;
|
||||
m_primitive_table[Primitive::GX_DRAW_TRIANGLE_FAN] = AddFan<true>;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_QUADS] = AddQuads<false>;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_QUADS_2] = AddQuads_nonstandard<false>;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLES] = AddList<false>;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP] = AddStrip<false>;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLE_FAN] = AddFan<false>;
|
||||
m_primitive_table[Primitive::GX_DRAW_QUADS] = AddQuads<false>;
|
||||
m_primitive_table[Primitive::GX_DRAW_QUADS_2] = AddQuads_nonstandard<false>;
|
||||
m_primitive_table[Primitive::GX_DRAW_TRIANGLES] = AddList<false>;
|
||||
m_primitive_table[Primitive::GX_DRAW_TRIANGLE_STRIP] = AddStrip<false>;
|
||||
m_primitive_table[Primitive::GX_DRAW_TRIANGLE_FAN] = AddFan<false>;
|
||||
}
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_LINES] = AddLineList;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_LINE_STRIP] = AddLineStrip;
|
||||
m_primitive_table[OpcodeDecoder::GX_DRAW_POINTS] = AddPoints;
|
||||
m_primitive_table[Primitive::GX_DRAW_LINES] = AddLineList;
|
||||
m_primitive_table[Primitive::GX_DRAW_LINE_STRIP] = AddLineStrip;
|
||||
m_primitive_table[Primitive::GX_DRAW_POINTS] = AddPoints;
|
||||
}
|
||||
|
||||
void IndexGenerator::Start(u16* index_ptr)
|
||||
|
@ -230,7 +232,7 @@ void IndexGenerator::Start(u16* index_ptr)
|
|||
m_base_index = 0;
|
||||
}
|
||||
|
||||
void IndexGenerator::AddIndices(int primitive, u32 num_vertices)
|
||||
void IndexGenerator::AddIndices(OpcodeDecoder::Primitive primitive, u32 num_vertices)
|
||||
{
|
||||
m_index_buffer_current =
|
||||
m_primitive_table[primitive](m_index_buffer_current, num_vertices, m_base_index);
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/EnumMap.h"
|
||||
#include "VideoCommon/OpcodeDecoding.h"
|
||||
|
||||
class IndexGenerator
|
||||
{
|
||||
|
@ -15,7 +16,7 @@ public:
|
|||
void Init();
|
||||
void Start(u16* index_ptr);
|
||||
|
||||
void AddIndices(int primitive, u32 num_vertices);
|
||||
void AddIndices(OpcodeDecoder::Primitive primitive, u32 num_vertices);
|
||||
|
||||
void AddExternalIndices(const u16* indices, u32 num_indices, u32 num_vertices);
|
||||
|
||||
|
@ -30,5 +31,5 @@ private:
|
|||
u32 m_base_index = 0;
|
||||
|
||||
using PrimitiveFunction = u16* (*)(u16*, u32, u32);
|
||||
std::array<PrimitiveFunction, 8> m_primitive_table{};
|
||||
Common::EnumMap<PrimitiveFunction, OpcodeDecoder::Primitive::GX_DRAW_POINTS> m_primitive_table{};
|
||||
};
|
||||
|
|
|
@ -102,18 +102,18 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list)
|
|||
return finish_up();
|
||||
|
||||
const u8 cmd_byte = src.Read<u8>();
|
||||
switch (cmd_byte)
|
||||
switch (static_cast<Opcode>(cmd_byte))
|
||||
{
|
||||
case GX_NOP:
|
||||
case Opcode::GX_NOP:
|
||||
total_cycles += 6; // Hm, this means that we scan over nop streams pretty slowly...
|
||||
break;
|
||||
|
||||
case GX_UNKNOWN_RESET:
|
||||
case Opcode::GX_UNKNOWN_RESET:
|
||||
total_cycles += 6; // Datel software uses this command
|
||||
DEBUG_LOG_FMT(VIDEO, "GX Reset?: {:08x}", cmd_byte);
|
||||
break;
|
||||
|
||||
case GX_LOAD_CP_REG:
|
||||
case Opcode::GX_LOAD_CP_REG:
|
||||
{
|
||||
if (src.size() < 1 + 4)
|
||||
return finish_up();
|
||||
|
@ -128,7 +128,7 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list)
|
|||
}
|
||||
break;
|
||||
|
||||
case GX_LOAD_XF_REG:
|
||||
case Opcode::GX_LOAD_XF_REG:
|
||||
{
|
||||
if (src.size() < 4)
|
||||
return finish_up();
|
||||
|
@ -151,10 +151,10 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list)
|
|||
}
|
||||
break;
|
||||
|
||||
case GX_LOAD_INDX_A: // Used for position matrices
|
||||
case GX_LOAD_INDX_B: // Used for normal matrices
|
||||
case GX_LOAD_INDX_C: // Used for postmatrices
|
||||
case GX_LOAD_INDX_D: // Used for lights
|
||||
case Opcode::GX_LOAD_INDX_A: // Used for position matrices
|
||||
case Opcode::GX_LOAD_INDX_B: // Used for normal matrices
|
||||
case Opcode::GX_LOAD_INDX_C: // Used for postmatrices
|
||||
case Opcode::GX_LOAD_INDX_D: // Used for lights
|
||||
{
|
||||
if (src.size() < 4)
|
||||
return finish_up();
|
||||
|
@ -175,7 +175,7 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list)
|
|||
}
|
||||
break;
|
||||
|
||||
case GX_CMD_CALL_DL:
|
||||
case Opcode::GX_CMD_CALL_DL:
|
||||
{
|
||||
if (src.size() < 8)
|
||||
return finish_up();
|
||||
|
@ -198,18 +198,18 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list)
|
|||
}
|
||||
break;
|
||||
|
||||
case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after
|
||||
// that
|
||||
case Opcode::GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics
|
||||
// registers after that
|
||||
total_cycles += 6;
|
||||
DEBUG_LOG_FMT(VIDEO, "GX 0x44: {:08x}", cmd_byte);
|
||||
break;
|
||||
|
||||
case GX_CMD_INVL_VC: // Invalidate Vertex Cache
|
||||
case Opcode::GX_CMD_INVL_VC: // Invalidate Vertex Cache
|
||||
total_cycles += 6;
|
||||
DEBUG_LOG_FMT(VIDEO, "Invalidate (vertex cache?)");
|
||||
break;
|
||||
|
||||
case GX_LOAD_BP_REG:
|
||||
case Opcode::GX_LOAD_BP_REG:
|
||||
// In skipped_frame case: We have to let BP writes through because they set
|
||||
// tokens and stuff. TODO: Call a much simplified LoadBPReg instead.
|
||||
{
|
||||
|
@ -242,7 +242,8 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list)
|
|||
const u16 num_vertices = src.Read<u16>();
|
||||
const int bytes = VertexLoaderManager::RunVertices(
|
||||
cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7)
|
||||
(cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, num_vertices, src, is_preprocess);
|
||||
static_cast<Primitive>((cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT),
|
||||
num_vertices, src, is_preprocess);
|
||||
|
||||
if (bytes < 0)
|
||||
return finish_up();
|
||||
|
@ -267,7 +268,7 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list)
|
|||
// Display lists get added directly into the FIFO stream
|
||||
if constexpr (!is_preprocess)
|
||||
{
|
||||
if (g_record_fifo_data && cmd_byte != GX_CMD_CALL_DL)
|
||||
if (g_record_fifo_data && static_cast<Opcode>(cmd_byte) != Opcode::GX_CMD_CALL_DL)
|
||||
{
|
||||
const u8* const opcode_end = src.GetPointer();
|
||||
FifoRecorder::GetInstance().WriteGPCommand(opcode_start, u32(opcode_end - opcode_start));
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/EnumFormatter.h"
|
||||
|
||||
class DataReader;
|
||||
|
||||
|
@ -12,7 +13,7 @@ namespace OpcodeDecoder
|
|||
// Global flag to signal if FifoRecorder is active.
|
||||
extern bool g_record_fifo_data;
|
||||
|
||||
enum
|
||||
enum class Opcode
|
||||
{
|
||||
GX_NOP = 0x00,
|
||||
GX_UNKNOWN_RESET = 0x01,
|
||||
|
@ -27,20 +28,20 @@ enum
|
|||
|
||||
GX_CMD_CALL_DL = 0x40,
|
||||
GX_CMD_UNKNOWN_METRICS = 0x44,
|
||||
GX_CMD_INVL_VC = 0x48
|
||||
GX_CMD_INVL_VC = 0x48,
|
||||
|
||||
GX_PRIMITIVE_START = 0x80,
|
||||
GX_PRIMITIVE_END = 0xbf,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GX_PRIMITIVE_MASK = 0x78,
|
||||
GX_PRIMITIVE_SHIFT = 3,
|
||||
GX_VAT_MASK = 0x07
|
||||
};
|
||||
constexpr u8 GX_PRIMITIVE_MASK = 0x78;
|
||||
constexpr u32 GX_PRIMITIVE_SHIFT = 3;
|
||||
constexpr u8 GX_VAT_MASK = 0x07;
|
||||
|
||||
// These values are the values extracted using GX_PRIMITIVE_MASK
|
||||
// and GX_PRIMITIVE_SHIFT.
|
||||
// GX_DRAW_QUADS_2 behaves the same way as GX_DRAW_QUADS.
|
||||
enum
|
||||
enum class Primitive : u8
|
||||
{
|
||||
GX_DRAW_QUADS = 0x0, // 0x80
|
||||
GX_DRAW_QUADS_2 = 0x1, // 0x88
|
||||
|
@ -58,3 +59,16 @@ template <bool is_preprocess = false>
|
|||
u8* Run(DataReader src, u32* cycles, bool in_display_list);
|
||||
|
||||
} // namespace OpcodeDecoder
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<OpcodeDecoder::Primitive>
|
||||
: EnumFormatter<OpcodeDecoder::Primitive::GX_DRAW_POINTS>
|
||||
{
|
||||
static constexpr array_type names = {
|
||||
"GX_DRAW_QUADS", "GX_DRAW_QUADS_2 (nonstandard)",
|
||||
"GX_DRAW_TRIANGLES", "GX_DRAW_TRIANGLE_STRIP",
|
||||
"GX_DRAW_TRIANGLE_FAN", "GX_DRAW_LINES",
|
||||
"GX_DRAW_LINE_STRIP", "GX_DRAW_POINTS",
|
||||
};
|
||||
formatter() : EnumFormatter(names) {}
|
||||
};
|
||||
|
|
|
@ -239,7 +239,8 @@ static VertexLoaderBase* RefreshLoader(int vtx_attr_group, bool preprocess = fal
|
|||
return loader;
|
||||
}
|
||||
|
||||
int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bool is_preprocess)
|
||||
int RunVertices(int vtx_attr_group, OpcodeDecoder::Primitive primitive, int count, DataReader src,
|
||||
bool is_preprocess)
|
||||
{
|
||||
if (!count)
|
||||
return 0;
|
||||
|
@ -266,7 +267,8 @@ int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bo
|
|||
// if cull mode is CULL_ALL, tell VertexManager to skip triangles and quads.
|
||||
// They still need to go through vertex loading, because we need to calculate a zfreeze refrence
|
||||
// slope.
|
||||
bool cullall = (bpmem.genMode.cullmode == CullMode::All && primitive < 5);
|
||||
bool cullall = (bpmem.genMode.cullmode == CullMode::All &&
|
||||
primitive < OpcodeDecoder::Primitive::GX_DRAW_LINES);
|
||||
|
||||
DataReader dst = g_vertex_manager->PrepareForAdditionalData(
|
||||
primitive, count, loader->m_native_vtx_decl.stride, cullall);
|
||||
|
|
|
@ -14,6 +14,11 @@ class DataReader;
|
|||
class NativeVertexFormat;
|
||||
struct PortableVertexDeclaration;
|
||||
|
||||
namespace OpcodeDecoder
|
||||
{
|
||||
enum class Primitive : u8;
|
||||
};
|
||||
|
||||
namespace VertexLoaderManager
|
||||
{
|
||||
using NativeVertexFormatMap =
|
||||
|
@ -35,7 +40,8 @@ NativeVertexFormat* GetOrCreateMatchingFormat(const PortableVertexDeclaration& d
|
|||
NativeVertexFormat* GetUberVertexFormat(const PortableVertexDeclaration& decl);
|
||||
|
||||
// Returns -1 if buf_size is insufficient, else the amount of bytes consumed
|
||||
int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bool is_preprocess);
|
||||
int RunVertices(int vtx_attr_group, OpcodeDecoder::Primitive primitive, int count, DataReader src,
|
||||
bool is_preprocess);
|
||||
|
||||
NativeVertexFormat* GetCurrentVertexFormat();
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Common/BitSet.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/EnumMap.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MathUtil.h"
|
||||
|
||||
|
@ -38,8 +39,10 @@
|
|||
|
||||
std::unique_ptr<VertexManagerBase> g_vertex_manager;
|
||||
|
||||
using OpcodeDecoder::Primitive;
|
||||
|
||||
// GX primitive -> RenderState primitive, no primitive restart
|
||||
constexpr std::array<PrimitiveType, 8> primitive_from_gx{{
|
||||
constexpr Common::EnumMap<PrimitiveType, Primitive::GX_DRAW_POINTS> primitive_from_gx{
|
||||
PrimitiveType::Triangles, // GX_DRAW_QUADS
|
||||
PrimitiveType::Triangles, // GX_DRAW_QUADS_2
|
||||
PrimitiveType::Triangles, // GX_DRAW_TRIANGLES
|
||||
|
@ -48,10 +51,10 @@ constexpr std::array<PrimitiveType, 8> primitive_from_gx{{
|
|||
PrimitiveType::Lines, // GX_DRAW_LINES
|
||||
PrimitiveType::Lines, // GX_DRAW_LINE_STRIP
|
||||
PrimitiveType::Points, // GX_DRAW_POINTS
|
||||
}};
|
||||
};
|
||||
|
||||
// GX primitive -> RenderState primitive, using primitive restart
|
||||
constexpr std::array<PrimitiveType, 8> primitive_from_gx_pr{{
|
||||
constexpr Common::EnumMap<PrimitiveType, Primitive::GX_DRAW_POINTS> primitive_from_gx_pr{
|
||||
PrimitiveType::TriangleStrip, // GX_DRAW_QUADS
|
||||
PrimitiveType::TriangleStrip, // GX_DRAW_QUADS_2
|
||||
PrimitiveType::TriangleStrip, // GX_DRAW_TRIANGLES
|
||||
|
@ -60,7 +63,7 @@ constexpr std::array<PrimitiveType, 8> primitive_from_gx_pr{{
|
|||
PrimitiveType::Lines, // GX_DRAW_LINES
|
||||
PrimitiveType::Lines, // GX_DRAW_LINE_STRIP
|
||||
PrimitiveType::Points, // GX_DRAW_POINTS
|
||||
}};
|
||||
};
|
||||
|
||||
// Due to the BT.601 standard which the GameCube is based on being a compromise
|
||||
// between PAL and NTSC, neither standard gets square pixels. They are each off
|
||||
|
@ -107,13 +110,13 @@ u32 VertexManagerBase::GetRemainingSize() const
|
|||
return static_cast<u32>(m_end_buffer_pointer - m_cur_buffer_pointer);
|
||||
}
|
||||
|
||||
void VertexManagerBase::AddIndices(int primitive, u32 num_vertices)
|
||||
void VertexManagerBase::AddIndices(OpcodeDecoder::Primitive primitive, u32 num_vertices)
|
||||
{
|
||||
m_index_generator.AddIndices(primitive, num_vertices);
|
||||
}
|
||||
|
||||
DataReader VertexManagerBase::PrepareForAdditionalData(int primitive, u32 count, u32 stride,
|
||||
bool cullall)
|
||||
DataReader VertexManagerBase::PrepareForAdditionalData(OpcodeDecoder::Primitive primitive,
|
||||
u32 count, u32 stride, bool cullall)
|
||||
{
|
||||
// Flush all EFB pokes. Since the buffer is shared, we can't draw pokes+primitives concurrently.
|
||||
g_framebuffer_manager->FlushEFBPokes();
|
||||
|
@ -185,7 +188,7 @@ void VertexManagerBase::FlushData(u32 count, u32 stride)
|
|||
m_cur_buffer_pointer += count * stride;
|
||||
}
|
||||
|
||||
u32 VertexManagerBase::GetRemainingIndices(int primitive) const
|
||||
u32 VertexManagerBase::GetRemainingIndices(OpcodeDecoder::Primitive primitive) const
|
||||
{
|
||||
const u32 index_len = MAXIBUFFERSIZE - m_index_generator.GetIndexLen();
|
||||
|
||||
|
@ -193,22 +196,22 @@ u32 VertexManagerBase::GetRemainingIndices(int primitive) const
|
|||
{
|
||||
switch (primitive)
|
||||
{
|
||||
case OpcodeDecoder::GX_DRAW_QUADS:
|
||||
case OpcodeDecoder::GX_DRAW_QUADS_2:
|
||||
case Primitive::GX_DRAW_QUADS:
|
||||
case Primitive::GX_DRAW_QUADS_2:
|
||||
return index_len / 5 * 4;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLES:
|
||||
case Primitive::GX_DRAW_TRIANGLES:
|
||||
return index_len / 4 * 3;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP:
|
||||
case Primitive::GX_DRAW_TRIANGLE_STRIP:
|
||||
return index_len / 1 - 1;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLE_FAN:
|
||||
case Primitive::GX_DRAW_TRIANGLE_FAN:
|
||||
return index_len / 6 * 4 + 1;
|
||||
|
||||
case OpcodeDecoder::GX_DRAW_LINES:
|
||||
case Primitive::GX_DRAW_LINES:
|
||||
return index_len;
|
||||
case OpcodeDecoder::GX_DRAW_LINE_STRIP:
|
||||
case Primitive::GX_DRAW_LINE_STRIP:
|
||||
return index_len / 2 + 1;
|
||||
|
||||
case OpcodeDecoder::GX_DRAW_POINTS:
|
||||
case Primitive::GX_DRAW_POINTS:
|
||||
return index_len;
|
||||
|
||||
default:
|
||||
|
@ -219,22 +222,22 @@ u32 VertexManagerBase::GetRemainingIndices(int primitive) const
|
|||
{
|
||||
switch (primitive)
|
||||
{
|
||||
case OpcodeDecoder::GX_DRAW_QUADS:
|
||||
case OpcodeDecoder::GX_DRAW_QUADS_2:
|
||||
case Primitive::GX_DRAW_QUADS:
|
||||
case Primitive::GX_DRAW_QUADS_2:
|
||||
return index_len / 6 * 4;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLES:
|
||||
case Primitive::GX_DRAW_TRIANGLES:
|
||||
return index_len;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP:
|
||||
case Primitive::GX_DRAW_TRIANGLE_STRIP:
|
||||
return index_len / 3 + 2;
|
||||
case OpcodeDecoder::GX_DRAW_TRIANGLE_FAN:
|
||||
case Primitive::GX_DRAW_TRIANGLE_FAN:
|
||||
return index_len / 3 + 2;
|
||||
|
||||
case OpcodeDecoder::GX_DRAW_LINES:
|
||||
case Primitive::GX_DRAW_LINES:
|
||||
return index_len;
|
||||
case OpcodeDecoder::GX_DRAW_LINE_STRIP:
|
||||
case Primitive::GX_DRAW_LINE_STRIP:
|
||||
return index_len / 2 + 1;
|
||||
|
||||
case OpcodeDecoder::GX_DRAW_POINTS:
|
||||
case Primitive::GX_DRAW_POINTS:
|
||||
return index_len;
|
||||
|
||||
default:
|
||||
|
|
|
@ -35,6 +35,11 @@ enum TexelBufferFormat : u32
|
|||
NUM_TEXEL_BUFFER_FORMATS
|
||||
};
|
||||
|
||||
namespace OpcodeDecoder
|
||||
{
|
||||
enum class Primitive : u8;
|
||||
};
|
||||
|
||||
class VertexManagerBase
|
||||
{
|
||||
private:
|
||||
|
@ -93,8 +98,9 @@ public:
|
|||
virtual bool Initialize();
|
||||
|
||||
PrimitiveType GetCurrentPrimitiveType() const { return m_current_primitive_type; }
|
||||
void AddIndices(int primitive, u32 num_vertices);
|
||||
DataReader PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall);
|
||||
void AddIndices(OpcodeDecoder::Primitive primitive, u32 num_vertices);
|
||||
DataReader PrepareForAdditionalData(OpcodeDecoder::Primitive primitive, u32 count, u32 stride,
|
||||
bool cullall);
|
||||
void FlushData(u32 count, u32 stride);
|
||||
|
||||
void Flush();
|
||||
|
@ -163,7 +169,7 @@ protected:
|
|||
virtual void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex);
|
||||
|
||||
u32 GetRemainingSize() const;
|
||||
u32 GetRemainingIndices(int primitive) const;
|
||||
u32 GetRemainingIndices(OpcodeDecoder::Primitive primitive) const;
|
||||
|
||||
void CalculateZSlope(NativeVertexFormat* format);
|
||||
void LoadTextures();
|
||||
|
|
Loading…
Reference in New Issue