diff --git a/3rdparty/OpenAL/openal-soft.vcxproj b/3rdparty/OpenAL/openal-soft.vcxproj index 2d5823ba2d..37945fdf01 100644 --- a/3rdparty/OpenAL/openal-soft.vcxproj +++ b/3rdparty/OpenAL/openal-soft.vcxproj @@ -48,21 +48,21 @@ call vsdevcmd.bat -arch=amd64 - cd $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform) - cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DCMAKE_SYSTEM_VERSION=6.1 -DLIBTYPE=STATIC -DFORCE_STATIC_VCRT=true -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false $(SolutionDir)3rdparty\OpenAL\openal-soft + cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)" + cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DCMAKE_SYSTEM_VERSION=6.1 -DLIBTYPE=STATIC -DFORCE_STATIC_VCRT=true -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft" call vsdevcmd.bat -arch=amd64 - cd $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform) - cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DCMAKE_SYSTEM_VERSION=6.1 -DLIBTYPE=STATIC -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false $(SolutionDir)3rdparty\OpenAL\openal-soft + cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)" + cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DCMAKE_SYSTEM_VERSION=6.1 -DLIBTYPE=STATIC -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft" echo Copying.. - copy $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\OpenAL32.lib $(SolutionDir)build\lib\$(Configuration)-$(Platform) + copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\OpenAL32.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)" echo Cleaning.. - del $(SolutionDir)build\lib\$(Configuration)-$(Platform)\OpenAL32.lib - rmdir /s /q $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform) + del "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\OpenAL32.lib" + rmdir /s /q "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)" diff --git a/3rdparty/glslang/glslang.vcxproj b/3rdparty/glslang/glslang.vcxproj index 0da04a3209..762fff7622 100644 --- a/3rdparty/glslang/glslang.vcxproj +++ b/3rdparty/glslang/glslang.vcxproj @@ -39,24 +39,24 @@ "Visual Studio $(VisualStudioVersion.Substring(0,2))" call vsdevcmd.bat -arch=amd64 - cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform) + cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)" call vsdevcmd.bat -arch=amd64 - cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform) + cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)" echo Copying.. - mkdir $(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName) - copy $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\hlsl\$(CONFIGURATION)\*.lib $(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName) - copy $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\SPIRV\$(CONFIGURATION)\*.lib $(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName) - copy $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\OGLCompilersDLL\$(CONFIGURATION)\*.lib $(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName) - copy $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\glslang\OSDependent\Windows\$(CONFIGURATION)\*.lib $(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName) - copy $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\glslang\$(CONFIGURATION)\*.lib $(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName) + mkdir "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)" + copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\hlsl\$(CONFIGURATION)\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)" + copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\SPIRV\$(CONFIGURATION)\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)" + copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\OGLCompilersDLL\$(CONFIGURATION)\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)" + copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\glslang\OSDependent\Windows\$(CONFIGURATION)\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)" + copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\glslang\$(CONFIGURATION)\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)" echo Cleaning.. - rmdir /s /q $(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName) - rmdir /s /q $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform) + rmdir /s /q "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)" + rmdir /s /q "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)" $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\buildfiles\msvc\common_default.props')) @@ -65,17 +65,17 @@ $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\ $(CmakeReleaseCLI) - msbuild.exe $(IntDir)\ALL_BUILD.vcxproj /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m + msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m $(CmakeCopyCLI) $(CmakeReleaseCLI) - msbuild.exe $(IntDir)\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m + msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m $(CmakeCopyCLI) $(CmakeReleaseCLI) - msbuild.exe $(IntDir)\ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m + msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m $(CmakeCleanCLI) @@ -84,17 +84,17 @@ $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\ $(CmakeDebugCLI) - msbuild.exe $(IntDir)\ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m + msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m $(CmakeCopyCLI) $(CmakeDebugCLI) - msbuild.exe $(IntDir)\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m + msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m $(CmakeCopyCLI) $(CmakeDebugCLI) - msbuild.exe $(IntDir)\ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m + msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m $(CmakeCleanCLI) diff --git a/3rdparty/llvm/llvm_build.vcxproj b/3rdparty/llvm/llvm_build.vcxproj index fe3517a5d9..73a33db1a2 100644 --- a/3rdparty/llvm/llvm_build.vcxproj +++ b/3rdparty/llvm/llvm_build.vcxproj @@ -39,17 +39,17 @@ call vsdevcmd.bat -arch=amd64 - cd $(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform) - cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON $(SolutionDir)3rdparty\llvm\llvm\llvm + cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)" + cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON "$(SolutionDir)3rdparty\llvm\llvm\llvm" call vsdevcmd.bat -arch=amd64 - cd $(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform) - cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON $(SolutionDir)3rdparty\llvm\llvm\llvm + cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)" + cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON "$(SolutionDir)3rdparty\llvm\llvm\llvm" echo Cleaning.. - rmdir /s /q $(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build - cd $(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform) + rmdir /s /q "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" + cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)" for /F "delims= eol=|" %%f in (' dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do ( echo Deleting .\%%f diff --git a/3rdparty/llvm/llvm_build_clang_cl.vcxproj b/3rdparty/llvm/llvm_build_clang_cl.vcxproj index a124b1a9a5..f9380e896d 100644 --- a/3rdparty/llvm/llvm_build_clang_cl.vcxproj +++ b/3rdparty/llvm/llvm_build_clang_cl.vcxproj @@ -39,17 +39,17 @@ call vsdevcmd.bat -arch=amd64 - cd $(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform) - cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON $(SolutionDir)3rdparty\llvm\llvm\llvm + cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)" + cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON "$(SolutionDir)3rdparty\llvm\llvm\llvm" call vsdevcmd.bat -arch=amd64 - cd $(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform) - cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON $(SolutionDir)3rdparty\llvm\llvm\llvm + cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)" + cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON "$(SolutionDir)3rdparty\llvm\llvm\llvm" echo Cleaning.. - rmdir /s /q $(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build - cd $(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform) + rmdir /s /q "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" + cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)" for /F "delims= eol=|" %%f in (' dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do ( echo Deleting .\%%f diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 35d7d91bd7..f4f67a4ea1 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -252,6 +252,7 @@ target_sources(rpcs3_emu PRIVATE Cell/Modules/cellCrossController.cpp Cell/Modules/cellDaisy.cpp Cell/Modules/cellDmux.cpp + Cell/Modules/cellDmuxPamf.cpp Cell/Modules/cellDtcpIpUtility.cpp Cell/Modules/cellFiber.cpp Cell/Modules/cellFont.cpp diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.cpp b/rpcs3/Emu/Cell/Modules/cellAdec.cpp index 5eb80638f7..43c5f7989b 100644 --- a/rpcs3/Emu/Cell/Modules/cellAdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAdec.cpp @@ -1,42 +1,57 @@ #include "stdafx.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" #include "Emu/Cell/PPUModule.h" #include "Emu/Cell/lv2/sys_sync.h" -#include "util/media_utils.h" +#include "Emu/savestate_utils.hpp" -#ifdef _MSC_VER -#pragma warning(push, 0) -#else -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wall" -#pragma GCC diagnostic ignored "-Wextra" -#pragma GCC diagnostic ignored "-Wold-style-cast" -#endif -extern "C" -{ -#include "libavcodec/avcodec.h" -#include "libavformat/avformat.h" -#ifndef AV_INPUT_BUFFER_PADDING_SIZE -#define AV_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE -#endif -} -#ifdef _MSC_VER -#pragma warning(pop) -#else -#pragma GCC diagnostic pop -#endif - -#include "cellPamf.h" -#include "cellAtracXdec.h" #include "cellAdec.h" #include - -extern std::mutex g_mutex_avcodec_open2; +#include "util/asm.hpp" LOG_CHANNEL(cellAdec); +// These need to be defined somewhere to access the LLE functions +vm::gvar g_cell_adec_core_ops_ac3; +vm::gvar g_cell_adec_core_ops_atrac3; +vm::gvar g_cell_adec_core_ops_atrac3multi; +vm::gvar g_cell_adec_core_ops_Celp8; +vm::gvar g_cell_adec_core_ops_Celp; +vm::gvar g_cell_adec_core_ops_Ddp; +vm::gvar g_cell_adec_core_ops_DtsCore; +vm::gvar g_cell_adec_core_ops_DtsHd_Core; +vm::gvar g_cell_adec_core_ops_DtsHd; +vm::gvar g_cell_adec_core_ops_DtsLbr; +vm::gvar g_cell_adec_core_ops_Aac; +vm::gvar g_cell_adec_core_ops_mpmc; +vm::gvar g_cell_adec_core_ops_M4Aac; +vm::gvar g_cell_adec_core_ops_M4Aac2ch; +vm::gvar g_cell_adec_core_ops_M4Aac2chmod; +vm::gvar g_cell_adec_core_ops_Mp3; +vm::gvar g_cell_adec_core_ops_Mp3s; +vm::gvar g_cell_adec_core_ops_mpmcl1; +vm::gvar g_cell_adec_core_ops_truehd; +vm::gvar g_cell_adec_core_ops_wma; +vm::gvar g_cell_adec_core_ops_WmaLsl; +vm::gvar g_cell_adec_core_ops_WmaPro; +error_code _SceAdecCorrectPtsValue_Celp8(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_Celp(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_Ddp(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_DtsCore(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_DtsHd_Core(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_DtsHd(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_DtsLbr(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_Aac(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_mpmc(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_M4Aac(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_M4Aac2ch(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_M4Aac2chmod(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_Mp3s(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_mpmcl1(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_truehd(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_wma(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_WmaLsl(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } +error_code _SceAdecCorrectPtsValue_WmaPro(ppu_thread&, vm::ptr, vm::ptr){ UNIMPLEMENTED_FUNC(cellAdec); return CELL_OK; } + template <> void fmt_class_string::format(std::string& out, u64 arg) { @@ -205,885 +220,946 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -class AudioDecoder : public ppu_thread + +// LPCM decoder (included in cellAdec/libadec.sprx) + +vm::gvar g_cell_adec_core_ops_lpcm; + +error_code _CellAdecCoreOpGetMemSize_lpcm(vm::ptr attr) { -public: - squeue_t job; - volatile bool is_closed = false; - volatile bool is_finished = false; - bool just_started = false; - bool just_finished = false; + cellAdec.todo("_CellAdecCoreOpGetMemSize_lpcm(attr=*0x%x)", attr); - const AVCodec* codec = nullptr; -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(59, 0, 0) - const AVInputFormat* input_format = nullptr; -#else - AVInputFormat* input_format = nullptr; -#endif - AVCodecContext* ctx = nullptr; - AVFormatContext* fmt = nullptr; - u8* io_buf = nullptr; - - struct AudioReader - { - u32 addr{}; - u32 size{}; - bool init{}; - bool has_ats{}; - - } reader; - - squeue_t frames; - - const s32 type; - const u32 memAddr; - const u32 memSize; - const vm::ptr cbFunc; - const u32 cbArg; - u32 memBias = 0; - - AdecTask task; - u64 last_pts{}; - u64 first_pts{}; - - u32 ch_out{}; - u32 ch_cfg{}; - u32 frame_size{}; - u32 sample_rate{}; - bool use_ats_headers{}; - - AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr func, u32 arg) - : ppu_thread({}, "", 0) - , type(type) - , memAddr(addr) - , memSize(size) - , cbFunc(func) - , cbArg(arg) - { - switch (type) - { - case CELL_ADEC_TYPE_ATRACX: - case CELL_ADEC_TYPE_ATRACX_2CH: - case CELL_ADEC_TYPE_ATRACX_6CH: - case CELL_ADEC_TYPE_ATRACX_8CH: - { - codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); - input_format = av_find_input_format("oma"); - break; - } - case CELL_ADEC_TYPE_MP3: - { - codec = avcodec_find_decoder(AV_CODEC_ID_MP3); - input_format = av_find_input_format("mp3"); - break; - } - default: - { - fmt::throw_exception("Unknown type (0x%x)", type); - } - } - - if (!codec) - { - fmt::throw_exception("avcodec_find_decoder() failed"); - } - if (!input_format) - { - fmt::throw_exception("av_find_input_format() failed"); - } - fmt = avformat_alloc_context(); - if (!fmt) - { - fmt::throw_exception("avformat_alloc_context() failed"); - } - io_buf = static_cast(av_malloc(4096)); - fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, nullptr, nullptr); - if (!fmt->pb) - { - fmt::throw_exception("avio_alloc_context() failed"); - } - } - - ~AudioDecoder() - { - // TODO: check finalization - AdecFrame af; - while (frames.try_pop(af)) - { - av_frame_unref(af.data); - av_frame_free(&af.data); - } - if (ctx) - { - avcodec_free_context(&ctx); - } - if (io_buf) - { - av_freep(&io_buf); - } - if (fmt) - { - if (fmt->pb) av_freep(&fmt->pb); - avformat_close_input(&fmt); - } - } - - void non_task() - { - while (true) - { - if (Emu.IsStopped() || is_closed) - { - break; - } - - if (!job.pop(task, &is_closed)) - { - break; - } - - switch (task.type) - { - case adecStartSeq: - { - // TODO: reset data - cellAdec.warning("adecStartSeq:"); - - reader.addr = 0; - reader.size = 0; - reader.init = false; - reader.has_ats = false; - just_started = true; - - if (adecIsAtracX(type)) - { - ch_cfg = task.at3p.channel_config; - ch_out = task.at3p.channels; - frame_size = task.at3p.frame_size; - sample_rate = task.at3p.sample_rate; - use_ats_headers = task.at3p.ats_header == 1; - } - break; - } - - case adecEndSeq: - { - // TODO: finalize - cellAdec.warning("adecEndSeq:"); - cbFunc(*this, id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, cbArg); - lv2_obj::sleep(*this); - - just_finished = true; - break; - } - - case adecDecodeAu: - { - int err = 0; - - reader.addr = task.au.addr; - reader.size = task.au.size; - reader.has_ats = use_ats_headers; - //cellAdec.notice("Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts); - - if (just_started) - { - first_pts = task.au.pts; - last_pts = task.au.pts; - if (adecIsAtracX(type)) last_pts -= 0x10000; // hack - } - - AVPacket* packet = av_packet_alloc(); - std::unique_ptr packet_(packet); - - if (just_started && just_finished) - { - avcodec_flush_buffers(ctx); - - reader.init = true; // wrong - just_finished = false; - just_started = false; - } - else if (just_started) // deferred initialization - { - AVDictionary* opts = nullptr; - err = av_dict_set(&opts, "probesize", "96", 0); - if (err < 0) - { - fmt::throw_exception("av_dict_set(probesize, 96) failed (err=0x%x='%s')", err, utils::av_error_to_string(err)); - } - err = avformat_open_input(&fmt, nullptr, input_format, &opts); - if (err || opts) - { - std::string dict_content; - if (opts) - { - AVDictionaryEntry* tag = nullptr; - while ((tag = av_dict_get(opts, "", tag, AV_DICT_IGNORE_SUFFIX))) - { - fmt::append(dict_content, "['%s': '%s']", tag->key, tag->value); - } - } - fmt::throw_exception("avformat_open_input() failed (err=0x%x='%s', opts=%s)", err, utils::av_error_to_string(err), dict_content); - } - //err = avformat_find_stream_info(fmt, NULL); - //if (err || !fmt->nb_streams) - //{ - // fmt::throw_exception("avformat_find_stream_info() failed (err=0x%x='%s', nb_streams=%d)", err, utils::av_error_to_string(err), fmt->nb_streams); - //} - if (!avformat_new_stream(fmt, codec)) - { - fmt::throw_exception("avformat_new_stream() failed"); - } - //ctx = fmt->streams[0]->codec; // TODO: check data - - opts = nullptr; - - { - std::lock_guard lock(g_mutex_avcodec_open2); - // not multithread-safe (???) - err = avcodec_open2(ctx, codec, &opts); - } - - if (err || opts) - { - std::string dict_content; - if (opts) - { - AVDictionaryEntry* tag = nullptr; - while ((tag = av_dict_get(opts, "", tag, AV_DICT_IGNORE_SUFFIX))) - { - fmt::append(dict_content, "['%s': '%s']", tag->key, tag->value); - } - } - fmt::throw_exception("avcodec_open2() failed (err=0x%x='%s', opts=%s)", err, utils::av_error_to_string(err), dict_content); - } - just_started = false; - } - - while (true) - { - if (Emu.IsStopped() || is_closed) - { - if (Emu.IsStopped()) cellAdec.warning("adecDecodeAu: aborted"); - break; - } - - av_read_frame(fmt, packet); - - struct AdecFrameHolder : AdecFrame - { - AdecFrameHolder() - { - data = av_frame_alloc(); - } - - ~AdecFrameHolder() - { - if (data) - { - av_frame_unref(data); - av_frame_free(&data); - } - } - - } frame; - - if (!frame.data) - { - fmt::throw_exception("av_frame_alloc() failed"); - } - - int got_frame = 0; - - int decode = 0; //avcodec_decode_audio4(ctx, frame.data, &got_frame, &au); - - if (decode <= 0) - { - if (decode < 0) - { - cellAdec.error("adecDecodeAu: AU decoding error(0x%x)", decode); - } - if (!got_frame && reader.size == 0) break; - } - - if (got_frame) - { - //u64 ts = av_frame_get_best_effort_timestamp(frame.data); - //if (ts != AV_NOPTS_VALUE) - //{ - // frame.pts = ts/* - first_pts*/; - // last_pts = frame.pts; - //} - last_pts += frame.data->nb_samples * 90000ull / frame.data->sample_rate; - frame.pts = last_pts; - - s32 nbps = av_get_bytes_per_sample(static_cast(frame.data->format)); - switch (frame.data->format) - { - case AV_SAMPLE_FMT_FLTP: break; - case AV_SAMPLE_FMT_S16P: break; - default: - { - fmt::throw_exception("Unsupported frame format(%d)", frame.data->format); - } - } - frame.auAddr = task.au.addr; - frame.auSize = task.au.size; - frame.userdata = task.au.userdata; - frame.size = frame.data->nb_samples * frame.data->ch_layout.nb_channels * nbps; - - //cellAdec.notice("got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)", - //frame.pts, frame.data->nb_samples, frame.data->ch_layout.nb_channels, frame.data->sample_rate, nbps); - - if (frames.push(frame, &is_closed)) - { - frame.data = nullptr; // to prevent destruction - cbFunc(*this, id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, cbArg); - lv2_obj::sleep(*this); - } - } - } - - cbFunc(*this, id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, cbArg); - lv2_obj::sleep(*this); - break; - } - - case adecClose: - { - break; - } - - default: - { - fmt::throw_exception("Unknown task(%d)", +task.type); - } - } - } - - is_finished = true; - } -}; - -int adecRead(void* opaque, u8* buf, int buf_size) -{ - AudioDecoder& adec = *static_cast(opaque); - - int res = 0; - -next: - if (adecIsAtracX(adec.type) && adec.reader.has_ats) - { - u8 code1 = vm::read8(adec.reader.addr + 2); - u8 code2 = vm::read8(adec.reader.addr + 3); - adec.ch_cfg = (code1 >> 2) & 0x7; - adec.frame_size = (((u32{code1} & 0x3) << 8) | code2) * 8 + 8; - adec.sample_rate = at3freq[code1 >> 5]; - - adec.reader.size -= 8; - adec.reader.addr += 8; - adec.reader.has_ats = false; - } - - if (adecIsAtracX(adec.type) && !adec.reader.init) - { - OMAHeader oma(1 /* atrac3p id */, adec.sample_rate, adec.ch_cfg, adec.frame_size); - if (buf_size + 0u < sizeof(oma)) - { - cellAdec.fatal("adecRead(): OMAHeader writing failed"); - return 0; - } - - memcpy(buf, &oma, sizeof(oma)); - buf += sizeof(oma); - buf_size -= sizeof(oma); - res += sizeof(oma); - - adec.reader.init = true; - } - - if (adec.reader.size < static_cast(buf_size) /*&& !adec.just_started*/) - { - AdecTask task; - if (!adec.job.peek(task, 0, &adec.is_closed)) - { - if (Emu.IsStopped()) cellAdec.warning("adecRawRead() aborted"); - return 0; - } - - switch (task.type) - { - case adecEndSeq: - case adecClose: - { - buf_size = adec.reader.size; - break; - } - case adecDecodeAu: - { - std::memcpy(buf, vm::base(adec.reader.addr), adec.reader.size); - - buf += adec.reader.size; - buf_size -= adec.reader.size; - res += adec.reader.size; - - adec.cbFunc(adec, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg); - - adec.job.pop(adec.task); - - adec.reader.addr = adec.task.au.addr; - adec.reader.size = adec.task.au.size; - adec.reader.has_ats = adec.use_ats_headers; - //cellAdec.notice("Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts); - break; - } - case adecStartSeq: // TODO ? - default: - { - cellAdec.fatal("adecRawRead(): unknown task (%d)", +task.type); - return -1; - } - } - - goto next; - } - else if (adec.reader.size < static_cast(buf_size) && 0) - { - buf_size = adec.reader.size; - } - - if (!buf_size) - { - return res; - } - - std::memcpy(buf, vm::base(adec.reader.addr), buf_size); - - adec.reader.addr += buf_size; - adec.reader.size -= buf_size; - return res + buf_size; + return CELL_OK; } -bool adecCheckType(s32 type) +[[noreturn]] error_code _CellAdecCoreOpOpenExt_lpcm(vm::ptr handle, vm::ptr notifyAuDone, vm::ptr notifyAuDoneArg, vm::ptr notifyPcmOut, vm::ptr notifyPcmOutArg, + vm::ptr notifyError, vm::ptr notifyErrorArg, vm::ptr notifySeqDone, vm::ptr notifySeqDoneArg, vm::cptr res, vm::cptr spursRes) +{ + cellAdec.todo("_CellAdecCoreOpOpenExt_lpcm(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=0x%x, notifyError=*0x%x, notifyErrorArg=0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=0x%x, res=*0x%x, spursRes=*0x%x)", + handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res, spursRes); + + fmt::throw_exception("LPCM decoder not implemented, please disable HLE libadec.sprx"); +} + +[[noreturn]] error_code _CellAdecCoreOpOpen_lpcm(vm::ptr handle, vm::ptr notifyAuDone, vm::ptr notifyAuDoneArg, vm::ptr notifyPcmOut, vm::ptr notifyPcmOutArg, + vm::ptr notifyError, vm::ptr notifyErrorArg, vm::ptr notifySeqDone, vm::ptr notifySeqDoneArg, vm::cptr res) +{ + cellAdec.todo("_CellAdecCoreOpOpen_lpcm(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=*0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=*0x%x, notifyError=*0x%x, notifyErrorArg=*0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=*0x%x, res=*0x%x)", + handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res); + + fmt::throw_exception("LPCM decoder not implemented, please disable HLE libadec.sprx"); +} + +error_code _CellAdecCoreOpClose_lpcm(vm::ptr handle) +{ + cellAdec.todo("_CellAdecCoreOpClose_lpcm(handle=*0x%x)", handle); + + return CELL_OK; +} + +error_code _CellAdecCoreOpStartSeq_lpcm(vm::ptr handle, vm::ptr lpcmParam) +{ + cellAdec.todo("_CellAdecCoreOpStartSeq_lpcm(handle=*0x%x, lpcmParam=*0x%x)", handle, lpcmParam); + + return CELL_OK; +} + +error_code _CellAdecCoreOpEndSeq_lpcm(vm::ptr handle) +{ + cellAdec.todo("_CellAdecCoreOpEndSeq_lpcm(handle=*0x%x)", handle); + + return CELL_OK; +} + +error_code _CellAdecCoreOpDecodeAu_lpcm(vm::ptr handle, s32 pcmHandle, vm::ptr auInfo) +{ + cellAdec.todo("_CellAdecCoreOpDecodeAu_lpcm(handle=*0x%x, pcmHandle=%d, auInfo=*0x%x)", handle, pcmHandle, auInfo); + + return CELL_OK; +} + +void _CellAdecCoreOpGetVersion_lpcm(vm::ptr> version) +{ + cellAdec.notice("_CellAdecCoreOpGetVersion_lpcm(version=*0x%x)", version); + + *version = 0x20070323; +} + +error_code _CellAdecCoreOpRealign_lpcm(vm::ptr handle, vm::ptr outBuffer, vm::cptr pcmStartAddr) +{ + cellAdec.todo("_CellAdecCoreOpRealign_lpcm(handle=*0x%x, outBuffer=*0x%x, pcmStartAddr=*0x%x)", handle, outBuffer, pcmStartAddr); + + return CELL_OK; +} + +error_code _CellAdecCoreOpReleasePcm_lpcm(vm::ptr handle, s32 pcmHandle, vm::ptr outBuffer) +{ + cellAdec.todo("_CellAdecCoreOpReleasePcm_lpcm(handle=*0x%x, pcmHandle=%d, outBuffer=*0x%x)", handle, pcmHandle, outBuffer); + + return CELL_OK; +} + +s32 _CellAdecCoreOpGetPcmHandleNum_lpcm() +{ + cellAdec.notice("_CellAdecCoreOpGetPcmHandleNum_lpcm()"); + + return 8; +} + +u32 _CellAdecCoreOpGetBsiInfoSize_lpcm() +{ + cellAdec.notice("_CellAdecCoreOpGetBsiInfoSize_lpcm()"); + + return sizeof(CellAdecLpcmInfo); +} + + +// cellAdec abstraction layer, operates the individual decoders + +error_code AdecContext::get_new_pcm_handle(vm::ptr au_info) const +{ + for (s32 i = 0; i < frames_num; i++) + { + if (!frames[i].in_use) + { + frames[i].in_use = true; + frames[i].au_info = *au_info; + return not_an_error(i); + } + } + + return CELL_ADEC_ERROR_BUSY; +} + +error_code AdecContext::verify_pcm_handle(s32 pcm_handle) const +{ + ensure(pcm_handle >= 0 && pcm_handle < frames_num); // Not properly checked on LLE, see below + + if ((pcm_handle < 0 && /* LLE uses && instead of || */ pcm_handle >= frames_num) || !frames[pcm_handle].in_use) + { + return CELL_ADEC_ERROR_FATAL; + } + + return CELL_OK; +} + +vm::ptr AdecContext::get_au_info(s32 pcm_handle) const +{ + if (verify_pcm_handle(pcm_handle) == static_cast(CELL_ADEC_ERROR_FATAL)) + { + return vm::null; + } + + return (frames + pcm_handle).ptr(&AdecFrame::au_info); +} + +void AdecContext::set_state(s32 pcm_handle, u32 state) const +{ + if (state == 1u << 9) + { + frames[pcm_handle].au_done = true; + } + else if (state == 1u << 11) + { + frames[pcm_handle].pcm_out = true; + } +} + +error_code AdecContext::get_pcm_item(s32 pcm_handle, vm::ptr& pcm_item) const +{ + if (verify_pcm_handle(pcm_handle) == static_cast(CELL_ADEC_ERROR_FATAL)) + { + return CELL_ADEC_ERROR_FATAL; + } + + pcm_item = (frames + pcm_handle).ptr(&AdecFrame::pcm_item); + + return CELL_OK; +} + +error_code AdecContext::set_pcm_item(s32 pcm_handle, vm::ptr pcm_addr, u32 pcm_size, vm::cpptr bitstream_info) const +{ + if (verify_pcm_handle(pcm_handle) == static_cast(CELL_ADEC_ERROR_FATAL)) + { + return CELL_ADEC_ERROR_FATAL; + } + + frames[pcm_handle].pcm_item.pcmHandle = pcm_handle; + frames[pcm_handle].pcm_item.status = CELL_OK; + frames[pcm_handle].pcm_item.startAddr = pcm_addr; + frames[pcm_handle].pcm_item.size = pcm_size; + frames[pcm_handle].pcm_item.auInfo = frames[pcm_handle].au_info; + std::memcpy(frames[pcm_handle].pcm_item.pcmAttr.bsiInfo.get_ptr(), bitstream_info->get_ptr(), bitstream_info_size); + + return CELL_OK; +} + +error_code AdecContext::link_frame(ppu_thread& ppu, s32 pcm_handle) +{ + ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE + + if (verify_pcm_handle(pcm_handle) == static_cast(CELL_ADEC_ERROR_FATAL)) + { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_ADEC_ERROR_FATAL; + } + + if (frames_tail == -1 && frames_head == -1) + { + frames[pcm_handle].next = pcm_handle; + frames[pcm_handle].prev = pcm_handle; + frames_head = pcm_handle; + frames_tail = pcm_handle; + } + else if (frames_tail != -1 && frames_head != -1) + { + frames[pcm_handle].next = pcm_handle; + frames[pcm_handle].prev = frames_tail; + frames[frames_tail].next = pcm_handle; + frames_tail = pcm_handle; + } + else + { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_ADEC_ERROR_FATAL; + } + + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_OK; +} + +error_code AdecContext::unlink_frame(ppu_thread& ppu, s32 pcm_handle) +{ + ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE + + if (verify_pcm_handle(pcm_handle) == static_cast(CELL_ADEC_ERROR_FATAL)) + { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_ADEC_ERROR_FATAL; + } + + if (frames_head == -1 || frames_tail == -1) + { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_ADEC_ERROR_FATAL; + } + + const s32 next = frames[pcm_handle].next; + const s32 prev = frames[pcm_handle].prev; + + if (frames_head == frames_tail) + { + if (pcm_handle != frames_tail) + { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_ADEC_ERROR_FATAL; + } + + frames_head = -1; + frames_tail = -1; + frames[pcm_handle].next = -1; + frames[pcm_handle].prev = -1; + } + else if (pcm_handle == frames_head) + { + frames_head = next; + frames[prev].next = next; + } + else if (pcm_handle == frames_tail) + { + frames_tail = prev; + frames[next].prev = prev; + } + else + { + frames[next].prev = prev; + frames[prev].next = next; + } + + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_OK; +} + +void AdecContext::reset_frame(s32 pcm_handle) const +{ + frames[pcm_handle].in_use = false; + frames[pcm_handle].au_done = false; + frames[pcm_handle].pcm_out = false; + frames[pcm_handle].next = -1; + frames[pcm_handle].prev = -1; +} + +error_code AdecContext::correct_pts_value(ppu_thread& ppu, s32 pcm_handle, s8 correct_pts_type) +{ + if (verify_pcm_handle(pcm_handle) == static_cast(CELL_ADEC_ERROR_FATAL)) + { + return CELL_ADEC_ERROR_FATAL; + } + + const vm::ptr au_pts = (frames + pcm_handle).ptr(&AdecFrame::au_info).ptr(&CellAdecAuInfo::pts); + + switch (correct_pts_type) + { + case ADEC_CORRECT_PTS_VALUE_TYPE_EAC3: return ppu_execute<&_SceAdecCorrectPtsValue_Ddp>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_DTSHD: return ppu_execute<&_SceAdecCorrectPtsValue_DtsHd>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_CELP: return ppu_execute<&_SceAdecCorrectPtsValue_Celp>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_M2AAC: return ppu_execute<&_SceAdecCorrectPtsValue_Aac>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_MPEG_L2: return ppu_execute<&_SceAdecCorrectPtsValue_mpmc>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_TRUEHD: return ppu_execute<&_SceAdecCorrectPtsValue_truehd>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_DTS: return ppu_execute<&_SceAdecCorrectPtsValue_DtsCore>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_M4AAC: + switch (type.audioCodecType) + { + case CELL_ADEC_TYPE_M4AAC: return ppu_execute<&_SceAdecCorrectPtsValue_M4Aac>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case CELL_ADEC_TYPE_M4AAC_2CH: return ppu_execute<&_SceAdecCorrectPtsValue_M4Aac2ch>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case CELL_ADEC_TYPE_M4AAC_2CH_MOD: return ppu_execute<&_SceAdecCorrectPtsValue_M4Aac2chmod>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + default: return CELL_OK; + } + + case ADEC_CORRECT_PTS_VALUE_TYPE_WMA: return ppu_execute<&_SceAdecCorrectPtsValue_wma>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_DTSLBR: return ppu_execute<&_SceAdecCorrectPtsValue_DtsLbr>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_MPEG_L1: return ppu_execute<&_SceAdecCorrectPtsValue_mpmcl1>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_MP3S: return ppu_execute<&_SceAdecCorrectPtsValue_Mp3s>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_CELP8: return ppu_execute<&_SceAdecCorrectPtsValue_Celp8>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_WMAPRO: return ppu_execute<&_SceAdecCorrectPtsValue_WmaPro>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_WMALSL: return ppu_execute<&_SceAdecCorrectPtsValue_WmaLsl>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + case ADEC_CORRECT_PTS_VALUE_TYPE_DTSHDCORE_UNK1: // Same as below + case ADEC_CORRECT_PTS_VALUE_TYPE_DTSHDCORE_UNK2: return ppu_execute<&_SceAdecCorrectPtsValue_DtsHd_Core>(ppu, +core_handle, au_pts) != CELL_OK ? static_cast(CELL_ADEC_ERROR_FATAL) : static_cast(CELL_OK); + } + + // If the user didn't set a PTS, we need to interpolate from the previous PTS + if (au_pts->upper == CODEC_TS_INVALID) + { + if (au_pts->lower != CODEC_TS_INVALID) + { + return CELL_ADEC_ERROR_FATAL; + } + + if (previous_pts.upper == CODEC_TS_INVALID && previous_pts.lower == CODEC_TS_INVALID) + { + return CELL_OK; + } + + const u32 pts_adjust = [&] + { + switch (correct_pts_type) + { + case ADEC_CORRECT_PTS_VALUE_TYPE_LPCM: return 450; + case 1: return 150; + case ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_48000Hz: return 3840; + case ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_44100Hz: return 4180; + case ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_32000Hz: return 5760; + case ADEC_CORRECT_PTS_VALUE_TYPE_AC3: return 2880; + case ADEC_CORRECT_PTS_VALUE_TYPE_ATRAC3: return 4180; + case ADEC_CORRECT_PTS_VALUE_TYPE_MP3_48000Hz: return 2160; + case ADEC_CORRECT_PTS_VALUE_TYPE_MP3_44100Hz: return 2351; + case ADEC_CORRECT_PTS_VALUE_TYPE_MP3_32000Hz: return 3240; + case ADEC_CORRECT_PTS_VALUE_TYPE_ATRAC3MULTI: return 3840; + default: return 0; + } + }(); + + au_pts->upper = previous_pts.upper; + au_pts->lower = previous_pts.lower + pts_adjust; + + if (au_pts->lower < previous_pts.lower) // overflow + { + au_pts->upper = (au_pts->upper + 1) & 1; + } + + if (au_pts->upper == CODEC_TS_INVALID) + { + return CELL_ADEC_ERROR_FATAL; + } + } + + if (au_pts->lower == CODEC_TS_INVALID) + { + return CELL_ADEC_ERROR_FATAL; + } + + previous_pts = *au_pts; + + return CELL_OK; +} + +static vm::cptr get_core_ops(s32 type) { switch (type) { - case CELL_ADEC_TYPE_ATRACX: cellAdec.notice("adecCheckType(): ATRAC3plus"); break; - case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec.notice("adecCheckType(): ATRAC3plus 2ch"); break; - case CELL_ADEC_TYPE_ATRACX_6CH: cellAdec.notice("adecCheckType(): ATRAC3plus 6ch"); break; - case CELL_ADEC_TYPE_ATRACX_8CH: cellAdec.notice("adecCheckType(): ATRAC3plus 8ch"); break; - case CELL_ADEC_TYPE_MP3: cellAdec.notice("adecCheckType(): MP3"); break; - - case CELL_ADEC_TYPE_LPCM_PAMF: - case CELL_ADEC_TYPE_AC3: - case CELL_ADEC_TYPE_ATRAC3: - case CELL_ADEC_TYPE_MPEG_L2: - case CELL_ADEC_TYPE_CELP: - case CELL_ADEC_TYPE_M4AAC: - case CELL_ADEC_TYPE_CELP8: - { - cellAdec.fatal("Unimplemented audio codec type (%d)", type); - break; + case CELL_ADEC_TYPE_INVALID1: fmt::throw_exception("Invalid audio codec: CELL_ADEC_TYPE_INVALID1"); + case CELL_ADEC_TYPE_LPCM_PAMF: return g_cell_adec_core_ops_lpcm; + case CELL_ADEC_TYPE_AC3: return vm::cptr::make(*ppu_module_manager::cell_libac3dec.variables.find(0xc58bb170)->second.export_addr); + case CELL_ADEC_TYPE_ATRACX: return vm::cptr::make(*ppu_module_manager::cellAtracXdec.variables.find(0x4944af9a)->second.export_addr); + case CELL_ADEC_TYPE_MP3: return vm::cptr::make(*ppu_module_manager::cellMP3dec.variables.find(0x84276a23)->second.export_addr); + case CELL_ADEC_TYPE_ATRAC3: return vm::cptr::make(*ppu_module_manager::cellAtrac3dec.variables.find(0x60487d65)->second.export_addr); + case CELL_ADEC_TYPE_MPEG_L2: return vm::cptr::make(*ppu_module_manager::cellM2BCdec.variables.find(0x300afe4d)->second.export_addr); + case CELL_ADEC_TYPE_M2AAC: return vm::cptr::make(*ppu_module_manager::cellM2AACdec.variables.find(0xac2f0831)->second.export_addr); + case CELL_ADEC_TYPE_EAC3: return vm::cptr::make(*ppu_module_manager::cellDDPdec.variables.find(0xf5e9c15c)->second.export_addr); + case CELL_ADEC_TYPE_TRUEHD: return vm::cptr::make(*ppu_module_manager::cellTRHDdec.variables.find(0xe88e381b)->second.export_addr); + case CELL_ADEC_TYPE_DTS: return vm::cptr::make(*ppu_module_manager::cellDTSdec.variables.find(0x15248ec5)->second.export_addr); + case CELL_ADEC_TYPE_CELP: return vm::cptr::make(*ppu_module_manager::cellCelpDec.variables.find(0xffe42c22)->second.export_addr); + case CELL_ADEC_TYPE_LPCM_BLURAY: return g_cell_adec_core_ops_lpcm; + case CELL_ADEC_TYPE_ATRACX_2CH: return vm::cptr::make(*ppu_module_manager::cellAtracXdec.variables.find(0x076b33ab)->second.export_addr); + case CELL_ADEC_TYPE_ATRACX_6CH: return vm::cptr::make(*ppu_module_manager::cellAtracXdec.variables.find(0x1d210eaa)->second.export_addr); + case CELL_ADEC_TYPE_ATRACX_8CH: return vm::cptr::make(*ppu_module_manager::cellAtracXdec.variables.find(0xe9a86e54)->second.export_addr); + case CELL_ADEC_TYPE_M4AAC: return vm::cptr::make(*ppu_module_manager::cellM4AacDec.variables.find(0xab61278d)->second.export_addr); + case CELL_ADEC_TYPE_LPCM_DVD: return g_cell_adec_core_ops_lpcm; + case CELL_ADEC_TYPE_WMA: return vm::cptr::make(*ppu_module_manager::cellWMAdec.variables.find(0x88320b10)->second.export_addr); + case CELL_ADEC_TYPE_DTSLBR: return vm::cptr::make(*ppu_module_manager::cellDTSLBRdec.variables.find(0x8c50af52)->second.export_addr); + case CELL_ADEC_TYPE_M4AAC_2CH: return vm::cptr::make(*ppu_module_manager::cellM4AacDec2ch.variables.find(0xe996c664)->second.export_addr); + case CELL_ADEC_TYPE_DTSHD: return vm::cptr::make(*ppu_module_manager::cellDTSHDdec.variables.find(0x51ac2b6c)->second.export_addr); + case CELL_ADEC_TYPE_MPEG_L1: return vm::cptr::make(*ppu_module_manager::cellMPL1dec.variables.find(0xbbc70551)->second.export_addr); + case CELL_ADEC_TYPE_MP3S: return vm::cptr::make(*ppu_module_manager::cellMP3Sdec.variables.find(0x292cdf0a)->second.export_addr); + case CELL_ADEC_TYPE_M4AAC_2CH_MOD: return vm::cptr::make(*ppu_module_manager::cellM4AacDec2chmod.variables.find(0xdbd26836)->second.export_addr); + case CELL_ADEC_TYPE_CELP8: return vm::cptr::make(*ppu_module_manager::cellCelp8Dec.variables.find(0xf0190c6c)->second.export_addr); + case CELL_ADEC_TYPE_INVALID2: fmt::throw_exception("Invalid audio codec: CELL_ADEC_TYPE_INVALID2"); + case CELL_ADEC_TYPE_INVALID3: fmt::throw_exception("Invalid audio codec: CELL_ADEC_TYPE_INVALID3"); + case CELL_ADEC_TYPE_RESERVED22: fmt::throw_exception("Invalid audio codec: CELL_ADEC_TYPE_RESERVED22"); + case CELL_ADEC_TYPE_RESERVED23: fmt::throw_exception("Invalid audio codec: CELL_ADEC_TYPE_RESERVED23"); + case CELL_ADEC_TYPE_DTSHDCORE: return vm::cptr::make(*ppu_module_manager::cellDTSHDCOREdec.variables.find(0x6c8f4f1c)->second.export_addr); + case CELL_ADEC_TYPE_ATRAC3MULTI: return vm::cptr::make(*ppu_module_manager::cellAtrac3multidec.variables.find(0xc20c6bd7)->second.export_addr); + default: fmt::throw_exception("Invalid audio codec: %d", type); } - default: return false; - } - - return true; } -error_code cellAdecQueryAttr(vm::ptr type, vm::ptr attr) +error_code adecNotifyAuDone(ppu_thread& ppu, s32 pcmHandle, vm::ptr handle) { - cellAdec.warning("cellAdecQueryAttr(type=*0x%x, attr=*0x%x)", type, attr); + // Block savestate creation during callbacks + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; - if (!adecCheckType(type->audioCodecType)) + if (!savestate_lock.owns_lock()) { - return CELL_ADEC_ERROR_ARG; + ppu.state += cpu_flag::again; + return {}; } - // TODO: check values - attr->adecVerLower = 0x280000; // from dmux - attr->adecVerUpper = 0x260000; - attr->workMemSize = 256 * 1024; // 256 KB + cellAdec.trace("adecNotifyAuDone(pcmHandle=%d, handle=*0x%x)", pcmHandle, handle); + + ensure(!!handle); // Not checked on LLE + + const auto au_info = handle->get_au_info(pcmHandle); + + if (!au_info) + { + return CELL_ADEC_ERROR_FATAL; + } + + handle->set_state(pcmHandle, 1u << 9); + + handle->callback.cbFunc(ppu, handle, CELL_ADEC_MSG_TYPE_AUDONE, static_cast(au_info.addr()), handle->callback.cbArg); return CELL_OK; } -error_code cellAdecOpen(vm::ptr type, vm::ptr res, vm::ptr cb, vm::ptr handle) +error_code adecNotifyPcmOut(ppu_thread& ppu, s32 pcmHandle, vm::ptr pcmAddr, u32 pcmSize, vm::ptr handle, vm::cpptr bsiInfo, s8 correctPtsValueType, s32 errorCode) { - cellAdec.warning("cellAdecOpen(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); + // Block savestate creation during callbacks + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; - if (!adecCheckType(type->audioCodecType)) + if (!savestate_lock.owns_lock()) { - return CELL_ADEC_ERROR_ARG; + ppu.state += cpu_flag::again; + return {}; } - fmt::throw_exception("cellAdec disabled, use LLE."); -} + cellAdec.trace("adecNotifyPcmOut(pcmHandle=%d, pcmAddr=*0x%x, pcmSize=0x%x, handle=*0x%x, bsiInfo=**0x%x, correctPtsValueType=%d, errorCode=0x%x)", pcmHandle, pcmAddr, pcmSize, handle, bsiInfo, correctPtsValueType, errorCode); -error_code cellAdecOpenEx(vm::ptr type, vm::ptr res, vm::ptr cb, vm::ptr handle) -{ - cellAdec.warning("cellAdecOpenEx(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); + ensure(!!handle && !!bsiInfo && !!*bsiInfo); // Not checked on LLE - if (!adecCheckType(type->audioCodecType)) + if (!handle->get_au_info(pcmHandle)) { - return CELL_ADEC_ERROR_ARG; + return CELL_ADEC_ERROR_FATAL; } - fmt::throw_exception("cellAdec disabled, use LLE."); -} - -error_code cellAdecOpenExt(vm::ptr type, vm::ptr res, vm::ptr cb, vm::ptr handle) -{ - cellAdec.warning("cellAdecOpenExt(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); - - return cellAdecOpenEx(type, res, cb, handle); -} - -error_code cellAdecClose(u32 handle) -{ - cellAdec.warning("cellAdecClose(handle=0x%x)", handle); - - const auto adec = idm::get(handle); - - if (!adec) + if (error_code ret = handle->correct_pts_value(ppu, pcmHandle, correctPtsValueType); ret != CELL_OK) { - return CELL_ADEC_ERROR_ARG; + return ret; } - adec->is_closed = true; - adec->job.try_push(AdecTask(adecClose)); - - while (!adec->is_finished) + if (handle->link_frame(ppu, pcmHandle) == static_cast(CELL_ADEC_ERROR_FATAL)) { - thread_ctrl::wait_for(1000); // hack + return CELL_ADEC_ERROR_FATAL; } - if (!idm::remove_verify(handle, std::move(adec))) + handle->set_state(pcmHandle, 1u << 11); + + if (handle->set_pcm_item(pcmHandle, pcmAddr, pcmSize, bsiInfo) == static_cast(CELL_ADEC_ERROR_FATAL)) { - // Removed by other thread beforehead - return CELL_ADEC_ERROR_ARG; + return CELL_ADEC_ERROR_FATAL; } + vm::ptr pcm_item{}; + + if (handle->get_pcm_item(pcmHandle, pcm_item) == static_cast(CELL_ADEC_ERROR_FATAL)) + { + return CELL_ADEC_ERROR_FATAL; + } + + if (handle->pcm_queue.push(ppu, pcm_item, pcmHandle) != CELL_OK) + { + return CELL_ADEC_ERROR_FATAL; + } + + if (handle->pcm_item_queue.push(ppu, pcm_item, pcmHandle) != CELL_OK) + { + return CELL_ADEC_ERROR_FATAL; + } + + handle->callback.cbFunc(ppu, handle, CELL_ADEC_MSG_TYPE_PCMOUT, errorCode, handle->callback.cbArg); + return CELL_OK; } -error_code cellAdecStartSeq(u32 handle, u32 param) +error_code adecNotifyError(ppu_thread& ppu, s32 errorCode, vm::ptr handle) { - cellAdec.warning("cellAdecStartSeq(handle=0x%x, param=*0x%x)", handle, param); + // Block savestate creation during callbacks + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; - const auto adec = idm::get(handle); + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } - if (!adec) + cellAdec.error("adecNotifyError(errorCode=0x%x, handle=*0x%x)", errorCode, handle); + + ensure(!!handle); // Not checked on LLE + + handle->callback.cbFunc(ppu, handle, CELL_ADEC_MSG_TYPE_ERROR, errorCode, handle->callback.cbArg); + + return CELL_OK; +} + +error_code adecNotifySeqDone(ppu_thread& ppu, vm::ptr handle) +{ + // Block savestate creation during callbacks + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellAdec.notice("adecNotifySeqDone(handle=*0x%x)", handle); + + ensure(!!handle); // Not checked on LLE + + handle->callback.cbFunc(ppu, handle, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, handle->callback.cbArg); + + return CELL_OK; +} + +error_code cellAdecQueryAttr(ppu_thread& ppu, vm::ptr type, vm::ptr attr) +{ + // Block savestate creation during ppu_thread::fast_call() + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellAdec.notice("cellAdecQueryAttr(type=*0x%x, attr=*0x%x)", type, attr); + + if (!type || type->audioCodecType >= 32 || type->audioCodecType == CELL_ADEC_TYPE_INVALID1 || type->audioCodecType == CELL_ADEC_TYPE_INVALID2 || type->audioCodecType == CELL_ADEC_TYPE_INVALID3 || !attr) { return CELL_ADEC_ERROR_ARG; } - AdecTask task(adecStartSeq); + const auto core_ops = get_core_ops(type->audioCodecType); - switch (adec->type) - { - case CELL_ADEC_TYPE_ATRACX: - case CELL_ADEC_TYPE_ATRACX_2CH: - case CELL_ADEC_TYPE_ATRACX_6CH: - case CELL_ADEC_TYPE_ATRACX_8CH: - { - const auto atx = vm::cptr::make(param); + core_ops->getMemSize(ppu, attr); - task.at3p.sample_rate = atx->sampling_freq; - task.at3p.channel_config = atx->ch_config_idx; - task.at3p.channels = atx->nch_out; - task.at3p.frame_size = atx->nbytes; - task.at3p.extra_config = atx->extra_config_data; - task.at3p.output = atx->bw_pcm; - task.at3p.downmix = atx->downmix_flag; - task.at3p.ats_header = atx->au_includes_ats_hdr_flg; - cellAdec.todo("*** CellAdecParamAtracX: sr=%d, ch_cfg=%d(%d), frame_size=0x%x, extra=%u:%u:%u:%u, output=%d, downmix=%d, ats_header=%d", - task.at3p.sample_rate, task.at3p.channel_config, task.at3p.channels, task.at3p.frame_size, - task.at3p.extra_config[0], task.at3p.extra_config[1], task.at3p.extra_config[2], task.at3p.extra_config[3], - task.at3p.output, task.at3p.downmix, task.at3p.ats_header); - break; - } - case CELL_ADEC_TYPE_MP3: - { - const auto mp3 = vm::cptr::make(param); + const s32 pcm_handle_num = core_ops->getPcmHandleNum(ppu); + const u32 bitstream_info_size = core_ops->getBsiInfoSize(ppu); + attr->workMemSize += static_cast((bitstream_info_size + sizeof(AdecFrame)) * pcm_handle_num + sizeof(AdecContext) + 0x7f); - cellAdec.todo("*** CellAdecParamMP3: bw_pcm=%d", mp3->bw_pcm); - break; - } - default: - { - cellAdec.fatal("cellAdecStartSeq(): Unimplemented audio codec type(%d)", adec->type); - return CELL_OK; - } - } + const vm::var> ver_lower; + core_ops->getVersion(ppu, ver_lower); + + attr->adecVerUpper = 0x491000; + attr->adecVerLower = *ver_lower; - adec->job.push(task, &adec->is_closed); return CELL_OK; } -error_code cellAdecEndSeq(u32 handle) +error_code adecOpen(ppu_thread& ppu, vm::ptr type, vm::cptr res, vm::cptr cb, vm::pptr handle, vm::cptr spursRes) { - cellAdec.warning("cellAdecEndSeq(handle=0x%x)", handle); - - const auto adec = idm::get(handle); - - if (!adec) + if (!type || type->audioCodecType >= 32 || !res || !res->startAddr || res->ppuThreadPriority >= 0xa00 || res->spuThreadPriority >= 0x100 || res->ppuThreadStackSize < 0x1000 || !cb || !cb->cbFunc || !handle) { return CELL_ADEC_ERROR_ARG; } - adec->job.push(AdecTask(adecEndSeq), &adec->is_closed); - return CELL_OK; + if (vm::var attr; cellAdecQueryAttr(ppu, type, attr), res->totalMemSize < attr->workMemSize) + { + return CELL_ADEC_ERROR_FATAL; + } + + const auto core_ops = get_core_ops(type->audioCodecType); + + const s32 pcm_handle_num = core_ops->getPcmHandleNum(ppu); + const u32 bitstream_info_size = core_ops->getBsiInfoSize(ppu); + + const auto _this = vm::ptr::make(utils::align(+res->startAddr, 0x80)); + const auto frames = vm::ptr::make(_this.addr() + sizeof(AdecContext)); + const u32 bitstream_infos_addr = frames.addr() + pcm_handle_num * sizeof(AdecFrame); + const auto core_handle = vm::ptr::make(utils::align(bitstream_infos_addr + bitstream_info_size * pcm_handle_num, 0x80)); + + if (type->audioCodecType == CELL_ADEC_TYPE_LPCM_DVD) + { + // TODO + } + else if (type->audioCodecType == CELL_ADEC_TYPE_LPCM_PAMF || type->audioCodecType == CELL_ADEC_TYPE_LPCM_BLURAY) + { + // TODO + } + + _this->_this = _this; + _this->this_size = sizeof(AdecContext) + (bitstream_info_size + sizeof(AdecFrame)) * pcm_handle_num; + _this->unk = 0; + _this->sequence_state = AdecSequenceState::dormant; + _this->type = *type; + _this->res = *res; + _this->callback = *cb; + _this->core_handle = core_handle; + _this->core_ops = core_ops; + _this->previous_pts = { CODEC_TS_INVALID, CODEC_TS_INVALID }; + _this->frames_num = pcm_handle_num; + _this->reserved1 = 0; + _this->frames_head = -1; + _this->frames_tail = -1; + _this->frames = frames; + _this->bitstream_info_size = bitstream_info_size; + _this->mutex_attribute = { SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, SYS_SYNC_NOT_PROCESS_SHARED, SYS_SYNC_NOT_ADAPTIVE, 0, 0, 0, { "_adem03"_u64 } }; + + _this->pcm_queue.init(ppu, _this.ptr(&AdecContext::pcm_queue)); + _this->pcm_item_queue.init(ppu, _this.ptr(&AdecContext::pcm_item_queue)); + + for (s32 i = 0; i < pcm_handle_num; i++) + { + frames[i].in_use = false; + frames[i].this_index = i; + frames[i].au_done = false; + frames[i].unk1 = false; + frames[i].pcm_out = false; + frames[i].unk2 = false; + frames[i].pcm_item.pcmAttr.bsiInfo.set(bitstream_infos_addr + bitstream_info_size * i); + frames[i].reserved1 = 0; + frames[i].reserved2 = 0; + frames[i].next = 0; + frames[i].prev = 0; + } + + ensure(sys_mutex_create(ppu, _this.ptr(&AdecContext::mutex), _this.ptr(&AdecContext::mutex_attribute)) == CELL_OK); // Error code isn't checked on LLE + + *handle = _this; + + const auto notifyAuDone = vm::ptr::make(g_fxo->get().func_addr(FIND_FUNC(adecNotifyAuDone))); + const auto notifyPcmOut = vm::ptr::make(g_fxo->get().func_addr(FIND_FUNC(adecNotifyPcmOut))); + const auto notifyError = vm::ptr::make(g_fxo->get().func_addr(FIND_FUNC(adecNotifyError))); + const auto notifySeqDone = vm::ptr::make(g_fxo->get().func_addr(FIND_FUNC(adecNotifySeqDone))); + + // Block savestate creation during ppu_thread::fast_call() + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + + if (spursRes) + { + return core_ops->openExt(ppu, _this->core_handle, notifyAuDone, _this, notifyPcmOut, _this, notifyError, _this, notifySeqDone, _this, res, spursRes); + } + + return core_ops->open(ppu, _this->core_handle, notifyAuDone, _this, notifyPcmOut, _this, notifyError, _this, notifySeqDone, _this, res); } -error_code cellAdecDecodeAu(u32 handle, vm::ptr auInfo) +error_code cellAdecOpen(ppu_thread& ppu, vm::ptr type, vm::ptr res, vm::ptr cb, vm::pptr handle) { - cellAdec.trace("cellAdecDecodeAu(handle=0x%x, auInfo=*0x%x)", handle, auInfo); + cellAdec.notice("cellAdecOpen(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); - const auto adec = idm::get(handle); + return adecOpen(ppu, type, res, cb, handle, vm::null); +} - if (!adec) +error_code cellAdecOpenExt(ppu_thread& ppu, vm::ptr type, vm::ptr res, vm::ptr cb, vm::pptr handle) +{ + cellAdec.notice("cellAdecOpenExt(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); + + if (!res) { return CELL_ADEC_ERROR_ARG; } - AdecTask task(adecDecodeAu); - task.au.auInfo_addr = auInfo.addr(); - task.au.addr = auInfo->startAddr.addr(); - task.au.size = auInfo->size; - task.au.pts = (u64{auInfo->pts.upper} << 32) | u64{auInfo->pts.lower}; - task.au.userdata = auInfo->userData; + const vm::var _res{{ res->totalMemSize, res->startAddr, res->ppuThreadPriority, 0, res->ppuThreadStackSize }}; + const vm::var spursRes{{ res->spurs_addr, res->priority, res->maxContention }}; + + return adecOpen(ppu, type, _res, cb, handle, spursRes); +} + +error_code cellAdecOpenEx(ppu_thread& ppu, vm::ptr type, vm::ptr res, vm::ptr cb, vm::pptr handle) +{ + cellAdec.notice("cellAdecOpenEx(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); + + return cellAdecOpenExt(ppu, type, res, cb, handle); +} + +error_code cellAdecClose(ppu_thread& ppu, vm::ptr handle) +{ + // Block savestate creation during ppu_thread::fast_call() + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellAdec.notice("cellAdecClose(handle=*0x%x)", handle); + + if (!handle || handle->_this != handle) + { + return CELL_ADEC_ERROR_ARG; + } + + if (error_code ret = handle->core_ops->close(ppu, handle->core_handle); ret != CELL_OK) + { + return ret; + } + + if (error_code ret = sys_mutex_destroy(ppu, handle->mutex); ret != CELL_OK) + { + return ret; + } + + if (error_code ret = handle->pcm_queue.finalize(ppu); ret != CELL_OK) + { + return ret; + } + + if (error_code ret = handle->pcm_item_queue.finalize(ppu); ret != CELL_OK) + { + return ret; + } + + handle->_this = vm::null; + handle->sequence_state = AdecSequenceState::closed; - //cellAdec.notice("cellAdecDecodeAu(): addr=0x%x, size=0x%x, pts=0x%llx", task.au.addr, task.au.size, task.au.pts); - adec->job.push(task, &adec->is_closed); return CELL_OK; } -error_code cellAdecGetPcm(u32 handle, vm::ptr outBuffer) +error_code cellAdecStartSeq(ppu_thread& ppu, vm::ptr handle, vm::ptr param) { + // Block savestate creation during ppu_thread::fast_call() + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellAdec.notice("cellAdecStartSeq(handle=*0x%x, param=*0x%x)", handle, param); + + if (!handle || !param) + { + return CELL_ADEC_ERROR_ARG; + } + + if (handle->sequence_state != AdecSequenceState::dormant && handle->sequence_state != AdecSequenceState::ready) + { + return CELL_ADEC_ERROR_SEQ; + } + + if (error_code ret = handle->core_ops->startSeq(ppu, handle->core_handle, param); ret != CELL_OK) + { + return ret; + } + + handle->sequence_state = AdecSequenceState::ready; + + return CELL_OK; +} + +error_code cellAdecEndSeq(ppu_thread& ppu, vm::ptr handle) +{ + // Block savestate creation during ppu_thread::fast_call() + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellAdec.notice("cellAdecEndSeq(handle=*0x%x)", handle); + + if (!handle || handle->_this != handle) + { + return CELL_ADEC_ERROR_ARG; + } + + if (handle->sequence_state != AdecSequenceState::ready) + { + return CELL_ADEC_ERROR_SEQ; + } + + // LLE does not set the sequence state to dormant + + return handle->core_ops->endSeq(ppu, handle->core_handle); +} + +error_code cellAdecDecodeAu(ppu_thread& ppu, vm::ptr handle, vm::ptr auInfo) +{ + // Block savestate creation during ppu_thread::fast_call() + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellAdec.trace("cellAdecDecodeAu(handle=*0x%x, auInfo=*0x%x)", handle, auInfo); + + if (!handle || !auInfo || !auInfo->size) + { + return CELL_ADEC_ERROR_ARG; + } + + cellAdec.trace("cellAdecDecodeAu(): startAddr=*0x%x, size=0x%x, pts=0x%llx, userData=0x%llx", auInfo->startAddr, auInfo->size, std::bit_cast>(auInfo->pts), auInfo->userData); + + if (handle->sequence_state != AdecSequenceState::ready) + { + return CELL_ADEC_ERROR_SEQ; + } + + if (!auInfo->startAddr) + { + return CELL_ADEC_ERROR_ARG; + } + + const error_code pcmHandle = handle->get_new_pcm_handle(auInfo); + + if (pcmHandle == static_cast(CELL_ADEC_ERROR_BUSY)) + { + return CELL_ADEC_ERROR_BUSY; + } + + if (handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_BLURAY) + { + // TODO + } + else if (handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_DVD) + { + // TODO + } + + return handle->core_ops->decodeAu(ppu, handle->core_handle, pcmHandle, auInfo); +} + +error_code cellAdecGetPcm(ppu_thread& ppu, vm::ptr handle, vm::ptr outBuffer) +{ + // Block savestate creation during ppu_thread::fast_call() + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + + ppu.state += cpu_flag::wait; + cellAdec.trace("cellAdecGetPcm(handle=0x%x, outBuffer=*0x%x)", handle, outBuffer); - const auto adec = idm::get(handle); - - if (!adec) + if (!handle) { return CELL_ADEC_ERROR_ARG; } - AdecFrame af; - if (!adec->frames.try_pop(af)) + // If the pcm_handles are equal, then cellAdecGetPcmItem() was not called before cellAdecGetPcm(). We need to pop pcm_item_queue as well + if (handle->pcm_item_queue.peek(ppu).pcm_handle == handle->pcm_queue.peek(ppu).pcm_handle) + { + handle->pcm_item_queue.pop(ppu); + } + + const auto pcm_queue_entry = handle->pcm_queue.pop(ppu); + + if (!pcm_queue_entry) { - //std::this_thread::sleep_for(1ms); // hack return CELL_ADEC_ERROR_EMPTY; } - std::unique_ptr frame(af.data, [](AVFrame* frame) - { - av_frame_unref(frame); - av_frame_free(&frame); - }); + const auto pcm_item = pcm_queue_entry->pcm_item; - if (outBuffer) + if (handle->verify_pcm_handle(pcm_item->pcmHandle) == static_cast(CELL_ADEC_ERROR_FATAL)) { - // reverse byte order: - if (frame->format == AV_SAMPLE_FMT_FLTP && frame->ch_layout.nb_channels == 1) - { - float* in_f = reinterpret_cast(frame->extended_data[0]); - for (u32 i = 0; i < af.size / 4; i++) - { - outBuffer[i] = in_f[i]; - } - } - else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->ch_layout.nb_channels == 2) - { - float* in_f[2]; - in_f[0] = reinterpret_cast(frame->extended_data[0]); - in_f[1] = reinterpret_cast(frame->extended_data[1]); - for (u32 i = 0; i < af.size / 8; i++) - { - outBuffer[i * 2 + 0] = in_f[0][i]; - outBuffer[i * 2 + 1] = in_f[1][i]; - } - } - else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->ch_layout.nb_channels == 6) - { - float* in_f[6]; - in_f[0] = reinterpret_cast(frame->extended_data[0]); - in_f[1] = reinterpret_cast(frame->extended_data[1]); - in_f[2] = reinterpret_cast(frame->extended_data[2]); - in_f[3] = reinterpret_cast(frame->extended_data[3]); - in_f[4] = reinterpret_cast(frame->extended_data[4]); - in_f[5] = reinterpret_cast(frame->extended_data[5]); - for (u32 i = 0; i < af.size / 24; i++) - { - outBuffer[i * 6 + 0] = in_f[0][i]; - outBuffer[i * 6 + 1] = in_f[1][i]; - outBuffer[i * 6 + 2] = in_f[2][i]; - outBuffer[i * 6 + 3] = in_f[3][i]; - outBuffer[i * 6 + 4] = in_f[4][i]; - outBuffer[i * 6 + 5] = in_f[5][i]; - } - } - else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->ch_layout.nb_channels == 8) - { - float* in_f[8]; - in_f[0] = reinterpret_cast(frame->extended_data[0]); - in_f[1] = reinterpret_cast(frame->extended_data[1]); - in_f[2] = reinterpret_cast(frame->extended_data[2]); - in_f[3] = reinterpret_cast(frame->extended_data[3]); - in_f[4] = reinterpret_cast(frame->extended_data[4]); - in_f[5] = reinterpret_cast(frame->extended_data[5]); - in_f[6] = reinterpret_cast(frame->extended_data[6]); - in_f[7] = reinterpret_cast(frame->extended_data[7]); - for (u32 i = 0; i < af.size / 24; i++) - { - outBuffer[i * 8 + 0] = in_f[0][i]; - outBuffer[i * 8 + 1] = in_f[1][i]; - outBuffer[i * 8 + 2] = in_f[2][i]; - outBuffer[i * 8 + 3] = in_f[3][i]; - outBuffer[i * 8 + 4] = in_f[4][i]; - outBuffer[i * 8 + 5] = in_f[5][i]; - outBuffer[i * 8 + 6] = in_f[6][i]; - outBuffer[i * 8 + 7] = in_f[7][i]; - } - } - else if (frame->format == AV_SAMPLE_FMT_S16P && frame->ch_layout.nb_channels == 1) - { - s16* in_i = reinterpret_cast(frame->extended_data[0]); - for (u32 i = 0; i < af.size / 2; i++) - { - outBuffer[i] = in_i[i] / 32768.f; - } - } - else if (frame->format == AV_SAMPLE_FMT_S16P && frame->ch_layout.nb_channels == 2) - { - s16* in_i[2]; - in_i[0] = reinterpret_cast(frame->extended_data[0]); - in_i[1] = reinterpret_cast(frame->extended_data[1]); - for (u32 i = 0; i < af.size / 4; i++) - { - outBuffer[i * 2 + 0] = in_i[0][i] / 32768.f; - outBuffer[i * 2 + 1] = in_i[1][i] / 32768.f; - } - } - else - { - fmt::throw_exception("Unsupported frame format (channels=%d, format=%d)", frame->ch_layout.nb_channels, frame->format); - } + return CELL_ADEC_ERROR_FATAL; } + if (handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_PAMF || handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_BLURAY || handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_DVD) + { + // TODO + } + + if (error_code ret = handle->core_ops->realign(ppu, handle->core_handle, outBuffer, pcm_queue_entry->pcm_item->startAddr); ret != CELL_OK) + { + return ret; + } + + if (error_code ret = handle->core_ops->releasePcm(ppu, handle->core_handle, pcm_item->pcmHandle, outBuffer); ret != CELL_OK) + { + return ret; + } + + if (handle->unlink_frame(ppu, pcm_item->pcmHandle) == static_cast(CELL_ADEC_ERROR_FATAL)) + { + return CELL_ADEC_ERROR_FATAL; + } + + handle->reset_frame(pcm_item->pcmHandle); + return CELL_OK; } -error_code cellAdecGetPcmItem(u32 handle, vm::pptr pcmItem) +error_code cellAdecGetPcmItem(ppu_thread& ppu, vm::ptr handle, vm::pptr pcmItem) { - cellAdec.trace("cellAdecGetPcmItem(handle=0x%x, pcmItem=**0x%x)", handle, pcmItem); + cellAdec.trace("cellAdecGetPcmItem(handle=*0x%x, pcmItem=**0x%x)", handle, pcmItem); - const auto adec = idm::get(handle); - - if (!adec) + if (!handle) { return CELL_ADEC_ERROR_ARG; } - AdecFrame af; - if (!adec->frames.try_peek(af)) + if (!pcmItem) + { + return CELL_ADEC_ERROR_FATAL; + } + + const auto pcm_item_entry = handle->pcm_item_queue.pop(ppu); + + if (ppu.state & cpu_flag::again) // Savestate was created while waiting on the queue mutex + { + return {}; + } + + if (!pcm_item_entry) { - //std::this_thread::sleep_for(1ms); // hack return CELL_ADEC_ERROR_EMPTY; } - AVFrame* frame = af.data; + *pcmItem = pcm_item_entry->pcm_item; - const auto pcm = vm::ptr::make(adec->memAddr + adec->memBias); - - adec->memBias += 512; - if (adec->memBias + 512 > adec->memSize) - { - adec->memBias = 0; - } - - pcm->pcmHandle = 0; // ??? - pcm->pcmAttr.bsiInfo_addr = pcm.addr() + u32{sizeof(CellAdecPcmItem)}; - pcm->startAddr = 0x00000312; // invalid address (no output) - pcm->size = af.size; - pcm->status = CELL_OK; - pcm->auInfo.pts.lower = static_cast(af.pts); - pcm->auInfo.pts.upper = static_cast(af.pts >> 32); - pcm->auInfo.size = af.auSize; - pcm->auInfo.startAddr.set(af.auAddr); - pcm->auInfo.userData = af.userdata; - - if (adecIsAtracX(adec->type)) - { - auto atx = vm::ptr::make(pcm.addr() + u32{sizeof(CellAdecPcmItem)}); - - atx->samplingFreq = frame->sample_rate; - atx->nbytes = frame->nb_samples * u32{sizeof(float)}; - - switch (frame->ch_layout.nb_channels) - { - case 1: - case 2: - case 6: - { - atx->channelConfigIndex = frame->ch_layout.nb_channels; - break; - } - case 8: - { - atx->channelConfigIndex = 7; - break; - } - default: - { - cellAdec.fatal("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->ch_layout.nb_channels); - break; - } - } - } - else if (adec->type == CELL_ADEC_TYPE_MP3) - { - auto mp3 = vm::ptr::make(pcm.addr() + u32{sizeof(CellAdecPcmItem)}); - - // TODO - memset(mp3.get_ptr(), 0, sizeof(CellAdecMP3Info)); - } - - *pcmItem = pcm; return CELL_OK; } DECLARE(ppu_module_manager::cellAdec)("cellAdec", []() { - static ppu_static_module cell_libac3dec("cell_libac3dec"); - static ppu_static_module cellAtrac3dec("cellAtrac3dec"); - static ppu_static_module cellCelpDec("cellCelpDec"); - static ppu_static_module cellDTSdec("cellDTSdec"); - static ppu_static_module cellM2AACdec("cellM2AACdec"); - static ppu_static_module cellM2BCdec("cellM2BCdec"); - static ppu_static_module cellM4AacDec("cellM4AacDec"); - static ppu_static_module cellMP3dec("cellMP3dec"); - static ppu_static_module cellTRHDdec("cellTRHDdec"); - static ppu_static_module cellWMAdec("cellWMAdec"); - static ppu_static_module cellDTSLBRdec("cellDTSLBRdec"); - static ppu_static_module cellDDPdec("cellDDPdec"); - static ppu_static_module cellM4AacDec2ch("cellM4AacDec2ch"); - static ppu_static_module cellDTSHDdec("cellDTSHDdec"); - static ppu_static_module cellMPL1dec("cellMPL1dec"); - static ppu_static_module cellMP3Sdec("cellMP3Sdec"); - static ppu_static_module cellM4AacDec2chmod("cellM4AacDec2chmod"); - static ppu_static_module cellCelp8Dec("cellCelp8Dec"); - static ppu_static_module cellWMAPROdec("cellWMAPROdec"); - static ppu_static_module cellWMALSLdec("cellWMALSLdec"); - static ppu_static_module cellDTSHDCOREdec("cellDTSHDCOREdec"); - static ppu_static_module cellAtrac3multidec("cellAtrac3multidec"); - REG_FUNC(cellAdec, cellAdecQueryAttr); REG_FUNC(cellAdec, cellAdecOpen); REG_FUNC(cellAdec, cellAdecOpenEx); @@ -1094,4 +1170,168 @@ DECLARE(ppu_module_manager::cellAdec)("cellAdec", []() REG_FUNC(cellAdec, cellAdecDecodeAu); REG_FUNC(cellAdec, cellAdecGetPcm); REG_FUNC(cellAdec, cellAdecGetPcmItem); + + REG_HIDDEN_FUNC(adecNotifyAuDone); + REG_HIDDEN_FUNC(adecNotifyPcmOut); + REG_HIDDEN_FUNC(adecNotifyError); + REG_HIDDEN_FUNC(adecNotifySeqDone); + + ppu_static_variable& lpcm_gvar = REG_VAR(cellAdec, g_cell_adec_core_ops_lpcm); + lpcm_gvar.flags = MFF_HIDDEN; + lpcm_gvar.init = [] + { + g_cell_adec_core_ops_lpcm->getMemSize.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_lpcm))); + g_cell_adec_core_ops_lpcm->open.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpOpen_lpcm))); + g_cell_adec_core_ops_lpcm->close.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpClose_lpcm))); + g_cell_adec_core_ops_lpcm->startSeq.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpStartSeq_lpcm))); + g_cell_adec_core_ops_lpcm->endSeq.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpEndSeq_lpcm))); + g_cell_adec_core_ops_lpcm->decodeAu.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpDecodeAu_lpcm))); + g_cell_adec_core_ops_lpcm->getVersion.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpGetVersion_lpcm))); + g_cell_adec_core_ops_lpcm->realign.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpRealign_lpcm))); + g_cell_adec_core_ops_lpcm->releasePcm.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpReleasePcm_lpcm))); + g_cell_adec_core_ops_lpcm->getPcmHandleNum.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpGetPcmHandleNum_lpcm))); + g_cell_adec_core_ops_lpcm->getBsiInfoSize.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpGetBsiInfoSize_lpcm))); + g_cell_adec_core_ops_lpcm->openExt.set(g_fxo->get().func_addr(FIND_FUNC(_CellAdecCoreOpOpenExt_lpcm))); + }; + + REG_HIDDEN_FUNC(_CellAdecCoreOpGetMemSize_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpOpen_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpClose_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpStartSeq_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpEndSeq_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpDecodeAu_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpGetVersion_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpRealign_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpReleasePcm_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpGetPcmHandleNum_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpGetBsiInfoSize_lpcm); + REG_HIDDEN_FUNC(_CellAdecCoreOpOpenExt_lpcm); +}); + +DECLARE(ppu_module_manager::cell_libac3dec)("cell_libac3dec", [] +{ + REG_VNID(cell_libac3dec, 0xc58bb170, g_cell_adec_core_ops_ac3); +}); + +DECLARE(ppu_module_manager::cellAtrac3dec)("cellAtrac3dec", [] +{ + REG_VNID(cellAtrac3dec, 0x60487d65, g_cell_adec_core_ops_atrac3); +}); + +DECLARE(ppu_module_manager::cellAtrac3multidec)("cellAtrac3multidec", [] +{ + REG_VNID(cellAtrac3multidec, 0xc20c6bd7, g_cell_adec_core_ops_atrac3multi); +}); + +DECLARE(ppu_module_manager::cellCelp8Dec)("cellCelp8Dec", [] +{ + REG_VNID(cellCelp8Dec, 0xf0190c6c, g_cell_adec_core_ops_Celp8); + REG_FUNC(cellCelp8Dec, _SceAdecCorrectPtsValue_Celp8); +}); + +DECLARE(ppu_module_manager::cellCelpDec)("cellCelpDec", [] +{ + REG_VNID(cellCelpDec, 0xffe42c22, g_cell_adec_core_ops_Celp); + REG_FUNC(cellCelpDec, _SceAdecCorrectPtsValue_Celp); +}); + +DECLARE(ppu_module_manager::cellDDPdec)("cellDDPdec", [] +{ + REG_VNID(cellDDPdec, 0xf5e9c15c, g_cell_adec_core_ops_Ddp); + REG_FUNC(cellDDPdec, _SceAdecCorrectPtsValue_Ddp); +}); + +DECLARE(ppu_module_manager::cellDTSdec)("cellDTSdec", [] +{ + REG_VNID(cellDTSdec, 0x15248ec5, g_cell_adec_core_ops_DtsCore); + REG_FUNC(cellDTSdec, _SceAdecCorrectPtsValue_DtsCore); +}); + +DECLARE(ppu_module_manager::cellDTSHDCOREdec)("cellDTSHDCOREdec", [] +{ + REG_VNID(cellDTSHDCOREdec, 0x6c8f4f1c, g_cell_adec_core_ops_DtsHd_Core); + REG_FUNC(cellDTSHDCOREdec, _SceAdecCorrectPtsValue_DtsHd_Core); +}); + +DECLARE(ppu_module_manager::cellDTSHDdec)("cellDTSHDdec", [] +{ + REG_VNID(cellDTSHDdec, 0x51ac2b6c, g_cell_adec_core_ops_DtsHd); + REG_FUNC(cellDTSHDdec, _SceAdecCorrectPtsValue_DtsHd); +}); + +DECLARE(ppu_module_manager::cellDTSLBRdec)("cellDTSLBRdec", [] +{ + REG_VNID(cellDTSLBRdec, 0x8c50af52, g_cell_adec_core_ops_DtsLbr); + REG_FUNC(cellDTSLBRdec, _SceAdecCorrectPtsValue_DtsLbr); +}); + +DECLARE(ppu_module_manager::cellM2AACdec)("cellM2AACdec", [] +{ + REG_VNID(cellM2AACdec, 0xac2f0831, g_cell_adec_core_ops_Aac); + REG_FUNC(cellM2AACdec, _SceAdecCorrectPtsValue_Aac); +}); + +DECLARE(ppu_module_manager::cellM2BCdec)("cellM2BCdec", [] +{ + REG_VNID(cellM2BCdec, 0x300afe4d, g_cell_adec_core_ops_mpmc); + REG_FUNC(cellM2BCdec, _SceAdecCorrectPtsValue_mpmc); +}); + +DECLARE(ppu_module_manager::cellM4AacDec)("cellM4AacDec", [] +{ + REG_VNID(cellM4AacDec, 0xab61278d, g_cell_adec_core_ops_M4Aac); + REG_FUNC(cellM4AacDec, _SceAdecCorrectPtsValue_M4Aac); +}); + +DECLARE(ppu_module_manager::cellM4AacDec2ch)("cellM4AacDec2ch", [] +{ + REG_VNID(cellM4AacDec2ch, 0xe996c664, g_cell_adec_core_ops_M4Aac2ch); + REG_FUNC(cellM4AacDec2ch, _SceAdecCorrectPtsValue_M4Aac2ch); +}); + +DECLARE(ppu_module_manager::cellM4AacDec2chmod)("cellM4AacDec2chmod", [] +{ + REG_VNID(cellM4AacDec2chmod, 0xdbd26836, g_cell_adec_core_ops_M4Aac2chmod); + REG_FUNC(cellM4AacDec2chmod, _SceAdecCorrectPtsValue_M4Aac2chmod); +}); + +DECLARE(ppu_module_manager::cellMP3dec)("cellMP3dec", [] +{ + REG_VNID(cellMP3dec, 0x84276a23, g_cell_adec_core_ops_Mp3); +}); + +DECLARE(ppu_module_manager::cellMP3Sdec)("cellMP3Sdec", [] +{ + REG_VNID(cellMP3Sdec, 0x292cdf0a, g_cell_adec_core_ops_Mp3s); + REG_FUNC(cellMP3Sdec, _SceAdecCorrectPtsValue_Mp3s); +}); + +DECLARE(ppu_module_manager::cellMPL1dec)("cellMPL1dec", [] +{ + REG_VNID(cellMPL1dec, 0xbbc70551, g_cell_adec_core_ops_mpmcl1); + REG_FUNC(cellMPL1dec, _SceAdecCorrectPtsValue_mpmcl1); +}); + +DECLARE(ppu_module_manager::cellTRHDdec)("cellTRHDdec", [] +{ + REG_VNID(cellTRHDdec, 0xe88e381b, g_cell_adec_core_ops_truehd); + REG_FUNC(cellTRHDdec, _SceAdecCorrectPtsValue_truehd); +}); + +DECLARE(ppu_module_manager::cellWMAdec)("cellWMAdec", [] +{ + REG_VNID(cellWMAdec, 0x88320b10, g_cell_adec_core_ops_wma); + REG_FUNC(cellWMAdec, _SceAdecCorrectPtsValue_wma); +}); + +DECLARE(ppu_module_manager::cellWMALSLdec)("cellWMALSLdec", [] +{ + REG_VNID(cellWMALSLdec, 0x602aab16, g_cell_adec_core_ops_WmaLsl); + REG_FUNC(cellWMALSLdec, _SceAdecCorrectPtsValue_WmaLsl); +}); + +DECLARE(ppu_module_manager::cellWMAPROdec)("cellWMAPROdec", [] +{ + REG_VNID(cellWMAPROdec, 0xa8bac670, g_cell_adec_core_ops_WmaPro); + REG_FUNC(cellWMAPROdec, _SceAdecCorrectPtsValue_WmaPro); }); diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.h b/rpcs3/Emu/Cell/Modules/cellAdec.h index ffa0cde002..1cbeca08b8 100644 --- a/rpcs3/Emu/Cell/Modules/cellAdec.h +++ b/rpcs3/Emu/Cell/Modules/cellAdec.h @@ -1,6 +1,8 @@ #pragma once -#include "Emu/Memory/vm_ptr.h" +#include "cellPamf.h" // CellCodecTimeStamp +#include "../lv2/sys_mutex.h" +#include "../lv2/sys_cond.h" // Error Codes enum CellAdecError : u32 @@ -222,14 +224,6 @@ enum AudioCodecType : s32 CELL_ADEC_TYPE_ATRAC3MULTI, }; -inline bool adecIsAtracX(s32 type) -{ - return type == CELL_ADEC_TYPE_ATRACX - || type == CELL_ADEC_TYPE_ATRACX_2CH - || type == CELL_ADEC_TYPE_ATRACX_6CH - || type == CELL_ADEC_TYPE_ATRACX_8CH; -} - // Output Channel Number enum CellAdecChannel : s32 { @@ -295,14 +289,14 @@ struct CellAdecResourceEx be_t ppuThreadPriority; be_t ppuThreadStackSize; be_t spurs_addr; - u8 priority[8]; + be_t priority; be_t maxContention; }; struct CellAdecResourceSpurs { be_t spurs_addr; // CellSpurs* - u8 priority[8]; + be_t priority; be_t maxContention; }; @@ -315,7 +309,7 @@ enum CellAdecMsgType : s32 CELL_ADEC_MSG_TYPE_SEQDONE, }; -using CellAdecCbMsg = s32(u32 handle, CellAdecMsgType msgType, s32 msgData, u32 cbArg); +using CellAdecCbMsg = s32(vm::ptr handle, CellAdecMsgType msgType, s32 msgData, vm::ptr cbArg); // Used for internal callbacks as well template @@ -339,14 +333,14 @@ struct CellAdecAuInfo // BSI Info struct CellAdecPcmAttr { - be_t bsiInfo_addr; + vm::bptr bsiInfo; }; struct CellAdecPcmItem { - be_t pcmHandle; + be_t pcmHandle; be_t status; - be_t startAddr; + vm::bcptr startAddr; be_t size; CellAdecPcmAttr pcmAttr; CellAdecAuInfo auInfo; @@ -363,36 +357,31 @@ enum AdecCorrectPtsValueType : s8 ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_48000Hz = 2, ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_44100Hz = 3, ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_32000Hz = 4, - // 5: Dolby Digital - // 6: ATRAC3 - // 7: MP3 - // 8: MP3 - // 9: MP3 - // 39: ATRAC3 multi-track + ADEC_CORRECT_PTS_VALUE_TYPE_AC3 = 5, + ADEC_CORRECT_PTS_VALUE_TYPE_ATRAC3 = 6, + ADEC_CORRECT_PTS_VALUE_TYPE_MP3_48000Hz = 7, + ADEC_CORRECT_PTS_VALUE_TYPE_MP3_44100Hz = 8, + ADEC_CORRECT_PTS_VALUE_TYPE_MP3_32000Hz = 9, + ADEC_CORRECT_PTS_VALUE_TYPE_ATRAC3MULTI = 39, // Calls a decoder function (_SceAdecCorrectPtsValue_codec()) - // 17: Dolby Digital Plus - // 18 - // 19 - // 20 - // 21: DTS HD - // 22 - // 23 - // 24: CELP - // 25: MPEG-2 AAC - // 26: MPEG-2 BC - // 27: Dolby TrueHD - // 28: DTS - // 29: MPEG-4 AAC - // 30: Windows Media Audio - // 31: DTS Express - // 32: MP1 - // 33: MP3 Surround - // 34: CELP8 - // 35: Windows Media Audio Professional - // 36: Windows Media Audio Lossless - // 37: DTS HD Core - // 38: DTS HD Core + ADEC_CORRECT_PTS_VALUE_TYPE_EAC3 = 17, + ADEC_CORRECT_PTS_VALUE_TYPE_DTSHD = 21, + ADEC_CORRECT_PTS_VALUE_TYPE_CELP = 24, + ADEC_CORRECT_PTS_VALUE_TYPE_M2AAC = 25, + ADEC_CORRECT_PTS_VALUE_TYPE_MPEG_L2 = 26, + ADEC_CORRECT_PTS_VALUE_TYPE_TRUEHD = 27, + ADEC_CORRECT_PTS_VALUE_TYPE_DTS = 28, + ADEC_CORRECT_PTS_VALUE_TYPE_M4AAC = 29, + ADEC_CORRECT_PTS_VALUE_TYPE_WMA = 30, + ADEC_CORRECT_PTS_VALUE_TYPE_DTSLBR = 31, + ADEC_CORRECT_PTS_VALUE_TYPE_MPEG_L1 = 32, + ADEC_CORRECT_PTS_VALUE_TYPE_MP3S = 33, + ADEC_CORRECT_PTS_VALUE_TYPE_CELP8 = 34, + ADEC_CORRECT_PTS_VALUE_TYPE_WMAPRO = 35, + ADEC_CORRECT_PTS_VALUE_TYPE_WMALSL = 36, + ADEC_CORRECT_PTS_VALUE_TYPE_DTSHDCORE_UNK1 = 37, + ADEC_CORRECT_PTS_VALUE_TYPE_DTSHDCORE_UNK2 = 38, }; // Internal callbacks @@ -471,6 +460,194 @@ struct AdecCmdQueue bool full() const { return size >= 4; } }; +struct AdecFrame +{ + b8 in_use; // True after issuing a decode command until the frame is consumed + + be_t this_index; // Set when initialized in cellAdecOpen(), unused afterward + + // Set when the corresponding callback is received, unused afterward + b8 au_done; + b8 unk1; + b8 pcm_out; + b8 unk2; + + CellAdecAuInfo au_info; + CellAdecPcmItem pcm_item; + + u32 reserved1; + u32 reserved2; + + // Frames that are ready to be consumed form a linked list. However, this list is not used (AdecOutputQueue is used instead) + be_t next; // Index of the next frame that can be consumed + be_t prev; // Index of the previous frame that can be consumed +}; + +CHECK_SIZE(AdecFrame, 0x68); + +class AdecOutputQueue +{ + struct entry + { + be_t this_index; // Unused + be_t state; // 0xff = empty, 0x10 = filled + vm::bptr pcm_item; + be_t pcm_handle; + } + entries[4]; + + be_t front; + be_t back; + be_t size; + + be_t mutex; // sys_mutex_t + be_t cond; // sys_cond_t, unused + +public: + void init(ppu_thread& ppu, vm::ptr _this) + { + this->front = 0; + this->back = 0; + this->size = 0; + + const vm::var mutex_attr = {{ SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, SYS_SYNC_NOT_PROCESS_SHARED, SYS_SYNC_NOT_ADAPTIVE, 0, 0, 0, { "_adem07"_u64 } }}; + ensure(sys_mutex_create(ppu, _this.ptr(&AdecOutputQueue::mutex), mutex_attr) == CELL_OK); // Error code isn't checked on LLE + + const vm::var cond_attr = {{ SYS_SYNC_NOT_PROCESS_SHARED, 0, 0, { "_adec05"_u64 } }}; + ensure(sys_cond_create(ppu, _this.ptr(&AdecOutputQueue::cond), mutex, cond_attr) == CELL_OK); // Error code isn't checked on LLE + + for (s32 i = 0; i < 4; i++) + { + entries[i] = { i, 0xff, vm::null, -1 }; + } + } + + error_code finalize(ppu_thread& ppu) const + { + if (error_code ret = sys_cond_destroy(ppu, cond); ret != CELL_OK) + { + return ret; + } + + if (error_code ret = sys_mutex_destroy(ppu, mutex); ret != CELL_OK) + { + return ret; + } + + return CELL_OK; + } + + error_code push(ppu_thread& ppu, vm::ptr pcm_item, s32 pcm_handle) + { + ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE + + if (entries[back].state != 0xff) + { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return true; // LLE returns the result of the comparison above + } + + entries[back].state = 0x10; + entries[back].pcm_item = pcm_item; + entries[back].pcm_handle = pcm_handle; + + back = (back + 1) & 3; + size++; + + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_OK; + } + + const entry* pop(ppu_thread& ppu) + { + ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE + + if (entries[front].state == 0xff) + { + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return nullptr; + } + + const entry* const ret = &entries[front]; + + entries[front].state = 0xff; + entries[front].pcm_handle = -1; + + front = (front + 1) & 3; + size--; + + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return ret; + } + + const entry& peek(ppu_thread& ppu) const + { + ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE + const entry& ret = entries[front]; + ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE + return ret; + } +}; + +CHECK_SIZE(AdecOutputQueue, 0x54); + +enum class AdecSequenceState : u32 +{ + dormant = 0x100, + ready = 0x200, + closed = 0xa00, +}; + +struct AdecContext // CellAdecHandle = AdecContext* +{ + vm::bptr _this; + be_t this_size; // Size of this struct + AdecFrames + bitstream info structs + + u32 unk; // Unused + + be_t sequence_state; + + CellAdecType type; + CellAdecResource res; + CellAdecCb callback; + + vm::bptr core_handle; + vm::bcptr core_ops; + + CellCodecTimeStamp previous_pts; + + be_t frames_num; + u32 reserved1; + be_t frames_head; // Index of the oldest frame that can be consumed + be_t frames_tail; // Index of the most recent frame that can be consumed + vm::bptr frames; // Array of AdecFrames, number of elements is return value of CellAdecCoreOps::getPcmHandleNum + + be_t bitstream_info_size; + + sys_mutex_attribute_t mutex_attribute; + be_t mutex; // sys_mutex_t + + AdecOutputQueue pcm_queue; // Output queue for cellAdecGetPcm() + AdecOutputQueue pcm_item_queue; // Output queue for cellAdecGetPcmItem() + + u8 reserved2[1028]; + + [[nodiscard]] error_code get_new_pcm_handle(vm::ptr au_info) const; + error_code verify_pcm_handle(s32 pcm_handle) const; + vm::ptr get_au_info(s32 pcm_handle) const; + void set_state(s32 pcm_handle, u32 state) const; + error_code get_pcm_item(s32 pcm_handle, vm::ptr& pcm_item) const; + error_code set_pcm_item(s32 pcm_handle, vm::ptr pcm_addr, u32 pcm_size, vm::cpptr bitstream_info) const; + error_code link_frame(ppu_thread& ppu, s32 pcm_handle); + error_code unlink_frame(ppu_thread& ppu, s32 pcm_handle); + void reset_frame(s32 pcm_handle) const; + error_code correct_pts_value(ppu_thread& ppu, s32 pcm_handle, s8 correct_pts_type); +}; + +static_assert(std::is_standard_layout_v && std::is_trivial_v); +CHECK_SIZE_ALIGN(AdecContext, 0x530, 8); + + struct CellAdecParamLpcm { be_t channelNumber; @@ -1024,106 +1201,3 @@ struct CellAdecMpmcInfo be_t lfePresent; be_t channelCoufiguration; }; - -/* Audio Decoder Thread Classes */ - -enum AdecJobType : u32 -{ - adecStartSeq, - adecEndSeq, - adecDecodeAu, - adecClose, -}; - -struct AdecTask -{ - AdecJobType type; - union - { - struct - { - u32 auInfo_addr; - u32 addr; - u32 size; - u64 pts; - u64 userdata; - } au; - - struct - { - s32 sample_rate; - s32 channel_config; - s32 channels; - s32 frame_size; - std::array extra_config; - s32 output; - u8 downmix; - u8 ats_header; - } at3p; - }; - - AdecTask(AdecJobType type) - : type(type) - { - } - - AdecTask() - { - } -}; - -struct AdecFrame -{ - struct AVFrame* data; - u64 pts; - u64 userdata; - u32 auAddr; - u32 auSize; - u32 size; -}; - -int adecRead(void* opaque, u8* buf, int buf_size); - -static const u32 at3freq[8] = { 32000, 44100, 48000, 88200, 96000, 0, 0, 0 }; - -struct OMAHeader // OMA Header -{ - u32 magic; // 0x01334145 - u16 size; // 96 << 8 - u16 unk0; // 0xffff - u64 unk1; // 0x00500f0100000000ULL - u64 unk2; // 0xcef5000000000400ULL - u64 unk3; // 0x1c458024329192d2ULL - u8 codecId; // 1 for ATRAC3P - u8 code0; // 0 - u8 code1; - u8 code2; - u32 reserved[15]; // 0 - - OMAHeader(u8 codec_id, u32 freq, u8 channel_count, u32 frame_size) - : magic(0x01334145) - , size(96 << 8) - , unk0(0xffff) - , unk1(0x00500f0100000000ULL) - , unk2(0xcef5000000000400ULL) - , unk3(0x1c458024329192d2ULL) - , codecId(codec_id) - , code0(0) - { - memset(reserved, 0, sizeof(reserved)); - - u8 freq_code; - for (freq_code = 0; freq_code < 5; freq_code++) - { - if (at3freq[freq_code] == freq) - { - break; - } - } - u32 prepared_frame_size = (frame_size - 8) / 8; - code1 = ((prepared_frame_size >> 8) & 0x3) | ((channel_count & 0x7) << 2) | (freq_code << 5); - code2 = prepared_frame_size & 0xff; - } -}; - -CHECK_SIZE(OMAHeader, 96); diff --git a/rpcs3/Emu/Cell/Modules/cellDmux.cpp b/rpcs3/Emu/Cell/Modules/cellDmux.cpp index f50fee1585..7850961aa9 100644 --- a/rpcs3/Emu/Cell/Modules/cellDmux.cpp +++ b/rpcs3/Emu/Cell/Modules/cellDmux.cpp @@ -1175,7 +1175,7 @@ error_code cellDmuxEnableEs(u32 handle, vm::cptr esFilterId const auto es = idm::make_ptr(dmux.get(), esResourceInfo->memAddr, esResourceInfo->memSize, esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2, - esCb->cbEsMsgFunc, esCb->cbArg, esSpecificInfo); + esCb->cbFunc, esCb->cbArg, esSpecificInfo); *esHandle = es->id; @@ -1359,8 +1359,6 @@ error_code cellDmuxFlushEs(u32 esHandle) DECLARE(ppu_module_manager::cellDmux)("cellDmux", []() { - static ppu_static_module cellDmuxPamf("cellDmuxPamf"); - REG_FUNC(cellDmux, cellDmuxQueryAttr); REG_FUNC(cellDmux, cellDmuxQueryAttr2); REG_FUNC(cellDmux, cellDmuxOpen); diff --git a/rpcs3/Emu/Cell/Modules/cellDmux.h b/rpcs3/Emu/Cell/Modules/cellDmux.h index 7be56a2705..884a3eb050 100644 --- a/rpcs3/Emu/Cell/Modules/cellDmux.h +++ b/rpcs3/Emu/Cell/Modules/cellDmux.h @@ -195,6 +195,13 @@ struct CellDmuxResourceEx be_t maxContention; }; +struct CellDmuxResourceSpurs +{ + vm::bptr spurs; // CellSpurs* + be_t priority; + be_t maxContention; +}; + /* struct CellDmuxResource2Ex { @@ -221,20 +228,20 @@ struct CellDmuxResource2 using CellDmuxCbMsg = u32(u32 demuxerHandle, vm::ptr demuxerMsg, u32 cbArg); -struct CellDmuxCb -{ - vm::bptr cbMsgFunc; - be_t cbArg; -}; - using CellDmuxCbEsMsg = u32(u32 demuxerHandle, u32 esHandle, vm::ptr esMsg, u32 cbArg); -struct CellDmuxEsCb +// Used for internal callbacks as well +template +struct DmuxCb { - vm::bptr cbEsMsgFunc; + vm::bptr cbFunc; be_t cbArg; }; +using CellDmuxCb = DmuxCb; + +using CellDmuxEsCb = DmuxCb; + struct CellDmuxAttr { be_t memSize; @@ -275,3 +282,46 @@ struct CellDmuxAuInfoEx CellCodecTimeStamp pts; CellCodecTimeStamp dts; }; + +struct CellDmuxPamfAttr; +struct CellDmuxPamfEsAttr; + +using DmuxNotifyDemuxDone = error_code(vm::ptr, u32, vm::ptr); +using DmuxNotifyFatalErr = error_code(vm::ptr, u32, vm::ptr); +using DmuxNotifyProgEndCode = error_code(vm::ptr, vm::ptr); + +using DmuxEsNotifyAuFound = error_code(vm::ptr, vm::cptr, vm::ptr); +using DmuxEsNotifyFlushDone = error_code(vm::ptr, vm::ptr); + +using CellDmuxCoreOpQueryAttr = error_code(vm::cptr, vm::ptr); +using CellDmuxCoreOpOpen = error_code(vm::cptr, vm::cptr, vm::cptr, vm::cptr>, vm::cptr>, vm::cptr>, vm::pptr); +using CellDmuxCoreOpClose = error_code(vm::ptr); +using CellDmuxCoreOpResetStream = error_code(vm::ptr); +using CellDmuxCoreOpCreateThread = error_code(vm::ptr); +using CellDmuxCoreOpJoinThread = error_code(vm::ptr); +using CellDmuxCoreOpSetStream = error_code(vm::ptr, vm::cptr, u32, b8, u64); +using CellDmuxCoreOpFreeMemory = error_code(vm::ptr, vm::ptr, u32); +using CellDmuxCoreOpQueryEsAttr = error_code(vm::cptr, vm::cptr, vm::ptr); +using CellDmuxCoreOpEnableEs = error_code(vm::ptr, vm::cptr, vm::cptr, vm::cptr>, vm::cptr>, vm::cptr, vm::pptr); +using CellDmuxCoreOpDisableEs = u32(vm::ptr); +using CellDmuxCoreOpFlushEs = u32(vm::ptr); +using CellDmuxCoreOpResetEs = u32(vm::ptr); +using CellDmuxCoreOpResetStreamAndWaitDone = u32(vm::ptr); + +struct CellDmuxCoreOps +{ + vm::bptr queryAttr; + vm::bptr open; + vm::bptr close; + vm::bptr resetStream; + vm::bptr createThread; + vm::bptr joinThread; + vm::bptr setStream; + vm::bptr freeMemory; + vm::bptr queryEsAttr; + vm::bptr enableEs; + vm::bptr disableEs; + vm::bptr flushEs; + vm::bptr resetEs; + vm::bptr resetStreamAndWaitDone; +}; diff --git a/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp b/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp new file mode 100644 index 0000000000..a7b24c3973 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp @@ -0,0 +1,170 @@ +#include "stdafx.h" +#include "Emu/Cell/PPUModule.h" +#include "Emu/IdManager.h" + +#include "cellPamf.h" +#include "cellDmux.h" +#include "cellDmuxPamf.h" + + +vm::gvar g_cell_dmux_core_ops_pamf; +vm::gvar g_cell_dmux_core_ops_raw_es; + +LOG_CHANNEL(cellDmuxPamf) + +error_code _CellDmuxCoreOpQueryAttr(vm::cptr pamfSpecificInfo, vm::ptr pamfAttr) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpQueryAttr(pamfSpecificInfo=*0x%x, pamfAttr=*0x%x)", pamfSpecificInfo, pamfAttr); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpOpen(vm::cptr pamfSpecificInfo, vm::cptr demuxerResource, vm::cptr demuxerResourceSpurs, vm::cptr> notifyDemuxDone, + vm::cptr> notifyProgEndCode, vm::cptr> notifyFatalErr, vm::pptr handle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpOpen(pamfSpecificInfo=*0x%x, demuxerResource=*0x%x, demuxerResourceSpurs=*0x%x, notifyDemuxDone=*0x%x, notifyProgEndCode=*0x%x, notifyFatalErr=*0x%x, handle=**0x%x)", + pamfSpecificInfo, demuxerResource, demuxerResourceSpurs, notifyDemuxDone, notifyProgEndCode, notifyFatalErr, handle); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpClose(vm::ptr handle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpClose(handle=*0x%x)", handle); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpResetStream(vm::ptr handle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpResetStream(handle=*0x%x)", handle); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpCreateThread(vm::ptr handle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpCreateThread(handle=*0x%x)", handle); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpJoinThread(vm::ptr handle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpJoinThread(handle=*0x%x)", handle); + + return CELL_OK; +} + +template +error_code _CellDmuxCoreOpSetStream(vm::ptr handle, vm::cptr streamAddress, u32 streamSize, b8 discontinuity, u64 userData) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpSetStream(handle=*0x%x, streamAddress=*0x%x, streamSize=0x%x, discontinuity=%d, userData=0x%llx)", raw_es, handle, streamAddress, streamSize, +discontinuity, userData); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpFreeMemory(vm::ptr esHandle, vm::ptr memAddr, u32 memSize) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpFreeMemory(esHandle=*0x%x, memAddr=*0x%x, memSize=0x%x)", esHandle, memAddr, memSize); + + return CELL_OK; +} + +template +error_code _CellDmuxCoreOpQueryEsAttr(vm::cptr esFilterId, vm::cptr esSpecificInfo, vm::ptr attr) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpQueryEsAttr(esFilterId=*0x%x, esSpecificInfo=*0x%x, attr=*0x%x)", raw_es, esFilterId, esSpecificInfo, attr); + + return CELL_OK; +} + +template +error_code _CellDmuxCoreOpEnableEs(vm::ptr handle, vm::cptr esFilterId, vm::cptr esResource, vm::cptr> notifyAuFound, + vm::cptr> notifyFlushDone, vm::cptr esSpecificInfo, vm::pptr esHandle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpEnableEs(handle=*0x%x, esFilterId=*0x%x, esResource=*0x%x, notifyAuFound=*0x%x, notifyFlushDone=*0x%x, esSpecificInfo=*0x%x, esHandle)", + raw_es, handle, esFilterId, esResource, notifyAuFound, notifyFlushDone, esSpecificInfo, esHandle); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpDisableEs(vm::ptr esHandle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpDisableEs(esHandle=*0x%x)", esHandle); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpFlushEs(vm::ptr esHandle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpFlushEs(esHandle=*0x%x)", esHandle); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpResetEs(vm::ptr esHandle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpResetEs(esHandle=*0x%x)", esHandle); + + return CELL_OK; +} + +error_code _CellDmuxCoreOpResetStreamAndWaitDone(vm::ptr handle) +{ + cellDmuxPamf.todo("_CellDmuxCoreOpResetStreamAndWaitDone(handle=*0x%x)", handle); + + return CELL_OK; +} + +static void init_gvar(const vm::gvar& var) +{ + var->queryAttr.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpQueryAttr))); + var->open.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpOpen))); + var->close.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpClose))); + var->resetStream.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpResetStream))); + var->createThread.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpCreateThread))); + var->joinThread.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpJoinThread))); + var->freeMemory.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpFreeMemory))); + var->disableEs.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpDisableEs))); + var->flushEs.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpFlushEs))); + var->resetEs.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpResetEs))); + var->resetStreamAndWaitDone.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpResetStreamAndWaitDone))); +} + +DECLARE(ppu_module_manager::cellDmuxPamf)("cellDmuxPamf", [] +{ + REG_VNID(cellDmuxPamf, 0x28b2b7b2, g_cell_dmux_core_ops_pamf).init = [] + { + g_cell_dmux_core_ops_pamf->setStream.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpSetStream))); + g_cell_dmux_core_ops_pamf->queryEsAttr.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpQueryEsAttr))); + g_cell_dmux_core_ops_pamf->enableEs.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpEnableEs))); + init_gvar(g_cell_dmux_core_ops_pamf); + }; + + REG_VNID(cellDmuxPamf, 0x9728a0e9, g_cell_dmux_core_ops_raw_es).init = [] + { + g_cell_dmux_core_ops_raw_es->setStream.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpSetStream))); + g_cell_dmux_core_ops_raw_es->queryEsAttr.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpQueryEsAttr))); + g_cell_dmux_core_ops_raw_es->enableEs.set(g_fxo->get().func_addr(FIND_FUNC(_CellDmuxCoreOpEnableEs))); + init_gvar(g_cell_dmux_core_ops_raw_es); + }; + + REG_HIDDEN_FUNC(_CellDmuxCoreOpQueryAttr); + REG_HIDDEN_FUNC(_CellDmuxCoreOpOpen); + REG_HIDDEN_FUNC(_CellDmuxCoreOpClose); + REG_HIDDEN_FUNC(_CellDmuxCoreOpResetStream); + REG_HIDDEN_FUNC(_CellDmuxCoreOpCreateThread); + REG_HIDDEN_FUNC(_CellDmuxCoreOpJoinThread); + REG_HIDDEN_FUNC(_CellDmuxCoreOpSetStream); + REG_HIDDEN_FUNC(_CellDmuxCoreOpSetStream); + REG_HIDDEN_FUNC(_CellDmuxCoreOpFreeMemory); + REG_HIDDEN_FUNC(_CellDmuxCoreOpQueryEsAttr); + REG_HIDDEN_FUNC(_CellDmuxCoreOpQueryEsAttr); + REG_HIDDEN_FUNC(_CellDmuxCoreOpEnableEs); + REG_HIDDEN_FUNC(_CellDmuxCoreOpEnableEs); + REG_HIDDEN_FUNC(_CellDmuxCoreOpDisableEs); + REG_HIDDEN_FUNC(_CellDmuxCoreOpFlushEs); + REG_HIDDEN_FUNC(_CellDmuxCoreOpResetEs); + REG_HIDDEN_FUNC(_CellDmuxCoreOpResetStreamAndWaitDone); +}); diff --git a/rpcs3/Emu/Cell/Modules/cellDmuxPamf.h b/rpcs3/Emu/Cell/Modules/cellDmuxPamf.h new file mode 100644 index 0000000000..01983b724a --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellDmuxPamf.h @@ -0,0 +1,15 @@ +#pragma once + +struct CellDmuxPamfAttr +{ + be_t maxEnabledEsNum; + be_t version; + be_t memSize; +}; + +struct CellDmuxPamfEsAttr +{ + be_t auQueueMaxSize; + be_t memSize; + be_t specificInfoSize; +}; diff --git a/rpcs3/Emu/Cell/PPUCallback.h b/rpcs3/Emu/Cell/PPUCallback.h index 8f25cb6c0b..f9254e29e9 100644 --- a/rpcs3/Emu/Cell/PPUCallback.h +++ b/rpcs3/Emu/Cell/PPUCallback.h @@ -66,9 +66,9 @@ namespace ppu_cb_detail static inline void set_value(ppu_thread& CPU, const T& arg) { - const s64 stack_pos = (g_count - 1) * 0x8 + 0x30 - FIXED_STACK_FRAME_SIZE; + const s64 stack_pos = (static_cast(g_count) - 1) * 0x8 + 0x30 - FIXED_STACK_FRAME_SIZE; static_assert(stack_pos < 0, "TODO: Increase FIXED_STACK_FRAME_SIZE (arg count limit broken)"); - vm::write64(CPU.gpr[1] + stack_pos, ppu_gpr_cast(arg)); // TODO + vm::write64(static_cast(CPU.gpr[1] + stack_pos), ppu_gpr_cast(arg)); // TODO } }; diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 627bb256ae..ae9b3ef47a 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -182,6 +182,8 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n { &ppu_module_manager::cellAdec, &ppu_module_manager::cellAtrac, + &ppu_module_manager::cellAtrac3dec, + &ppu_module_manager::cellAtrac3multidec, &ppu_module_manager::cellAtracMulti, &ppu_module_manager::cellAtracXdec, &ppu_module_manager::cellAudio, @@ -189,12 +191,20 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n &ppu_module_manager::cellAuthDialogUtility, &ppu_module_manager::cellBGDL, &ppu_module_manager::cellCamera, + &ppu_module_manager::cellCelp8Dec, &ppu_module_manager::cellCelp8Enc, + &ppu_module_manager::cellCelpDec, &ppu_module_manager::cellCelpEnc, &ppu_module_manager::cellCrossController, &ppu_module_manager::cellDaisy, + &ppu_module_manager::cellDDPdec, &ppu_module_manager::cellDmux, + &ppu_module_manager::cellDmuxPamf, &ppu_module_manager::cellDtcpIpUtility, + &ppu_module_manager::cellDTSdec, + &ppu_module_manager::cellDTSHDCOREdec, + &ppu_module_manager::cellDTSHDdec, + &ppu_module_manager::cellDTSLBRdec, &ppu_module_manager::cellFiber, &ppu_module_manager::cellFont, &ppu_module_manager::cellFontFT, @@ -213,8 +223,16 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n &ppu_module_manager::cellJpgEnc, &ppu_module_manager::cellKey2char, &ppu_module_manager::cellL10n, + &ppu_module_manager::cell_libac3dec, &ppu_module_manager::cellLibprof, + &ppu_module_manager::cellM2AACdec, + &ppu_module_manager::cellM2BCdec, + &ppu_module_manager::cellM4AacDec, + &ppu_module_manager::cellM4AacDec2ch, + &ppu_module_manager::cellM4AacDec2chmod, &ppu_module_manager::cellMic, + &ppu_module_manager::cellMP3dec, + &ppu_module_manager::cellMP3Sdec, &ppu_module_manager::cellMusic, &ppu_module_manager::cellMusicDecode, &ppu_module_manager::cellMusicExport, @@ -258,6 +276,7 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n &ppu_module_manager::cellSysutilAvcExt, &ppu_module_manager::cellSysutilNpEula, &ppu_module_manager::cellSysutilMisc, + &ppu_module_manager::cellTRHDdec, &ppu_module_manager::cellUsbd, &ppu_module_manager::cellUsbPspcm, &ppu_module_manager::cellUserInfo, @@ -267,6 +286,9 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n &ppu_module_manager::cellVideoUpload, &ppu_module_manager::cellVoice, &ppu_module_manager::cellVpost, + &ppu_module_manager::cellWMAdec, + &ppu_module_manager::cellWMALSLdec, + &ppu_module_manager::cellWMAPROdec, &ppu_module_manager::libad_async, &ppu_module_manager::libad_core, &ppu_module_manager::libfs_utility_init, diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h index 405fe76d45..fdcd736f38 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -167,6 +167,8 @@ public: static const ppu_static_module cellAdec; static const ppu_static_module cellAtrac; + static const ppu_static_module cellAtrac3dec; + static const ppu_static_module cellAtrac3multidec; static const ppu_static_module cellAtracMulti; static const ppu_static_module cellAtracXdec; static const ppu_static_module cellAudio; @@ -174,12 +176,20 @@ public: static const ppu_static_module cellAuthDialogUtility; static const ppu_static_module cellBGDL; static const ppu_static_module cellCamera; + static const ppu_static_module cellCelp8Dec; static const ppu_static_module cellCelp8Enc; + static const ppu_static_module cellCelpDec; static const ppu_static_module cellCelpEnc; static const ppu_static_module cellCrossController; static const ppu_static_module cellDaisy; + static const ppu_static_module cellDDPdec; static const ppu_static_module cellDmux; + static const ppu_static_module cellDmuxPamf; static const ppu_static_module cellDtcpIpUtility; + static const ppu_static_module cellDTSdec; + static const ppu_static_module cellDTSHDCOREdec; + static const ppu_static_module cellDTSHDdec; + static const ppu_static_module cellDTSLBRdec; static const ppu_static_module cellFiber; static const ppu_static_module cellFont; static const ppu_static_module cellFontFT; @@ -198,8 +208,17 @@ public: static const ppu_static_module cellJpgEnc; static const ppu_static_module cellKey2char; static const ppu_static_module cellL10n; + static const ppu_static_module cell_libac3dec; static const ppu_static_module cellLibprof; + static const ppu_static_module cellM2AACdec; + static const ppu_static_module cellM2BCdec; + static const ppu_static_module cellM4AacDec; + static const ppu_static_module cellM4AacDec2ch; + static const ppu_static_module cellM4AacDec2chmod; static const ppu_static_module cellMic; + static const ppu_static_module cellMP3dec; + static const ppu_static_module cellMP3Sdec; + static const ppu_static_module cellMPL1dec; static const ppu_static_module cellMusic; static const ppu_static_module cellMusicDecode; static const ppu_static_module cellMusicExport; @@ -243,6 +262,7 @@ public: static const ppu_static_module cellSysutilAvcExt; static const ppu_static_module cellSysutilNpEula; static const ppu_static_module cellSysutilMisc; + static const ppu_static_module cellTRHDdec; static const ppu_static_module cellUsbd; static const ppu_static_module cellUsbPspcm; static const ppu_static_module cellUserInfo; @@ -252,6 +272,9 @@ public: static const ppu_static_module cellVideoUpload; static const ppu_static_module cellVoice; static const ppu_static_module cellVpost; + static const ppu_static_module cellWMAdec; + static const ppu_static_module cellWMALSLdec; + static const ppu_static_module cellWMAPROdec; static const ppu_static_module libad_async; static const ppu_static_module libad_core; static const ppu_static_module libfs_utility_init; diff --git a/rpcs3/Emu/Cell/lv2/sys_net.cpp b/rpcs3/Emu/Cell/lv2/sys_net.cpp index 9b4428686a..efac7556d1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net.cpp @@ -54,7 +54,7 @@ void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](auto error) { - switch (s32 _error = error) + switch (static_cast(error)) { #define SYS_NET_ERROR_CASE(x) \ case -x: return "-" #x; \ @@ -1413,6 +1413,7 @@ error_code sys_net_bnet_poll(ppu_thread& ppu, vm::ptr fds, s32 n } has_timedout = network_clear_queue(ppu); + clear_ppu_to_awake(ppu); ppu.state -= cpu_flag::signal; break; } @@ -1646,6 +1647,7 @@ error_code sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptrget_name(), ppu->current_function, ppu->gpr[3], ppu->gpr[4], ppu->gpr[5], ppu->gpr[6]); ppu->gpr[3] = static_cast(-SYS_NET_EINTR); lv2_obj::append(ppu.get()); diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp index d5d53b6c70..02f5b2c697 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp @@ -165,11 +165,11 @@ void lv2_socket::queue_wake(ppu_thread* ppu) { case SYS_NET_SOCK_STREAM: case SYS_NET_SOCK_DGRAM: - g_fxo->get().ppu_to_awake.emplace_back(ppu); + g_fxo->get().add_ppu_to_awake(ppu); break; case SYS_NET_SOCK_DGRAM_P2P: case SYS_NET_SOCK_STREAM_P2P: - g_fxo->get().ppu_to_awake.emplace_back(ppu); + g_fxo->get().add_ppu_to_awake(ppu); break; default: break; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp index 72356c54e1..aaf79d4f41 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp @@ -85,8 +85,32 @@ namespace np void init_np_handler_dependencies(); } +void base_network_thread::add_ppu_to_awake(ppu_thread* ppu) +{ + std::lock_guard lock(mutex_ppu_to_awake); + ppu_to_awake.emplace_back(ppu); +} + +void base_network_thread::del_ppu_to_awake(ppu_thread* ppu) +{ + std::lock_guard lock(mutex_ppu_to_awake); + + for (auto it = ppu_to_awake.begin(); it != ppu_to_awake.end();) + { + if (*it == ppu) + { + it = ppu_to_awake.erase(it); + continue; + } + + it++; + } +} + void base_network_thread::wake_threads() { + std::lock_guard lock(mutex_ppu_to_awake); + ppu_to_awake.erase(std::unique(ppu_to_awake.begin(), ppu_to_awake.end()), ppu_to_awake.end()); for (ppu_thread* ppu : ppu_to_awake) { @@ -117,7 +141,10 @@ void network_thread::operator()() std::vector> socklist; socklist.reserve(lv2_socket::id_count); - ppu_to_awake.clear(); + { + std::lock_guard lock(mutex_ppu_to_awake); + ppu_to_awake.clear(); + } std::vector<::pollfd> fds(lv2_socket::id_count); #ifdef _WIN32 diff --git a/rpcs3/Emu/Cell/lv2/sys_net/network_context.h b/rpcs3/Emu/Cell/lv2/sys_net/network_context.h index 5cb846bd88..658196c4b4 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/network_context.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/network_context.h @@ -9,6 +9,10 @@ struct base_network_thread { + void add_ppu_to_awake(ppu_thread* ppu); + void del_ppu_to_awake(ppu_thread* ppu); + + shared_mutex mutex_ppu_to_awake; std::vector ppu_to_awake; void wake_threads(); diff --git a/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.cpp b/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.cpp index 8eb13bc168..0fabc61cae 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.cpp @@ -6,6 +6,8 @@ #include "lv2_socket.h" #include "sys_net_helpers.h" +#include "network_context.h" + LOG_CHANNEL(sys_net); int get_native_error() @@ -194,6 +196,12 @@ u32 network_clear_queue(ppu_thread& ppu) return cleared; } +void clear_ppu_to_awake(ppu_thread& ppu) +{ + g_fxo->get().del_ppu_to_awake(&ppu); + g_fxo->get().del_ppu_to_awake(&ppu); +} + #ifdef _WIN32 // Workaround function for WSAPoll not reporting failed connections void windows_poll(std::vector& fds, unsigned long nfds, int timeout, std::vector& connecting) diff --git a/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.h b/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.h index 1243ec1933..1cd9e136ca 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/sys_net_helpers.h @@ -24,6 +24,7 @@ sys_net_sockaddr native_addr_to_sys_net_addr(const ::sockaddr_storage& native_ad ::sockaddr_in sys_net_addr_to_native_addr(const sys_net_sockaddr& sn_addr); bool is_ip_public_address(const ::sockaddr_in& addr); u32 network_clear_queue(ppu_thread& ppu); +void clear_ppu_to_awake(ppu_thread& ppu); #ifdef _WIN32 void windows_poll(std::vector& fds, unsigned long nfds, int timeout, std::vector& connecting); diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index 46302e3ea5..89de9767b8 100644 --- a/rpcs3/Emu/savestate_utils.cpp +++ b/rpcs3/Emu/savestate_utils.cpp @@ -42,7 +42,7 @@ static std::array s_serial_versions; return ::s_serial_versions[identifier].current_version;\ } -SERIALIZATION_VER(global_version, 0, 16) // For stuff not listed here +SERIALIZATION_VER(global_version, 0, 17) // For stuff not listed here SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep order*/, 3/*PPU FNID and module*/) SERIALIZATION_VER(spu, 2, 1) SERIALIZATION_VER(lv2_sync, 3, 1) diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index f8aaf36ec0..d066b83908 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -301,6 +301,7 @@ + @@ -822,6 +823,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 25274879c6..3183f8dd83 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -393,6 +393,9 @@ Emu\Cell\Modules + + Emu\Cell\Modules + Emu\Cell\Modules @@ -1644,6 +1647,9 @@ Emu\Cell\Modules + + Emu\Cell\Modules + Emu\Cell\Modules