From 3aaeb2b9ef3f6b9cde69c77ecdf96e8defc996d5 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Fri, 30 Apr 2021 14:57:12 -0700 Subject: [PATCH] Convert OpcodeDecoder::Opcode and OpcodeDecoder::Primitive to enum class --- Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp | 27 +++++---- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 60 ++++++++++--------- .../VideoBackends/Software/SWVertexLoader.cpp | 13 ++-- .../Core/VideoBackends/Software/SetupUnit.cpp | 21 +++---- .../Core/VideoBackends/Software/SetupUnit.h | 9 ++- Source/Core/VideoCommon/IndexGenerator.cpp | 30 +++++----- Source/Core/VideoCommon/IndexGenerator.h | 7 ++- Source/Core/VideoCommon/OpcodeDecoding.cpp | 33 +++++----- Source/Core/VideoCommon/OpcodeDecoding.h | 32 +++++++--- .../Core/VideoCommon/VertexLoaderManager.cpp | 6 +- Source/Core/VideoCommon/VertexLoaderManager.h | 8 ++- Source/Core/VideoCommon/VertexManagerBase.cpp | 51 ++++++++-------- Source/Core/VideoCommon/VertexManagerBase.h | 12 +++- 13 files changed, 177 insertions(+), 132 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp index 3ac65e9999..a2103bd8a8 100644 --- a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp @@ -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(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(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); diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 4fcc0b2fb8..21a4572d38 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -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 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(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(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(Opcode::GX_NOP)) { u32 nop_count = 2; - while (object[++object_offset] == OpcodeDecoder::GX_NOP) + while (object[++object_offset] == static_cast(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(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(*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)); diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp index 738162de80..a7d0506a1f 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp @@ -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++) diff --git a/Source/Core/VideoBackends/Software/SetupUnit.cpp b/Source/Core/VideoBackends/Software/SetupUnit.cpp index b2488a63d8..48ab2b2d9b 100644 --- a/Source/Core/VideoBackends/Software/SetupUnit.cpp +++ b/Source/Core/VideoBackends/Software/SetupUnit.cpp @@ -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; } diff --git a/Source/Core/VideoBackends/Software/SetupUnit.h b/Source/Core/VideoBackends/Software/SetupUnit.h index a9f9584e07..e454c73ff3 100644 --- a/Source/Core/VideoBackends/Software/SetupUnit.h +++ b/Source/Core/VideoBackends/Software/SetupUnit.h @@ -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(); diff --git a/Source/Core/VideoCommon/IndexGenerator.cpp b/Source/Core/VideoCommon/IndexGenerator.cpp index d71f6c8292..be2dc99e3a 100644 --- a/Source/Core/VideoCommon/IndexGenerator.cpp +++ b/Source/Core/VideoCommon/IndexGenerator.cpp @@ -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; - m_primitive_table[OpcodeDecoder::GX_DRAW_QUADS_2] = AddQuads_nonstandard; - m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLES] = AddList; - m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP] = AddStrip; - m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLE_FAN] = AddFan; + m_primitive_table[Primitive::GX_DRAW_QUADS] = AddQuads; + m_primitive_table[Primitive::GX_DRAW_QUADS_2] = AddQuads_nonstandard; + m_primitive_table[Primitive::GX_DRAW_TRIANGLES] = AddList; + m_primitive_table[Primitive::GX_DRAW_TRIANGLE_STRIP] = AddStrip; + m_primitive_table[Primitive::GX_DRAW_TRIANGLE_FAN] = AddFan; } else { - m_primitive_table[OpcodeDecoder::GX_DRAW_QUADS] = AddQuads; - m_primitive_table[OpcodeDecoder::GX_DRAW_QUADS_2] = AddQuads_nonstandard; - m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLES] = AddList; - m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP] = AddStrip; - m_primitive_table[OpcodeDecoder::GX_DRAW_TRIANGLE_FAN] = AddFan; + m_primitive_table[Primitive::GX_DRAW_QUADS] = AddQuads; + m_primitive_table[Primitive::GX_DRAW_QUADS_2] = AddQuads_nonstandard; + m_primitive_table[Primitive::GX_DRAW_TRIANGLES] = AddList; + m_primitive_table[Primitive::GX_DRAW_TRIANGLE_STRIP] = AddStrip; + m_primitive_table[Primitive::GX_DRAW_TRIANGLE_FAN] = AddFan; } - 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); diff --git a/Source/Core/VideoCommon/IndexGenerator.h b/Source/Core/VideoCommon/IndexGenerator.h index 00c8f73132..32cf21e207 100644 --- a/Source/Core/VideoCommon/IndexGenerator.h +++ b/Source/Core/VideoCommon/IndexGenerator.h @@ -6,8 +6,9 @@ #pragma once -#include #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 m_primitive_table{}; + Common::EnumMap m_primitive_table{}; }; diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index a1abacc4c6..362afd6a7a 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -102,18 +102,18 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list) return finish_up(); const u8 cmd_byte = src.Read(); - switch (cmd_byte) + switch (static_cast(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(); 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((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(cmd_byte) != Opcode::GX_CMD_CALL_DL) { const u8* const opcode_end = src.GetPointer(); FifoRecorder::GetInstance().WriteGPCommand(opcode_start, u32(opcode_end - opcode_start)); diff --git a/Source/Core/VideoCommon/OpcodeDecoding.h b/Source/Core/VideoCommon/OpcodeDecoding.h index 98e5a292de..df1059f221 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.h +++ b/Source/Core/VideoCommon/OpcodeDecoding.h @@ -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 u8* Run(DataReader src, u32* cycles, bool in_display_list); } // namespace OpcodeDecoder + +template <> +struct fmt::formatter + : EnumFormatter +{ + 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) {} +}; diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 33af56762f..b794c5dfc0 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -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); diff --git a/Source/Core/VideoCommon/VertexLoaderManager.h b/Source/Core/VideoCommon/VertexLoaderManager.h index b43f0d919f..bd9066c5bb 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.h +++ b/Source/Core/VideoCommon/VertexLoaderManager.h @@ -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(); diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 63213edd3a..5fa85b2761 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -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 g_vertex_manager; +using OpcodeDecoder::Primitive; + // GX primitive -> RenderState primitive, no primitive restart -constexpr std::array primitive_from_gx{{ +constexpr Common::EnumMap 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 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 primitive_from_gx_pr{{ +constexpr Common::EnumMap 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 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(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: diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h index f41be70836..b3dd49aa61 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.h +++ b/Source/Core/VideoCommon/VertexManagerBase.h @@ -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();