Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions core/libs/prx/libSceHmd2/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,12 @@ int APS5_VABI sceHmd2ReprojectionDisableVrMode() {
}

int APS5_VABI sceHmd2ReprojectionEnableMirroring(const Hmd2::MirroringParameter* parameter) {
return Hmd2::ReprojectionNotInitialized;
{
std::lock_guard lock(reprojectionMutex);
if (reprojectionState == nullptr) return Hmd2::ReprojectionNotInitialized;
}
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceHmd2ReprojectionEnableVrMode(std::uint64_t mode) {
Expand All @@ -258,7 +263,13 @@ Hmd2::SizeAlign APS5_VABI sceHmd2ReprojectionGetMirroringWorkMemorySizeAlign() {
}

int APS5_VABI sceHmd2ReprojectionGetPredictedDisplayTime(std::uint64_t frameId, std::uint64_t* time) {
return Hmd2::ReprojectionNotInitialized;
{
std::lock_guard lock(reprojectionMutex);
if (reprojectionState == nullptr) return Hmd2::ReprojectionNotInitialized;
}
if (time == nullptr) return Hmd2::ParameterNull;
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceHmd2ReprojectionInitialize(const Hmd2::ReprojectionInitializeParameter* parameter, const void* reserved) {
Expand Down Expand Up @@ -318,7 +329,13 @@ int APS5_VABI sceHmd2ReprojectionSetParamWithBuffer(std::uint32_t bufferSetId, s
}

int APS5_VABI sceHmd2ReprojectionSetRenderConfig(std::uint64_t flags, std::uint64_t reserved, std::uint64_t reserved2) {
return Hmd2::ReprojectionNotInitialized;
{
std::lock_guard lock(reprojectionMutex);
if (reprojectionState == nullptr) return Hmd2::ReprojectionNotInitialized;
}
if ((flags & ~(1ull | (1ull << 32))) != 0 || reserved != 0 || reserved2 != 0) return Hmd2::ParameterInvalid;
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceHmd2ReprojectionSetTiming(std::int32_t timing) {
Expand Down
30 changes: 30 additions & 0 deletions core/libs/tests/GuestHmd2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>

namespace Hmd2 {

Expand Down Expand Up @@ -275,6 +276,33 @@ void SizeQueriesReturnTheConsoleSizes() {
Require(work.size == 0x4000 && work.align == 0x100, "mirroring work memory size");
}

template <typename Call>
bool AnswersNoSession(Call call) {
try {
return call() == Hmd2::ReprojectionNotInitialized;
} catch (const std::exception&) {
return false;
}
}

void TestGatedCallsInsideReprojectionSession() {
std::array<std::uint8_t, 64> memory;
memory.fill(0xaa);
const Hmd2::MirroringParameter mirroring{memory.data(), memory.data() + 32};
std::uint64_t time = 0xaaaaaaaaaaaaaaaa;
Require(!AnswersNoSession([&] { return sceHmd2ReprojectionEnableMirroring(&mirroring); }), "mirroring inside a reprojection session answered as without one");
Require(!AnswersNoSession([&] { return sceHmd2ReprojectionGetPredictedDisplayTime(1, &time); }), "predicted display time inside a reprojection session answered as without one");
Require(!AnswersNoSession([&] { return sceHmd2ReprojectionSetRenderConfig(1, 0, 0); }), "render config inside a reprojection session answered as without one");
Require(!AnswersNoSession([&] { return sceHmd2ReprojectionSetRenderConfig(1ull << 32, 0, 0); }), "render config with the second accepted bit inside a reprojection session answered as without one");
for (const std::uint64_t frameId : {0ull, 1ull, 0x123456789ull}) {
Require(sceHmd2ReprojectionGetPredictedDisplayTime(frameId, nullptr) == Hmd2::ParameterNull, "predicted display time into a null output inside a reprojection session");
}
Require(sceHmd2ReprojectionSetRenderConfig(0, 1, 1) == Hmd2::ParameterInvalid, "render config with nonzero reserved arguments inside a reprojection session");
Require(sceHmd2ReprojectionSetRenderConfig(2, 0, 0) == Hmd2::ParameterInvalid, "render config with a bit outside the accepted ones inside a reprojection session");
Require(sceHmd2ReprojectionSetRenderConfig(1, 1, 0) == Hmd2::ParameterInvalid && sceHmd2ReprojectionSetRenderConfig(1, 0, 1) == Hmd2::ParameterInvalid, "render config with one nonzero reserved argument inside a reprojection session");
Require(sceHmd2ReprojectionSetRenderConfig(~0ull, 0, 0) == Hmd2::ParameterInvalid && sceHmd2ReprojectionSetRenderConfig(3, 0, 0) == Hmd2::ParameterInvalid, "render config with several bits inside a reprojection session");
}

void TestReprojection() {
Require(sceHmd2ReprojectionSetAllowPositionalReprojection(2) == 0,
"the positional setting without a session did not succeed");
Expand Down Expand Up @@ -356,7 +384,9 @@ void TestReprojection() {
const Hmd2::SizeAlign cleared = sceHmd2ReprojectionQueryBufferSizeAlign();
Require(cleared.size == Hmd2::ReprojectionBufferSize && cleared.align == Hmd2::ReprojectionBufferAlign,
"clearing the positional setting did not restore the work-size answer");
TestGatedCallsInsideReprojectionSession();
Require(sceHmd2ReprojectionTerminate() == 0, "terminate did not succeed");
TestCallsWithoutReprojectionSession();
Require(sceHmd2ReprojectionSetTiming(3000) == Hmd2::ReprojectionNotInitialized,
"setting the timing after terminate");
Require(sceHmd2ReprojectionEnableVrMode(Hmd2::OutputMode89_91Hz) == Hmd2::ReprojectionNotInitialized,
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/debt/libSceHmd2.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
- [Hmd2BeforeInitializeParameterNull](../../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - before `sceHmd2Initialize` the console answers `0x8a720008` to these 16 exports both with every argument null and with every argument pointing at a zeroed 16 KiB buffer, writing nothing: `MNtiJTDOPAU`, `RRy9WmqZfgU` (sceHmd2InternalDecryptData), `uobR4m9lgwc` (sceHmd2InternalGetMirroringMode), `-XPk5KWBYdo` (sceHmd2InternalRelocalizerSetResultData), `J44idh9izZM`, `Ps0wAvYaa1E`, `kLnMR8oQ1MY`, `kMz4rbBxvjo`, `DIU1sFRRaiE` (sceHmd2GazeGetCalibrationData), `ZQvU4vDzZGQ` (sceHmd2GazeSetUserCalibrationData), `TJpyGGP9YEY`, `Dih+Odk+RC0`, `oaqdSJw+HVY`, `m35gtHuanXU`, `CTM7QPLJF9Q` (sceHmd2InternalGetFlipInfo), `+rExHeC9lP0` (sceHmd2GazeObjectSelectionInitialize). Measured from a payload process on firmware 13.60, so a game process before initialization is assumed to answer the same; the arguments and the behaviour after initialization are not measured, and the handler throws once `sceHmd2Initialize` has succeeded
- [Hmd2BeforeInitializeParameterInvalid](../../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - before `sceHmd2Initialize` the console answers `0x8a720009` to these 9 exports both with every argument null and with every argument pointing at a zeroed 16 KiB buffer, writing nothing: `bBh5bCp9coo` (sceHmd2InternalSetPositionResetIcon), `G3PNDE2VjfY` (sceHmd2InternalSetPowerOff), `nScCT0OPU0o`, `6Q0Ng7OTN9o`, `-fJKh4SnFR0` (sceHmd2InternalSetBudgetMode), `jUA2s-l0npY` (sceHmd2InternalSetForceIcon), `+9XhyAIJVj4`, `eBGK-o6E4RQ` (sceHmd2InternalBindDeviceWithUserId), `MTuFeL9184E`. Measured from a payload process on firmware 13.60, so a game process before initialization is assumed to answer the same; the arguments and the behaviour after initialization are not measured, and the handler throws once `sceHmd2Initialize` has succeeded
- [Hmd2BeforeInitializeReprojectionNotInitialized](../../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - before `sceHmd2Initialize` the console answers `0x8a72000b` to these 10 exports both with every argument null and with every argument pointing at a zeroed 16 KiB buffer, writing nothing: `d3SEIYTP6wc`, `EVECbTvBezo`, `ciusPdJKjSU`, `DIwqTkcZiJo` (sceHmd2ReprojectionSetUserEventStart), `64ERZWVFBTE` (sceHmd2ReprojectionSetUserEventEnd), `z0+0gXUJWs8` (sceHmd2ReprojectionClearUserEventStart), `rjAd4nCY4DM` (sceHmd2ReprojectionClearUserEventEnd), `Acyg4vTdGm0` (sceHmd2ReprojectionGetCurrentOutput), `aGOWaEeg04I`, `9up+EPhw1No`. Measured from a payload process on firmware 13.60, so a game process before initialization is assumed to answer the same; the arguments and the behaviour after initialization are not measured, and the handler throws once `sceHmd2Initialize` has succeeded
- [sceHmd2ReprojectionEnableMirroring, sceHmd2ReprojectionGetPredictedDisplayTime and sceHmd2ReprojectionSetRenderConfig](../../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - the answers inside a reprojection session are not implemented (for the last two [measured](https://github.com/boykopovar/AnyPS5/pull/7658#issuecomment-6408246816) in a PPSA01317 session on firmware 13.40), so a session has to gate these calls once `sceHmd2ReprojectionInitialize` can create one. Without a session each returns 0x8a72000b for every argument and writes nothing: the firmware 13.40 module tests the session before its arguments, and a retail PS5 answered so from a payload before `sceHmd2Initialize` with null arguments and with zeroed buffers ([firmware 13.60](https://github.com/boykopovar/AnyPS5/pull/7798#issuecomment-6262489180)) and in a PPSA23479 game process whose arguments were not recorded ([firmware 13.40](https://github.com/boykopovar/AnyPS5/pull/8645#issuecomment-6307024384))
- [sceHmd2ReprojectionEnableMirroring, sceHmd2ReprojectionGetPredictedDisplayTime and sceHmd2ReprojectionSetRenderConfig](../../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - inside a reprojection session they throw, except the answers [measured](https://github.com/boykopovar/AnyPS5/pull/7658#issuecomment-6408246816) in a PPSA01317 session on firmware 13.40: GetPredictedDisplayTime with a null output 0x8a720008, SetRenderConfig with a bit outside bits 0 and 32 or a nonzero second or third argument 0x8a720009. The 0x8a720019 GetPredictedDisplayTime answered there without a headset is not returned, because the answer with one is unknown. Without a session each returns 0x8a72000b for every argument and writes nothing, as a retail PS5 answered from a payload before `sceHmd2Initialize` ([firmware 13.60](https://github.com/boykopovar/AnyPS5/pull/7798#issuecomment-6262489180))
- [Hmd2BeforeInitializeError002C](../../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - before `sceHmd2Initialize` the console answers `0x8a72002c` to these 1 exports both with every argument null and with every argument pointing at a zeroed 16 KiB buffer, writing nothing: `V1kLQmP-17U` (sceHmd2GazeObjectSelectionTerminate). Measured from a payload process on firmware 13.60, so a game process before initialization is assumed to answer the same; the arguments and the behaviour after initialization are not measured, and the handler throws once `sceHmd2Initialize` has succeeded
- [Hmd2BeforeInitializeError1002](../../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - before `sceHmd2Initialize` the console answers `0x8a721002` to these 5 exports both with every argument null and with every argument pointing at a zeroed 16 KiB buffer, writing nothing: `2LVD1EC5SYE`, `Bf87AL6zWxU`, `XKt7w1MODFY`, `Y5s22M-qUDA`, `JJKY-BtQJLg`. Measured from a payload process on firmware 13.60, so a game process before initialization is assumed to answer the same; the arguments and the behaviour after initialization are not measured, and the handler throws once `sceHmd2Initialize` has succeeded
- [Hmd2BeforeInitializeError1003](../../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - before `sceHmd2Initialize` the console answers `0x8a721003` to these 1 exports both with every argument null and with every argument pointing at a zeroed 16 KiB buffer, writing nothing: `9kj9vw8UShQ`. Measured from a payload process on firmware 13.60, so a game process before initialization is assumed to answer the same; the arguments and the behaviour after initialization are not measured, and the handler throws once `sceHmd2Initialize` has succeeded
Expand Down
Loading