From dbe504fff949070d6c1f305ca3f14fb259abc123 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Mon, 24 Apr 2023 02:35:48 +0300 Subject: [PATCH] [Y2R] Bunch of service calls --- include/services/y2r.hpp | 34 ++++++++ src/core/services/y2r.cpp | 164 +++++++++++++++++++++++++++++++++++++- 2 files changed, 197 insertions(+), 1 deletion(-) diff --git a/include/services/y2r.hpp b/include/services/y2r.hpp index 35dbfa4f..ec0a6e65 100644 --- a/include/services/y2r.hpp +++ b/include/services/y2r.hpp @@ -37,8 +37,29 @@ class Y2RService { RGB565 = 3 }; + // Clockwise rotation + enum class Rotation : u32 { + None = 0, + Rotate90 = 1, + Rotate180 = 2, + Rotate270 = 3 + }; + + enum class BlockAlignment : u32 { + Line = 0, // Output buffer's pixels are arranged linearly. Used when outputting to the framebuffer. + Block8x8 = 1, // Output buffer's pixels are morton swizzled. Used when outputting to a GPU texture. + }; + InputFormat inputFmt; OutputFormat outputFmt; + Rotation rotation; + BlockAlignment alignment; + + bool spacialDithering; + bool temporalDithering; + u16 alpha; + u16 inputLineWidth; + u16 inputLines; // Service commands void driverInitialize(u32 messagePointer); @@ -46,8 +67,21 @@ class Y2RService { void pingProcess(u32 messagePointer); void setTransferEndInterrupt(u32 messagePointer); void getTransferEndEvent(u32 messagePointer); + + void setAlpha(u32 messagePointer); + void setBlockAlignment(u32 messagePointer); void setInputFormat(u32 messagePointer); + void setInputLineWidth(u32 messagePointer); + void setInputLines(u32 messagePointer); void setOutputFormat(u32 messagePointer); + void setReceiving(u32 messagePointer); + void setRotation(u32 messagePointer); + void setSendingY(u32 messagePointer); + void setSendingU(u32 messagePointer); + void setSendingV(u32 messagePointer); + void setSpacialDithering(u32 messagePointer); + void setStandardCoeff(u32 messagePointer); + void setTemporalDithering(u32 messagePointer); void stopConversion(u32 messagePointer); public: diff --git a/src/core/services/y2r.cpp b/src/core/services/y2r.cpp index 0571572c..6991c49b 100644 --- a/src/core/services/y2r.cpp +++ b/src/core/services/y2r.cpp @@ -6,8 +6,20 @@ namespace Y2RCommands { enum : u32 { SetInputFormat = 0x00010040, SetOutputFormat = 0x00030040, + SetRotation = 0x00050040, + SetBlockAlignment = 0x00070040, + SetSpacialDithering = 0x00090040, + SetTemporalDithering = 0x000B0040, SetTransferEndInterrupt = 0x000D0040, GetTransferEndEvent = 0x000F0000, + SetSendingY = 0x00100102, + SetSendingU = 0x00110102, + SetSendingV = 0x00120102, + SetReceiving = 0x00180102, + SetInputLineWidth = 0x001A0040, + SetInputLines = 0x001C0040, + SetStandardCoeff = 0x00200040, + SetAlpha = 0x00220040, StopConversion = 0x00270000, IsBusyConversion = 0x00280000, PingProcess = 0x002A0000, @@ -25,8 +37,17 @@ void Y2RService::reset() { transferEndInterruptEnabled = false; transferEndEvent = std::nullopt; + alignment = BlockAlignment::Line; inputFmt = InputFormat::YUV422_Individual8; outputFmt = OutputFormat::RGB32; + rotation = Rotation::None; + + spacialDithering = false; + temporalDithering = false; + + alpha = 0xFFFF; + inputLines = 69; + inputLineWidth = 420; } void Y2RService::handleSyncRequest(u32 messagePointer) { @@ -36,8 +57,20 @@ void Y2RService::handleSyncRequest(u32 messagePointer) { case Y2RCommands::GetTransferEndEvent: getTransferEndEvent(messagePointer); break; case Y2RCommands::IsBusyConversion: isBusyConversion(messagePointer); break; case Y2RCommands::PingProcess: pingProcess(messagePointer); break; + case Y2RCommands::SetAlpha: setAlpha(messagePointer); break; + case Y2RCommands::SetBlockAlignment: setBlockAlignment(messagePointer); break; case Y2RCommands::SetInputFormat: setInputFormat(messagePointer); break; + case Y2RCommands::SetInputLineWidth: setInputLineWidth(messagePointer); break; + case Y2RCommands::SetInputLines: setInputLines(messagePointer); break; case Y2RCommands::SetOutputFormat: setOutputFormat(messagePointer); break; + case Y2RCommands::SetReceiving: setReceiving(messagePointer); break; + case Y2RCommands::SetRotation: setRotation(messagePointer); break; + case Y2RCommands::SetSendingY: setSendingY(messagePointer); break; + case Y2RCommands::SetSendingU: setSendingU(messagePointer); break; + case Y2RCommands::SetSendingV: setSendingV(messagePointer); break; + case Y2RCommands::SetSpacialDithering: setSpacialDithering(messagePointer); break; + case Y2RCommands::SetStandardCoeff: setStandardCoeff(messagePointer); break; + case Y2RCommands::SetTemporalDithering: setTemporalDithering(messagePointer); break; case Y2RCommands::SetTransferEndInterrupt: setTransferEndInterrupt(messagePointer); break; case Y2RCommands::StopConversion: stopConversion(messagePointer); break; default: Helpers::panic("Y2R service requested. Command: %08X\n", command); @@ -97,6 +130,20 @@ void Y2RService::isBusyConversion(u32 messagePointer) { mem.write32(messagePointer + 8, static_cast(BusyStatus::NotBusy)); } +void Y2RService::setBlockAlignment(u32 messagePointer) { + const u32 newAlignment = mem.read32(messagePointer + 4); + log("Y2R::SetBlockAlignment (format = %d)\n", newAlignment); + + if (newAlignment > 1) { + Helpers::warn("Warning: Invalid block alignment for Y2R conversion\n"); + } else { + alignment = static_cast(newAlignment); + } + + mem.write32(messagePointer, IPC::responseHeader(0x7, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + void Y2RService::setInputFormat(u32 messagePointer) { const u32 format = mem.read32(messagePointer + 4); log("Y2R::SetInputFormat (format = %d)\n", format); @@ -121,6 +168,121 @@ void Y2RService::setOutputFormat(u32 messagePointer) { outputFmt = static_cast(format); } - mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); + mem.write32(messagePointer, IPC::responseHeader(0x3, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void Y2RService::setRotation(u32 messagePointer) { + const u32 rot = mem.read32(messagePointer + 4); + log("Y2R::SetRotation (format = %d)\n", rot); + + if (rot > 3) { + Helpers::warn("Warning: Invalid rotation for Y2R conversion\n"); + } else { + rotation = static_cast(rot); + } + + mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void Y2RService::setAlpha(u32 messagePointer) { + alpha = mem.read16(messagePointer + 4); + log("Y2R::SetAlpha (value = %04X)\n", alpha); + + mem.write32(messagePointer, IPC::responseHeader(0x22, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void Y2RService::setSpacialDithering(u32 messagePointer) { + const bool enable = mem.read32(messagePointer + 4) != 0; + log("Y2R::SetSpacialDithering (enable = %d)\n", enable); + + spacialDithering = enable; + mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void Y2RService::setTemporalDithering(u32 messagePointer) { + const bool enable = mem.read32(messagePointer + 4) != 0; + log("Y2R::SetTemporalDithering (enable = %d)\n", enable); + + temporalDithering = enable; + mem.write32(messagePointer, IPC::responseHeader(0xB, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void Y2RService::setInputLineWidth(u32 messagePointer) { + const u16 width = mem.read16(messagePointer + 4); + log("Y2R::SetInputLineWidth (width = %d)\n", width); + + mem.write32(messagePointer, IPC::responseHeader(0x1A, 1, 0)); + // Width must be > 0, <= 1024 and must be aligned to 8 pixels + if (width == 0 || width > 1024 || (width & 7) != 0) { + Helpers::panic("Y2R: Invalid input line width"); + } else { + inputLineWidth = width; + mem.write32(messagePointer + 4, Result::Success); + } +} + +void Y2RService::setInputLines(u32 messagePointer) { + const u16 lines = mem.read16(messagePointer + 4); + log("Y2R::SetInputLines (lines = %d)\n", lines); + mem.write32(messagePointer, IPC::responseHeader(0x1C, 1, 0)); + + // Width must be > 0, <= 1024 and must be aligned to 8 pixels + if (lines == 0 || lines > 1024) { + Helpers::panic("Y2R: Invalid input line count"); + } else { + // According to Citra, the Y2R module seems to accidentally skip setting the line # if it's 1024 + if (lines != 1024) + inputLines = lines; + mem.write32(messagePointer + 4, Result::Success); + } +} + +void Y2RService::setStandardCoeff(u32 messagePointer) { + const u32 coeff = mem.read32(messagePointer + 4); + log("Y2R::SetStandardCoeff (coefficient = %d)\n", coeff); + mem.write32(messagePointer, IPC::responseHeader(0x20, 1, 0)); + + if (coeff > 3) + Helpers::panic("Y2R: Invalid standard coefficient"); + else { + Helpers::warn("Unimplemented: Y2R standard coefficient"); + mem.write32(messagePointer + 4, Result::Success); + } +} + +void Y2RService::setSendingY(u32 messagePointer) { + log("Y2R::SetSendingY\n"); + Helpers::warn("Unimplemented Y2R::SetSendingY"); + + mem.write32(messagePointer, IPC::responseHeader(0x10, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void Y2RService::setSendingU(u32 messagePointer) { + log("Y2R::SetSendingU\n"); + Helpers::warn("Unimplemented Y2R::SetSendingU"); + + mem.write32(messagePointer, IPC::responseHeader(0x11, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void Y2RService::setSendingV(u32 messagePointer) { + log("Y2R::SetSendingV\n"); + Helpers::warn("Unimplemented Y2R::SetSendingV"); + + mem.write32(messagePointer, IPC::responseHeader(0x12, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void Y2RService::setReceiving(u32 messagePointer) { + log("Y2R::SetReceiving\n"); + Helpers::warn("Unimplemented Y2R::setReceiving"); + + mem.write32(messagePointer, IPC::responseHeader(0x18, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file