shadPS4/src/core/libraries/videodec/videodec2.cpp
Stephen Miller 3844a2fb54
Lib.Videodec2: Stub sceVideodec2AllocateComputeQueue to return a valid computeQueue pointer. (#3915)
* Stub compute queue output to cpuGpuMemory

* Rename namespace

This has bugged me for far too long

* Oops
2026-01-11 10:47:34 +02:00

265 lines
10 KiB
C++

// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/libraries/libs.h"
#include "core/libraries/videodec/videodec2.h"
#include "core/libraries/videodec/videodec2_impl.h"
#include "core/libraries/videodec/videodec_error.h"
namespace Libraries::Videodec2 {
static constexpr u64 kMinimumMemorySize = 16_MB; ///> Fake minimum memory size for querying
s32 PS4_SYSV_ABI
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) {
LOG_INFO(Lib_Vdec2, "called");
if (!computeMemInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
if (computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
computeMemInfo->cpuGpuMemory = nullptr;
computeMemInfo->cpuGpuMemorySize = kMinimumMemorySize;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI
sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* computeCfgInfo,
const OrbisVideodec2ComputeMemoryInfo* computeMemInfo,
OrbisVideodec2ComputeQueue* computeQueue) {
LOG_WARNING(Lib_Vdec2, "called");
if (!computeCfgInfo || !computeMemInfo || !computeQueue) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
if (computeCfgInfo->thisSize != sizeof(OrbisVideodec2ComputeConfigInfo) ||
computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
if (computeCfgInfo->reserved0 != 0 || computeCfgInfo->reserved1 != 0) {
LOG_ERROR(Lib_Vdec2, "Invalid compute config");
return ORBIS_VIDEODEC2_ERROR_CONFIG_INFO;
}
if (computeCfgInfo->computePipeId > 4) {
LOG_ERROR(Lib_Vdec2, "Invalid compute pipe id");
return ORBIS_VIDEODEC2_ERROR_COMPUTE_PIPE_ID;
}
if (computeCfgInfo->computeQueueId > 7) {
LOG_ERROR(Lib_Vdec2, "Invalid compute queue id");
return ORBIS_VIDEODEC2_ERROR_COMPUTE_QUEUE_ID;
}
if (!computeMemInfo->cpuGpuMemory) {
LOG_ERROR(Lib_Vdec2, "Invalid memory pointer");
return ORBIS_VIDEODEC2_ERROR_MEMORY_POINTER;
}
// The real library returns a pointer to memory inside cpuGpuMemory
*computeQueue = computeMemInfo->cpuGpuMemory;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueue) {
LOG_INFO(Lib_Vdec2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI
sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
OrbisVideodec2DecoderMemoryInfo* decoderMemInfo) {
LOG_INFO(Lib_Vdec2, "called");
if (!decoderCfgInfo || !decoderMemInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
decoderMemInfo->cpuMemory = nullptr;
decoderMemInfo->gpuMemory = nullptr;
decoderMemInfo->cpuGpuMemory = nullptr;
decoderMemInfo->cpuGpuMemorySize = kMinimumMemorySize;
decoderMemInfo->cpuMemorySize = kMinimumMemorySize;
decoderMemInfo->gpuMemorySize = kMinimumMemorySize;
decoderMemInfo->maxFrameBufferSize = kMinimumMemorySize;
decoderMemInfo->frameBufferAlignment = 0x100;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
const OrbisVideodec2DecoderMemoryInfo* decoderMemInfo,
OrbisVideodec2Decoder* decoder) {
LOG_INFO(Lib_Vdec2, "called");
if (!decoderCfgInfo || !decoderMemInfo || !decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
*decoder = new VdecDecoder(*decoderCfgInfo, *decoderMemInfo);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder) {
LOG_INFO(Lib_Vdec2, "called");
if (!decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
}
delete decoder;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder,
const OrbisVideodec2InputData* inputData,
OrbisVideodec2FrameBuffer* frameBuffer,
OrbisVideodec2OutputInfo* outputInfo) {
LOG_TRACE(Lib_Vdec2, "called");
if (!decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
}
if (!inputData || !frameBuffer || !outputInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
if (inputData->thisSize != sizeof(OrbisVideodec2InputData) ||
frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
return decoder->Decode(*inputData, *frameBuffer, *outputInfo);
}
s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
OrbisVideodec2FrameBuffer* frameBuffer,
OrbisVideodec2OutputInfo* outputInfo) {
LOG_INFO(Lib_Vdec2, "called");
if (!decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
}
if (!frameBuffer || !outputInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) ||
(outputInfo->thisSize | 8) != sizeof(OrbisVideodec2OutputInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
return decoder->Flush(*frameBuffer, *outputInfo);
}
s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder) {
LOG_INFO(Lib_Vdec2, "called");
if (!decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
}
return decoder->Reset();
}
s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outputInfo,
void* p1stPictureInfoOut, void* p2ndPictureInfoOut) {
LOG_TRACE(Lib_Vdec2, "called");
if (!outputInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
if ((outputInfo->thisSize | 8) != sizeof(OrbisVideodec2OutputInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
if (outputInfo->pictureCount == 0) {
LOG_ERROR(Lib_Vdec2, "No picture info available");
return ORBIS_OK;
}
// If the game uses the older Videodec2 structs, we need to accomodate that.
if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
if (gLegacyPictureInfos.empty()) {
LOG_ERROR(Lib_Vdec2, "No picture info available");
return ORBIS_OK;
}
if (p1stPictureInfoOut) {
OrbisVideodec2LegacyAvcPictureInfo* picInfo =
static_cast<OrbisVideodec2LegacyAvcPictureInfo*>(p1stPictureInfoOut);
if (picInfo->thisSize != sizeof(OrbisVideodec2LegacyAvcPictureInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
*picInfo = gLegacyPictureInfos.back();
}
} else {
if (gPictureInfos.empty()) {
LOG_ERROR(Lib_Vdec2, "No picture info available");
return ORBIS_OK;
}
if (p1stPictureInfoOut) {
OrbisVideodec2AvcPictureInfo* picInfo =
static_cast<OrbisVideodec2AvcPictureInfo*>(p1stPictureInfoOut);
if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
*picInfo = gPictureInfos.back();
}
}
if (outputInfo->pictureCount > 1) {
UNREACHABLE();
}
return ORBIS_OK;
}
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("RnDibcGCPKw", "libSceVideodec2", 1, "libSceVideodec2",
sceVideodec2QueryComputeMemoryInfo);
LIB_FUNCTION("eD+X2SmxUt4", "libSceVideodec2", 1, "libSceVideodec2",
sceVideodec2AllocateComputeQueue);
LIB_FUNCTION("UvtA3FAiF4Y", "libSceVideodec2", 1, "libSceVideodec2",
sceVideodec2ReleaseComputeQueue);
LIB_FUNCTION("qqMCwlULR+E", "libSceVideodec2", 1, "libSceVideodec2",
sceVideodec2QueryDecoderMemoryInfo);
LIB_FUNCTION("CNNRoRYd8XI", "libSceVideodec2", 1, "libSceVideodec2", sceVideodec2CreateDecoder);
LIB_FUNCTION("jwImxXRGSKA", "libSceVideodec2", 1, "libSceVideodec2", sceVideodec2DeleteDecoder);
LIB_FUNCTION("852F5+q6+iM", "libSceVideodec2", 1, "libSceVideodec2", sceVideodec2Decode);
LIB_FUNCTION("l1hXwscLuCY", "libSceVideodec2", 1, "libSceVideodec2", sceVideodec2Flush);
LIB_FUNCTION("wJXikG6QFN8", "libSceVideodec2", 1, "libSceVideodec2", sceVideodec2Reset);
LIB_FUNCTION("NtXRa3dRzU0", "libSceVideodec2", 1, "libSceVideodec2",
sceVideodec2GetPictureInfo);
}
} // namespace Libraries::Videodec2