mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 16:43:05 -05:00
sceVideoOutOpen with bus type 0x20, the PS VR2 output PPSA05666 opens as SCE_VIDEO_OUT_BUS_TYPE_HMD2_MAIN after sceHmd2ReprojectionEnableVrMode, threw VIDEO_OUT_ERROR_INVALID_VALUE and aborted the title. The console returns that code to a process that is not a game, with the headset connected and worn or not, for users 255 and 0 and for a null or zeroed open parameter, so the bus is answered that way before the other argument checks and the title carries on with the error as its handle, as it does on the console without a headset. The debt entry records the sequence the title follows on that handle (RegisterBuffers2 with category 16 and 4000x2040 descriptors that point at Hmd2 per-eye textures, ConfigureOutput and IsOutputSupported with 0x2000F, a GPU wait on buffer 0), which a VR backend will have to model, and the test covers the bus and the HMD output modes 0x20001 and 0x2000C to 0x20010, which the console and this implementation answer with VIDEO_OUT_ERROR_UNKNOWN_OUTPUT_MODE on the TV bus. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
106 lines
5.7 KiB
C++
106 lines
5.7 KiB
C++
#include "SceTypes.hpp"
|
|
#include "prx/libc/include/Shutdown.hpp"
|
|
#include "tests/VideoOutTestEnvironment.hpp"
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
|
|
extern "C" {
|
|
int APS5_VABI sceVideoOutOpen(int userId, int busType, int index, const void* param);
|
|
int APS5_VABI sceVideoOutClose(int handle);
|
|
int APS5_VABI sceVideoOutInitializeOutputOptions(VideoOutOutputOptions* options);
|
|
int APS5_VABI sceVideoOutIsOutputSupported(int handle, std::uint64_t mode, const VideoOutOutputOptions* options, void* reservedPtr, std::uint64_t reserved);
|
|
int APS5_VABI sceVideoOutConfigureOutput(int handle, std::uint64_t mode, const VideoOutOutputOptions* options, void* reservedPtr, std::uint64_t reserved);
|
|
}
|
|
|
|
static constexpr int SYSTEM_USER = 255;
|
|
static constexpr int MAIN_BUS = 0;
|
|
static constexpr int HMD2_MAIN_BUS = 0x20;
|
|
static constexpr int INVALID_VALUE = static_cast<int>(0x80290001);
|
|
static constexpr int INVALID_ADDRESS = static_cast<int>(0x80290002);
|
|
static constexpr int INVALID_HANDLE = static_cast<int>(0x8029000B);
|
|
static constexpr int RESOURCE_BUSY = static_cast<int>(0x80290009);
|
|
static constexpr int UNSUPPORTED_OUTPUT_MODE = static_cast<int>(0x80290016);
|
|
static constexpr int UNKNOWN_OUTPUT_MODE = static_cast<int>(0x8029001E);
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
int main() {
|
|
VideoOutTestEnvironment environment;
|
|
std::array<std::uint8_t, sizeof(VideoOutOutputOptions)> raw{};
|
|
raw.fill(0xAA);
|
|
VideoOutOutputOptions options{};
|
|
std::memcpy(&options, raw.data(), raw.size());
|
|
Require(sceVideoOutInitializeOutputOptions(&options) == 0);
|
|
std::memcpy(raw.data(), &options, raw.size());
|
|
for (std::size_t index = 0; index < raw.size(); ++index) Require(raw[index] == (index == 2 ? 0xFF : 0));
|
|
Require(sceVideoOutInitializeOutputOptions(nullptr) == INVALID_ADDRESS);
|
|
|
|
std::array<std::uint8_t, 64> zeroedOpenParam{};
|
|
Require(sceVideoOutOpen(SYSTEM_USER, HMD2_MAIN_BUS, 0, nullptr) == INVALID_VALUE);
|
|
Require(sceVideoOutOpen(SYSTEM_USER, HMD2_MAIN_BUS, 0, zeroedOpenParam.data()) == INVALID_VALUE);
|
|
Require(sceVideoOutOpen(0, HMD2_MAIN_BUS, 0, nullptr) == INVALID_VALUE);
|
|
|
|
int handle = 0;
|
|
try {
|
|
for (int unopened : {-1, 0, 1, 0x7FFFFFFF}) {
|
|
Require(sceVideoOutIsOutputSupported(unopened, 1, &options, nullptr, 0) == INVALID_HANDLE);
|
|
Require(sceVideoOutIsOutputSupported(unopened, 2, nullptr, &options, 1) == INVALID_HANDLE);
|
|
}
|
|
handle = sceVideoOutOpen(SYSTEM_USER, MAIN_BUS, 0, nullptr);
|
|
} catch (const std::runtime_error& error) {
|
|
if (std::getenv("ANYPS5_REQUIRE_DISPLAY") != nullptr) throw;
|
|
std::printf("skipped, no display or Vulkan device: %s\n", error.what());
|
|
return 77;
|
|
}
|
|
Require(handle > 0);
|
|
Require(sceVideoOutOpen(SYSTEM_USER, MAIN_BUS, 0, nullptr) == RESOURCE_BUSY);
|
|
Require(sceVideoOutIsOutputSupported(handle, 1, &options, nullptr, 0) == 1);
|
|
Require(sceVideoOutIsOutputSupported(handle, 1, nullptr, nullptr, 0) == 1);
|
|
const int highFrameRate = sceVideoOutIsOutputSupported(handle, 15, &options, nullptr, 0);
|
|
Require(highFrameRate == 1 || highFrameRate == UNSUPPORTED_OUTPUT_MODE);
|
|
Require(sceVideoOutConfigureOutput(handle, 15, &options, nullptr, 0) == UNSUPPORTED_OUTPUT_MODE);
|
|
for (std::uint64_t mode : {0x4ull, 0x7ull, 0x8ull, 0xCull, 0xDull, 0xEull, 0x10ull, 0x11ull, 0x13ull}) {
|
|
Require(sceVideoOutIsOutputSupported(handle, mode, &options, nullptr, 0) == UNSUPPORTED_OUTPUT_MODE);
|
|
Require(sceVideoOutConfigureOutput(handle, mode, &options, nullptr, 0) == UNSUPPORTED_OUTPUT_MODE);
|
|
}
|
|
for (std::uint64_t mode : {0x0ull, 0x2ull, 0x3ull, 0x5ull, 0x6ull, 0x9ull, 0xAull, 0xBull, 0x14ull, 0x20ull, 0x3Full, 0x100ull, 0xD000000Aull, 0x8000000000000001ull, ~0ull}) {
|
|
Require(sceVideoOutIsOutputSupported(handle, mode, &options, nullptr, 0) == UNKNOWN_OUTPUT_MODE);
|
|
}
|
|
for (std::uint64_t mode : {0x20001ull, 0x2000Cull, 0x2000Dull, 0x2000Eull, 0x2000Full, 0x20010ull}) {
|
|
Require(sceVideoOutIsOutputSupported(handle, mode, nullptr, nullptr, 0) == UNKNOWN_OUTPUT_MODE);
|
|
Require(sceVideoOutConfigureOutput(handle, mode, nullptr, nullptr, 0) == UNKNOWN_OUTPUT_MODE);
|
|
}
|
|
bool thrown = false;
|
|
try {
|
|
sceVideoOutIsOutputSupported(handle, 0x12, &options, nullptr, 0);
|
|
} catch (const std::runtime_error&) {
|
|
thrown = true;
|
|
}
|
|
Require(thrown);
|
|
|
|
Require(sceVideoOutIsOutputSupported(handle, 1, &options, &options, 0) == INVALID_VALUE);
|
|
Require(sceVideoOutIsOutputSupported(handle, 1, &options, nullptr, 1) == INVALID_VALUE);
|
|
Require(sceVideoOutIsOutputSupported(handle, 2, &options, nullptr, 1) == INVALID_VALUE);
|
|
VideoOutOutputOptions zeroed{};
|
|
Require(sceVideoOutIsOutputSupported(handle, 1, &zeroed, nullptr, 0) == INVALID_VALUE);
|
|
Require(sceVideoOutIsOutputSupported(handle, 2, &zeroed, nullptr, 0) == UNKNOWN_OUTPUT_MODE);
|
|
Require(sceVideoOutIsOutputSupported(handle, 4, &zeroed, nullptr, 0) == UNSUPPORTED_OUTPUT_MODE);
|
|
for (std::size_t word = 0; word < 16; ++word) {
|
|
VideoOutOutputOptions changed = options;
|
|
changed.internalData[word] ^= 1;
|
|
Require(sceVideoOutIsOutputSupported(handle, 1, &changed, nullptr, 0) == (word == 3 ? 1 : INVALID_VALUE));
|
|
}
|
|
VideoOutOutputOptions freeWord = options;
|
|
freeWord.internalData[3] = 0xFFFFFFFF;
|
|
Require(sceVideoOutIsOutputSupported(handle, 1, &freeWord, nullptr, 0) == 1);
|
|
Require(sceVideoOutConfigureOutput(handle, 1, &options, nullptr, 0) == 0);
|
|
|
|
Require(sceVideoOutClose(handle) == 0);
|
|
Require(sceVideoOutIsOutputSupported(handle, 1, &options, nullptr, 0) == INVALID_HANDLE);
|
|
LibcRunShutdown_nid_postfix();
|
|
}
|