diff --git a/src/core/libraries/videodec/videodec.cpp b/src/core/libraries/videodec/videodec.cpp index 80fe7df99..9a565a2f7 100644 --- a/src/core/libraries/videodec/videodec.cpp +++ b/src/core/libraries/videodec/videodec.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/alignment.h" #include "common/logging/log.h" #include "core/libraries/libs.h" #include "core/libraries/videodec/videodec.h" @@ -9,7 +10,44 @@ namespace Libraries::Videodec { -static constexpr u64 kMinimumMemorySize = 16_MB; ///> Fake minimum memory size for querying +static constexpr u64 kFallbackMemorySize = 16_MB; + +static u64 ComputeFrameSizeBytes(s32 width, s32 height) { + if (width <= 0 || height <= 0) { + return 0; + } + + const u32 aligned_width = Common::AlignUp((u32)width, 256); + const u32 aligned_height = Common::AlignUp((u32)height, 16); + + const u64 pixels = (u64)aligned_width * (u64)aligned_height; + return (pixels * 3) / 2; +} + +static s32 ComputeDpbCount(const OrbisVideodecConfigInfo& cfg) { + if (cfg.maxDpbFrameCount > 0) { + return cfg.maxDpbFrameCount; + } + + return 8; +} + +static void ComputeWorstCaseDimensions(const OrbisVideodecConfigInfo& cfg, s32& out_width, + s32& out_height) { + if (cfg.maxFrameWidth > 0 && cfg.maxFrameHeight > 0) { + out_width = cfg.maxFrameWidth; + out_height = cfg.maxFrameHeight; + return; + } + + out_width = 1920; + out_height = 1080; + + if (cfg.maxLevel >= 150) { + out_width = 3840; + out_height = 2160; + } +} int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInfoIn, const OrbisVideodecResourceInfo* pRsrcInfoIn, @@ -29,7 +67,7 @@ int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInf VdecDecoder* decoder = new VdecDecoder(*pCfgInfoIn, *pRsrcInfoIn); pCtrlOut->thisSize = sizeof(OrbisVideodecCtrl); pCtrlOut->handle = decoder; - pCtrlOut->version = 1; //??? + pCtrlOut->version = 1; return ORBIS_OK; } @@ -110,14 +148,39 @@ int PS4_SYSV_ABI sceVideodecQueryResourceInfo(const OrbisVideodecConfigInfo* pCf return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; } + s32 width = 0; + s32 height = 0; + ComputeWorstCaseDimensions(*pCfgInfoIn, width, height); + + const u64 frame_size = ComputeFrameSizeBytes(width, height); + const s32 dpb_count = ComputeDpbCount(*pCfgInfoIn); + + u64 cpu_gpu_size = 0; + u64 cpu_size = 0; + u64 max_frame_buffer = 0; + + if (frame_size == 0) { + cpu_gpu_size = kFallbackMemorySize; + cpu_size = kFallbackMemorySize; + max_frame_buffer = kFallbackMemorySize; + } else { + const u64 padded_frame = Common::AlignUp(frame_size, 256) + 0x4000; + const u64 surfaces = (u64)dpb_count + 2; + + max_frame_buffer = padded_frame; + + cpu_gpu_size = (padded_frame * surfaces) + 8_MB; + cpu_size = 16_MB; + } + pRsrcInfoOut->thisSize = sizeof(OrbisVideodecResourceInfo); pRsrcInfoOut->pCpuMemory = nullptr; pRsrcInfoOut->pCpuGpuMemory = nullptr; - pRsrcInfoOut->cpuGpuMemorySize = kMinimumMemorySize; - pRsrcInfoOut->cpuMemorySize = kMinimumMemorySize; + pRsrcInfoOut->cpuGpuMemorySize = cpu_gpu_size; + pRsrcInfoOut->cpuMemorySize = cpu_size; - pRsrcInfoOut->maxFrameBufferSize = kMinimumMemorySize; + pRsrcInfoOut->maxFrameBufferSize = max_frame_buffer; pRsrcInfoOut->frameBufferAlignment = 0x100; return ORBIS_OK;