diff --git a/core/libs/prx/libSceAgc/Cb/src/Registers.cpp b/core/libs/prx/libSceAgc/Cb/src/Registers.cpp index 62857c1c2..f8ed2f09c 100644 --- a/core/libs/prx/libSceAgc/Cb/src/Registers.cpp +++ b/core/libs/prx/libSceAgc/Cb/src/Registers.cpp @@ -17,15 +17,11 @@ std::uint32_t* APS5_VABI sceAgcCbSetShRegisterRangeDirect(CommandBuffer* buf, st } uint32_t APS5_VABI sceAgcCbSetShRegisterRangeDirectGetSize(uint32_t num_values) { - (void)num_values; - NotImplemented_nid_no_patch(__func__); - return 0; + return (num_values + 2u) * 4u; // header + offset + values } std::uint32_t APS5_VABI sceAgcCbSetUcRegisterRangeDirectGetSize(std::uint32_t numValues) { - (void)numValues; - NotImplemented_nid_no_patch(__func__); - return 0; + return (numValues + 2u) * 4u; // header + offset + values } std::uint32_t* APS5_VABI sceAgcCbSetShRegistersDirect(CommandBuffer* buf, const volatile ShaderRegister* regs, std::uint32_t numRegs) { diff --git a/core/libs/prx/libSceAgc/Cb/src/Sync.cpp b/core/libs/prx/libSceAgc/Cb/src/Sync.cpp index 473c39dae..05d5395f8 100644 --- a/core/libs/prx/libSceAgc/Cb/src/Sync.cpp +++ b/core/libs/prx/libSceAgc/Cb/src/Sync.cpp @@ -15,9 +15,7 @@ std::uint32_t* APS5_VABI sceAgcCbNop_nid_postfix(CommandBuffer* buf, std::uint32 } uint32_t APS5_VABI sceAgcCbNopGetSize(uint32_t size_in_dwords) { - (void)size_in_dwords; - NotImplemented_nid_no_patch(__func__); - return 0; + return size_in_dwords * 4u; // a NOP packet is exactly size_in_dwords dwords including its header } std::uint32_t APS5_VABI sceAgcCbQueueEndOfPipeActionGetSize() { diff --git a/core/libs/prx/libSceAgc/Command/src/Control.cpp b/core/libs/prx/libSceAgc/Command/src/Control.cpp index 88f8d637d..9906cd432 100644 --- a/core/libs/prx/libSceAgc/Command/src/Control.cpp +++ b/core/libs/prx/libSceAgc/Command/src/Control.cpp @@ -7,7 +7,9 @@ std::uint32_t* WriteJump(CommandBuffer* buffer, std::uint8_t chain, std::uint8_t CheckBits(chain, 1, function); CheckBits(cachePolicy, 3, function); CheckBits(sizeInDwords, 0xfffffu, function); - CheckAddress(guestAddress, 4, function); + // Titles reserve a jump with a null target and write the address into the packet later. + Require((guestAddress & 3u) == 0, function, "misaligned jump target"); + // INDIRECT_BUFFER: address, then size in bits 19:0, chain (no return) in bit 20, cache policy in 29:28. return Emit(buffer, 0x3fu, {static_cast(guestAddress) & ~3u, static_cast(guestAddress >> 32u), 0x0f200000u | (static_cast(cachePolicy) << 28u) | (static_cast(chain) << 20u) | sizeInDwords}, function); } diff --git a/core/libs/prx/libSceAgc/DcbDraw/src/DrawIndexed.cpp b/core/libs/prx/libSceAgc/DcbDraw/src/DrawIndexed.cpp index 1578158dc..6129e7174 100644 --- a/core/libs/prx/libSceAgc/DcbDraw/src/DrawIndexed.cpp +++ b/core/libs/prx/libSceAgc/DcbDraw/src/DrawIndexed.cpp @@ -32,8 +32,7 @@ std::uint32_t* APS5_VABI sceAgcDcbDrawIndexOffset(CommandBuffer* buf, std::uint3 } uint32_t APS5_VABI sceAgcDcbDrawIndexOffsetGetSize(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 20; // DRAW_INDEX_OFFSET_2: header + 4 dwords } uint32_t* APS5_VABI sceAgcDcbDrawIndexIndirect(CommandBuffer* buf, uint32_t data_offset_in_bytes, uint64_t modifier) { diff --git a/core/libs/prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp b/core/libs/prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp index bdc1ac7c4..09e477f28 100644 --- a/core/libs/prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp +++ b/core/libs/prx/libSceAgc/DcbDraw/src/IndexBuffer.cpp @@ -14,8 +14,7 @@ std::uint32_t* APS5_VABI sceAgcDcbSetIndexBuffer(CommandBuffer* buf, std::uint64 } std::uint32_t APS5_VABI sceAgcDcbSetIndexBufferGetSize() { - NotImplemented_nid_no_patch(__func__); - return 0; + return 12; // INDEX_BASE: header + 2 dwords } std::uint32_t* APS5_VABI sceAgcDcbSetIndexCount(CommandBuffer* buf, std::uint32_t indexCount) { @@ -33,8 +32,7 @@ std::uint32_t* APS5_VABI sceAgcDcbSetIndexSize(CommandBuffer* buf, std::uint8_t } std::uint32_t APS5_VABI sceAgcDcbSetIndexSizeGetSize() { - NotImplemented_nid_no_patch(__func__); - return 0; + return 12; // SET_UCONFIG_REG_INDEX: header + 2 dwords } std::uint32_t* APS5_VABI sceAgcDcbSetIndexIndirectArgs(CommandBuffer* buf, std::uint32_t dataOffsetInBytes) { diff --git a/core/libs/prx/libSceAgc/DcbFlow/src/Sync.cpp b/core/libs/prx/libSceAgc/DcbFlow/src/Sync.cpp index 9e63c69d3..2e196b43d 100644 --- a/core/libs/prx/libSceAgc/DcbFlow/src/Sync.cpp +++ b/core/libs/prx/libSceAgc/DcbFlow/src/Sync.cpp @@ -42,9 +42,7 @@ std::uint32_t* APS5_VABI sceAgcDcbEventWrite(CommandBuffer* buf, std::uint8_t ev } std::uint64_t APS5_VABI sceAgcDcbEventWriteGetSize(std::uint8_t eventType) { - (void)eventType; - NotImplemented_nid_no_patch(__func__); - return 0; + return (eventType & 0xfeu) == 0x38u ? 16 : 8; // EVENT_WRITE, plus the address for the 0x38/0x39 events } std::uint32_t* APS5_VABI sceAgcDcbStallCommandBufferParser(CommandBuffer* buf) { diff --git a/core/libs/prx/libSceAgc/DcbState/src/Registers.cpp b/core/libs/prx/libSceAgc/DcbState/src/Registers.cpp index cf78cf4c8..36c25d7f5 100644 --- a/core/libs/prx/libSceAgc/DcbState/src/Registers.cpp +++ b/core/libs/prx/libSceAgc/DcbState/src/Registers.cpp @@ -9,15 +9,11 @@ extern "C" { uint32_t* APS5_VABI sceAgcDcbSetCxRegisterDirect(CommandBuffer* buf, ShaderRegister reg) { - (void)buf; - (void)reg; - NotImplemented_nid_no_patch(__func__); - return nullptr; + return Agc::Command::WriteRegisterRange(buf, 0x69u, reg.offset, ®.value, 1u, __func__); } uint32_t APS5_VABI sceAgcDcbSetCxRegisterDirectGetSize(void) { - NotImplemented_nid_no_patch(__func__); - return 0; + return 12; } std::uint32_t* APS5_VABI sceAgcDcbSetCxRegistersIndirect(CommandBuffer* buf, const volatile ShaderRegister* regs, std::uint32_t numRegs) { @@ -31,15 +27,11 @@ std::uint32_t APS5_VABI sceAgcDcbSetCxRegistersIndirectGetSize(std::uint32_t num } uint32_t* APS5_VABI sceAgcDcbSetShRegisterDirect(CommandBuffer* buf, ShaderRegister reg) { - (void)buf; - (void)reg; - NotImplemented_nid_no_patch(__func__); - return nullptr; + return Agc::Command::WriteRegisterRange(buf, 0x76u, reg.offset, ®.value, 1u, __func__); } std::uint32_t APS5_VABI sceAgcDcbSetShRegisterDirectGetSize() { - NotImplemented_nid_no_patch(__func__); - return 0; + return 12; } std::uint32_t* APS5_VABI sceAgcDcbSetShRegistersIndirect(CommandBuffer* buf, const volatile ShaderRegister* regs, std::uint32_t numRegs) { @@ -52,15 +44,11 @@ std::uint32_t APS5_VABI sceAgcDcbSetShRegistersIndirectGetSize(std::uint32_t num } uint32_t* APS5_VABI sceAgcDcbSetUcRegisterDirect(CommandBuffer* buf, ShaderRegister reg) { - (void)buf; - (void)reg; - NotImplemented_nid_no_patch(__func__); - return nullptr; + return Agc::Command::WriteRegisterRange(buf, 0x79u, reg.offset, ®.value, 1u, __func__); } std::uint32_t APS5_VABI sceAgcDcbSetUcRegisterDirectGetSize() { - NotImplemented_nid_no_patch(__func__); - return 0; + return 12; } std::uint32_t* APS5_VABI sceAgcDcbSetUcRegistersIndirect(CommandBuffer* buf, const volatile ShaderRegister* regs, std::uint32_t numRegs) { diff --git a/core/libs/prx/libSceAgc/Misc/src/ShaderFusion.cpp b/core/libs/prx/libSceAgc/Misc/src/ShaderFusion.cpp index 519e720bd..0f3cc6356 100644 --- a/core/libs/prx/libSceAgc/Misc/src/ShaderFusion.cpp +++ b/core/libs/prx/libSceAgc/Misc/src/ShaderFusion.cpp @@ -1,33 +1,116 @@ #include "prx/libSceAgc/Misc/include/ShaderFusion.hpp" +#include +#include +#include +#include #include #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include "prx/libSceAgc/Shader/include/ShaderConstants.hpp" struct SizeAlign { uint64_t m_size; size_t m_align; }; +namespace { + +using namespace ShaderRegs; + +constexpr int GRAPHICS5_ERROR_INVALID_SHADER_HALVES = static_cast(0x8a6c0008u); +constexpr std::uint32_t SPI_SHADER_PGM_CHKSUM_GS = 0x080u; +constexpr std::uint32_t SPI_SHADER_PGM_RSRC1_GS = 0x08Au; +constexpr std::uint32_t SPI_SHADER_PGM_RSRC2_GS = 0x08Bu; +constexpr std::uint32_t SPI_SHADER_PGM_CHKSUM_HS = 0x100u; +constexpr std::uint32_t SPI_SHADER_PGM_RSRC1_HS = 0x10Au; +constexpr std::uint32_t SPI_SHADER_PGM_RSRC2_HS = 0x10Bu; + +bool ValidHalves(const Shader* front, const Shader* back) { + const auto frontType = static_cast(front->type); + const auto backType = static_cast(back->type); + return (frontType == ShaderBinaryType::GsFront && backType == ShaderBinaryType::GsBack) || + (frontType == ShaderBinaryType::HsFront && backType == ShaderBinaryType::HsBack); +} + +ShaderRegister& FindRegister(ShaderRegister* regs, std::uint32_t count, std::uint32_t offset, std::uint32_t occurrence = 0) { + for (std::uint32_t i = 0; regs != nullptr && i < count; ++i) { + if (regs[i].offset == offset && occurrence-- == 0) return regs[i]; + } + throw std::runtime_error("sceAgcUnknownFuseShaderHalves: shader half lacks register " + std::to_string(offset)); +} + +void MergeMax(ShaderRegister& dst, const ShaderRegister& src, std::uint32_t shift, std::uint32_t mask) { + const auto field = std::max((dst.value >> shift) & mask, (src.value >> shift) & mask); + dst.value = (dst.value & ~(mask << shift)) | (field << shift); +} + +} + extern "C" { APS5_EXPORT("fd5Bp5tGTgo", sceAgcUnknownFuseShaderHalves); int APS5_VABI sceAgcUnknownFuseShaderHalves(Shader* fused_result, const Shader* front, const Shader* back, void* scratch_mem) { - (void)fused_result; - (void)front; - (void)back; - (void)scratch_mem; - NotImplemented_nid_no_patch(__func__); + if (fused_result == nullptr || front == nullptr || back == nullptr) APS5_INVALID_ARG_EX; + if (!ValidHalves(front, back)) return GRAPHICS5_ERROR_INVALID_SHADER_HALVES; + const bool isGs = static_cast(front->type) == ShaderBinaryType::GsFront; + const std::uint32_t stageBit = isGs ? (1u << 22u) : (1u << 21u); + if (((front->specials->vgt_shader_stages_en.value ^ back->specials->vgt_shader_stages_en.value) & stageBit) != 0) { + return GRAPHICS5_ERROR_INVALID_SHADER_HALVES; + } + *fused_result = *back; + fused_result->type = static_cast(isGs ? ShaderBinaryType::Gs : ShaderBinaryType::Hs); + if (scratch_mem != nullptr) { + auto* regs = static_cast(scratch_mem); + std::memcpy(regs, back->sh_registers, std::size_t{back->num_sh_registers} * sizeof(ShaderRegister)); + fused_result->sh_registers = regs; + } + ShaderRegister* fused = fused_result->sh_registers; + const std::uint32_t fusedCount = fused_result->num_sh_registers; + const std::uint32_t frontCount = front->num_sh_registers; + const std::uint32_t checksum = isGs ? SPI_SHADER_PGM_CHKSUM_GS : SPI_SHADER_PGM_CHKSUM_HS; + for (std::uint32_t occurrence = 0; occurrence < 2; ++occurrence) { + FindRegister(fused, fusedCount, checksum, occurrence).value = FindRegister(front->sh_registers, frontCount, checksum, occurrence).value; + } + const auto& frontRsrc1 = FindRegister(front->sh_registers, frontCount, isGs ? SPI_SHADER_PGM_RSRC1_GS : SPI_SHADER_PGM_RSRC1_HS); + const auto& frontRsrc2 = FindRegister(front->sh_registers, frontCount, isGs ? SPI_SHADER_PGM_RSRC2_GS : SPI_SHADER_PGM_RSRC2_HS); + auto& fusedRsrc1 = FindRegister(fused, fusedCount, isGs ? SPI_SHADER_PGM_RSRC1_GS : SPI_SHADER_PGM_RSRC1_HS); + auto& fusedRsrc2 = FindRegister(fused, fusedCount, isGs ? SPI_SHADER_PGM_RSRC2_GS : SPI_SHADER_PGM_RSRC2_HS); + // Both halves run in one wave, so VGPRs are the larger of the two and shared VGPRs are reallocated (after Kyty). + const std::uint32_t frontVgprs = ((frontRsrc1.value & 0x3fu) + 1u) * 4u; + const std::uint32_t backVgprs = ((fusedRsrc1.value & 0x3fu) + 1u) * 4u; + const std::uint32_t frontTotal = frontVgprs + (frontRsrc2.value >> 28u) * 8u; + const std::uint32_t backTotal = backVgprs + (fusedRsrc2.value >> 28u) * 8u; + const std::uint32_t maxTotal = std::max(frontTotal, backTotal); + const std::uint32_t shared = std::max(frontVgprs, backVgprs) >= maxTotal ? 0u : (maxTotal - std::min(frontTotal, backTotal) + 7u) / 64u; + fusedRsrc2.value = (fusedRsrc2.value & 0x0fffffffu) | ((shared & 0xfu) << 28u); + MergeMax(fusedRsrc1, frontRsrc1, 0, 0x3fu); + if (isGs) { + MergeMax(fusedRsrc1, frontRsrc1, 29, 0x3u); + MergeMax(fusedRsrc2, frontRsrc2, 16, 0x3u); + fusedRsrc2.value = (fusedRsrc2.value & 0xfffbffffu) | (frontRsrc2.value & 0x00040000u); + } else { + MergeMax(fusedRsrc1, frontRsrc1, 28, 0x3u); + } + fusedRsrc2.value = (fusedRsrc2.value & 0xf7ffffc1u) | (frontRsrc2.value & 0x0800003eu); + // The fused program starts at the front half; its address goes in the ES/LS program registers. + const std::uint32_t lo = isGs ? SPI_SHADER_PGM_LO_ES : SPI_SHADER_PGM_LO_LS; + auto& loRegister = FindRegister(fused, fusedCount, lo); + auto& hiRegister = FindRegister(fused, fusedCount, lo + 1u); + const auto address = reinterpret_cast(front->code); + loRegister.value = static_cast(address >> 8u); + hiRegister.value = (hiRegister.value & 0xffffff00u) | static_cast((address >> 40u) & 0xffu); + fused_result->user_data = nullptr; return 0; } APS5_EXPORT("dolOmWH+huQ", sceAgcUnknownGetFusedShaderSize); int APS5_VABI sceAgcUnknownGetFusedShaderSize(SizeAlign* dst, const Shader* front, const Shader* back) { - (void)dst; - (void)front; - (void)back; - NotImplemented_nid_no_patch(__func__); + if (dst == nullptr || front == nullptr || back == nullptr) APS5_INVALID_ARG_EX; + if (!ValidHalves(front, back)) return GRAPHICS5_ERROR_INVALID_SHADER_HALVES; + dst->m_size = std::uint64_t{back->num_sh_registers} * sizeof(ShaderRegister); + dst->m_align = 4; return 0; } diff --git a/core/libs/prx/libSceAgc/Patch/src/Jump.cpp b/core/libs/prx/libSceAgc/Patch/src/Jump.cpp index da33b9147..435489880 100644 --- a/core/libs/prx/libSceAgc/Patch/src/Jump.cpp +++ b/core/libs/prx/libSceAgc/Patch/src/Jump.cpp @@ -7,14 +7,35 @@ #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +namespace { + +// INDIRECT_BUFFER as sceAgcDcbJump writes it: [1..2] target, [3] size in 19:0, chain in 20, cache policy in 29:28. +void PatchJump(std::uint32_t* cmd, const volatile std::uint32_t* target, std::uint32_t sizeInDwords, const char* function) { + Agc::Command::ValidatePacket(cmd, 0x3fu, 4, function); + const auto address = reinterpret_cast(target); + Agc::Command::CheckAddress(address, 4, function); + Agc::Command::CheckBits(sizeInDwords, 0xfffffu, function); + cmd[1] = static_cast(address); + cmd[2] = static_cast(address >> 32u); + cmd[3] = (cmd[3] & ~0xfffffu) | sizeInDwords; +} + +} + extern "C" { int APS5_VABI sceAgcJumpPatchSetTarget(uint32_t* cmd, const volatile uint32_t* target, uint32_t size_in_dwords) { - (void)cmd; - (void)target; - (void)size_in_dwords; - NotImplemented_nid_no_patch(__func__); - return 0; + PatchJump(cmd, target, size_in_dwords, __func__); + return 0; +} + +// Named after Kyty's reading: a jump patch that also sets the cache policy. +APS5_EXPORT("Ikfdt-rIqCE", sceAgcUnknown_Ikfdt_MrIqCE); +int APS5_VABI sceAgcUnknown_Ikfdt_MrIqCE(uint32_t* cmd, uint64_t cache_policy, const volatile uint32_t* target, uint32_t size_in_dwords) { + Agc::Command::CheckBits(cache_policy, 3u, __func__); + PatchJump(cmd, target, size_in_dwords, __func__); + cmd[3] = (cmd[3] & ~(3u << 28u)) | (static_cast(cache_policy) << 28u); + return 0; } } diff --git a/core/libs/prx/libSceAgc/Patch/src/QueueEndOfPipeAction.cpp b/core/libs/prx/libSceAgc/Patch/src/QueueEndOfPipeAction.cpp index 53b2e91ed..c7be7ba5f 100644 --- a/core/libs/prx/libSceAgc/Patch/src/QueueEndOfPipeAction.cpp +++ b/core/libs/prx/libSceAgc/Patch/src/QueueEndOfPipeAction.cpp @@ -31,25 +31,37 @@ int APS5_VABI sceAgcQueueEndOfPipeActionPatchAddress(std::uint32_t* cmd, const v } int APS5_VABI sceAgcQueueEndOfPipeActionPatchData(uint32_t* cmd, uint32_t context_id, uint32_t data_sel, uint64_t data) { - (void)cmd; - (void)context_id; - (void)data_sel; - (void)data; - NotImplemented_nid_no_patch(__func__); - return 0; + // RELEASE_MEM as built by sceAgcCbReleaseMem: [2] dst | interrupt << 24 | data select << 29, [5..6] data, [7] interrupt context. + Agc::Command::ValidatePacket(cmd, 0x49u, 8, __func__); + Agc::Command::Require(data_sel <= 3, __func__, "invalid release data selector"); + Agc::Command::CheckBits(context_id, 0x7ffffffu, __func__); + if (data_sel == 1) { + Agc::Command::CheckBits(data, 0xffffffffu, __func__); + } + Agc::Command::Require(((cmd[2] >> 24u) & 7u) != 4u || data_sel == 0, __func__, "interrupt-only release cannot write data"); + cmd[2] = (cmd[2] & 0x1fffffffu) | (data_sel << 29u); + cmd[5] = static_cast(data); + cmd[6] = static_cast(data >> 32u); + cmd[7] = context_id; + return 0; } int APS5_VABI sceAgcQueueEndOfPipeActionPatchGcrCntl(std::uint32_t* cmd, std::uint16_t gcrControl) { - (void)cmd; - (void)gcrControl; - NotImplemented_nid_no_patch(__func__); + Agc::Command::ValidatePacket(cmd, 0x49u, 8, __func__); + Agc::Command::CheckBits(gcrControl, 0xfffu, __func__); + std::uint32_t control = gcrControl; + if ((control & 0x300u) == 0x100u) { + control |= 0x200u; + } + cmd[1] = (cmd[1] & ~(0xfffu << 12u)) | (control << 12u); return 0; } int APS5_VABI sceAgcQueueEndOfPipeActionPatchType(std::uint32_t* cmd, std::uint8_t action) { - (void)cmd; - (void)action; - NotImplemented_nid_no_patch(__func__); + Agc::Command::ValidatePacket(cmd, 0x49u, 8, __func__); + Agc::Command::CheckBits(action, 0x3fu, __func__); + const std::uint32_t eventIndex = action >= 0x2fu ? 6u : 5u; + cmd[1] = (cmd[1] & ~0xf3fu) | action | (eventIndex << 8u); return 0; } diff --git a/core/libs/prx/libSceAgc/Patch/src/Rewind.cpp b/core/libs/prx/libSceAgc/Patch/src/Rewind.cpp index fed73340b..26eabbc17 100644 --- a/core/libs/prx/libSceAgc/Patch/src/Rewind.cpp +++ b/core/libs/prx/libSceAgc/Patch/src/Rewind.cpp @@ -2,25 +2,33 @@ #include "prx/libSceAgc/Command/include/Memory.hpp" #include "prx/libSceAgc/Command/include/Packet.hpp" +#include #include #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" -extern "C" { +namespace { -int APS5_VABI sceAgcRewindPatchSetRewindState(uint32_t* cmd, uint8_t state) { - (void)cmd; - (void)state; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int APS5_VABI sceAgcAsyncRewindPatchSetRewindState(std::uint32_t* cmd, std::uint8_t state) { - (void)cmd; - (void)state; - NotImplemented_nid_no_patch(__func__); +// The valid bit (31) releases a queue stalled on the REWIND; the release store publishes the commands +// the title wrote behind it before setting the bit. +int SetRewindState(std::uint32_t* cmd, std::uint8_t state, const char* function) { + Agc::Command::ValidatePacket(cmd, 0x59u, 2, function); + Agc::Command::CheckBits(state, 1, function); + std::atomic_ref(cmd[1]).store(static_cast(state) << 31u, std::memory_order_release); return 0; } } + +extern "C" { + +int APS5_VABI sceAgcRewindPatchSetRewindState(uint32_t* cmd, uint8_t state) { + return SetRewindState(cmd, state, __func__); +} + +int APS5_VABI sceAgcAsyncRewindPatchSetRewindState(std::uint32_t* cmd, std::uint8_t state) { + return SetRewindState(cmd, state, __func__); +} + +} diff --git a/core/libs/prx/libSceAgc/Unimplemented.cpp b/core/libs/prx/libSceAgc/Unimplemented.cpp index b4b94f6a4..3cb827709 100644 --- a/core/libs/prx/libSceAgc/Unimplemented.cpp +++ b/core/libs/prx/libSceAgc/Unimplemented.cpp @@ -121,12 +121,6 @@ int APS5_VABI sceAgcUnknown_ICkECTBxrMw() { return 0; } -APS5_EXPORT("Ikfdt-rIqCE", sceAgcUnknown_Ikfdt_MrIqCE); -int APS5_VABI sceAgcUnknown_Ikfdt_MrIqCE() { - NotImplemented_nid_no_patch(__func__); - return 0; -} - APS5_EXPORT("RTpj-tIlvZc", sceAgcUnknown_RTpj_MtIlvZc); int APS5_VABI sceAgcUnknown_RTpj_MtIlvZc() { NotImplemented_nid_no_patch(__func__);