diff --git a/.editorconfig b/.editorconfig index 7c6f14d27f..20d5c776b5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -29,6 +29,10 @@ charset = utf-8-bom [Windows/{aboutbox.rc,version.rc}] charset = utf-8 +[ext/at3_standalone/**.{cpp,h}] +indent_style = space +indent_size = 4 + [libretro/**.{cpp,h}] indent_style = space indent_size = 3 diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 95dd9e21d5..7ee80bae84 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -127,7 +127,7 @@ body: attributes: label: Checklist options: - - label: "Test in the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already fixed." + - label: "Test in the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already fixed." required: true - label: "[Search for other reports](https://github.com/hrydgard/ppsspp/search?q=my+issue&type=issues) of the same issue." required: true diff --git a/.github/ISSUE_TEMPLATE/build.yml b/.github/ISSUE_TEMPLATE/build.yml index 01830ac853..675fee7b33 100644 --- a/.github/ISSUE_TEMPLATE/build.yml +++ b/.github/ISSUE_TEMPLATE/build.yml @@ -84,7 +84,7 @@ body: attributes: label: Checklist options: - - label: "Test in the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already fixed." + - label: "Test in the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already fixed." required: true - label: "Make sure to run `git submodule update --init --recursive` before building." required: true diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml index 8af90a3f0c..bc107fb505 100644 --- a/.github/ISSUE_TEMPLATE/feature.yml +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -68,7 +68,7 @@ body: attributes: label: Checklist options: - - label: "Check the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already implemented." + - label: "Check the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already implemented." required: true - label: "[Search for other requests](https://github.com/hrydgard/ppsspp/search?q=my+issue&type=issues) of the same feature." required: true diff --git a/.github/ISSUE_TEMPLATE/graphics.yml b/.github/ISSUE_TEMPLATE/graphics.yml index 1c473ec033..6ac8e5f1ac 100644 --- a/.github/ISSUE_TEMPLATE/graphics.yml +++ b/.github/ISSUE_TEMPLATE/graphics.yml @@ -141,7 +141,7 @@ body: attributes: label: Checklist options: - - label: "Test in the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already fixed." + - label: "Test in the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already fixed." required: true - label: "[Search for other reports](https://github.com/hrydgard/ppsspp/search?q=my+issue&type=issues) of the same issue." required: true diff --git a/.github/ISSUE_TEMPLATE/performance.yml b/.github/ISSUE_TEMPLATE/performance.yml index 7ee87a8543..737048b70f 100644 --- a/.github/ISSUE_TEMPLATE/performance.yml +++ b/.github/ISSUE_TEMPLATE/performance.yml @@ -125,7 +125,7 @@ body: attributes: label: Checklist options: - - label: "Test in the [latest git build](https://buildbot.orphis.net/ppsspp/) in case it's already fixed." + - label: "Test in the [latest git build](https://www.ppsspp.org/devbuilds) in case it's already fixed." required: true - label: "[Search for other reports](https://github.com/hrydgard/ppsspp/search?q=my+issue&type=issues) of the same issue." required: true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4e922ddc08..2f249aeb63 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,12 +34,12 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1.1 + uses: microsoft/setup-msbuild@v2 - name: Build Windows working-directory: ${{ env.GITHUB_WORKSPACE }} @@ -63,7 +63,7 @@ jobs: run: cp Windows/Release/*.exe ppsspp/ - name: Upload build - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Windows ${{ matrix.platform }} build path: ppsspp/ @@ -71,12 +71,12 @@ jobs: build-uwp: runs-on: windows-2019 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1.1 + uses: microsoft/setup-msbuild@v2 - name: Build UWP working-directory: ${{ env.GITHUB_WORKSPACE }} @@ -87,7 +87,7 @@ jobs: needs: build-windows timeout-minutes: 30 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: false @@ -97,7 +97,7 @@ jobs: run: git submodule update --init pspautotests assets/lang - name: Download build - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Windows x64 build path: ppsspp/ @@ -192,7 +192,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive @@ -203,7 +203,7 @@ jobs: git fetch --deepen=15000 --no-recurse-submodules --tags || exit 0 - name: Install Qt - uses: jurplel/install-qt-action@v3 + uses: jurplel/install-qt-action@v4 if: matrix.extra == 'qt' with: cache: true @@ -285,7 +285,7 @@ jobs: fi - name: Upload build - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: matrix.extra == 'test' with: name: ${{ matrix.os }} build @@ -298,7 +298,7 @@ jobs: mv PPSSPPSDL.zip PPSSPPSDL-macOS-${GITHUB_REF##*/}.zip || exit 1 - name: Upload macOS release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 if: startsWith(github.ref, 'refs/tags/') && runner.os == 'macOS' && matrix.extra == 'test' with: files: ppsspp/*.zip @@ -319,7 +319,7 @@ jobs: needs: build timeout-minutes: 30 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: false @@ -341,7 +341,7 @@ jobs: git submodule update --init SDL/macOS - name: Download build - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: ${{ matrix.os }} build path: ppsspp/ @@ -362,3 +362,40 @@ jobs: - name: Execute headless tests working-directory: ${{ env.GITHUB_WORKSPACE }} run: python test.py -g --graphics=software + + build_test_headless_alpine: + runs-on: ubuntu-latest + container: + image: alpine:latest + options: --shm-size=8g + steps: + - name: Install Linux dependencies (Alpine) + run: | + apk add build-base wget git bash cmake python3 glu-dev sdl2-dev + + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Fix git detected dubious ownership in repository + run: | + chown -R $(id -u):$(id -g) $PWD + + - name: Setup ccache + uses: hendrikmuhs/ccache-action@v1.2 + + - name: Compile ffmpeg + run: | + cd ffmpeg && ./linux_x86-64.sh + + - name: Build for testing + run: | + ./b.sh --headless --unittest + + - name: Execute unit tests + run: | + ./build/PPSSPPUnitTest ALL + + - name: Execute headless tests + run: | + python test.py -g --graphics=software diff --git a/.github/workflows/generateDockerLayer.yml b/.github/workflows/generateDockerLayer.yml index 5e038f398f..8db0d05d5d 100644 --- a/.github/workflows/generateDockerLayer.yml +++ b/.github/workflows/generateDockerLayer.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Extract DOCKER_TAG using tag name if: startsWith(github.ref, 'refs/tags/') @@ -25,13 +25,13 @@ jobs: echo "DOCKER_TAG=latest" >> $GITHUB_ENV - name: Login to Github registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io - - uses: docker/build-push-action@v3 + - uses: docker/build-push-action@v6 with: push: true tags: ghcr.io/${{ github.repository }}:${{ env.DOCKER_TAG }} diff --git a/.github/workflows/manual_generate_apk.yml b/.github/workflows/manual_generate_apk.yml index 3fdca44207..f33bf676f6 100644 --- a/.github/workflows/manual_generate_apk.yml +++ b/.github/workflows/manual_generate_apk.yml @@ -11,6 +11,9 @@ on: options: - NormalOptimized - NormalDebug + - VROptimized + - VRDebug + - LegacyOptimized jobs: diff --git a/.github/workflows/manual_generate_ipa.yml b/.github/workflows/manual_generate_ipa.yml index 4ca750d03e..ddbc72493b 100644 --- a/.github/workflows/manual_generate_ipa.yml +++ b/.github/workflows/manual_generate_ipa.yml @@ -66,8 +66,13 @@ jobs: env: CC: clang CXX: clang++ + USE_CCACHE: 1 run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + export CCACHE_SLOPPINESS=pch_defines,clang_index_store,ivfsoverlay,include_file_ctime,include_file_mtime,modules,system_headers,time_macros + export CCACHE_FILECLONE=true + export CCACHE_DEPEND=true + export CCACHE_COMPILERCHECK=content ./b.sh --ios --${{ github.event.inputs.buildVariant }} - name: Package build diff --git a/.gitignore b/.gitignore index 71c0425320..cc442f2568 100644 --- a/.gitignore +++ b/.gitignore @@ -136,6 +136,8 @@ build libretro/obj/local ppsspp_retroachievements.dat +RACache +RAPrefs_PPSSPP.cfg # For CLion cmake-build-*/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e25c599bbb..7e5a7618cc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -103,6 +103,8 @@ libretro-build-linux-i686: libretro-build-osx-x64: tags: - macosx-packaging + variables: + CORE_ARGS: -DLIBRETRO=ON -DUSE_SYSTEM_LIBPNG=OFF extends: - .libretro-osx-cmake-x86_64 - .core-defs diff --git a/.gitmodules b/.gitmodules index 17fee96935..64be2c658e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -30,7 +30,7 @@ url = https://github.com/hrydgard/ppsspp-freetype.git [submodule "ext/miniupnp"] path = ext/miniupnp - url = https://github.com/hrydgard/miniupnp.git + url = https://github.com/miniupnp/miniupnp.git [submodule "zstd"] path = ext/zstd url = https://github.com/facebook/zstd.git @@ -59,3 +59,6 @@ [submodule "ext/OpenXR-SDK"] path = ext/OpenXR-SDK url = https://github.com/KhronosGroup/OpenXR-SDK.git +[submodule "ios/MoltenVK"] + path = ios/MoltenVK + url = https://github.com/hrydgard/ppsspp-moltenvk.git diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..4ca8260df4 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug", + "program": "build/PPSSPPSDL", + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000000..faa2a39b90 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,23 @@ +{ + "tasks": [ + { + "type": "shell", + "label": "C/C++: build", + "command": "./b.sh", + "args": [ + "--debug", + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "compiler: /usr/bin/g++" + }, + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7decc89c36..a7b642a3ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # vim:noexpandtab: -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.16) project(PPSSPP) enable_testing() @@ -131,7 +131,20 @@ if(GOLD) add_definitions(-DGOLD) message("Gold Build") else() - message("Normal Build") + message("Non-gold Build") +endif() + +if(IOS_APP_STORE) + add_definitions(-DPPSSPP_PLATFORM_IOS_APP_STORE) + add_definitions(-DGLES_SILENCE_DEPRECATION) + # Set a global default to not generate schemes for each target. + # Makes using XCode sligthly more sane. + set(CMAKE_XCODE_GENERATE_SCHEME NO) + set(CMAKE_XCODE_SCHEME_ENABLE_GPU_API_VALIDATION FALSE) + set(CMAKE_XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE DISABLED) + message("iOS App Store build") +elseif(IOS) + message("iOS sideload build") endif() # User-editable options (go into CMakeCache.txt) @@ -173,6 +186,7 @@ option(USE_SYSTEM_MINIUPNPC "Dynamically link against system miniUPnPc" ${USE_SY option(USE_ASAN "Use address sanitizer" OFF) option(USE_UBSAN "Use undefined behaviour sanitizer" OFF) option(USE_CCACHE "Use ccache if detected" ON) +option(USE_NO_MMAP "Disable mmap usage" OFF) if(USE_CCACHE) include(ccache) @@ -234,6 +248,12 @@ if(HTTPS_NOT_AVAILABLE) add_definitions(-DHTTPS_NOT_AVAILABLE) endif() +# Disable the usage of MMAP for the memory system. +# It is not tested on all platforms and can cause issues. +if(USE_NO_MMAP) + add_definitions(-DNO_MMAP -DMASKED_PSP_MEMORY) +endif() + # Work around for some misfeature of the current glslang build system include_directories(ext/glslang) @@ -312,6 +332,8 @@ endif() if(NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, default to Release") set(CMAKE_BUILD_TYPE "Release") +else() + message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") endif() message("CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") @@ -364,9 +386,17 @@ if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17") endif() if(CLANG) - add_definitions(-Wno-nullability-completeness) - add_definitions(-Wno-tautological-pointer-compare) - add_definitions(-Wno-deprecated-register) + add_definitions( + -Wno-nullability-completeness + -Wno-tautological-pointer-compare + -Wno-deprecated-register + -Wno-sign-conversion + -Wno-shorten-64-to-32 + ) + if(MACOSX OR IOS) + # Hack around a bad check for __GNUC__ in basis_universal that makes it use old stuff on iOS + add_definitions(-Wno-deprecated-builtins) + endif() endif() if(USE_ASAN) @@ -422,7 +452,7 @@ if(NOT MSVC) endif() if(IOS) - set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0") + set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0") elseif(APPLE AND NOT CMAKE_CROSSCOMPILING) if(LIBRETRO AND ARM64) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") @@ -840,8 +870,6 @@ add_library(Common STATIC Common/Common.h Common/CommonFuncs.h Common/CommonTypes.h - Common/ConsoleListener.cpp - Common/ConsoleListener.h Common/DbgNew.h Common/FakeEmitter.h Common/FakeCPUDetect.cpp @@ -849,8 +877,12 @@ add_library(Common STATIC Common/ExceptionHandlerSetup.h Common/Log.h Common/Log.cpp - Common/LogManager.cpp - Common/LogManager.h + Common/Log/ConsoleListener.cpp + Common/Log/ConsoleListener.h + Common/Log/StdioListener.cpp + Common/Log/StdioListener.h + Common/Log/LogManager.cpp + Common/Log/LogManager.h Common/LogReporting.cpp Common/LogReporting.h Common/MemArenaAndroid.cpp @@ -1250,6 +1282,12 @@ if(OPENXR AND NOT ARMV7_DEVICE) set(nativeExtraLibs ${nativeExtraLibs} openxr_loader) endif() +if(IOS OR MACOSX) + set(nativeExtra ${nativeExtra} + Common/Render/Text/draw_text_cocoa.mm + Common/Render/Text/draw_text_cocoa.h) +endif() + if(ANDROID) set(NativeAppSource ${NativeAppSource} android/jni/app-android.cpp @@ -1271,8 +1309,13 @@ elseif(IOS AND NOT LIBRETRO) ios/AppDelegate.h ios/DisplayManager.h ios/DisplayManager.mm + ios/Controls.h + ios/Controls.mm + ios/ViewControllerCommon.h ios/ViewController.mm ios/ViewController.h + ios/ViewControllerMetal.mm + ios/ViewControllerMetal.h ios/iOSCoreAudio.mm ios/iOSCoreAudio.h ios/CameraHelper.mm @@ -1291,7 +1334,7 @@ elseif(IOS AND NOT LIBRETRO) Common/Battery/AppleBatteryClient.m ) - set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreVideo -framework CoreMedia -framework CoreServices" ) + set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework CoreMotion -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreText -framework CoreVideo -framework CoreMedia -framework CoreServices -framework Metal -framework IOSurface" ) if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework") set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController") endif() @@ -1300,16 +1343,23 @@ elseif(IOS AND NOT LIBRETRO) set(nativeExtraLibs ${nativeExtraLibs} iconv) endif() + # TODO: Enable arc globally? set_source_files_properties(ios/AppDelegate.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(ios/ViewController.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(ios/ViewControllerMetal.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(ios/iOSCoreAudio.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(ios/PPSSPPUIApplication.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(ios/iCade/iCadeReaderView.m PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(ios/main.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(ios/CameraHelper.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(ios/AudioEngine.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(ios/LocationHelper.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(ios/DisplayManager.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(ios/Controls.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(Common/Render/Text/draw_text_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set(TargetBin PPSSPP) elseif(IOS AND LIBRETRO) set(nativeExtraLibs ${nativeExtraLibs} "-framework GLKit") @@ -1333,6 +1383,7 @@ elseif(USING_QT_UI) Common/Battery/AppleBatteryClient.m) set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(Common/Render/Text/draw_text_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY}) endif() include_directories(Qt) @@ -1410,11 +1461,16 @@ else() UI/PSPNSApplicationDelegate.mm UI/PSPNSApplicationDelegate.h) + # TODO + # set_source_files_properties(SDL/SDLMain.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(UI/PSPNSApplicationDelegate.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(SDL/CocoaMetalLayer.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(SDL/CocoaBarItems.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(SDL/PPSSPPAboutViewController.m PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(Common/Render/Text/draw_text_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY}) if(USE_SYSTEM_LIBSDL2) @@ -1507,6 +1563,8 @@ list(APPEND NativeAppSource UI/CwCheatScreen.cpp UI/InstallZipScreen.h UI/InstallZipScreen.cpp + UI/JitCompareScreen.h + UI/JitCompareScreen.cpp UI/MemStickScreen.h UI/MemStickScreen.cpp UI/ProfilerDraw.h @@ -1858,6 +1916,8 @@ set(GPU_SOURCES GPU/Common/SoftwareTransformCommon.h GPU/Common/VertexDecoderCommon.cpp GPU/Common/VertexDecoderCommon.h + GPU/Common/VertexDecoderHandwritten.cpp + GPU/Common/VertexDecoderHandwritten.h GPU/Common/TransformCommon.cpp GPU/Common/TransformCommon.h GPU/Common/IndexGenerator.cpp @@ -2079,6 +2139,10 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/__sceAudio.h Core/HLE/sceAdler.cpp Core/HLE/sceAdler.h + Core/HLE/AtracCtx.cpp + Core/HLE/AtracCtx.h + Core/HLE/AtracCtx2.cpp + Core/HLE/AtracCtx2.h Core/HLE/sceAtrac.cpp Core/HLE/sceAtrac.h Core/HLE/sceAudio.cpp @@ -2215,6 +2279,9 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/scePauth.h Core/HW/SimpleAudioDec.cpp Core/HW/SimpleAudioDec.h + Core/HW/Atrac3Standalone.cpp + Core/HW/Atrac3Standalone.h + Core/HW/SimpleAudioDec.h Core/HW/AsyncIOManager.cpp Core/HW/AsyncIOManager.h Core/HW/BufferQueue.cpp @@ -2275,6 +2342,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/MIPS/MIPSVFPUFallbacks.h Core/MIPS/MIPSAsm.cpp Core/MIPS/MIPSAsm.h + Core/MIPS/MIPSTracer.cpp + Core/MIPS/MIPSTracer.h Core/MemFault.cpp Core/MemFault.h Core/MemMap.cpp @@ -2354,16 +2423,14 @@ if(USE_SYSTEM_ZSTD) target_include_directories(${CoreLibName} PRIVATE ${ZSTD_INCLUDE_DIR}) target_link_libraries(${CoreLibName} ${ZSTD_LIBRARY}) else() - set(ZSTD_BUILD_PROGRAMS OFF CACHE BOOL "we don't need zstd programs" FORCE) - set(ZSTD_LEGACY_SUPPORT OFF CACHE BOOL "we don't use any old zstd files" FORCE) - add_subdirectory(ext/zstd/build/cmake EXCLUDE_FROM_ALL) + add_subdirectory(ext/zstd-build) set(CoreExtraLibs ${CoreExtraLibs} libzstd_static) include_directories(ext/zstd/lib) endif() include_directories(ext/libchdr/include) -target_link_libraries(${CoreLibName} Common native chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos ${GlslangLibs} +target_link_libraries(${CoreLibName} Common native chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos minimp3 at3_standalone ${GlslangLibs} ${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS}) if(NOT HTTPS_NOT_AVAILABLE) @@ -2406,8 +2473,8 @@ if(USE_MINIUPNPC) target_link_libraries(${CoreLibName} ${MINIUPNP_LIBRARY}) add_definitions(-DWITH_UPNP -DUSE_SYSTEM_MINIUPNPC) else() - set (MINIUPNPC_VERSION 2.1) # used by miniupnpcstrings.h.cmake - set (MINIUPNPC_API_VERSION 17) + set (MINIUPNPC_VERSION 2.2) # used by miniupnpcstrings.h.cmake + set (MINIUPNPC_API_VERSION 18) option(UPNPC_BUILD_STATIC "Build static library" TRUE) option(NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) mark_as_advanced(NO_GETADDRINFO) @@ -2431,25 +2498,28 @@ if(USE_MINIUPNPC) add_definitions(-DWITH_UPNP -DMINIUPNP_STATICLIB) set(MINIUPNP_DIR "ext/miniupnp/miniupnpc") include_directories(${CMAKE_CURRENT_BINARY_DIR}) + include_directories(ext/miniupnp/miniupnpc/src) + include_directories(ext/miniupnp/miniupnpc/include) configure_file(${MINIUPNP_DIR}/miniupnpcstrings.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h) # by default miniupnp repo doesn't contains miniupnpcstrings.h and need to be generated set(MINIUPNPC_SOURCES # the needed bits of miniupnpc (no python module, no tests, no cli) - ${MINIUPNP_DIR}/addr_is_reserved.c - ${MINIUPNP_DIR}/connecthostport.c - ${MINIUPNP_DIR}/igd_desc_parse.c - ${MINIUPNP_DIR}/minisoap.c - ${MINIUPNP_DIR}/minissdpc.c - ${MINIUPNP_DIR}/miniupnpc.c - ${MINIUPNP_DIR}/miniwget.c - ${MINIUPNP_DIR}/minixml.c - ${MINIUPNP_DIR}/minixmlvalid.c - ${MINIUPNP_DIR}/portlistingparse.c - ${MINIUPNP_DIR}/receivedata.c + ${MINIUPNP_DIR}/src/addr_is_reserved.c + ${MINIUPNP_DIR}/src/connecthostport.c + ${MINIUPNP_DIR}/src/igd_desc_parse.c + ${MINIUPNP_DIR}/src/minisoap.c + ${MINIUPNP_DIR}/src/minissdpc.c + ${MINIUPNP_DIR}/src/miniupnpc.c + #${MINIUPNP_DIR}/miniupnpcmodule.c + ${MINIUPNP_DIR}/src/miniwget.c + ${MINIUPNP_DIR}/src/minixml.c + ${MINIUPNP_DIR}/src/minixmlvalid.c + ${MINIUPNP_DIR}/src/portlistingparse.c + ${MINIUPNP_DIR}/src/receivedata.c #${MINIUPNP_DIR}/upnpc.c # causing an error due to already existing _main() - ${MINIUPNP_DIR}/upnpcommands.c - ${MINIUPNP_DIR}/upnpdev.c - ${MINIUPNP_DIR}/upnperrors.c - ${MINIUPNP_DIR}/upnpreplyparse.c + ${MINIUPNP_DIR}/src/upnpcommands.c + ${MINIUPNP_DIR}/src/upnpdev.c + ${MINIUPNP_DIR}/src/upnperrors.c + ${MINIUPNP_DIR}/src/upnpreplyparse.c ${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h ) if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") @@ -2601,7 +2671,7 @@ set(WindowsFiles list(APPEND LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT}) if(WIN32) - list(APPEND LinkCommon kernel32 user32 gdi32 shell32 comctl32 dsound xinput d3d9 winmm dinput8 ole32 winspool ksuser mf uxtheme mfplat mfreadwrite mfuuid shlwapi) + list(APPEND LinkCommon kernel32 user32 gdi32 shell32 comctl32 dsound xinput d3d9 winmm dinput8 ole32 winspool ksuser dwmapi mf uxtheme mfplat mfreadwrite mfuuid shlwapi) #setup_target_project(${TargetBin} Windows) list(APPEND NativeAppSource ${WindowsFiles}) endif() @@ -2755,8 +2825,11 @@ if(TargetBin) endif() if(IOS) - add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${BigFontAssets} ${SHADER_FILES} ${THEME_FILE} ${DEBUGGER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Settings.bundle" "ios/Launch Screen.storyboard") - file(INSTALL "${CMAKE_SOURCE_DIR}/ext/vulkan/iOS/Frameworks/libMoltenVK.dylib" DESTINATION "${CMAKE_BINARY_DIR}/PPSSPP.app/Frameworks/") + set(AssetCatalog "${CMAKE_SOURCE_DIR}/ios/assets.xcassets") + add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${BigFontAssets} ${AssetCatalog} ${SHADER_FILES} ${THEME_FILE} ${DEBUGGER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Settings.bundle" "ios/Launch Screen.storyboard") + if(NOT IOS_APP_STORE) + file(INSTALL "${CMAKE_SOURCE_DIR}/ext/vulkan/iOS/Frameworks/libMoltenVK.dylib" DESTINATION "${CMAKE_BINARY_DIR}/PPSSPP.app/Frameworks/") + endif() else() add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${BigFontAssets} ${SHADER_FILES} ${THEME_FILE} ${DEBUGGER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource}) file(INSTALL "${CMAKE_SOURCE_DIR}/ext/vulkan/macOS/Frameworks/libMoltenVK.dylib" DESTINATION "${CMAKE_BINARY_DIR}/${TargetBin}.app/Contents/Frameworks/") @@ -2788,7 +2861,11 @@ if(NOT ANDROID) endif() # packaging and code signing if(IOS AND NOT LIBRETRO) - set(DEPLOYMENT_TARGET 11.0) + if(IOS_APP_STORE) + set(DEPLOYMENT_TARGET 12.0) + else() + set(DEPLOYMENT_TARGET 11.0) + endif() file(GLOB IOSAssets ios/assets/*.png) list(REMOVE_ITEM IOSAssets ${CMAKE_CURRENT_SOURCE_DIR}/ios/assets/Default-568h@2x.png) list(REMOVE_ITEM IOSAssets ${CMAKE_CURRENT_SOURCE_DIR}/ios/assets/Default-568h@3x.png) @@ -2798,33 +2875,113 @@ if(IOS AND NOT LIBRETRO) if(IOS_DEBUG) file(INSTALL pspautotests DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/assets) endif() - set(RSRC_XIB_FILES assets/Icon@2x.png) - set(RSRC_XIB_FILES "Launch Screen.storyboard") + set(RSRC_XIB_FILES "Launch Screen.storyboard" ${CMAKE_CURRENT_SOURCE_DIR}/ios/assets.xcassets) + set_source_files_properties(${RSRC_XIB_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) + #This breaks in modern XCode. Not sure when it worked... #if(CMAKE_GENERATOR STREQUAL "Xcode") # set(APP_DIR_NAME "$(TARGET_BUILD_DIR)/$(FULL_PRODUCT_NAME)") #else() set(APP_DIR_NAME "$") #endif() - add_custom_command(TARGET PPSSPP POST_BUILD - COMMAND mkdir -p \"${APP_DIR_NAME}\" - COMMAND tar -c -C ${CMAKE_CURRENT_BINARY_DIR} --exclude .DS_Store --exclude .git assets *.png | tar -x -C \"${APP_DIR_NAME}\" - COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/ios/macbundle.sh" \"${APP_DIR_NAME}\" - ) + set(MACOSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET}) - set_target_properties(${TargetBin} PROPERTIES - MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/PPSSPP-Info.plist" - RESOURCE "ios/Launch Screen.storyboard" - RESOURCE "ios/Settings.bundle" - RESOURCE "ext/vulkan/iOS/Frameworks" - XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} - XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "iPhone/iPad" - XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES - XCODE_ATTRIBUTE_ENABLE_BITCODE NO - XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" + set(PRODUCT_NAME "PPSSPP") + set(BUNDLE_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/PPSSPP-Info.plist") + if(GOLD) + if(IOS_APP_STORE) + set(BUNDLE_IDENTIFIER "org.ppsspp.ppsspp-gold") + else() + set(BUNDLE_IDENTIFIER "org.ppsspp.ppssppgold") + endif() + set(ICON_NAME "AppIconGold") + set(DISPLAY_NAME "PPSSPP Gold") + else() + if(IOS_APP_STORE) + set(BUNDLE_IDENTIFIER "org.ppsspp.ppsspp-free") + else() + set(BUNDLE_IDENTIFIER "org.ppsspp.ppsspp") + endif() + set(ICON_NAME "AppIcon") + set(DISPLAY_NAME "PPSSPP") + endif() + if(IOS_APP_STORE) + message(STATUS "DevTeam: ${DEVELOPMENT_TEAM_ID} Icon: ${ICON_NAME} Target: ${TargetBin}") + message(STATUS "CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}") + + # This is for injecting the version into the plist, and also copying resources. + # Should find a different way to do both these things. + add_custom_command(TARGET ${TargetBin} POST_BUILD + COMMAND echo "Creating ${APP_DIR_NAME} for app store build" + COMMAND mkdir -p \"${APP_DIR_NAME}\" + # This tar command seems to be responsible for copying assets. I thought we had another step that did that.. + # Prepend -v to the extracting command to see the files copied. + COMMAND tar -c -C ${CMAKE_CURRENT_BINARY_DIR} --exclude .DS_Store --exclude .git assets *.png | tar -x -C \"${APP_DIR_NAME}\" + # This updates the version in the plist. + COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/ios/iosbundle.sh" \"${APP_DIR_NAME}\" "${CMAKE_CURRENT_BINARY_DIR}" + ) + + # Can't figure out properly using .xcframework from CMake, so just linking directly to the .a file. + target_link_libraries(${TargetBin} + "${CMAKE_CURRENT_SOURCE_DIR}/ios/MoltenVK/MoltenVK.xcframework/ios-arm64/libMoltenVK.a" + ) + + # https://stackoverflow.com/questions/40664125/cmake-and-code-signing-in-xcode-8-for-ios-projects + set_target_properties(${TargetBin} PROPERTIES + XCODE_GENERATE_SCHEME YES # Avoid the scheme bloat in XCode by only setting it to YES for this target. + RESOURCE "ios/Launch Screen.storyboard" + RESOURCE "ios/Settings.bundle" + RESOURCE "ios/assets.xcassets" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${BUNDLE_IDENTIFIER} + XCODE_ATTRIBUTE_PRODUCT_NAME ${PRODUCT_NAME} + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${ICON_NAME} + BUILD_WITH_INSTALL_RPATH YES + MACOSX_BUNDLE_INFO_PLIST ${BUNDLE_PLIST} + # Some sources say we should generate the PLIST. There's stuff in it that + # I don't know how to generate, though. + #XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE "YES" + #XCODE_ATTRIBUTE_INFOPLIST_KEY_UIRequiredDeviceCapabilities arm64 + XCODE_ATTRIBUTE_INFOPLIST_KEY_UIFileSharingEnabled YES + XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY YES + XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY YES + XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} + XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES + XCODE_ATTRIBUTE_ENABLE_BITCODE NO + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEVELOPMENT_TEAM_ID} + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development" + XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic" + XCODE_ATTRIBUTE_SKIP_INSTALL NO + XCODE_ATTRIBUTE_INSTALL_PATH "$(LOCAL_APPS_DIR)" + ) + else() + # This is for injecting the version into the plist. + add_custom_command(TARGET PPSSPP POST_BUILD + COMMAND echo "Creating ${APP_DIR_NAME} for sideload build" + COMMAND mkdir -p \"${APP_DIR_NAME}\" + COMMAND tar -c -C ${CMAKE_CURRENT_BINARY_DIR} --exclude .DS_Store --exclude .git assets *.png | tar -x -C \"${APP_DIR_NAME}\" + COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/ios/macbundle.sh" \"${APP_DIR_NAME}\" + ) + set_target_properties(${TargetBin} PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${BUNDLE_PLIST} + XCODE_GENERATE_SCHEME YES + RESOURCE "ios/Launch Screen.storyboard" + RESOURCE "ios/Settings.bundle" + RESOURCE "ext/vulkan/iOS/Frameworks" + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${ICON_NAME} + XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} + XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES + XCODE_ATTRIBUTE_ENABLE_BITCODE NO + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" + ) + endif() + add_custom_command(TARGET PPSSPP POST_BUILD + COMMAND plutil -replace CFBundleDisplayName -string "${DISPLAY_NAME}" "${APP_DIR_NAME}/Info.plist" + COMMAND plutil -replace CFBundleIdentifier -string "${BUNDLE_IDENTIFIER}" "${APP_DIR_NAME}/Info.plist" ) endif() diff --git a/Common/Arm64Emitter.cpp b/Common/Arm64Emitter.cpp index f9ab5ec195..462ddc7346 100644 --- a/Common/Arm64Emitter.cpp +++ b/Common/Arm64Emitter.cpp @@ -1041,7 +1041,7 @@ void ARM64XEmitter::QuickCallFunction(ARM64Reg scratchreg, const void *func) { s64 distance = (s64)func - (s64)m_code; distance >>= 2; // Can only branch to opcode-aligned (4) addresses if (!IsInRangeImm26(distance)) { - // WARN_LOG(DYNA_REC, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func); + // WARN_LOG(Log::JIT, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func); MOVI2R(scratchreg, (uintptr_t)func); BLR(scratchreg); } else { diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index d119f2443a..6b2745e618 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -96,7 +96,7 @@ Operand2 AssumeMakeOperand2(u32 imm) { _dbg_assert_msg_(result, "Could not make assumed Operand2."); if (!result) { // Make double sure that we get it logged. - ERROR_LOG(JIT, "Could not make assumed Operand2."); + ERROR_LOG(Log::JIT, "Could not make assumed Operand2."); } return op2; } @@ -166,7 +166,7 @@ void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate) conv.f = negate ? -val : val; // Try moving directly first if mantisse is empty Operand2 op2; - if (cpu_info.bVFPv3 && TryMakeFloatIMM8(conv.u, op2)) + if (TryMakeFloatIMM8(conv.u, op2)) VMOV(dest, op2); else { @@ -182,7 +182,7 @@ void ARMXEmitter::MOVI2F_neon(ARMReg dest, float val, ARMReg tempReg, bool negat conv.f = negate ? -val : val; // Try moving directly first if mantisse is empty Operand2 op2; - if (cpu_info.bVFPv3 && TryMakeFloatIMM8(conv.u, op2)) + if (TryMakeFloatIMM8(conv.u, op2)) VMOV_neon(F_32, dest, conv.u); else { @@ -1264,7 +1264,6 @@ void ARMXEmitter::LDMBitmask(ARMReg dest, bool Add, bool Before, bool WriteBack, void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _assert_msg_(Vd >= D0, "Pass invalid register to VABD(float)"); - _assert_msg_(cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it"); bool register_quad = Vd >= Q0; // Gets encoded as a double register @@ -1279,7 +1278,6 @@ void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _assert_msg_(Vd >= D0, "Pass invalid register to VADD(integer)"); - _assert_msg_(cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it"); bool register_quad = Vd >= Q0; @@ -1296,7 +1294,6 @@ void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _assert_msg_(Vd >= Q0, "Pass invalid register to VSUB(integer)"); - _assert_msg_(cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it"); // Gets encoded as a double register Vd = SubBase(Vd); @@ -1506,7 +1503,7 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset) _assert_msg_((imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough"); if (imm & 0xC03) - ERROR_LOG(JIT, "VLDR: Bad offset %08x", imm); + ERROR_LOG(Log::JIT, "VLDR: Bad offset %08x", imm); bool single_reg = Dest < D0; @@ -1534,7 +1531,7 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset) _assert_msg_((imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough"); if (imm & 0xC03) - ERROR_LOG(JIT, "VSTR: Bad offset %08x", imm); + ERROR_LOG(Log::JIT, "VSTR: Bad offset %08x", imm); bool single_reg = Src < D0; @@ -1564,14 +1561,12 @@ void ARMXEmitter::VMSR(ARMReg Rt) { void ARMXEmitter::VMOV(ARMReg Dest, Operand2 op2) { - _assert_msg_(cpu_info.bVFPv3, "VMOV #imm requires VFPv3"); int sz = Dest >= D0 ? (1 << 8) : 0; Write32(condition | (0xEB << 20) | EncodeVd(Dest) | (5 << 9) | sz | op2.Imm8VFP()); } void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, u32 imm) { - _assert_msg_(cpu_info.bNEON, "VMOV_neon #imm requires NEON"); _assert_msg_(Vd >= D0, "VMOV_neon #imm must target a double or quad"); bool register_quad = Vd >= Q0; @@ -1656,8 +1651,6 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, u32 imm) void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, ARMReg Rt, int lane) { - _assert_msg_(cpu_info.bNEON, "VMOV_neon requires NEON"); - int opc1 = 0; int opc2 = 0; @@ -1697,8 +1690,6 @@ void ARMXEmitter::VMOV_neon(u32 Size, ARMReg Vd, ARMReg Rt, int lane) void ARMXEmitter::VMOV(ARMReg Vd, ARMReg Rt, ARMReg Rt2) { - _assert_msg_(cpu_info.bVFP | cpu_info.bNEON, "VMOV_neon requires VFP or NEON"); - if (Vd < S0 && Rt < S0 && Rt2 >= D0) { // Oh, reading to regs, our params are backwards. @@ -1732,7 +1723,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high) void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) { if (Dest == Src) { - WARN_LOG(JIT, "VMOV %s, %s - same register", ARMRegAsString(Src), ARMRegAsString(Dest)); + WARN_LOG(Log::JIT, "VMOV %s, %s - same register", ARMRegAsString(Src), ARMRegAsString(Dest)); } if (Dest > R15) { @@ -1787,7 +1778,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) _assert_msg_(SrcSize == DestSize, "VMOV doesn't support moving different register sizes"); if (SrcSize != DestSize) { - ERROR_LOG(JIT, "SrcSize: %i (%s) DestDize: %i (%s)", SrcSize, ARMRegAsString(Src), DestSize, ARMRegAsString(Dest)); + ERROR_LOG(Log::JIT, "SrcSize: %i (%s) DestDize: %i (%s)", SrcSize, ARMRegAsString(Src), DestSize, ARMRegAsString(Dest)); } Dest = SubBase(Dest); @@ -1803,7 +1794,6 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) // Double and quad if (Quad) { - _assert_msg_(cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD."); // Gets encoded as a Double register Write32((0xF2 << 24) | ((Dest & 0x10) << 18) | (2 << 20) | ((Src & 0xF) << 16) \ | ((Dest & 0xF) << 12) | (1 << 8) | ((Src & 0x10) << 3) | (1 << 6) \ @@ -1865,7 +1855,6 @@ void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags) void ARMXEmitter::VABA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -1878,7 +1867,6 @@ void ARMXEmitter::VABAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | EncodeVn(Vn) \ @@ -1888,7 +1876,6 @@ void ARMXEmitter::VABAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VABD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; if (Size & F_32) @@ -1903,7 +1890,6 @@ void ARMXEmitter::VABDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | EncodeVn(Vn) \ @@ -1913,7 +1899,6 @@ void ARMXEmitter::VABDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VABS(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xB1 << 16) | (encodedSize(Size) << 18) | EncodeVd(Vd) \ @@ -1924,7 +1909,6 @@ void ARMXEmitter::VACGE(ARMReg Vd, ARMReg Vn, ARMReg Vm) { // Only Float _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) \ @@ -1935,7 +1919,6 @@ void ARMXEmitter::VACGT(ARMReg Vd, ARMReg Vn, ARMReg Vm) { // Only Float _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) \ @@ -1955,7 +1938,6 @@ void ARMXEmitter::VACLT(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -1971,7 +1953,6 @@ void ARMXEmitter::VADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) _dbg_assert_msg_(Vd < Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \ @@ -1983,7 +1964,6 @@ void ARMXEmitter::VADDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vn >= D0 && Vn < Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \ @@ -1994,7 +1974,6 @@ void ARMXEmitter::VADDW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \ @@ -2003,7 +1982,6 @@ void ARMXEmitter::VADDW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VAND(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Vd == Vn && Vn == Vm), "All operands the same for %s is a nop", __FUNCTION__); // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2013,7 +1991,6 @@ void ARMXEmitter::VAND(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VBIC(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2022,7 +1999,6 @@ void ARMXEmitter::VBIC(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s: %i", __FUNCTION__, Vd); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm)); @@ -2030,7 +2006,6 @@ void ARMXEmitter::VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VBIF(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2039,7 +2014,6 @@ void ARMXEmitter::VBIF(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VBIT(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2048,7 +2022,6 @@ void ARMXEmitter::VBIT(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VBSL(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2057,7 +2030,6 @@ void ARMXEmitter::VBSL(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; if (Size & F_32) @@ -2070,7 +2042,6 @@ void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2080,7 +2051,6 @@ void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; if (Size & F_32) @@ -2092,7 +2062,6 @@ void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 16) \ @@ -2101,7 +2070,6 @@ void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; if (Size & F_32) @@ -2113,7 +2081,6 @@ void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \ @@ -2126,7 +2093,6 @@ void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \ @@ -2135,7 +2101,6 @@ void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VCLS(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2149,7 +2114,6 @@ void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \ @@ -2158,7 +2122,6 @@ void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VCLZ(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) \ @@ -2167,7 +2130,6 @@ void ARMXEmitter::VCLZ(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VCNT(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(Size & I_8, "Can only use I_8 with %s", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2178,7 +2140,6 @@ void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Vm, u8 index) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; u32 imm4 = 0; @@ -2195,7 +2156,6 @@ void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Rt) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Rt < S0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Vd = SubBase(Vd); @@ -2213,7 +2173,6 @@ void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Rt) void ARMXEmitter::VEXT(ARMReg Vd, ARMReg Vn, ARMReg Vm, u8 index) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Write32((0xF2 << 24) | (0xB << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (index & 0xF) \ @@ -2223,7 +2182,6 @@ void ARMXEmitter::VFMA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Size == F_32, "Passed invalid size to FP-only NEON instruction"); _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(cpu_info.bVFPv4, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2233,7 +2191,6 @@ void ARMXEmitter::VFMS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Size == F_32, "Passed invalid size to FP-only NEON instruction"); _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(cpu_info.bVFPv4, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2242,7 +2199,6 @@ void ARMXEmitter::VFMS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2253,7 +2209,6 @@ void ARMXEmitter::VHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VHSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2264,7 +2219,6 @@ void ARMXEmitter::VHSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2277,7 +2231,6 @@ void ARMXEmitter::VMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2290,7 +2243,6 @@ void ARMXEmitter::VMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMLA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2302,7 +2254,6 @@ void ARMXEmitter::VMLA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMLS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2316,7 +2267,6 @@ void ARMXEmitter::VMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) \ @@ -2327,7 +2277,6 @@ void ARMXEmitter::VMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vn >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= D0 && Vm < Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float.", __FUNCTION__); Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) \ @@ -2336,7 +2285,6 @@ void ARMXEmitter::VMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMUL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2349,7 +2297,6 @@ void ARMXEmitter::VMUL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ @@ -2358,7 +2305,6 @@ void ARMXEmitter::VMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMLA_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2374,7 +2320,6 @@ void ARMXEmitter::VMLA_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2393,7 +2338,6 @@ void ARMXEmitter::VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VMVN(ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2404,7 +2348,6 @@ void ARMXEmitter::VMVN(ARMReg Vd, ARMReg Vm) void ARMXEmitter::VNEG(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2414,7 +2357,6 @@ void ARMXEmitter::VNEG(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VORN(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2423,7 +2365,6 @@ void ARMXEmitter::VORN(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Vd == Vn && Vn == Vm), "All operands the same for %s is a nop", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2433,7 +2374,6 @@ void ARMXEmitter::VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VPADAL(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2444,7 +2384,6 @@ void ARMXEmitter::VPADAL(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VPADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); if (Size & F_32) Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD0 << 4) | EncodeVm(Vm)); @@ -2455,7 +2394,6 @@ void ARMXEmitter::VPADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VPADDL(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2466,7 +2404,6 @@ void ARMXEmitter::VPADDL(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VPMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); if (Size & F_32) Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | EncodeVm(Vm)); @@ -2477,7 +2414,6 @@ void ARMXEmitter::VPMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VPMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); if (Size & F_32) Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | EncodeVm(Vm)); @@ -2488,7 +2424,6 @@ void ARMXEmitter::VPMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQABS(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2499,7 +2434,6 @@ void ARMXEmitter::VQABS(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VQADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2510,7 +2444,6 @@ void ARMXEmitter::VQADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQDMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ @@ -2519,7 +2452,6 @@ void ARMXEmitter::VQDMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQDMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ @@ -2528,7 +2460,6 @@ void ARMXEmitter::VQDMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ @@ -2537,7 +2468,6 @@ void ARMXEmitter::VQDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQDMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ @@ -2546,7 +2476,6 @@ void ARMXEmitter::VQDMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQNEG(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2557,7 +2486,6 @@ void ARMXEmitter::VQNEG(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VQRDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF3 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ @@ -2566,7 +2494,6 @@ void ARMXEmitter::VQRDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2577,7 +2504,6 @@ void ARMXEmitter::VQRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2588,7 +2514,6 @@ void ARMXEmitter::VQSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VQSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2599,7 +2524,6 @@ void ARMXEmitter::VQSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VRADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF3 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ @@ -2608,7 +2532,6 @@ void ARMXEmitter::VRADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VRECPE(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2618,7 +2541,6 @@ void ARMXEmitter::VRECPE(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VRECPS(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2627,7 +2549,6 @@ void ARMXEmitter::VRECPS(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VRHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2638,7 +2559,6 @@ void ARMXEmitter::VRHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2649,7 +2569,6 @@ void ARMXEmitter::VRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VRSQRTE(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; Vd = SubBase(Vd); @@ -2662,7 +2581,6 @@ void ARMXEmitter::VRSQRTE(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VRSQRTS(ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2672,7 +2590,6 @@ void ARMXEmitter::VRSQRTS(ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VRSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); Write32((0xF3 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ @@ -2681,7 +2598,6 @@ void ARMXEmitter::VRSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VSHL(u32 Size, ARMReg Vd, ARMReg Vm, ARMReg Vn) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2710,7 +2626,6 @@ static int EncodeSizeShift(u32 Size, int amount, bool inverse, bool halve) { void ARMXEmitter::EncodeShiftByImm(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount, u8 opcode, bool register_quad, bool inverse, bool halve) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_(!(Size & F_32), "%s doesn't support float", __FUNCTION__); int imm7 = EncodeSizeShift(Size, shiftAmount, inverse, halve); int L = (imm7 >> 6) & 1; @@ -2754,7 +2669,6 @@ void ARMXEmitter::VSHRN(u32 Size, ARMReg Vd, ARMReg Vm, int shiftAmount) { void ARMXEmitter::VSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2768,7 +2682,6 @@ void ARMXEmitter::VSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); Write32((0xF2 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x60 << 4) | EncodeVm(Vm)); @@ -2776,7 +2689,6 @@ void ARMXEmitter::VSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VSUBL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x20 << 4) | EncodeVm(Vm)); @@ -2784,7 +2696,6 @@ void ARMXEmitter::VSUBL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VSUBW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \ (0x30 << 4) | EncodeVm(Vm)); @@ -2792,7 +2703,6 @@ void ARMXEmitter::VSUBW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VSWP(ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2802,7 +2712,6 @@ void ARMXEmitter::VSWP(ARMReg Vd, ARMReg Vm) void ARMXEmitter::VTRN(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2812,7 +2721,6 @@ void ARMXEmitter::VTRN(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VTST(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2822,7 +2730,6 @@ void ARMXEmitter::VTST(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) void ARMXEmitter::VUZP(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2832,7 +2739,6 @@ void ARMXEmitter::VUZP(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VZIP(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= D0, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); bool register_quad = Vd >= Q0; @@ -2844,7 +2750,6 @@ void ARMXEmitter::VMOVL(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vd >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vm >= D0 && Vm <= D31, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_((Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VMOVL"); bool unsign = (Size & I_UNSIGNED) != 0; @@ -2861,7 +2766,6 @@ void ARMXEmitter::VMOVN(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); // For consistency with assembler syntax and VMOVL - encode one size down. @@ -2874,7 +2778,6 @@ void ARMXEmitter::VQMOVN(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_((Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in %s NEON", __FUNCTION__); _dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); @@ -2888,7 +2791,6 @@ void ARMXEmitter::VQMOVUN(u32 Size, ARMReg Vd, ARMReg Vm) { _dbg_assert_msg_(Vm >= Q0, "Pass invalid register to %s", __FUNCTION__); _dbg_assert_msg_(Vd >= D0 && Vd <= D31, "Pass invalid register to %s", __FUNCTION__); - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); _dbg_assert_msg_((Size & I_8) == 0, "%s cannot narrow from I_8", __FUNCTION__); u32 halfSize = encodedSize(Size) - 1; @@ -2940,12 +2842,10 @@ void ARMXEmitter::WriteVLDST1(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int reg } void ARMXEmitter::VLD1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) { - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); WriteVLDST1(true, Size, Vd, Rn, regCount, align, Rm); } void ARMXEmitter::VST1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) { - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); WriteVLDST1(false, Size, Vd, Rn, regCount, align, Rm); } @@ -2975,12 +2875,10 @@ void ARMXEmitter::WriteVLDST1_lane(bool load, u32 Size, ARMReg Vd, ARMReg Rn, in } void ARMXEmitter::VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) { - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); WriteVLDST1_lane(true, Size, Vd, Rn, lane, aligned, Rm); } void ARMXEmitter::VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) { - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); WriteVLDST1_lane(false, Size, Vd, Rn, lane, aligned, Rm); } @@ -3017,7 +2915,6 @@ void ARMXEmitter::WriteVimm(ARMReg Vd, int cmode, u8 imm, int op) { } void ARMXEmitter::VMOV_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // Only let through the modes that apply. switch (type) { case VIMM___x___x: @@ -3054,7 +2951,6 @@ error: } void ARMXEmitter::VMOV_immf(ARMReg Vd, float value) { // This only works with a select few values. I've hardcoded 1.0f. - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); u8 bits = 0; if (value == 0.0f) { @@ -3076,7 +2972,6 @@ void ARMXEmitter::VMOV_immf(ARMReg Vd, float value) { // This only works with a } void ARMXEmitter::VORR_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // Only let through the modes that apply. switch (type) { case VIMM___x___x: @@ -3102,7 +2997,6 @@ error: } void ARMXEmitter::VBIC_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // Only let through the modes that apply. switch (type) { case VIMM___x___x: @@ -3129,7 +3023,6 @@ error: void ARMXEmitter::VMVN_imm(u32 Size, ARMReg Vd, VIMMMode type, int imm) { - _dbg_assert_msg_(cpu_info.bNEON, "Can't use %s when CPU doesn't support it", __FUNCTION__); // Only let through the modes that apply. switch (type) { case VIMM___x___x: @@ -3187,7 +3080,6 @@ void ARMXEmitter::VREV16(u32 Size, ARMReg Vd, ARMReg Vm) void ARMXEmitter::VCVTF32F16(ARMReg Dest, ARMReg Src) { _assert_msg_(cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4"); if (Dest < Q0 || Dest > Q15 || Src < D0 || Src > D15) { - _assert_msg_(cpu_info.bNEON, "Bad inputs to VCVTF32F16"); // Invalid! } @@ -3203,7 +3095,6 @@ void ARMXEmitter::VCVTF32F16(ARMReg Dest, ARMReg Src) { void ARMXEmitter::VCVTF16F32(ARMReg Dest, ARMReg Src) { _assert_msg_(cpu_info.bVFPv4, "Can't use half-float conversions when you don't support VFPv4"); if (Dest < D0 || Dest > D15 || Src < Q0 || Src > Q15) { - _assert_msg_(cpu_info.bNEON, "Bad inputs to VCVTF32F16"); // Invalid! } Dest = SubBase(Dest); diff --git a/Common/BitSet.h b/Common/BitSet.h index 28c7597048..e76ddcce63 100644 --- a/Common/BitSet.h +++ b/Common/BitSet.h @@ -8,7 +8,21 @@ #include #include "CommonTypes.h" -// Helper functions: +// TODO: ARM has an intrinsic for the RBIT instruction in some compilers, __rbit. +inline u32 ReverseBits32(u32 v) { + // http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel + // swap odd and even bits + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); + // swap consecutive pairs + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); + // swap nibbles ... + v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); + // swap bytes + v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); + // swap 2-byte long pairs + v = (v >> 16) | (v << 16); + return v; +} #ifdef _WIN32 #include @@ -35,6 +49,7 @@ inline int LeastSignificantSetBit(u64 val) _BitScanForward64(&index, val); return (int)index; } + #endif #else inline int CountSetBits(u32 val) { return __builtin_popcount(val); } diff --git a/Common/Buffer.cpp b/Common/Buffer.cpp index 25af9607d1..4b05d99e51 100644 --- a/Common/Buffer.cpp +++ b/Common/Buffer.cpp @@ -22,7 +22,9 @@ char *Buffer::Append(size_t length) { void Buffer::Append(const std::string &str) { char *ptr = Append(str.size()); - memcpy(ptr, str.data(), str.size()); + if (ptr) { + memcpy(ptr, str.data(), str.size()); + } } void Buffer::Append(const char *str) { @@ -48,7 +50,7 @@ void Buffer::AppendValue(int value) { void Buffer::Take(size_t length, std::string *dest) { if (length > data_.size()) { - ERROR_LOG(IO, "Truncating length in Buffer::Take()"); + ERROR_LOG(Log::IO, "Truncating length in Buffer::Take()"); length = data_.size(); } dest->resize(length); @@ -77,7 +79,7 @@ int Buffer::TakeLineCRLF(std::string *dest) { void Buffer::Skip(size_t length) { if (length > data_.size()) { - ERROR_LOG(IO, "Truncating length in Buffer::Skip()"); + ERROR_LOG(Log::IO, "Truncating length in Buffer::Skip()"); length = data_.size(); } data_.erase(data_.begin(), data_.begin() + length); @@ -109,10 +111,10 @@ void Buffer::Printf(const char *fmt, ...) { size_t retval = vsnprintf(buffer, sizeof(buffer), fmt, vl); if ((int)retval >= (int)sizeof(buffer)) { // Output was truncated. TODO: Do something. - ERROR_LOG(IO, "Buffer::Printf truncated output"); + ERROR_LOG(Log::IO, "Buffer::Printf truncated output"); } - if (retval < 0) { - ERROR_LOG(IO, "Buffer::Printf failed"); + if ((int)retval < 0) { + ERROR_LOG(Log::IO, "Buffer::Printf failed"); } va_end(vl); char *ptr = Append(retval); diff --git a/Common/CPUDetect.cpp b/Common/CPUDetect.cpp index 057a892390..2cbe99b4cf 100644 --- a/Common/CPUDetect.cpp +++ b/Common/CPUDetect.cpp @@ -542,3 +542,31 @@ std::string CPUInfo::Summarize() { } #endif // PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) + +const char *GetCompilerABI() { +#if PPSSPP_ARCH(ARMV7) + return "armeabi-v7a"; +#elif PPSSPP_ARCH(ARM) + return "armeabi"; +#elif PPSSPP_ARCH(ARM64) + return "arm64"; +#elif PPSSPP_ARCH(X86) + return "x86"; +#elif PPSSPP_ARCH(AMD64) + return "x86-64"; +#elif PPSSPP_ARCH(RISCV64) + //https://github.com/riscv/riscv-toolchain-conventions#cc-preprocessor-definitions + //https://github.com/riscv/riscv-c-api-doc/blob/master/riscv-c-api.md#abi-related-preprocessor-definitions + #if defined(__riscv_float_abi_single) + return "lp64f"; + #elif defined(__riscv_float_abi_double) + return "lp64d"; + #elif defined(__riscv_float_abi_quad) + return "lp64q"; + #elif defined(__riscv_float_abi_soft) + return "lp64"; + #endif +#else + return "other"; +#endif +} diff --git a/Common/CPUDetect.h b/Common/CPUDetect.h index e4f0a567a4..20bb523415 100644 --- a/Common/CPUDetect.h +++ b/Common/CPUDetect.h @@ -161,3 +161,5 @@ private: }; extern CPUInfo cpu_info; + +const char *GetCompilerABI(); diff --git a/Common/CodeBlock.h b/Common/CodeBlock.h index 766d0a1cca..bb017c31f1 100644 --- a/Common/CodeBlock.h +++ b/Common/CodeBlock.h @@ -139,7 +139,7 @@ public: const uint8_t *end = GetCodePtr(); size_t sz = end - writeStart_; if (sz > writeEstimated_) - WARN_LOG(JIT, "EndWrite(): Estimated %d bytes, wrote %d", (int)writeEstimated_, (int)sz); + WARN_LOG(Log::JIT, "EndWrite(): Estimated %d bytes, wrote %d", (int)writeEstimated_, (int)sz); // If we protected and wrote less, we may need to unprotect. // Especially if we're linking blocks or similar. if (sz < writeEstimated_) diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index f3a3ab22f7..0b65c4e83c 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -1,4 +1,4 @@ - + @@ -385,6 +385,17 @@ + + + + + + + + + + + @@ -399,6 +410,7 @@ + @@ -509,6 +521,16 @@ + + true + true + true + true + true + true + true + true + @@ -526,7 +548,8 @@ - + + @@ -535,7 +558,7 @@ - + @@ -583,6 +606,15 @@ + + + + + + + + + NotUsing @@ -832,6 +864,7 @@ + @@ -947,7 +980,8 @@ - + + true @@ -973,7 +1007,7 @@ - + @@ -1014,6 +1048,8 @@ + + @@ -1035,6 +1071,16 @@ + + true + true + true + true + true + true + true + true + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 6d82c03c04..6541f4776e 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -5,10 +5,8 @@ - - @@ -521,14 +519,59 @@ Math + + ext\minimp3 + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + Render\Text + + + + Log + + + Log + - + - @@ -975,6 +1018,42 @@ GPU\Vulkan + + ext\minimp3 + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + Log + + + Log + @@ -1085,11 +1164,26 @@ {b681797d-7747-487f-b448-5ef5b2d2805b} + + {83cd76d0-d1ac-4ed1-9bdc-11fb5a20e5d3} + + + {586da66e-922a-4479-9dac-9d608a1b9183} + + + {cb2c7c09-1177-4a1e-962c-5cc7bcb56789} + ext\libpng17 + + ext\at3_standalone + + + ext\at3_standalone + @@ -1122,5 +1216,8 @@ ext\basis_universal + + Render\Text + \ No newline at end of file diff --git a/Common/Data/Collections/FastVec.h b/Common/Data/Collections/FastVec.h index 673c3ef5db..a8abb5e140 100644 --- a/Common/Data/Collections/FastVec.h +++ b/Common/Data/Collections/FastVec.h @@ -7,6 +7,7 @@ #include #include +#include #include "Common/Log.h" diff --git a/Common/Data/Collections/FixedSizeQueue.h b/Common/Data/Collections/FixedSizeQueue.h index 7d0b0998e7..68c96e829c 100644 --- a/Common/Data/Collections/FixedSizeQueue.h +++ b/Common/Data/Collections/FixedSizeQueue.h @@ -150,7 +150,7 @@ public: Do(p, size); if (size != N) { - ERROR_LOG(COMMON, "Savestate failure: Incompatible queue size."); + ERROR_LOG(Log::Common, "Savestate failure: Incompatible queue size."); return; } // TODO: This is quite wasteful, could just store the actual data. Would be slightly more complex though. diff --git a/Common/Data/Collections/Hashmaps.h b/Common/Data/Collections/Hashmaps.h index a9e5dece99..862c0e49af 100644 --- a/Common/Data/Collections/Hashmaps.h +++ b/Common/Data/Collections/Hashmaps.h @@ -347,7 +347,7 @@ private: Insert(old[i].hash, old[i].value); } } - INFO_LOG(G3D, "Grew hashmap capacity from %d to %d", oldCapacity, capacity_); + INFO_LOG(Log::G3D, "Grew hashmap capacity from %d to %d", oldCapacity, capacity_); _assert_msg_(oldCount == count_, "PrehashMap: count should not change in Grow()"); } struct Pair { diff --git a/Common/Data/Convert/ColorConv.h b/Common/Data/Convert/ColorConv.h index 53a286d127..6c47702b70 100644 --- a/Common/Data/Convert/ColorConv.h +++ b/Common/Data/Convert/ColorConv.h @@ -64,26 +64,28 @@ inline u32 RGBA4444ToRGBA8888(u16 src) { const u32 g = (src & 0x00F0) << 4; const u32 b = (src & 0x0F00) << 8; const u32 a = (src & 0xF000) << 12; - const u32 c = r | g | b | a; return c | (c << 4); } inline u32 RGBA5551ToRGBA8888(u16 src) { - u8 r = Convert5To8((src >> 0) & 0x1F); - u8 g = Convert5To8((src >> 5) & 0x1F); - u8 b = Convert5To8((src >> 10) & 0x1F); - u8 a = (src >> 15) & 0x1; - a = (a) ? 0xff : 0; - return (a << 24) | (b << 16) | (g << 8) | r; + u32 dark = ((src & 0x1F) << 3) | ((src & 0x3E0) << 6) | ((src & 0x7C00) << 9); + // Replicate the top 3 upper bits into the missing lower bits. + u32 full = (dark | ((dark >> 5) & 0x070707)); + if (src >> 15) { + full |= 0xFF000000; + } + return full; } inline u32 RGB565ToRGBA8888(u16 src) { - u8 r = Convert5To8((src >> 0) & 0x1F); - u8 g = Convert6To8((src >> 5) & 0x3F); - u8 b = Convert5To8((src >> 11) & 0x1F); - u8 a = 0xFF; - return (a << 24) | (b << 16) | (g << 8) | r; + u32 dark_rb = ((src & 0x1F) << 3) | ((src & 0xF800) << 8); + // Replicate the top 3 upper bits into the missing lower bits. + u32 full_rb = (dark_rb | ((dark_rb >> 5) & 0x070007)); + // Add in green (6 bits instead of 5). + u32 dark_g = ((src & 0x7E0) << 5); + u32 full_g = dark_g | ((dark_g >> 6) & 0x300); + return full_rb | full_g | 0xFF000000; } inline u16 RGBA8888ToRGB565(u32 value) { diff --git a/Common/Data/Encoding/Compression.cpp b/Common/Data/Encoding/Compression.cpp index 3e2e499a18..01bc6a1815 100644 --- a/Common/Data/Encoding/Compression.cpp +++ b/Common/Data/Encoding/Compression.cpp @@ -20,7 +20,7 @@ bool compress_string(const std::string& str, std::string *dest, int compressionl memset(&zs, 0, sizeof(zs)); if (deflateInit(&zs, compressionlevel) != Z_OK) { - ERROR_LOG(IO, "deflateInit failed while compressing."); + ERROR_LOG(Log::IO, "deflateInit failed while compressing."); return false; } @@ -67,7 +67,7 @@ bool decompress_string(const std::string& str, std::string *dest) { // modification by hrydgard: inflateInit2, 16+MAXWBITS makes it read gzip data too if (inflateInit2(&zs, 32+MAX_WBITS) != Z_OK) { - ERROR_LOG(IO, "inflateInit failed while decompressing."); + ERROR_LOG(Log::IO, "inflateInit failed while decompressing."); return false; } @@ -95,7 +95,7 @@ bool decompress_string(const std::string& str, std::string *dest) { inflateEnd(&zs); if (ret != Z_STREAM_END) { // an error occurred that was not EOF - ERROR_LOG(IO, "Exception during zlib decompression: (%i) %s", ret, zs.msg); + ERROR_LOG(Log::IO, "Exception during zlib decompression: (%i) %s", ret, zs.msg); return false; } diff --git a/Common/Data/Encoding/Utf8.cpp b/Common/Data/Encoding/Utf8.cpp index 3ec3fc6ac6..00e2b70578 100644 --- a/Common/Data/Encoding/Utf8.cpp +++ b/Common/Data/Encoding/Utf8.cpp @@ -29,6 +29,7 @@ #include "Common/Data/Encoding/Utf8.h" #include "Common/Data/Encoding/Utf16.h" +#include "Common/Log.h" // is start of UTF sequence inline bool isutf(char c) { @@ -209,6 +210,7 @@ int u8_charnum(const char *s, int offset) /* reads the next utf-8 sequence out of a string, updating an index */ uint32_t u8_nextchar(const char *s, int *index, size_t size) { uint32_t ch = 0; + _dbg_assert_(*index >= 0 && *index < 100000000); int sz = 0; int i = *index; do { @@ -372,8 +374,6 @@ int u8_is_locale_utf8(const char *locale) return 0; } -UTF8::UTF8(const char *c) : c_(c), size_((int)strlen(c)), index_(0) {} - bool AnyEmojiInString(std::string_view str, size_t byteCount) { int i = 0; while (i < byteCount) { diff --git a/Common/Data/Encoding/Utf8.h b/Common/Data/Encoding/Utf8.h index 87ede82241..7a397d2c5c 100644 --- a/Common/Data/Encoding/Utf8.h +++ b/Common/Data/Encoding/Utf8.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -39,7 +40,7 @@ class UTF8 { public: static const uint32_t INVALID = (uint32_t)-1; // TODO: Try to get rid of this constructor. - explicit UTF8(const char *c); + explicit UTF8(const char *c) : c_(c), size_((int)strlen(c)), index_(0) {} explicit UTF8(std::string_view view) : c_(view.data()), size_((int)view.size()), index_(0) {} explicit UTF8(std::string_view view, int index) : c_(view.data()), size_((int)view.size()), index_(index) {} bool end() const { return index_ == size_; } diff --git a/Common/Data/Format/IniFile.cpp b/Common/Data/Format/IniFile.cpp index 3455e6d5b2..829f09097b 100644 --- a/Common/Data/Format/IniFile.cpp +++ b/Common/Data/Format/IniFile.cpp @@ -198,7 +198,7 @@ bool Section::GetKeys(std::vector &keys) const { return true; } -ParsedIniLine *Section::GetLine(const char *key) { +ParsedIniLine *Section::GetLine(std::string_view key) { for (auto &line : lines_) { if (equalsNoCase(line.Key(), key)) return &line; @@ -206,7 +206,7 @@ ParsedIniLine *Section::GetLine(const char *key) { return nullptr; } -const ParsedIniLine *Section::GetLine(const char* key) const { +const ParsedIniLine *Section::GetLine(std::string_view key) const { for (auto &line : lines_) { if (equalsNoCase(line.Key(), key)) return &line; @@ -214,38 +214,38 @@ const ParsedIniLine *Section::GetLine(const char* key) const { return nullptr; } -void Section::Set(const char* key, uint32_t newValue) { +void Section::Set(std::string_view key, uint32_t newValue) { char temp[128]; snprintf(temp, sizeof(temp), "0x%08x", newValue); Set(key, (const char *)temp); } -void Section::Set(const char* key, uint64_t newValue) { +void Section::Set(std::string_view key, uint64_t newValue) { char temp[128]; snprintf(temp, sizeof(temp), "0x%016" PRIx64, newValue); Set(key, (const char *)temp); } -void Section::Set(const char* key, float newValue) { +void Section::Set(std::string_view key, float newValue) { _dbg_assert_(!my_isnanorinf(newValue)); char temp[128]; snprintf(temp, sizeof(temp), "%f", newValue); Set(key, (const char *)temp); } -void Section::Set(const char* key, double newValue) { +void Section::Set(std::string_view key, double newValue) { char temp[128]; snprintf(temp, sizeof(temp), "%f", newValue); Set(key, (const char *)temp); } -void Section::Set(const char* key, int newValue) { +void Section::Set(std::string_view key, int newValue) { char temp[128]; snprintf(temp, sizeof(temp), "%d", newValue); Set(key, (const char *)temp); } -void Section::Set(const char* key, const char* newValue) { +void Section::Set(std::string_view key, const char* newValue) { ParsedIniLine *line = GetLine(key); if (line) { line->SetValue(newValue); @@ -255,7 +255,7 @@ void Section::Set(const char* key, const char* newValue) { } } -void Section::Set(const char* key, const std::string& newValue, const std::string& defaultValue) +void Section::Set(std::string_view key, const std::string& newValue, const std::string& defaultValue) { if (newValue != defaultValue) Set(key, newValue); @@ -263,7 +263,7 @@ void Section::Set(const char* key, const std::string& newValue, const std::strin Delete(key); } -bool Section::Get(const char* key, std::string* value, const char* defaultValue) const { +bool Section::Get(std::string_view key, std::string* value, const char* defaultValue) const { const ParsedIniLine *line = GetLine(key); if (!line) { if (defaultValue) { @@ -276,7 +276,7 @@ bool Section::Get(const char* key, std::string* value, const char* defaultValue) return true; } -void Section::Set(const char* key, const float newValue, const float defaultValue) +void Section::Set(std::string_view key, const float newValue, const float defaultValue) { if (newValue != defaultValue) Set(key, newValue); @@ -284,7 +284,7 @@ void Section::Set(const char* key, const float newValue, const float defaultValu Delete(key); } -void Section::Set(const char* key, int newValue, int defaultValue) +void Section::Set(std::string_view key, int newValue, int defaultValue) { if (newValue != defaultValue) Set(key, newValue); @@ -292,7 +292,7 @@ void Section::Set(const char* key, int newValue, int defaultValue) Delete(key); } -void Section::Set(const char* key, bool newValue, bool defaultValue) +void Section::Set(std::string_view key, bool newValue, bool defaultValue) { if (newValue != defaultValue) Set(key, newValue); @@ -300,7 +300,7 @@ void Section::Set(const char* key, bool newValue, bool defaultValue) Delete(key); } -void Section::Set(const char* key, const std::vector& newValues) +void Section::Set(std::string_view key, const std::vector& newValues) { std::string temp; // Join the strings with , @@ -319,36 +319,32 @@ void Section::AddComment(const std::string &comment) { lines_.emplace_back(ParsedIniLine::CommentOnly("# " + comment)); } -bool Section::Get(const char* key, std::vector& values) const -{ +bool Section::Get(std::string_view key, std::vector& values) const { std::string temp; bool retval = Get(key, &temp, 0); - if (!retval || temp.empty()) - { + if (!retval || temp.empty()) { return false; } // ignore starting , if any - size_t subStart = temp.find_first_not_of(","); + size_t subStart = temp.find_first_not_of(','); size_t subEnd; // split by , while (subStart != std::string::npos) { - // Find next , - subEnd = temp.find_first_of(",", subStart); + subEnd = temp.find_first_of(',', subStart); if (subStart != subEnd) // take from first char until next , values.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart))); // Find the next non , char - subStart = temp.find_first_not_of(",", subEnd); + subStart = temp.find_first_not_of(',', subEnd); } return true; } -bool Section::Get(const char* key, int* value, int defaultValue) const -{ +bool Section::Get(std::string_view key, int* value, int defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); if (retval && TryParse(temp, value)) @@ -357,8 +353,7 @@ bool Section::Get(const char* key, int* value, int defaultValue) const return false; } -bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) const -{ +bool Section::Get(std::string_view key, uint32_t* value, uint32_t defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); if (retval && TryParse(temp, value)) @@ -367,8 +362,7 @@ bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) const return false; } -bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) const -{ +bool Section::Get(std::string_view key, uint64_t* value, uint64_t defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); if (retval && TryParse(temp, value)) @@ -377,8 +371,7 @@ bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) const return false; } -bool Section::Get(const char* key, bool* value, bool defaultValue) const -{ +bool Section::Get(std::string_view key, bool* value, bool defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); if (retval && TryParse(temp, value)) @@ -387,8 +380,7 @@ bool Section::Get(const char* key, bool* value, bool defaultValue) const return false; } -bool Section::Get(const char* key, float* value, float defaultValue) const -{ +bool Section::Get(std::string_view key, float* value, float defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); if (retval && TryParse(temp, value)) @@ -397,8 +389,7 @@ bool Section::Get(const char* key, float* value, float defaultValue) const return false; } -bool Section::Get(const char* key, double* value, double defaultValue) const -{ +bool Section::Get(std::string_view key, double* value, double defaultValue) const { std::string temp; bool retval = Get(key, &temp, 0); if (retval && TryParse(temp, value)) @@ -407,7 +398,7 @@ bool Section::Get(const char* key, double* value, double defaultValue) const return false; } -bool Section::Exists(const char *key) const { +bool Section::Exists(std::string_view key) const { for (auto &line : lines_) { if (equalsNoCase(key, line.Key())) return true; @@ -425,7 +416,7 @@ std::map Section::ToMap() const { return outMap; } -bool Section::Delete(const char *key) { +bool Section::Delete(std::string_view key) { ParsedIniLine *line = GetLine(key); for (auto liter = lines_.begin(); liter != lines_.end(); ++liter) { if (line == &*liter) { diff --git a/Common/Data/Format/IniFile.h b/Common/Data/Format/IniFile.h index 1103721ca9..8e944f8d1e 100644 --- a/Common/Data/Format/IniFile.h +++ b/Common/Data/Format/IniFile.h @@ -54,56 +54,56 @@ class Section { public: Section() {} - Section(const std::string& name) : name_(name) {} + Section(std::string_view name) : name_(name) {} - bool Exists(const char *key) const; - bool Delete(const char *key); + bool Exists(std::string_view key) const; + bool Delete(std::string_view key); void Clear(); std::map ToMap() const; - ParsedIniLine *GetLine(const char *key); - const ParsedIniLine *GetLine(const char *key) const; + ParsedIniLine *GetLine(std::string_view key); + const ParsedIniLine *GetLine(std::string_view key) const; - void Set(const char* key, const char* newValue); - void Set(const char* key, const std::string& newValue, const std::string& defaultValue); + void Set(std::string_view key, const char* newValue); + void Set(std::string_view key, const std::string& newValue, const std::string& defaultValue); - void Set(const std::string &key, const std::string &value) { - Set(key.c_str(), value.c_str()); + void Set(std::string_view key, const std::string &value) { + Set(key, value.c_str()); } - bool Get(const char* key, std::string* value, const char* defaultValue) const; + bool Get(std::string_view key, std::string* value, const char* defaultValue) const; - void Set(const char* key, uint32_t newValue); - void Set(const char* key, uint64_t newValue); - void Set(const char* key, float newValue); - void Set(const char* key, const float newValue, const float defaultValue); - void Set(const char* key, double newValue); + void Set(std::string_view key, uint32_t newValue); + void Set(std::string_view key, uint64_t newValue); + void Set(std::string_view key, float newValue); + void Set(std::string_view key, const float newValue, const float defaultValue); + void Set(std::string_view key, double newValue); - void Set(const char* key, int newValue, int defaultValue); - void Set(const char* key, int newValue); + void Set(std::string_view key, int newValue, int defaultValue); + void Set(std::string_view key, int newValue); - void Set(const char* key, bool newValue, bool defaultValue); - void Set(const char* key, bool newValue) { + void Set(std::string_view key, bool newValue, bool defaultValue); + void Set(std::string_view key, bool newValue) { Set(key, newValue ? "True" : "False"); } - void Set(const char* key, const std::vector& newValues); + void Set(std::string_view key, const std::vector& newValues); // Declare without a body to make it fail to compile. This is to prevent accidentally // setting a pointer as a bool. The failure is in the linker unfortunately, but that's better // than accidentally succeeding in a bad way. template - void Set(const char *key, T *ptr); + void Set(std::string_view key, T *ptr); void AddComment(const std::string &comment); - bool Get(const char* key, int* value, int defaultValue = 0) const; - bool Get(const char* key, uint32_t* value, uint32_t defaultValue = 0) const; - bool Get(const char* key, uint64_t* value, uint64_t defaultValue = 0) const; - bool Get(const char* key, bool* value, bool defaultValue = false) const; - bool Get(const char* key, float* value, float defaultValue = false) const; - bool Get(const char* key, double* value, double defaultValue = false) const; - bool Get(const char* key, std::vector& values) const; + bool Get(std::string_view key, int* value, int defaultValue = 0) const; + bool Get(std::string_view key, uint32_t* value, uint32_t defaultValue = 0) const; + bool Get(std::string_view key, uint64_t* value, uint64_t defaultValue = 0) const; + bool Get(std::string_view key, bool* value, bool defaultValue = false) const; + bool Get(std::string_view key, float* value, float defaultValue = false) const; + bool Get(std::string_view key, double* value, double defaultValue = false) const; + bool Get(std::string_view key, std::vector& values) const; // Return a list of all keys in this section bool GetKeys(std::vector &keys) const; @@ -133,30 +133,7 @@ public: // Returns true if key exists in section bool Exists(const char* sectionName, const char* key) const; - // TODO: Get rid of these, in favor of the Section ones. - void Set(const char* sectionName, const char* key, const char* newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, const std::string& newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue.c_str()); - } - void Set(const char* sectionName, const char* key, int newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, uint32_t newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, uint64_t newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, bool newValue) { - GetOrCreateSection(sectionName)->Set(key, newValue); - } - void Set(const char* sectionName, const char* key, const std::vector& newValues) { - GetOrCreateSection(sectionName)->Set(key, newValues); - } - - // TODO: Get rid of these, in favor of the Section ones. + // These will not create the section if it doesn't exist. bool Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue = ""); bool Get(const char* sectionName, const char* key, int* value, int defaultValue = 0); bool Get(const char* sectionName, const char* key, uint32_t* value, uint32_t defaultValue = 0); @@ -164,13 +141,6 @@ public: bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false); bool Get(const char* sectionName, const char* key, std::vector& values); - template bool GetIfExists(const char* sectionName, const char* key, T value) - { - if (Exists(sectionName, key)) - return Get(sectionName, key, value); - return false; - } - bool GetKeys(const char* sectionName, std::vector& keys) const; bool DeleteKey(const char* sectionName, const char* key); @@ -180,13 +150,12 @@ public: std::vector> &Sections() { return sections; } - bool HasSection(const char *section) { return GetSection(section) != 0; } + bool HasSection(const char *section) { return GetSection(section) != nullptr; } + const Section* GetSection(const char* section) const; + Section* GetSection(const char* section); Section* GetOrCreateSection(const char* section); private: std::vector> sections; - - const Section* GetSection(const char* section) const; - Section* GetSection(const char* section); }; diff --git a/Common/Data/Format/JSONReader.cpp b/Common/Data/Format/JSONReader.cpp index 49ea00b559..7fbe1ab2d2 100644 --- a/Common/Data/Format/JSONReader.cpp +++ b/Common/Data/Format/JSONReader.cpp @@ -17,7 +17,7 @@ JsonReader::JsonReader(const std::string &filename) { if (buffer_) { parse(); } else { - ERROR_LOG(IO, "Failed to read json file '%s'", filename.c_str()); + ERROR_LOG(Log::IO, "Failed to read json file '%s'", filename.c_str()); } } } @@ -26,7 +26,7 @@ bool JsonReader::parse() { char *error_pos; int status = jsonParse(buffer_, &error_pos, &root_, alloc_); if (status != JSON_OK) { - ERROR_LOG(IO, "Error at (%i): %s\n%s\n\n", (int)(error_pos - buffer_), jsonStrError(status), error_pos); + ERROR_LOG(Log::IO, "Error at (%i): %s\n%s\n\n", (int)(error_pos - buffer_), jsonStrError(status), error_pos); return false; } ok_ = true; @@ -46,7 +46,7 @@ int JsonGet::numChildren() const { const JsonNode *JsonGet::get(const char *child_name) const { if (!child_name) { - ERROR_LOG(IO, "JSON: Cannot get from null child name"); + ERROR_LOG(Log::IO, "JSON: Cannot get from null child name"); return nullptr; } if (value_.getTag() != JSON_OBJECT) { @@ -71,7 +71,7 @@ const char *JsonGet::getStringOrNull(const char *child_name) const { const JsonNode *val = get(child_name, JSON_STRING); if (val) return val->value.toString(); - ERROR_LOG(IO, "String '%s' missing from node", child_name); + ERROR_LOG(Log::IO, "String '%s' missing from node", child_name); return nullptr; } diff --git a/Common/Data/Format/PNGLoad.cpp b/Common/Data/Format/PNGLoad.cpp index b2ed18f99b..9dbaed8bbd 100644 --- a/Common/Data/Format/PNGLoad.cpp +++ b/Common/Data/Format/PNGLoad.cpp @@ -17,7 +17,7 @@ int pngLoad(const char *file, int *pwidth, int *pheight, unsigned char **image_d if (PNG_IMAGE_FAILED(png)) { - WARN_LOG(IO, "pngLoad: %s (%s)", png.message, file); + WARN_LOG(Log::IO, "pngLoad: %s (%s)", png.message, file); *image_data_ptr = nullptr; return 0; } @@ -38,7 +38,7 @@ int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, in png_image_begin_read_from_memory(&png, input_ptr, input_len); if (PNG_IMAGE_FAILED(png)) { - WARN_LOG(IO, "pngLoad: %s", png.message); + WARN_LOG(Log::IO, "pngLoad: %s", png.message); *image_data_ptr = nullptr; return 0; } @@ -50,7 +50,7 @@ int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, in size_t size = PNG_IMAGE_SIZE(png); if (!size) { - ERROR_LOG(IO, "pngLoad: empty image"); + ERROR_LOG(Log::IO, "pngLoad: empty image"); *image_data_ptr = nullptr; return 0; } diff --git a/Common/Data/Format/RIFF.cpp b/Common/Data/Format/RIFF.cpp index 2b6056a125..a748e41dfd 100644 --- a/Common/Data/Format/RIFF.cpp +++ b/Common/Data/Format/RIFF.cpp @@ -21,11 +21,12 @@ RIFFReader::~RIFFReader() { } int RIFFReader::ReadInt() { + int value = 0; if (data_ && pos_ < eof_ - 3) { pos_ += 4; - return *(int *)(data_ + pos_ - 4); + memcpy(&value, data_ + pos_ - 4, 4); } - return 0; + return value; } bool RIFFReader::Descend(uint32_t intoId) { @@ -46,7 +47,7 @@ bool RIFFReader::Descend(uint32_t intoId) { int startLocation = pos_; if (pos_ + length > fileSize_) { - ERROR_LOG(IO, "Block extends outside of RIFF file - failing descend"); + ERROR_LOG(Log::IO, "Block extends outside of RIFF file - failing descend"); pos_ = stack[depth_].parentStartLocation; return false; } @@ -61,7 +62,7 @@ bool RIFFReader::Descend(uint32_t intoId) { if (length > 0) { pos_ += length; // try next block } else { - ERROR_LOG(IO, "Bad data in RIFF file : block length %d. Not descending.", length); + ERROR_LOG(Log::IO, "Bad data in RIFF file : block length %d. Not descending.", length); pos_ = stack[depth_].parentStartLocation; return false; } @@ -104,4 +105,3 @@ int RIFFReader::GetCurrentChunkSize() { else return 0; } - diff --git a/Common/Data/Format/ZIMLoad.cpp b/Common/Data/Format/ZIMLoad.cpp index 1379521c7c..d61559e9eb 100644 --- a/Common/Data/Format/ZIMLoad.cpp +++ b/Common/Data/Format/ZIMLoad.cpp @@ -51,7 +51,7 @@ int ezuncompress(unsigned char* pDest, long* pnDestLen, const unsigned char* pSr int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int *flags, uint8_t **image) { if (zim[0] != 'Z' || zim[1] != 'I' || zim[2] != 'M' || zim[3] != 'G') { - ERROR_LOG(IO, "Not a ZIM file"); + ERROR_LOG(Log::IO, "Not a ZIM file"); return 0; } memcpy(width, zim + 4, 4); @@ -78,14 +78,14 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int image_data_size[i] = width[i] * height[i] * 2; break; default: - ERROR_LOG(IO, "Invalid ZIM format %i", *flags & ZIM_FORMAT_MASK); + ERROR_LOG(Log::IO, "Invalid ZIM format %i", *flags & ZIM_FORMAT_MASK); return 0; } total_data_size += image_data_size[i]; } if (total_data_size == 0) { - ERROR_LOG(IO, "Invalid ZIM data size 0"); + ERROR_LOG(Log::IO, "Invalid ZIM data size 0"); return 0; } @@ -98,19 +98,19 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int long outlen = (long)total_data_size; int retcode = ezuncompress(*image, &outlen, (unsigned char *)(zim + 16), (long)datasize - 16); if (Z_OK != retcode) { - ERROR_LOG(IO, "ZIM zlib format decompression failed: %d", retcode); + ERROR_LOG(Log::IO, "ZIM zlib format decompression failed: %d", retcode); free(*image); *image = 0; return 0; } if (outlen != total_data_size) { // Shouldn't happen if return value was Z_OK. - ERROR_LOG(IO, "Wrong size data in ZIM: %i vs %i", (int)outlen, (int)total_data_size); + ERROR_LOG(Log::IO, "Wrong size data in ZIM: %i vs %i", (int)outlen, (int)total_data_size); } } else if (*flags & ZIM_ZSTD_COMPRESSED) { size_t outlen = ZSTD_decompress(*image, total_data_size, zim + 16, datasize - 16); if (outlen != (size_t)total_data_size) { - ERROR_LOG(IO, "ZIM zstd format decompression failed: %lld", (long long)outlen); + ERROR_LOG(Log::IO, "ZIM zstd format decompression failed: %lld", (long long)outlen); free(*image); *image = 0; return 0; @@ -118,7 +118,7 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int } else { memcpy(*image, zim + 16, datasize - 16); if (datasize - 16 != (size_t)total_data_size) { - ERROR_LOG(IO, "Wrong size data in ZIM: %i vs %i", (int)(datasize-16), (int)total_data_size); + ERROR_LOG(Log::IO, "Wrong size data in ZIM: %i vs %i", (int)(datasize-16), (int)total_data_size); } } return num_levels; @@ -128,13 +128,13 @@ int LoadZIM(const char *filename, int *width, int *height, int *format, uint8_t size_t size; uint8_t *buffer = g_VFS.ReadFile(filename, &size); if (!buffer) { - ERROR_LOG(IO, "Couldn't read data for '%s'", filename); + ERROR_LOG(Log::IO, "Couldn't read data for '%s'", filename); return 0; } int retval = LoadZIMPtr(buffer, size, width, height, format, image); if (!retval) { - ERROR_LOG(IO, "Not a valid ZIM file: %s (size: %lld bytes)", filename, (long long)size); + ERROR_LOG(Log::IO, "Not a valid ZIM file: %s (size: %lld bytes)", filename, (long long)size); } delete [] buffer; return retval; diff --git a/Common/Data/Format/ZIMSave.cpp b/Common/Data/Format/ZIMSave.cpp index b18fcf682a..0abe0a40da 100644 --- a/Common/Data/Format/ZIMSave.cpp +++ b/Common/Data/Format/ZIMSave.cpp @@ -143,7 +143,7 @@ void Convert(const uint8_t *image_data, int width, int height, int pitch, int fl break; default: - ERROR_LOG(IO, "Unhandled ZIM format %d", flags & ZIM_FORMAT_MASK); + ERROR_LOG(Log::IO, "Unhandled ZIM format %d", flags & ZIM_FORMAT_MASK); *data = 0; *data_size = 0; return; @@ -199,7 +199,7 @@ void SaveZIM(FILE *f, int width, int height, int pitch, int flags, const uint8_t if (Z_OK == ezcompress(dest, &dest_len, data, data_size, compressLevel == 0 ? Z_DEFAULT_COMPRESSION : compressLevel)) { fwrite(dest, 1, dest_len, f); } else { - ERROR_LOG(IO, "Zlib compression failed.\n"); + ERROR_LOG(Log::IO, "Zlib compression failed.\n"); } delete [] dest; } else if (flags & ZIM_ZSTD_COMPRESSED) { @@ -209,7 +209,7 @@ void SaveZIM(FILE *f, int width, int height, int pitch, int flags, const uint8_t if (!ZSTD_isError(dest_len)) { fwrite(dest, 1, dest_len, f); } else { - ERROR_LOG(IO, "Zlib compression failed.\n"); + ERROR_LOG(Log::IO, "Zlib compression failed.\n"); } delete [] dest; } else { diff --git a/Common/Data/Text/I18n.cpp b/Common/Data/Text/I18n.cpp index 51f9960701..bcd2237c48 100644 --- a/Common/Data/Text/I18n.cpp +++ b/Common/Data/Text/I18n.cpp @@ -112,6 +112,11 @@ void I18NCategory::SetMap(const std::map &m) { } } +std::map I18NCategory::Missed() const { + std::lock_guard guard(missedKeyLock_); + return missedKeyLog_; +} + std::shared_ptr I18NRepo::GetCategory(I18NCat category) { std::lock_guard guard(catsLock_); if (category != I18NCat::NONE) @@ -137,7 +142,7 @@ bool I18NRepo::LoadIni(const std::string &languageID, const Path &overridePath) IniFile ini; Path iniPath; -// INFO_LOG(SYSTEM, "Loading lang ini %s", iniPath.c_str()); +// INFO_LOG(Log::System, "Loading lang ini %s", iniPath.c_str()); if (!overridePath.empty()) { iniPath = overridePath / (languageID + ".ini"); } else { @@ -169,7 +174,7 @@ void I18NRepo::LogMissingKeys() const { for (size_t i = 0; i < (size_t)I18NCat::CATEGORY_COUNT; i++) { auto &cat = cats_[i]; for (auto &key : cat->Missed()) { - INFO_LOG(SYSTEM, "Missing translation [%s]: %s (%s)", g_categoryNames[i], key.first.c_str(), key.second.c_str()); + INFO_LOG(Log::System, "Missing translation [%s]: %s (%s)", g_categoryNames[i], key.first.c_str(), key.second.c_str()); } } } diff --git a/Common/Data/Text/I18n.h b/Common/Data/Text/I18n.h index 083528e0c3..7af752804e 100644 --- a/Common/Data/Text/I18n.h +++ b/Common/Data/Text/I18n.h @@ -64,19 +64,12 @@ enum class I18NCat : uint8_t { }; struct I18NEntry { - I18NEntry(const std::string &t) : text(t), readFlag(false) {} + I18NEntry(std::string_view t) : text(t), readFlag(false) {} I18NEntry() : readFlag(false) {} std::string text; bool readFlag; }; -struct I18NCandidate { - I18NCandidate() : key(0), defVal(0) {} - I18NCandidate(const char *k, const char *d) : key(k), defVal(d) {} - const char *key; - const char *defVal; -}; - class I18NCategory { public: I18NCategory() {} @@ -88,10 +81,7 @@ public: // Try to avoid this. Still useful in snprintf. const char *T_cstr(const char *key, const char *def = nullptr); - std::map Missed() const { - std::lock_guard guard(missedKeyLock_); - return missedKeyLog_; - } + std::map Missed() const; const std::map> &GetMap() { return map_; } void ClearMissed() { missedKeyLog_.clear(); } @@ -155,4 +145,4 @@ inline std::string_view T(I18NCat category, std::string_view key, std::string_vi inline const char *T_cstr(I18NCat category, const char *key, const char *def = "") { return g_i18nrepo.T_cstr(category, key, def); -} \ No newline at end of file +} diff --git a/Common/Data/Text/WrapText.cpp b/Common/Data/Text/WrapText.cpp index 65989e7c0b..2cabc24232 100644 --- a/Common/Data/Text/WrapText.cpp +++ b/Common/Data/Text/WrapText.cpp @@ -141,7 +141,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) { // This will include the newline. if (x_ <= maxW_) { - out_.append(str_ + lastWordStartIndex, str_ + endIndex); + out_.append(str_.data() + lastWordStartIndex, str_.data() + endIndex); } else { scanForNewline_ = true; } @@ -153,7 +153,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) { x_ = 0.0f; } else { // We may have appended a newline - check. - size_t pos = out_.find_last_of("\n"); + size_t pos = out_.find_last_of('\n'); if (pos != out_.npos) { lastLineStart_ = pos + 1; } @@ -167,7 +167,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) { if (lastLineStart_ != out_.size()) { // To account for kerning around spaces, we recalculate the entire line width. - x_ = MeasureWidth(out_.c_str() + lastLineStart_, out_.size() - lastLineStart_); + x_ = MeasureWidth(std::string_view(out_.c_str() + lastLineStart_, out_.size() - lastLineStart_)); } else { x_ = 0.0f; } @@ -178,10 +178,10 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) { void WordWrapper::Wrap() { // First, let's check if it fits as-is. - size_t len = strlen(str_); - if (MeasureWidth(str_, len) <= maxW_) { + size_t len = str_.length(); + if (MeasureWidth(str_) <= maxW_) { // If it fits, we don't need to go through each character. - out_ = str_; + out_ = std::string(str_); return; } @@ -190,7 +190,7 @@ void WordWrapper::Wrap() { out_.reserve(len + len / 16); if (flags_ & FLAG_ELLIPSIZE_TEXT) { - ellipsisWidth_ = MeasureWidth("...", 3); + ellipsisWidth_ = MeasureWidth("..."); } for (UTF8 utf(str_); !utf.end(); ) { @@ -219,7 +219,10 @@ void WordWrapper::Wrap() { } // Measure the entire word for kerning purposes. May not be 100% perfect. - float newWordWidth = MeasureWidth(str_ + lastIndex_, afterIndex - lastIndex_); + float newWordWidth = 0.0f; + if (afterIndex <= str_.length()) { + newWordWidth = MeasureWidth(str_.substr(lastIndex_, afterIndex - lastIndex_)); + } // Is this the end of a word (space)? We'll also output up to a soft hyphen. if (wordWidth_ > 0.0f && IsSpaceOrShy(c)) { diff --git a/Common/Data/Text/WrapText.h b/Common/Data/Text/WrapText.h index d51f860362..1392307aca 100644 --- a/Common/Data/Text/WrapText.h +++ b/Common/Data/Text/WrapText.h @@ -1,18 +1,21 @@ #pragma once #include +#include class WordWrapper { public: - WordWrapper(const char *str, float maxW, int flags) + WordWrapper(std::string_view str, float maxW, int flags) : str_(str), maxW_(maxW), flags_(flags) { } virtual ~WordWrapper() {} + // TODO: This should return a vector of std::string_view for the lines, instead of building up a new string. std::string Wrapped(); protected: - virtual float MeasureWidth(const char *str, size_t bytes) = 0; + virtual float MeasureWidth(std::string_view str) = 0; + void Wrap(); bool WrapBeforeWord(); void AppendWord(int endIndex, int lastChar, bool addNewline); @@ -26,7 +29,7 @@ protected: return IsSpace(c) || IsShy(c); } - const char *const str_; + const std::string_view str_; const float maxW_; const int flags_; std::string out_; diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 70b5285bf0..75b88bc2b7 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -81,7 +81,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { return; } - INFO_LOG(SYSTEM, "Installing exception handler"); + INFO_LOG(Log::System, "Installing exception handler"); g_badAccessHandler = badAccessHandler; g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, GlobalExceptionHandler); } @@ -89,7 +89,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { void UninstallExceptionHandler() { if (g_vectoredExceptionHandle) { RemoveVectoredExceptionHandler(g_vectoredExceptionHandle); - INFO_LOG(SYSTEM, "Removed exception handler"); + INFO_LOG(Log::System, "Removed exception handler"); g_vectoredExceptionHandle = nullptr; } g_badAccessHandler = nullptr; @@ -186,7 +186,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { } g_badAccessHandler = badAccessHandler; - INFO_LOG(SYSTEM, "Installing exception handler"); + INFO_LOG(Log::System, "Installing exception handler"); mach_port_t port; CheckKR("mach_port_allocate", mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)); @@ -290,7 +290,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { // Add some extra room. altStackSize += 65536; - INFO_LOG(SYSTEM, "Installed exception handler. stack size: %d", (int)altStackSize); + INFO_LOG(Log::System, "Installed exception handler. stack size: %d", (int)altStackSize); g_badAccessHandler = badAccessHandler; stack_t signal_stack{}; @@ -323,7 +323,7 @@ void UninstallExceptionHandler() { stack_t signal_stack{}; signal_stack.ss_flags = SS_DISABLE; if (0 != sigaltstack(&signal_stack, nullptr)) { - ERROR_LOG(SYSTEM, "Could not remove signal altstack"); + ERROR_LOG(Log::System, "Could not remove signal altstack"); } if (altStack) { free(altStack); @@ -333,7 +333,7 @@ void UninstallExceptionHandler() { #ifdef __APPLE__ sigaction(SIGBUS, &old_sa_bus, nullptr); #endif - INFO_LOG(SYSTEM, "Uninstalled exception handler"); + INFO_LOG(Log::System, "Uninstalled exception handler"); g_badAccessHandler = nullptr; } @@ -342,7 +342,7 @@ void UninstallExceptionHandler() { #else // !MACHINE_CONTEXT_SUPPORTED void InstallExceptionHandler(BadAccessHandler badAccessHandler) { - ERROR_LOG(SYSTEM, "Exception handler not implemented on this platform, can't install"); + ERROR_LOG(Log::System, "Exception handler not implemented on this platform, can't install"); } void UninstallExceptionHandler() { } diff --git a/Common/FakeEmitter.h b/Common/FakeEmitter.h index f1d7a3f584..5727be7b5c 100644 --- a/Common/FakeEmitter.h +++ b/Common/FakeEmitter.h @@ -145,26 +145,26 @@ public: return Type; } Operand2() {} - Operand2(u32 imm, OpType type = TYPE_IMM) + Operand2(u32 imm, OpType type = TYPE_IMM) : IndexOrShift(), Shift() { Type = type; Value = imm; Rotation = 0; } - Operand2(FakeReg Reg) + Operand2(FakeReg Reg) : IndexOrShift(), Shift() { Type = TYPE_REG; Value = Reg; Rotation = 0; } - Operand2(u8 imm, u8 rotation) + Operand2(u8 imm, u8 rotation) : IndexOrShift(), Shift() { Type = TYPE_IMM; Value = imm; Rotation = rotation; } - Operand2(FakeReg base, ShiftType type, FakeReg shift) // RSR + Operand2(FakeReg base, ShiftType type, FakeReg shift) : Rotation(0) // RSR { Type = TYPE_RSR; _assert_msg_(type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount"); @@ -173,7 +173,7 @@ public: Value = base; } - Operand2(FakeReg base, ShiftType type, u8 shift)// For IMM shifted register + Operand2(FakeReg base, ShiftType type, u8 shift) : Rotation(0) // For IMM shifted register { if(shift == 32) shift = 0; switch (type) diff --git a/Common/File/AndroidContentURI.cpp b/Common/File/AndroidContentURI.cpp index 5c5a722218..1bcd7f48b3 100644 --- a/Common/File/AndroidContentURI.cpp +++ b/Common/File/AndroidContentURI.cpp @@ -48,7 +48,7 @@ bool AndroidContentURI::Parse(std::string_view path) { AndroidContentURI AndroidContentURI::WithRootFilePath(const std::string &filePath) { if (root.empty()) { - ERROR_LOG(SYSTEM, "WithRootFilePath cannot be used with single file URIs."); + ERROR_LOG(Log::System, "WithRootFilePath cannot be used with single file URIs."); return *this; } @@ -114,9 +114,9 @@ bool AndroidContentURI::CanNavigateUp() const { // Only goes downwards in hierarchies. No ".." will ever be generated. bool AndroidContentURI::ComputePathTo(const AndroidContentURI &other, std::string &path) const { size_t offset = FilePath().size() + 1; - std::string otherFilePath = other.FilePath(); + const auto &otherFilePath = other.FilePath(); if (offset >= otherFilePath.size()) { - ERROR_LOG(SYSTEM, "Bad call to PathTo. '%s' -> '%s'", FilePath().c_str(), other.FilePath().c_str()); + ERROR_LOG(Log::System, "Bad call to PathTo. '%s' -> '%s'", FilePath().c_str(), other.FilePath().c_str()); return false; } @@ -125,11 +125,11 @@ bool AndroidContentURI::ComputePathTo(const AndroidContentURI &other, std::strin } std::string AndroidContentURI::GetFileExtension() const { - size_t pos = file.rfind("."); + size_t pos = file.rfind('.'); if (pos == std::string::npos) { return ""; } - size_t slash_pos = file.rfind("/"); + size_t slash_pos = file.rfind('/'); if (slash_pos != std::string::npos && slash_pos > pos) { // Don't want to detect "df/file" from "/as.df/file" return ""; diff --git a/Common/File/AndroidContentURI.h b/Common/File/AndroidContentURI.h index 7015e0a20a..bc6bc65fe8 100644 --- a/Common/File/AndroidContentURI.h +++ b/Common/File/AndroidContentURI.h @@ -67,6 +67,10 @@ public: return root.empty() ? file : root; } + const std::string &Provider() const { + return provider; + } + bool IsTreeURI() const { return !root.empty(); } diff --git a/Common/File/AndroidStorage.cpp b/Common/File/AndroidStorage.cpp index fe106f772d..2ec63fb47c 100644 --- a/Common/File/AndroidStorage.cpp +++ b/Common/File/AndroidStorage.cpp @@ -154,20 +154,26 @@ static bool ParseFileInfo(const std::string &line, File::FileInfo *fileInfo) { std::vector parts; SplitString(line, '|', parts); if (parts.size() != 4) { - ERROR_LOG(FILESYS, "Bad format: %s", line.c_str()); + ERROR_LOG(Log::FileSystem, "Bad format (1): %s", line.c_str()); return false; } fileInfo->name = std::string(parts[2]); fileInfo->isDirectory = parts[0][0] == 'D'; fileInfo->exists = true; - sscanf(parts[1].c_str(), "%" PRIu64, &fileInfo->size); + if (1 != sscanf(parts[1].c_str(), "%" PRIu64, &fileInfo->size)) { + ERROR_LOG(Log::FileSystem, "Bad format (2): %s", line.c_str()); + return false; + } fileInfo->isWritable = true; // TODO: Should be passed as part of the string. // TODO: For read-only mappings, reflect that here, similarly as with isWritable. // Directories are normally executable (0111) which means they're traversable. fileInfo->access = fileInfo->isDirectory ? 0777 : 0666; uint64_t lastModifiedMs = 0; - sscanf(parts[3].c_str(), "%" PRIu64, &lastModifiedMs); + if (1 != sscanf(parts[3].c_str(), "%" PRIu64, &lastModifiedMs)) { + ERROR_LOG(Log::FileSystem, "Bad format (3): %s", line.c_str()); + return false; + } // Convert from milliseconds uint32_t lastModified = lastModifiedMs / 1000; @@ -229,7 +235,7 @@ std::vector Android_ListContentUri(const std::string &path, bool const char *charArray = env->GetStringUTFChars(str, 0); if (charArray) { // paranoia std::string line = charArray; - File::FileInfo info; + File::FileInfo info{}; if (line == "X") { // Indicates an exception thrown, path doesn't exist. *exists = false; @@ -247,7 +253,7 @@ std::vector Android_ListContentUri(const std::string &path, bool double elapsed = time_now_d() - start; double threshold = 0.1; if (elapsed >= threshold) { - INFO_LOG(FILESYS, "Listing directory on content URI '%s' took %0.3f s (%d files, log threshold = %0.3f)", path.c_str(), elapsed, (int)items.size(), threshold); + INFO_LOG(Log::FileSystem, "Listing directory on content URI '%s' took %0.3f s (%d files, log threshold = %0.3f)", path.c_str(), elapsed, (int)items.size(), threshold); } return items; } @@ -284,7 +290,7 @@ int64_t Android_ComputeRecursiveDirectorySize(const std::string &uri) { int64_t size = env->CallLongMethod(g_nativeActivity, computeRecursiveDirectorySize, param); double elapsed = time_now_d() - start; - INFO_LOG(IO, "ComputeRecursiveDirectorySize(%s) in %0.3f s", uri.c_str(), elapsed); + INFO_LOG(Log::IO, "ComputeRecursiveDirectorySize(%s) in %0.3f s", uri.c_str(), elapsed); return size; } diff --git a/Common/File/DiskFree.cpp b/Common/File/DiskFree.cpp index 35a0947dfa..9257ac880f 100644 --- a/Common/File/DiskFree.cpp +++ b/Common/File/DiskFree.cpp @@ -43,7 +43,7 @@ bool free_disk_space(const Path &path, int64_t &space) { #else if (path.Type() == PathType::CONTENT_URI) { space = Android_GetFreeSpaceByContentUri(path.ToString()); - INFO_LOG(COMMON, "Free space at '%s': %" PRIu64, path.c_str(), space); + INFO_LOG(Log::Common, "Free space at '%s': %" PRIu64, path.c_str(), space); return space >= 0; } diff --git a/Common/File/FileDescriptor.cpp b/Common/File/FileDescriptor.cpp index a68dc77f40..233f89b6d1 100644 --- a/Common/File/FileDescriptor.cpp +++ b/Common/File/FileDescriptor.cpp @@ -114,7 +114,7 @@ void SetNonBlocking(int sock, bool non_blocking) { int opts = fcntl(sock, F_GETFL); if (opts < 0) { perror("fcntl(F_GETFL)"); - ERROR_LOG(IO, "Error getting socket status while changing nonblocking status"); + ERROR_LOG(Log::IO, "Error getting socket status while changing nonblocking status"); } if (non_blocking) { opts = (opts | O_NONBLOCK); @@ -124,12 +124,12 @@ void SetNonBlocking(int sock, bool non_blocking) { if (fcntl(sock, F_SETFL, opts) < 0) { perror("fcntl(F_SETFL)"); - ERROR_LOG(IO, "Error setting socket nonblocking status"); + ERROR_LOG(Log::IO, "Error setting socket nonblocking status"); } #else u_long val = non_blocking ? 1 : 0; if (ioctlsocket(sock, FIONBIO, &val) != 0) { - ERROR_LOG(IO, "Error setting socket nonblocking status"); + ERROR_LOG(Log::IO, "Error setting socket nonblocking status"); } #endif } diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index 5aa74027b7..ee1969577b 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -20,6 +20,9 @@ #ifndef UNICODE #error Win32 build requires a unicode build #endif +#else +#define _POSIX_SOURCE +#define _LARGE_TIME_API #endif #include "ppsspp_config.h" @@ -37,6 +40,8 @@ #include #include +#include + #include "Common/Log.h" #include "Common/LogReporting.h" #include "Common/File/AndroidContentURI.h" @@ -46,6 +51,7 @@ #ifdef _WIN32 #include "Common/CommonWindows.h" +#include #include #include // for SHGetFolderPath #include @@ -63,6 +69,7 @@ #include #include #include +#include #endif #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) @@ -110,7 +117,7 @@ FILE *OpenCFile(const Path &path, const char *mode) { case PathType::CONTENT_URI: // We're gonna need some error codes.. if (!strcmp(mode, "r") || !strcmp(mode, "rb") || !strcmp(mode, "rt")) { - INFO_LOG(COMMON, "Opening content file for read: '%s'", path.c_str()); + INFO_LOG(Log::Common, "Opening content file for read: '%s'", path.c_str()); // Read, let's support this - easy one. int descriptor = Android_OpenContentUriFd(path.ToString(), Android_OpenContentUriMode::READ); if (descriptor < 0) { @@ -121,20 +128,20 @@ FILE *OpenCFile(const Path &path, const char *mode) { // Need to be able to create the file here if it doesn't exist. // Not exactly sure which abstractions are best, let's start simple. if (!File::Exists(path)) { - INFO_LOG(COMMON, "OpenCFile(%s): Opening content file for write. Doesn't exist, creating empty and reopening.", path.c_str()); + INFO_LOG(Log::Common, "OpenCFile(%s): Opening content file for write. Doesn't exist, creating empty and reopening.", path.c_str()); std::string name = path.GetFilename(); if (path.CanNavigateUp()) { Path parent = path.NavigateUp(); if (Android_CreateFile(parent.ToString(), name) != StorageError::SUCCESS) { - WARN_LOG(COMMON, "Failed to create file '%s' in '%s'", name.c_str(), parent.c_str()); + WARN_LOG(Log::Common, "Failed to create file '%s' in '%s'", name.c_str(), parent.c_str()); return nullptr; } } else { - INFO_LOG_REPORT_ONCE(openCFileFailedNavigateUp, COMMON, "Failed to navigate up to create file: %s", path.c_str()); + INFO_LOG_REPORT_ONCE(openCFileFailedNavigateUp, Log::Common, "Failed to navigate up to create file: %s", path.c_str()); return nullptr; } } else { - INFO_LOG(COMMON, "OpenCFile(%s): Opening existing content file for write (truncating). Requested mode: '%s'", path.c_str(), mode); + INFO_LOG(Log::Common, "OpenCFile(%s): Opening existing content file for write (truncating). Requested mode: '%s'", path.c_str(), mode); } // TODO: Support append modes and stuff... For now let's go with the most common one. @@ -146,7 +153,7 @@ FILE *OpenCFile(const Path &path, const char *mode) { } int descriptor = Android_OpenContentUriFd(path.ToString(), openMode); if (descriptor < 0) { - INFO_LOG(COMMON, "Opening '%s' for write failed", path.ToString().c_str()); + INFO_LOG(Log::Common, "Opening '%s' for write failed", path.ToString().c_str()); return nullptr; } FILE *f = fdopen(descriptor, fmode); @@ -156,18 +163,18 @@ FILE *OpenCFile(const Path &path, const char *mode) { } return f; } else { - ERROR_LOG(COMMON, "OpenCFile(%s): Mode not yet supported: %s", path.c_str(), mode); + ERROR_LOG(Log::Common, "OpenCFile(%s): Mode not yet supported: %s", path.c_str(), mode); return nullptr; } break; default: - ERROR_LOG(COMMON, "OpenCFile(%s): PathType not yet supported", path.c_str()); + ERROR_LOG(Log::Common, "OpenCFile(%s): PathType not yet supported", path.c_str()); return nullptr; } #if defined(_WIN32) && defined(UNICODE) #if PPSSPP_PLATFORM(UWP) && !defined(__LIBRETRO__) - // We shouldn't use _wfopen here, + // We shouldn't use _wfopen here, // this function is not allowed to read outside Local and Installation folders // FileSystem (broadFileSystemAccess) doesn't apply on _wfopen // if we have custom memory stick location _wfopen will return null @@ -206,27 +213,27 @@ int OpenFD(const Path &path, OpenFlag flags) { case PathType::CONTENT_URI: break; default: - ERROR_LOG(COMMON, "OpenFD: Only supports Content URI paths. Not '%s' (%s)!", path.c_str(), OpenFlagToString(flags).c_str()); + ERROR_LOG(Log::Common, "OpenFD: Only supports Content URI paths. Not '%s' (%s)!", path.c_str(), OpenFlagToString(flags).c_str()); // Not yet supported - use other paths. return -1; } if (flags & OPEN_CREATE) { if (!File::Exists(path)) { - INFO_LOG(COMMON, "OpenFD(%s): Creating file.", path.c_str()); + INFO_LOG(Log::Common, "OpenFD(%s): Creating file.", path.c_str()); std::string name = path.GetFilename(); if (path.CanNavigateUp()) { Path parent = path.NavigateUp(); if (Android_CreateFile(parent.ToString(), name) != StorageError::SUCCESS) { - WARN_LOG(COMMON, "OpenFD: Failed to create file '%s' in '%s'", name.c_str(), parent.c_str()); + WARN_LOG(Log::Common, "OpenFD: Failed to create file '%s' in '%s'", name.c_str(), parent.c_str()); return -1; } } else { - INFO_LOG(COMMON, "Failed to navigate up to create file: %s", path.c_str()); + INFO_LOG(Log::Common, "Failed to navigate up to create file: %s", path.c_str()); return -1; } } else { - INFO_LOG(COMMON, "OpenCFile(%s): Opening existing content file ('%s')", path.c_str(), OpenFlagToString(flags).c_str()); + INFO_LOG(Log::Common, "OpenCFile(%s): Opening existing content file ('%s')", path.c_str(), OpenFlagToString(flags).c_str()); } } @@ -242,14 +249,14 @@ int OpenFD(const Path &path, OpenFlag flags) { // TODO: Maybe better checking of additional flags here. } else { // TODO: Add support for more modes if possible. - ERROR_LOG_REPORT_ONCE(openFlagNotSupported, COMMON, "OpenFlag %s not yet supported", OpenFlagToString(flags).c_str()); + ERROR_LOG_REPORT_ONCE(openFlagNotSupported, Log::Common, "OpenFlag %s not yet supported", OpenFlagToString(flags).c_str()); return -1; } - INFO_LOG(COMMON, "Android_OpenContentUriFd: %s (%s)", path.c_str(), OpenFlagToString(flags).c_str()); + INFO_LOG(Log::Common, "Android_OpenContentUriFd: %s (%s)", path.c_str(), OpenFlagToString(flags).c_str()); int descriptor = Android_OpenContentUriFd(path.ToString(), mode); if (descriptor < 0) { - ERROR_LOG(COMMON, "Android_OpenContentUriFd failed: '%s'", path.c_str()); + ERROR_LOG(Log::Common, "Android_OpenContentUriFd failed: '%s'", path.c_str()); } if (flags & OPEN_APPEND) { @@ -340,6 +347,9 @@ std::string ResolvePath(const std::string &path) { delete [] buf; return output; +#elif PPSSPP_PLATFORM(IOS) + // Resolving has wacky effects on documents paths. + return path; #else std::unique_ptr buf(new char[PATH_MAX + 32768]); if (realpath(path.c_str(), buf.get()) == nullptr) @@ -404,8 +414,8 @@ bool Exists(const Path &path) { SetErrorMode(OldMode); #endif return true; -#else - struct stat file_info; +#else // !WIN32 + struct stat file_info{}; return stat(path.c_str(), &file_info) == 0; #endif } @@ -436,7 +446,7 @@ bool IsDirectory(const Path &filename) { #endif auto err = GetLastError(); if (err != ERROR_FILE_NOT_FOUND) { - WARN_LOG(COMMON, "GetFileAttributes failed on %s: %08x %s", filename.ToVisualString().c_str(), (uint32_t)err, GetStringErrorMsg(err).c_str()); + WARN_LOG(Log::Common, "GetFileAttributes failed on %s: %08x %s", filename.ToVisualString().c_str(), (uint32_t)err, GetStringErrorMsg(err).c_str()); } return false; } @@ -447,7 +457,7 @@ bool IsDirectory(const Path &filename) { struct stat file_info; int result = stat(copy.c_str(), &file_info); if (result < 0) { - WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", copy.c_str(), GetLastErrorMsg().c_str()); + WARN_LOG(Log::Common, "IsDirectory: stat failed on %s: %s", copy.c_str(), GetLastErrorMsg().c_str()); return false; } return S_ISDIR(file_info.st_mode); @@ -466,36 +476,36 @@ bool Delete(const Path &filename) { return false; } - INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); + INFO_LOG(Log::Common, "Delete: file %s", filename.c_str()); - // Return true because we care about the file no + // Return true because we care about the file no // being there, not the actual delete. if (!Exists(filename)) { - WARN_LOG(COMMON, "Delete: '%s' already does not exist", filename.c_str()); + WARN_LOG(Log::Common, "Delete: '%s' already does not exist", filename.c_str()); return true; } // We can't delete a directory if (IsDirectory(filename)) { - WARN_LOG(COMMON, "Delete failed: '%s' is a directory", filename.c_str()); + WARN_LOG(Log::Common, "Delete failed: '%s' is a directory", filename.c_str()); return false; } #ifdef _WIN32 #if PPSSPP_PLATFORM(UWP) if (!DeleteFileFromAppW(filename.ToWString().c_str())) { - WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); + WARN_LOG(Log::Common, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); return false; } #else if (!DeleteFile(filename.ToWString().c_str())) { - WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); + WARN_LOG(Log::Common, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); return false; } #endif #else if (unlink(filename.c_str()) == -1) { - WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", + WARN_LOG(Log::Common, "Delete: unlink failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); return false; } @@ -522,11 +532,11 @@ bool CreateDir(const Path &path) { AndroidContentURI uri(path.ToString()); std::string newDirName = uri.GetLastPart(); if (uri.NavigateUp()) { - INFO_LOG(COMMON, "Calling Android_CreateDirectory(%s, %s)", uri.ToString().c_str(), newDirName.c_str()); + INFO_LOG(Log::Common, "Calling Android_CreateDirectory(%s, %s)", uri.ToString().c_str(), newDirName.c_str()); return Android_CreateDirectory(uri.ToString(), newDirName) == StorageError::SUCCESS; } else { // Bad path - can't create this directory. - WARN_LOG(COMMON, "CreateDir failed: '%s'", path.c_str()); + WARN_LOG(Log::Common, "CreateDir failed: '%s'", path.c_str()); return false; } break; @@ -535,7 +545,7 @@ bool CreateDir(const Path &path) { return false; } - DEBUG_LOG(COMMON, "CreateDir('%s')", path.c_str()); + DEBUG_LOG(Log::Common, "CreateDir('%s')", path.c_str()); #ifdef _WIN32 #if PPSSPP_PLATFORM(UWP) if (CreateDirectoryFromAppW(path.ToWString().c_str(), NULL)) @@ -544,13 +554,13 @@ bool CreateDir(const Path &path) { if (::CreateDirectory(path.ToWString().c_str(), NULL)) return true; #endif - + DWORD error = GetLastError(); if (error == ERROR_ALREADY_EXISTS) { - WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); + WARN_LOG(Log::Common, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); return true; } - ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %08x %s", path.c_str(), (uint32_t)error, GetStringErrorMsg(error).c_str()); + ERROR_LOG(Log::Common, "CreateDir: CreateDirectory failed on %s: %08x %s", path.c_str(), (uint32_t)error, GetStringErrorMsg(error).c_str()); return false; #else if (mkdir(path.ToString().c_str(), 0755) == 0) { @@ -559,11 +569,11 @@ bool CreateDir(const Path &path) { int err = errno; if (err == EEXIST) { - WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str()); + WARN_LOG(Log::Common, "CreateDir: mkdir failed on %s: already exists", path.c_str()); return true; } - ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err)); + ERROR_LOG(Log::Common, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err)); return false; #endif } @@ -571,7 +581,7 @@ bool CreateDir(const Path &path) { // Creates the full path of fullPath returns true on success bool CreateFullPath(const Path &path) { if (File::Exists(path)) { - DEBUG_LOG(COMMON, "CreateFullPath: path exists %s", path.c_str()); + DEBUG_LOG(Log::Common, "CreateFullPath: path exists %s", path.c_str()); return true; } @@ -580,7 +590,7 @@ bool CreateFullPath(const Path &path) { case PathType::CONTENT_URI: break; // OK default: - ERROR_LOG(COMMON, "CreateFullPath(%s): Not yet supported", path.c_str()); + ERROR_LOG(Log::Common, "CreateFullPath(%s): Not yet supported", path.c_str()); return false; } @@ -598,7 +608,7 @@ bool CreateFullPath(const Path &path) { // Probably not necessary sanity check, ported from the old code. if (parts.size() > 100) { - ERROR_LOG(COMMON, "CreateFullPath: directory structure too deep"); + ERROR_LOG(Log::Common, "CreateFullPath: directory structure too deep"); return false; } @@ -613,7 +623,7 @@ bool CreateFullPath(const Path &path) { return true; } -// renames file srcFilename to destFilename, returns true on success +// renames file srcFilename to destFilename, returns true on success bool Rename(const Path &srcFilename, const Path &destFilename) { if (srcFilename.Type() != destFilename.Type()) { // Impossible. You're gonna need to make a copy, and delete the original. Not the responsibility @@ -630,16 +640,16 @@ bool Rename(const Path &srcFilename, const Path &destFilename) { // Content URI: Can only rename if in the same folder. // TODO: Fallback to move + rename? Or do we even care about that use case? We have MoveIfFast for such tricks. if (srcFilename.GetDirectory() != destFilename.GetDirectory()) { - INFO_LOG(COMMON, "Content URI rename: Directories not matching, failing. %s --> %s", srcFilename.c_str(), destFilename.c_str()); + INFO_LOG(Log::Common, "Content URI rename: Directories not matching, failing. %s --> %s", srcFilename.c_str(), destFilename.c_str()); return false; } - INFO_LOG(COMMON, "Content URI rename: %s --> %s", srcFilename.c_str(), destFilename.c_str()); + INFO_LOG(Log::Common, "Content URI rename: %s --> %s", srcFilename.c_str(), destFilename.c_str()); return Android_RenameFileTo(srcFilename.ToString(), destFilename.GetFilename()) == StorageError::SUCCESS; default: return false; } - INFO_LOG(COMMON, "Rename: %s --> %s", srcFilename.c_str(), destFilename.c_str()); + INFO_LOG(Log::Common, "Rename: %s --> %s", srcFilename.c_str(), destFilename.c_str()); #if defined(_WIN32) && defined(UNICODE) #if PPSSPP_PLATFORM(UWP) @@ -656,12 +666,12 @@ bool Rename(const Path &srcFilename, const Path &destFilename) { return true; #endif - ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", + ERROR_LOG(Log::Common, "Rename: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); return false; } -// copies file srcFilename to destFilename, returns true on success +// copies file srcFilename to destFilename, returns true on success bool Copy(const Path &srcFilename, const Path &destFilename) { switch (srcFilename.Type()) { case PathType::NATIVE: @@ -673,6 +683,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename) { if (Android_CopyFile(srcFilename.ToString(), destParent.ToString()) == StorageError::SUCCESS) { return true; } + INFO_LOG(Log::Common, "Android_CopyFile failed, falling back."); // Else fall through, and try using file I/O. } break; @@ -680,7 +691,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename) { return false; } - INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str()); + INFO_LOG(Log::Common, "Copy by OpenCFile: %s --> %s", srcFilename.c_str(), destFilename.c_str()); #ifdef _WIN32 #if PPSSPP_PLATFORM(UWP) if (CopyFileFromAppW(srcFilename.ToWString().c_str(), destFilename.ToWString().c_str(), FALSE)) @@ -689,10 +700,10 @@ bool Copy(const Path &srcFilename, const Path &destFilename) { if (CopyFile(srcFilename.ToWString().c_str(), destFilename.ToWString().c_str(), FALSE)) return true; #endif - ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", + ERROR_LOG(Log::Common, "Copy: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); return false; -#else +#else // Non-Win32 // buffer size #define BSIZE 16384 @@ -702,7 +713,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename) { // Open input file FILE *input = OpenCFile(srcFilename, "rb"); if (!input) { - ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", + ERROR_LOG(Log::Common, "Copy: input failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); return false; } @@ -711,22 +722,24 @@ bool Copy(const Path &srcFilename, const Path &destFilename) { FILE *output = OpenCFile(destFilename, "wb"); if (!output) { fclose(input); - ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", + ERROR_LOG(Log::Common, "Copy: output failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); return false; } + int bytesWritten = 0; + // copy loop while (!feof(input)) { // read input int rnum = fread(buffer, sizeof(char), BSIZE, input); if (rnum != BSIZE) { if (ferror(input) != 0) { - ERROR_LOG(COMMON, - "Copy: failed reading from source, %s --> %s: %s", + ERROR_LOG(Log::Common, + "Copy: failed reading from source, %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); fclose(input); - fclose(output); + fclose(output); return false; } } @@ -734,14 +747,21 @@ bool Copy(const Path &srcFilename, const Path &destFilename) { // write output int wnum = fwrite(buffer, sizeof(char), rnum, output); if (wnum != rnum) { - ERROR_LOG(COMMON, - "Copy: failed writing to output, %s --> %s: %s", + ERROR_LOG(Log::Common, + "Copy: failed writing to output, %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); fclose(input); - fclose(output); + fclose(output); return false; } + + bytesWritten += wnum; } + + if (bytesWritten == 0) { + WARN_LOG(Log::Common, "Copy: No bytes written (must mean that input was empty)"); + } + // close flushes fclose(input); fclose(output); @@ -826,14 +846,14 @@ uint64_t GetFileSize(const Path &filename) { int result = stat64(filename.c_str(), &file_info); #endif if (result != 0) { - WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.ToVisualString().c_str()); + WARN_LOG(Log::Common, "GetSize: failed %s: No such file", filename.ToVisualString().c_str()); return 0; } if (S_ISDIR(file_info.st_mode)) { - WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.ToVisualString().c_str()); + WARN_LOG(Log::Common, "GetSize: failed %s: is a directory", filename.ToVisualString().c_str()); return 0; } - DEBUG_LOG(COMMON, "GetSize: %s: %lld", filename.ToVisualString().c_str(), (long long)file_info.st_size); + DEBUG_LOG(Log::Common, "GetSize: %s: %lld", filename.ToVisualString().c_str(), (long long)file_info.st_size); return file_info.st_size; #endif } @@ -880,12 +900,12 @@ uint64_t GetFileSize(FILE *f) { #endif } -// creates an empty file filename, returns true on success +// creates an empty file filename, returns true on success bool CreateEmptyFile(const Path &filename) { - INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); + INFO_LOG(Log::Common, "CreateEmptyFile: %s", filename.c_str()); FILE *pFile = OpenCFile(filename, "wb"); if (!pFile) { - ERROR_LOG(COMMON, "CreateEmptyFile: failed to create '%s': %s", filename.c_str(), GetLastErrorMsg().c_str()); + ERROR_LOG(Log::Common, "CreateEmptyFile: failed to create '%s': %s", filename.c_str(), GetLastErrorMsg().c_str()); return false; } fclose(pFile); @@ -903,11 +923,11 @@ bool DeleteDir(const Path &path) { default: return false; } - INFO_LOG(COMMON, "DeleteDir: directory %s", path.c_str()); + INFO_LOG(Log::Common, "DeleteDir: directory %s", path.c_str()); // check if a directory if (!File::IsDirectory(path)) { - ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", path.c_str()); + ERROR_LOG(Log::Common, "DeleteDir: Not a directory %s", path.c_str()); return false; } @@ -923,7 +943,7 @@ bool DeleteDir(const Path &path) { if (rmdir(path.c_str()) == 0) return true; #endif - ERROR_LOG(COMMON, "DeleteDir: %s: %s", path.c_str(), GetLastErrorMsg().c_str()); + ERROR_LOG(Log::Common, "DeleteDir: %s: %s", path.c_str(), GetLastErrorMsg().c_str()); return false; } @@ -937,7 +957,7 @@ bool DeleteDirRecursively(const Path &path) { // We make use of the dangerous auto-recursive property of Android_RemoveFile. return Android_RemoveFile(path.ToString()) == StorageError::SUCCESS; default: - ERROR_LOG(COMMON, "DeleteDirRecursively: Path type not supported"); + ERROR_LOG(Log::Common, "DeleteDirRecursively: Path type not supported"); return false; } @@ -958,7 +978,7 @@ bool OpenFileInEditor(const Path &fileName) { case PathType::NATIVE: break; // OK default: - ERROR_LOG(COMMON, "OpenFileInEditor(%s): Path type not supported", fileName.c_str()); + ERROR_LOG(Log::Common, "OpenFileInEditor(%s): Path type not supported", fileName.c_str()); return false; } @@ -976,10 +996,10 @@ bool OpenFileInEditor(const Path &fileName) { iniFile = "xdg-open "; #endif iniFile.append(fileName.ToString()); - NOTICE_LOG(BOOT, "Launching %s", iniFile.c_str()); + NOTICE_LOG(Log::Boot, "Launching %s", iniFile.c_str()); int retval = system(iniFile.c_str()); if (retval != 0) { - ERROR_LOG(COMMON, "Failed to launch ini file"); + ERROR_LOG(Log::Common, "Failed to launch ini file"); } #endif return true; @@ -1115,7 +1135,7 @@ bool IOFile::Seek(int64_t off, int origin) } uint64_t IOFile::Tell() -{ +{ if (IsOpen()) return ftello(m_file); else @@ -1237,4 +1257,42 @@ bool WriteDataToFile(bool text_file, const void* data, size_t size, const Path & return true; } +void ChangeMTime(const Path &path, time_t mtime) { + if (path.Type() == PathType::CONTENT_URI) { + // No clue what to do here. + return; + } + +#ifdef _WIN32 + _utimbuf buf{}; + buf.actime = mtime; + buf.modtime = mtime; + _utime(path.c_str(), &buf); +#else + utimbuf buf{}; + buf.actime = mtime; + buf.modtime = mtime; + utime(path.c_str(), &buf); +#endif +} + +bool IsProbablyInDownloadsFolder(const Path &filename) { + INFO_LOG(Log::Common, "IsProbablyInDownloadsFolder: Looking at %s (%s)...", filename.c_str(), filename.ToVisualString().c_str()); + switch (filename.Type()) { + case PathType::CONTENT_URI: + { + AndroidContentURI uri(filename.ToString()); + INFO_LOG(Log::Common, "Content URI provider: %s", uri.Provider().c_str()); + if (containsNoCase(uri.Provider(), "download")) { + // like com.android.providers.downloads.documents + return true; + } + break; + } + default: + break; + } + return filename.FilePathContainsNoCase("download"); +} + } // namespace File diff --git a/Common/File/FileUtil.h b/Common/File/FileUtil.h index 872ba6e4bc..eedf4cecf1 100644 --- a/Common/File/FileUtil.h +++ b/Common/File/FileUtil.h @@ -83,6 +83,8 @@ uint64_t ComputeRecursiveDirectorySize(const Path &path); // Returns true if successful, or path already exists. bool CreateDir(const Path &filename); +void ChangeMTime(const Path &path, time_t mtime); + // Creates the full path of fullPath returns true on success bool CreateFullPath(const Path &fullPath); @@ -120,6 +122,10 @@ bool CreateEmptyFile(const Path &filename); // TODO: Belongs in System or something. bool OpenFileInEditor(const Path &fileName); +// Uses some heuristics to determine if this is a folder that we would want to +// write to. +bool IsProbablyInDownloadsFolder(const Path &folder); + // TODO: Belongs in System or something. const Path &GetExeDirectory(); diff --git a/Common/File/Path.cpp b/Common/File/Path.cpp index c9302437eb..8592ed401c 100644 --- a/Common/File/Path.cpp +++ b/Common/File/Path.cpp @@ -51,7 +51,7 @@ void Path::Init(std::string_view str) { // and flip it to a NATIVE url and hope for the best. AndroidContentURI uri(str); if (startsWith(uri.FilePath(), "raw:/")) { - INFO_LOG(SYSTEM, "Raw path detected: %s", uri.FilePath().c_str()); + INFO_LOG(Log::System, "Raw path detected: %s", uri.FilePath().c_str()); path_ = uri.FilePath().substr(4); type_ = PathType::NATIVE; } else { @@ -240,6 +240,9 @@ bool Path::FilePathContainsNoCase(std::string_view needle) const { } bool Path::StartsWith(const Path &other) const { + if (other.empty()) { + return true; + } if (type_ != other.type_) { // Bad return false; diff --git a/Common/File/Path.h b/Common/File/Path.h index e94caf14c3..cf48fb277d 100644 --- a/Common/File/Path.h +++ b/Common/File/Path.h @@ -50,6 +50,9 @@ public: PathType Type() const { return type_; } + bool IsLocalType() const { + return type_ == PathType::NATIVE || type_ == PathType::CONTENT_URI; + } bool Valid() const { return !path_.empty(); } bool IsRoot() const { return path_ == "/"; } // Special value - only path that can end in a slash. diff --git a/Common/File/PathBrowser.cpp b/Common/File/PathBrowser.cpp index 40689c0c9f..ea5bb92e88 100644 --- a/Common/File/PathBrowser.cpp +++ b/Common/File/PathBrowser.cpp @@ -74,7 +74,7 @@ bool LoadRemoteFileList(const Path &url, const std::string &userAgent, bool *can // Try to extract from an automatic webserver directory listing... GetQuotedStrings(listing, items); } else { - ERROR_LOG(IO, "Unsupported Content-Type: %s", contentType.c_str()); + ERROR_LOG(Log::IO, "Unsupported Content-Type: %s", contentType.c_str()); return false; } Path basePath(baseURL.ToString()); @@ -124,9 +124,15 @@ PathBrowser::~PathBrowser() { void PathBrowser::SetPath(const Path &path) { path_ = path; + ApplyRestriction(); HandlePath(); } +void PathBrowser::RestrictToRoot(const Path &root) { + INFO_LOG(Log::System, "Restricting to root: %s", root.c_str()); + restrictedRoot_ = root; +} + void PathBrowser::HandlePath() { if (!path_.empty() && path_.ToString()[0] == '!') { if (pendingActive_) @@ -162,24 +168,26 @@ void PathBrowser::HandlePath() { break; } lastPath = pendingPath_; - bool success = false; if (lastPath.Type() == PathType::HTTP) { guard.unlock(); results.clear(); - success = LoadRemoteFileList(lastPath, userAgent_, &pendingCancel_, results); + success_ = LoadRemoteFileList(lastPath, userAgent_, &pendingCancel_, results); guard.lock(); } else if (lastPath.empty()) { results.clear(); - success = true; + success_ = true; } else { guard.unlock(); results.clear(); - success = File::GetFilesInDir(lastPath, &results, nullptr); + success_ = File::GetFilesInDir(lastPath, &results, nullptr); + if (!success_) { + WARN_LOG(Log::IO, "PathBrowser: Failed to list directory: %s", lastPath.c_str()); + } guard.lock(); } if (pendingPath_ == lastPath) { - if (success && !pendingCancel_) { + if (success_ && !pendingCancel_) { pendingFiles_ = results; } pendingPath_.clear(); @@ -201,19 +209,28 @@ bool PathBrowser::IsListingReady() { } std::string PathBrowser::GetFriendlyPath() const { - std::string str = GetPath().ToVisualString(); // Show relative to memstick root if there. - if (startsWith(str, aliasMatch_)) { - return aliasDisplay_ + str.substr(aliasMatch_.size()); + if (path_.StartsWith(aliasMatch_)) { + std::string p; + if (aliasMatch_.ComputePathTo(path_, p)) { + return aliasDisplay_ + p; + } + std::string str = path_.ToString(); + if (aliasMatch_.size() < str.length()) { + return aliasDisplay_ + str.substr(aliasMatch_.size()); + } else { + return aliasDisplay_; + } } -#if PPSSPP_PLATFORM(LINUX) || PPSSPP_PLATFORM(MAC) + std::string str = path_.ToString(); +#if !PPSSPP_PLATFORM(ANDROID) && (PPSSPP_PLATFORM(LINUX) || PPSSPP_PLATFORM(MAC)) char *home = getenv("HOME"); if (home != nullptr && !strncmp(str.c_str(), home, strlen(home))) { - str = std::string("~") + str.substr(strlen(home)); + return std::string("~") + str.substr(strlen(home)); } #endif - return str; + return path_.ToVisualString(); } bool PathBrowser::GetListing(std::vector &fileInfo, const char *filter, bool *cancel) { @@ -229,12 +246,24 @@ bool PathBrowser::GetListing(std::vector &fileInfo, const char * return true; } +void PathBrowser::ApplyRestriction() { + if (!path_.StartsWith(restrictedRoot_) && !startsWith(path_.ToString(), "!")) { + WARN_LOG(Log::System, "Applying path restriction: %s (%s didn't match)", restrictedRoot_.c_str(), path_.c_str()); + path_ = restrictedRoot_; + } +} + bool PathBrowser::CanNavigateUp() { + if (path_ == restrictedRoot_) { + return false; + } return path_.CanNavigateUp(); } void PathBrowser::NavigateUp() { + _dbg_assert_(CanNavigateUp()); path_ = path_.NavigateUp(); + ApplyRestriction(); } // TODO: Support paths like "../../hello" diff --git a/Common/File/PathBrowser.h b/Common/File/PathBrowser.h index f6a8e782df..38733c6cae 100644 --- a/Common/File/PathBrowser.h +++ b/Common/File/PathBrowser.h @@ -8,7 +8,6 @@ #include #include - #include "Common/File/DirListing.h" #include "Common/File/Path.h" @@ -18,7 +17,6 @@ class PathBrowser { public: PathBrowser() {} - PathBrowser(const Path &path) { SetPath(path); } ~PathBrowser(); void SetPath(const Path &path); @@ -41,24 +39,29 @@ public: void SetUserAgent(const std::string &s) { userAgent_ = s; } - void SetRootAlias(const std::string &alias, const std::string &longValue) { + void SetRootAlias(const std::string &alias, const Path &rootPath) { aliasDisplay_ = alias; - aliasMatch_ = longValue; + aliasMatch_ = rootPath; } - + void RestrictToRoot(const Path &root); bool empty() const { return path_.empty(); } + bool Success() const { + return success_; + } private: void HandlePath(); void ResetPending(); + void ApplyRestriction(); Path path_; Path pendingPath_; + Path restrictedRoot_; std::string userAgent_; std::string aliasDisplay_; - std::string aliasMatch_; + Path aliasMatch_; std::vector pendingFiles_; std::condition_variable pendingCond_; std::mutex pendingLock_; @@ -67,5 +70,6 @@ private: bool pendingCancel_ = false; bool pendingStop_ = false; bool ready_ = false; + bool success_ = true; }; diff --git a/Common/File/VFS/VFS.cpp b/Common/File/VFS/VFS.cpp index 0b6636d83e..3334b7cae4 100644 --- a/Common/File/VFS/VFS.cpp +++ b/Common/File/VFS/VFS.cpp @@ -11,9 +11,9 @@ VFS g_VFS; void VFS::Register(const char *prefix, VFSBackend *reader) { if (reader) { entries_.push_back(VFSEntry{ prefix, reader }); - DEBUG_LOG(IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str()); + DEBUG_LOG(Log::IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str()); } else { - ERROR_LOG(IO, "Trying to register null VFS backend for prefix %s", prefix); + ERROR_LOG(Log::IO, "Trying to register null VFS backend for prefix %s", prefix); } } @@ -25,7 +25,7 @@ void VFS::Clear() { } // TODO: Use Path more. -static bool IsLocalAbsolutePath(const char *path) { +static bool IsLocalAbsolutePath(std::string_view path) { bool isUnixLocal = path[0] == '/'; #ifdef _WIN32 bool isWindowsLocal = (isalpha(path[0]) && path[1] == ':') || startsWith(path, "\\\\") || startsWith(path, "//"); @@ -40,7 +40,7 @@ static bool IsLocalAbsolutePath(const char *path) { uint8_t *VFS::ReadFile(const char *filename, size_t *size) { if (IsLocalAbsolutePath(filename)) { // Local path, not VFS. - // INFO_LOG(IO, "Not a VFS path: %s . Reading local file.", filename); + // INFO_LOG(Log::IO, "Not a VFS path: %s . Reading local file.", filename); return File::ReadLocalFile(Path(filename), size); } @@ -51,7 +51,7 @@ uint8_t *VFS::ReadFile(const char *filename, size_t *size) { if (prefix_len >= fn_len) continue; if (0 == memcmp(filename, entry.prefix, prefix_len)) { fileSystemFound = true; - // INFO_LOG(IO, "Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len); + // INFO_LOG(Log::IO, "Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len); uint8_t *data = entry.reader->ReadFile(filename + prefix_len, size); if (data) return data; @@ -61,7 +61,7 @@ uint8_t *VFS::ReadFile(const char *filename, size_t *size) { } } if (!fileSystemFound) { - ERROR_LOG(IO, "Missing filesystem for '%s'", filename); + ERROR_LOG(Log::IO, "Missing filesystem for '%s'", filename); } // Otherwise, the file was just missing. No need to log. return nullptr; } @@ -69,7 +69,7 @@ uint8_t *VFS::ReadFile(const char *filename, size_t *size) { bool VFS::GetFileListing(const char *path, std::vector *listing, const char *filter) { if (IsLocalAbsolutePath(path)) { // Local path, not VFS. - // INFO_LOG(IO, "Not a VFS path: %s . Reading local directory.", path); + // INFO_LOG(Log::IO, "Not a VFS path: %s . Reading local directory.", path); File::GetFilesInDir(Path(std::string(path)), listing, filter); return true; } @@ -88,7 +88,7 @@ bool VFS::GetFileListing(const char *path, std::vector *listing, } if (!fileSystemFound) { - ERROR_LOG(IO, "Missing filesystem for %s", path); + ERROR_LOG(Log::IO, "Missing filesystem for %s", path); } // Otherwise, the file was just missing. No need to log. return false; } @@ -96,7 +96,7 @@ bool VFS::GetFileListing(const char *path, std::vector *listing, bool VFS::GetFileInfo(const char *path, File::FileInfo *info) { if (IsLocalAbsolutePath(path)) { // Local path, not VFS. - // INFO_LOG(IO, "Not a VFS path: %s . Getting local file info.", path); + // INFO_LOG(Log::IO, "Not a VFS path: %s . Getting local file info.", path); return File::GetFileInfo(Path(std::string(path)), info); } @@ -114,7 +114,7 @@ bool VFS::GetFileInfo(const char *path, File::FileInfo *info) { } } if (!fileSystemFound) { - ERROR_LOG(IO, "Missing filesystem for '%s'", path); + ERROR_LOG(Log::IO, "Missing filesystem for '%s'", path); } // Otherwise, the file was just missing. No need to log. return false; } diff --git a/Common/File/VFS/ZipFileReader.cpp b/Common/File/VFS/ZipFileReader.cpp index c25b17f680..fa416eef04 100644 --- a/Common/File/VFS/ZipFileReader.cpp +++ b/Common/File/VFS/ZipFileReader.cpp @@ -22,7 +22,7 @@ ZipFileReader *ZipFileReader::Create(const Path &zipFile, const char *inZipPath, int fd = File::OpenFD(zipFile, File::OPEN_READ); if (!fd) { if (logErrors) { - ERROR_LOG(IO, "Failed to open FD for '%s' as zip file", zipFile.c_str()); + ERROR_LOG(Log::IO, "Failed to open FD for '%s' as zip file", zipFile.c_str()); } return nullptr; } @@ -33,7 +33,7 @@ ZipFileReader *ZipFileReader::Create(const Path &zipFile, const char *inZipPath, if (!zip_file) { if (logErrors) { - ERROR_LOG(IO, "Failed to open %s as a zip file", zipFile.c_str()); + ERROR_LOG(Log::IO, "Failed to open %s as a zip file", zipFile.c_str()); } return nullptr; } @@ -61,7 +61,7 @@ uint8_t *ZipFileReader::ReadFile(const char *path, size_t *size) { zip_stat(zip_file_, temp_path.c_str(), ZIP_FL_NOCASE | ZIP_FL_UNCHANGED, &zstat); zip_file *file = zip_fopen(zip_file_, temp_path.c_str(), ZIP_FL_NOCASE | ZIP_FL_UNCHANGED); if (!file) { - ERROR_LOG(IO, "Error opening %s from ZIP", temp_path.c_str()); + ERROR_LOG(Log::IO, "Error opening %s from ZIP", temp_path.c_str()); return 0; } uint8_t *contents = new uint8_t[zstat.size + 1]; @@ -107,7 +107,7 @@ bool ZipFileReader::GetFileListing(const char *orig_path, std::vectorclear(); - // INFO_LOG(SYSTEM, "Zip: Listing '%s'", orig_path); + // INFO_LOG(Log::System, "Zip: Listing '%s'", orig_path); listing->reserve(directories.size() + files.size()); for (auto diter = directories.begin(); diter != directories.end(); ++diter) { @@ -120,7 +120,7 @@ bool ZipFileReader::GetFileListing(const char *orig_path, std::vectorpush_back(info); } @@ -139,7 +139,7 @@ bool ZipFileReader::GetFileListing(const char *orig_path, std::vectorpush_back(info); } @@ -279,7 +279,7 @@ VFSOpenFile *ZipFileReader::OpenFileForRead(VFSFileReference *vfsReference, size openFile->zf = zip_fopen_index(zip_file_, reference->zi, 0); if (!openFile->zf) { - WARN_LOG(G3D, "File with index %d not found in zip", reference->zi); + WARN_LOG(Log::G3D, "File with index %d not found in zip", reference->zi); lock_.unlock(); delete openFile; return nullptr; diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index c9e7f3a291..6ac9b4e593 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -281,6 +281,8 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.blendMinMaxSupported = true; caps_.multiSampleLevelsMask = 1; // More could be supported with some work. + caps_.provokingVertexLast = false; // D3D has it first, unfortunately. (and no way to change it). + caps_.presentInstantModeChange = true; caps_.presentMaxInterval = 4; caps_.presentModesSupported = PresentMode::FIFO | PresentMode::IMMEDIATE; @@ -1036,7 +1038,7 @@ void D3D11DrawContext::UpdateTextureLevels(Texture *texture, const uint8_t **dat ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) { if (language != ShaderLanguage::HLSL_D3D11) { - ERROR_LOG(G3D, "Unsupported shader language"); + ERROR_LOG(Log::G3D, "Unsupported shader language"); return nullptr; } @@ -1079,7 +1081,7 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang } if (errorMsgs) { errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); - ERROR_LOG(G3D, "Failed compiling %s:\n%s\n%s", tag, data, errors.c_str()); + ERROR_LOG(Log::G3D, "Failed compiling %s:\n%s\n%s", tag, data, errors.c_str()); errorMsgs->Release(); } @@ -1104,7 +1106,7 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang result = device_->CreateGeometryShader(data, dataSize, nullptr, &module->gs); break; default: - ERROR_LOG(G3D, "Unsupported shader stage"); + ERROR_LOG(Log::G3D, "Unsupported shader stage"); result = S_FALSE; break; } @@ -1484,7 +1486,7 @@ Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) { depthViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; hr = device_->CreateShaderResourceView(fb->depthStencilTex, &depthViewDesc, &fb->depthSRView); if (FAILED(hr)) { - WARN_LOG(G3D, "Failed to create SRV for depth buffer."); + WARN_LOG(Log::G3D, "Failed to create SRV for depth buffer."); fb->depthSRView = nullptr; } } diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 3773a4e288..97f0919e16 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -375,7 +375,7 @@ bool D3D9Texture::Create(const TextureDesc &desc) { break; } if (FAILED(hr)) { - ERROR_LOG(G3D, "D3D9 Texture creation failed"); + ERROR_LOG(Log::G3D, "D3D9 Texture creation failed"); return false; } @@ -486,7 +486,7 @@ void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int d } default: - ERROR_LOG(G3D, "Non-LINEAR2D textures not yet supported"); + ERROR_LOG(Log::G3D, "Non-LINEAR2D textures not yet supported"); break; } } @@ -733,7 +733,7 @@ static NVIDIAGeneration NVIDIAGetDeviceGeneration(int deviceID) { D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx) : d3d_(d3d), d3dEx_(d3dEx), device_(device), deviceEx_(deviceEx), adapterId_(adapterId), caps_{} { if (FAILED(d3d->GetAdapterIdentifier(adapterId, 0, &identifier_))) { - ERROR_LOG(G3D, "Failed to get adapter identifier: %d", adapterId); + ERROR_LOG(Log::G3D, "Failed to get adapter identifier: %d", adapterId); } switch (identifier_.VendorId) { case 0x10DE: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break; @@ -758,7 +758,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID if (SUCCEEDED(result)) { snprintf(shadeLangVersion_, sizeof(shadeLangVersion_), "PS: %04x VS: %04x", d3dCaps_.PixelShaderVersion & 0xFFFF, d3dCaps_.VertexShaderVersion & 0xFFFF); } else { - WARN_LOG(G3D, "Direct3D9: Failed to get the device caps!"); + WARN_LOG(Log::G3D, "Direct3D9: Failed to get the device caps!"); truncate_cpy(shadeLangVersion_, "N/A"); } @@ -786,6 +786,8 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.presentMaxInterval = 1; caps_.presentModesSupported = PresentMode::FIFO; + caps_.provokingVertexLast = false; // D3D has it first, unfortunately (and no way to change it). + if ((caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && caps.MaxAnisotropy > 1) { caps_.anisoSupported = true; } @@ -846,13 +848,13 @@ ShaderModule *D3D9Context::CreateShaderModule(ShaderStage stage, ShaderLanguage Pipeline *D3D9Context::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) { if (!desc.shaders.size()) { - ERROR_LOG(G3D, "Pipeline %s requires at least one shader", tag); + ERROR_LOG(Log::G3D, "Pipeline %s requires at least one shader", tag); return NULL; } D3D9Pipeline *pipeline = new D3D9Pipeline(); for (auto iter : desc.shaders) { if (!iter) { - ERROR_LOG(G3D, "NULL shader passed to CreateGraphicsPipeline(%s)", tag); + ERROR_LOG(Log::G3D, "NULL shader passed to CreateGraphicsPipeline(%s)", tag); delete pipeline; return NULL; } @@ -1041,7 +1043,7 @@ D3D9InputLayout::D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc HRESULT hr = device->CreateVertexDeclaration(elements, &decl_); if (FAILED(hr)) { - ERROR_LOG(G3D, "Error creating vertex decl"); + ERROR_LOG(Log::G3D, "Error creating vertex decl"); } delete[] elements; } @@ -1119,7 +1121,7 @@ void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offse if (!size) return; if (offset + size > buf->maxSize_) { - ERROR_LOG(G3D, "Can't SubData with bigger size than buffer was created with"); + ERROR_LOG(Log::G3D, "Can't SubData with bigger size than buffer was created with"); return; } if (buf->vbuffer_) { @@ -1253,8 +1255,8 @@ bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, si error = "D3D9 shader compiler not installed"; } - ERROR_LOG(G3D, "Compile error: %s", error); - ERROR_LOG(G3D, "%s", LineNumberString(std::string((const char *)data)).c_str()); + ERROR_LOG(Log::G3D, "Compile error: %s", error); + ERROR_LOG(Log::G3D, "%s", LineNumberString(std::string((const char *)data)).c_str()); OutputDebugStringA(source); OutputDebugStringA(error); @@ -1307,7 +1309,7 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { HRESULT rtResult = device_->CreateTexture(desc.width, desc.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &fbo->tex, nullptr); if (FAILED(rtResult)) { - ERROR_LOG(G3D, "Failed to create render target"); + ERROR_LOG(Log::G3D, "Failed to create render target"); fbo->Release(); return NULL; } @@ -1323,7 +1325,7 @@ Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) { dsResult = device_->CreateDepthStencilSurface(desc.width, desc.height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &fbo->depthstencil, NULL); } if (FAILED(dsResult)) { - ERROR_LOG(G3D, "Failed to create depth buffer"); + ERROR_LOG(Log::G3D, "Failed to create depth buffer"); fbo->surf->Release(); fbo->tex->Release(); if (fbo->depthstenciltex) { @@ -1595,7 +1597,7 @@ void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, voi DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx) { bool result = LoadD3DCompilerDynamic(); if (!result) { - ERROR_LOG(G3D, "Failed to load D3DCompiler!"); + ERROR_LOG(Log::G3D, "Failed to load D3DCompiler!"); return nullptr; } return new D3D9Context(d3d, d3dEx, adapterId, device, deviceEx); diff --git a/Common/GPU/OpenGL/GLDebugLog.cpp b/Common/GPU/OpenGL/GLDebugLog.cpp index 94b79dabc0..7a76ffeb75 100644 --- a/Common/GPU/OpenGL/GLDebugLog.cpp +++ b/Common/GPU/OpenGL/GLDebugLog.cpp @@ -37,7 +37,7 @@ std::string GLEnumToString(uint16_t value) { bool CheckGLError(const char *file, int line) { GLenum err = glGetError(); if (err != GL_NO_ERROR) { - ERROR_LOG(G3D, "GL error %s on %s:%d", GLEnumToString(err).c_str(), file, line); + ERROR_LOG(Log::G3D, "GL error %s on %s:%d", GLEnumToString(err).c_str(), file, line); return false; } return true; diff --git a/Common/GPU/OpenGL/GLFeatures.cpp b/Common/GPU/OpenGL/GLFeatures.cpp index 6b3ce749af..32e1aba67d 100644 --- a/Common/GPU/OpenGL/GLFeatures.cpp +++ b/Common/GPU/OpenGL/GLFeatures.cpp @@ -105,7 +105,7 @@ int GLExtensions::GLSLVersion() { void ProcessGPUFeatures() { gl_extensions.bugs = 0; - DEBUG_LOG(G3D, "Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model); + DEBUG_LOG(Log::G3D, "Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model); if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { if (!strcmp(gl_extensions.model, "PowerVR SGX 545") || @@ -115,11 +115,11 @@ void ProcessGPUFeatures() { !strcmp(gl_extensions.model, "PowerVR SGX 540") || !strcmp(gl_extensions.model, "PowerVR SGX 530") || !strcmp(gl_extensions.model, "PowerVR SGX 520") ) { - WARN_LOG(G3D, "GL DRIVER BUG: PVR with bad and terrible precision"); + WARN_LOG(Log::G3D, "GL DRIVER BUG: PVR with bad and terrible precision"); gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_TERRIBLE | BUG_PVR_SHADER_PRECISION_BAD; } else { // TODO: I'm not sure if the Rogue series is affected by this. - WARN_LOG(G3D, "GL DRIVER BUG: PVR with bad precision"); + WARN_LOG(Log::G3D, "GL DRIVER BUG: PVR with bad precision"); gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_BAD; } } @@ -193,14 +193,14 @@ bool CheckGLExtensions() { } else if (vendor == "Apple Inc." || vendor == "Apple") { gl_extensions.gpuVendor = GPU_VENDOR_APPLE; } else { - WARN_LOG(G3D, "Unknown GL vendor: '%s'", vendor.c_str()); + WARN_LOG(Log::G3D, "Unknown GL vendor: '%s'", vendor.c_str()); gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN; } } else { gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN; } - INFO_LOG(G3D, "GPU Vendor : %s ; renderer: %s version str: %s ; GLSL version str: %s", cvendor ? cvendor : "N/A", renderer, versionStr ? versionStr : "N/A", glslVersionStr ? glslVersionStr : "N/A"); + INFO_LOG(Log::G3D, "GPU Vendor : %s ; renderer: %s version str: %s ; GLSL version str: %s", cvendor ? cvendor : "N/A", renderer, versionStr ? versionStr : "N/A", glslVersionStr ? glslVersionStr : "N/A"); strncpy(gl_extensions.model, renderer, sizeof(gl_extensions.model)); gl_extensions.model[sizeof(gl_extensions.model) - 1] = 0; @@ -263,7 +263,7 @@ bool CheckGLExtensions() { gl_extensions.ver[1] = 0; } else if (parsed[0] && (gl_extensions.ver[0] != parsed[0] || gl_extensions.ver[1] != parsed[1])) { // Something going wrong. Possible bug in GL ES drivers. See #9688 - INFO_LOG(G3D, "GL ES version mismatch. Version string '%s' parsed as %d.%d but API return %d.%d. Fallback to GL ES 2.0.", + INFO_LOG(Log::G3D, "GL ES version mismatch. Version string '%s' parsed as %d.%d but API return %d.%d. Fallback to GL ES 2.0.", versionStr ? versionStr : "N/A", parsed[0], parsed[1], gl_extensions.ver[0], gl_extensions.ver[1]); gl_extensions.ver[0] = 2; @@ -287,7 +287,7 @@ bool CheckGLExtensions() { gl_extensions.GLES3 = true; // Though, let's ban Mali from the GLES 3 path for now, see #4078 if (strstr(renderer, "Mali") != 0) { - INFO_LOG(G3D, "Forcing GLES3 off for Mali driver version: %s\n", versionStr ? versionStr : "N/A"); + INFO_LOG(Log::G3D, "Forcing GLES3 off for Mali driver version: %s\n", versionStr ? versionStr : "N/A"); gl_extensions.GLES3 = false; } } else { @@ -308,9 +308,9 @@ bool CheckGLExtensions() { if (gl_extensions.GLES3) { if (gl_extensions.ver[1] >= 1) { - INFO_LOG(G3D, "OpenGL ES 3.1 support detected!\n"); + INFO_LOG(Log::G3D, "OpenGL ES 3.1 support detected!\n"); } else { - INFO_LOG(G3D, "OpenGL ES 3.0 support detected!\n"); + INFO_LOG(Log::G3D, "OpenGL ES 3.0 support detected!\n"); } } } @@ -404,7 +404,7 @@ bool CheckGLExtensions() { #ifdef _DEBUG void *invalidAddress = (void *)eglGetProcAddress("InvalidGlCall1"); void *invalidAddress2 = (void *)eglGetProcAddress("AnotherInvalidGlCall2"); - DEBUG_LOG(G3D, "Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2); + DEBUG_LOG(Log::G3D, "Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2); #endif // These are all the same. Let's alias. @@ -505,7 +505,7 @@ bool CheckGLExtensions() { // The model number comparison should probably be 400 or 500. This causes us to avoid depal-in-shader. // It seems though that this caused large perf regressions on Adreno 5xx, so I've bumped it up to 600. if (gl_extensions.gpuVendor == GPU_VENDOR_QUALCOMM && gl_extensions.modelNumber < 600) { - WARN_LOG(G3D, "Detected old Adreno - lowering reported int precision for safety"); + WARN_LOG(Log::G3D, "Detected old Adreno - lowering reported int precision for safety"); gl_extensions.range[1][5][0] = 15; gl_extensions.range[1][5][1] = 15; } @@ -615,7 +615,7 @@ bool CheckGLExtensions() { int error = glGetError(); if (error) - ERROR_LOG(G3D, "GL error in init: %i", error); + ERROR_LOG(Log::G3D, "GL error in init: %i", error); #endif return true; diff --git a/Common/GPU/OpenGL/GLMemory.cpp b/Common/GPU/OpenGL/GLMemory.cpp index 4da0d9bba2..6718bd23eb 100644 --- a/Common/GPU/OpenGL/GLMemory.cpp +++ b/Common/GPU/OpenGL/GLMemory.cpp @@ -137,7 +137,7 @@ void GLPushBuffer::Flush() { } void GLPushBuffer::AddBuffer() { - // INFO_LOG(G3D, "GLPushBuffer(%s): Allocating %d bytes", tag_, size_); + // INFO_LOG(Log::G3D, "GLPushBuffer(%s): Allocating %d bytes", tag_, size_); BufInfo info; info.localMemory = (uint8_t *)AllocateAlignedMemory(size_, 16); _assert_msg_(info.localMemory != 0, "GLPushBuffer alloc fail: %d (%s)", (int)size_, tag_); diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index c4b5533b3d..36a391302f 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -107,19 +107,6 @@ static std::string GetInfoLog(GLuint name, Getiv getiv, GetLog getLog) { return infoLog; } -static int GetStereoBufferIndex(const char *uniformName) { - if (!uniformName) return -1; - else if (strcmp(uniformName, "u_view") == 0) return 0; - else if (strcmp(uniformName, "u_proj_lens") == 0) return 1; - else return -1; -} - -static std::string GetStereoBufferLayout(const char *uniformName) { - if (strcmp(uniformName, "u_view") == 0) return "ViewMatrices"; - else if (strcmp(uniformName, "u_proj_lens") == 0) return "ProjectionMatrix"; - else return "undefined"; -} - void GLQueueRunner::RunInitSteps(const FastVec &steps, bool skipGLCalls) { if (skipGLCalls) { // Some bookkeeping still needs to be done. @@ -143,12 +130,12 @@ void GLQueueRunner::RunInitSteps(const FastVec &steps, bool skipGLC } case GLRInitStepType::CREATE_PROGRAM: { - WARN_LOG(G3D, "CREATE_PROGRAM found with skipGLCalls, not good"); + WARN_LOG(Log::G3D, "CREATE_PROGRAM found with skipGLCalls, not good"); break; } case GLRInitStepType::CREATE_SHADER: { - WARN_LOG(G3D, "CREATE_SHADER found with skipGLCalls, not good"); + WARN_LOG(Log::G3D, "CREATE_SHADER found with skipGLCalls, not good"); break; } default: @@ -250,11 +237,11 @@ void GLQueueRunner::RunInitSteps(const FastVec &steps, bool skipGLC if (!anyFailed) Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", infoLog.c_str(), fsDesc.c_str(), fsCode, vsDesc.c_str(), vsCode); - ERROR_LOG(G3D, "Could not link program:\n %s", infoLog.c_str()); - ERROR_LOG(G3D, "VS desc:\n%s", vsDesc.c_str()); - ERROR_LOG(G3D, "FS desc:\n%s", fsDesc.c_str()); - ERROR_LOG(G3D, "VS:\n%s\n", LineNumberString(vsCode).c_str()); - ERROR_LOG(G3D, "FS:\n%s\n", LineNumberString(fsCode).c_str()); + ERROR_LOG(Log::G3D, "Could not link program:\n %s", infoLog.c_str()); + ERROR_LOG(Log::G3D, "VS desc:\n%s", vsDesc.c_str()); + ERROR_LOG(Log::G3D, "FS desc:\n%s", fsDesc.c_str()); + ERROR_LOG(Log::G3D, "VS:\n%s\n", LineNumberString(vsCode).c_str()); + ERROR_LOG(Log::G3D, "FS:\n%s\n", LineNumberString(fsCode).c_str()); #ifdef _WIN32 OutputDebugStringUTF8(infoLog.c_str()); @@ -274,28 +261,10 @@ void GLQueueRunner::RunInitSteps(const FastVec &steps, bool skipGLC auto &query = program->queries_[j]; _dbg_assert_(query.name); - int location = -1; - if (IsVREnabled() && IsMultiviewSupported()) { - int index = GetStereoBufferIndex(query.name); - if (index >= 0) { - std::string layout = GetStereoBufferLayout(query.name); - glUniformBlockBinding(program->program, glGetUniformBlockIndex(program->program, layout.c_str()), index); - - GLuint buffer = 0; - glGenBuffers(1, &buffer); - glBindBuffer(GL_UNIFORM_BUFFER, buffer); - glBufferData(GL_UNIFORM_BUFFER,2 * 16 * sizeof(float),NULL, GL_STATIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - location = buffer; - } else { - location = glGetUniformLocation(program->program, query.name); - } - } else { - location = glGetUniformLocation(program->program, query.name); - } + int location = glGetUniformLocation(program->program, query.name); if (location < 0 && query.required) { - WARN_LOG(G3D, "Required uniform query for '%s' failed", query.name); + WARN_LOG(Log::G3D, "Required uniform query for '%s' failed", query.name); } *query.dest = location; } @@ -337,7 +306,7 @@ void GLQueueRunner::RunInitSteps(const FastVec &steps, bool skipGLC std::vector lines; SplitString(errorString, '\n', lines); for (auto line : lines) { - ERROR_LOG(G3D, "%.*s", (int)line.size(), line.data()); + ERROR_LOG(Log::G3D, "%.*s", (int)line.size(), line.data()); } if (errorCallback_) { std::string desc = StringFromFormat("Shader compilation failed: %s", step.create_shader.stage == GL_VERTEX_SHADER ? "vertex" : "fragment"); @@ -462,12 +431,12 @@ void GLQueueRunner::RunInitSteps(const FastVec &steps, bool skipGLC // Calling glGetError() isn't great, but at the end of init, only after creating textures, shouldn't be too bad... GLenum err = glGetError(); if (err == GL_OUT_OF_MEMORY) { - WARN_LOG_REPORT(G3D, "GL ran out of GPU memory; switching to low memory mode"); + WARN_LOG_REPORT(Log::G3D, "GL ran out of GPU memory; switching to low memory mode"); sawOutOfMemory_ = true; } else if (err != GL_NO_ERROR) { // We checked the err anyway, might as well log if there is one. std::string errorString = GLEnumToString(err); - WARN_LOG(G3D, "Got an error after init: %08x (%s)", err, errorString.c_str()); + WARN_LOG(Log::G3D, "Got an error after init: %08x (%s)", err, errorString.c_str()); if (errorCallback_) { errorCallback_("GL frame init error", errorString.c_str(), errorCallbackUserData_); } @@ -525,7 +494,7 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { retry_depth: if (!fbo->z_stencil_) { - INFO_LOG(G3D, "Creating %d x %d FBO using no depth", fbo->width, fbo->height); + INFO_LOG(Log::G3D, "Creating %d x %d FBO using no depth", fbo->width, fbo->height); fbo->z_stencil_buffer = 0; fbo->stencil_buffer = 0; @@ -538,7 +507,7 @@ retry_depth: glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); } else if (gl_extensions.IsGLES) { if (gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3)) { - INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); + INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); fbo->z_stencil_buffer = 0; fbo->stencil_buffer = 0; fbo->z_buffer = 0; @@ -559,7 +528,7 @@ retry_depth: glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); } } else if (gl_extensions.OES_packed_depth_stencil) { - INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8", fbo->width, fbo->height); + INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8", fbo->width, fbo->height); // Standard method fbo->stencil_buffer = 0; fbo->z_buffer = 0; @@ -574,7 +543,7 @@ retry_depth: glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer); } else { - INFO_LOG(G3D, "Creating %d x %d FBO using separate stencil", fbo->width, fbo->height); + INFO_LOG(Log::G3D, "Creating %d x %d FBO using separate stencil", fbo->width, fbo->height); // TEGRA fbo->z_stencil_buffer = 0; // 16/24-bit Z, separate 8-bit stencil @@ -595,7 +564,7 @@ retry_depth: glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer); } } else if (gl_extensions.VersionGEThan(3, 0)) { - INFO_LOG(G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); + INFO_LOG(Log::G3D, "Creating %d x %d FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); fbo->z_stencil_buffer = 0; fbo->stencil_buffer = 0; fbo->z_buffer = 0; @@ -631,13 +600,13 @@ retry_depth: switch (status) { case GL_FRAMEBUFFER_COMPLETE: - // INFO_LOG(G3D, "Framebuffer verified complete."); + // INFO_LOG(Log::G3D, "Framebuffer verified complete."); break; case GL_FRAMEBUFFER_UNSUPPORTED: - ERROR_LOG(G3D, "GL_FRAMEBUFFER_UNSUPPORTED"); + ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_UNSUPPORTED"); break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - ERROR_LOG(G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); break; default: _assert_msg_(false, "Other framebuffer error: %d", status); @@ -778,7 +747,7 @@ void GLQueueRunner::PerformBlit(const GLRStep &step) { CHECK_GL_ERROR_IF_DEBUG(); #endif // defined(USING_GLES2) && defined(__ANDROID__) } else { - ERROR_LOG(G3D, "GLQueueRunner: Tried to blit without the capability"); + ERROR_LOG(Log::G3D, "GLQueueRunner: Tried to blit without the capability"); } } @@ -1119,36 +1088,22 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last case GLRRenderCommand::UNIFORMSTEREOMATRIX: { _dbg_assert_(curProgram); - if (IsMultiviewSupported()) { - int layout = GetStereoBufferIndex(c.uniformStereoMatrix4.name); - if (layout >= 0) { - int size = 2 * 16 * sizeof(float); - glBindBufferBase(GL_UNIFORM_BUFFER, layout, *c.uniformStereoMatrix4.loc); - glBindBuffer(GL_UNIFORM_BUFFER, *c.uniformStereoMatrix4.loc); - void *matrices = glMapBufferRange(GL_UNIFORM_BUFFER, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - memcpy(matrices, c.uniformStereoMatrix4.mData, size); - glUnmapBuffer(GL_UNIFORM_BUFFER); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - } - delete[] c.uniformStereoMatrix4.mData; // We only playback once. - } else { - int loc = c.uniformStereoMatrix4.loc ? *c.uniformStereoMatrix4.loc : -1; - if (c.uniformStereoMatrix4.name) { - loc = curProgram->GetUniformLoc(c.uniformStereoMatrix4.name); - } - if (loc >= 0) { - if (GetVRFBOIndex() == 0) { - glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData); - } else { - glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData + 16); - } - } - if (GetVRFBOIndex() == 1 || GetVRPassesCount() == 1) { - // Only delete the data if we're rendering the only or the second eye. - // If we delete during the first eye, we get a use-after-free or double delete. - delete[] c.uniformStereoMatrix4.mData; + int loc = c.uniformStereoMatrix4.loc ? *c.uniformStereoMatrix4.loc : -1; + if (c.uniformStereoMatrix4.name) { + loc = curProgram->GetUniformLoc(c.uniformStereoMatrix4.name); + } + if (loc >= 0) { + if (GetVRFBOIndex() == 0) { + glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData); + } else { + glUniformMatrix4fv(loc, 1, false, c.uniformStereoMatrix4.mData + 16); } } + if (GetVRFBOIndex() == 1 || GetVRPassesCount() == 1) { + // Only delete the data if we're rendering the only or the second eye. + // If we delete during the first eye, we get a use-after-free or double delete. + delete[] c.uniformStereoMatrix4.mData; + } CHECK_GL_ERROR_IF_DEBUG(); break; } @@ -1739,13 +1694,13 @@ void GLQueueRunner::fbo_ext_create(const GLRInitStep &step) { GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch (status) { case GL_FRAMEBUFFER_COMPLETE_EXT: - // INFO_LOG(G3D, "Framebuffer verified complete."); + // INFO_LOG(Log::G3D, "Framebuffer verified complete."); break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - ERROR_LOG(G3D, "GL_FRAMEBUFFER_UNSUPPORTED"); + ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_UNSUPPORTED"); break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - ERROR_LOG(G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT "); + ERROR_LOG(Log::G3D, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT "); break; default: _assert_msg_(false, "Other framebuffer error: %d", status); diff --git a/Common/GPU/OpenGL/GLQueueRunner.h b/Common/GPU/OpenGL/GLQueueRunner.h index df86b9565f..87d9a76be6 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.h +++ b/Common/GPU/OpenGL/GLQueueRunner.h @@ -298,7 +298,7 @@ enum GLRAspect { const char *GLRAspectToString(GLRAspect aspect); struct GLRStep { - GLRStep(GLRStepType _type) : stepType(_type) {} + GLRStep(GLRStepType _type) : stepType(_type), tag() {} GLRStepType stepType; FastVec commands; TinySet dependencies; diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index 575289707b..18d93a0f4f 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -12,7 +12,7 @@ #include "Common/Math/math_util.h" #if 0 // def _DEBUG -#define VLOG(...) INFO_LOG(G3D, __VA_ARGS__) +#define VLOG(...) INFO_LOG(Log::G3D, __VA_ARGS__) #else #define VLOG(...) #endif @@ -59,7 +59,7 @@ void GLRenderManager::ThreadStart(Draw::DrawContext *draw) { renderThreadId = std::this_thread::get_id(); if (newInflightFrames_ != -1) { - INFO_LOG(G3D, "Updating inflight frames to %d", newInflightFrames_); + INFO_LOG(Log::G3D, "Updating inflight frames to %d", newInflightFrames_); inflightFrames_ = newInflightFrames_; newInflightFrames_ = -1; } @@ -99,7 +99,7 @@ void GLRenderManager::ThreadStart(Draw::DrawContext *draw) { } void GLRenderManager::ThreadEnd() { - INFO_LOG(G3D, "ThreadEnd"); + INFO_LOG(Log::G3D, "ThreadEnd"); queueRunner_.DestroyDeviceObjects(); VLOG(" PULL: Quitting"); @@ -171,7 +171,7 @@ bool GLRenderManager::ThreadFrame() { void GLRenderManager::StopThread() { // There's not really a lot to do here anymore. - INFO_LOG(G3D, "GLRenderManager::StopThread()"); + INFO_LOG(Log::G3D, "GLRenderManager::StopThread()"); if (runCompileThread_) { runCompileThread_ = false; @@ -179,7 +179,17 @@ void GLRenderManager::StopThread() { renderThreadQueue_.push(new GLRRenderThreadTask(GLRRunType::EXIT)); pushCondVar_.notify_one(); } else { - WARN_LOG(G3D, "GL submission thread was already paused."); + WARN_LOG(Log::G3D, "GL submission thread was already paused."); + } +} + +void GLRenderManager::StartThread() { + // There's not really a lot to do here anymore. + INFO_LOG(Log::G3D, "GLRenderManager::StartThread()"); + if (!runCompileThread_) { + runCompileThread_ = true; + } else { + INFO_LOG(Log::G3D, "GL submission thread was already running."); } } @@ -348,6 +358,9 @@ void GLRenderManager::BeginFrame(bool enableProfiling) { curProgram_ = nullptr; #endif + // Shouldn't call BeginFrame unless we're in a run state. + _dbg_assert_(runCompileThread_); + int curFrame = GetCurFrame(); FrameTimeData &frameTimeData = frameTimeHistory_.Add(frameIdGen_); @@ -368,10 +381,6 @@ void GLRenderManager::BeginFrame(bool enableProfiling) { frameData.readyForFence = false; } - if (!runCompileThread_) { - WARN_LOG(G3D, "BeginFrame while !run_!"); - } - insideFrame_ = true; } diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index b3230da67f..558fd37879 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -421,7 +421,6 @@ public: // an init command, that's for sure. GLRInitStep &step = initSteps_.push_uninitialized(); step.stepType = GLRInitStepType::BUFFER_SUBDATA; - _dbg_assert_(offset >= 0); _dbg_assert_(offset <= buffer->size_ - size); step.buffer_subdata.buffer = buffer; step.buffer_subdata.offset = (int)offset; @@ -835,6 +834,7 @@ public: } } + void StartThread(); // Currently only used on iOS, since we fully recreate the context on Android void StopThread(); bool SawOutOfMemory() { @@ -874,6 +874,7 @@ private: FastVec initSteps_; // Execution time state + // TODO: Rename this, as we don't actually use a compile thread on OpenGL. bool runCompileThread_ = true; // Thread is managed elsewhere, and should call ThreadFrame. diff --git a/Common/GPU/OpenGL/GLSLProgram.cpp b/Common/GPU/OpenGL/GLSLProgram.cpp index fc5698085e..ef71731323 100644 --- a/Common/GPU/OpenGL/GLSLProgram.cpp +++ b/Common/GPU/OpenGL/GLSLProgram.cpp @@ -23,9 +23,9 @@ bool CompileShader(const char *source, GLuint shader, const char *filename, std: GLsizei len; glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog); infoLog[len] = '\0'; - ERROR_LOG(G3D, "Error in shader compilation of %s!\n", filename); - ERROR_LOG(G3D, "Info log: %s\n", infoLog); - ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)source); + ERROR_LOG(Log::G3D, "Error in shader compilation of %s!\n", filename); + ERROR_LOG(Log::G3D, "Info log: %s\n", infoLog); + ERROR_LOG(Log::G3D, "Shader source:\n%s\n", (const char *)source); if (error_message) *error_message = infoLog; return false; @@ -46,7 +46,7 @@ GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src if (glsl_recompile(program, error_message)) { active_programs.insert(program); } else { - ERROR_LOG(G3D, "Failed compiling GLSL program from source strings"); + ERROR_LOG(Log::G3D, "Failed compiling GLSL program from source strings"); delete program; return 0; } @@ -105,7 +105,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { vsh_src.reset((char *)g_VFS.ReadFile(program->vshader_filename, &sz)); } if (!program->vshader_source && !vsh_src) { - ERROR_LOG(G3D, "File missing: %s", program->vshader_filename); + ERROR_LOG(Log::G3D, "File missing: %s", program->vshader_filename); if (error_message) { *error_message = std::string("File missing: ") + program->vshader_filename; } @@ -116,7 +116,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { fsh_src.reset((char *)g_VFS.ReadFile(program->fshader_filename, &sz)); } if (!program->fshader_source && !fsh_src) { - ERROR_LOG(G3D, "File missing: %s", program->fshader_filename); + ERROR_LOG(Log::G3D, "File missing: %s", program->fshader_filename); if (error_message) { *error_message = std::string("File missing: ") + program->fshader_filename; } @@ -150,15 +150,15 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { if (bufLength) { char* buf = new char[bufLength + 1]; // safety glGetProgramInfoLog(prog, bufLength, NULL, buf); - INFO_LOG(G3D, "vsh: %i fsh: %i", vsh, fsh); - ERROR_LOG(G3D, "Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf); + INFO_LOG(Log::G3D, "vsh: %i fsh: %i", vsh, fsh); + ERROR_LOG(Log::G3D, "Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf); if (error_message) { *error_message = buf; } delete [] buf; } else { - INFO_LOG(G3D, "vsh: %i fsh: %i", vsh, fsh); - ERROR_LOG(G3D, "Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus); + INFO_LOG(Log::G3D, "vsh: %i fsh: %i", vsh, fsh); + ERROR_LOG(Log::G3D, "Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus); if (error_message) { *error_message = "(no error message available)"; } @@ -193,7 +193,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { program->u_sundir = glGetUniformLocation(program->program_, "u_sundir"); program->u_camerapos = glGetUniformLocation(program->program_, "u_camerapos"); - //INFO_LOG(G3D, "Shader compilation success: %s %s", + //INFO_LOG(Log::G3D, "Shader compilation success: %s %s", // program->vshader_filename, // program->fshader_filename); return true; @@ -214,7 +214,7 @@ void glsl_destroy(GLSLProgram *program) { glDeleteProgram(program->program_); active_programs.erase(program); } else { - ERROR_LOG(G3D, "Deleting null GLSL program!"); + ERROR_LOG(Log::G3D, "Deleting null GLSL program!"); } delete program; } diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 8752386362..6a0237a012 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -598,6 +598,9 @@ OpenGLContext::OpenGLContext(bool canChangeSwapInterval) : renderManager_(frameT // GLES has no support for logic framebuffer operations. There doesn't even seem to exist any such extensions. caps_.logicOpSupported = !gl_extensions.IsGLES; + // Always the case in GL (which is what we want for PSP flat shade). + caps_.provokingVertexLast = true; + // Interesting potential hack for emulating GL_DEPTH_CLAMP (use a separate varying, force depth in fragment shader): // This will induce a performance penalty on many architectures though so a blanket enable of this // is probably not a good idea. @@ -843,7 +846,7 @@ static GLuint TypeToTarget(TextureType type) { #endif case TextureType::ARRAY2D: return GL_TEXTURE_2D_ARRAY; default: - ERROR_LOG(G3D, "Bad texture type %d", (int)type); + ERROR_LOG(Log::G3D, "Bad texture type %d", (int)type); return GL_NONE; } } @@ -998,30 +1001,30 @@ static void LogReadPixelsError(GLenum error) { case GL_NO_ERROR: break; case GL_INVALID_ENUM: - ERROR_LOG(G3D, "glReadPixels: GL_INVALID_ENUM"); + ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_ENUM"); break; case GL_INVALID_VALUE: - ERROR_LOG(G3D, "glReadPixels: GL_INVALID_VALUE"); + ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_VALUE"); break; case GL_INVALID_OPERATION: - ERROR_LOG(G3D, "glReadPixels: GL_INVALID_OPERATION"); + ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_OPERATION"); break; case GL_INVALID_FRAMEBUFFER_OPERATION: - ERROR_LOG(G3D, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION"); + ERROR_LOG(Log::G3D, "glReadPixels: GL_INVALID_FRAMEBUFFER_OPERATION"); break; case GL_OUT_OF_MEMORY: - ERROR_LOG(G3D, "glReadPixels: GL_OUT_OF_MEMORY"); + ERROR_LOG(Log::G3D, "glReadPixels: GL_OUT_OF_MEMORY"); break; #ifndef USING_GLES2 case GL_STACK_UNDERFLOW: - ERROR_LOG(G3D, "glReadPixels: GL_STACK_UNDERFLOW"); + ERROR_LOG(Log::G3D, "glReadPixels: GL_STACK_UNDERFLOW"); break; case GL_STACK_OVERFLOW: - ERROR_LOG(G3D, "glReadPixels: GL_STACK_OVERFLOW"); + ERROR_LOG(Log::G3D, "glReadPixels: GL_STACK_OVERFLOW"); break; #endif default: - ERROR_LOG(G3D, "glReadPixels: %08x", error); + ERROR_LOG(Log::G3D, "glReadPixels: %08x", error); break; } } @@ -1166,15 +1169,15 @@ void OpenGLContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t off Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) { if (!desc.shaders.size()) { - ERROR_LOG(G3D, "Pipeline requires at least one shader"); + ERROR_LOG(Log::G3D, "Pipeline requires at least one shader"); return nullptr; } if ((uint32_t)desc.prim >= (uint32_t)Primitive::PRIMITIVE_TYPE_COUNT) { - ERROR_LOG(G3D, "Invalid primitive type"); + ERROR_LOG(Log::G3D, "Invalid primitive type"); return nullptr; } if (!desc.depthStencil || !desc.blend || !desc.raster) { - ERROR_LOG(G3D, "Incomplete prim desciption"); + ERROR_LOG(Log::G3D, "Incomplete prim desciption"); return nullptr; } @@ -1184,7 +1187,7 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const iter->AddRef(); pipeline->shaders.push_back(static_cast(iter)); } else { - ERROR_LOG(G3D, "ERROR: Tried to create graphics pipeline %s with a null shader module", tag ? tag : "no tag"); + ERROR_LOG(Log::G3D, "ERROR: Tried to create graphics pipeline %s with a null shader module", tag ? tag : "no tag"); delete pipeline; return nullptr; } @@ -1205,7 +1208,7 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const pipeline->inputLayout = (OpenGLInputLayout *)desc.inputLayout; return pipeline; } else { - ERROR_LOG(G3D, "Failed to create pipeline %s - shaders failed to link", tag ? tag : "no tag"); + ERROR_LOG(Log::G3D, "Failed to create pipeline %s - shaders failed to link", tag ? tag : "no tag"); delete pipeline; return nullptr; } @@ -1274,11 +1277,11 @@ bool OpenGLPipeline::LinkShaders(const PipelineDesc &desc) { if (shader) { linkShaders.push_back(shader); } else { - ERROR_LOG(G3D, "LinkShaders: Bad shader module"); + ERROR_LOG(Log::G3D, "LinkShaders: Bad shader module"); return false; } } else { - ERROR_LOG(G3D, "LinkShaders: Bad shader in module"); + ERROR_LOG(Log::G3D, "LinkShaders: Bad shader in module"); return false; } } @@ -1462,7 +1465,7 @@ void OpenGLInputLayout::Compile(const InputLayoutDesc &desc) { break; case DataFormat::UNDEFINED: default: - ERROR_LOG(G3D, "Thin3DGLVertexFormat: Invalid or unknown component type applied."); + ERROR_LOG(Log::G3D, "Thin3DGLVertexFormat: Invalid or unknown component type applied."); break; } diff --git a/Common/GPU/ShaderTranslation.cpp b/Common/GPU/ShaderTranslation.cpp index dc15433742..ad8c1ee76b 100644 --- a/Common/GPU/ShaderTranslation.cpp +++ b/Common/GPU/ShaderTranslation.cpp @@ -203,7 +203,7 @@ bool ConvertToVulkanGLSL(std::string *dest, TranslatedShaderMetadata *destMetada } // DUMPLOG(src.c_str()); - // INFO_LOG(SYSTEM, "---->"); + // INFO_LOG(Log::System, "---->"); // DUMPLOG(LineNumberString(out.str()).c_str()); *dest = out.str(); diff --git a/Common/GPU/Vulkan/VulkanBarrier.cpp b/Common/GPU/Vulkan/VulkanBarrier.cpp index 585fe98c04..d262c400c6 100644 --- a/Common/GPU/Vulkan/VulkanBarrier.cpp +++ b/Common/GPU/Vulkan/VulkanBarrier.cpp @@ -1,13 +1,14 @@ #include "VulkanLoader.h" #include "VulkanContext.h" #include "VulkanBarrier.h" +#include "VulkanFramebuffer.h" #include "Common/Log.h" VulkanBarrierBatch::~VulkanBarrierBatch() { // _dbg_assert_(imageBarriers_.empty()); if (!imageBarriers_.empty()) { - ERROR_LOG(G3D, "~VulkanBarrierBatch: %d barriers remaining", (int)imageBarriers_.size()); + ERROR_LOG(Log::G3D, "~VulkanBarrierBatch: %d barriers remaining", (int)imageBarriers_.size()); } } @@ -50,30 +51,29 @@ void VulkanBarrierBatch::TransitionImage( imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; } -void VulkanBarrierBatch::TransitionImageAuto( - VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, - VkImageLayout oldImageLayout, VkImageLayout newImageLayout) { +void VulkanBarrierBatch::TransitionColorImageAuto( + VkImage image, VkImageLayout *imageLayout, VkImageLayout newImageLayout, int baseMip, int numMipLevels, int numLayers) { _dbg_assert_(image != VK_NULL_HANDLE); - VkAccessFlags srcAccessMask = 0; VkAccessFlags dstAccessMask = 0; - switch (oldImageLayout) { + switch (*imageLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + srcAccessMask = 0; + srcStageMask_ |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + break; case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - // Assert aspect here? - srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; srcStageMask_ |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - // Assert aspect here? - srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - srcStageMask_ |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + case VK_IMAGE_LAYOUT_GENERAL: + // We came from the Mali workaround, and are transitioning back to COLOR_ATTACHMENT_OPTIMAL. + srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + srcStageMask_ |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break; - case VK_IMAGE_LAYOUT_UNDEFINED: - // Actually this seems wrong? - if (aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { - srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - srcStageMask_ |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - } + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + // We only texture from images in the fragment shader, so can do this simply. + srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcStageMask_ |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -84,7 +84,7 @@ void VulkanBarrierBatch::TransitionImageAuto( srcStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT; break; default: - _assert_msg_(false, "Unexpected oldLayout: %d", (int)oldImageLayout); + _assert_msg_(false, "Unexpected oldLayout: %s", VulkanImageLayoutToString(*imageLayout)); break; } @@ -93,8 +93,20 @@ void VulkanBarrierBatch::TransitionImageAuto( dstAccessMask = VK_ACCESS_SHADER_READ_BIT; dstStageMask_ |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + dstStageMask_ |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; default: - _assert_msg_(false, "Unexpected newLayout: %d", (int)newImageLayout); + _assert_msg_(false, "Unexpected newLayout: %s", VulkanImageLayoutToString(newImageLayout)); break; } @@ -103,33 +115,98 @@ void VulkanBarrierBatch::TransitionImageAuto( imageBarrier.pNext = nullptr; imageBarrier.srcAccessMask = srcAccessMask; imageBarrier.dstAccessMask = dstAccessMask; - imageBarrier.oldLayout = oldImageLayout; + imageBarrier.oldLayout = *imageLayout; imageBarrier.newLayout = newImageLayout; imageBarrier.image = image; - imageBarrier.subresourceRange.aspectMask = aspectMask; + imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageBarrier.subresourceRange.baseMipLevel = baseMip; imageBarrier.subresourceRange.levelCount = numMipLevels; imageBarrier.subresourceRange.layerCount = numLayers; // NOTE: We could usually use VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS, but really old Mali drivers have problems with those. imageBarrier.subresourceRange.baseArrayLayer = 0; imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + *imageLayout = newImageLayout; } -void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, - VkImageLayout oldImageLayout, VkImageLayout newImageLayout, - VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, - VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) { - VkImageMemoryBarrier image_memory_barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; - image_memory_barrier.srcAccessMask = srcAccessMask; - image_memory_barrier.dstAccessMask = dstAccessMask; - image_memory_barrier.oldLayout = oldImageLayout; - image_memory_barrier.newLayout = newImageLayout; - image_memory_barrier.image = image; - image_memory_barrier.subresourceRange.aspectMask = aspectMask; - image_memory_barrier.subresourceRange.baseMipLevel = baseMip; - image_memory_barrier.subresourceRange.levelCount = numMipLevels; - image_memory_barrier.subresourceRange.layerCount = numLayers; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. - image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); +void VulkanBarrierBatch::TransitionDepthStencilImageAuto( + VkImage image, VkImageLayout *imageLayout, VkImageLayout newImageLayout, int baseMip, int numMipLevels, int numLayers) { + _dbg_assert_(image != VK_NULL_HANDLE); + + VkAccessFlags srcAccessMask = 0; + VkAccessFlags dstAccessMask = 0; + switch (*imageLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + srcAccessMask = 0; + srcStageMask_ |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + srcStageMask_ |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + // We only texture from images in the fragment shader, so can do this simply. + srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcStageMask_ |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + srcStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + default: + _assert_msg_(false, "Unexpected oldLayout: %s", VulkanImageLayoutToString(*imageLayout)); + break; + } + + switch (newImageLayout) { + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + dstStageMask_ |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + dstStageMask_ |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + break; + default: + _assert_msg_(false, "Unexpected newLayout: %s", VulkanImageLayoutToString(newImageLayout)); + break; + } + + VkImageMemoryBarrier &imageBarrier = imageBarriers_.push_uninitialized(); + imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageBarrier.pNext = nullptr; + imageBarrier.srcAccessMask = srcAccessMask; + imageBarrier.dstAccessMask = dstAccessMask; + imageBarrier.oldLayout = *imageLayout; + imageBarrier.newLayout = newImageLayout; + imageBarrier.image = image; + imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + imageBarrier.subresourceRange.baseMipLevel = baseMip; + imageBarrier.subresourceRange.levelCount = numMipLevels; + imageBarrier.subresourceRange.layerCount = numLayers; // NOTE: We could usually use VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS, but really old Mali drivers have problems with those. + imageBarrier.subresourceRange.baseArrayLayer = 0; + imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + *imageLayout = newImageLayout; +} + +void VulkanBarrierBatch::TransitionColorImageAuto(VKRImage *image, VkImageLayout newImageLayout) { + TransitionColorImageAuto(image->image, &image->layout, newImageLayout, 0, 1, image->numLayers); +} + +void VulkanBarrierBatch::TransitionDepthStencilImageAuto(VKRImage *image, VkImageLayout newImageLayout) { + TransitionDepthStencilImageAuto(image->image, &image->layout, newImageLayout, 0, 1, image->numLayers); } diff --git a/Common/GPU/Vulkan/VulkanBarrier.h b/Common/GPU/Vulkan/VulkanBarrier.h index 60b1ea3fc0..884e0919c7 100644 --- a/Common/GPU/Vulkan/VulkanBarrier.h +++ b/Common/GPU/Vulkan/VulkanBarrier.h @@ -8,6 +8,7 @@ #include "Common/Data/Collections/TinySet.h" class VulkanContext; +struct VKRImage; class VulkanBarrierBatch { public: @@ -16,6 +17,7 @@ public: bool empty() const { return imageBarriers_.empty(); } + // TODO: Replace this with TransitionImage. VkImageMemoryBarrier *Add(VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags) { srcStageMask_ |= srcStageMask; dstStageMask_ |= dstStageMask; @@ -44,8 +46,11 @@ public: // Automatically determines access and stage masks from layouts. // Not universally usable, but works for PPSSPP's use. - void TransitionImageAuto(VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask, - VkImageLayout oldImageLayout, VkImageLayout newImageLayout); + void TransitionColorImageAuto(VkImage image, VkImageLayout *imageLayout, VkImageLayout newImageLayout, int baseMip, int numMipLevels, int numLayers); + void TransitionDepthStencilImageAuto(VkImage image, VkImageLayout *imageLayout, VkImageLayout newImageLayout, int baseMip, int numMipLevels, int numLayers); + + void TransitionColorImageAuto(VKRImage *image, VkImageLayout newImageLayout); + void TransitionDepthStencilImageAuto(VKRImage *image, VkImageLayout newImageLayout); void Flush(VkCommandBuffer cmd); @@ -55,9 +60,3 @@ private: VkPipelineStageFlags dstStageMask_ = 0; VkDependencyFlags dependencyFlags_ = 0; }; - -// Detailed control, but just a single image. Use the barrier batch when possible. -void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int mipLevels, int numLayers, VkImageAspectFlags aspectMask, - VkImageLayout oldImageLayout, VkImageLayout newImageLayout, - VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, - VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp index dc5b9246bc..127d1ccea1 100644 --- a/Common/GPU/Vulkan/VulkanContext.cpp +++ b/Common/GPU/Vulkan/VulkanContext.cpp @@ -76,6 +76,20 @@ const char *VulkanPresentModeToString(VkPresentModeKHR presentMode) { } } +const char *VulkanImageLayoutToString(VkImageLayout imageLayout) { + switch (imageLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: return "UNDEFINED"; + case VK_IMAGE_LAYOUT_GENERAL: return "GENERAL"; + case VK_IMAGE_LAYOUT_PREINITIALIZED: return "PREINITIALIZED"; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return "TRANSFER_SRC_OPTIMAL"; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return "TRANSFER_DST_OPTIMAL"; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return "SHADER_READ_ONLY_OPTIMAL"; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return "COLOR_ATTACHMENT_OPTIMAL"; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return "DEPTH_STENCIL_ATTACHMENT_OPTIMAL"; + default: return "OTHER"; + } +} + VulkanContext::VulkanContext() { // Do nothing here. } @@ -151,9 +165,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { } instance_extensions_enabled_.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); extensionsLookup_.EXT_debug_utils = true; - INFO_LOG(G3D, "Vulkan debug_utils validation enabled."); + INFO_LOG(Log::G3D, "Vulkan debug_utils validation enabled."); } else { - ERROR_LOG(G3D, "Validation layer extension not available - not enabling Vulkan validation."); + ERROR_LOG(Log::G3D, "Validation layer extension not available - not enabling Vulkan validation."); flags_ &= ~VULKAN_FLAG_VALIDATE; } } @@ -161,19 +175,24 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { // Temporary hack for libretro. For some reason, when we try to load the functions from this extension, // we get null pointers when running libretro. Quite strange. #if !defined(__LIBRETRO__) - if (EnableInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + if (EnableInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_API_VERSION_1_1)) { extensionsLookup_.KHR_get_physical_device_properties2 = true; } #endif - if (EnableInstanceExtension(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME)) { + if (EnableInstanceExtension(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME, 0)) { extensionsLookup_.EXT_swapchain_colorspace = true; } +#if PPSSPP_PLATFORM(IOS_APP_STORE) + if (EnableInstanceExtension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, 0)) { + + } +#endif // Validate that all the instance extensions we ask for are actually available. for (auto ext : instance_extensions_enabled_) { if (!IsInstanceExtensionAvailable(ext)) - WARN_LOG(G3D, "WARNING: Does not seem that instance extension '%s' is available. Trying to proceed anyway.", ext); + WARN_LOG(Log::G3D, "WARNING: Does not seem that instance extension '%s' is available. Trying to proceed anyway.", ext); } VkApplicationInfo app_info{ VK_STRUCTURE_TYPE_APPLICATION_INFO }; @@ -192,6 +211,10 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { inst_info.enabledExtensionCount = (uint32_t)instance_extensions_enabled_.size(); inst_info.ppEnabledExtensionNames = instance_extensions_enabled_.size() ? instance_extensions_enabled_.data() : nullptr; +#if PPSSPP_PLATFORM(IOS_APP_STORE) + inst_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; +#endif + #if SIMULATE_VULKAN_FAILURE == 2 VkResult res = VK_ERROR_INCOMPATIBLE_DRIVER; #else @@ -199,7 +222,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { #endif if (res != VK_SUCCESS) { if (res == VK_ERROR_LAYER_NOT_PRESENT) { - WARN_LOG(G3D, "Validation on but instance layer not available - dropping layers"); + WARN_LOG(Log::G3D, "Validation on but instance layer not available - dropping layers"); // Drop the validation layers and try again. instance_layer_names_.clear(); device_layer_names_.clear(); @@ -207,9 +230,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { inst_info.ppEnabledLayerNames = nullptr; res = vkCreateInstance(&inst_info, nullptr, &instance_); if (res != VK_SUCCESS) - ERROR_LOG(G3D, "Failed to create instance even without validation: %d", res); + ERROR_LOG(Log::G3D, "Failed to create instance even without validation: %d", res); } else { - ERROR_LOG(G3D, "Failed to create instance : %d", res); + ERROR_LOG(Log::G3D, "Failed to create instance : %d", res); } } if (res != VK_SUCCESS) { @@ -217,9 +240,9 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { return res; } - VulkanLoadInstanceFunctions(instance_, extensionsLookup_); + VulkanLoadInstanceFunctions(instance_, extensionsLookup_, vulkanApiVersion_); if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) { - WARN_LOG(G3D, "CheckLayers for instance failed"); + WARN_LOG(Log::G3D, "CheckLayers for instance failed"); // init_error_ = "Failed to validate instance layers"; // return; } @@ -231,7 +254,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { res = vkEnumeratePhysicalDevices(instance_, &gpu_count, nullptr); #endif if (gpu_count <= 0) { - ERROR_LOG(G3D, "Vulkan driver found but no supported GPU is available"); + ERROR_LOG(Log::G3D, "Vulkan driver found but no supported GPU is available"); init_error_ = "No Vulkan physical devices found"; vkDestroyInstance(instance_, nullptr); instance_ = nullptr; @@ -249,18 +272,18 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { return res; } - if (extensionsLookup_.KHR_get_physical_device_properties2) { + if (extensionsLookup_.KHR_get_physical_device_properties2 && vkGetPhysicalDeviceProperties2) { for (uint32_t i = 0; i < gpu_count; i++) { VkPhysicalDeviceProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; VkPhysicalDevicePushDescriptorPropertiesKHR pushProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR}; VkPhysicalDeviceExternalMemoryHostPropertiesEXT extHostMemProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT}; VkPhysicalDeviceDepthStencilResolveProperties depthStencilResolveProps{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES}; + ChainStruct(props2, &pushProps); + ChainStruct(props2, &extHostMemProps); + ChainStruct(props2, &depthStencilResolveProps); + vkGetPhysicalDeviceProperties2(physical_devices_[i], &props2); - props2.pNext = &pushProps; - pushProps.pNext = &extHostMemProps; - extHostMemProps.pNext = &depthStencilResolveProps; - vkGetPhysicalDeviceProperties2KHR(physical_devices_[i], &props2); - // Don't want bad pointers sitting around. + // Don't want bad pointers sitting around. Probably not really necessary. props2.pNext = nullptr; pushProps.pNext = nullptr; extHostMemProps.pNext = nullptr; @@ -277,6 +300,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { } if (extensionsLookup_.EXT_debug_utils) { + _assert_(vkCreateDebugUtilsMessengerEXT != nullptr); InitDebugUtilsCallback(); } @@ -535,13 +559,39 @@ int VulkanContext::GetBestPhysicalDevice() { return best; } -void VulkanContext::ChooseDevice(int physical_device) { +bool VulkanContext::EnableDeviceExtension(const char *extension, uint32_t coreVersion) { + if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) { + return true; + } + for (auto &iter : device_extension_properties_) { + if (!strcmp(iter.extensionName, extension)) { + device_extensions_enabled_.push_back(extension); + return true; + } + } + return false; +} + +bool VulkanContext::EnableInstanceExtension(const char *extension, uint32_t coreVersion) { + if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) { + return true; + } + for (auto &iter : instance_extension_properties_) { + if (!strcmp(iter.extensionName, extension)) { + instance_extensions_enabled_.push_back(extension); + return true; + } + } + return false; +} + +VkResult VulkanContext::CreateDevice(int physical_device) { physical_device_ = physical_device; - INFO_LOG(G3D, "Chose physical device %d: %s", physical_device, physicalDeviceProperties_[physical_device].properties.deviceName); + INFO_LOG(Log::G3D, "Chose physical device %d: %s", physical_device, physicalDeviceProperties_[physical_device].properties.deviceName); GetDeviceLayerProperties(); if (!CheckLayers(device_layer_properties_, device_layer_names_)) { - WARN_LOG(G3D, "CheckLayers for device %d failed", physical_device); + WARN_LOG(Log::G3D, "CheckLayers for device %d failed", physical_device); } vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr); @@ -579,72 +629,24 @@ void VulkanContext::ChooseDevice(int physical_device) { // This is as good a place as any to do this. Though, we don't use this much anymore after we added // support for VMA. vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties_); - INFO_LOG(G3D, "Memory Types (%d):", memory_properties_.memoryTypeCount); + INFO_LOG(Log::G3D, "Memory Types (%d):", memory_properties_.memoryTypeCount); for (int i = 0; i < (int)memory_properties_.memoryTypeCount; i++) { // Don't bother printing dummy memory types. if (!memory_properties_.memoryTypes[i].propertyFlags) continue; - INFO_LOG(G3D, " %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties_.memoryTypes[i].heapIndex, + INFO_LOG(Log::G3D, " %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties_.memoryTypes[i].heapIndex, (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL " : "", (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE " : "", (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED " : "", (memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT " : ""); } - // Optional features - if (extensionsLookup_.KHR_get_physical_device_properties2) { - VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR}; - // Add to chain even if not supported, GetPhysicalDeviceFeatures is supposed to ignore unknown structs. - VkPhysicalDeviceMultiviewFeatures multiViewFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES }; - VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR }; - VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR }; - - features2.pNext = &multiViewFeatures; - multiViewFeatures.pNext = &presentWaitFeatures; - presentWaitFeatures.pNext = &presentIdFeatures; - presentIdFeatures.pNext = nullptr; - - vkGetPhysicalDeviceFeatures2KHR(physical_devices_[physical_device_], &features2); - deviceFeatures_.available.standard = features2.features; - deviceFeatures_.available.multiview = multiViewFeatures; - deviceFeatures_.available.presentWait = presentWaitFeatures; - deviceFeatures_.available.presentId = presentIdFeatures; - } else { - vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard); - deviceFeatures_.available.multiview = {}; - } - GetDeviceLayerExtensionList(nullptr, device_extension_properties_); device_extensions_enabled_.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); -} -bool VulkanContext::EnableDeviceExtension(const char *extension, uint32_t coreVersion) { - if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) { - return true; - } - for (auto &iter : device_extension_properties_) { - if (!strcmp(iter.extensionName, extension)) { - device_extensions_enabled_.push_back(extension); - return true; - } - } - return false; -} - -bool VulkanContext::EnableInstanceExtension(const char *extension) { - for (auto &iter : instance_extension_properties_) { - if (!strcmp(iter.extensionName, extension)) { - instance_extensions_enabled_.push_back(extension); - return true; - } - } - return false; -} - -VkResult VulkanContext::CreateDevice() { if (!init_error_.empty() || physical_device_ < 0) { - ERROR_LOG(G3D, "Vulkan init failed: %s", init_error_.c_str()); + ERROR_LOG(Log::G3D, "Vulkan init failed: %s", init_error_.c_str()); return VK_ERROR_INITIALIZATION_FAILED; } @@ -689,6 +691,44 @@ VkResult VulkanContext::CreateDevice() { extensionsLookup_.KHR_present_wait = EnableDeviceExtension(VK_KHR_PRESENT_WAIT_EXTENSION_NAME, 0); } + extensionsLookup_.EXT_provoking_vertex = EnableDeviceExtension(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, 0); + + // Optional features + if (extensionsLookup_.KHR_get_physical_device_properties2 && vkGetPhysicalDeviceFeatures2) { + VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR }; + // Add to chain even if not supported, GetPhysicalDeviceFeatures is supposed to ignore unknown structs. + VkPhysicalDeviceMultiviewFeatures multiViewFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES }; + VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR }; + VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR }; + VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertexFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT }; + + ChainStruct(features2, &multiViewFeatures); + if (extensionsLookup_.KHR_present_wait) { + ChainStruct(features2, &presentWaitFeatures); + } + if (extensionsLookup_.KHR_present_id) { + ChainStruct(features2, &presentIdFeatures); + } + if (extensionsLookup_.EXT_provoking_vertex) { + ChainStruct(features2, &provokingVertexFeatures); + } + vkGetPhysicalDeviceFeatures2(physical_devices_[physical_device_], &features2); + deviceFeatures_.available.standard = features2.features; + deviceFeatures_.available.multiview = multiViewFeatures; + if (extensionsLookup_.KHR_present_wait) { + deviceFeatures_.available.presentWait = presentWaitFeatures; + } + if (extensionsLookup_.KHR_present_id) { + deviceFeatures_.available.presentId = presentIdFeatures; + } + if (extensionsLookup_.EXT_provoking_vertex) { + deviceFeatures_.available.provokingVertex = provokingVertexFeatures; + } + } else { + vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard); + deviceFeatures_.available.multiview = {}; + } + deviceFeatures_.enabled = {}; // Enable a few safe ones if they are available. deviceFeatures_.enabled.standard.dualSrcBlend = deviceFeatures_.available.standard.dualSrcBlend; @@ -719,6 +759,11 @@ VkResult VulkanContext::CreateDevice() { if (extensionsLookup_.KHR_present_wait) { deviceFeatures_.enabled.presentWait.presentWait = deviceFeatures_.available.presentWait.presentWait; } + deviceFeatures_.enabled.provokingVertex = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT }; + if (extensionsLookup_.EXT_provoking_vertex) { + deviceFeatures_.enabled.provokingVertex.provokingVertexLast = true; + } + // deviceFeatures_.enabled.multiview.multiviewGeometryShader = deviceFeatures_.available.multiview.multiviewGeometryShader; VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; @@ -734,10 +779,16 @@ VkResult VulkanContext::CreateDevice() { if (extensionsLookup_.KHR_get_physical_device_properties2) { device_info.pNext = &features2; features2.features = deviceFeatures_.enabled.standard; - features2.pNext = &deviceFeatures_.enabled.multiview; - deviceFeatures_.enabled.multiview.pNext = &deviceFeatures_.enabled.presentWait; - deviceFeatures_.enabled.presentWait.pNext = &deviceFeatures_.enabled.presentId; - deviceFeatures_.enabled.presentId.pNext = nullptr; + ChainStruct(features2, &deviceFeatures_.enabled.multiview); + if (extensionsLookup_.KHR_present_wait) { + ChainStruct(features2, &deviceFeatures_.enabled.presentWait); + } + if (extensionsLookup_.KHR_present_id) { + ChainStruct(features2, &deviceFeatures_.enabled.presentId); + } + if (extensionsLookup_.EXT_provoking_vertex) { + ChainStruct(features2, &deviceFeatures_.enabled.provokingVertex); + } } else { device_info.pEnabledFeatures = &deviceFeatures_.enabled.standard; } @@ -745,11 +796,11 @@ VkResult VulkanContext::CreateDevice() { VkResult res = vkCreateDevice(physical_devices_[physical_device_], &device_info, nullptr, &device_); if (res != VK_SUCCESS) { init_error_ = "Unable to create Vulkan device"; - ERROR_LOG(G3D, "Unable to create Vulkan device"); + ERROR_LOG(Log::G3D, "Unable to create Vulkan device"); } else { - VulkanLoadDeviceFunctions(device_, extensionsLookup_); + VulkanLoadDeviceFunctions(device_, extensionsLookup_, vulkanApiVersion_); } - INFO_LOG(G3D, "Vulkan Device created: %s", physicalDeviceProperties_[physical_device_].properties.deviceName); + INFO_LOG(Log::G3D, "Vulkan Device created: %s", physicalDeviceProperties_[physical_device_].properties.deviceName); // Since we successfully created a device (however we got here, might be interesting in debug), we force the choice to be visible in the menu. VulkanSetAvailable(true); @@ -820,15 +871,40 @@ VkResult VulkanContext::InitDebugUtilsCallback() { VkDebugUtilsMessengerEXT messenger; VkResult res = vkCreateDebugUtilsMessengerEXT(instance_, &callback1, nullptr, &messenger); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "Failed to register debug callback with vkCreateDebugUtilsMessengerEXT"); + ERROR_LOG(Log::G3D, "Failed to register debug callback with vkCreateDebugUtilsMessengerEXT"); // Do error handling for VK_ERROR_OUT_OF_MEMORY } else { - INFO_LOG(G3D, "Debug callback registered with vkCreateDebugUtilsMessengerEXT."); + INFO_LOG(Log::G3D, "Debug callback registered with vkCreateDebugUtilsMessengerEXT."); utils_callbacks.push_back(messenger); } return res; } +bool VulkanContext::CreateInstanceAndDevice(const CreateInfo &info) { + VkResult res = CreateInstance(info); + if (res != VK_SUCCESS) { + ERROR_LOG(Log::G3D, "Failed to create vulkan context: %s", InitError().c_str()); + VulkanSetAvailable(false); + return false; + } + + int physicalDevice = GetBestPhysicalDevice(); + if (physicalDevice < 0) { + ERROR_LOG(Log::G3D, "No usable Vulkan device found."); + DestroyInstance(); + return false; + } + + INFO_LOG(Log::G3D, "Creating Vulkan device (flags: %08x)", info.flags); + if (CreateDevice(physicalDevice) != VK_SUCCESS) { + INFO_LOG(Log::G3D, "Failed to create vulkan device: %s", InitError().c_str()); + DestroyInstance(); + return false; + } + + return true; +} + void VulkanContext::SetDebugNameImpl(uint64_t handle, VkObjectType type, const char *name) { VkDebugUtilsObjectNameInfoEXT info{ VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT }; info.pObjectName = name; @@ -846,12 +922,12 @@ VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data VkResult VulkanContext::ReinitSurface() { if (surface_ != VK_NULL_HANDLE) { - INFO_LOG(G3D, "Destroying Vulkan surface (%d, %d)", swapChainExtent_.width, swapChainExtent_.height); + INFO_LOG(Log::G3D, "Destroying Vulkan surface (%d, %d)", swapChainExtent_.width, swapChainExtent_.height); vkDestroySurfaceKHR(instance_, surface_, nullptr); surface_ = VK_NULL_HANDLE; } - INFO_LOG(G3D, "Creating Vulkan surface for window (%p %p)", winsysData1_, winsysData2_); + INFO_LOG(Log::G3D, "Creating Vulkan surface for window (data1=%p data2=%p)", winsysData1_, winsysData2_); VkResult retval = VK_SUCCESS; @@ -1171,7 +1247,7 @@ bool VulkanContext::ChooseQueue() { // Generate error if could not find both a graphics and a present queue if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) { - ERROR_LOG(G3D, "Could not find a graphics and a present queue"); + ERROR_LOG(Log::G3D, "Could not find a graphics and a present queue"); return false; } @@ -1195,7 +1271,7 @@ bool VulkanContext::ChooseQueue() { // the surface has no preferred format. Otherwise, at least one // supported format will be returned. if (formatCount == 0 || (formatCount == 1 && surfFormats_[0].format == VK_FORMAT_UNDEFINED)) { - INFO_LOG(G3D, "swapchain_format: Falling back to B8G8R8A8_UNORM"); + INFO_LOG(Log::G3D, "swapchain_format: Falling back to B8G8R8A8_UNORM"); swapchainFormat_ = VK_FORMAT_B8G8R8A8_UNORM; } else { swapchainFormat_ = VK_FORMAT_UNDEFINED; @@ -1212,7 +1288,7 @@ bool VulkanContext::ChooseQueue() { // Okay, take the first one then. swapchainFormat_ = surfFormats_[0].format; } - INFO_LOG(G3D, "swapchain_format: %d (/%d)", swapchainFormat_, formatCount); + INFO_LOG(Log::G3D, "swapchain_format: %d (/%d)", swapchainFormat_, formatCount); } vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &gfx_queue_); @@ -1244,14 +1320,14 @@ static std::string surface_transforms_to_string(VkSurfaceTransformFlagsKHR trans bool VulkanContext::InitSwapchain() { _assert_(physical_device_ >= 0 && physical_device_ < physical_devices_.size()); if (!surface_) { - ERROR_LOG(G3D, "VK: No surface, can't create swapchain"); + ERROR_LOG(Log::G3D, "VK: No surface, can't create swapchain"); return false; } VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_); if (res == VK_ERROR_SURFACE_LOST_KHR) { // Not much to do. - ERROR_LOG(G3D, "VK: Surface lost in InitSwapchain"); + ERROR_LOG(Log::G3D, "VK: Surface lost in InitSwapchain"); return false; } _dbg_assert_(res == VK_SUCCESS); @@ -1266,7 +1342,11 @@ bool VulkanContext::InitSwapchain() { VkExtent2D currentExtent { surfCapabilities_.currentExtent }; // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSurfaceCapabilitiesKHR.html // currentExtent is the current width and height of the surface, or the special value (0xFFFFFFFF, 0xFFFFFFFF) indicating that the surface size will be determined by the extent of a swapchain targeting the surface. - if (currentExtent.width == 0xFFFFFFFFu || currentExtent.height == 0xFFFFFFFFu) { + if (currentExtent.width == 0xFFFFFFFFu || currentExtent.height == 0xFFFFFFFFu +#if PPSSPP_PLATFORM(IOS) + || currentExtent.width == 0 || currentExtent.height == 0 +#endif + ) { _dbg_assert_((bool)cbGetDrawSize_) if (cbGetDrawSize_) { currentExtent = cbGetDrawSize_(); @@ -1276,7 +1356,7 @@ bool VulkanContext::InitSwapchain() { swapChainExtent_.width = clamp(currentExtent.width, surfCapabilities_.minImageExtent.width, surfCapabilities_.maxImageExtent.width); swapChainExtent_.height = clamp(currentExtent.height, surfCapabilities_.minImageExtent.height, surfCapabilities_.maxImageExtent.height); - INFO_LOG(G3D, "surfCapabilities_.current: %dx%d min: %dx%d max: %dx%d computed: %dx%d", + INFO_LOG(Log::G3D, "surfCapabilities_.current: %dx%d min: %dx%d max: %dx%d computed: %dx%d", currentExtent.width, currentExtent.height, surfCapabilities_.minImageExtent.width, surfCapabilities_.minImageExtent.height, surfCapabilities_.maxImageExtent.width, surfCapabilities_.maxImageExtent.height, @@ -1295,7 +1375,7 @@ bool VulkanContext::InitSwapchain() { availablePresentModes_.push_back(presentModes[i]); } - INFO_LOG(G3D, "Supported present modes: %s", modes.c_str()); + INFO_LOG(Log::G3D, "Supported present modes: %s", modes.c_str()); for (size_t i = 0; i < presentModeCount; i++) { bool match = false; match = match || ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR); @@ -1323,7 +1403,7 @@ bool VulkanContext::InitSwapchain() { desiredNumberOfSwapChainImages = surfCapabilities_.maxImageCount; } - INFO_LOG(G3D, "Chosen present mode: %d (%s). numSwapChainImages: %d/%d", + INFO_LOG(Log::G3D, "Chosen present mode: %d (%s). numSwapChainImages: %d/%d", swapchainPresentMode, VulkanPresentModeToString(swapchainPresentMode), desiredNumberOfSwapChainImages, surfCapabilities_.maxImageCount); @@ -1370,13 +1450,13 @@ bool VulkanContext::InitSwapchain() { } std::string preTransformStr = surface_transforms_to_string(preTransform); - INFO_LOG(G3D, "Transform supported: %s current: %s chosen: %s", supportedTransforms.c_str(), currentTransform.c_str(), preTransformStr.c_str()); + INFO_LOG(Log::G3D, "Transform supported: %s current: %s chosen: %s", supportedTransforms.c_str(), currentTransform.c_str(), preTransformStr.c_str()); if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) { u32 driverVersion = physicalDeviceProperties_[physical_device_].properties.driverVersion; // Cutoff the hack at driver version 1.386.1368 (0x00582558, see issue #15773). if (driverVersion < 0x00582558) { - INFO_LOG(G3D, "Applying PowerVR hack (rounding off the width!) driverVersion=%08x", driverVersion); + INFO_LOG(Log::G3D, "Applying PowerVR hack (rounding off the width!) driverVersion=%08x", driverVersion); // Swap chain width hack to avoid issue #11743 (PowerVR driver bug). // To keep the size consistent even with pretransform, do this after the swap. Should be fine. // This is fixed in newer PowerVR drivers but I don't know the cutoff. @@ -1386,7 +1466,7 @@ bool VulkanContext::InitSwapchain() { // This will get a bit messy. Ideally we should remove that logic from app-android.cpp // and move it here, but the OpenGL code still needs it. } else { - INFO_LOG(G3D, "PowerVR driver version new enough (%08x), not applying swapchain width hack", driverVersion); + INFO_LOG(Log::G3D, "PowerVR driver version new enough (%08x), not applying swapchain width hack", driverVersion); } } @@ -1430,10 +1510,10 @@ bool VulkanContext::InitSwapchain() { res = vkCreateSwapchainKHR(device_, &swap_chain_info, NULL, &swapchain_); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "vkCreateSwapchainKHR failed!"); + ERROR_LOG(Log::G3D, "vkCreateSwapchainKHR failed!"); return false; } - INFO_LOG(G3D, "Created swapchain: %dx%d", swap_chain_info.imageExtent.width, swap_chain_info.imageExtent.height); + INFO_LOG(Log::G3D, "Created swapchain: %dx%d", swap_chain_info.imageExtent.width, swap_chain_info.imageExtent.height); return true; } @@ -1458,17 +1538,17 @@ void VulkanContext::PerformPendingDeletes() { void VulkanContext::DestroyDevice() { if (swapchain_) { - ERROR_LOG(G3D, "DestroyDevice: Swapchain should have been destroyed."); + ERROR_LOG(Log::G3D, "DestroyDevice: Swapchain should have been destroyed."); } if (surface_) { - ERROR_LOG(G3D, "DestroyDevice: Surface should have been destroyed."); + ERROR_LOG(Log::G3D, "DestroyDevice: Surface should have been destroyed."); } for (int i = 0; i < ARRAY_SIZE(frame_); i++) { frame_[i].profiler.Shutdown(); } - INFO_LOG(G3D, "VulkanContext::DestroyDevice (performing deletes)"); + INFO_LOG(Log::G3D, "VulkanContext::DestroyDevice (performing deletes)"); PerformPendingDeletes(); vmaDestroyAllocator(allocator_); @@ -1760,9 +1840,9 @@ void VulkanContext::GetImageMemoryRequirements(VkImage image, VkMemoryRequiremen VkMemoryRequirements2KHR memReq2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR}; VkMemoryDedicatedRequirementsKHR memDedicatedReq{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR}; - memReq2.pNext = &memDedicatedReq; + ChainStruct(memReq2, &memDedicatedReq); - vkGetImageMemoryRequirements2KHR(GetDevice(), &memReqInfo2, &memReq2); + vkGetImageMemoryRequirements2(GetDevice(), &memReqInfo2, &memReq2); *mem_reqs = memReq2.memoryRequirements; *dedicatedAllocation = diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index 516b41d6e3..4f1e368cdb 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -44,6 +44,11 @@ VK_DEFINE_HANDLE(VmaAllocation); std::string VulkanVendorString(uint32_t vendorId); +template inline void ChainStruct(R &root, T *newStruct) { + newStruct->pNext = root.pNext; + root.pNext = newStruct; +} + // Not all will be usable on all platforms, of course... enum WindowSystem { #ifdef _WIN32 @@ -181,11 +186,17 @@ public: int GetBestPhysicalDevice(); int GetPhysicalDeviceByName(const std::string &name); - void ChooseDevice(int physical_device); - bool EnableInstanceExtension(const char *extension); - // The core version is to avoid enabling extensions that are merged into core Vulkan from a certain version. + + // Convenience method to avoid code duplication. + // If it returns false, delete the context. + bool CreateInstanceAndDevice(const CreateInfo &info); + + // The coreVersion is to avoid enabling extensions that are merged into core Vulkan from a certain version. + bool EnableInstanceExtension(const char *extension, uint32_t coreVersion); bool EnableDeviceExtension(const char *extension, uint32_t coreVersion); - VkResult CreateDevice(); + + // Was previously two functions, ChooseDevice and CreateDevice. + VkResult CreateDevice(int physical_device); const std::string &InitError() const { return init_error_; } @@ -273,6 +284,7 @@ public: VkPhysicalDeviceMultiviewFeatures multiview; VkPhysicalDevicePresentWaitFeaturesKHR presentWait; VkPhysicalDevicePresentIdFeaturesKHR presentId; + VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertex; }; const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const { @@ -417,7 +429,7 @@ private: bool CheckLayers(const std::vector &layer_props, const std::vector &layer_names) const; - WindowSystem winsys_; + WindowSystem winsys_{}; // Don't use the real types here to avoid having to include platform-specific stuff // that we really don't want in everything that uses VulkanContext. @@ -481,7 +493,7 @@ private: std::vector utils_callbacks; VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; - VkFormat swapchainFormat_; + VkFormat swapchainFormat_ = VK_FORMAT_UNDEFINED; uint32_t queue_count = 0; @@ -490,7 +502,7 @@ private: VkSurfaceCapabilitiesKHR surfCapabilities_{}; std::vector surfFormats_{}; - VkPresentModeKHR presentMode_; + VkPresentModeKHR presentMode_ = VK_PRESENT_MODE_FIFO_KHR; std::vector availablePresentModes_; std::vector cmdQueue_; @@ -513,6 +525,7 @@ bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *sourceCode, const char *VulkanColorSpaceToString(VkColorSpaceKHR colorSpace); const char *VulkanFormatToString(VkFormat format); const char *VulkanPresentModeToString(VkPresentModeKHR presentMode); +const char *VulkanImageLayoutToString(VkImageLayout imageLayout); std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props); diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp index b9638394ad..bae1ad0540 100644 --- a/Common/GPU/Vulkan/VulkanDebug.cpp +++ b/Common/GPU/Vulkan/VulkanDebug.cpp @@ -62,13 +62,6 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( return false; break; - case 606910136: - case -392708513: - case -384083808: - // VUID-vkCmdDraw-None-02686 - // Kinda false positive, or at least very unnecessary, now that I solved the real issue. - // See https://github.com/hrydgard/ppsspp/pull/16354 - return false; case -375211665: // VUID-vkAllocateMemory-pAllocateInfo-01713 // Can happen when VMA aggressively tries to allocate aperture memory for upload. It gracefully @@ -128,7 +121,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( count = g_errorCount[messageCode]++; } if (count == MAX_SAME_ERROR_COUNT) { - WARN_LOG(G3D, "Too many validation messages with message %d, stopping", messageCode); + WARN_LOG(Log::G3D, "Too many validation messages with message %d, stopping", messageCode); } if (count >= MAX_SAME_ERROR_COUNT) { return false; @@ -173,9 +166,9 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( #endif if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { - ERROR_LOG(G3D, "VKDEBUG: %s", msg.c_str()); + ERROR_LOG(Log::G3D, "VKDEBUG: %s", msg.c_str()); } else { - WARN_LOG(G3D, "VKDEBUG: %s", msg.c_str()); + WARN_LOG(Log::G3D, "VKDEBUG: %s", msg.c_str()); } // false indicates that layer should not bail-out of an diff --git a/Common/GPU/Vulkan/VulkanDescSet.cpp b/Common/GPU/Vulkan/VulkanDescSet.cpp index 640f034d39..df68d67b87 100644 --- a/Common/GPU/Vulkan/VulkanDescSet.cpp +++ b/Common/GPU/Vulkan/VulkanDescSet.cpp @@ -56,7 +56,7 @@ bool VulkanDescSetPool::Allocate(VkDescriptorSet *descriptorSets, int count, con VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, descriptorSets); if (result == VK_ERROR_FRAGMENTED_POOL || result < 0) { - WARN_LOG(G3D, "Pool %s %s - recreating", tag_, result == VK_ERROR_FRAGMENTED_POOL ? "fragmented" : "full"); + WARN_LOG(Log::G3D, "Pool %s %s - recreating", tag_, result == VK_ERROR_FRAGMENTED_POOL ? "fragmented" : "full"); // There seems to have been a spec revision. Here we should apparently recreate the descriptor pool, // so let's do that. See https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkAllocateDescriptorSets.html // Fragmentation shouldn't really happen though since we wipe the pool every frame. @@ -113,7 +113,7 @@ VkResult VulkanDescSetPool::Recreate(bool grow) { // Delete the pool if it already exists. if (descPool_ != VK_NULL_HANDLE) { - INFO_LOG(G3D, "Reallocating %s desc pool from %d to %d", tag_, prevSize, info_.maxSets); + INFO_LOG(Log::G3D, "Reallocating %s desc pool from %d to %d", tag_, prevSize, info_.maxSets); vulkan_->Delete().QueueDeleteDescriptorPool(descPool_); usage_ = 0; } diff --git a/Common/GPU/Vulkan/VulkanFrameData.cpp b/Common/GPU/Vulkan/VulkanFrameData.cpp index a95dd42b19..9eb65ddfd3 100644 --- a/Common/GPU/Vulkan/VulkanFrameData.cpp +++ b/Common/GPU/Vulkan/VulkanFrameData.cpp @@ -5,7 +5,7 @@ #include "Common/StringUtils.h" #if 0 // def _DEBUG -#define VLOG(...) NOTICE_LOG(G3D, __VA_ARGS__) +#define VLOG(...) NOTICE_LOG(Log::G3D, __VA_ARGS__) #else #define VLOG(...) #endif @@ -90,17 +90,17 @@ void FrameData::AcquireNextImage(VulkanContext *vulkan) { case VK_SUBOPTIMAL_KHR: hasAcquired = true; // Hopefully the resize will happen shortly. Ignore - one frame might look bad or something. - WARN_LOG(G3D, "VK_SUBOPTIMAL_KHR returned - ignoring"); + WARN_LOG(Log::G3D, "VK_SUBOPTIMAL_KHR returned - ignoring"); break; case VK_ERROR_OUT_OF_DATE_KHR: case VK_TIMEOUT: case VK_NOT_READY: // We do not set hasAcquired here! - WARN_LOG(G3D, "%s returned from AcquireNextImage - processing the frame, but not presenting", VulkanResultToString(res)); + WARN_LOG(Log::G3D, "%s returned from AcquireNextImage - processing the frame, but not presenting", VulkanResultToString(res)); skipSwap = true; break; case VK_ERROR_SURFACE_LOST_KHR: - ERROR_LOG(G3D, "%s returned from AcquireNextImage - ignoring, but this better be during shutdown", VulkanResultToString(res)); + ERROR_LOG(Log::G3D, "%s returned from AcquireNextImage - ignoring, but this better be during shutdown", VulkanResultToString(res)); skipSwap = true; break; default: @@ -132,13 +132,13 @@ VkResult FrameData::QueuePresent(VulkanContext *vulkan, FrameDataShared &shared) if (shared.measurePresentTime) { if (vulkan->Extensions().KHR_present_id && vulkan->GetDeviceFeatures().enabled.presentId.presentId) { + ChainStruct(present, &presentID); presentID.pPresentIds = &frameId; presentID.swapchainCount = 1; - present.pNext = &presentID; } else if (vulkan->Extensions().GOOGLE_display_timing) { + ChainStruct(present, &presentGOOGLE); presentGOOGLE.pTimes = &presentTimeGOOGLE; presentGOOGLE.swapchainCount = 1; - present.pNext = &presentGOOGLE; } } @@ -208,10 +208,11 @@ void FrameData::Submit(VulkanContext *vulkan, FrameSubmitType type, FrameDataSha cmdBufs[numCmdBufs++] = presentCmd; hasPresentCommands = false; + } - if (type == FrameSubmitType::FinishFrame) { - fenceToTrigger = fence; - } + if (type == FrameSubmitType::FinishFrame) { + _dbg_assert_(!fenceToTrigger); + fenceToTrigger = fence; } if (!numCmdBufs && fenceToTrigger == VK_NULL_HANDLE) { diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index 815d68bb61..5e6d7a61a1 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -117,7 +117,7 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas views[attachmentCount++] = color.rtView; // 2D array texture if multilayered. if (hasDepth) { if (!depth.rtView) { - WARN_LOG(G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", (void *)depth.image, (void *)depth.texAllLayersView, depth.format, tag_.c_str(), width, height); + WARN_LOG(Log::G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", (void *)depth.image, (void *)depth.texAllLayersView, depth.format, tag_.c_str(), width, height); // Will probably crash, depending on driver. } views[attachmentCount++] = depth.rtView; @@ -505,7 +505,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas VkAttachmentReference2KHR depthResolveReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR }; VkSubpassDescriptionDepthStencilResolveKHR depthStencilResolve{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR }; if (hasDepth && multisample) { - subpass2.pNext = &depthStencilResolve; + ChainStruct(subpass2, &depthStencilResolve); depthResolveReference2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; depthResolveReference2.attachment = 1; depthResolveReference2.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -524,7 +524,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas rp2.pCorrelatedViewMasks = multiview ? &viewMask : nullptr; rp2.pSubpasses = &subpass2; rp2.subpassCount = 1; - res = vkCreateRenderPass2KHR(vulkan->GetDevice(), &rp2, nullptr, &pass); + res = vkCreateRenderPass2(vulkan->GetDevice(), &rp2, nullptr, &pass); } else { res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass); } diff --git a/Common/GPU/Vulkan/VulkanImage.cpp b/Common/GPU/Vulkan/VulkanImage.cpp index 0361d66d4a..6b5e724aa6 100644 --- a/Common/GPU/Vulkan/VulkanImage.cpp +++ b/Common/GPU/Vulkan/VulkanImage.cpp @@ -38,14 +38,14 @@ static bool IsDepthStencilFormat(VkFormat format) { } } -bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) { +bool VulkanTexture::CreateDirect(int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, VulkanBarrierBatch *barrierBatch, const VkComponentMapping *mapping) { if (w == 0 || h == 0 || numMips == 0) { - ERROR_LOG(G3D, "Can't create a zero-size VulkanTexture"); + ERROR_LOG(Log::G3D, "Can't create a zero-size VulkanTexture"); return false; } int maxDim = vulkan_->GetPhysicalDeviceProperties(0).properties.limits.maxImageDimension2D; if (w > maxDim || h > maxDim) { - ERROR_LOG(G3D, "Can't create a texture this large"); + ERROR_LOG(Log::G3D, "Can't create a texture this large"); return false; } @@ -113,10 +113,10 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i _assert_(false); break; } - TransitionImageLayout2(cmd, image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT, + barrierBatch->TransitionImage(image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, initialLayout, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, - 0, dstAccessFlags); + 0, dstAccessFlags, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage); } // Create the view while we're at it. @@ -137,7 +137,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view_); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "vkCreateImageView failed: %s. Destroying image.", VulkanResultToString(res)); + ERROR_LOG(Log::G3D, "vkCreateImageView failed: %s. Destroying image.", VulkanResultToString(res)); _assert_msg_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS, "%d", (int)res); vmaDestroyImage(vulkan_->Allocator(), image_, allocation_); view_ = VK_NULL_HANDLE; diff --git a/Common/GPU/Vulkan/VulkanImage.h b/Common/GPU/Vulkan/VulkanImage.h index 4adaf4f1a1..05e6039108 100644 --- a/Common/GPU/Vulkan/VulkanImage.h +++ b/Common/GPU/Vulkan/VulkanImage.h @@ -28,7 +28,7 @@ public: // Fast uploads from buffer. Mipmaps supported. // Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip. // When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. - bool CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr); + bool CreateDirect(int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, VulkanBarrierBatch *barrierBatch, const VkComponentMapping *mapping = nullptr); void ClearMip(VkCommandBuffer cmd, int mip, uint32_t value); // Can also be used to copy individual levels of a 3D texture. diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index ca404021f8..cafbdc7e76 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -39,6 +39,7 @@ #endif namespace PPSSPP_VK { +#if !PPSSPP_PLATFORM(IOS_APP_STORE) PFN_vkCreateInstance vkCreateInstance; PFN_vkDestroyInstance vkDestroyInstance; PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; @@ -74,10 +75,8 @@ PFN_vkBindBufferMemory2 vkBindBufferMemory2; PFN_vkBindImageMemory vkBindImageMemory; PFN_vkBindImageMemory2 vkBindImageMemory2; PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; -PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements; PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; -PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; PFN_vkGetDeviceImageMemoryRequirements vkGetDeviceImageMemoryRequirements; PFN_vkCreateFence vkCreateFence; PFN_vkDestroyFence vkDestroyFence; @@ -233,20 +232,23 @@ PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; // Assorted other extensions. -PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; -PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; -PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; -PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; -PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; +PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; +PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; +PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; +PFN_vkCreateRenderPass2 vkCreateRenderPass2; + PFN_vkWaitForPresentKHR vkWaitForPresentKHR; PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; - +#endif } // namespace PPSSPP_VK using namespace PPSSPP_VK; -#if PPSSPP_PLATFORM(SWITCH) +#if PPSSPP_PLATFORM(IOS_APP_STORE) +// Statically linked MoltenVK +#elif PPSSPP_PLATFORM(SWITCH) typedef void *VulkanLibraryHandle; static VulkanLibraryHandle vulkanLibrary; #define dlsym(x, y) nullptr @@ -262,23 +264,35 @@ static VulkanLibraryHandle vulkanLibrary; bool g_vulkanAvailabilityChecked = false; bool g_vulkanMayBeAvailable = false; -#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #x); if (!x) {INFO_LOG(G3D, "Missing (instance): %s", #x);} -#define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {INFO_LOG(G3D, "Missing (device): %s", #x);} -#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {INFO_LOG(G3D,"Missing (global): %s", #x);} +#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #x); if (!x) {INFO_LOG(Log::G3D, "Missing (instance): %s", #x);} +#define LOAD_INSTANCE_FUNC_CORE(instance, x, ext_x, min_core) \ + x = (PFN_ ## x)vkGetInstanceProcAddr(instance, vulkanApiVersion >= min_core ? #x : #ext_x); \ + if (vulkanApiVersion >= min_core && !x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #ext_x); \ + if (!x) {INFO_LOG(Log::G3D, "Missing (instance): %s (%s)", #x, #ext_x);} +#define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {INFO_LOG(Log::G3D, "Missing (device): %s", #x);} +#define LOAD_DEVICE_FUNC_CORE(instance, x, ext_x, min_core) \ + x = (PFN_ ## x)vkGetDeviceProcAddr(instance, vulkanApiVersion >= min_core ? #x : #ext_x); \ + if (vulkanApiVersion >= min_core && !x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #ext_x); \ + if (!x) {INFO_LOG(Log::G3D, "Missing (device): %s (%s)", #x, #ext_x);} +#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {INFO_LOG(Log::G3D,"Missing (global): %s", #x);} #define LOAD_GLOBAL_FUNC_LOCAL(lib, x) (PFN_ ## x)dlsym(lib, #x); static const char * const device_name_blacklist[] = { "NVIDIA:SHIELD Tablet K1", "SDL:Horizon", + "motorola:moto g54 5G", // See issue #18681 / #17825 }; #ifndef _WIN32 static const char * const so_names[] = { -#if PPSSPP_PLATFORM(IOS) +#if PPSSPP_PLATFORM(IOS_APP_STORE) +#elif PPSSPP_PLATFORM(IOS) "@executable_path/Frameworks/libMoltenVK.dylib", + "MoltenVK", #elif PPSSPP_PLATFORM(MAC) "@executable_path/../Frameworks/libMoltenVK.dylib", + "MoltenVK", #else "libvulkan.so", #if !defined(__ANDROID__) @@ -288,6 +302,7 @@ static const char * const so_names[] = { }; #endif +#if !PPSSPP_PLATFORM(IOS_APP_STORE) static VulkanLibraryHandle VulkanLoadLibrary(std::string *errorString) { #if PPSSPP_PLATFORM(SWITCH) // Always unavailable, for now. @@ -323,9 +338,9 @@ static VulkanLibraryHandle VulkanLoadLibrary(std::string *errorString) { (std::string(driverPath.c_str()) + "/").c_str(), driverLibName.c_str(), (std::string(fileRedirectDir.c_str()) + "/").c_str(), nullptr); if (!lib) { - ERROR_LOG(G3D, "Failed to load custom driver with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str()); + ERROR_LOG(Log::G3D, "Failed to load custom driver with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str()); } else { - INFO_LOG(G3D, "Vulkan library loaded with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str()); + INFO_LOG(Log::G3D, "Vulkan library loaded with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str()); } } } @@ -335,15 +350,17 @@ static VulkanLibraryHandle VulkanLoadLibrary(std::string *errorString) { for (int i = 0; i < ARRAY_SIZE(so_names); i++) { lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL); if (lib) { - INFO_LOG(G3D, "Vulkan library loaded ('%s')", so_names[i]); + INFO_LOG(Log::G3D, "Vulkan library loaded ('%s')", so_names[i]); break; } } -} + } return lib; #endif } +#endif +#if !PPSSPP_PLATFORM(IOS_APP_STORE) static void VulkanFreeLibrary(VulkanLibraryHandle &h) { if (h) { #if PPSSPP_PLATFORM(SWITCH) @@ -356,14 +373,21 @@ static void VulkanFreeLibrary(VulkanLibraryHandle &h) { h = nullptr; } } +#endif void VulkanSetAvailable(bool available) { - INFO_LOG(G3D, "Setting Vulkan availability to true"); + INFO_LOG(Log::G3D, "Setting Vulkan availability to true"); g_vulkanAvailabilityChecked = true; g_vulkanMayBeAvailable = available; } bool VulkanMayBeAvailable() { +#if PPSSPP_PLATFORM(IOS) + g_vulkanAvailabilityChecked = true; + // MoltenVK does no longer seem to support iOS <= 12, despite what the docs say. + g_vulkanMayBeAvailable = System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 13; + return g_vulkanMayBeAvailable; +#else // Unsupported in VR at the moment if (IsVREnabled()) { return false; @@ -376,18 +400,18 @@ bool VulkanMayBeAvailable() { std::string name = System_GetProperty(SYSPROP_NAME); for (const char *blacklisted_name : device_name_blacklist) { if (!strcmp(name.c_str(), blacklisted_name)) { - INFO_LOG(G3D, "VulkanMayBeAvailable: Device blacklisted ('%s')", name.c_str()); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Device blacklisted ('%s')", name.c_str()); g_vulkanAvailabilityChecked = true; g_vulkanMayBeAvailable = false; return false; } } - INFO_LOG(G3D, "VulkanMayBeAvailable: Device allowed ('%s')", name.c_str()); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Device allowed ('%s')", name.c_str()); std::string errorStr; VulkanLibraryHandle lib = VulkanLoadLibrary(&errorStr); if (!lib) { - INFO_LOG(G3D, "Vulkan loader: Library not available: %s", errorStr.c_str()); + INFO_LOG(Log::G3D, "Vulkan loader: Library not available: %s", errorStr.c_str()); g_vulkanAvailabilityChecked = true; g_vulkanMayBeAvailable = false; return false; @@ -427,32 +451,32 @@ bool VulkanMayBeAvailable() { #endif if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) { - WARN_LOG(G3D, "VulkanMayBeAvailable: Function pointer missing, bailing"); + WARN_LOG(Log::G3D, "VulkanMayBeAvailable: Function pointer missing, bailing"); goto bail; } - INFO_LOG(G3D, "VulkanMayBeAvailable: Enumerating instance extensions"); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Enumerating instance extensions"); res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr); // Maximum paranoia. if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res)); + ERROR_LOG(Log::G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res)); goto bail; } if (instanceExtCount == 0) { - ERROR_LOG(G3D, "No VK instance extensions - won't be able to present."); + ERROR_LOG(Log::G3D, "No VK instance extensions - won't be able to present."); goto bail; } - INFO_LOG(G3D, "VulkanMayBeAvailable: Instance extension count: %d", instanceExtCount); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Instance extension count: %d", instanceExtCount); instanceExts.resize(instanceExtCount); res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, instanceExts.data()); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res)); + ERROR_LOG(Log::G3D, "Enumerating VK extensions failed (%s)", VulkanResultToString(res)); goto bail; } for (const auto &iter : instanceExts) { - INFO_LOG(G3D, "VulkanMaybeAvailable: Instance extension found: %s (%08x)", iter.extensionName, iter.specVersion); + INFO_LOG(Log::G3D, "VulkanMaybeAvailable: Instance extension found: %s (%08x)", iter.extensionName, iter.specVersion); if (platformSurfaceExtension && !strcmp(iter.extensionName, platformSurfaceExtension)) { - INFO_LOG(G3D, "VulkanMayBeAvailable: Found platform surface extension '%s'", platformSurfaceExtension); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Found platform surface extension '%s'", platformSurfaceExtension); instanceExtensions[ci.enabledExtensionCount++] = platformSurfaceExtension; platformSurfaceExtensionFound = true; break; @@ -463,19 +487,19 @@ bool VulkanMayBeAvailable() { } if (platformSurfaceExtension) { if (!platformSurfaceExtensionFound || !surfaceExtensionFound) { - ERROR_LOG(G3D, "Platform surface extension not found"); + ERROR_LOG(Log::G3D, "Platform surface extension not found"); goto bail; } } else { if (!surfaceExtensionFound) { - ERROR_LOG(G3D, "Surface extension not found"); + ERROR_LOG(Log::G3D, "Surface extension not found"); goto bail; } } // This can't happen unless the driver is double-reporting a surface extension. if (ci.enabledExtensionCount > 2) { - ERROR_LOG(G3D, "Unexpected number of enabled instance extensions"); + ERROR_LOG(Log::G3D, "Unexpected number of enabled instance extensions"); goto bail; } @@ -488,27 +512,27 @@ bool VulkanMayBeAvailable() { info.pEngineName = "VulkanCheckerEngine"; ci.pApplicationInfo = &info; ci.flags = 0; - INFO_LOG(G3D, "VulkanMayBeAvailable: Calling vkCreateInstance"); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Calling vkCreateInstance"); res = localCreateInstance(&ci, nullptr, &instance); if (res != VK_SUCCESS) { instance = nullptr; - ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to create vulkan instance (%s)", VulkanResultToString(res)); + ERROR_LOG(Log::G3D, "VulkanMayBeAvailable: Failed to create vulkan instance (%s)", VulkanResultToString(res)); goto bail; } - INFO_LOG(G3D, "VulkanMayBeAvailable: Vulkan test instance created successfully."); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Vulkan test instance created successfully."); res = localEnumerate(instance, &physicalDeviceCount, nullptr); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to count physical devices (%s)", VulkanResultToString(res)); + ERROR_LOG(Log::G3D, "VulkanMayBeAvailable: Failed to count physical devices (%s)", VulkanResultToString(res)); goto bail; } if (physicalDeviceCount == 0) { - ERROR_LOG(G3D, "VulkanMayBeAvailable: No physical Vulkan devices (count = 0)."); + ERROR_LOG(Log::G3D, "VulkanMayBeAvailable: No physical Vulkan devices (count = 0)."); goto bail; } devices.resize(physicalDeviceCount); res = localEnumerate(instance, &physicalDeviceCount, devices.data()); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "VulkanMayBeAvailable: Failed to enumerate physical devices (%s)", VulkanResultToString(res)); + ERROR_LOG(Log::G3D, "VulkanMayBeAvailable: Failed to enumerate physical devices (%s)", VulkanResultToString(res)); goto bail; } anyGood = false; @@ -520,39 +544,45 @@ bool VulkanMayBeAvailable() { case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: anyGood = true; - INFO_LOG(G3D, "VulkanMayBeAvailable: Eligible device found: '%s'", props.deviceName); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Eligible device found: '%s'", props.deviceName); break; default: - INFO_LOG(G3D, "VulkanMayBeAvailable: Ineligible device found and ignored: '%s'", props.deviceName); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Ineligible device found and ignored: '%s'", props.deviceName); break; } // TODO: Should also check queuefamilyproperties for a GRAPHICS queue family? Oh well. } if (!anyGood) { - WARN_LOG(G3D, "VulkanMayBeAvailable: Found Vulkan API, but no good Vulkan device!"); + WARN_LOG(Log::G3D, "VulkanMayBeAvailable: Found Vulkan API, but no good Vulkan device!"); g_vulkanMayBeAvailable = false; } else { - INFO_LOG(G3D, "VulkanMayBeAvailable: Found working Vulkan API!"); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Found working Vulkan API!"); g_vulkanMayBeAvailable = true; } bail: g_vulkanAvailabilityChecked = true; if (instance) { - INFO_LOG(G3D, "VulkanMayBeAvailable: Destroying instance"); + INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Destroying instance"); localDestroyInstance(instance, nullptr); } if (lib) { VulkanFreeLibrary(lib); } if (!g_vulkanMayBeAvailable) { - WARN_LOG(G3D, "Vulkan with working device not detected."); + WARN_LOG(Log::G3D, "Vulkan with working device not detected."); } return g_vulkanMayBeAvailable; +#endif } bool VulkanLoad(std::string *errorStr) { +#if PPSSPP_PLATFORM(IOS_APP_STORE) + INFO_LOG(Log::G3D, "iOS: Vulkan doesn't need loading"); + return true; +#else + if (!vulkanLibrary) { vulkanLibrary = VulkanLoadLibrary(errorStr); if (!vulkanLibrary) { @@ -569,17 +599,20 @@ bool VulkanLoad(std::string *errorStr) { LOAD_GLOBAL_FUNC(vkEnumerateInstanceLayerProperties); if (vkCreateInstance && vkGetInstanceProcAddr && vkGetDeviceProcAddr && vkEnumerateInstanceExtensionProperties && vkEnumerateInstanceLayerProperties) { - INFO_LOG(G3D, "VulkanLoad: Base functions loaded."); + INFO_LOG(Log::G3D, "VulkanLoad: Base functions loaded."); + // NOTE: It's ok if vkEnumerateInstanceVersion is missing. return true; } else { *errorStr = "Failed to load Vulkan base functions"; - ERROR_LOG(G3D, "VulkanLoad: %s", errorStr->c_str()); + ERROR_LOG(Log::G3D, "VulkanLoad: %s", errorStr->c_str()); VulkanFreeLibrary(vulkanLibrary); return false; } +#endif } -void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions) { +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion) { +#if !PPSSPP_PLATFORM(IOS_APP_STORE) // OK, let's use the above functions to get the rest. LOAD_INSTANCE_FUNC(instance, vkDestroyInstance); LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices); @@ -632,8 +665,8 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &en LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR); if (enabledExtensions.KHR_get_physical_device_properties2) { - LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceProperties2KHR); - LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceFeatures2KHR); + LOAD_INSTANCE_FUNC_CORE(instance, vkGetPhysicalDeviceProperties2, vkGetPhysicalDeviceProperties2KHR, VK_API_VERSION_1_1); + LOAD_INSTANCE_FUNC_CORE(instance, vkGetPhysicalDeviceFeatures2, vkGetPhysicalDeviceFeatures2KHR, VK_API_VERSION_1_1); } if (enabledExtensions.EXT_debug_utils) { @@ -646,14 +679,16 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &en LOAD_INSTANCE_FUNC(instance, vkSetDebugUtilsObjectTagEXT); } - INFO_LOG(G3D, "Vulkan instance functions loaded."); + INFO_LOG(Log::G3D, "Vulkan instance functions loaded."); +#endif } // On some implementations, loading functions (that have Device as their first parameter) via vkGetDeviceProcAddr may // increase performance - but then these function pointers will only work on that specific device. Thus, this loader is not very // good for multi-device - not likely we'll ever try that anyway though. -void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions) { - INFO_LOG(G3D, "Vulkan device functions loaded."); +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion) { +#if !PPSSPP_PLATFORM(IOS_APP_STORE) + INFO_LOG(Log::G3D, "Vulkan device functions loaded."); LOAD_DEVICE_FUNC(device, vkQueueSubmit); LOAD_DEVICE_FUNC(device, vkQueueWaitIdle); @@ -785,16 +820,19 @@ void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledE LOAD_DEVICE_FUNC(device, vkGetRefreshCycleDurationGOOGLE); } if (enabledExtensions.KHR_dedicated_allocation) { - LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2KHR); - LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2KHR); + LOAD_DEVICE_FUNC_CORE(device, vkGetBufferMemoryRequirements2, vkGetBufferMemoryRequirements2KHR, VK_API_VERSION_1_1); + LOAD_DEVICE_FUNC_CORE(device, vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR, VK_API_VERSION_1_1); } if (enabledExtensions.KHR_create_renderpass2) { - LOAD_DEVICE_FUNC(device, vkCreateRenderPass2KHR); + LOAD_DEVICE_FUNC_CORE(device, vkCreateRenderPass2, vkCreateRenderPass2KHR, VK_API_VERSION_1_2); } +#endif } void VulkanFree() { +#if !PPSSPP_PLATFORM(IOS_APP_STORE) VulkanFreeLibrary(vulkanLibrary); +#endif } const char *VulkanResultToString(VkResult res) { diff --git a/Common/GPU/Vulkan/VulkanLoader.h b/Common/GPU/Vulkan/VulkanLoader.h index a08c232daa..2dd6a3fcbe 100644 --- a/Common/GPU/Vulkan/VulkanLoader.h +++ b/Common/GPU/Vulkan/VulkanLoader.h @@ -17,7 +17,9 @@ #pragma once -#ifdef __ANDROID__ +#include "ppsspp_config.h" + +#if PPSSPP_PLATFORM(ANDROID) #define VK_USE_PLATFORM_ANDROID_KHR #elif defined(_WIN32) #define VK_USE_PLATFORM_WIN32_KHR @@ -29,7 +31,10 @@ #define VK_USE_PLATFORM_METAL_EXT #endif +#if !PPSSPP_PLATFORM(IOS_APP_STORE) #define VK_NO_PROTOTYPES +#define VK_ENABLE_BETA_EXTENSIONS 1 // VK_KHR_portability_subset +#endif #include "ext/vulkan/vulkan.h" #include @@ -40,6 +45,7 @@ #endif namespace PPSSPP_VK { +#if !PPSSPP_PLATFORM(IOS_APP_STORE) // Putting our own Vulkan function pointers in a namespace ensures that ppsspp_libretro.so doesn't collide with libvulkan.so. extern PFN_vkCreateInstance vkCreateInstance; extern PFN_vkDestroyInstance vkDestroyInstance; @@ -230,15 +236,17 @@ extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; // Assorted other extensions. -extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; -extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; +extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; +extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; +extern PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; +extern PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; +extern PFN_vkCreateRenderPass2 vkCreateRenderPass2; + extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; -extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; -extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; -extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; extern PFN_vkWaitForPresentKHR vkWaitForPresentKHR; extern PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; extern PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif // !PPSSPP_PLATFORM(IOS_APP_STORE) } // namespace PPSSPP_VK // For fast extension-enabled checks. @@ -260,6 +268,7 @@ struct VulkanExtensions { bool KHR_present_id; // Should probably check the feature flags instead. bool KHR_present_wait; // Same bool GOOGLE_display_timing; + bool EXT_provoking_vertex; // bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers. }; @@ -268,8 +277,8 @@ bool VulkanMayBeAvailable(); void VulkanSetAvailable(bool available); bool VulkanLoad(std::string *errorStr); -void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions); -void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions); +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion); +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion); void VulkanFree(); const char *VulkanResultToString(VkResult res); diff --git a/Common/GPU/Vulkan/VulkanMemory.cpp b/Common/GPU/Vulkan/VulkanMemory.cpp index 83588c9179..146b4eba15 100644 --- a/Common/GPU/Vulkan/VulkanMemory.cpp +++ b/Common/GPU/Vulkan/VulkanMemory.cpp @@ -121,7 +121,7 @@ void VulkanPushPool::BeginFrame() { size_t size = blocks_.back().size; blocks_.back().Destroy(vulkan_); blocks_.pop_back(); - DEBUG_LOG(G3D, "%s: Garbage collected block of size %s in %0.2f ms", name_, NiceSizeFormat(size).c_str(), time_now_d() - start); + DEBUG_LOG(Log::G3D, "%s: Garbage collected block of size %s in %0.2f ms", name_, NiceSizeFormat(size).c_str(), time_now_d() - start); } } @@ -153,7 +153,7 @@ void VulkanPushPool::NextBlock(VkDeviceSize allocationSize) { blocks_.back().used = allocationSize; blocks_.back().lastUsed = time_now_d(); // curBlockIndex_ is already set correctly here. - DEBUG_LOG(G3D, "%s: Created new block of size %s in %0.2f ms", name_, NiceSizeFormat(newBlockSize).c_str(), 1000.0 * (time_now_d() - start)); + DEBUG_LOG(Log::G3D, "%s: Created new block of size %s in %0.2f ms", name_, NiceSizeFormat(newBlockSize).c_str(), 1000.0 * (time_now_d() - start)); } size_t VulkanPushPool::GetUsedThisFrame() const { diff --git a/Common/GPU/Vulkan/VulkanProfiler.cpp b/Common/GPU/Vulkan/VulkanProfiler.cpp index a31952b1bc..60f9805426 100644 --- a/Common/GPU/Vulkan/VulkanProfiler.cpp +++ b/Common/GPU/Vulkan/VulkanProfiler.cpp @@ -50,13 +50,13 @@ void VulkanProfiler::BeginFrame(VulkanContext *vulkan, VkCommandBuffer firstComm static const char * const indent[4] = { "", " ", " ", " " }; if (!scopes_.empty()) { - INFO_LOG(G3D, "Profiling events this frame:"); + INFO_LOG(Log::G3D, "Profiling events this frame:"); } // Log it all out. for (auto &scope : scopes_) { if (scope.endQueryId == -1) { - WARN_LOG(G3D, "Unclosed scope: %s", scope.name); + WARN_LOG(Log::G3D, "Unclosed scope: %s", scope.name); continue; } uint64_t startTime = results[scope.startQueryId]; @@ -66,7 +66,7 @@ void VulkanProfiler::BeginFrame(VulkanContext *vulkan, VkCommandBuffer firstComm double milliseconds = (double)delta * timestampConversionFactor; - INFO_LOG(G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name, milliseconds); + INFO_LOG(Log::G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name, milliseconds); } scopes_.clear(); diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 949355e81d..8c50403530 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -20,11 +20,11 @@ static void MergeRenderAreaRectInto(VkRect2D *dest, const VkRect2D &src) { dest->extent.height += (dest->offset.y - src.offset.y); dest->offset.y = src.offset.y; } - if (dest->extent.width < src.extent.width) { - dest->extent.width = src.extent.width; + if (dest->offset.x + dest->extent.width < src.offset.x + src.extent.width) { + dest->extent.width = src.offset.x + src.extent.width - dest->offset.x; } - if (dest->extent.height < src.extent.height) { - dest->extent.height = src.extent.height; + if (dest->offset.y + dest->extent.height < src.offset.y + src.extent.height) { + dest->extent.height = src.offset.y + src.extent.height - dest->offset.y; } } @@ -44,7 +44,7 @@ RenderPassType MergeRPTypes(RenderPassType a, RenderPassType b) { } void VulkanQueueRunner::CreateDeviceObjects() { - INFO_LOG(G3D, "VulkanQueueRunner::CreateDeviceObjects"); + INFO_LOG(Log::G3D, "VulkanQueueRunner::CreateDeviceObjects"); RPKey key{ VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR, @@ -56,19 +56,19 @@ void VulkanQueueRunner::CreateDeviceObjects() { // Just to check whether it makes sense to split some of these. drawidx is way bigger than the others... // We should probably just move to variable-size data in a raw buffer anyway... VkRenderData rd; - INFO_LOG(G3D, "sizeof(pipeline): %d", (int)sizeof(rd.pipeline)); - INFO_LOG(G3D, "sizeof(draw): %d", (int)sizeof(rd.draw)); - INFO_LOG(G3D, "sizeof(drawidx): %d", (int)sizeof(rd.drawIndexed)); - INFO_LOG(G3D, "sizeof(clear): %d", (int)sizeof(rd.clear)); - INFO_LOG(G3D, "sizeof(viewport): %d", (int)sizeof(rd.viewport)); - INFO_LOG(G3D, "sizeof(scissor): %d", (int)sizeof(rd.scissor)); - INFO_LOG(G3D, "sizeof(blendColor): %d", (int)sizeof(rd.blendColor)); - INFO_LOG(G3D, "sizeof(push): %d", (int)sizeof(rd.push)); + INFO_LOG(Log::G3D, "sizeof(pipeline): %d", (int)sizeof(rd.pipeline)); + INFO_LOG(Log::G3D, "sizeof(draw): %d", (int)sizeof(rd.draw)); + INFO_LOG(Log::G3D, "sizeof(drawidx): %d", (int)sizeof(rd.drawIndexed)); + INFO_LOG(Log::G3D, "sizeof(clear): %d", (int)sizeof(rd.clear)); + INFO_LOG(Log::G3D, "sizeof(viewport): %d", (int)sizeof(rd.viewport)); + INFO_LOG(Log::G3D, "sizeof(scissor): %d", (int)sizeof(rd.scissor)); + INFO_LOG(Log::G3D, "sizeof(blendColor): %d", (int)sizeof(rd.blendColor)); + INFO_LOG(Log::G3D, "sizeof(push): %d", (int)sizeof(rd.push)); #endif } void VulkanQueueRunner::DestroyDeviceObjects() { - INFO_LOG(G3D, "VulkanQueueRunner::DestroyDeviceObjects"); + INFO_LOG(Log::G3D, "VulkanQueueRunner::DestroyDeviceObjects"); syncReadback_.Destroy(vulkan_); @@ -87,7 +87,7 @@ bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit, VulkanBarrierBa VkImage *swapchainImages = new VkImage[swapchainImageCount_]; res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, swapchainImages); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "vkGetSwapchainImagesKHR failed"); + ERROR_LOG(Log::G3D, "vkGetSwapchainImagesKHR failed"); delete[] swapchainImages; return false; } @@ -245,10 +245,9 @@ void VulkanQueueRunner::DestroyBackBuffers() { } framebuffers_.clear(); - INFO_LOG(G3D, "Backbuffers destroyed"); + INFO_LOG(Log::G3D, "Backbuffers destroyed"); } - // Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827 // Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies VKRRenderPass *VulkanQueueRunner::GetRenderPass(const RPKey &key) { @@ -489,18 +488,24 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { for (int j = 0; j < (int)copies.size(); j++) { steps[i + j] = copies[j]; } + + const int firstRender = i + (int)copies.size(); + // Write the renders back (so they will be deleted properly). for (int j = 0; j < (int)renders.size(); j++) { - steps[i + j + copies.size()] = renders[j]; + steps[firstRender + j] = renders[j]; } - _assert_(steps[i + copies.size()]->stepType == VKRStepType::RENDER); + _assert_(steps[firstRender]->stepType == VKRStepType::RENDER); // Combine the renders. for (int j = 1; j < (int)renders.size(); j++) { - steps[i + copies.size()]->commands.reserve(renders[j]->commands.size()); + steps[firstRender]->commands.reserve(renders[j]->commands.size()); for (int k = 0; k < (int)renders[j]->commands.size(); k++) { - steps[i + copies.size()]->commands.push_back(renders[j]->commands[k]); + steps[firstRender]->commands.push_back(renders[j]->commands[k]); } - steps[i + copies.size() + j]->stepType = VKRStepType::RENDER_SKIP; + MergeRenderAreaRectInto(&steps[firstRender]->render.renderArea, renders[j]->render.renderArea); + // Easier than removing them from the list, though that might be the better option. + steps[firstRender + j]->stepType = VKRStepType::RENDER_SKIP; + steps[firstRender + j]->commands.clear(); } // We're done. break; @@ -561,6 +566,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { break; } } + MergeRenderAreaRectInto(&steps[i]->render.renderArea, steps[j]->render.renderArea); steps[j]->stepType = VKRStepType::RENDER_SKIP; } @@ -576,6 +582,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { break; } } + MergeRenderAreaRectInto(&steps[i + 1]->render.renderArea, steps[j]->render.renderArea); steps[j]->stepType = VKRStepType::RENDER_SKIP; } @@ -657,7 +664,8 @@ void VulkanQueueRunner::ApplySonicHack(std::vector &steps) { for (int k = 0; k < (int)type2[j]->commands.size(); k++) { steps[i + type1.size()]->commands.push_back(type2[j]->commands[k]); } - steps[i + j + type1.size()]->stepType = VKRStepType::RENDER_SKIP; + // Technically, should merge render area here, but they're all the same so not needed. + steps[i + type1.size() + j]->stepType = VKRStepType::RENDER_SKIP; } // We're done. break; @@ -803,7 +811,7 @@ void VulkanQueueRunner::ApplyRenderPassMerge(std::vector &steps) { } void VulkanQueueRunner::LogSteps(const std::vector &steps, bool verbose) { - INFO_LOG(G3D, "=================== FRAME ===================="); + INFO_LOG(Log::G3D, "=================== FRAME ===================="); for (size_t i = 0; i < steps.size(); i++) { const VKRStep &step = *steps[i]; switch (step.stepType) { @@ -823,11 +831,11 @@ void VulkanQueueRunner::LogSteps(const std::vector &steps, bool verbo LogReadbackImage(step); break; case VKRStepType::RENDER_SKIP: - INFO_LOG(G3D, "(skipped render pass)"); + INFO_LOG(Log::G3D, "(skipped render pass)"); break; } } - INFO_LOG(G3D, "------------------- SUBMIT ------------------"); + INFO_LOG(Log::G3D, "------------------- SUBMIT ------------------"); } const char *RenderPassActionName(VKRRenderPassLoadAction a) { @@ -862,47 +870,47 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { int w = r.framebuffer ? r.framebuffer->width : vulkan_->GetBackbufferWidth(); int h = r.framebuffer ? r.framebuffer->height : vulkan_->GetBackbufferHeight(); - INFO_LOG(G3D, "RENDER %s Begin(%s, draws: %d, %dx%d, %s, %s, %s)", pass.tag, framebuf, r.numDraws, w, h, RenderPassActionName(r.colorLoad), RenderPassActionName(r.depthLoad), RenderPassActionName(r.stencilLoad)); + INFO_LOG(Log::G3D, "RENDER %s Begin(%s, draws: %d, %dx%d, %s, %s, %s)", pass.tag, framebuf, r.numDraws, w, h, RenderPassActionName(r.colorLoad), RenderPassActionName(r.depthLoad), RenderPassActionName(r.stencilLoad)); // TODO: Log these in detail. for (int i = 0; i < (int)pass.preTransitions.size(); i++) { - INFO_LOG(G3D, " PRETRANSITION: %s %s -> %s", pass.preTransitions[i].fb->Tag(), AspectToString(pass.preTransitions[i].aspect), ImageLayoutToString(pass.preTransitions[i].targetLayout)); + INFO_LOG(Log::G3D, " PRETRANSITION: %s %s -> %s", pass.preTransitions[i].fb->Tag(), AspectToString(pass.preTransitions[i].aspect), ImageLayoutToString(pass.preTransitions[i].targetLayout)); } if (verbose) { for (auto &cmd : pass.commands) { switch (cmd.cmd) { case VKRRenderCommand::REMOVED: - INFO_LOG(G3D, " (Removed)"); + INFO_LOG(Log::G3D, " (Removed)"); break; case VKRRenderCommand::BIND_GRAPHICS_PIPELINE: - INFO_LOG(G3D, " BindGraphicsPipeline(%x)", (int)(intptr_t)cmd.graphics_pipeline.pipeline); + INFO_LOG(Log::G3D, " BindGraphicsPipeline(%x)", (int)(intptr_t)cmd.graphics_pipeline.pipeline); break; case VKRRenderCommand::BLEND: - INFO_LOG(G3D, " BlendColor(%08x)", cmd.blendColor.color); + INFO_LOG(Log::G3D, " BlendColor(%08x)", cmd.blendColor.color); break; case VKRRenderCommand::CLEAR: - INFO_LOG(G3D, " Clear"); + INFO_LOG(Log::G3D, " Clear"); break; case VKRRenderCommand::DRAW: - INFO_LOG(G3D, " Draw(%d)", cmd.draw.count); + INFO_LOG(Log::G3D, " Draw(%d)", cmd.draw.count); break; case VKRRenderCommand::DRAW_INDEXED: - INFO_LOG(G3D, " DrawIndexed(%d)", cmd.drawIndexed.count); + INFO_LOG(Log::G3D, " DrawIndexed(%d)", cmd.drawIndexed.count); break; case VKRRenderCommand::SCISSOR: - INFO_LOG(G3D, " Scissor(%d, %d, %d, %d)", (int)cmd.scissor.scissor.offset.x, (int)cmd.scissor.scissor.offset.y, (int)cmd.scissor.scissor.extent.width, (int)cmd.scissor.scissor.extent.height); + INFO_LOG(Log::G3D, " Scissor(%d, %d, %d, %d)", (int)cmd.scissor.scissor.offset.x, (int)cmd.scissor.scissor.offset.y, (int)cmd.scissor.scissor.extent.width, (int)cmd.scissor.scissor.extent.height); break; case VKRRenderCommand::STENCIL: - INFO_LOG(G3D, " Stencil(ref=%d, compare=%d, write=%d)", cmd.stencil.stencilRef, cmd.stencil.stencilCompareMask, cmd.stencil.stencilWriteMask); + INFO_LOG(Log::G3D, " Stencil(ref=%d, compare=%d, write=%d)", cmd.stencil.stencilRef, cmd.stencil.stencilCompareMask, cmd.stencil.stencilWriteMask); break; case VKRRenderCommand::VIEWPORT: - INFO_LOG(G3D, " Viewport(%f, %f, %f, %f, %f, %f)", cmd.viewport.vp.x, cmd.viewport.vp.y, cmd.viewport.vp.width, cmd.viewport.vp.height, cmd.viewport.vp.minDepth, cmd.viewport.vp.maxDepth); + INFO_LOG(Log::G3D, " Viewport(%f, %f, %f, %f, %f, %f)", cmd.viewport.vp.x, cmd.viewport.vp.y, cmd.viewport.vp.width, cmd.viewport.vp.height, cmd.viewport.vp.minDepth, cmd.viewport.vp.maxDepth); break; case VKRRenderCommand::PUSH_CONSTANTS: - INFO_LOG(G3D, " PushConstants(%d)", cmd.push.size); + INFO_LOG(Log::G3D, " PushConstants(%d)", cmd.push.size); break; case VKRRenderCommand::DEBUG_ANNOTATION: - INFO_LOG(G3D, " DebugAnnotation(%s)", cmd.debugAnnotation.annotation); + INFO_LOG(Log::G3D, " DebugAnnotation(%s)", cmd.debugAnnotation.annotation); break; case VKRRenderCommand::NUM_RENDER_COMMANDS: @@ -911,221 +919,39 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { } } - INFO_LOG(G3D, " Final: %s %s", ImageLayoutToString(pass.render.finalColorLayout), ImageLayoutToString(pass.render.finalDepthStencilLayout)); - INFO_LOG(G3D, "RENDER End(%s) - %d commands executed", framebuf, (int)pass.commands.size()); + INFO_LOG(Log::G3D, " Final: %s %s", ImageLayoutToString(pass.render.finalColorLayout), ImageLayoutToString(pass.render.finalDepthStencilLayout)); + INFO_LOG(Log::G3D, "RENDER End(%s) - %d commands executed", framebuf, (int)pass.commands.size()); } void VulkanQueueRunner::LogCopy(const VKRStep &step) { - INFO_LOG(G3D, "%s", StepToString(vulkan_, step).c_str()); + INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str()); } void VulkanQueueRunner::LogBlit(const VKRStep &step) { - INFO_LOG(G3D, "%s", StepToString(vulkan_, step).c_str()); + INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str()); } void VulkanQueueRunner::LogReadback(const VKRStep &step) { - INFO_LOG(G3D, "%s", StepToString(vulkan_, step).c_str()); + INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str()); } void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) { - INFO_LOG(G3D, "%s", StepToString(vulkan_, step).c_str()); -} - -void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout, int numLayers, VulkanBarrierBatch *recordBarrier) { - if (colorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { - VkPipelineStageFlags srcStageMask = 0; - VkAccessFlags srcAccessMask = 0; - switch (colorLayout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - // No need to specify stage or access. - break; - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - // Already the right color layout. Unclear that we need to do a lot here.. - break; - case VK_IMAGE_LAYOUT_GENERAL: - // We came from the Mali workaround, and are transitioning back to COLOR_ATTACHMENT_OPTIMAL. - srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - default: - _dbg_assert_msg_(false, "TransitionToOptimal: Unexpected color layout %d", (int)colorLayout); - break; - } - recordBarrier->TransitionImage( - colorImage, 0, 1, numLayers, VK_IMAGE_ASPECT_COLOR_BIT, - colorLayout, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - srcAccessMask, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - srcStageMask, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - } - - if (depthStencilImage != VK_NULL_HANDLE && depthStencilLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - VkPipelineStageFlags srcStageMask = 0; - VkAccessFlags srcAccessMask = 0; - switch (depthStencilLayout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - // No need to specify stage or access. - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - // Already the right depth layout. Unclear that we need to do a lot here.. - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - default: - _dbg_assert_msg_(false, "TransitionToOptimal: Unexpected depth layout %d", (int)depthStencilLayout); - break; - } - recordBarrier->TransitionImage( - depthStencilImage, 0, 1, numLayers, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, - depthStencilLayout, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - srcAccessMask, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, - srcStageMask, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); - } -} - -void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, int numLayers, VkImageLayout depthStencilLayout) { - VkPipelineStageFlags srcStageMask = 0; - VkPipelineStageFlags dstStageMask = 0; - - // If layouts aren't optimal, transition them. - VkImageMemoryBarrier barrier[2]{}; - - int barrierCount = 0; - if (colorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { - barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier[0].pNext = nullptr; - srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - barrier[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - // And the final transition. - // Don't need to transition it if VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL. - switch (colorLayout) { - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_UNDEFINED: - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - // Nothing to do. - break; - default: - _dbg_assert_msg_(false, "TransitionFromOptimal: Unexpected final color layout %d", (int)colorLayout); - break; - } - barrier[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier[0].newLayout = colorLayout; - barrier[0].image = colorImage; - barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier[0].subresourceRange.baseMipLevel = 0; - barrier[0].subresourceRange.levelCount = 1; - barrier[0].subresourceRange.layerCount = numLayers; - barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrierCount++; - } - - if (depthStencilImage && depthStencilLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - barrier[barrierCount].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier[barrierCount].pNext = nullptr; - - srcStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - barrier[barrierCount].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - switch (depthStencilLayout) { - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - barrier[barrierCount].dstAccessMask |= VK_ACCESS_SHADER_READ_BIT; - dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - barrier[barrierCount].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; - dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - barrier[barrierCount].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; - dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_UNDEFINED: - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - // Nothing to do. - break; - default: - _dbg_assert_msg_(false, "TransitionFromOptimal: Unexpected final depth layout %d", (int)depthStencilLayout); - break; - } - barrier[barrierCount].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - barrier[barrierCount].newLayout = depthStencilLayout; - barrier[barrierCount].image = depthStencilImage; - barrier[barrierCount].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - barrier[barrierCount].subresourceRange.baseMipLevel = 0; - barrier[barrierCount].subresourceRange.levelCount = 1; - barrier[barrierCount].subresourceRange.layerCount = numLayers; - barrier[barrierCount].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[barrierCount].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrierCount++; - } - if (barrierCount) { - vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, barrierCount, barrier); - } + INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str()); } void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd, int curFrame, QueueProfileContext &profile) { for (size_t i = 0; i < step.preTransitions.size(); i++) { const TransitionRequest &iter = step.preTransitions[i]; if (iter.aspect == VK_IMAGE_ASPECT_COLOR_BIT && iter.fb->color.layout != iter.targetLayout) { - recordBarrier_.TransitionImageAuto( - iter.fb->color.image, - 0, - 1, - iter.fb->numLayers, - VK_IMAGE_ASPECT_COLOR_BIT, - iter.fb->color.layout, + recordBarrier_.TransitionColorImageAuto( + &iter.fb->color, iter.targetLayout ); - iter.fb->color.layout = iter.targetLayout; } else if (iter.fb->depth.image != VK_NULL_HANDLE && (iter.aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) && iter.fb->depth.layout != iter.targetLayout) { - recordBarrier_.TransitionImageAuto( - iter.fb->depth.image, - 0, - 1, - iter.fb->numLayers, - VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, - iter.fb->depth.layout, + recordBarrier_.TransitionDepthStencilImageAuto( + &iter.fb->depth, iter.targetLayout ); - iter.fb->depth.layout = iter.targetLayout; } } @@ -1140,7 +966,9 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } // Write-after-write hazards. Fixed flicker in God of War on ARM (before we added another fix that removed these). - // These aren't so common so not bothering to combine the barrier with the pretransition one. + // NOTE: These are commented out because the normal barriers no longer check for equality, effectively generating these + // barriers automatically. This is safe, but sometimes I think can be improved on. + /* if (step.render.framebuffer) { int n = 0; int stage = 0; @@ -1158,7 +986,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT - ); + ); } if (step.render.framebuffer->depth.image != VK_NULL_HANDLE && step.render.framebuffer->depth.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { recordBarrier_.TransitionImage( @@ -1171,16 +999,16 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, ); } - } + }*/ - // This reads the layout of the color and depth images, and chooses a render pass using them that - // will transition to the desired final layout. + // This chooses a render pass according to the load/store attachment state. We no longer transition + // image layouts as part of the passes. // - // NOTE: Flushes recordBarrier_. + // NOTE: Unconditionally flushes recordBarrier_. VKRRenderPass *renderPass = PerformBindFramebufferAsRenderTarget(step, cmd); int curWidth = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth(); @@ -1395,18 +1223,22 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c break; default: - ERROR_LOG(G3D, "Unimpl queue command"); + ERROR_LOG(Log::G3D, "Unimpl queue command"); break; } } vkCmdEndRenderPass(cmd); - if (fb) { - // If the desired final layout aren't the optimal layout for rendering, transition. - TransitionFromOptimal(cmd, fb->color.image, step.render.finalColorLayout, fb->depth.image, fb->numLayers, step.render.finalDepthStencilLayout); + _dbg_assert_(recordBarrier_.empty()); - fb->color.layout = step.render.finalColorLayout; - fb->depth.layout = step.render.finalDepthStencilLayout; + if (fb) { + // If the desired final layout aren't the optimal layout needed next, early-transition the image. + if (step.render.finalColorLayout != fb->color.layout) { + recordBarrier_.TransitionColorImageAuto(&fb->color, step.render.finalColorLayout); + } + if (fb->depth.image && step.render.finalDepthStencilLayout != fb->depth.layout) { + recordBarrier_.TransitionDepthStencilImageAuto(&fb->depth, step.render.finalDepthStencilLayout); + } } } @@ -1422,6 +1254,9 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR VkSampleCountFlagBits sampleCount; + // Can be used to separate the final*Layout barrier from the rest for debugging in renderdoc. + // recordBarrier_.Flush(cmd); + if (step.render.framebuffer) { _dbg_assert_(step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED); _dbg_assert_(step.render.finalDepthStencilLayout != VK_IMAGE_LAYOUT_UNDEFINED); @@ -1447,6 +1282,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR step.render.colorLoad == VKRRenderPassLoadAction::CLEAR && vulkan_->GetPhysicalDeviceProperties().properties.driverVersion == 0xaa9c4b29; if (maliBugWorkaround) { + // A little suboptimal but let's go for maximum safety here. recordBarrier_.TransitionImage(fb->color.image, 0, 1, fb->numLayers, VK_IMAGE_ASPECT_COLOR_BIT, fb->color.layout, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, @@ -1455,7 +1291,12 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR fb->color.layout = VK_IMAGE_LAYOUT_GENERAL; } - TransitionToOptimal(cmd, fb->color.image, fb->color.layout, fb->depth.image, fb->depth.layout, fb->numLayers, &recordBarrier_); + recordBarrier_.TransitionColorImageAuto(&fb->color, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + // If the render pass doesn't touch depth, we can avoid a layout transition of the depth buffer. + if (fb->depth.image && RenderPassTypeHasDepth(step.render.renderPassType)) { + recordBarrier_.TransitionDepthStencilImageAuto(&fb->depth, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } // The transition from the optimal format happens after EndRenderPass, now that we don't // do it as part of the renderpass itself anymore. @@ -1539,45 +1380,38 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { // TODO: If dst covers exactly the whole destination, we can set up a UNDEFINED->TRANSFER_DST_OPTIMAL transition, // which can potentially be more efficient. - // First source barriers. if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { - SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + recordBarrier_.TransitionColorImageAuto(&src->color, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + recordBarrier_.TransitionColorImageAuto(&dst->color, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } // We can't copy only depth or only stencil unfortunately - or can we?. if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { _dbg_assert_(src->depth.image != VK_NULL_HANDLE); - SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + recordBarrier_.TransitionDepthStencilImageAuto(&src->depth, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); if (dst->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - SetupTransitionToTransferDst(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - _dbg_assert_(dst->depth.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + recordBarrier_.TransitionDepthStencilImageAuto(&dst->depth, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } else { // Kingdom Hearts: Subsequent copies twice to the same depth buffer without any other use. // Not super sure how that happens, but we need a barrier to pass sync validation. SetupTransferDstWriteAfterWrite(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); } } - recordBarrier_.Flush(cmd); bool multisampled = src->sampleCount != VK_SAMPLE_COUNT_1_BIT && dst->sampleCount != VK_SAMPLE_COUNT_1_BIT; if (multisampled) { // If both the targets are multisampled, copy the msaa targets too. // For that, we need to transition them from their normally permanent VK_*_ATTACHMENT_OPTIMAL layouts, and then back. if (step.copy.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { - SetupTransitionToTransferSrc(src->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - recordBarrier_.Flush(cmd); - SetupTransitionToTransferDst(dst->msaaColor, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - recordBarrier_.Flush(cmd); + recordBarrier_.TransitionColorImageAuto(&src->msaaColor, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + recordBarrier_.TransitionColorImageAuto(&dst->msaaColor, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { // Kingdom Hearts: Subsequent copies to the same depth buffer without any other use. // Not super sure how that happens, but we need a barrier to pass sync validation. - SetupTransitionToTransferSrc(src->msaaDepth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - recordBarrier_.Flush(cmd); - SetupTransitionToTransferDst(dst->msaaDepth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - recordBarrier_.Flush(cmd); + recordBarrier_.TransitionDepthStencilImageAuto(&src->msaaDepth, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + recordBarrier_.TransitionDepthStencilImageAuto(&dst->msaaDepth, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } } @@ -1635,6 +1469,7 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ); + src->msaaColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; recordBarrier_.TransitionImage( dst->msaaColor.image, 0, @@ -1648,7 +1483,6 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ); - src->msaaColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; dst->msaaColor.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { @@ -1665,6 +1499,7 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT ); + src->msaaDepth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; recordBarrier_.TransitionImage( dst->msaaDepth.image, 0, @@ -1678,9 +1513,9 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT ); - src->msaaDepth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; dst->msaaDepth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } + // Probably not necessary. recordBarrier_.Flush(cmd); } } @@ -1697,16 +1532,16 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { // First source barriers. if (step.blit.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { - SetupTransitionToTransferSrc(src->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); - SetupTransitionToTransferDst(dst->color, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + recordBarrier_.TransitionColorImageAuto(&src->color, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + recordBarrier_.TransitionColorImageAuto(&dst->color, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } // We can't copy only depth or only stencil unfortunately. if (step.blit.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { _assert_(src->depth.image != VK_NULL_HANDLE); _assert_(dst->depth.image != VK_NULL_HANDLE); - SetupTransitionToTransferSrc(src->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); - SetupTransitionToTransferDst(dst->depth, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, &recordBarrier_); + recordBarrier_.TransitionDepthStencilImageAuto(&src->depth, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + recordBarrier_.TransitionDepthStencilImageAuto(&dst->depth, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } recordBarrier_.Flush(cmd); @@ -1754,111 +1589,6 @@ void VulkanQueueRunner::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) { } } -void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier) { - if (img.layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - return; - } - VkImageAspectFlags imageAspect = aspect; - VkAccessFlags srcAccessMask = 0; - VkPipelineStageFlags srcStageMask = 0; - switch (img.layout) { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - default: - _dbg_assert_msg_(false, "Transition from this layout to transfer src not supported (%d)", (int)img.layout); - break; - } - - if (img.format == VK_FORMAT_D16_UNORM_S8_UINT || img.format == VK_FORMAT_D24_UNORM_S8_UINT || img.format == VK_FORMAT_D32_SFLOAT_S8_UINT) { - // Barrier must specify both for combined depth/stencil buffers. - imageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } else { - imageAspect = aspect; - } - - recordBarrier->TransitionImage( - img.image, - 0, - 1, - img.numLayers, - imageAspect, - img.layout, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - srcAccessMask, - VK_ACCESS_TRANSFER_READ_BIT, - srcStageMask, - VK_PIPELINE_STAGE_TRANSFER_BIT - ); - img.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; -} - -void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier) { - if (img.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - return; - } - VkImageAspectFlags imageAspect = aspect; - VkAccessFlags srcAccessMask = 0; - VkPipelineStageFlags srcStageMask = 0; - if (img.format == VK_FORMAT_D16_UNORM_S8_UINT || img.format == VK_FORMAT_D24_UNORM_S8_UINT || img.format == VK_FORMAT_D32_SFLOAT_S8_UINT) { - // Barrier must specify both for combined depth/stencil buffers. - imageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } else { - imageAspect = aspect; - } - - switch (img.layout) { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - default: - _dbg_assert_msg_(false, "Transition from this layout to transfer dst not supported (%d)", (int)img.layout); - break; - } - - recordBarrier->TransitionImage( - img.image, - 0, - 1, - img.numLayers, - aspect, - img.layout, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - srcAccessMask, - VK_ACCESS_TRANSFER_WRITE_BIT, - srcStageMask, - VK_PIPELINE_STAGE_TRANSFER_BIT - ); - - img.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; -} - void VulkanQueueRunner::SetupTransferDstWriteAfterWrite(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier) { VkImageAspectFlags imageAspect = aspect; VkAccessFlags srcAccessMask = 0; @@ -1923,32 +1653,31 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd // We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT, // and then back into it. // Regarding layers, backbuffer currently only has one layer. - TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, + recordBarrier_.TransitionImage(backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, VK_ACCESS_TRANSFER_READ_BIT); + 0, VK_ACCESS_TRANSFER_READ_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); copyLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; image = backbufferImage_; } else { VKRImage *srcImage; if (step.readback.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { srcImage = &step.readback.src->color; + recordBarrier_.TransitionColorImageAuto(srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); } else if (step.readback.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { srcImage = &step.readback.src->depth; + recordBarrier_.TransitionDepthStencilImageAuto(srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); _dbg_assert_(srcImage->image != VK_NULL_HANDLE); } else { _dbg_assert_msg_(false, "No image aspect to readback?"); return; } - - if (srcImage->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - SetupTransitionToTransferSrc(*srcImage, step.readback.aspectMask, &recordBarrier_); - recordBarrier_.Flush(cmd); - } image = srcImage->image; copyLayout = srcImage->layout; } + recordBarrier_.Flush(cmd); + // TODO: Handle different readback formats! u32 readbackSizeInBytes = sizeof(uint32_t) * step.readback.srcRect.extent.width * step.readback.srcRect.extent.height; @@ -1990,22 +1719,19 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd // We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT, // and then back into it. // Regarding layers, backbuffer currently only has one layer. - TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, + recordBarrier_.TransitionImage(backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_TRANSFER_READ_BIT, 0); + VK_ACCESS_TRANSFER_READ_BIT, 0, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + recordBarrier_.Flush(cmd); // probably not needed copyLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; } } void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffer cmd) { // TODO: Clean this up - just reusing `SetupTransitionToTransferSrc`. - VKRImage srcImage{}; - srcImage.image = step.readback_image.image; - srcImage.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - srcImage.numLayers = 1; - - SetupTransitionToTransferSrc(srcImage, VK_IMAGE_ASPECT_COLOR_BIT, &recordBarrier_); + VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + recordBarrier_.TransitionColorImageAuto(step.readback_image.image, &layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 1, 1); recordBarrier_.Flush(cmd); ResizeReadbackBuffer(&syncReadback_, sizeof(uint32_t) * step.readback_image.srcRect.extent.width * step.readback_image.srcRect.extent.height); @@ -2022,11 +1748,12 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe vkCmdCopyImageToBuffer(cmd, step.readback_image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, syncReadback_.buffer, 1, ®ion); // Now transfer it back to a texture. - TransitionImageLayout2(cmd, step.readback_image.image, 0, 1, 1, // I don't think we have any multilayer cases for regular textures. Above in PerformReadback, though.. + recordBarrier_.TransitionImage(step.readback_image.image, 0, 1, 1, // I don't think we have any multilayer cases for regular textures. Above in PerformReadback, though.. VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + recordBarrier_.Flush(cmd); // probably not needed // NOTE: Can't read the buffer using the CPU here - need to sync first. // Doing that will also act like a heavyweight barrier ensuring that device writes are visible on the host. @@ -2059,7 +1786,7 @@ bool VulkanQueueRunner::CopyReadbackBuffer(FrameData &frameData, VKRFramebuffer VkResult res = vmaMapMemory(vulkan_->Allocator(), readback->allocation, &mappedData); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "CopyReadbackBuffer: vkMapMemory failed! result=%d", (int)res); + ERROR_LOG(Log::G3D, "CopyReadbackBuffer: vkMapMemory failed! result=%d", (int)res); return false; } @@ -2087,7 +1814,7 @@ bool VulkanQueueRunner::CopyReadbackBuffer(FrameData &frameData, VKRFramebuffer ConvertToD16(pixels, (const uint8_t *)mappedData, pixelStride, width, width, height, srcFormat); } else { // TODO: Maybe a depth conversion or something? - ERROR_LOG(G3D, "CopyReadbackBuffer: Unknown format"); + ERROR_LOG(Log::G3D, "CopyReadbackBuffer: Unknown format"); _assert_msg_(false, "CopyReadbackBuffer: Unknown src format %d", (int)srcFormat); } diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index ab39c7b06f..da40ad300b 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -50,6 +50,7 @@ enum class PipelineFlags : u8 { USES_GEOMETRY_SHADER = (1 << 3), USES_MULTIVIEW = (1 << 4), // Inherited from the render pass it was created with. USES_DISCARD = (1 << 5), + USES_FLAT_SHADING = (1 << 6), }; ENUM_CLASS_BITOPS(PipelineFlags); @@ -154,9 +155,9 @@ struct VKRStep { VKRRenderPassStoreAction colorStore; VKRRenderPassStoreAction depthStore; VKRRenderPassStoreAction stencilStore; - u8 clearStencil; uint32_t clearColor; float clearDepth; + u8 clearStencil; int numDraws; // Downloads and textures from this pass. int numReads; @@ -173,20 +174,20 @@ struct VKRStep { VKRFramebuffer *dst; VkRect2D srcRect; VkOffset2D dstPos; - int aspectMask; + VkImageAspectFlags aspectMask; } copy; struct { VKRFramebuffer *src; VKRFramebuffer *dst; VkRect2D srcRect; VkRect2D dstRect; - int aspectMask; + VkImageAspectFlags aspectMask; VkFilter filter; } blit; struct { - int aspectMask; VKRFramebuffer *src; VkRect2D srcRect; + VkImageAspectFlags aspectMask; bool delayed; } readback; struct { @@ -289,8 +290,6 @@ private: void ApplySonicHack(std::vector &steps); void ApplyRenderPassMerge(std::vector &steps); - static void SetupTransitionToTransferSrc(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier); - static void SetupTransitionToTransferDst(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier); static void SetupTransferDstWriteAfterWrite(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier); VulkanContext *vulkan_; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index d8a2bea729..102595dc93 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -17,7 +17,7 @@ #include "Common/VR/PPSSPPVR.h" #if 0 // def _DEBUG -#define VLOG(...) NOTICE_LOG(G3D, __VA_ARGS__) +#define VLOG(...) NOTICE_LOG(Log::G3D, __VA_ARGS__) #else #define VLOG(...) #endif @@ -46,7 +46,7 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR // Sanity check. // Seen in crash reports from PowerVR GE8320, presumably we failed creating some shader modules. if (!desc->vertexShader || !desc->fragmentShader) { - ERROR_LOG(G3D, "Failed creating graphics pipeline - missing vs/fs shader module pointers!"); + ERROR_LOG(Log::G3D, "Failed creating graphics pipeline - missing vs/fs shader module pointers!"); pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); return false; } @@ -57,13 +57,13 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR VkShaderModule gs = desc->geometryShader ? desc->geometryShader->BlockUntilReady() : VK_NULL_HANDLE; if (!vs || !fs || (!gs && desc->geometryShader)) { - ERROR_LOG(G3D, "Failed creating graphics pipeline - missing shader modules"); + ERROR_LOG(Log::G3D, "Failed creating graphics pipeline - missing shader modules"); pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); return false; } if (!compatibleRenderPass) { - ERROR_LOG(G3D, "Failed creating graphics pipeline - compatible render pass was nullptr"); + ERROR_LOG(Log::G3D, "Failed creating graphics pipeline - compatible render pass was nullptr"); pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); return false; } @@ -130,10 +130,10 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR double taken_ms = (now - start) * 1000.0; if (taken_ms < 0.1) { - DEBUG_LOG(G3D, "Pipeline (x/%d) time on %s: %0.2f ms, %0.2f ms since scheduling (fast) rpType: %04x sampleBits: %d (%s)", + DEBUG_LOG(Log::G3D, "Pipeline (x/%d) time on %s: %0.2f ms, %0.2f ms since scheduling (fast) rpType: %04x sampleBits: %d (%s)", countToCompile, GetCurrentThreadName(), taken_ms, taken_ms_since_scheduling, (u32)rpType, (u32)sampleCount, tag_.c_str()); } else { - INFO_LOG(G3D, "Pipeline (x/%d) time on %s: %0.2f ms, %0.2f ms since scheduling rpType: %04x sampleBits: %d (%s)", + INFO_LOG(Log::G3D, "Pipeline (x/%d) time on %s: %0.2f ms, %0.2f ms since scheduling rpType: %04x sampleBits: %d (%s)", countToCompile, GetCurrentThreadName(), taken_ms, taken_ms_since_scheduling, (u32)rpType, (u32)sampleCount, tag_.c_str()); } @@ -144,12 +144,12 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR // // At least create a null placeholder to avoid creating over and over if something is broken. pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); - ERROR_LOG(G3D, "Failed creating graphics pipeline! VK_INCOMPLETE"); + ERROR_LOG(Log::G3D, "Failed creating graphics pipeline! VK_INCOMPLETE"); LogCreationFailure(); success = false; } else if (result != VK_SUCCESS) { pipeline[(size_t)rpType]->Post(VK_NULL_HANDLE); - ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); + ERROR_LOG(Log::G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); LogCreationFailure(); success = false; } else { @@ -228,13 +228,13 @@ u32 VKRGraphicsPipeline::GetVariantsBitmask() const { } void VKRGraphicsPipeline::LogCreationFailure() const { - ERROR_LOG(G3D, "vs: %s\n[END VS]", desc->vertexShaderSource.c_str()); - ERROR_LOG(G3D, "fs: %s\n[END FS]", desc->fragmentShaderSource.c_str()); + ERROR_LOG(Log::G3D, "vs: %s\n[END VS]", desc->vertexShaderSource.c_str()); + ERROR_LOG(Log::G3D, "fs: %s\n[END FS]", desc->fragmentShaderSource.c_str()); if (desc->geometryShader) { - ERROR_LOG(G3D, "gs: %s\n[END GS]", desc->geometryShaderSource.c_str()); + ERROR_LOG(Log::G3D, "gs: %s\n[END GS]", desc->geometryShaderSource.c_str()); } // TODO: Maybe log various other state? - ERROR_LOG(G3D, "======== END OF PIPELINE =========="); + ERROR_LOG(Log::G3D, "======== END OF PIPELINE =========="); } struct SinglePipelineTask { @@ -310,7 +310,7 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan, bool useThread, bool VulkanRenderManager::CreateBackbuffers() { if (!vulkan_->GetSwapchain()) { - ERROR_LOG(G3D, "No swapchain - can't create backbuffers"); + ERROR_LOG(Log::G3D, "No swapchain - can't create backbuffers"); return false; } @@ -328,7 +328,7 @@ bool VulkanRenderManager::CreateBackbuffers() { } if (newInflightFrames_ != -1) { - INFO_LOG(G3D, "Updating inflight frames to %d", newInflightFrames_); + INFO_LOG(Log::G3D, "Updating inflight frames to %d", newInflightFrames_); vulkan_->UpdateInflightFrames(newInflightFrames_); newInflightFrames_ = -1; } @@ -356,14 +356,14 @@ void VulkanRenderManager::StartThreads() { runCompileThread_ = true; // For controlling the compiler thread's exit if (useRenderThread_) { - INFO_LOG(G3D, "Starting Vulkan submission thread"); + INFO_LOG(Log::G3D, "Starting Vulkan submission thread"); renderThread_ = std::thread(&VulkanRenderManager::RenderThreadFunc, this); } - INFO_LOG(G3D, "Starting Vulkan compiler thread"); + INFO_LOG(Log::G3D, "Starting Vulkan compiler thread"); compileThread_ = std::thread(&VulkanRenderManager::CompileThreadFunc, this); if (measurePresentTime_ && vulkan_->Extensions().KHR_present_wait && vulkan_->GetPresentMode() == VK_PRESENT_MODE_FIFO_KHR) { - INFO_LOG(G3D, "Starting Vulkan present wait thread"); + INFO_LOG(Log::G3D, "Starting Vulkan present wait thread"); presentWaitThread_ = std::thread(&VulkanRenderManager::PresentWaitThreadFunc, this); } } @@ -385,7 +385,7 @@ void VulkanRenderManager::StopThreads() { pushCondVar_.notify_one(); // Once the render thread encounters the above exit task, it'll exit. renderThread_.join(); - INFO_LOG(G3D, "Vulkan submission thread joined. Frame=%d", vulkan_->GetCurFrame()); + INFO_LOG(Log::G3D, "Vulkan submission thread joined. Frame=%d", vulkan_->GetCurFrame()); } for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { @@ -406,7 +406,7 @@ void VulkanRenderManager::StopThreads() { presentWaitThread_.join(); } - INFO_LOG(G3D, "Vulkan compiler thread joined. Now wait for any straggling compile tasks."); + INFO_LOG(Log::G3D, "Vulkan compiler thread joined. Now wait for any straggling compile tasks."); CreateMultiPipelinesTask::WaitForAll(); { @@ -431,7 +431,7 @@ void VulkanRenderManager::CheckNothingPending() { } VulkanRenderManager::~VulkanRenderManager() { - INFO_LOG(G3D, "VulkanRenderManager destructor"); + INFO_LOG(Log::G3D, "VulkanRenderManager destructor"); { std::unique_lock lock(compileMutex_); @@ -507,7 +507,7 @@ void VulkanRenderManager::CompileThreadFunc() { auto &shaders = iter.first; auto &entries = iter.second; - // NOTICE_LOG(G3D, "For this shader pair, we have %d pipelines to create", (int)entries.size()); + // NOTICE_LOG(Log::G3D, "For this shader pair, we have %d pipelines to create", (int)entries.size()); Task *task = new CreateMultiPipelinesTask(vulkan_, entries); g_threadManager.EnqueueTask(task); @@ -563,6 +563,7 @@ void VulkanRenderManager::RenderThreadFunc() { void VulkanRenderManager::PresentWaitThreadFunc() { SetCurrentThreadName("PresentWait"); +#if !PPSSPP_PLATFORM(IOS_APP_STORE) _dbg_assert_(vkWaitForPresentKHR != nullptr); uint64_t waitedId = frameIdGen_; @@ -579,8 +580,9 @@ void VulkanRenderManager::PresentWaitThreadFunc() { } _dbg_assert_(waitedId <= frameIdGen_); } +#endif - INFO_LOG(G3D, "Leaving PresentWaitThreadFunc()"); + INFO_LOG(Log::G3D, "Leaving PresentWaitThreadFunc()"); } void VulkanRenderManager::PollPresentTiming() { @@ -766,12 +768,12 @@ void VulkanRenderManager::ReportBadStateForDraw() { std::string str = VulkanQueueRunner::StepToString(vulkan_, *curRenderStep_); truncate_cpy(cause2, str.c_str()); } - ERROR_LOG_REPORT_ONCE(baddraw, G3D, "Can't draw: %s%s. Step count: %d", cause1, cause2, (int)steps_.size()); + ERROR_LOG_REPORT_ONCE(baddraw, Log::G3D, "Can't draw: %s%s. Step count: %d", cause1, cause2, (int)steps_.size()); } VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, bool cacheLoad, const char *tag) { if (!desc->vertexShader || !desc->fragmentShader) { - ERROR_LOG(G3D, "Can't create graphics pipeline with missing vs/ps: %p %p", desc->vertexShader, desc->fragmentShader); + ERROR_LOG(Log::G3D, "Can't create graphics pipeline with missing vs/ps: %p %p", desc->vertexShader, desc->fragmentShader); return nullptr; } @@ -783,7 +785,7 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe pipelinesToCheck_.push_back(pipeline); } else { if (!variantBitmask) { - WARN_LOG(G3D, "WARNING: Will not compile any variants of pipeline, not in renderpass and empty variantBitmask"); + WARN_LOG(Log::G3D, "WARNING: Will not compile any variants of pipeline, not in renderpass and empty variantBitmask"); } // Presumably we're in initialization, loading the shader cache. // Look at variantBitmask to see what variants we should queue up. @@ -801,12 +803,12 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe // Sanity check - don't compile incompatible types (could be caused by corrupt caches, changes in data structures, etc). if ((pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) && !RenderPassTypeHasDepth(rpType)) { - WARN_LOG(G3D, "Not compiling pipeline that requires depth, for non depth renderpass type"); + WARN_LOG(Log::G3D, "Not compiling pipeline that requires depth, for non depth renderpass type"); continue; } // Shouldn't hit this, these should have been filtered elsewhere. However, still a good check to do. if (sampleCount == VK_SAMPLE_COUNT_1_BIT && RenderPassTypeHasMultisample(rpType)) { - WARN_LOG(G3D, "Not compiling single sample pipeline for a multisampled render pass type"); + WARN_LOG(Log::G3D, "Not compiling single sample pipeline for a multisampled render pass type"); continue; } @@ -839,7 +841,7 @@ void VulkanRenderManager::EndCurRenderStep() { RenderPassType rpType = depthStencil ? RenderPassType::HAS_DEPTH : RenderPassType::DEFAULT; if (curRenderStep_->render.framebuffer && (rpType & RenderPassType::HAS_DEPTH) && !curRenderStep_->render.framebuffer->HasDepth()) { - WARN_LOG(G3D, "Trying to render with a depth-writing pipeline to a framebuffer without depth: %s", curRenderStep_->render.framebuffer->Tag()); + WARN_LOG(Log::G3D, "Trying to render with a depth-writing pipeline to a framebuffer without depth: %s", curRenderStep_->render.framebuffer->Tag()); rpType = RenderPassType::DEFAULT; } @@ -898,6 +900,7 @@ void VulkanRenderManager::EndCurRenderStep() { void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) { _dbg_assert_(insideFrame_); + // Eliminate dupes (bind of the framebuffer we already are rendering to), instantly convert to a clear if possible. if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) { u32 clearMask = 0; @@ -942,6 +945,10 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR } } +#ifdef _DEBUG + SanityCheckPassesOnAdd(); +#endif + // More redundant bind elimination. if (curRenderStep_) { if (curRenderStep_->commands.empty()) { @@ -1082,7 +1089,7 @@ bool VulkanRenderManager::CopyFramebufferToMemory(VKRFramebuffer *src, VkImageAs } else { // Backbuffer. if (!(vulkan_->GetSurfaceCapabilities().supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) { - ERROR_LOG(G3D, "Copying from backbuffer not supported, can't take screenshots"); + ERROR_LOG(Log::G3D, "Copying from backbuffer not supported, can't take screenshots"); return false; } switch (vulkan_->GetSwapchainFormat()) { @@ -1090,7 +1097,7 @@ bool VulkanRenderManager::CopyFramebufferToMemory(VKRFramebuffer *src, VkImageAs case VK_FORMAT_R8G8B8A8_UNORM: srcFormat = Draw::DataFormat::R8G8B8A8_UNORM; break; // NOTE: If you add supported formats here, make sure to also support them in VulkanQueueRunner::CopyReadbackBuffer. default: - ERROR_LOG(G3D, "Unsupported backbuffer format for screenshots"); + ERROR_LOG(Log::G3D, "Unsupported backbuffer format for screenshots"); return false; } } @@ -1209,7 +1216,7 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten if (clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (curRenderStep_->render.framebuffer && !curRenderStep_->render.framebuffer->HasDepth()) { - WARN_LOG(G3D, "Trying to clear depth/stencil on a non-depth framebuffer: %s", curRenderStep_->render.framebuffer->Tag()); + WARN_LOG(Log::G3D, "Trying to clear depth/stencil on a non-depth framebuffer: %s", curRenderStep_->render.framebuffer->Tag()); } else { curPipelineFlags_ |= PipelineFlags::USES_DEPTH_STENCIL; } @@ -1231,6 +1238,10 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten } void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag) { +#ifdef _DEBUG + SanityCheckPassesOnAdd(); +#endif + _dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x); _dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y); _dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width); @@ -1295,6 +1306,10 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, } void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag) { +#ifdef _DEBUG + SanityCheckPassesOnAdd(); +#endif + _dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x); _dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y); _dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width); @@ -1847,3 +1862,14 @@ void VKRPipelineLayout::FlushDescSets(VulkanContext *vulkan, int frame, QueuePro profile->descriptorsWritten += writeCount; profile->descriptorsDeduped += dedupCount; } + +void VulkanRenderManager::SanityCheckPassesOnAdd() { +#if _DEBUG + // Check that we don't have any previous passes that write to the backbuffer, that must ALWAYS be the last one. + for (int i = 0; i < steps_.size(); i++) { + if (steps_[i]->stepType == VKRStepType::RENDER) { + _dbg_assert_(steps_[i]->render.framebuffer != nullptr); + } + } +#endif +} diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 44031a54fa..c1af6cc342 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -90,6 +90,7 @@ public: VkDynamicState dynamicStates[6]{}; VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; + VkPipelineRasterizationProvokingVertexStateCreateInfoEXT rs_provoking{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT }; // Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish. Promise *vertexShader = nullptr; @@ -533,6 +534,10 @@ public: void StartThreads(); void StopThreads(); + size_t GetNumSteps() const { + return steps_.size(); + } + private: void EndCurRenderStep(); @@ -550,6 +555,8 @@ private: void ResetDescriptorLists(int frame); void FlushDescriptors(int frame); + void SanityCheckPassesOnAdd(); + FrameDataShared frameDataShared_; FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index eaace00be0..1101d38e25 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -221,7 +221,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con std::vector spirv; std::string errorMessage; if (!GLSLtoSPV(vkstage_, source_.c_str(), GLSLVariant::VULKAN, spirv, &errorMessage)) { - WARN_LOG(G3D, "Shader compile to module failed (%s): %s", tag_.c_str(), errorMessage.c_str()); + WARN_LOG(Log::G3D, "Shader compile to module failed (%s): %s", tag_.c_str(), errorMessage.c_str()); return false; } @@ -239,7 +239,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con module_ = Promise::AlreadyDone(shaderModule); ok_ = true; } else { - WARN_LOG(G3D, "vkCreateShaderModule failed (%s)", tag_.c_str()); + WARN_LOG(Log::G3D, "vkCreateShaderModule failed (%s)", tag_.c_str()); ok_ = false; } return ok_; @@ -380,6 +380,13 @@ public: VKContext(VulkanContext *vulkan, bool useRenderThread); ~VKContext(); + BackendState GetCurrentBackendState() const override { + return BackendState{ + (u32)renderManager_.GetNumSteps(), + true, + }; + } + void DebugAnnotate(const char *annotation) override; void Wait() override { vkDeviceWaitIdle(vulkan_->GetDevice()); @@ -699,8 +706,10 @@ VulkanTexture *VKContext::GetNullTexture() { nullTexture_ = new VulkanTexture(vulkan_, "Null"); int w = 8; int h = 8; - nullTexture_->CreateDirect(cmdInit, w, h, 1, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + VulkanBarrierBatch barrier; + nullTexture_->CreateDirect(w, h, 1, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, &barrier); + barrier.Flush(cmdInit); uint32_t bindOffset; VkBuffer bindBuf; uint32_t *data = (uint32_t *)push_->Allocate(w * h * 4, 4, &bindBuf, &bindOffset); @@ -772,7 +781,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, Vu // Zero-sized textures not allowed. _assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1! if (desc.width * desc.height * desc.depth <= 0) { - ERROR_LOG(G3D, "Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth); + ERROR_LOG(Log::G3D, "Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth); return false; } _dbg_assert_(pushBuffer); @@ -791,10 +800,12 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, Vu VkComponentMapping r8AsAlpha[4] = { VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_R }; - if (!vkTex_->CreateDirect(cmd, width_, height_, 1, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits, desc.swizzle == TextureSwizzle::R8_AS_ALPHA ? r8AsAlpha : nullptr)) { - ERROR_LOG(G3D, "Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_); + VulkanBarrierBatch barrier; + if (!vkTex_->CreateDirect(width_, height_, 1, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits, &barrier, desc.swizzle == TextureSwizzle::R8_AS_ALPHA ? r8AsAlpha : nullptr)) { + ERROR_LOG(Log::G3D, "Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_); return false; } + barrier.Flush(cmd); VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; if (desc.initData.size()) { UpdateInternal(cmd, pushBuffer, desc.initData.data(), desc.initDataCallback, (int)desc.initData.size()); @@ -902,6 +913,9 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread) caps_.sampleRateShadingSupported = vulkan->GetDeviceFeatures().enabled.standard.sampleRateShading != 0; caps_.textureSwizzleSupported = true; + // Note that it must also be enabled on the pipelines (which we do). + caps_.provokingVertexLast = vulkan->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast; + // Present mode stuff caps_.presentMaxInterval = 1; caps_.presentInstantModeChange = false; // TODO: Fix this with some work in VulkanContext @@ -929,7 +943,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread) case VULKAN_VENDOR_APPLE: caps_.vendor = GPUVendor::VENDOR_APPLE; break; case VULKAN_VENDOR_MESA: caps_.vendor = GPUVendor::VENDOR_MESA; break; default: - WARN_LOG(G3D, "Unknown vendor ID %08x", deviceProps.vendorID); + WARN_LOG(Log::G3D, "Unknown vendor ID %08x", deviceProps.vendorID); caps_.vendor = GPUVendor::VENDOR_UNKNOWN; break; } @@ -1040,11 +1054,9 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread) } if (!vulkan->Extensions().KHR_depth_stencil_resolve) { - INFO_LOG(G3D, "KHR_depth_stencil_resolve not supported, disabling multisampling"); + INFO_LOG(Log::G3D, "KHR_depth_stencil_resolve not supported, disabling multisampling"); } - bugs_.Infest(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI); - // We limit multisampling functionality to reasonably recent and known-good tiling GPUs. if (multisampleAllowed) { // Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess @@ -1053,9 +1065,9 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread) const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve; if (((resolveProperties.supportedDepthResolveModes & resolveProperties.supportedStencilResolveModes) & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) { caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts); - INFO_LOG(G3D, "Multisample levels mask: %d", caps_.multiSampleLevelsMask); + INFO_LOG(Log::G3D, "Multisample levels mask: %d", caps_.multiSampleLevelsMask); } else { - INFO_LOG(G3D, "Not enough depth/stencil resolve modes supported, disabling multisampling."); + INFO_LOG(Log::G3D, "Not enough depth/stencil resolve modes supported, disabling multisampling."); caps_.multiSampleLevelsMask = 1; } } else { @@ -1187,7 +1199,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char } else if (vkshader->GetStage() == ShaderStage::Fragment) { gDesc.fragmentShader = vkshader->Get(); } else { - ERROR_LOG(G3D, "Bad stage"); + ERROR_LOG(Log::G3D, "Bad stage"); delete pipeline; return nullptr; } @@ -1212,8 +1224,6 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char gDesc.dss = depth->info; - raster->ToVulkan(&gDesc.rs); - // Copy bindings from input layout. gDesc.topology = primToVK[(int)desc.prim]; @@ -1235,6 +1245,11 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; raster->ToVulkan(&gDesc.rs); + if (renderManager_.GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) { + ChainStruct(gDesc.rs, &gDesc.rs_provoking); + gDesc.rs_provoking.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT; + } + pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, false, tag ? tag : "thin3d"); if (desc.uniformDesc) { @@ -1300,14 +1315,14 @@ Texture *VKContext::CreateTexture(const TextureDesc &desc) { VkCommandBuffer initCmd = renderManager_.GetInitCmd(); if (!push_ || !initCmd) { // Too early! Fail. - ERROR_LOG(G3D, "Can't create textures before the first frame has started."); + ERROR_LOG(Log::G3D, "Can't create textures before the first frame has started."); return nullptr; } VKTexture *tex = new VKTexture(vulkan_, initCmd, push_, desc); if (tex->Create(initCmd, &renderManager_.PostInitBarrier(), push_, desc)) { return tex; } else { - ERROR_LOG(G3D, "Failed to create texture"); + ERROR_LOG(Log::G3D, "Failed to create texture"); tex->Release(); return nullptr; } @@ -1317,7 +1332,7 @@ void VKContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, Text VkCommandBuffer initCmd = renderManager_.GetInitCmd(); if (!push_ || !initCmd) { // Too early! Fail. - ERROR_LOG(G3D, "Can't create textures before the first frame has started."); + ERROR_LOG(Log::G3D, "Can't create textures before the first frame has started."); return; } @@ -1429,7 +1444,7 @@ ShaderModule *VKContext::CreateShaderModule(ShaderStage stage, ShaderLanguage la if (shader->Compile(vulkan_, language, data, size)) { return shader; } else { - ERROR_LOG(G3D, "Failed to compile shader %s:\n%s", tag, (const char *)LineNumberString((const char *)data).c_str()); + ERROR_LOG(Log::G3D, "Failed to compile shader %s:\n%s", tag, (const char *)LineNumberString((const char *)data).c_str()); shader->Release(); return nullptr; } @@ -1555,6 +1570,7 @@ std::vector VKContext::GetFeatureList() const { AddFeature(features, "multiviewGeometryShader", vulkan_->GetDeviceFeatures().available.multiview.multiviewGeometryShader, vulkan_->GetDeviceFeatures().enabled.multiview.multiviewGeometryShader); AddFeature(features, "presentId", vulkan_->GetDeviceFeatures().available.presentId.presentId, vulkan_->GetDeviceFeatures().enabled.presentId.presentId); AddFeature(features, "presentWait", vulkan_->GetDeviceFeatures().available.presentWait.presentWait, vulkan_->GetDeviceFeatures().enabled.presentWait.presentWait); + AddFeature(features, "provokingVertexLast", vulkan_->GetDeviceFeatures().available.provokingVertex.provokingVertexLast, vulkan_->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast); features.emplace_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat)); diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index d98f53667a..bd93cd133c 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -601,7 +601,7 @@ void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, u case Draw::DataFormat::R8G8B8A8_UNORM: case Draw::DataFormat::UNDEFINED: default: - WARN_LOG(G3D, "Unable to convert from format: %d", (int)format); + WARN_LOG(Log::G3D, "Unable to convert from format: %d", (int)format); break; } } @@ -663,7 +663,7 @@ void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, u case Draw::DataFormat::R8G8B8A8_UNORM: case Draw::DataFormat::UNDEFINED: default: - WARN_LOG(G3D, "Unable to convert from format to BGRA: %d", (int)format); + WARN_LOG(Log::G3D, "Unable to convert from format to BGRA: %d", (int)format); break; } } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 83101eeb1c..b1a9f94487 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -612,7 +612,7 @@ struct DeviceCaps { bool setMaxFrameLatencySupported; bool textureSwizzleSupported; bool requiresHalfPixelOffset; - + bool provokingVertexLast; // GL behavior, what the PSP does bool verySlowShaderCompiler; // From the other backends, we can detect if D3D9 support is known bad (like on Xe) and disable it. @@ -687,6 +687,11 @@ enum class DebugFlags { }; ENUM_CLASS_BITOPS(DebugFlags); +struct BackendState { + u32 passes; + bool valid; +}; + class DrawContext { public: virtual ~DrawContext(); @@ -705,6 +710,10 @@ public: virtual std::vector GetPresentModeList(std::string_view currentMarkerString) const { return std::vector(); } virtual std::vector GetSurfaceFormatList() const { return std::vector(); } + virtual BackendState GetCurrentBackendState() const { + return BackendState{}; + } + // Describes the primary shader language that this implementation prefers. const ShaderLanguageDesc &GetShaderLanguageDesc() { return shaderLanguageDesc_; diff --git a/Common/Input/InputState.cpp b/Common/Input/InputState.cpp index 4daa5df990..1d94e8d590 100644 --- a/Common/Input/InputState.cpp +++ b/Common/Input/InputState.cpp @@ -26,7 +26,6 @@ const char *GetDeviceName(int deviceId) { case DEVICE_ID_XINPUT_3: return "x360_4"; case DEVICE_ID_ACCELEROMETER: return "accelerometer"; case DEVICE_ID_MOUSE: return "mouse"; - case DEVICE_ID_XR_HMD: return "xr_hmd"; case DEVICE_ID_XR_CONTROLLER_LEFT: return "xr_l"; case DEVICE_ID_XR_CONTROLLER_RIGHT: return "xr_r"; default: diff --git a/Common/Input/InputState.h b/Common/Input/InputState.h index bc604ebb2c..2e74836de9 100644 --- a/Common/Input/InputState.h +++ b/Common/Input/InputState.h @@ -32,7 +32,6 @@ enum InputDeviceID { DEVICE_ID_XINPUT_2 = 22, DEVICE_ID_XINPUT_3 = 23, DEVICE_ID_ACCELEROMETER = 30, // no longer used - DEVICE_ID_XR_HMD = 39, DEVICE_ID_XR_CONTROLLER_LEFT = 40, DEVICE_ID_XR_CONTROLLER_RIGHT = 41, DEVICE_ID_TOUCH = 42, diff --git a/Common/Input/KeyCodes.h b/Common/Input/KeyCodes.h index 8614e5a2d2..b8a53113a9 100644 --- a/Common/Input/KeyCodes.h +++ b/Common/Input/KeyCodes.h @@ -246,19 +246,6 @@ enum InputKeyCode { NKCODE_EXT_MOUSEWHEEL_UP = 1008, NKCODE_EXT_MOUSEWHEEL_DOWN = 1009, - // Virtual reality motion - NKCODE_EXT_MOTION_UP = 1101, - NKCODE_EXT_MOTION_DOWN = 1102, - NKCODE_EXT_MOTION_LEFT = 1103, - NKCODE_EXT_MOTION_RIGHT = 1104, - NKCODE_EXT_MOTION_FORWARD = 1105, - - // Virtual reality rotation - NKCODE_EXT_ROTATION_UP = 1111, - NKCODE_EXT_ROTATION_DOWN = 1112, - NKCODE_EXT_ROTATION_LEFT = 1113, - NKCODE_EXT_ROTATION_RIGHT = 1114, - NKCODE_MAX }; diff --git a/Common/Log.cpp b/Common/Log.cpp index 988e51f439..d5b0e62005 100644 --- a/Common/Log.cpp +++ b/Common/Log.cpp @@ -37,9 +37,10 @@ static bool hitAnyAsserts = false; -std::mutex g_extraAssertInfoMutex; -std::string g_extraAssertInfo = "menu"; -double g_assertInfoTime = 0.0; +static std::mutex g_extraAssertInfoMutex; +static std::string g_extraAssertInfo = "menu"; +static double g_assertInfoTime = 0.0; +static bool g_exitOnAssert; void SetExtraAssertInfo(const char *info) { std::lock_guard guard(g_extraAssertInfoMutex); @@ -47,6 +48,10 @@ void SetExtraAssertInfo(const char *info) { g_assertInfoTime = time_now_d(); } +void SetCleanExitOnAssert() { + g_exitOnAssert = true; +} + bool HandleAssert(const char *function, const char *file, int line, const char *expression, const char* format, ...) { // Read message and write it to the log char text[LOG_BUF_SIZE]; @@ -65,8 +70,8 @@ bool HandleAssert(const char *function, const char *file, int line, const char * } // Normal logging (will also log to Android log) - ERROR_LOG(SYSTEM, "%s", formatted); - // Also do a simple printf for good measure, in case logging of SYSTEM is disabled (should we disallow that?) + ERROR_LOG(Log::System, "%s", formatted); + // Also do a simple printf for good measure, in case logging of System is disabled (should we disallow that?) fprintf(stderr, "%s\n", formatted); hitAnyAsserts = true; @@ -78,8 +83,13 @@ bool HandleAssert(const char *function, const char *file, int line, const char * std::wstring wtext = ConvertUTF8ToWString(formatted) + L"\n\nTry to continue?"; std::wstring wcaption = ConvertUTF8ToWString(std::string(caption) + " " + GetCurrentThreadName()); OutputDebugString(wtext.c_str()); + printf("%s\n", formatted); if (IDYES != MessageBox(0, wtext.c_str(), wcaption.c_str(), msgBoxStyle)) { - return false; + if (g_exitOnAssert) { + // Hard exit. + ExitProcess(1); + return false; + } } else { return true; } diff --git a/Common/Log.h b/Common/Log.h index 91b834b7fa..b3375a4d10 100644 --- a/Common/Log.h +++ b/Common/Log.h @@ -27,41 +27,41 @@ #define VERBOSE_LEVEL 6 // Noisy debugging - sometimes needed but usually unimportant. // NOTE: Needs to be kept in sync with the g_logTypeNames array. -enum class LogType { - SYSTEM = 0, // Catch-all for uncategorized things - BOOT, - COMMON, +enum class Log { + System = 0, // Catch-all for uncategorized things + Boot, + Common, CPU, - FILESYS, + FileSystem, G3D, HLE, // dumping ground that we should get rid of JIT, - LOADER, + Loader, ME, - MEMMAP, - SASMIX, - SAVESTATE, - FRAMEBUF, - AUDIO, + MemMap, + SasMix, + SaveState, + FrameBuf, + Audio, IO, - ACHIEVEMENTS, + Achievements, HTTP, - PRINTF, + Printf, - SCEAUDIO, - SCECTRL, - SCEDISPLAY, - SCEFONT, - SCEGE, - SCEINTC, - SCEIO, - SCEKERNEL, - SCEMODULE, - SCENET, - SCERTC, - SCESAS, - SCEUTILITY, - SCEMISC, + sceAudio, + sceCtrl, + sceDisplay, + sceFont, + sceGe, + sceIntc, + sceIo, + sceKernel, + sceModule, + sceNet, + sceRtc, + sceSas, + sceUtility, + sceMisc, NUMBER_OF_LOGS, // Must be last }; @@ -75,13 +75,12 @@ enum class LogLevel : int { LVERBOSE = VERBOSE_LEVEL, }; -void GenericLog(LogLevel level, LogType type, - const char *file, int line, const char *fmt, ...) +void GenericLog(LogLevel level, Log type, const char *file, int line, const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 5, 6))) #endif ; -bool GenericLogEnabled(LogLevel level, LogType type); +bool GenericLogEnabled(LogLevel level, Log type); // Exception for Windows - enable more log levels in release mode than on other platforms. #if defined(_DEBUG) || defined(_WIN32) @@ -104,12 +103,12 @@ bool GenericLogEnabled(LogLevel level, LogType type); GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ } -#define ERROR_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LERROR, __VA_ARGS__) } while (false) -#define WARN_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LWARNING, __VA_ARGS__) } while (false) -#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LNOTICE, __VA_ARGS__) } while (false) -#define INFO_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LINFO, __VA_ARGS__) } while (false) -#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LDEBUG, __VA_ARGS__) } while (false) -#define VERBOSE_LOG(t,...) do { GENERIC_LOG(LogType::t, LogLevel::LVERBOSE, __VA_ARGS__) } while (false) +#define ERROR_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LERROR, __VA_ARGS__) } while (false) +#define WARN_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LWARNING, __VA_ARGS__) } while (false) +#define NOTICE_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LNOTICE, __VA_ARGS__) } while (false) +#define INFO_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LINFO, __VA_ARGS__) } while (false) +#define DEBUG_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LDEBUG, __VA_ARGS__) } while (false) +#define VERBOSE_LOG(t,...) do { GENERIC_LOG(t, LogLevel::LVERBOSE, __VA_ARGS__) } while (false) // Currently only actually shows a dialog box on Windows. bool HandleAssert(const char *function, const char *file, int line, const char *expression, const char* format, ...) @@ -121,6 +120,7 @@ __attribute__((format(printf, 5, 6))) bool HitAnyAsserts(); void ResetHitAnyAsserts(); void SetExtraAssertInfo(const char *info); +void SetCleanExitOnAssert(); #if defined(__ANDROID__) // Tricky macro to get the basename, that also works if *built* on Win32. diff --git a/Common/ConsoleListener.cpp b/Common/Log/ConsoleListener.cpp similarity index 62% rename from Common/ConsoleListener.cpp rename to Common/Log/ConsoleListener.cpp index 35fa1e5e05..e1c49461fe 100644 --- a/Common/ConsoleListener.cpp +++ b/Common/Log/ConsoleListener.cpp @@ -15,85 +15,64 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#include "ppsspp_config.h" + +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) #include #include // min +#include #include #include // System: To be able to add strings with "+" #include -#ifdef _WIN32 #include -#include "CommonWindows.h" -#include -#else -#include -#endif +#include "Common/CommonWindows.h" + #ifndef _MSC_VER #include #endif -#include "ppsspp_config.h" #include "Common/Thread/ThreadUtil.h" #include "Common/Data/Encoding/Utf8.h" #include "Common/CommonTypes.h" -#include "Common/ConsoleListener.h" +#include "Common/Log/ConsoleListener.h" #include "Common/StringUtils.h" -#if defined(USING_WIN_UI) const int LOG_PENDING_MAX = 120 * 10000; const int LOG_LATENCY_DELAY_MS = 20; const int LOG_SHUTDOWN_DELAY_MS = 250; const int LOG_MAX_DISPLAY_LINES = 4000; -int ConsoleListener::refCount = 0; -HANDLE ConsoleListener::hThread = NULL; -HANDLE ConsoleListener::hTriggerEvent = NULL; -CRITICAL_SECTION ConsoleListener::criticalSection; +static bool g_Initialized; -char *ConsoleListener::logPending = NULL; -std::atomic ConsoleListener::logPendingReadPos; -std::atomic ConsoleListener::logPendingWritePos; -#endif +ConsoleListener::ConsoleListener() : hidden_(true) { + useColor_ = true; -ConsoleListener::ConsoleListener() : bHidden(true) -{ -#if defined(USING_WIN_UI) - hConsole = NULL; - bUseColor = true; - if (hTriggerEvent == NULL) { - hTriggerEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + // useThread_ = false; + + if (useThread_ && !hTriggerEvent) { + hTriggerEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); InitializeCriticalSection(&criticalSection); - logPending = new char[LOG_PENDING_MAX]; + logPending_ = new char[LOG_PENDING_MAX]; } - ++refCount; -#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(SWITCH) - bUseColor = false; -#elif defined(_MSC_VER) - bUseColor = false; -#elif defined(__APPLE__) - // Xcode builtin terminal used for debugging does not support colours. - // Fortunately it can be detected with a TERM env variable. - bUseColor = isatty(fileno(stdout)) && getenv("TERM") != NULL; -#else - bUseColor = isatty(fileno(stdout)); -#endif + + _dbg_assert_(!g_Initialized); + g_Initialized = true; + + logPendingReadPos_.store(0); + logPendingWritePos_.store(0); } -ConsoleListener::~ConsoleListener() -{ +ConsoleListener::~ConsoleListener() { + g_Initialized = false; Close(); } -#if defined(_WIN32) // Handle console event -bool WINAPI ConsoleHandler(DWORD msgType) -{ - if (msgType == CTRL_C_EVENT) - { +bool WINAPI ConsoleHandler(DWORD msgType) { + if (msgType == CTRL_C_EVENT) { OutputDebugString(L"Ctrl-C!\n"); return TRUE; - } - else if (msgType == CTRL_CLOSE_EVENT) - { + } else if (msgType == CTRL_CLOSE_EVENT) { OutputDebugString(L"Close console window!\n"); return TRUE; } @@ -105,156 +84,110 @@ bool WINAPI ConsoleHandler(DWORD msgType) */ return FALSE; } -#endif - -// 100, 100, "Dolphin Log Console" // Open console window - width and height is the size of console window // Name is the window title -void ConsoleListener::Init(bool AutoOpen, int Width, int Height, const char *Title) -{ -#if defined(USING_WIN_UI) +void ConsoleListener::Init(bool AutoOpen, int Width, int Height) { openWidth_ = Width; openHeight_ = Height; - title_ = ConvertUTF8ToWString(Title); - - if (AutoOpen) - { + if (AutoOpen) { Open(); - bHidden = false; + hidden_ = false; } -#endif } -void ConsoleListener::Open() -{ -#if defined(USING_WIN_UI) - if (!GetConsoleWindow()) - { +void ConsoleListener::Open() { + if (!GetConsoleWindow()) { // Open the console window and create the window handle for GetStdHandle() AllocConsole(); hWnd = GetConsoleWindow(); ShowWindow(hWnd, SW_SHOWDEFAULT); // disable console close button - HMENU hMenu=GetSystemMenu(hWnd, false); + HMENU hMenu = GetSystemMenu(hWnd, false); EnableMenuItem(hMenu,SC_CLOSE,MF_GRAYED|MF_BYCOMMAND); // Save the window handle that AllocConsole() created hConsole = GetStdHandle(STD_OUTPUT_HANDLE); // Set console handler - if(SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE)){OutputDebugString(L"Console handler is installed!\n");} + if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE)) { + OutputDebugStringA("Console handler is installed!\n"); + } // Set the console window title - SetConsoleTitle(title_.c_str()); + SetConsoleTitle(L"PPSSPP Debug Console"); SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); // Set letter space LetterSpace(openWidth_, LOG_MAX_DISPLAY_LINES); //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); - } - else - { + } else { hConsole = GetStdHandle(STD_OUTPUT_HANDLE); } - if (hTriggerEvent != NULL && hThread == NULL) - hThread = (HANDLE)_beginthreadex(NULL, 0, &ConsoleListener::RunThread, this, 0, NULL); -#endif + if (useThread_ && hTriggerEvent != NULL && !thread_.joinable()) { + thread_ = std::thread([&] { + SetCurrentThreadName("Console"); + LogWriterThread(); + }); + } } -void ConsoleListener::Show(bool bShow) -{ -#if defined(USING_WIN_UI) - if (bShow && bHidden) - { - if (!IsOpen()) +void ConsoleListener::Show(bool bShow) { + if (bShow && hidden_) { + if (!IsOpen()) { Open(); + } ShowWindow(GetConsoleWindow(), SW_SHOW); - bHidden = false; - } - else if (!bShow && !bHidden) - { + hidden_ = false; + } else if (!bShow && !hidden_) { ShowWindow(GetConsoleWindow(), SW_HIDE); - bHidden = true; + hidden_ = true; } -#endif } - -void ConsoleListener::UpdateHandle() -{ -#if defined(USING_WIN_UI) +void ConsoleListener::UpdateHandle() { hConsole = GetStdHandle(STD_OUTPUT_HANDLE); -#endif } // Close the console window and close the eventual file handle -void ConsoleListener::Close() -{ -#if defined(USING_WIN_UI) - - if (--refCount <= 0) - { - if (hThread != NULL) - { - logPendingWritePos.store((u32)-1, std::memory_order_release); - - SetEvent(hTriggerEvent); - WaitForSingleObject(hThread, LOG_SHUTDOWN_DELAY_MS); - CloseHandle(hThread); - hThread = NULL; - } - if (hTriggerEvent != NULL) - { - DeleteCriticalSection(&criticalSection); - CloseHandle(hTriggerEvent); - hTriggerEvent = NULL; - } - if (logPending != NULL) - { - delete [] logPending; - logPending = NULL; - } - refCount = 0; +void ConsoleListener::Close() { + if (thread_.joinable()) { + logPendingWritePos_.store((u32)-1, std::memory_order_release); + SetEvent(hTriggerEvent); + thread_.join(); + } + if (hTriggerEvent) { + DeleteCriticalSection(&criticalSection); + CloseHandle(hTriggerEvent); + hTriggerEvent = nullptr; + } + if (logPending_) { + delete [] logPending_; + logPending_ = nullptr; } - if (hConsole != NULL) { + if (hConsole) { FreeConsole(); - hConsole = NULL; + hConsole = nullptr; } -#else - fflush(NULL); -#endif } -bool ConsoleListener::IsOpen() -{ -#if defined(USING_WIN_UI) - return (hConsole != NULL); -#else - return true; -#endif +bool ConsoleListener::IsOpen() { + return (hConsole != nullptr); } -/* - LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are - dependent on each other, that's the reason for the additional checks. -*/ -void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) -{ +// LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are +// dependent on each other, that's the reason for the additional checks. +void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) { _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); -#if defined(USING_WIN_UI) BOOL SB, SW; - if (BufferFirst) - { + if (BufferFirst) { // Change screen buffer size COORD Co = {(SHORT)BufferWidth, (SHORT)BufferHeight}; SB = SetConsoleScreenBufferSize(hConsole, Co); // Change the screen buffer window size SMALL_RECT coo = {(SHORT)0, (SHORT)0, (SHORT)ScreenWidth, (SHORT)ScreenHeight}; // top, left, right, bottom SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); - } - else - { + } else { // Change the screen buffer window size SMALL_RECT coo = {(SHORT)0, (SHORT)0, (SHORT)ScreenWidth, (SHORT)ScreenHeight}; // top, left, right, bottom SW = SetConsoleWindowInfo(hConsole, TRUE, &coo); @@ -262,22 +195,19 @@ void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int S COORD Co = {(SHORT)BufferWidth, (SHORT)BufferHeight}; SB = SetConsoleScreenBufferSize(hConsole, Co); } -#endif } -void ConsoleListener::LetterSpace(int Width, int Height) -{ + +void ConsoleListener::LetterSpace(int Width, int Height) { _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); -#if defined(USING_WIN_UI) // Get console info CONSOLE_SCREEN_BUFFER_INFO ConInfo; GetConsoleScreenBufferInfo(hConsole, &ConInfo); - // int OldBufferWidth = ConInfo.dwSize.X; int OldBufferHeight = ConInfo.dwSize.Y; int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left); int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top); - // + int NewBufferWidth = Width; int NewBufferHeight = Height; int NewScreenWidth = NewBufferWidth - 1; @@ -289,13 +219,10 @@ void ConsoleListener::LetterSpace(int Width, int Height) BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1)); // Resize the window too - //MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true); -#endif + // MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true); } -#if defined(USING_WIN_UI) -COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) -{ +COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) { COORD Ret = {0, 0}; // Full rows int Step = (int)floor((float)BytesRead / (float)BufferWidth); @@ -305,76 +232,65 @@ COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) return Ret; } -unsigned int WINAPI ConsoleListener::RunThread(void *lpParam) -{ - SetCurrentThreadName("Console"); - ConsoleListener *consoleLog = (ConsoleListener *)lpParam; - consoleLog->LogWriterThread(); - return 0; -} - -void ConsoleListener::LogWriterThread() -{ +void ConsoleListener::LogWriterThread() { char *logLocal = new char[LOG_PENDING_MAX]; int logLocalSize = 0; - while (true) - { + while (true) { WaitForSingleObject(hTriggerEvent, INFINITE); Sleep(LOG_LATENCY_DELAY_MS); - u32 logRemotePos = logPendingWritePos.load(std::memory_order_acquire); - if (logRemotePos == (u32) -1) + u32 logRemotePos = logPendingWritePos_.load(std::memory_order_acquire); + if (logRemotePos == (u32)-1) { break; - else if (logRemotePos == logPendingReadPos) + } else if (logRemotePos == logPendingReadPos_) { continue; - else - { + } else { EnterCriticalSection(&criticalSection); - logRemotePos = logPendingWritePos.load(std::memory_order_acquire); + logRemotePos = logPendingWritePos_.load(std::memory_order_acquire); int start = 0; - if (logRemotePos < logPendingReadPos) - { - const int count = LOG_PENDING_MAX - logPendingReadPos; - memcpy(logLocal + start, logPending + logPendingReadPos, count); + if (logRemotePos < logPendingReadPos_) { + const int count = LOG_PENDING_MAX - logPendingReadPos_; + memcpy(logLocal + start, logPending_ + logPendingReadPos_, count); start = count; - logPendingReadPos = 0; + logPendingReadPos_ = 0; } - const int count = logRemotePos - logPendingReadPos; - memcpy(logLocal + start, logPending + logPendingReadPos, count); + const int count = logRemotePos - logPendingReadPos_; + memcpy(logLocal + start, logPending_ + logPendingReadPos_, count); - logPendingReadPos += count; + logPendingReadPos_ += count; LeaveCriticalSection(&criticalSection); // Double check. - if (logPendingWritePos == (u32) -1) + if (logPendingWritePos_ == (u32)-1) { break; + } logLocalSize = start + count; } - for (char *Text = logLocal, *End = logLocal + logLocalSize; Text < End; ) - { + for (char *Text = logLocal, *End = logLocal + logLocalSize; Text < End; ) { LogLevel Level = LogLevel::LINFO; char *next = (char *) memchr(Text + 1, '\033', End - Text); size_t Len = next - Text; - if (next == NULL) + if (!next) { Len = End - Text; + } - if (Text[0] == '\033' && Text + 1 < End) - { + if (Text[0] == '\033' && Text + 1 < End) { Level = (LogLevel)(Text[1] - '0'); Len -= 2; Text += 2; } - // Make sure we didn't start quitting. This is kinda slow. - if (logPendingWritePos == (u32) -1) + // Make sure we didn't start quitting. This is kinda slow. + if (logPendingWritePos_ == (u32)-1) { break; + } WriteToConsole(Level, Text, Len); Text += Len; @@ -384,11 +300,11 @@ void ConsoleListener::LogWriterThread() delete [] logLocal; } -void ConsoleListener::SendToThread(LogLevel Level, const char *Text) -{ +void ConsoleListener::SendToThread(LogLevel Level, const char *Text) { // Oops, we're already quitting. Just do nothing. - if (logPendingWritePos == (u32) -1) + if (logPendingWritePos_ == (u32)-1) { return; + } int Len = (int)strlen(Text); if (Len > LOG_PENDING_MAX) @@ -396,8 +312,7 @@ void ConsoleListener::SendToThread(LogLevel Level, const char *Text) char ColorAttr[16] = ""; int ColorLen = 0; - if (bUseColor) - { + if (useColor_) { // Not ANSI, since the console doesn't support it, but ANSI-like. snprintf(ColorAttr, 16, "\033%d", Level); // For now, rather than properly support it. @@ -406,64 +321,58 @@ void ConsoleListener::SendToThread(LogLevel Level, const char *Text) } EnterCriticalSection(&criticalSection); - u32 logWritePos = logPendingWritePos.load(); + u32 logWritePos = logPendingWritePos_.load(); u32 prevLogWritePos = logWritePos; - if (logWritePos + ColorLen + Len >= LOG_PENDING_MAX) - { - for (int i = 0; i < ColorLen; ++i) - logPending[(logWritePos + i) % LOG_PENDING_MAX] = ColorAttr[i]; + if (logWritePos + ColorLen + Len >= LOG_PENDING_MAX) { + for (int i = 0; i < ColorLen; ++i) { + logPending_[(logWritePos + i) % LOG_PENDING_MAX] = ColorAttr[i]; + } logWritePos += ColorLen; if (logWritePos >= LOG_PENDING_MAX) logWritePos -= LOG_PENDING_MAX; int start = 0; - if (logWritePos < LOG_PENDING_MAX && logWritePos + Len >= LOG_PENDING_MAX) - { + if (logWritePos < LOG_PENDING_MAX && logWritePos + Len >= LOG_PENDING_MAX) { const int count = LOG_PENDING_MAX - logWritePos; - memcpy(logPending + logWritePos, Text, count); + memcpy(logPending_ + logWritePos, Text, count); start = count; logWritePos = 0; } const int count = Len - start; - if (count > 0) - { - memcpy(logPending + logWritePos, Text + start, count); + if (count > 0) { + memcpy(logPending_ + logWritePos, Text + start, count); logWritePos += count; } - } - else - { - memcpy(logPending + logWritePos, ColorAttr, ColorLen); - memcpy(logPending + logWritePos + ColorLen, Text, Len); + } else { + memcpy(logPending_ + logWritePos, ColorAttr, ColorLen); + memcpy(logPending_ + logWritePos + ColorLen, Text, Len); logWritePos += ColorLen + Len; } // Oops, we passed the read pos. - if (prevLogWritePos < logPendingReadPos && logWritePos >= logPendingReadPos) - { - char *nextNewline = (char *) memchr(logPending + logWritePos, '\n', LOG_PENDING_MAX - logWritePos); + if (prevLogWritePos < logPendingReadPos_ && logWritePos >= logPendingReadPos_) { + char *nextNewline = (char *) memchr(logPending_ + logWritePos, '\n', LOG_PENDING_MAX - logWritePos); if (nextNewline == NULL && logWritePos > 0) - nextNewline = (char *) memchr(logPending, '\n', logWritePos); + nextNewline = (char *) memchr(logPending_, '\n', logWritePos); // Okay, have it go right after the next newline. if (nextNewline != NULL) - logPendingReadPos = (u32)(nextNewline - logPending + 1); + logPendingReadPos_ = (u32)(nextNewline - logPending_ + 1); } // Double check we didn't start quitting. - if (logPendingWritePos == (u32) -1) { + if (logPendingWritePos_ == (u32) -1) { LeaveCriticalSection(&criticalSection); return; } - logPendingWritePos.store(logWritePos, std::memory_order::memory_order_release); + logPendingWritePos_.store(logWritePos, std::memory_order::memory_order_release); LeaveCriticalSection(&criticalSection); SetEvent(hTriggerEvent); } -void ConsoleListener::WriteToConsole(LogLevel Level, const char *Text, size_t Len) -{ +void ConsoleListener::WriteToConsole(LogLevel Level, const char *Text, size_t Len) { _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); /* @@ -499,8 +408,7 @@ void ConsoleListener::WriteToConsole(LogLevel Level, const char *Text, size_t Le Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; } - if (Len > 10) - { + if (Len > 10) { // First 10 chars white SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); int wlen = MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, NULL, NULL); @@ -514,12 +422,9 @@ void ConsoleListener::WriteToConsole(LogLevel Level, const char *Text, size_t Le MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, tempBuf, wlen); WriteConsole(hConsole, tempBuf, (DWORD)wlen, &cCharsWritten, NULL); } -#endif -void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) -{ +void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize) { _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); -#if defined(USING_WIN_UI) // Check size if (Width < 8 || Height < 12) return; @@ -546,8 +451,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool DWORD cAttrRead = ReadBufferSize; DWORD BytesRead = 0; - while (BytesRead < BufferSize) - { + while (BytesRead < BufferSize) { Str.resize(Str.size() + 1); if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) SLog += StringFromFormat("WriteConsoleOutputCharacter error"); @@ -577,8 +481,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool int BytesWritten = 0; DWORD cAttrWritten = 0; - for (size_t i = 0; i < Attr.size(); i++) - { + for (size_t i = 0; i < Attr.size(); i++) { if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) SLog += StringFromFormat("WriteConsoleOutputCharacter error"); if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) @@ -595,67 +498,40 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool // if (SLog.length() > 0) Log(LogLevel::LNOTICE, SLog.c_str()); // Resize the window too - if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true); -#endif + if (Resize) { + MoveWindow(GetConsoleWindow(), Left, Top, (Width + 100), Height, true); + } } void ConsoleListener::Log(const LogMessage &msg) { - char Text[2048]; - snprintf(Text, sizeof(Text), "%s %s %s", msg.timestamp, msg.header, msg.msg.c_str()); - Text[sizeof(Text) - 2] = '\n'; - Text[sizeof(Text) - 1] = '\0'; + char buf[2048]; + snprintf(buf, sizeof(buf), "%s %s %s", msg.timestamp, msg.header, msg.msg.c_str()); + buf[sizeof(buf) - 2] = '\n'; + buf[sizeof(buf) - 1] = '\0'; -#if defined(USING_WIN_UI) - if (hThread == NULL && IsOpen()) - WriteToConsole(msg.level, Text, strlen(Text)); + if (!useThread_ && IsOpen()) + WriteToConsole(msg.level, buf, strlen(buf)); else - SendToThread(msg.level, Text); -#else - char ColorAttr[16] = ""; - char ResetAttr[16] = ""; - - if (bUseColor) { - strcpy(ResetAttr, "\033[0m"); - switch (msg.level) { - case LogLevel::LNOTICE: // light green - strcpy(ColorAttr, "\033[92m"); - break; - case LogLevel::LERROR: // light red - strcpy(ColorAttr, "\033[91m"); - break; - case LogLevel::LWARNING: // light yellow - strcpy(ColorAttr, "\033[93m"); - break; - case LogLevel::LINFO: // cyan - strcpy(ColorAttr, "\033[96m"); - break; - case LogLevel::LDEBUG: // gray - strcpy(ColorAttr, "\033[90m"); - break; - default: - break; - } - } - fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr); -#endif + SendToThread(msg.level, buf); } + // Clear console screen -void ConsoleListener::ClearScreen(bool Cursor) -{ +void ConsoleListener::ClearScreen(bool Cursor) { _dbg_assert_msg_(IsOpen(), "Don't call this before opening the console."); -#if defined(USING_WIN_UI) - COORD coordScreen = { 0, 0 }; - DWORD cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD dwConSize; - GetConsoleScreenBufferInfo(hConsole, &csbi); - dwConSize = csbi.dwSize.X * csbi.dwSize.Y; + DWORD dwConSize = csbi.dwSize.X * csbi.dwSize.Y; // Write space to the entire console - FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); + DWORD cCharsWritten; + COORD coordScreen = { 0, 0 }; + FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); GetConsoleScreenBufferInfo(hConsole, &csbi); FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); // Reset cursor - if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); -#endif + if (Cursor) { + SetConsoleCursorPosition(hConsole, coordScreen); + } } + +#endif // PPSSPP_PLATFORM(WINDOWS) diff --git a/Common/ConsoleListener.h b/Common/Log/ConsoleListener.h similarity index 72% rename from Common/ConsoleListener.h rename to Common/Log/ConsoleListener.h index a84bb25765..15390d15d1 100644 --- a/Common/ConsoleListener.h +++ b/Common/Log/ConsoleListener.h @@ -17,20 +17,24 @@ #pragma once +// Windows-only. + +#include "ppsspp_config.h" + +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) + #include +#include -#include "LogManager.h" - -#ifdef _WIN32 -#include "CommonWindows.h" -#endif +#include "Common/Log/LogManager.h" +#include "Common/CommonWindows.h" class ConsoleListener : public LogListener { public: ConsoleListener(); ~ConsoleListener(); - void Init(bool AutoOpen = true, int Width = 200, int Height = 100, const char * Name = "DebugConsole (PPSSPP)"); + void Init(bool AutoOpen = true, int Width = 200, int Height = 100); void Open(); void UpdateHandle(); void Close(); @@ -38,38 +42,35 @@ public: void LetterSpace(int Width, int Height); void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst); void PixelSpace(int Left, int Top, int Width, int Height, bool); -#if defined(USING_WIN_UI) COORD GetCoordinates(int BytesRead, int BufferWidth); -#endif void Log(const LogMessage &message) override; void ClearScreen(bool Cursor = true); void Show(bool bShow); - bool Hidden() const { return bHidden; } + bool Hidden() const { return hidden_; } private: -#if defined(USING_WIN_UI) - HWND hWnd; - HANDLE hConsole; + HWND hWnd = nullptr; + HANDLE hConsole = nullptr; - static unsigned int WINAPI RunThread(void *lpParam); void LogWriterThread(); void SendToThread(LogLevel Level, const char *Text); void WriteToConsole(LogLevel Level, const char *Text, size_t Len); - static int refCount; - static HANDLE hThread; - static HANDLE hTriggerEvent; - static CRITICAL_SECTION criticalSection; + std::thread thread_; - static char *logPending; - static std::atomic logPendingReadPos; - static std::atomic logPendingWritePos; + HANDLE hTriggerEvent = nullptr; + CRITICAL_SECTION criticalSection{}; + + char *logPending_ = nullptr; + std::atomic logPendingReadPos_; + std::atomic logPendingWritePos_; int openWidth_ = 0; int openHeight_ = 0; - std::wstring title_; -#endif - bool bHidden; - bool bUseColor; + bool hidden_ = false; + bool useColor_ = true; + bool useThread_ = true; }; + +#endif diff --git a/Common/LogManager.cpp b/Common/Log/LogManager.cpp similarity index 87% rename from Common/LogManager.cpp rename to Common/Log/LogManager.cpp index cc3c6bf884..5b85b7d8a0 100644 --- a/Common/LogManager.cpp +++ b/Common/Log/LogManager.cpp @@ -28,8 +28,13 @@ #include "Common/Data/Encoding/Utf8.h" -#include "Common/LogManager.h" -#include "Common/ConsoleListener.h" +#include "Common/Log/LogManager.h" + +#if PPSSPP_PLATFORM(WINDOWS) +#include "Common/Log/ConsoleListener.h" +#endif + +#include "Common/Log/StdioListener.h" #include "Common/TimeUtil.h" #include "Common/File/FileUtil.h" #include "Common/StringUtils.h" @@ -47,14 +52,14 @@ static const char level_to_char[8] = "-NEWIDV"; #define LOG_MSC_OUTPUTDEBUG false #endif -void GenericLog(LogLevel level, LogType type, const char *file, int line, const char* fmt, ...) { +void GenericLog(LogLevel level, Log type, const char *file, int line, const char* fmt, ...) { if (g_bLogEnabledSetting && !(*g_bLogEnabledSetting)) return; va_list args; va_start(args, fmt); LogManager *instance = LogManager::GetInstance(); if (instance) { - instance->Log(level, type, file, line, fmt, args); + instance->LogLine(level, type, file, line, fmt, args); } else { // Fall back to printf or direct android logger with a small buffer if the log manager hasn't been initialized yet. #if PPSSPP_PLATFORM(ANDROID) @@ -69,7 +74,7 @@ void GenericLog(LogLevel level, LogType type, const char *file, int line, const va_end(args); } -bool GenericLogEnabled(LogLevel level, LogType type) { +bool GenericLogEnabled(LogLevel level, Log type) { if (LogManager::GetInstance()) return (*g_bLogEnabledSetting) && LogManager::GetInstance()->IsEnabled(level, type); return false; @@ -77,7 +82,7 @@ bool GenericLogEnabled(LogLevel level, LogType type) { LogManager *LogManager::logManager_ = NULL; -// NOTE: Needs to be kept in sync with the LogType enum. +// NOTE: Needs to be kept in sync with the Log enum. static const char * const g_logTypeNames[] = { "SYSTEM", "BOOT", @@ -118,7 +123,7 @@ static const char * const g_logTypeNames[] = { LogManager::LogManager(bool *enabledSetting) { g_bLogEnabledSetting = enabledSetting; - _dbg_assert_(ARRAY_SIZE(g_logTypeNames) == (size_t)LogType::NUMBER_OF_LOGS); + _dbg_assert_(ARRAY_SIZE(g_logTypeNames) == (size_t)Log::NUMBER_OF_LOGS); for (size_t i = 0; i < ARRAY_SIZE(g_logTypeNames); i++) { truncate_cpy(log_[i].m_shortName, g_logTypeNames[i]); @@ -137,10 +142,14 @@ LogManager::LogManager(bool *enabledSetting) { #else #if !defined(MOBILE_DEVICE) || defined(_DEBUG) fileLog_ = new FileLogListener(""); +#if PPSSPP_PLATFORM(WINDOWS) +#if !PPSSPP_PLATFORM(UWP) consoleLog_ = new ConsoleListener(); -#ifdef _WIN32 +#endif if (IsDebuggerPresent()) debuggerLog_ = new OutputDebugStringLogListener(); +#else + stdioLog_ = new StdioListener(); #endif #endif ringLog_ = new RingbufferLogListener(); @@ -148,7 +157,13 @@ LogManager::LogManager(bool *enabledSetting) { #if !defined(MOBILE_DEVICE) || defined(_DEBUG) AddListener(fileLog_); +#if PPSSPP_PLATFORM(WINDOWS) +#if !PPSSPP_PLATFORM(UWP) AddListener(consoleLog_); +#endif +#else + AddListener(stdioLog_); +#endif #if defined(_MSC_VER) && (defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP)) if (IsDebuggerPresent() && debuggerLog_ && LOG_MSC_OUTPUTDEBUG) AddListener(debuggerLog_); @@ -158,10 +173,13 @@ LogManager::LogManager(bool *enabledSetting) { } LogManager::~LogManager() { - for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; ++i) { + for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; ++i) { #if !defined(MOBILE_DEVICE) || defined(_DEBUG) RemoveListener(fileLog_); +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) RemoveListener(consoleLog_); +#endif + RemoveListener(stdioLog_); #if defined(_MSC_VER) && defined(USING_WIN_UI) RemoveListener(debuggerLog_); #endif @@ -174,7 +192,10 @@ LogManager::~LogManager() { if (fileLog_) delete fileLog_; #if !defined(MOBILE_DEVICE) || defined(_DEBUG) +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) delete consoleLog_; +#endif + delete stdioLog_; delete debuggerLog_; #endif delete ringLog_; @@ -194,14 +215,14 @@ void LogManager::ChangeFileLog(const char *filename) { } void LogManager::SaveConfig(Section *section) { - for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; i++) { + for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) { section->Set((std::string(log_[i].m_shortName) + "Enabled").c_str(), log_[i].enabled); section->Set((std::string(log_[i].m_shortName) + "Level").c_str(), (int)log_[i].level); } } void LogManager::LoadConfig(const Section *section, bool debugDefaults) { - for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; i++) { + for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) { bool enabled = false; int level = 0; section->Get((std::string(log_[i].m_shortName) + "Enabled").c_str(), &enabled, true); @@ -211,7 +232,7 @@ void LogManager::LoadConfig(const Section *section, bool debugDefaults) { } } -void LogManager::Log(LogLevel level, LogType type, const char *file, int line, const char *format, va_list args) { +void LogManager::LogLine(LogLevel level, Log type, const char *file, int line, const char *format, va_list args) { const LogChannel &log = log_[(size_t)type]; if (level > log.level || !log.enabled) return; @@ -234,7 +255,7 @@ void LogManager::Log(LogLevel level, LogType type, const char *file, int line, c file = fileshort + 1; } - GetTimeFormatted(message.timestamp); + GetCurrentTimeFormatted(message.timestamp); if (hleCurrentThreadName) { snprintf(message.header, sizeof(message.header), "%-12.12s %c[%s]: %s:%d", @@ -268,7 +289,7 @@ void LogManager::Log(LogLevel level, LogType type, const char *file, int line, c } } -bool LogManager::IsEnabled(LogLevel level, LogType type) { +bool LogManager::IsEnabled(LogLevel level, Log type) { LogChannel &log = log_[(size_t)type]; if (level > log.level || !log.enabled) return false; @@ -356,7 +377,7 @@ void OutputDebugStringUTF8(const char *p) { #else void OutputDebugStringUTF8(const char *p) { - INFO_LOG(SYSTEM, "%s", p); + INFO_LOG(Log::System, "%s", p); } #endif diff --git a/Common/LogManager.h b/Common/Log/LogManager.h similarity index 86% rename from Common/LogManager.h rename to Common/Log/LogManager.h index 7151774067..1bceb3433e 100644 --- a/Common/LogManager.h +++ b/Common/Log/LogManager.h @@ -104,6 +104,7 @@ struct LogChannel { }; class ConsoleListener; +class StdioListener; class LogManager { private: @@ -114,9 +115,12 @@ private: LogManager(const LogManager &) = delete; void operator=(const LogManager &) = delete; - LogChannel log_[(size_t)LogType::NUMBER_OF_LOGS]; + LogChannel log_[(size_t)Log::NUMBER_OF_LOGS]; FileLogListener *fileLog_ = nullptr; +#if PPSSPP_PLATFORM(WINDOWS) ConsoleListener *consoleLog_ = nullptr; +#endif + StdioListener *stdioLog_ = nullptr; OutputDebugStringLogListener *debuggerLog_ = nullptr; RingbufferLogListener *ringLog_ = nullptr; static LogManager *logManager_; // Singleton. Ugh. @@ -129,37 +133,43 @@ public: void RemoveListener(LogListener *listener); static u32 GetMaxLevel() { return (u32)MAX_LOGLEVEL; } - static int GetNumChannels() { return (int)LogType::NUMBER_OF_LOGS; } + static int GetNumChannels() { return (int)Log::NUMBER_OF_LOGS; } - void Log(LogLevel level, LogType type, - const char *file, int line, const char *fmt, va_list args); - bool IsEnabled(LogLevel level, LogType type); + void LogLine(LogLevel level, Log type, + const char *file, int line, const char *fmt, va_list args); + bool IsEnabled(LogLevel level, Log type); - LogChannel *GetLogChannel(LogType type) { + LogChannel *GetLogChannel(Log type) { return &log_[(size_t)type]; } - void SetLogLevel(LogType type, LogLevel level) { + void SetLogLevel(Log type, LogLevel level) { log_[(size_t)type].level = level; } void SetAllLogLevels(LogLevel level) { - for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; ++i) { + for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; ++i) { log_[i].level = level; } } - void SetEnabled(LogType type, bool enable) { + void SetEnabled(Log type, bool enable) { log_[(size_t)type].enabled = enable; } - LogLevel GetLogLevel(LogType type) { + LogLevel GetLogLevel(Log type) { return log_[(size_t)type].level; } +#if PPSSPP_PLATFORM(WINDOWS) ConsoleListener *GetConsoleListener() const { return consoleLog_; } +#endif + + StdioListener *GetStdioListener() const { + return stdioLog_; + } OutputDebugStringLogListener *GetDebuggerListener() const { return debuggerLog_; diff --git a/Common/Log/StdioListener.cpp b/Common/Log/StdioListener.cpp new file mode 100644 index 0000000000..ce0efd5203 --- /dev/null +++ b/Common/Log/StdioListener.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2014- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include // min +#include +#include // System: To be able to add strings with "+" +#include +#include +#ifndef _MSC_VER +#include +#endif + +#include "ppsspp_config.h" +#include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/CommonTypes.h" +#include "Common/Log/StdioListener.h" +#include "Common/StringUtils.h" + +StdioListener::StdioListener() { +#if PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(SWITCH) + bUseColor = false; +#elif defined(_MSC_VER) + bUseColor = false; +#elif defined(__APPLE__) + // Xcode builtin terminal used for debugging does not support colours. + // Fortunately it can be detected with a TERM env variable. + bUseColor = isatty(fileno(stdout)) && getenv("TERM") != NULL; +#else + bUseColor = isatty(fileno(stdout)); +#endif +} + +void StdioListener::Log(const LogMessage &msg) { + char Text[2048]; + snprintf(Text, sizeof(Text), "%s %s %s", msg.timestamp, msg.header, msg.msg.c_str()); + Text[sizeof(Text) - 2] = '\n'; + Text[sizeof(Text) - 1] = '\0'; + + char ColorAttr[16] = ""; + char ResetAttr[16] = ""; + + if (bUseColor) { + strcpy(ResetAttr, "\033[0m"); + switch (msg.level) { + case LogLevel::LNOTICE: // light green + strcpy(ColorAttr, "\033[92m"); + break; + case LogLevel::LERROR: // light red + strcpy(ColorAttr, "\033[91m"); + break; + case LogLevel::LWARNING: // light yellow + strcpy(ColorAttr, "\033[93m"); + break; + case LogLevel::LINFO: // cyan + strcpy(ColorAttr, "\033[96m"); + break; + case LogLevel::LDEBUG: // gray + strcpy(ColorAttr, "\033[90m"); + break; + default: + break; + } + } + fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr); +} diff --git a/Common/Log/StdioListener.h b/Common/Log/StdioListener.h new file mode 100644 index 0000000000..2b46599b34 --- /dev/null +++ b/Common/Log/StdioListener.h @@ -0,0 +1,36 @@ +#pragma once + +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include + +#include "Common/Log/LogManager.h" + +#ifdef _WIN32 +#include "Common/CommonWindows.h" +#endif + +class StdioListener : public LogListener { +public: + StdioListener(); + void Log(const LogMessage &message) override; +private: + bool bUseColor = true; +}; diff --git a/Common/LogReporting.cpp b/Common/LogReporting.cpp index 0fcc78d0ad..7c6ac3b440 100644 --- a/Common/LogReporting.cpp +++ b/Common/LogReporting.cpp @@ -59,7 +59,7 @@ void SetupCallbacks(AllowedCallback allowed, MessageCallback message) { void ReportMessage(const char *message, ...) { if (!allowedCallback || !messageCallback) { - ERROR_LOG(SYSTEM, "Reporting not initialized, skipping: %s", message); + ERROR_LOG(Log::System, "Reporting not initialized, skipping: %s", message); return; } @@ -80,7 +80,7 @@ void ReportMessage(const char *message, ...) { void ReportMessageFormatted(const char *message, const char *formatted) { if (!allowedCallback || !messageCallback) { - ERROR_LOG(SYSTEM, "Reporting not initialized, skipping: %s", message); + ERROR_LOG(Log::System, "Reporting not initialized, skipping: %s", message); return; } @@ -89,4 +89,4 @@ void ReportMessageFormatted(const char *message, const char *formatted) { messageCallback(message, formatted); } -} +} // namespace diff --git a/Common/LogReporting.h b/Common/LogReporting.h index f4b0ea7903..bccc750ec2 100644 --- a/Common/LogReporting.h +++ b/Common/LogReporting.h @@ -62,4 +62,4 @@ void ReportMessage(const char *message, ...); // The same, but with a preformatted version (message is still the key.) void ReportMessageFormatted(const char *message, const char *formatted); -} +} // namespace Reporting diff --git a/Common/Math/curves.cpp b/Common/Math/curves.cpp index 88c915b62d..982b8ea285 100644 --- a/Common/Math/curves.cpp +++ b/Common/Math/curves.cpp @@ -33,14 +33,14 @@ float linearOut(int t, int fadeOutLength) { } float ease(float val) { - if (val > 1.0f) return 1.0f; - if (val < 0.0f) return 0.0f; + if (val >= 1.0f) return 1.0f; + if (val <= 0.0f) return 0.0f; return (float)(((-cosf(val * PI)) + 1.0f) * 0.5); } float ease(int t, int fadeLength) { - if (t < 0) return 0.0f; + if (t <= 0.0f) return 0.0f; if (t >= fadeLength) return 1.0f; return ease((float)t / (float)fadeLength); } diff --git a/Common/Math/geom2d.h b/Common/Math/geom2d.h index f319d7c79d..bfbe950c83 100644 --- a/Common/Math/geom2d.h +++ b/Common/Math/geom2d.h @@ -2,19 +2,19 @@ #include -struct Point { - Point() : x(0.0f), y(0.0f) {} - Point(float x_, float y_) : x(x_), y(y_) {} +struct Point2D { + Point2D() : x(0.0f), y(0.0f) {} + Point2D(float x_, float y_) : x(x_), y(y_) {} float x; float y; - float distanceTo(const Point &other) const { + float distanceTo(const Point2D &other) const { float dx = other.x - x, dy = other.y - y; return sqrtf(dx*dx + dy*dy); } - bool operator ==(const Point &other) const { + bool operator ==(const Point2D &other) const { return x == other.x && y == other.y; } @@ -60,8 +60,8 @@ struct Bounds { float y2() const { return y + h; } float centerX() const { return x + w * 0.5f; } float centerY() const { return y + h * 0.5f; } - Point Center() const { - return Point(centerX(), centerY()); + Point2D Center() const { + return Point2D(centerX(), centerY()); } Bounds Expand(float amount) const { return Bounds(x - amount, y - amount, w + amount * 2, h + amount * 2); diff --git a/Common/Math/math_util.h b/Common/Math/math_util.h index aa56b53073..6cd9e711d2 100644 --- a/Common/Math/math_util.h +++ b/Common/Math/math_util.h @@ -110,6 +110,10 @@ inline bool my_isinf(float f) { f2u.u == 0xff800000; } +inline bool my_isinf_u(uint32_t u) { + return u == 0x7f800000 || u == 0xff800000; +} + inline bool my_isnan(float f) { FP32 f2u; f2u.f = f; diff --git a/Common/MemArenaAndroid.cpp b/Common/MemArenaAndroid.cpp index 73dd4e7cc6..551a89bd60 100644 --- a/Common/MemArenaAndroid.cpp +++ b/Common/MemArenaAndroid.cpp @@ -88,7 +88,7 @@ static int legacy_ashmem_create_region(const char *name, size_t size) { return fd; error: - ERROR_LOG(MEMMAP, "NASTY ASHMEM ERROR: ret = %08x", ret); + ERROR_LOG(Log::MemMap, "NASTY ASHMEM ERROR: ret = %08x", ret); close(fd); return ret; } @@ -110,7 +110,7 @@ bool MemArena::GrabMemSpace(size_t size) { } // Note that it appears that ashmem is pinned by default, so no need to pin. if (fd < 0) { - ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); + ERROR_LOG(Log::MemMap, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); return false; } return true; @@ -123,7 +123,7 @@ void MemArena::ReleaseSpace() { void *MemArena::CreateView(s64 offset, size_t size, void *base) { void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | ((base == 0) ? 0 : MAP_FIXED), fd, offset); if (retval == MAP_FAILED) { - NOTICE_LOG(MEMMAP, "mmap on ashmem (fd: %d) failed", (int)fd); + NOTICE_LOG(Log::MemMap, "mmap on ashmem (fd: %d) failed", (int)fd); return nullptr; } return retval; @@ -142,14 +142,14 @@ u8* MemArena::Find4GBBase() { const uint64_t EIGHT_GIGS = 0x200000000ULL; void *base = mmap(0, EIGHT_GIGS, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); if (base && base != MAP_FAILED) { - INFO_LOG(SYSTEM, "base: %p", base); + INFO_LOG(Log::System, "base: %p", base); uint64_t aligned_base = ((uint64_t)base + 0xFFFFFFFF) & ~0xFFFFFFFFULL; - INFO_LOG(SYSTEM, "aligned_base: %p", (void *)aligned_base); + INFO_LOG(Log::System, "aligned_base: %p", (void *)aligned_base); munmap(base, EIGHT_GIGS); return reinterpret_cast(aligned_base); } else { u8 *hardcoded_ptr = reinterpret_cast(0x2300000000ULL); - INFO_LOG(SYSTEM, "Failed to anonymously map 8GB. Fall back to the hardcoded pointer %p.", hardcoded_ptr); + INFO_LOG(Log::System, "Failed to anonymously map 8GB. Fall back to the hardcoded pointer %p.", hardcoded_ptr); // Just grab some random 4GB... // This has been known to fail lately though, see issue #12249. return hardcoded_ptr; @@ -159,7 +159,7 @@ u8* MemArena::Find4GBBase() { void *base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); if (base == MAP_FAILED) { - ERROR_LOG(SYSTEM, "Failed to map 256 MB of memory space: %s", strerror(errno)); + ERROR_LOG(Log::System, "Failed to map 256 MB of memory space: %s", strerror(errno)); return nullptr; } diff --git a/Common/MemArenaDarwin.cpp b/Common/MemArenaDarwin.cpp index 0b1abd16b8..c6f91eaf53 100644 --- a/Common/MemArenaDarwin.cpp +++ b/Common/MemArenaDarwin.cpp @@ -42,10 +42,10 @@ bool MemArena::GrabMemSpace(size_t size) { vm_size = size; kern_return_t retval = vm_allocate(mach_task_self(), &vm_mem, size, VM_FLAGS_ANYWHERE); if (retval != KERN_SUCCESS) { - ERROR_LOG(MEMMAP, "Failed to grab a block of virtual memory"); + ERROR_LOG(Log::MemMap, "Failed to grab a block of virtual memory"); return false; } else { - INFO_LOG(MEMMAP, "Successfully allocated %d bytes at %p", (int)size, (void *)vm_mem); + INFO_LOG(Log::MemMap, "Successfully allocated %d bytes at %p", (int)size, (void *)vm_mem); return true; } } @@ -72,7 +72,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base) { // 1 == KERN_INVALID_ADDRESS // 3 == KERN_NO_SPACE (race?) // 4 == KERN_INVALID_ARGUMENT - ERROR_LOG(MEMMAP, "vm_remap failed (%d) - could not remap from %llx (offset %llx) of size %llx to %p", + ERROR_LOG(Log::MemMap, "vm_remap failed (%d) - could not remap from %llx (offset %llx) of size %llx to %p", (int)retval, (uint64_t)source, (uint64_t)offset, (uint64_t)size, base); return nullptr; } diff --git a/Common/MemArenaPosix.cpp b/Common/MemArenaPosix.cpp index 7923b99b85..a413f4eaf2 100644 --- a/Common/MemArenaPosix.cpp +++ b/Common/MemArenaPosix.cpp @@ -63,11 +63,11 @@ bool MemArena::GrabMemSpace(size_t size) { // This opens atomically, so will fail if another process is starting. fd = shm_open(ram_temp_filename, O_RDWR | O_CREAT | O_EXCL, mode); if (fd >= 0) { - INFO_LOG(MEMMAP, "Got shm file: %s", ram_temp_filename); + INFO_LOG(Log::MemMap, "Got shm file: %s", ram_temp_filename); is_shm = true; // Our handle persists per POSIX, so no need to keep it around. if (shm_unlink(ram_temp_filename) != 0) { - WARN_LOG(MEMMAP, "Failed to shm_unlink %s", ram_temp_file.c_str()); + WARN_LOG(Log::MemMap, "Failed to shm_unlink %s", ram_temp_file.c_str()); } break; } @@ -79,24 +79,24 @@ bool MemArena::GrabMemSpace(size_t size) { if (fd >= 0) { // Great, this definitely shouldn't flush to disk. ram_temp_file = tmpfs_ram_temp_file; - INFO_LOG(MEMMAP, "Got tmpfs ram file: %s", tmpfs_ram_temp_file.c_str()); + INFO_LOG(Log::MemMap, "Got tmpfs ram file: %s", tmpfs_ram_temp_file.c_str()); } } if (fd < 0) { - INFO_LOG(MEMMAP, "Trying '%s' as ram temp file", ram_temp_file.c_str()); + INFO_LOG(Log::MemMap, "Trying '%s' as ram temp file", ram_temp_file.c_str()); fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode); } if (fd < 0) { - ERROR_LOG(MEMMAP, "Failed to grab memory space as a file: %s of size: %08x. Error: %s", ram_temp_file.c_str(), (int)size, strerror(errno)); + ERROR_LOG(Log::MemMap, "Failed to grab memory space as a file: %s of size: %08x. Error: %s", ram_temp_file.c_str(), (int)size, strerror(errno)); return false; } // delete immediately, we keep the fd so it still lives if (!is_shm && unlink(ram_temp_file.c_str()) != 0) { - WARN_LOG(MEMMAP, "Failed to unlink %s", ram_temp_file.c_str()); + WARN_LOG(Log::MemMap, "Failed to unlink %s", ram_temp_file.c_str()); } if (ftruncate(fd, size) != 0) { - ERROR_LOG(MEMMAP, "Failed to ftruncate %d (%s) to size %08x", (int)fd, ram_temp_file.c_str(), (int)size); + ERROR_LOG(Log::MemMap, "Failed to ftruncate %d (%s) to size %08x", (int)fd, ram_temp_file.c_str(), (int)size); // Should this be a failure? } #endif @@ -122,7 +122,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base) ((base == 0) ? 0 : MAP_FIXED), fd, offset); if (retval == MAP_FAILED) { - NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed: %s", ram_temp_file.c_str(), (int)fd, strerror(errno)); + NOTICE_LOG(Log::MemMap, "mmap on %s (fd: %d) failed: %s", ram_temp_file.c_str(), (int)fd, strerror(errno)); return 0; } return retval; @@ -137,7 +137,7 @@ void MemArena::ReleaseView(s64 offset, void* view, size_t size) { u8* MemArena::Find4GBBase() { // Now, create views in high memory where there's plenty of space. -#if PPSSPP_ARCH(64BIT) && !defined(USE_ASAN) +#if PPSSPP_ARCH(64BIT) && !defined(USE_ASAN) && !defined(NO_MMAP) // We should probably just go look in /proc/self/maps for some free space. // But let's try the anonymous mmap trick, just like on 32-bit, but bigger and // aligned to 4GB for the movk trick. We can ensure that we get an aligned 4GB @@ -145,14 +145,14 @@ u8* MemArena::Find4GBBase() { const uint64_t EIGHT_GIGS = 0x200000000ULL; void *base = mmap(0, EIGHT_GIGS, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, -1, 0); if (base && base != MAP_FAILED) { - INFO_LOG(MEMMAP, "base: %p", base); + INFO_LOG(Log::MemMap, "base: %p", base); uint64_t aligned_base = ((uint64_t)base + 0xFFFFFFFF) & ~0xFFFFFFFFULL; - INFO_LOG(MEMMAP, "aligned_base: %p", (void *)aligned_base); + INFO_LOG(Log::MemMap, "aligned_base: %p", (void *)aligned_base); munmap(base, EIGHT_GIGS); return reinterpret_cast(aligned_base); } else { u8 *hardcoded_ptr = reinterpret_cast(0x2300000000ULL); - INFO_LOG(MEMMAP, "Failed to anonymously map 8GB (%s). Fall back to the hardcoded pointer %p.", strerror(errno), hardcoded_ptr); + INFO_LOG(Log::MemMap, "Failed to anonymously map 8GB (%s). Fall back to the hardcoded pointer %p.", strerror(errno), hardcoded_ptr); // Just grab some random 4GB... // This has been known to fail lately though, see issue #12249. return hardcoded_ptr; diff --git a/Common/MemoryUtil.cpp b/Common/MemoryUtil.cpp index 4cebd6eb4d..9c7130e8dd 100644 --- a/Common/MemoryUtil.cpp +++ b/Common/MemoryUtil.cpp @@ -146,7 +146,7 @@ void *AllocateExecutableMemory(size_t size) { if (ptr) { ptr = VirtualAlloc(ptr, aligned_size, MEM_RESERVE | MEM_COMMIT, prot); } else { - WARN_LOG(COMMON, "Unable to find nearby executable memory for jit. Proceeding with far memory."); + WARN_LOG(Log::Common, "Unable to find nearby executable memory for jit. Proceeding with far memory."); // Can still run, thanks to "RipAccessible". ptr = VirtualAlloc(nullptr, aligned_size, MEM_RESERVE | MEM_COMMIT, prot); } @@ -161,7 +161,7 @@ void *AllocateExecutableMemory(size_t size) { #endif } if (!ptr) { - ERROR_LOG(MEMMAP, "Failed to allocate executable memory (%d)", (int)size); + ERROR_LOG(Log::MemMap, "Failed to allocate executable memory (%d)", (int)size); } return ptr; } @@ -193,7 +193,7 @@ void *AllocateExecutableMemory(size_t size) { if (ptr == MAP_FAILED) { ptr = nullptr; - ERROR_LOG(MEMMAP, "Failed to allocate executable memory (%d) errno=%d", (int)size, errno); + ERROR_LOG(Log::MemMap, "Failed to allocate executable memory (%d) errno=%d", (int)size, errno); } #if PPSSPP_ARCH(AMD64) @@ -227,7 +227,7 @@ void *AllocateMemoryPages(size_t size, uint32_t memProtFlags) { void* ptr = VirtualAlloc(0, size, MEM_COMMIT, protect); #endif if (!ptr) { - ERROR_LOG(MEMMAP, "Failed to allocate raw memory pages"); + ERROR_LOG(Log::MemMap, "Failed to allocate raw memory pages"); return nullptr; } #else @@ -235,7 +235,7 @@ void *AllocateMemoryPages(size_t size, uint32_t memProtFlags) { uint32_t protect = ConvertProtFlagsUnix(memProtFlags); void *ptr = mmap(0, size, protect, MAP_ANON | MAP_PRIVATE, -1, 0); if (ptr == MAP_FAILED) { - ERROR_LOG(MEMMAP, "Failed to allocate raw memory pages: errno=%d", errno); + ERROR_LOG(Log::MemMap, "Failed to allocate raw memory pages: errno=%d", errno); return nullptr; } #endif @@ -271,7 +271,7 @@ void FreeMemoryPages(void *ptr, size_t size) { size = (size + page_size - 1) & (~(page_size - 1)); #ifdef _WIN32 if (!VirtualFree(ptr, 0, MEM_RELEASE)) { - ERROR_LOG(MEMMAP, "FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); + ERROR_LOG(Log::MemMap, "FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); } #else munmap(ptr, size); @@ -306,7 +306,7 @@ bool PlatformIsWXExclusive() { } bool ProtectMemoryPages(const void* ptr, size_t size, uint32_t memProtFlags) { - VERBOSE_LOG(JIT, "ProtectMemoryPages: %p (%d) : r%d w%d x%d", ptr, (int)size, + VERBOSE_LOG(Log::JIT, "ProtectMemoryPages: %p (%d) : r%d w%d x%d", ptr, (int)size, (memProtFlags & MEM_PROT_READ) != 0, (memProtFlags & MEM_PROT_WRITE) != 0, (memProtFlags & MEM_PROT_EXEC) != 0); if (PlatformIsWXExclusive()) { @@ -322,13 +322,13 @@ bool ProtectMemoryPages(const void* ptr, size_t size, uint32_t memProtFlags) { #if PPSSPP_PLATFORM(UWP) DWORD oldValue; if (!VirtualProtectFromApp((void *)ptr, size, protect, &oldValue)) { - ERROR_LOG(MEMMAP, "WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); + ERROR_LOG(Log::MemMap, "WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); return false; } #else DWORD oldValue; if (!VirtualProtect((void *)ptr, size, protect, &oldValue)) { - ERROR_LOG(MEMMAP, "WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); + ERROR_LOG(Log::MemMap, "WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); return false; } #endif @@ -343,7 +343,7 @@ bool ProtectMemoryPages(const void* ptr, size_t size, uint32_t memProtFlags) { end = (end + page_size - 1) & ~(page_size - 1); int retval = mprotect((void *)start, end - start, protect); if (retval != 0) { - ERROR_LOG(MEMMAP, "mprotect failed (%p)! errno=%d (%s)", (void *)start, errno, strerror(errno)); + ERROR_LOG(Log::MemMap, "mprotect failed (%p)! errno=%d (%s)", (void *)start, errno, strerror(errno)); return false; } return true; diff --git a/Common/Net/HTTPClient.cpp b/Common/Net/HTTPClient.cpp index 43e94fe85a..13be8e4998 100644 --- a/Common/Net/HTTPClient.cpp +++ b/Common/Net/HTTPClient.cpp @@ -69,11 +69,11 @@ const char *DNSTypeAsString(DNSType type) { bool Connection::Resolve(const char *host, int port, DNSType type) { if ((intptr_t)sock_ != -1) { - ERROR_LOG(IO, "Resolve: Already have a socket"); + ERROR_LOG(Log::IO, "Resolve: Already have a socket"); return false; } if (!host || port < 1 || port > 65535) { - ERROR_LOG(IO, "Resolve: Invalid host or port (%d)", port); + ERROR_LOG(Log::IO, "Resolve: Invalid host or port (%d)", port); return false; } @@ -85,7 +85,7 @@ bool Connection::Resolve(const char *host, int port, DNSType type) { std::string err; if (!net::DNSResolve(host, port_str, &resolved_, err, type)) { - WARN_LOG(IO, "Failed to resolve host '%s': '%s' (%s)", host, err.c_str(), DNSTypeAsString(type)); + WARN_LOG(Log::IO, "Failed to resolve host '%s': '%s' (%s)", host, err.c_str(), DNSTypeAsString(type)); // Zero port so that future calls fail. port_ = 0; return false; @@ -108,7 +108,7 @@ static void FormatAddr(char *addrbuf, size_t bufsize, const addrinfo *info) { bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) { if (port_ <= 0) { - ERROR_LOG(IO, "Bad port"); + ERROR_LOG(Log::IO, "Bad port"); return false; } sock_ = -1; @@ -124,13 +124,13 @@ bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) { int sock = socket(possible->ai_family, SOCK_STREAM, IPPROTO_TCP); if ((intptr_t)sock == -1) { - ERROR_LOG(IO, "Bad socket"); + ERROR_LOG(Log::IO, "Bad socket"); continue; } // Windows sockets aren't limited by socket number, just by count, so checking FD_SETSIZE there is wrong. #if !PPSSPP_PLATFORM(WINDOWS) if (sock >= FD_SETSIZE) { - ERROR_LOG(IO, "Socket doesn't fit in FD_SET: %d We probably have a leak.", sock); + ERROR_LOG(Log::IO, "Socket doesn't fit in FD_SET: %d We probably have a leak.", sock); closesocket(sock); continue; } @@ -155,9 +155,9 @@ bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) { char addrStr[128]{}; FormatAddr(addrStr, sizeof(addrStr), possible); if (!unreachable) { - ERROR_LOG(HTTP, "connect(%d) call to %s failed (%d: %s)", sock, addrStr, errorCode, errorString.c_str()); + ERROR_LOG(Log::HTTP, "connect(%d) call to %s failed (%d: %s)", sock, addrStr, errorCode, errorString.c_str()); } else { - INFO_LOG(HTTP, "connect(%d): Ignoring unreachable resolved address %s", sock, addrStr); + INFO_LOG(Log::HTTP, "connect(%d): Ignoring unreachable resolved address %s", sock, addrStr); } closesocket(sock); continue; @@ -186,7 +186,7 @@ bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) { selectResult = select(maxfd, nullptr, &fds, nullptr, &tv); if (cancelConnect && *cancelConnect) { - WARN_LOG(HTTP, "connect: cancelled (1)"); + WARN_LOG(Log::HTTP, "connect: cancelled (1)"); break; } } @@ -210,7 +210,7 @@ bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) { } if (cancelConnect && *cancelConnect) { - WARN_LOG(HTTP, "connect: cancelled (2)"); + WARN_LOG(Log::HTTP, "connect: cancelled (2)"); break; } @@ -270,15 +270,18 @@ bool GetHeaderValue(const std::vector &responseHeaders, const std:: return found; } -void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength) { +static bool DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength) { + _dbg_assert_(outbuffer->empty()); int dechunkedBytes = 0; while (true) { std::string line; inbuffer->TakeLineCRLF(&line); if (!line.size()) - return; + return false; unsigned int chunkSize = 0; - sscanf(line.c_str(), "%x", &chunkSize); + if (sscanf(line.c_str(), "%x", &chunkSize) != 1) { + return false; + } if (chunkSize) { std::string data; inbuffer->Take(chunkSize, &data); @@ -286,11 +289,13 @@ void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength) { } else { // a zero size chunk should mean the end. inbuffer->clear(); - return; + return true; } dechunkedBytes += chunkSize; inbuffer->Skip(2); } + // Unreachable + return true; } int Client::GET(const RequestParams &req, Buffer *output, std::vector &responseHeaders, net::RequestProgress *progress) { @@ -391,13 +396,13 @@ int Client::ReadResponseHeaders(net::Buffer *readbuf, std::vector & return -1; ready = fd_util::WaitUntilReady(sock(), CANCEL_INTERVAL, false); if (!ready && time_now_d() > endTimeout) { - ERROR_LOG(HTTP, "HTTP headers timed out"); + ERROR_LOG(Log::HTTP, "HTTP headers timed out"); return -1; } }; // Let's hope all the headers are available in a single packet... if (readbuf->Read(sock(), 4096) < 0) { - ERROR_LOG(HTTP, "Failed to read HTTP headers :("); + ERROR_LOG(Log::HTTP, "Failed to read HTTP headers :("); return -1; } @@ -415,7 +420,7 @@ int Client::ReadResponseHeaders(net::Buffer *readbuf, std::vector & if (code_pos != line.npos) { code = atoi(&line[code_pos]); } else { - ERROR_LOG(HTTP, "Could not parse HTTP status code: %s", line.c_str()); + ERROR_LOG(Log::HTTP, "Could not parse HTTP status code: %s", line.c_str()); return -1; } @@ -427,7 +432,7 @@ int Client::ReadResponseHeaders(net::Buffer *readbuf, std::vector & } if (responseHeaders.size() == 0) { - ERROR_LOG(HTTP, "No HTTP response headers"); + ERROR_LOG(Log::HTTP, "No HTTP response headers"); return -1; } @@ -464,7 +469,7 @@ int Client::ReadResponseEntity(net::Buffer *readbuf, const std::vectorIsVoid()) { if (chunked) { - DeChunk(readbuf, output, contentLength); + if (!DeChunk(readbuf, output, contentLength)) { + ERROR_LOG(Log::HTTP, "Bad chunked data, couldn't read chunk size"); + progress->Update(0, 0, true); + return -1; + } } else { output->Append(*readbuf); } @@ -486,7 +495,7 @@ int Client::ReadResponseEntity(net::Buffer *readbuf, const std::vectorTakeAll(&compressed); bool result = decompress_string(compressed, &decompressed); if (!result) { - ERROR_LOG(HTTP, "Error decompressing using zlib"); + ERROR_LOG(Log::HTTP, "Error decompressing using zlib"); progress->Update(0, 0, true); return -1; } @@ -514,7 +523,7 @@ void HTTPRequest::Start() { void HTTPRequest::Join() { if (joined_) { - ERROR_LOG(HTTP, "Already joined thread!"); + ERROR_LOG(Log::HTTP, "Already joined thread!"); } thread_.join(); joined_ = true; @@ -538,7 +547,7 @@ int HTTPRequest::Perform(const std::string &url) { } if (!client.Resolve(fileUrl.Host().c_str(), fileUrl.Port())) { - ERROR_LOG(HTTP, "Failed resolving %s", url.c_str()); + ERROR_LOG(Log::HTTP, "Failed resolving %s", url.c_str()); return -1; } @@ -547,7 +556,7 @@ int HTTPRequest::Perform(const std::string &url) { } if (!client.Connect(2, 20.0, &cancelled_)) { - ERROR_LOG(HTTP, "Failed connecting to server or cancelled."); + ERROR_LOG(Log::HTTP, "Failed connecting to server or cancelled."); return -1; } @@ -563,14 +572,13 @@ int HTTPRequest::Perform(const std::string &url) { } } -std::string HTTPRequest::RedirectLocation(const std::string &baseUrl) { +std::string HTTPRequest::RedirectLocation(const std::string &baseUrl) const { std::string redirectUrl; if (GetHeaderValue(responseHeaders_, "Location", &redirectUrl)) { Url url(baseUrl); url = url.Relative(redirectUrl); redirectUrl = url.ToString(); } - return redirectUrl; } @@ -582,6 +590,7 @@ void HTTPRequest::Do() { std::string downloadURL = url_; while (resultCode_ == 0) { + // This is where the new request is performed. int resultCode = Perform(downloadURL); if (resultCode == -1) { SetFailed(resultCode); @@ -591,7 +600,7 @@ void HTTPRequest::Do() { if (resultCode == 301 || resultCode == 302 || resultCode == 303 || resultCode == 307 || resultCode == 308) { std::string redirectURL = RedirectLocation(downloadURL); if (redirectURL.empty()) { - ERROR_LOG(HTTP, "Could not find Location header for redirect"); + ERROR_LOG(Log::HTTP, "Could not find Location header for redirect"); resultCode_ = resultCode; } else if (redirectURL == downloadURL || redirectURL == url_) { // Simple loop detected, bail out. @@ -599,19 +608,22 @@ void HTTPRequest::Do() { } // Perform the next GET. - if (resultCode_ == 0) - INFO_LOG(HTTP, "Download of %s redirected to %s", downloadURL.c_str(), redirectURL.c_str()); + if (resultCode_ == 0) { + INFO_LOG(Log::HTTP, "Download of %s redirected to %s", downloadURL.c_str(), redirectURL.c_str()); + buffer_.clear(); + responseHeaders_.clear(); + } downloadURL = redirectURL; continue; } if (resultCode == 200) { - INFO_LOG(HTTP, "Completed requesting %s (storing result to %s)", url_.c_str(), outfile_.empty() ? "memory" : outfile_.c_str()); + INFO_LOG(Log::HTTP, "Completed requesting %s (storing result to %s)", url_.c_str(), outfile_.empty() ? "memory" : outfile_.c_str()); if (!outfile_.empty() && !buffer_.FlushToFile(outfile_)) { - ERROR_LOG(HTTP, "Failed writing download to '%s'", outfile_.c_str()); + ERROR_LOG(Log::HTTP, "Failed writing download to '%s'", outfile_.c_str()); } } else { - ERROR_LOG(HTTP, "Error requesting '%s' (storing result to '%s'): %i", url_.c_str(), outfile_.empty() ? "memory" : outfile_.c_str(), resultCode); + ERROR_LOG(Log::HTTP, "Error requesting '%s' (storing result to '%s'): %i", url_.c_str(), outfile_.empty() ? "memory" : outfile_.c_str(), resultCode); } resultCode_ = resultCode; } diff --git a/Common/Net/HTTPClient.h b/Common/Net/HTTPClient.h index 12a8ddf0b8..92a56686be 100644 --- a/Common/Net/HTTPClient.h +++ b/Common/Net/HTTPClient.h @@ -121,7 +121,7 @@ public: private: void Do(); // Actually does the download. Runs on thread. int Perform(const std::string &url); - std::string RedirectLocation(const std::string &baseUrl); + std::string RedirectLocation(const std::string &baseUrl) const; void SetFailed(int code); std::string postData_; diff --git a/Common/Net/HTTPHeaders.cpp b/Common/Net/HTTPHeaders.cpp index ddb706285f..7111898548 100644 --- a/Common/Net/HTTPHeaders.cpp +++ b/Common/Net/HTTPHeaders.cpp @@ -31,7 +31,7 @@ bool RequestHeader::GetParamValue(const char *param_name, std::string *value) co for (size_t i = 0; i < v.size(); i++) { std::vector parts; SplitString(v[i], '=', parts); - DEBUG_LOG(IO, "Param: %.*s Value: %.*s", (int)parts[0].size(), parts[0].data(), (int)parts[1].size(), parts[1].data()); + DEBUG_LOG(Log::IO, "Param: %.*s Value: %.*s", (int)parts[0].size(), parts[0].data(), (int)parts[1].size(), parts[1].data()); if (parts[0] == param_name) { *value = parts[1]; return true; @@ -119,13 +119,13 @@ int RequestHeader::ParseHttpHeader(const char *buffer) { if (!strncasecmp(key, "User-Agent", key_len)) { user_agent = new char[value_len + 1]; memcpy(user_agent, buffer, value_len + 1); - VERBOSE_LOG(IO, "user-agent: %s", user_agent); + VERBOSE_LOG(Log::IO, "user-agent: %s", user_agent); } else if (!strncasecmp(key, "Referer", key_len)) { referer = new char[value_len + 1]; memcpy(referer, buffer, value_len + 1); } else if (!strncasecmp(key, "Content-Length", key_len)) { content_length = atoi(buffer); - VERBOSE_LOG(IO, "Content-Length: %i", (int)content_length); + VERBOSE_LOG(Log::IO, "Content-Length: %i", (int)content_length); } else { std::string key_str(key, key_len); std::transform(key_str.begin(), key_str.end(), key_str.begin(), tolower); @@ -148,12 +148,12 @@ void RequestHeader::ParseHeaders(net::InputSink *sink) { line_count++; if (type == SIMPLE) { // Done! - VERBOSE_LOG(IO, "Simple: Done parsing http request."); + VERBOSE_LOG(Log::IO, "Simple: Done parsing http request."); break; } } - VERBOSE_LOG(IO, "finished parsing request."); + VERBOSE_LOG(Log::IO, "finished parsing request."); ok = line_count > 1 && resource != nullptr; } diff --git a/Common/Net/HTTPNaettRequest.cpp b/Common/Net/HTTPNaettRequest.cpp index f3bf0304ab..6c39f0a4df 100644 --- a/Common/Net/HTTPNaettRequest.cpp +++ b/Common/Net/HTTPNaettRequest.cpp @@ -60,7 +60,7 @@ void HTTPSRequest::Join() { res_ = nullptr; req_ = nullptr; } else { - ERROR_LOG(IO, "HTTPSDownload::Join not implemented"); + ERROR_LOG(Log::IO, "HTTPSDownload::Join not implemented"); } } @@ -85,33 +85,33 @@ bool HTTPSRequest::Done() { // It's a naett error. Translate and handle. switch (resultCode_) { case naettConnectionError: // -1 - ERROR_LOG(IO, "Connection error"); + ERROR_LOG(Log::IO, "Connection error"); break; case naettProtocolError: // -2 - ERROR_LOG(IO, "Protocol error"); + ERROR_LOG(Log::IO, "Protocol error"); break; case naettReadError: // -3 - ERROR_LOG(IO, "Read error"); + ERROR_LOG(Log::IO, "Read error"); break; case naettWriteError: // -4 - ERROR_LOG(IO, "Write error"); + ERROR_LOG(Log::IO, "Write error"); break; case naettGenericError: // -5 - ERROR_LOG(IO, "Generic error"); + ERROR_LOG(Log::IO, "Generic error"); break; default: - ERROR_LOG(IO, "Unhandled naett error %d", resultCode_); + ERROR_LOG(Log::IO, "Unhandled naett error %d", resultCode_); break; } failed_ = true; progress_.Update(bodyLength, bodyLength, true); } else if (resultCode_ == 200) { if (!outfile_.empty() && !buffer_.FlushToFile(outfile_)) { - ERROR_LOG(IO, "Failed writing download to '%s'", outfile_.c_str()); + ERROR_LOG(Log::IO, "Failed writing download to '%s'", outfile_.c_str()); } progress_.Update(bodyLength, bodyLength, true); } else { - WARN_LOG(IO, "Naett request failed: %d", resultCode_); + WARN_LOG(Log::IO, "Naett request failed: %d", resultCode_); failed_ = true; progress_.Update(0, 0, true); } diff --git a/Common/Net/HTTPRequest.cpp b/Common/Net/HTTPRequest.cpp index 1633653609..d606a6c946 100644 --- a/Common/Net/HTTPRequest.cpp +++ b/Common/Net/HTTPRequest.cpp @@ -10,7 +10,7 @@ namespace http { Request::Request(RequestMethod method, const std::string &url, std::string_view name, bool *cancelled, ProgressBarMode mode) : method_(method), url_(url), name_(name), progress_(cancelled), progressBarMode_(mode) { - INFO_LOG(HTTP, "HTTP %s request: %s (%.*s)", RequestMethodToString(method), url.c_str(), (int)name.size(), name.data()); + INFO_LOG(Log::HTTP, "HTTP %s request: %s (%.*s)", RequestMethodToString(method), url.c_str(), (int)name.size(), name.data()); progress_.callback = [=](int64_t bytes, int64_t contentLength, bool done) { std::string message; diff --git a/Common/Net/HTTPServer.cpp b/Common/Net/HTTPServer.cpp index a4e19d805b..623726cfca 100644 --- a/Common/Net/HTTPServer.cpp +++ b/Common/Net/HTTPServer.cpp @@ -67,7 +67,7 @@ ServerRequest::ServerRequest(int fd) header_.ParseHeaders(in_); if (header_.ok) { - VERBOSE_LOG(IO, "The request carried with it %i bytes", (int)header_.content_length); + VERBOSE_LOG(Log::IO, "The request carried with it %i bytes", (int)header_.content_length); } else { Close(); } @@ -77,11 +77,11 @@ ServerRequest::~ServerRequest() { Close(); if (!in_->Empty()) { - ERROR_LOG(IO, "Input not empty - invalid request?"); + ERROR_LOG(Log::IO, "Input not empty - invalid request?"); } delete in_; if (!out_->Empty()) { - WARN_LOG(IO, "Output not empty - connection abort? (%s) (%d bytes)", this->header_.resource, (int)out_->BytesRemaining()); + WARN_LOG(Log::IO, "Output not empty - connection abort? (%s) (%d bytes)", this->header_.resource, (int)out_->BytesRemaining()); } delete out_; } @@ -191,7 +191,7 @@ bool Server::Listen4(int port) { #else int err = errno; #endif - ERROR_LOG(IO, "Failed to bind to port %d, error=%d - Bailing (ipv4)", port, err); + ERROR_LOG(Log::IO, "Failed to bind to port %d, error=%d - Bailing (ipv4)", port, err); closesocket(listener_); return false; } @@ -209,7 +209,7 @@ bool Server::Listen4(int port) { port = ntohs(server_addr.sin_port); } - INFO_LOG(IO, "HTTP server started on port %d", port); + INFO_LOG(Log::IO, "HTTP server started on port %d", port); port_ = port; return true; @@ -241,7 +241,7 @@ bool Server::Listen6(int port, bool ipv6_only) { #else int err = errno; #endif - ERROR_LOG(IO, "Failed to bind to port %d, error=%d - Bailing (ipv6)", port, err); + ERROR_LOG(Log::IO, "Failed to bind to port %d, error=%d - Bailing (ipv6)", port, err); closesocket(listener_); return false; } @@ -259,7 +259,7 @@ bool Server::Listen6(int port, bool ipv6_only) { port = ntohs(server_addr.sin6_port); } - INFO_LOG(IO, "HTTP server started on port %d", port); + INFO_LOG(Log::IO, "HTTP server started on port %d", port); port_ = port; return true; @@ -294,7 +294,7 @@ bool Server::RunSlice(double timeout) { return true; } else { - ERROR_LOG(IO, "socket accept failed: %i", conn_fd); + ERROR_LOG(Log::IO, "socket accept failed: %i", conn_fd); return false; } } @@ -319,7 +319,7 @@ void Server::Stop() { void Server::HandleConnection(int conn_fd) { ServerRequest request(conn_fd); if (!request.IsOK()) { - WARN_LOG(IO, "Bad request, ignoring."); + WARN_LOG(Log::IO, "Bad request, ignoring."); return; } HandleRequest(request); @@ -351,9 +351,9 @@ void Server::HandleRequestDefault(const ServerRequest &request) { } void Server::Handle404(const ServerRequest &request) { - INFO_LOG(IO, "No handler for '%s', falling back to 404.", request.resource()); + INFO_LOG(Log::IO, "No handler for '%s', falling back to 404.", request.resource()); const char *payload = "404 not found\r\n"; - request.WriteHttpResponseHeader("1.0", 404, (int)strlen(payload)); + request.WriteHttpResponseHeader("1.0", 404, strlen(payload)); request.Out()->Push(payload); } diff --git a/Common/Net/NetBuffer.cpp b/Common/Net/NetBuffer.cpp index 09a4853963..cb36bcd6b7 100644 --- a/Common/Net/NetBuffer.cpp +++ b/Common/Net/NetBuffer.cpp @@ -44,14 +44,14 @@ bool Buffer::FlushSocket(uintptr_t sock, double timeout, bool *cancelled) { return false; ready = fd_util::WaitUntilReady(sock, CANCEL_INTERVAL, true); if (!ready && time_now_d() > endTimeout) { - ERROR_LOG(IO, "FlushSocket timed out"); + ERROR_LOG(Log::IO, "FlushSocket timed out"); return false; } } - int sent = send(sock, &data_[pos], (int)(end - pos), MSG_NOSIGNAL); + int sent = send(sock, &data_[pos], end - pos, MSG_NOSIGNAL); // TODO: Do we need some retry logic here, instead of just giving up? if (sent < 0) { - ERROR_LOG(IO, "FlushSocket failed to send: %d", errno); + ERROR_LOG(Log::IO, "FlushSocket failed to send: %d", errno); return false; } pos += sent; @@ -85,7 +85,7 @@ bool Buffer::ReadAllWithProgress(int fd, int knownSize, RequestProgress *progres ready = fd_util::WaitUntilReady(fd, CANCEL_INTERVAL, false); } - int retval = recv(fd, &buf[0], (int)buf.size(), MSG_NOSIGNAL); + int retval = recv(fd, &buf[0], buf.size(), MSG_NOSIGNAL); if (retval == 0) { return true; } else if (retval < 0) { @@ -94,7 +94,7 @@ bool Buffer::ReadAllWithProgress(int fd, int knownSize, RequestProgress *progres #else if (errno != EWOULDBLOCK) { #endif - ERROR_LOG(IO, "Error reading from buffer: %i", retval); + ERROR_LOG(Log::IO, "Error reading from buffer: %i", retval); return false; } @@ -116,7 +116,7 @@ int Buffer::Read(int fd, size_t sz) { char buf[1024]; int retval; size_t received = 0; - while ((retval = recv(fd, buf, (int)std::min(sz, sizeof(buf)), MSG_NOSIGNAL)) > 0) { + while ((retval = recv(fd, buf, std::min(sz, sizeof(buf)), MSG_NOSIGNAL)) > 0) { if (retval < 0) { return retval; } diff --git a/Common/Net/Resolve.cpp b/Common/Net/Resolve.cpp index c8fe425186..f7219d4ef8 100644 --- a/Common/Net/Resolve.cpp +++ b/Common/Net/Resolve.cpp @@ -133,7 +133,7 @@ bool GetIPList(std::vector &IP4s) { char ipstr[INET6_ADDRSTRLEN]; // We use IPv6 length since it's longer than IPv4 // getifaddrs first appeared in glibc 2.3, On Android officially supported since __ANDROID_API__ >= 24 #if defined(_IFADDRS_H_) || (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) || (__ANDROID_API__ >= 24) - INFO_LOG(SCENET, "GetIPList from getifaddrs"); + INFO_LOG(Log::sceNet, "GetIPList from getifaddrs"); struct ifaddrs* ifAddrStruct = NULL; struct ifaddrs* ifa = NULL; @@ -161,7 +161,7 @@ bool GetIPList(std::vector &IP4s) { return true; } #elif defined(SIOCGIFCONF) // Better detection on Linux/UNIX/MacOS/some Android - INFO_LOG(SCENET, "GetIPList from SIOCGIFCONF"); + INFO_LOG(Log::sceNet, "GetIPList from SIOCGIFCONF"); static struct ifreq ifreqs[32]; struct ifconf ifc; memset(&ifc, 0, sizeof(ifconf)); @@ -170,13 +170,13 @@ bool GetIPList(std::vector &IP4s) { int sd = socket(AF_INET, SOCK_DGRAM, 0); if (sd < 0) { - ERROR_LOG(SCENET, "GetIPList failed to create socket (result = %i, errno = %i)", sd, errno); + ERROR_LOG(Log::sceNet, "GetIPList failed to create socket (result = %i, errno = %i)", sd, errno); return false; } int r = ioctl(sd, SIOCGIFCONF, (char*)&ifc); if (r != 0) { - ERROR_LOG(SCENET, "GetIPList failed ioctl/SIOCGIFCONF (result = %i, errno = %i)", r, errno); + ERROR_LOG(Log::sceNet, "GetIPList failed ioctl/SIOCGIFCONF (result = %i, errno = %i)", r, errno); return false; } @@ -192,7 +192,7 @@ bool GetIPList(std::vector &IP4s) { r = ioctl(sd, SIOCGIFADDR, item); if (r != 0) { - ERROR_LOG(SCENET, "GetIPList failed ioctl/SIOCGIFADDR (i = %i, result = %i, errno = %i)", i, r, errno); + ERROR_LOG(Log::sceNet, "GetIPList failed ioctl/SIOCGIFADDR (i = %i, result = %i, errno = %i)", i, r, errno); } if (ifreqs[i].ifr_addr.sa_family == AF_INET) { @@ -212,7 +212,7 @@ bool GetIPList(std::vector &IP4s) { close(sd); return true; #else // Fallback to POSIX/Cross-platform way but may not works well on Linux (ie. only shows 127.0.0.1) - INFO_LOG(SCENET, "GetIPList from Fallback"); + INFO_LOG(Log::sceNet, "GetIPList from Fallback"); struct addrinfo hints, * res, * p; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version diff --git a/Common/Net/Sinks.cpp b/Common/Net/Sinks.cpp index 62eb407dac..d93f477f68 100644 --- a/Common/Net/Sinks.cpp +++ b/Common/Net/Sinks.cpp @@ -176,7 +176,7 @@ void InputSink::Fill() { // Whatever isn't valid and follows write_ is what's available. size_t avail = BUFFER_SIZE - std::max(write_, valid_); - int bytes = recv(fd_, buf_ + write_, (int)avail, MSG_NOSIGNAL); + int bytes = recv(fd_, buf_ + write_, avail, MSG_NOSIGNAL); AccountFill(bytes); } } @@ -200,7 +200,7 @@ void InputSink::AccountFill(int bytes) { if (errno == EWOULDBLOCK || errno == EAGAIN) return; #endif - ERROR_LOG(IO, "Error reading from socket"); + ERROR_LOG(Log::IO, "Error reading from socket"); return; } @@ -266,7 +266,7 @@ size_t OutputSink::PushAtMost(const char *buf, size_t bytes) { if (valid_ == 0 && bytes > PRESSURE) { // Special case for pushing larger buffers: let's try to send directly. - int sentBytes = send(fd_, buf, (int)bytes, MSG_NOSIGNAL); + int sentBytes = send(fd_, buf, bytes, MSG_NOSIGNAL); // If it was 0 or EWOULDBLOCK, that's fine, we'll enqueue as we can. if (sentBytes > 0) { return sentBytes; @@ -321,10 +321,10 @@ bool OutputSink::Printf(const char *fmt, ...) { // Okay, did we actually write? if (result >= (int)avail) { // This means the result string was too big for the buffer. - ERROR_LOG(IO, "Not enough space to format output."); + ERROR_LOG(Log::IO, "Not enough space to format output."); return false; } else if (result < 0) { - ERROR_LOG(IO, "vsnprintf failed."); + ERROR_LOG(Log::IO, "vsnprintf failed."); return false; } @@ -348,7 +348,7 @@ bool OutputSink::Flush(bool allowBlock) { while (valid_ > 0) { size_t avail = std::min(BUFFER_SIZE - read_, valid_); - int bytes = send(fd_, buf_ + read_, (int)avail, MSG_NOSIGNAL); + int bytes = send(fd_, buf_ + read_, avail, MSG_NOSIGNAL); #if !PPSSPP_PLATFORM(WINDOWS) if (bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) bytes = 0; @@ -380,7 +380,7 @@ void OutputSink::Drain() { // Let's just do contiguous valid. size_t avail = std::min(BUFFER_SIZE - read_, valid_); - int bytes = send(fd_, buf_ + read_, (int)avail, MSG_NOSIGNAL); + int bytes = send(fd_, buf_ + read_, avail, MSG_NOSIGNAL); #if !PPSSPP_PLATFORM(WINDOWS) if (bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) bytes = 0; @@ -407,7 +407,7 @@ void OutputSink::AccountDrain(int bytes) { if (errno == EWOULDBLOCK || errno == EAGAIN) return; #endif - ERROR_LOG(IO, "Error writing to socket"); + ERROR_LOG(Log::IO, "Error writing to socket"); return; } diff --git a/Common/Net/URL.cpp b/Common/Net/URL.cpp index 3280c39cc9..bef6efc2be 100644 --- a/Common/Net/URL.cpp +++ b/Common/Net/URL.cpp @@ -34,7 +34,7 @@ void UrlEncoder::AppendEscaped(const std::string &value) void Url::Split() { size_t colonSlashSlash = url_.find("://"); if (colonSlashSlash == std::string::npos) { - ERROR_LOG(IO, "Invalid URL: %s", url_.c_str()); + ERROR_LOG(Log::IO, "Invalid URL: %s", url_.c_str()); return; } diff --git a/Common/OSVersion.cpp b/Common/OSVersion.cpp index ee35ef7c4e..a69b8217c7 100644 --- a/Common/OSVersion.cpp +++ b/Common/OSVersion.cpp @@ -46,7 +46,7 @@ bool GetVersionFromKernel32(uint32_t &major, uint32_t &minor, uint32_t &build) { #endif } -bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor, uint32_t spMinor, bool greater) { +bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor, uint32_t spMinor, uint32_t build, bool greater) { #if !PPSSPP_PLATFORM(UWP) if (spMajor == 0 && spMinor == 0) { // "Applications not manifested for Windows 10 will return the Windows 8 OS version value (6.2)." @@ -55,7 +55,9 @@ bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor, u if (GetVersionFromKernel32(actualMajor, actualMinor, actualBuild)) { if (greater) return actualMajor > major || (major == actualMajor && actualMinor >= minor); - return major == actualMajor && minor == actualMinor; + + // To detect Windows 11 we must check build number + return major == actualMajor && minor == actualMinor && actualBuild >= build; } } @@ -86,59 +88,25 @@ bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor, u return VerifyVersionInfo(&osvi, typeMask, conditionMask) != FALSE; #else - if (greater) { + if (greater) return true; - } return false; #endif } -bool DoesVersionMatchWindows(WindowsReleaseInfo release) { - if (release.spMajor == 0 && release.spMinor == 0) { - // Compare Info - uint32_t major = release.major; - uint32_t minor = release.minor; - uint32_t build = release.build; - bool greater = release.greater; - - OSVERSIONINFOEX osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - GetVersionEx((LPOSVERSIONINFO)&osvi); - - // OS Info - uint32_t osMajor = osvi.dwMajorVersion; - uint32_t osMinor = osvi.dwMinorVersion; - uint32_t osBuild = osvi.dwBuildNumber; - -#if !PPSSPP_PLATFORM(UWP) - // "Applications not manifested for Windows 10 will return the Windows 8 OS version value (6.2)." - // Try to use kernel32.dll instead, for Windows 10+. - GetVersionFromKernel32(osMajor, osMinor, osBuild); -#endif - - if (major == osMajor) { - // To detect Windows 11 we must check build number - if (osMinor >= minor && osBuild >= build) { - return true; - } - } - } - else { - return DoesVersionMatchWindows(release.major, release.minor, release.spMajor, release.spMinor, release.greater); - } - - return false; -} - bool IsVistaOrHigher() { // Vista is 6.0 - return DoesVersionMatchWindows(6, 0, 0, 0, true); + return DoesVersionMatchWindows(6, 0, 0, 0, 0, true); } bool IsWin7OrHigher() { // Win7 is 6.1 - return DoesVersionMatchWindows(6, 1, 0, 0, true); + return DoesVersionMatchWindows(6, 1, 0, 0, 0, true); +} + +bool IsWin8OrHigher() { + // Win8 is 6.2 + return DoesVersionMatchWindows(6, 2, 0, 0, 0, true); } std::string GetWindowsVersion() { @@ -160,8 +128,7 @@ std::string GetWindowsVersion() { // Start from higher to lower for (auto release = rbegin(windowsReleases); release != rend(windowsReleases); ++release) { WindowsReleaseInfo releaseInfo = release->second; - bool buildMatch = DoesVersionMatchWindows(releaseInfo); - if (buildMatch) { + if (DoesVersionMatchWindows(releaseInfo.major, releaseInfo.minor, releaseInfo.spMajor, releaseInfo.spMinor, releaseInfo.build, releaseInfo.greater)) { std::string previewText = release->first; return previewText; } diff --git a/Common/OSVersion.h b/Common/OSVersion.h index 262cba05ac..c1704b85df 100644 --- a/Common/OSVersion.h +++ b/Common/OSVersion.h @@ -6,7 +6,10 @@ bool IsVistaOrHigher(); bool IsWin7OrHigher(); -bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor, uint32_t spMinor, bool acceptGreater); +bool IsWin8OrHigher(); +bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor, uint32_t spMinor, uint32_t build, bool acceptGreater); +bool GetVersionFromKernel32(uint32_t& major, uint32_t& minor, uint32_t& build); + std::string GetWindowsVersion(); std::string GetWindowsSystemArchitecture(); diff --git a/Common/Profiler/Profiler.cpp b/Common/Profiler/Profiler.cpp index 7d59a9add7..c5829ea980 100644 --- a/Common/Profiler/Profiler.cpp +++ b/Common/Profiler/Profiler.cpp @@ -146,7 +146,7 @@ int internal_profiler_enter(const char *category_name, int *out_thread_id) { } internal_profiler_resume(thread_id, category, now); } else { - DEBUG_LOG(SYSTEM, "profiler: recursive enter (%i - %s)", category, category_name); + DEBUG_LOG(Log::System, "profiler: recursive enter (%i - %s)", category, category_name); } depth++; @@ -163,7 +163,7 @@ void internal_profiler_leave(int thread_id, int category) { int &depth = profiler.depth[thread_id]; if (category < 0 || category >= MAX_CATEGORIES) { - ERROR_LOG(SYSTEM, "Bad category index %d", category); + ERROR_LOG(Log::System, "Bad category index %d", category); depth--; return; } diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 8e29732394..63c06f4c98 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -69,7 +69,7 @@ void DrawBuffer::Flush(bool set_blend_state) { if (count_ == 0) return; if (!pipeline_) { - ERROR_LOG(G3D, "DrawBuffer: No program set, skipping flush!"); + ERROR_LOG(Log::G3D, "DrawBuffer: No program set, skipping flush!"); count_ = 0; return; } @@ -446,34 +446,31 @@ void DrawBuffer::DrawImage2GridH(ImageID atlas_image, float x1, float y1, float class AtlasWordWrapper : public WordWrapper { public: // Note: maxW may be height if rotated. - AtlasWordWrapper(const AtlasFont &atlasfont, float scale, const char *str, float maxW, int flags) : WordWrapper(str, maxW, flags), atlasfont_(atlasfont), scale_(scale) { + AtlasWordWrapper(const AtlasFont &atlasfont, float scale, std::string_view str, float maxW, int flags) + : WordWrapper(str, maxW, flags), atlasfont_(atlasfont), scale_(scale) { } protected: - float MeasureWidth(const char *str, size_t bytes) override; + float MeasureWidth(std::string_view str) override; const AtlasFont &atlasfont_; const float scale_; }; -float AtlasWordWrapper::MeasureWidth(const char *str, size_t bytes) { +float AtlasWordWrapper::MeasureWidth(std::string_view str) { float w = 0.0f; - for (UTF8 utf(str); utf.byteIndex() < (int)bytes; ) { + for (UTF8 utf(str); !utf.end(); ) { uint32_t c = utf.next(); - if (c == '&') { - // Skip ampersand prefixes ("&&" is an ampersand.) - c = utf.next(); - } const AtlasChar *ch = atlasfont_.getChar(c); - if (!ch) + if (!ch) { ch = atlasfont_.getChar('?'); - + } w += ch->wx * scale_; } return w; } -void DrawBuffer::MeasureTextCount(FontID font, const char *text, int count, float *w, float *h) { +void DrawBuffer::MeasureText(FontID font, std::string_view text, float *w, float *h) { const AtlasFont *atlasfont = fontAtlas_->getFont(font); if (!atlasfont) atlasfont = atlas->getFont(font); @@ -491,7 +488,7 @@ void DrawBuffer::MeasureTextCount(FontID font, const char *text, int count, floa while (true) { if (utf.end()) break; - if (utf.byteIndex() >= count) + if (utf.byteIndex() >= text.length()) break; cval = utf.next(); // Translate non-breaking space to space. @@ -517,14 +514,14 @@ void DrawBuffer::MeasureTextCount(FontID font, const char *text, int count, floa if (h) *h = atlasfont->height * fontscaley * lines; } -void DrawBuffer::MeasureTextRect(FontID font_id, const char *text, int count, const Bounds &bounds, float *w, float *h, int align) { - if (!text || font_id.isInvalid()) { +void DrawBuffer::MeasureTextRect(FontID font_id, std::string_view text, const Bounds &bounds, float *w, float *h, int align) { + if (text.empty() || font_id.isInvalid()) { *w = 0.0f; *h = 0.0f; return; } - std::string toMeasure = std::string(text, count); + std::string toMeasure = std::string(text); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); if (wrap) { const AtlasFont *font = fontAtlas_->getFont(font_id); @@ -535,17 +532,13 @@ void DrawBuffer::MeasureTextRect(FontID font_id, const char *text, int count, co *h = 0.0f; return; } - AtlasWordWrapper wrapper(*font, fontscalex, toMeasure.c_str(), bounds.w, wrap); + AtlasWordWrapper wrapper(*font, fontscalex, toMeasure, bounds.w, wrap); toMeasure = wrapper.Wrapped(); } - MeasureTextCount(font_id, toMeasure.c_str(), (int)toMeasure.length(), w, h); + MeasureText(font_id, toMeasure, w, h); } -void DrawBuffer::MeasureText(FontID font, const char *text, float *w, float *h) { - return MeasureTextCount(font, text, (int)strlen(text), w, h); -} - -void DrawBuffer::DrawTextShadow(FontID font, const char *text, float x, float y, Color color, int flags) { +void DrawBuffer::DrawTextShadow(FontID font, std::string_view text, float x, float y, Color color, int flags) { uint32_t alpha = (color >> 1) & 0xFF000000; DrawText(font, text, x + 2, y + 2, alpha, flags); DrawText(font, text, x, y, color, flags); @@ -556,15 +549,10 @@ void DrawBuffer::DoAlign(int flags, float *x, float *y, float *w, float *h) { if (flags & ALIGN_RIGHT) *x -= *w; if (flags & ALIGN_VCENTER) *y -= *h / 2; if (flags & ALIGN_BOTTOM) *y -= *h; - if (flags & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) { - std::swap(*w, *h); - std::swap(*x, *y); - } } - // TODO: Actually use the rect properly, take bounds. -void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, float w, float h, Color color, int align) { +void DrawBuffer::DrawTextRect(FontID font, std::string_view text, float x, float y, float w, float h, Color color, int align) { if (align & ALIGN_HCENTER) { x += w / 2; } else if (align & ALIGN_RIGHT) { @@ -576,18 +564,18 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f y += h; } - std::string toDraw = text; + std::string toDraw(text); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); const AtlasFont *atlasfont = fontAtlas_->getFont(font); if (!atlasfont) atlasfont = atlas->getFont(font); if (wrap && atlasfont) { - AtlasWordWrapper wrapper(*atlasfont, fontscalex, toDraw.c_str(), w, wrap); + AtlasWordWrapper wrapper(*atlasfont, fontscalex, toDraw, w, wrap); toDraw = wrapper.Wrapped(); } float totalWidth, totalHeight; - MeasureTextRect(font, toDraw.c_str(), (int)toDraw.size(), Bounds(x, y, w, h), &totalWidth, &totalHeight, align); + MeasureTextRect(font, toDraw, Bounds(x, y, w, h), &totalWidth, &totalHeight, align); std::vector lines; SplitString(toDraw, '\n', lines); @@ -606,21 +594,22 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f DrawText(font, line.c_str(), x, baseY, color, align); float tw, th; - MeasureText(font, line.c_str(), &tw, &th); + MeasureText(font, line, &tw, &th); baseY += th; } } // ROTATE_* doesn't yet work right. -void DrawBuffer::DrawText(FontID font, const char *text, float x, float y, Color color, int align) { +void DrawBuffer::DrawText(FontID font, std::string_view text, float x, float y, Color color, int align) { // rough estimate - size_t textLen = strlen(text); + int textLen = (int)text.length(); if (count_ + textLen * 6 > MAX_VERTS) { Flush(true); if (textLen * 6 >= MAX_VERTS) { textLen = std::min(MAX_VERTS / 6 - 10, (int)textLen); } } + text = text.substr(0, textLen); const AtlasFont *atlasfont = fontAtlas_->getFont(font); if (!atlasfont) @@ -634,12 +623,8 @@ void DrawBuffer::DrawText(FontID font, const char *text, float x, float y, Color DoAlign(align, &x, &y, &w, &h); } - if (align & ROTATE_90DEG_LEFT) { - x -= atlasfont->ascend * fontscaley; - // y += h; - } else { - y += atlasfont->ascend * fontscaley; - } + y += atlasfont->ascend * fontscaley; + float sx = x; UTF8 utf(text); for (size_t i = 0; i < textLen; i++) { @@ -665,27 +650,17 @@ void DrawBuffer::DrawText(FontID font, const char *text, float x, float y, Color if (ch) { const AtlasChar &c = *ch; float cx1, cy1, cx2, cy2; - if (align & ROTATE_90DEG_LEFT) { - cy1 = y - c.ox * fontscalex; - cx1 = x + c.oy * fontscaley; - cy2 = y - (c.ox + c.pw) * fontscalex; - cx2 = x + (c.oy + c.ph) * fontscaley; - } else { - cx1 = x + c.ox * fontscalex; - cy1 = y + c.oy * fontscaley; - cx2 = x + (c.ox + c.pw) * fontscalex; - cy2 = y + (c.oy + c.ph) * fontscaley; - } + cx1 = x + c.ox * fontscalex; + cy1 = y + c.oy * fontscaley; + cx2 = x + (c.ox + c.pw) * fontscalex; + cy2 = y + (c.oy + c.ph) * fontscaley; V(cx1, cy1, color, c.sx, c.sy); V(cx2, cy1, color, c.ex, c.sy); V(cx2, cy2, color, c.ex, c.ey); V(cx1, cy1, color, c.sx, c.sy); V(cx2, cy2, color, c.ex, c.ey); V(cx1, cy2, color, c.sx, c.ey); - if (align & ROTATE_90DEG_LEFT) - y -= c.wx * fontscalex; - else - x += c.wx * fontscalex; + x += c.wx * fontscalex; } } } diff --git a/Common/Render/DrawBuffer.h b/Common/Render/DrawBuffer.h index c8ac2815f4..378a43f7fe 100644 --- a/Common/Render/DrawBuffer.h +++ b/Common/Render/DrawBuffer.h @@ -28,11 +28,6 @@ enum { ALIGN_BOTTOMLEFT = ALIGN_BOTTOM | ALIGN_LEFT, ALIGN_BOTTOMRIGHT = ALIGN_BOTTOM | ALIGN_RIGHT, - // Only for text drawing - ROTATE_90DEG_LEFT = 256, - ROTATE_90DEG_RIGHT = 512, - ROTATE_180DEG = 1024, - // For "uncachable" text like debug log. // Avoids using system font drawing as it's too slow. // Not actually used here but is reserved for whatever system wraps DrawBuffer. @@ -131,15 +126,13 @@ public: // This is only 6 triangles, much cheaper. void DrawImage2GridH(ImageID atlas_image, float x1, float y1, float x2, Color color = COLOR(0xFFFFFF), float scale = 1.0); - void MeasureText(FontID font, const char *text, float *w, float *h); + void MeasureText(FontID font, std::string_view text, float *w, float *h); - // NOTE: Count is in plain chars not utf-8 chars! - void MeasureTextCount(FontID font, const char *text, int count, float *w, float *h); - void MeasureTextRect(FontID font, const char *text, int count, const Bounds &bounds, float *w, float *h, int align = 0); + void MeasureTextRect(FontID font, std::string_view text, const Bounds &bounds, float *w, float *h, int align = 0); - void DrawTextRect(FontID font, const char *text, float x, float y, float w, float h, Color color = 0xFFFFFFFF, int align = 0); - void DrawText(FontID font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); - void DrawTextShadow(FontID font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); + void DrawTextRect(FontID font, std::string_view text, float x, float y, float w, float h, Color color = 0xFFFFFFFF, int align = 0); + void DrawText(FontID font, std::string_view text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); + void DrawTextShadow(FontID font, std::string_view text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); void SetFontScale(float xs, float ys) { fontscalex = xs; diff --git a/Common/Render/ManagedTexture.cpp b/Common/Render/ManagedTexture.cpp index 0bf8407219..027abd2b77 100644 --- a/Common/Render/ManagedTexture.cpp +++ b/Common/Render/ManagedTexture.cpp @@ -32,7 +32,7 @@ public: size_t fileSize; uint8_t *buffer = g_VFS.ReadFile(filename_.c_str(), &fileSize); if (!buffer) { - ERROR_LOG(IO, "Failed to read file '%s'", filename_.c_str()); + WARN_LOG(Log::IO, "Failed to read file '%s'", filename_.c_str()); filename_.clear(); *state_ = ManagedTexture::LoadState::FAILED; waitable_->Notify(); @@ -90,7 +90,7 @@ bool TempImage::LoadTextureLevelsFromFileData(const uint8_t *data, size_t size, typeSuggestion = DetectImageFileType(data, size); } if (typeSuggestion == ImageFileType::UNKNOWN) { - ERROR_LOG(G3D, "File (size: %d) has unknown format", (int)size); + ERROR_LOG(Log::G3D, "File (size: %d) has unknown format", (int)size); return false; } @@ -109,11 +109,11 @@ bool TempImage::LoadTextureLevelsFromFileData(const uint8_t *data, size_t size, numLevels = 1; fmt = Draw::DataFormat::R8G8B8A8_UNORM; if (!levels[0]) { - ERROR_LOG(IO, "pngLoadPtr failed (input size = %d)", (int)size); + ERROR_LOG(Log::IO, "pngLoadPtr failed (input size = %d)", (int)size); return false; } } else { - ERROR_LOG(IO, "PNG load failed"); + ERROR_LOG(Log::IO, "PNG load failed"); return false; } break; @@ -131,7 +131,7 @@ bool TempImage::LoadTextureLevelsFromFileData(const uint8_t *data, size_t size, } default: - ERROR_LOG(IO, "Unsupported image format %d", (int)type); + ERROR_LOG(Log::IO, "Unsupported image format %d", (int)type); return false; } @@ -144,7 +144,7 @@ Draw::Texture *CreateTextureFromTempImage(Draw::DrawContext *draw, const TempIma int numLevels = image.numLevels; if (numLevels < 0 || numLevels >= 16) { - ERROR_LOG(IO, "Invalid num_levels: %d. Falling back to one. Image: %dx%d", numLevels, image.width[0], image.height[0]); + ERROR_LOG(Log::IO, "Invalid num_levels: %d. Falling back to one. Image: %dx%d", numLevels, image.width[0], image.height[0]); numLevels = 1; } @@ -178,7 +178,7 @@ Draw::Texture *CreateTextureFromFile(Draw::DrawContext *draw, const char *filena size_t fileSize; uint8_t *buffer = g_VFS.ReadFile(filename, &fileSize); if (!buffer) { - ERROR_LOG(IO, "Failed to read file '%s'", filename); + ERROR_LOG(Log::IO, "Failed to read file '%s'", filename); return nullptr; } Draw::Texture *texture = CreateTextureFromFileData(draw, buffer, fileSize, type, generateMips, filename); @@ -228,7 +228,7 @@ void ManagedTexture::StartLoadTask() { } void ManagedTexture::DeviceLost() { - INFO_LOG(G3D, "ManagedTexture::DeviceLost(%s)", filename_.c_str()); + INFO_LOG(Log::G3D, "ManagedTexture::DeviceLost(%s)", filename_.c_str()); if (taskWaitable_) { taskWaitable_->WaitAndRelease(); taskWaitable_ = nullptr; @@ -243,13 +243,13 @@ void ManagedTexture::DeviceLost() { } void ManagedTexture::DeviceRestored(Draw::DrawContext *draw) { - INFO_LOG(G3D, "ManagedTexture::DeviceRestored(%s)", filename_.c_str()); + INFO_LOG(Log::G3D, "ManagedTexture::DeviceRestored(%s)", filename_.c_str()); draw_ = draw; _dbg_assert_(!texture_); if (texture_) { - ERROR_LOG(G3D, "ManagedTexture: Unexpected - texture already present: %s", filename_.c_str()); + ERROR_LOG(Log::G3D, "ManagedTexture: Unexpected - texture already present: %s", filename_.c_str()); return; } diff --git a/Common/Render/Text/draw_text.cpp b/Common/Render/Text/draw_text.cpp index cb09dbda98..020d777d47 100644 --- a/Common/Render/Text/draw_text.cpp +++ b/Common/Render/Text/draw_text.cpp @@ -8,6 +8,7 @@ #include "Common/Render/Text/draw_text.h" #include "Common/Render/Text/draw_text_win.h" +#include "Common/Render/Text/draw_text_cocoa.h" #include "Common/Render/Text/draw_text_uwp.h" #include "Common/Render/Text/draw_text_qt.h" #include "Common/Render/Text/draw_text_android.h" @@ -20,13 +21,13 @@ TextDrawer::TextDrawer(Draw::DrawContext *draw) : draw_(draw) { TextDrawer::~TextDrawer() { } -float TextDrawerWordWrapper::MeasureWidth(const char *str, size_t bytes) { +float TextDrawerWordWrapper::MeasureWidth(std::string_view str) { float w, h; - drawer_->MeasureString(str, bytes, &w, &h); + drawer_->MeasureString(str, &w, &h); return w; } -void TextDrawer::WrapString(std::string &out, const char *str, float maxW, int flags) { +void TextDrawer::WrapString(std::string &out, std::string_view str, float maxW, int flags) { TextDrawerWordWrapper wrapper(this, str, maxW, flags); out = wrapper.Wrapped(); } @@ -46,7 +47,92 @@ float TextDrawer::CalculateDPIScale() { return scale; } -void TextDrawer::DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) { +void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, float y, uint32_t color, int align) { + using namespace Draw; + if (str.empty()) { + return; + } + + CacheKey key{ std::string(str), fontHash_ }; + target.Flush(true); + + TextStringEntry *entry; + + auto iter = cache_.find(key); + if (iter != cache_.end()) { + entry = iter->second.get(); + entry->lastUsedFrame = frameCount_; + if (!entry->texture) { + return; + } + } else { + DataFormat texFormat; + // Pick between the supported formats, of which at least one is supported on each platform. Prefer R8 (but only if swizzle is supported) + bool emoji = SupportsColorEmoji() && AnyEmojiInString(str.data(), str.length()); + if (emoji) { + texFormat = Draw::DataFormat::R8G8B8A8_UNORM; + } else if ((draw_->GetDataFormatSupport(Draw::DataFormat::R8_UNORM) & Draw::FMT_TEXTURE) != 0 && draw_->GetDeviceCaps().textureSwizzleSupported) { + texFormat = Draw::DataFormat::R8_UNORM; + } else if (draw_->GetDataFormatSupport(Draw::DataFormat::R4G4B4A4_UNORM_PACK16) & FMT_TEXTURE) { + texFormat = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; + } else if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE) { + texFormat = Draw::DataFormat::A4R4G4B4_UNORM_PACK16; + } else if (draw_->GetDataFormatSupport(Draw::DataFormat::B4G4R4A4_UNORM_PACK16) & FMT_TEXTURE) { + texFormat = Draw::DataFormat::B4G4R4A4_UNORM_PACK16; + } else { + texFormat = Draw::DataFormat::R8G8B8A8_UNORM; + } + + entry = new TextStringEntry(frameCount_); + + // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format + // because we need white. Well, we could using swizzle, but not all our backends support that. + TextureDesc desc{}; + std::vector bitmapData; + if (!DrawStringBitmap(bitmapData, *entry, texFormat, str, align, emoji)) { + // Nothing drawn. Store that fact in the cache. + cache_[key] = std::unique_ptr(entry); + return; + } + + desc.initData.push_back(&bitmapData[0]); + + desc.type = TextureType::LINEAR2D; + desc.format = texFormat; + desc.width = entry->bmWidth; + desc.height = entry->bmHeight; + desc.depth = 1; + desc.mipLevels = 1; + desc.tag = "TextDrawer"; + desc.swizzle = texFormat == Draw::DataFormat::R8_UNORM ? Draw::TextureSwizzle::R8_AS_ALPHA : Draw::TextureSwizzle::DEFAULT, + entry->texture = draw_->CreateTexture(desc); + cache_[key] = std::unique_ptr(entry); + } + + _dbg_assert_(entry->texture); + draw_->BindTexture(0, entry->texture); + + // Okay, the texture is bound, let's draw. + float w = (float)entry->width * (fontScaleX_ * dpiScale_); + float h = (float)entry->height * (fontScaleY_ * dpiScale_); + float u = (float)entry->width / (float)entry->bmWidth; + float v = (float)entry->height / (float)entry->bmHeight; + DrawBuffer::DoAlign(align, &x, &y, &w, &h); + + target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, u, v, color); + target.Flush(true); +} + +void TextDrawer::MeasureStringRect(std::string_view str, const Bounds &bounds, float *w, float *h, int align) { + std::string toMeasure = std::string(str); + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { + WrapString(toMeasure, toMeasure.c_str(), bounds.w, wrap); + } + MeasureString(toMeasure, w, h); +} + +void TextDrawer::DrawStringRect(DrawBuffer &target, std::string_view str, const Bounds &bounds, uint32_t color, int align) { float x = bounds.x; float y = bounds.y; if (align & ALIGN_HCENTER) { @@ -60,25 +146,65 @@ void TextDrawer::DrawStringRect(DrawBuffer &target, const char *str, const Bound y = bounds.y2(); } - std::string toDraw = str; + std::string toDraw(str); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); if (wrap) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toDraw, str, rotated ? bounds.h : bounds.w, wrap); + WrapString(toDraw, str, bounds.w, wrap); } DrawString(target, toDraw.c_str(), x, y, color, align); } -void TextDrawer::DrawStringBitmapRect(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, const Bounds &bounds, int align) { - std::string toDraw = str; +bool TextDrawer::DrawStringBitmapRect(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, const Bounds &bounds, int align, bool fullColor) { + std::string toDraw(str); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); if (wrap) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toDraw, str, rotated ? bounds.h : bounds.w, wrap); + WrapString(toDraw, str, bounds.w, wrap); + } + return DrawStringBitmap(bitmapData, entry, texFormat, toDraw.c_str(), align, fullColor); +} + +void TextDrawer::ClearCache() { + for (auto &iter : cache_) { + if (iter.second->texture) + iter.second->texture->Release(); + } + cache_.clear(); + sizeCache_.clear(); + fontHash_ = 0; +} + +void TextDrawer::OncePerFrame() { + frameCount_++; + // If DPI changed (small-mode, future proper monitor DPI support), drop everything. + float newDpiScale = CalculateDPIScale(); + if (newDpiScale != dpiScale_) { + INFO_LOG(Log::G3D, "DPI Scale changed (%f to %f) - wiping font cache (%d items)", dpiScale_, newDpiScale, (int)cache_.size()); + dpiScale_ = newDpiScale; + ClearCache(); + ClearFonts(); } - DrawStringBitmap(bitmapData, entry, texFormat, toDraw.c_str(), align); + // Drop old strings. Use a prime number to reduce clashing with other rhythms + if (frameCount_ % 23 == 0) { + for (auto iter = cache_.begin(); iter != cache_.end();) { + if (frameCount_ - iter->second->lastUsedFrame > 100) { + if (iter->second->texture) + iter->second->texture->Release(); + cache_.erase(iter++); + } else { + iter++; + } + } + + for (auto iter = sizeCache_.begin(); iter != sizeCache_.end(); ) { + if (frameCount_ - iter->second->lastUsedFrame > 100) { + sizeCache_.erase(iter++); + } else { + iter++; + } + } + } } TextDrawer *TextDrawer::Create(Draw::DrawContext *draw) { @@ -89,6 +215,8 @@ TextDrawer *TextDrawer::Create(Draw::DrawContext *draw) { drawer = new TextDrawerWin32(draw); #elif PPSSPP_PLATFORM(UWP) drawer = new TextDrawerUWP(draw); +#elif PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) + drawer = new TextDrawerCocoa(draw); #elif defined(USING_QT_UI) drawer = new TextDrawerQt(draw); #elif PPSSPP_PLATFORM(ANDROID) diff --git a/Common/Render/Text/draw_text.h b/Common/Render/Text/draw_text.h index 252029b8a3..9f8f7c08e6 100644 --- a/Common/Render/Text/draw_text.h +++ b/Common/Render/Text/draw_text.h @@ -12,6 +12,7 @@ #include #include +#include #include "Common/Data/Text/WrapText.h" #include "Common/Render/DrawBuffer.h" @@ -22,17 +23,20 @@ namespace Draw { } struct TextStringEntry { - Draw::Texture *texture; - int width; - int height; - int bmWidth; - int bmHeight; + TextStringEntry(int frameCount) : lastUsedFrame(frameCount) {} + + Draw::Texture *texture = nullptr; + int width = 0; + int height = 0; + int bmWidth = 0; + int bmHeight = 0; int lastUsedFrame; }; struct TextMeasureEntry { int width; int height; + int leading; // only used with Cocoa int lastUsedFrame; }; @@ -44,14 +48,15 @@ public: virtual uint32_t SetFont(const char *fontName, int size, int flags) = 0; virtual void SetFont(uint32_t fontHandle) = 0; // Shortcut once you've set the font once. void SetFontScale(float xscale, float yscale); - virtual void MeasureString(const char *str, size_t len, float *w, float *h) = 0; - virtual void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) = 0; - virtual void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) = 0; - void DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align); - virtual void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) = 0; - void DrawStringBitmapRect(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, const Bounds &bounds, int align); + virtual void MeasureString(std::string_view str, float *w, float *h) = 0; + virtual void MeasureStringRect(std::string_view str, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT); + + void DrawString(DrawBuffer &target, std::string_view str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT); + void DrawStringRect(DrawBuffer &target, std::string_view str, const Bounds &bounds, uint32_t color, int align); + virtual bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) = 0; + bool DrawStringBitmapRect(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, const Bounds &bounds, int align, bool fullColor); // Use for housekeeping like throwing out old strings. - virtual void OncePerFrame() = 0; + void OncePerFrame(); float CalculateDPIScale(); void SetForcedDPIScale(float dpi) { @@ -64,10 +69,12 @@ public: protected: TextDrawer(Draw::DrawContext *draw); + void ClearCache(); - Draw::DrawContext *draw_; - virtual void ClearCache() = 0; - void WrapString(std::string &out, const char *str, float maxWidth, int flags); + virtual bool SupportsColorEmoji() const = 0; + virtual void ClearFonts() = 0; + + void WrapString(std::string &out, std::string_view str, float maxWidth, int flags); struct CacheKey { bool operator < (const CacheKey &other) const { @@ -81,20 +88,27 @@ protected: uint32_t fontHash; }; + Draw::DrawContext *draw_; + int frameCount_ = 0; float fontScaleX_ = 1.0f; float fontScaleY_ = 1.0f; float dpiScale_ = 1.0f; bool ignoreGlobalDpi_ = false; + + uint32_t fontHash_ = 0; + + std::map> cache_; + std::map> sizeCache_; }; class TextDrawerWordWrapper : public WordWrapper { public: - TextDrawerWordWrapper(TextDrawer *drawer, const char *str, float maxW, int flags) + TextDrawerWordWrapper(TextDrawer *drawer, std::string_view str, float maxW, int flags) : WordWrapper(str, maxW, flags), drawer_(drawer) {} protected: - float MeasureWidth(const char *str, size_t bytes) override; + float MeasureWidth(std::string_view str) override; TextDrawer *drawer_; }; diff --git a/Common/Render/Text/draw_text_android.cpp b/Common/Render/Text/draw_text_android.cpp index d98987ccea..df8da6a8b8 100644 --- a/Common/Render/Text/draw_text_android.cpp +++ b/Common/Render/Text/draw_text_android.cpp @@ -25,15 +25,11 @@ TextDrawerAndroid::TextDrawerAndroid(Draw::DrawContext *draw) : TextDrawer(draw) method_measureText = env->GetStaticMethodID(cls_textRenderer, "measureText", "(Ljava/lang/String;D)I"); method_renderText = env->GetStaticMethodID(cls_textRenderer, "renderText", "(Ljava/lang/String;D)[I"); } else { - ERROR_LOG(G3D, "Failed to find class: '%s'", textRendererClassName); + ERROR_LOG(Log::G3D, "Failed to find class: '%s'", textRendererClassName); } dpiScale_ = CalculateDPIScale(); - // Pick between the two supported formats, of which at least one is supported on each platform. Prefer R8 (but only if swizzle is supported) - use4444Format_ = (draw->GetDataFormatSupport(Draw::DataFormat::R4G4B4A4_UNORM_PACK16) & Draw::FMT_TEXTURE) != 0; - if ((draw->GetDataFormatSupport(Draw::DataFormat::R8_UNORM) & Draw::FMT_TEXTURE) != 0 && draw->GetDeviceCaps().textureSwizzleSupported) - use4444Format_ = false; - INFO_LOG(G3D, "Initializing TextDrawerAndroid with DPI scale %f, use4444=%d", dpiScale_, (int)use4444Format_); + INFO_LOG(Log::G3D, "Initializing TextDrawerAndroid with DPI scale %f", dpiScale_); } TextDrawerAndroid::~TextDrawerAndroid() { @@ -41,6 +37,7 @@ TextDrawerAndroid::~TextDrawerAndroid() { // At worst we leak one ref... // env_->DeleteGlobalRef(cls_textRenderer); ClearCache(); + ClearFonts(); } bool TextDrawerAndroid::IsReady() const { @@ -74,22 +71,18 @@ void TextDrawerAndroid::SetFont(uint32_t fontHandle) { if (iter != fontMap_.end()) { fontHash_ = fontHandle; } else { - ERROR_LOG(G3D, "Invalid font handle %08x", fontHandle); + ERROR_LOG(Log::G3D, "Invalid font handle %08x", fontHandle); } } -std::string TextDrawerAndroid::NormalizeString(std::string str) { - return ReplaceAll(str, "&&", "&"); -} - -void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, float *h) { - if (!str) { +void TextDrawerAndroid::MeasureString(std::string_view str, float *w, float *h) { + if (str.empty()) { *w = 0.0; *h = 0.0; return; } - CacheKey key{ std::string(str, len), fontHash_ }; + CacheKey key{ std::string(str), fontHash_ }; TextMeasureEntry *entry; auto iter = sizeCache_.find(key); if (iter != sizeCache_.end()) { @@ -100,10 +93,11 @@ void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, flo if (iter != fontMap_.end()) { scaledSize = iter->second.size; } else { - ERROR_LOG(G3D, "Missing font"); + ERROR_LOG(Log::G3D, "Missing font"); } - std::string text(NormalizeString(std::string(str, len))); + std::string text(str); auto env = getEnv(); + // Unfortunate that we can't create a jstr from a std::string_view directly. jstring jstr = env->NewStringUTF(text.c_str()); uint32_t size = env->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, scaledSize); env->DeleteLocalRef(jstr); @@ -118,61 +112,10 @@ void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, flo *h = entry->height * fontScaleY_ * dpiScale_; } -void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) { - double scaledSize = 14; - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - scaledSize = iter->second.size; - } else { - ERROR_LOG(G3D, "Missing font"); - } - - std::string toMeasure = std::string(str, len); - int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - if (wrap) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); - } - - auto env = getEnv(); - std::vector lines; - SplitString(toMeasure, '\n', lines); - int total_w = 0; - int total_h = 0; - for (size_t i = 0; i < lines.size(); i++) { - CacheKey key{ lines[i], fontHash_ }; - - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - std::string text(NormalizeString(lines[i])); - jstring jstr = env->NewStringUTF(text.c_str()); - uint32_t size = env->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, scaledSize); - env->DeleteLocalRef(jstr); - int sizecx = size >> 16; - int sizecy = size & 0xFFFF; - entry = new TextMeasureEntry(); - entry->width = sizecx; - entry->height = sizecy; - sizeCache_[key] = std::unique_ptr(entry); - } - entry->lastUsedFrame = frameCount_; - - if (total_w < entry->width) { - total_w = entry->width; - } - total_h += entry->height; - } - *w = total_w * fontScaleX_ * dpiScale_; - *h = total_h * fontScaleY_ * dpiScale_; -} - -void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { - if (!strlen(str)) { +bool TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { + if (str.empty()) { bitmapData.clear(); - return; + return false; } double size = 0.0; @@ -180,11 +123,11 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS if (iter != fontMap_.end()) { size = iter->second.size; } else { - ERROR_LOG(G3D, "Missing font"); + ERROR_LOG(Log::G3D, "Missing font"); } auto env = getEnv(); - jstring jstr = env->NewStringUTF(str); + jstring jstr = env->NewStringUTF(std::string(str).c_str()); uint32_t textSize = env->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, size); int imageWidth = (short)(textSize >> 16); int imageHeight = (short)(textSize & 0xFFFF); @@ -239,107 +182,11 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS } env->ReleaseIntArrayElements(imageData, jimage, 0); env->DeleteLocalRef(imageData); + return true; } -void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { - using namespace Draw; - if (!str) - return; - - std::string text(NormalizeString(std::string(str))); - if (text.empty()) - return; - - CacheKey key{ std::string(str), fontHash_ }; - target.Flush(true); - - TextStringEntry *entry; - - auto iter = cache_.find(key); - if (iter != cache_.end()) { - entry = iter->second.get(); - entry->lastUsedFrame = frameCount_; - } else { - DataFormat texFormat = use4444Format_ ? Draw::DataFormat::R4G4B4A4_UNORM_PACK16 : Draw::DataFormat::R8_UNORM; - bool emoji = AnyEmojiInString(text.c_str(), text.size()); - if (emoji) { - texFormat = Draw::DataFormat::R8G8B8A8_UNORM; - } - - entry = new TextStringEntry(); - - TextureDesc desc{}; - std::vector bitmapData; - DrawStringBitmap(bitmapData, *entry, texFormat, text.c_str(), align); - desc.initData.push_back(&bitmapData[0]); - - desc.type = TextureType::LINEAR2D; - desc.format = texFormat; - desc.width = entry->bmWidth; - desc.height = entry->bmHeight; - desc.depth = 1; - desc.mipLevels = 1; - desc.generateMips = false; - desc.swizzle = texFormat == Draw::DataFormat::R8_UNORM ? Draw::TextureSwizzle::R8_AS_ALPHA : Draw::TextureSwizzle::DEFAULT, - desc.tag = "TextDrawer"; - entry->texture = draw_->CreateTexture(desc); - cache_[key] = std::unique_ptr(entry); - } - - if (entry->texture) { - draw_->BindTexture(0, entry->texture); - } - - float w = entry->bmWidth * fontScaleX_ * dpiScale_; - float h = entry->bmHeight * fontScaleY_ * dpiScale_; - DrawBuffer::DoAlign(align, &x, &y, &w, &h); - if (entry->texture) { - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); - target.Flush(true); - } -} - -void TextDrawerAndroid::ClearCache() { - for (auto &iter : cache_) { - if (iter.second->texture) - iter.second->texture->Release(); - } - cache_.clear(); - sizeCache_.clear(); -} - -void TextDrawerAndroid::OncePerFrame() { - frameCount_++; - // If DPI changed (small-mode, future proper monitor DPI support), drop everything. - float newDpiScale = CalculateDPIScale(); - if (newDpiScale != dpiScale_) { - // TODO: Don't bother if it's a no-op (cache already empty) - INFO_LOG(G3D, "DPI Scale changed (%f to %f) - wiping font cache (%d items, %d fonts)", dpiScale_, newDpiScale, (int)cache_.size(), (int)fontMap_.size()); - dpiScale_ = newDpiScale; - ClearCache(); - fontMap_.clear(); // size is precomputed using dpiScale_. - } - - // Drop old strings. Use a prime number to reduce clashing with other rhythms - if (frameCount_ % 23 == 0) { - for (auto iter = cache_.begin(); iter != cache_.end();) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - if (iter->second->texture) - iter->second->texture->Release(); - cache_.erase(iter++); - } else { - iter++; - } - } - - for (auto iter = sizeCache_.begin(); iter != sizeCache_.end(); ) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - sizeCache_.erase(iter++); - } else { - iter++; - } - } - } +void TextDrawerAndroid::ClearFonts() { + fontMap_.clear(); // size is precomputed using dpiScale_. } #endif diff --git a/Common/Render/Text/draw_text_android.h b/Common/Render/Text/draw_text_android.h index f4b7e431e6..17212aa331 100644 --- a/Common/Render/Text/draw_text_android.h +++ b/Common/Render/Text/draw_text_android.h @@ -21,31 +21,21 @@ public: bool IsReady() const override; uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(const char *str, size_t len, float *w, float *h) override; - void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; - void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; - // Use for housekeeping like throwing out old strings. - void OncePerFrame() override; + void MeasureString(std::string_view str, float *w, float *h) override; + bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void ClearCache() override; + bool SupportsColorEmoji() const override { return true; } + + void ClearFonts() override; private: - std::string NormalizeString(std::string str); - // JNI functions jclass cls_textRenderer; jmethodID method_measureText; jmethodID method_renderText; - uint32_t fontHash_; - bool use4444Format_ = false; - std::map fontMap_; - - std::map> cache_; - std::map> sizeCache_; }; #endif diff --git a/Common/Render/Text/draw_text_cocoa.h b/Common/Render/Text/draw_text_cocoa.h new file mode 100644 index 0000000000..011d523a3f --- /dev/null +++ b/Common/Render/Text/draw_text_cocoa.h @@ -0,0 +1,33 @@ +#pragma once + +#include "ppsspp_config.h" + +#if PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) + +#include +#include "Common/Render/Text/draw_text.h" + +struct TextDrawerContext; +// Internal struct but all details in .cpp file (pimpl to avoid pulling in excessive headers here) +class TextDrawerFontContext; + +class TextDrawerCocoa : public TextDrawer { +public: + TextDrawerCocoa(Draw::DrawContext *draw); + ~TextDrawerCocoa(); + + uint32_t SetFont(const char *fontName, int size, int flags) override; + void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. + void MeasureString(std::string_view str, float *w, float *h) override; + bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; + +protected: + bool SupportsColorEmoji() const override { return true; } + + void ClearFonts() override; + + TextDrawerContext *ctx_; + std::map> fontMap_; +}; + +#endif diff --git a/Common/Render/Text/draw_text_cocoa.mm b/Common/Render/Text/draw_text_cocoa.mm new file mode 100644 index 0000000000..52b615172c --- /dev/null +++ b/Common/Render/Text/draw_text_cocoa.mm @@ -0,0 +1,297 @@ +#include "ppsspp_config.h" + +#import "draw_text_cocoa.h" + +#if PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) + +#import +#import +#import + +#if PPSSPP_PLATFORM(MAC) +#import +#define ColorType NSColor +#else +#import +#define ColorType UIColor +#endif + +#include "Common/System/Display.h" +#include "Common/GPU/thin3d.h" +#include "Common/Data/Hash/Hash.h" +#include "Common/Data/Text/WrapText.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Render/Text/draw_text.h" +#include "Common/Render/Text/draw_text_cocoa.h" + +#include "Common/Log.h" +#include "Common/StringUtils.h" + +enum { + MAX_TEXT_WIDTH = 4096, + MAX_TEXT_HEIGHT = 512 +}; + +#define APPLE_FONT "Helvetica" + +class TextDrawerFontContext { +public: + ~TextDrawerFontContext() { + Destroy(); + } + + void Create() { + // Create an attributed string with string and font information + CGFloat fontSize = ceilf((height / dpiScale) * 1.25f); + INFO_LOG(Log::G3D, "Creating cocoa typeface '%s' size %d (effective size %0.1f)", APPLE_FONT, height, fontSize); + // CTFontRef font = CTFontCreateWithName(CFSTR(APPLE_FONT), fontSize, nil); + CTFontRef font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, fontSize, nil); + attributes = [NSDictionary dictionaryWithObjectsAndKeys: + (__bridge id)font, kCTFontAttributeName, + kCFBooleanTrue, kCTForegroundColorFromContextAttributeName, // Lets us specify the color later. + nil]; + } + void Destroy() { + //CFRelease(font); + font = {}; + } + + NSDictionary* attributes = nil; + CTFontRef font = nil; + std::string fname; + int height; + int bold; + float dpiScale; +}; + +TextDrawerCocoa::TextDrawerCocoa(Draw::DrawContext *draw) : TextDrawer(draw) { +} + +TextDrawerCocoa::~TextDrawerCocoa() { + ClearCache(); + ClearFonts(); +} + +// TODO: Share with other backends. +uint32_t TextDrawerCocoa::SetFont(const char *fontName, int size, int flags) { + uint32_t fontHash = fontName ? hash::Adler32((const uint8_t *)fontName, strlen(fontName)) : 0; + fontHash ^= size; + fontHash ^= flags << 10; + + auto iter = fontMap_.find(fontHash); + if (iter != fontMap_.end()) { + fontHash_ = fontHash; + return fontHash; + } + + std::string fname; + if (fontName) + fname = fontName; + else + fname = APPLE_FONT; + + TextDrawerFontContext *font = new TextDrawerFontContext(); + font->bold = false; + font->height = size; + font->fname = fname; + font->dpiScale = dpiScale_; + font->Create(); + + fontMap_[fontHash] = std::unique_ptr(font); + fontHash_ = fontHash; + return fontHash; +} + +void TextDrawerCocoa::SetFont(uint32_t fontHandle) { + auto iter = fontMap_.find(fontHandle); + if (iter != fontMap_.end()) { + fontHash_ = fontHandle; + } +} + +void TextDrawerCocoa::ClearFonts() { + for (auto &iter : fontMap_) { + iter.second->dpiScale = dpiScale_; + iter.second->Destroy(); + } + fontMap_.clear(); +} + +void TextDrawerCocoa::MeasureString(std::string_view str, float *w, float *h) { + CacheKey key{ std::string(str), fontHash_ }; + + TextMeasureEntry *entry; + auto iter = sizeCache_.find(key); + if (iter != sizeCache_.end()) { + entry = iter->second.get(); + } else { + // INFO_LOG(Log::System, "Measuring %.*s", (int)str.length(), str.data()); + + auto iter = fontMap_.find(fontHash_); + NSDictionary *attributes = nil; + if (iter != fontMap_.end()) { + attributes = iter->second->attributes; + } + + std::vector lines; + SplitString(str, '\n', lines); + + int extW = 0, extH = 0; + for (auto &line : lines) { + NSString *string = [[NSString alloc] initWithBytes:line.data() length:line.size() encoding: NSUTF8StringEncoding]; + NSAttributedString* as = [[NSAttributedString alloc] initWithString:string attributes:attributes]; + CTLineRef ctline = CTLineCreateWithAttributedString((CFAttributedStringRef)as); + CGFloat ascent, descent, leading; + double fWidth = CTLineGetTypographicBounds(ctline, &ascent, &descent, &leading); + + size_t width = (size_t)ceilf(fWidth); + size_t height = (size_t)ceilf(ascent + descent); + + if (width > extW) + extW = width; + extH += height; + } + + entry = new TextMeasureEntry(); + entry->width = extW; + entry->height = extH; + sizeCache_[key] = std::unique_ptr(entry); + } + + entry->lastUsedFrame = frameCount_; + *w = entry->width * fontScaleX_ * dpiScale_; + *h = entry->height * fontScaleY_ * dpiScale_; +} + +bool TextDrawerCocoa::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { + if (str.empty()) { + bitmapData.clear(); + return false; + } + + auto iter = fontMap_.find(fontHash_); + if (iter == fontMap_.end()) { + return false; + } + + // INFO_LOG(Log::System, "Rasterizing %.*s", (int)str.length(), str.data()); + + NSString* string = [[NSString alloc] initWithBytes:str.data() length:str.length() encoding: NSUTF8StringEncoding]; + + NSDictionary* attributes = iter->second->attributes; + NSAttributedString* as = [[NSAttributedString alloc] initWithString:string attributes:attributes]; + + // Figure out how big an image we need. + // We re-use MeasureString here. + float w, h; + MeasureString(str, &w, &h); + // Reverse the DPI scale that MeasureString baked in. + w /= (dpiScale_ * fontScaleX_); + h /= (dpiScale_ * fontScaleY_); + + int width = (int)ceilf(w); + int height = (int)ceilf(h); + if (width <= 0 || height <= 0) { + WARN_LOG(Log::G3D, "Text '%.*s' caused a zero size image", (int)str.length(), str.data()); + return false; + } + + // Round width and height upwards to the closest multiple of 4. + int bmWidth = (width + 1 + 3) & ~3; + int bmHeight = (height + 1 + 3) & ~3; + + uint32_t *bitmap = new uint32_t[bmWidth * bmHeight]; + memset(bitmap, 0, bmWidth * bmHeight * 4); + + // Create the context and fill it with white background + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast; + CGContextRef ctx = CGBitmapContextCreate(bitmap, bmWidth, bmHeight, 8, bmWidth*4, space, bitmapInfo); + CGColorSpaceRelease(space); + // CGContextSetRGBStrokeColor(ctx, 1.0, 1.0, 1.0, 1.0); // white background + CGContextSetStrokeColorWithColor(ctx, [ColorType whiteColor].CGColor); + CGContextSetFillColorWithColor(ctx, [ColorType whiteColor].CGColor); + + std::vector lines; + SplitString(str, '\n', lines); + + float lineY = 0.0; + for (std::string_view line : lines) { + NSString *string = [[NSString alloc] initWithBytes:line.data() length:line.size() encoding: NSUTF8StringEncoding]; + NSAttributedString* as = [[NSAttributedString alloc] initWithString:string attributes:attributes]; + CTLineRef ctline = CTLineCreateWithAttributedString((CFAttributedStringRef)as); + CGFloat ascent, descent, leading; + double fWidth = CTLineGetTypographicBounds(ctline, &ascent, &descent, &leading); + + // Draw the text + CGFloat x = 0.0; + CGFloat y = bmHeight - lineY - ascent; // from bottom??? + CGContextSetTextPosition(ctx, x, y); + CTLineDraw(ctline, ctx); + CFRelease(ctline); + + lineY += ascent + descent + leading; + } + + entry.texture = nullptr; + entry.width = width; + entry.height = height; + entry.bmWidth = bmWidth; + entry.bmHeight = bmHeight; + entry.lastUsedFrame = frameCount_; + + // data now contains the bytes in RGBA, presumably. + // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format + // because we need white. Well, we could using swizzle, but not all our backends support that. + if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint32_t)); + uint32_t *bitmapData32 = (uint32_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint32_t color = bitmap[bmWidth * y + x]; + if (fullColor) { + bitmapData32[entry.bmWidth * y + x] = color; + } else { + // Don't know why we'd end up here, but let's support it. + bitmapData32[entry.bmWidth * y + x] = (color << 24) | 0xFFFFFF; + } + } + } + } else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) { + _dbg_assert_(!fullColor); + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); + uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)((bitmap[bmWidth * y + x] & 0xff) >> 4); + bitmapData16[entry.bmWidth * y + x] = (bAlpha) | 0xfff0; + } + } + } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) { + _dbg_assert_(!fullColor); + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); + uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)((bitmap[bmWidth * y + x] & 0xff) >> 4); + bitmapData16[entry.bmWidth * y + x] = (bAlpha << 12) | 0x0fff; + } + } + } else if (texFormat == Draw::DataFormat::R8_UNORM) { + _dbg_assert_(!fullColor); + bitmapData.resize(entry.bmWidth * entry.bmHeight); + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = bitmap[bmWidth * y + x] & 0xff; + bitmapData[entry.bmWidth * y + x] = bAlpha; + } + } + } else { + _assert_msg_(false, "Bad TextDrawer format"); + } + + delete [] bitmap; + return true; +} + +#endif diff --git a/Common/Render/Text/draw_text_qt.cpp b/Common/Render/Text/draw_text_qt.cpp index ce0600cb81..050761c6e8 100644 --- a/Common/Render/Text/draw_text_qt.cpp +++ b/Common/Render/Text/draw_text_qt.cpp @@ -16,11 +16,11 @@ #include #include -TextDrawerQt::TextDrawerQt(Draw::DrawContext *draw) : TextDrawer(draw) { -} +TextDrawerQt::TextDrawerQt(Draw::DrawContext *draw) : TextDrawer(draw) {} TextDrawerQt::~TextDrawerQt() { ClearCache(); + ClearFonts(); } uint32_t TextDrawerQt::SetFont(const char *fontName, int size, int flags) { @@ -47,12 +47,12 @@ void TextDrawerQt::SetFont(uint32_t fontHandle) { if (iter != fontMap_.end()) { fontHash_ = fontHandle; } else { - ERROR_LOG(G3D, "Invalid font handle %08x", fontHandle); + ERROR_LOG(Log::G3D, "Invalid font handle %08x", fontHandle); } } -void TextDrawerQt::MeasureString(const char *str, size_t len, float *w, float *h) { - CacheKey key{ std::string(str, len), fontHash_ }; +void TextDrawerQt::MeasureString(std::string_view str, float *w, float *h) { + CacheKey key{ std::string(str), fontHash_ }; TextMeasureEntry *entry; auto iter = sizeCache_.find(key); @@ -61,7 +61,7 @@ void TextDrawerQt::MeasureString(const char *str, size_t len, float *w, float *h } else { QFont* font = fontMap_.find(fontHash_)->second; QFontMetrics fm(*font); - QSize size = fm.size(0, QString::fromUtf8(str, (int)len)); + QSize size = fm.size(0, QString::fromUtf8(str.data(), str.length())); entry = new TextMeasureEntry(); entry->width = size.width(); @@ -74,34 +74,21 @@ void TextDrawerQt::MeasureString(const char *str, size_t len, float *w, float *h *h = entry->height * fontScaleY_ * dpiScale_; } -void TextDrawerQt::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) { - std::string toMeasure = std::string(str, len); - int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - if (wrap) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); - } +bool TextDrawerQt::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { + _dbg_assert_(!fullColor); - QFont* font = fontMap_.find(fontHash_)->second; - QFontMetrics fm(*font); - QSize size = fm.size(0, QString::fromUtf8(toMeasure.c_str(), (int)toMeasure.size())); - *w = (float)size.width() * fontScaleX_ * dpiScale_; - *h = (float)size.height() * fontScaleY_ * dpiScale_; -} - -void TextDrawerQt::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { - if (!strlen(str)) { + if (str.empty()) { bitmapData.clear(); - return; + return false; } QFont *font = fontMap_.find(fontHash_)->second; QFontMetrics fm(*font); - QSize size = fm.size(0, QString::fromUtf8(str)); + QSize size = fm.size(0, QString::fromUtf8(str.data(), str.length())); QImage image((size.width() + 3) & ~3, (size.height() + 3) & ~3, QImage::Format_ARGB32_Premultiplied); if (image.isNull()) { bitmapData.clear(); - return; + return false; } image.fill(0); @@ -110,7 +97,7 @@ void TextDrawerQt::DrawStringBitmap(std::vector &bitmapData, TextString painter.setFont(*font); painter.setPen(0xFFFFFFFF); // TODO: Involve ALIGN_HCENTER (bounds etc.) - painter.drawText(image.rect(), Qt::AlignTop | Qt::AlignLeft, QString::fromUtf8(str).replace("&&", "&")); + painter.drawText(image.rect(), Qt::AlignTop | Qt::AlignLeft, QString::fromUtf8(str.data(), str.length())); painter.end(); entry.texture = nullptr; @@ -136,63 +123,10 @@ void TextDrawerQt::DrawStringBitmap(std::vector &bitmapData, TextString } else { _assert_msg_(false, "Bad TextDrawer format"); } + return true; } -void TextDrawerQt::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { - using namespace Draw; - if (!strlen(str)) - return; - - CacheKey key{ std::string(str), fontHash_ }; - target.Flush(true); - - TextStringEntry *entry; - - auto iter = cache_.find(key); - if (iter != cache_.end()) { - entry = iter->second.get(); - entry->lastUsedFrame = frameCount_; - } else { - DataFormat texFormat = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; - - entry = new TextStringEntry(); - - TextureDesc desc{}; - std::vector bitmapData; - DrawStringBitmap(bitmapData, *entry, texFormat, str, align); - desc.initData.push_back(&bitmapData[0]); - - desc.type = TextureType::LINEAR2D; - desc.format = texFormat; - desc.width = entry->bmWidth; - desc.height = entry->bmHeight; - desc.depth = 1; - desc.mipLevels = 1; - desc.tag = "TextDrawer"; - entry->texture = draw_->CreateTexture(desc); - cache_[key] = std::unique_ptr(entry); - } - - if (entry->texture) { - draw_->BindTexture(0, entry->texture); - } - - float w = entry->bmWidth * fontScaleX_ * dpiScale_; - float h = entry->bmHeight * fontScaleY_ * dpiScale_; - DrawBuffer::DoAlign(align, &x, &y, &w, &h); - if (entry->texture) { - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); - target.Flush(true); - } -} - -void TextDrawerQt::ClearCache() { - for (auto &iter : cache_) { - if (iter.second->texture) - iter.second->texture->Release(); - } - cache_.clear(); - sizeCache_.clear(); +void TextDrawerQt::ClearFonts() { // Also wipe the font map. for (auto iter : fontMap_) { delete iter.second; @@ -201,35 +135,4 @@ void TextDrawerQt::ClearCache() { fontHash_ = 0; } -void TextDrawerQt::OncePerFrame() { - frameCount_++; - // If DPI changed (small-mode, future proper monitor DPI support), drop everything. - float newDpiScale = CalculateDPIScale(); - if (newDpiScale != dpiScale_) { - dpiScale_ = newDpiScale; - ClearCache(); - } - - // Drop old strings. Use a prime number to reduce clashing with other rhythms - if (frameCount_ % 23 == 0) { - for (auto iter = cache_.begin(); iter != cache_.end();) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - if (iter->second->texture) - iter->second->texture->Release(); - cache_.erase(iter++); - } else { - iter++; - } - } - - for (auto iter = sizeCache_.begin(); iter != sizeCache_.end(); ) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - sizeCache_.erase(iter++); - } else { - iter++; - } - } - } -} - #endif diff --git a/Common/Render/Text/draw_text_qt.h b/Common/Render/Text/draw_text_qt.h index 47fb8ab48f..62c3bdf5b2 100644 --- a/Common/Render/Text/draw_text_qt.h +++ b/Common/Render/Text/draw_text_qt.h @@ -16,21 +16,15 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(const char *str, size_t len, float *w, float *h) override; - void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; - void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; - // Use for housekeeping like throwing out old strings. - void OncePerFrame() override; + void MeasureString(std::string_view str, float *w, float *h) override; + bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void ClearCache() override; + bool SupportsColorEmoji() const override { return false; } + + void ClearFonts() override; - uint32_t fontHash_; std::map fontMap_; - - std::map> cache_; - std::map> sizeCache_; }; #endif diff --git a/Common/Render/Text/draw_text_sdl.cpp b/Common/Render/Text/draw_text_sdl.cpp index 0fd0ff1817..cc194cb654 100644 --- a/Common/Render/Text/draw_text_sdl.cpp +++ b/Common/Render/Text/draw_text_sdl.cpp @@ -32,7 +32,7 @@ static std::string getlocale() { TextDrawerSDL::TextDrawerSDL(Draw::DrawContext *draw): TextDrawer(draw) { if (TTF_Init() < 0) { - ERROR_LOG(G3D, "Unable to initialize SDL2_ttf"); + ERROR_LOG(Log::G3D, "Unable to initialize SDL2_ttf"); } dpiScale_ = CalculateDPIScale(); @@ -46,6 +46,8 @@ TextDrawerSDL::TextDrawerSDL(Draw::DrawContext *draw): TextDrawer(draw) { TextDrawerSDL::~TextDrawerSDL() { ClearCache(); + ClearFonts(); + TTF_Quit(); #if defined(USE_SDL2_TTF_FONTCONFIG) @@ -273,12 +275,12 @@ void TextDrawerSDL::SetFont(uint32_t fontHandle) { if (iter != fontMap_.end()) { fontHash_ = fontHandle; } else { - ERROR_LOG(G3D, "Invalid font handle %08x", fontHandle); + ERROR_LOG(Log::G3D, "Invalid font handle %08x", fontHandle); } } -void TextDrawerSDL::MeasureString(const char *str, size_t len, float *w, float *h) { - CacheKey key{ std::string(str, len), fontHash_ }; +void TextDrawerSDL::MeasureString(std::string_view str, float *w, float *h) { + CacheKey key{ std::string(str), fontHash_ }; TextMeasureEntry *entry; auto iter = sizeCache_.find(key); @@ -312,118 +314,15 @@ void TextDrawerSDL::MeasureString(const char *str, size_t len, float *w, float * *h = entry->height * fontScaleY_ * dpiScale_; } -void TextDrawerSDL::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) { - std::string toMeasure = std::string(str, len); - int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - if (wrap) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); - } +bool TextDrawerSDL::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { + _dbg_assert_(!fullColor) - TTF_Font *font = fontMap_.find(fontHash_)->second; - int ptSize = TTF_FontHeight(font) / 1.35; - uint32_t missingGlyph = CheckMissingGlyph(toMeasure); - - if (missingGlyph) { - int fallbackFont = FindFallbackFonts(missingGlyph, ptSize); - if (fallbackFont >= 0) { - font = fallbackFonts_[fallbackFont]; - } - } - - std::vector lines; - SplitString(toMeasure, '\n', lines); - - int total_w = 0; - int total_h = 0; - for (size_t i = 0; i < lines.size(); i++) { - CacheKey key{ lines[i], fontHash_ }; - - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - int width = 0; - int height = 0; - TTF_SizeUTF8(font, lines[i].c_str(), &width, &height); - entry = new TextMeasureEntry(); - entry->width = width; - entry->height = height; - sizeCache_[key] = std::unique_ptr(entry); - } - - entry->lastUsedFrame = frameCount_; - if (total_w < entry->width) { - total_w = entry->width; - } - total_h += TTF_FontLineSkip(font); - } - - *w = total_w * fontScaleX_ * dpiScale_; - *h = total_h * fontScaleY_ * dpiScale_; -} - -void TextDrawerSDL::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { - using namespace Draw; - if (!strlen(str)) - return; - - CacheKey key{ std::string(str), fontHash_ }; - target.Flush(true); - - TextStringEntry *entry; - - auto iter = cache_.find(key); - if (iter != cache_.end()) { - entry = iter->second.get(); - entry->lastUsedFrame = frameCount_; - } else { - DataFormat texFormat = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; - if ((draw_->GetDataFormatSupport(texFormat) & Draw::FMT_TEXTURE) == 0) { - // This is always supported in Vulkan. The other format is the common OpenGL one. - texFormat = Draw::DataFormat::B4G4R4A4_UNORM_PACK16; - } - - entry = new TextStringEntry(); - - TextureDesc desc{}; - std::vector bitmapData; - DrawStringBitmap(bitmapData, *entry, texFormat, str, align); - desc.initData.push_back(&bitmapData[0]); - - desc.type = TextureType::LINEAR2D; - desc.format = texFormat; - desc.width = entry->bmWidth; - desc.height = entry->bmHeight; - desc.depth = 1; - desc.mipLevels = 1; - desc.tag = "TextDrawer"; - entry->texture = draw_->CreateTexture(desc); - cache_[key] = std::unique_ptr(entry); - } - - if (entry->texture) { - draw_->BindTexture(0, entry->texture); - } - - float w = entry->bmWidth * fontScaleX_ * dpiScale_; - float h = entry->bmHeight * fontScaleY_ * dpiScale_; - DrawBuffer::DoAlign(align, &x, &y, &w, &h); - if (entry->texture) { - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); - target.Flush(true); - } -} - -void TextDrawerSDL::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { - if (!strlen(str)) { + if (str.empty()) { bitmapData.clear(); - return; + return false; } - // Replace "&&" with "&" - std::string processedStr = ReplaceAll(str, "&&", "&"); + std::string processedStr(str); // If a string includes only newlines, SDL2_ttf will refuse to render it // thinking it is empty. Add a space to avoid that. @@ -492,46 +391,10 @@ void TextDrawerSDL::DrawStringBitmap(std::vector &bitmapData, TextStrin SDL_UnlockSurface(text); SDL_FreeSurface(text); + return true; } -void TextDrawerSDL::OncePerFrame() { - // Reset everything if DPI changes - float newDpiScale = CalculateDPIScale(); - if (newDpiScale != dpiScale_) { - dpiScale_ = newDpiScale; - ClearCache(); - } - - // Drop old strings. Use a prime number to reduce clashing with other rhythms - if (frameCount_ % 23 == 0) { - for (auto iter = cache_.begin(); iter != cache_.end();) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - if (iter->second->texture) - iter->second->texture->Release(); - cache_.erase(iter++); - } else { - iter++; - } - } - - for (auto iter = sizeCache_.begin(); iter != sizeCache_.end(); ) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - sizeCache_.erase(iter++); - } else { - iter++; - } - } - } -} - -void TextDrawerSDL::ClearCache() { - for (auto &iter : cache_) { - if (iter.second->texture) - iter.second->texture->Release(); - } - cache_.clear(); - sizeCache_.clear(); - +void TextDrawerSDL::ClearFonts() { for (auto iter : fontMap_) { TTF_CloseFont(iter.second); } @@ -540,7 +403,6 @@ void TextDrawerSDL::ClearCache() { } fontMap_.clear(); fallbackFonts_.clear(); - fontHash_ = 0; } #endif diff --git a/Common/Render/Text/draw_text_sdl.h b/Common/Render/Text/draw_text_sdl.h index af690e1acc..b6a2003f0b 100644 --- a/Common/Render/Text/draw_text_sdl.h +++ b/Common/Render/Text/draw_text_sdl.h @@ -19,25 +19,20 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(const char *str, size_t len, float *w, float *h) override; - void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; - void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; - // Use for housekeeping like throwing out old strings. - void OncePerFrame() override; + void MeasureString(std::string_view str, float *w, float *h) override; + bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void ClearCache() override; + bool SupportsColorEmoji() const override { return false; } + void ClearFonts() override; + +private: void PrepareFallbackFonts(std::string_view locale); uint32_t CheckMissingGlyph(const std::string& text); int FindFallbackFonts(uint32_t missingGlyph, int ptSize); - uint32_t fontHash_; std::map fontMap_; - std::map> cache_; - std::map> sizeCache_; - std::vector<_TTF_Font *> fallbackFonts_; std::vector> fallbackFontPaths_; // path and font face index diff --git a/Common/Render/Text/draw_text_uwp.cpp b/Common/Render/Text/draw_text_uwp.cpp index 832a0caa03..aba313ff96 100644 --- a/Common/Render/Text/draw_text_uwp.cpp +++ b/Common/Render/Text/draw_text_uwp.cpp @@ -33,7 +33,9 @@ public: Destroy(); } - if (factory == nullptr) return; + if (!factory) { + return; + } HRESULT hr = factory->CreateTextFormat( fname.c_str(), @@ -45,15 +47,20 @@ public: L"", &textFmt ); + if (FAILED(hr)) { + ERROR_LOG(Log::G3D, "Failed creating font %s", fname.c_str()); + } } void Destroy() { - textFmt->Release(); + if (textFmt) { + textFmt->Release(); + } textFmt = nullptr; } - IDWriteFactory4* factory = nullptr; - IDWriteFontCollection1* fontCollection = nullptr; - IDWriteTextFormat* textFmt = nullptr; + IDWriteFactory4 *factory = nullptr; + IDWriteFontCollection1 *fontCollection = nullptr; + IDWriteTextFormat *textFmt = nullptr; std::wstring fname; int height; DWRITE_FONT_WEIGHT weight; @@ -61,8 +68,8 @@ public: }; struct TextDrawerContext { - ID2D1Bitmap1* bitmap; - ID2D1Bitmap1* mirror_bmp; + ID2D1Bitmap1 *bitmap; + ID2D1Bitmap1 *mirror_bmp; }; TextDrawerUWP::TextDrawerUWP(Draw::DrawContext *draw) : TextDrawer(draw), ctx_(nullptr) { @@ -99,9 +106,9 @@ TextDrawerUWP::TextDrawerUWP(Draw::DrawContext *draw) : TextDrawer(draw), ctx_(n // Load the Roboto font hr = m_dwriteFactory->CreateFontFileReference(L"Content/Roboto-Condensed.ttf", nullptr, &m_fontFile); - if (FAILED(hr)) ERROR_LOG(SYSTEM, "CreateFontFileReference failed"); + if (FAILED(hr)) ERROR_LOG(Log::System, "CreateFontFileReference failed"); hr = m_dwriteFactory->CreateFontSetBuilder(&m_fontSetBuilder); - if (FAILED(hr)) ERROR_LOG(SYSTEM, "CreateFontSetBuilder failed"); + if (FAILED(hr)) ERROR_LOG(Log::System, "CreateFontSetBuilder failed"); hr = m_fontSetBuilder->AddFontFile(m_fontFile); hr = m_fontSetBuilder->CreateFontSet(&m_fontSet); hr = m_dwriteFactory->CreateFontCollectionFromFontSet(m_fontSet, &m_fontCollection); @@ -141,8 +148,7 @@ TextDrawerUWP::TextDrawerUWP(Draw::DrawContext *draw) : TextDrawer(draw), ctx_(n TextDrawerUWP::~TextDrawerUWP() { ClearCache(); - - fontMap_.clear(); + ClearFonts(); ctx_->bitmap->Release(); ctx_->mirror_bmp->Release(); @@ -198,8 +204,8 @@ void TextDrawerUWP::SetFont(uint32_t fontHandle) { } } -void TextDrawerUWP::MeasureString(const char *str, size_t len, float *w, float *h) { - CacheKey key{ std::string(str, len), fontHash_ }; +void TextDrawerUWP::MeasureString(std::string_view str, float *w, float *h) { + CacheKey key{ std::string(str), fontHash_ }; TextMeasureEntry *entry; auto iter = sizeCache_.find(key); @@ -213,7 +219,7 @@ void TextDrawerUWP::MeasureString(const char *str, size_t len, float *w, float * } if (!format) return; - std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(ReplaceAll(std::string(str, len), "\n", "\r\n"), "&&", "&")); + std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(std::string(str), "\n", "\r\n")); format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); @@ -242,83 +248,13 @@ void TextDrawerUWP::MeasureString(const char *str, size_t len, float *w, float * *h = entry->height * fontScaleY_ * dpiScale_; } -void TextDrawerUWP::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) { - IDWriteTextFormat *format = nullptr; - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - format = iter->second->textFmt; - } - if (!format) { - *w = 0; - *h = 0; - return; - } - - std::string toMeasure = std::string(str, len); - int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - if (wrap) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); - } - - std::vector lines; - SplitString(toMeasure, '\n', lines); - int total_w = 0; - int total_h = 0; - for (size_t i = 0; i < lines.size(); i++) { - CacheKey key{ lines[i], fontHash_ }; - - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - std::wstring wstr = ConvertUTF8ToWString(lines[i].length() == 0 ? " " : ReplaceAll(lines[i], "&&", "&")); - - if (align & ALIGN_HCENTER) - format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); - else if (align & ALIGN_LEFT) - format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - else if (align & ALIGN_RIGHT) - format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING); - - IDWriteTextLayout* layout; - m_dwriteFactory->CreateTextLayout( - (LPWSTR)wstr.c_str(), - (int)wstr.size(), - format, - MAX_TEXT_WIDTH, - MAX_TEXT_HEIGHT, - &layout - ); - - DWRITE_TEXT_METRICS metrics; - layout->GetMetrics(&metrics); - layout->Release(); - - entry = new TextMeasureEntry(); - entry->width = (int)(metrics.width + 1.0f); - entry->height = (int)(metrics.height + 1.0f); - sizeCache_[key] = std::unique_ptr(entry); - } - entry->lastUsedFrame = frameCount_; - - if (total_w < entry->width) { - total_w = entry->width; - } - total_h += entry->height; - } - *w = total_w * fontScaleX_ * dpiScale_; - *h = total_h * fontScaleY_ * dpiScale_; -} - -void TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { - if (!strlen(str)) { +bool TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { + if (str.empty()) { bitmapData.clear(); - return; + return false; } - std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(ReplaceAll(str, "\n", "\r\n"), "&&", "&")); + std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n")); SIZE size; IDWriteTextFormat *format = nullptr; @@ -328,7 +264,7 @@ void TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStrin } if (!format) { bitmapData.clear(); - return; + return false; } if (align & ALIGN_HCENTER) @@ -401,12 +337,17 @@ void TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStrin uint32_t *bmpLine = (uint32_t *)&map.bits[map.pitch * y]; for (int x = 0; x < entry.bmWidth; x++) { uint32_t v = bmpLine[x]; - if (swap) - v = (v & 0xFF00FF00) | ((v >> 16) & 0xFF) | ((v << 16) & 0xFF0000); - bitmapData32[entry.bmWidth * y + x] = v; + if (fullColor) { + if (swap) + v = (v & 0xFF00FF00) | ((v >> 16) & 0xFF) | ((v << 16) & 0xFF0000); + bitmapData32[entry.bmWidth * y + x] = v; + } else { + bitmapData32[entry.bmWidth * y + x] = (v << 24) | 0xFFFFFF; + } } } } else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) { + _dbg_assert_(!fullColor); bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; for (int y = 0; y < entry.bmHeight; y++) { @@ -416,6 +357,7 @@ void TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStrin } } } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) { + _dbg_assert_(!fullColor); bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; for (int y = 0; y < entry.bmHeight; y++) { @@ -425,6 +367,7 @@ void TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStrin } } } else if (texFormat == Draw::DataFormat::R8_UNORM) { + _dbg_assert_(!fullColor); bitmapData.resize(entry.bmWidth * entry.bmHeight); for (int y = 0; y < entry.bmHeight; y++) { for (int x = 0; x < entry.bmWidth; x++) { @@ -437,119 +380,15 @@ void TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStrin } ctx_->mirror_bmp->Unmap(); + return true; } -void TextDrawerUWP::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { - using namespace Draw; - if (!strlen(str)) - return; - - CacheKey key{ std::string(str), fontHash_ }; - target.Flush(true); - - TextStringEntry *entry; - - auto iter = cache_.find(key); - if (iter != cache_.end()) { - entry = iter->second.get(); - entry->lastUsedFrame = frameCount_; - } else { - DataFormat texFormat; - - // For our purposes these are equivalent, so just choose the supported one. D3D can emulate them. - if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE) - texFormat = Draw::DataFormat::A4R4G4B4_UNORM_PACK16; - else if (draw_->GetDataFormatSupport(Draw::DataFormat::B4G4R4A4_UNORM_PACK16) & FMT_TEXTURE) - texFormat = Draw::DataFormat::B4G4R4A4_UNORM_PACK16; - else - texFormat = Draw::DataFormat::R8G8B8A8_UNORM; - - bool emoji = AnyEmojiInString(key.text.c_str(), key.text.size()); - if (emoji) - texFormat = Draw::DataFormat::R8G8B8A8_UNORM; - - entry = new TextStringEntry(); - - // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format - // because we need white. Well, we could using swizzle, but not all our backends support that. - TextureDesc desc{}; - std::vector bitmapData; - DrawStringBitmap(bitmapData, *entry, texFormat, str, align); - desc.initData.push_back(&bitmapData[0]); - - desc.type = TextureType::LINEAR2D; - desc.format = texFormat; - desc.width = entry->bmWidth; - desc.height = entry->bmHeight; - desc.depth = 1; - desc.mipLevels = 1; - desc.tag = "TextDrawer"; - entry->texture = draw_->CreateTexture(desc); - cache_[key] = std::unique_ptr(entry); - } - - if (entry->texture) { - draw_->BindTexture(0, entry->texture); - } - - // Okay, the texture is bound, let's draw. - float w = entry->width * fontScaleX_ * dpiScale_; - float h = entry->height * fontScaleY_ * dpiScale_; - float u = entry->width / (float)entry->bmWidth; - float v = entry->height / (float)entry->bmHeight; - DrawBuffer::DoAlign(align, &x, &y, &w, &h); - if (entry->texture) { - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, u, v, color); - target.Flush(true); - } -} - -void TextDrawerUWP::RecreateFonts() { +void TextDrawerUWP::ClearFonts() { for (auto &iter : fontMap_) { iter.second->dpiScale = dpiScale_; - iter.second->Create(); - } -} - -void TextDrawerUWP::ClearCache() { - for (auto &iter : cache_) { - if (iter.second->texture) - iter.second->texture->Release(); - } - cache_.clear(); - sizeCache_.clear(); -} - -void TextDrawerUWP::OncePerFrame() { - frameCount_++; - // If DPI changed (small-mode, future proper monitor DPI support), drop everything. - float newDpiScale = CalculateDPIScale(); - if (newDpiScale != dpiScale_) { - dpiScale_ = newDpiScale; - ClearCache(); - RecreateFonts(); - } - - // Drop old strings. Use a prime number to reduce clashing with other rhythms - if (frameCount_ % 23 == 0) { - for (auto iter = cache_.begin(); iter != cache_.end();) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - if (iter->second->texture) - iter->second->texture->Release(); - cache_.erase(iter++); - } else { - iter++; - } - } - - for (auto iter = sizeCache_.begin(); iter != sizeCache_.end(); ) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - sizeCache_.erase(iter++); - } else { - iter++; - } - } + iter.second->Destroy(); } + fontMap_.clear(); } #endif diff --git a/Common/Render/Text/draw_text_uwp.h b/Common/Render/Text/draw_text_uwp.h index 816ae7ec06..58f8fdaf71 100644 --- a/Common/Render/Text/draw_text_uwp.h +++ b/Common/Render/Text/draw_text_uwp.h @@ -21,25 +21,16 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(const char *str, size_t len, float *w, float *h) override; - void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; - void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; - // Use for housekeeping like throwing out old strings. - void OncePerFrame() override; + void MeasureString(std::string_view str, float *w, float *h) override; + bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void ClearCache() override; - void RecreateFonts(); // On DPI change + bool SupportsColorEmoji() const override { return true; } + void ClearFonts() override; TextDrawerContext *ctx_; std::map> fontMap_; - uint32_t fontHash_; - std::map> cache_; - std::map> sizeCache_; - - // Direct2D drawing components. ID2D1Factory5* m_d2dFactory; ID2D1Device4* m_d2dDevice; diff --git a/Common/Render/Text/draw_text_win.cpp b/Common/Render/Text/draw_text_win.cpp index 36ffe8006d..05b4fe354a 100644 --- a/Common/Render/Text/draw_text_win.cpp +++ b/Common/Render/Text/draw_text_win.cpp @@ -77,8 +77,7 @@ TextDrawerWin32::TextDrawerWin32(Draw::DrawContext *draw) : TextDrawer(draw), ct TextDrawerWin32::~TextDrawerWin32() { ClearCache(); - - fontMap_.clear(); + ClearFonts(); DeleteObject(ctx_->hbmBitmap); DeleteDC(ctx_->hDC); @@ -121,8 +120,8 @@ void TextDrawerWin32::SetFont(uint32_t fontHandle) { } } -void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float *h) { - CacheKey key{ std::string(str, len), fontHash_ }; +void TextDrawerWin32::MeasureString(std::string_view str, float *w, float *h) { + CacheKey key{ std::string(str), fontHash_ }; TextMeasureEntry *entry; auto iter = sizeCache_.find(key); @@ -134,7 +133,7 @@ void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float SelectObject(ctx_->hDC, iter->second->hFont); } - std::string toMeasure = ReplaceAll(std::string(str, len), "&&", "&"); + std::string toMeasure(str); std::vector lines; SplitString(toMeasure, '\n', lines); @@ -153,6 +152,8 @@ void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float entry = new TextMeasureEntry(); entry->width = extW; entry->height = extH; + // Hm, use the old calculation? + // int h = i == lines.size() - 1 ? entry->height : metrics.tmHeight + metrics.tmExternalLeading; sizeCache_[key] = std::unique_ptr(entry); } @@ -161,64 +162,13 @@ void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float *h = entry->height * fontScaleY_ * dpiScale_; } -void TextDrawerWin32::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) { - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - SelectObject(ctx_->hDC, iter->second->hFont); - } - - std::string toMeasure = std::string(str, len); - int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - if (wrap) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); - } - - TEXTMETRIC metrics{}; - GetTextMetrics(ctx_->hDC, &metrics); - - std::vector lines; - SplitString(toMeasure, '\n', lines); - int total_w = 0; - int total_h = 0; - CacheKey key{ "", fontHash_}; - for (size_t i = 0; i < lines.size(); i++) { - key.text = lines[i]; - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - SIZE size; - std::wstring wstr = ConvertUTF8ToWString(lines[i].empty() ? " " : ReplaceAll(lines[i], "&&", "&")); - GetTextExtentPoint32(ctx_->hDC, wstr.c_str(), (int)wstr.size(), &size); - - entry = new TextMeasureEntry(); - entry->width = size.cx; - entry->height = size.cy; - sizeCache_[key] = std::unique_ptr(entry); - } - entry->lastUsedFrame = frameCount_; - - if (total_w < entry->width) { - total_w = entry->width; - } - int h = i == lines.size() - 1 ? entry->height : metrics.tmHeight + metrics.tmExternalLeading; - total_h += h; - } - - *w = total_w * fontScaleX_ * dpiScale_; - *h = total_h * fontScaleY_ * dpiScale_; -} - -void TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { - if (!strlen(str)) { +bool TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { + if (str.empty()) { bitmapData.clear(); - return; + return false; } std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n")); - SIZE size; auto iter = fontMap_.find(fontHash_); if (iter != fontMap_.end()) { @@ -233,7 +183,8 @@ void TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStr UINT dtAlign = (align & ALIGN_HCENTER) == 0 ? DT_LEFT : DT_CENTER; RECT textRect = { 0 }; - DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &textRect, DT_HIDEPREFIX | DT_TOP | dtAlign | DT_CALCRECT, 0); + DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &textRect, DT_NOPREFIX | DT_TOP | dtAlign | DT_CALCRECT, 0); + SIZE size; size.cx = textRect.right; size.cy = textRect.bottom; @@ -241,13 +192,11 @@ void TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStr size.cx = MAX_TEXT_WIDTH; if (size.cy > MAX_TEXT_HEIGHT) size.cy = MAX_TEXT_HEIGHT; - // Prevent zero-sized textures, which can occur. Not worth to avoid - // creating the texture altogether in this case. One example is a string - // containing only '\r\n', see issue #10764. - if (size.cx == 0) - size.cx = 1; - if (size.cy == 0) - size.cy = 1; + + if (size.cx == 0 || size.cy == 0) { + // Don't draw zero-sized textures. + return false; + } entry.texture = nullptr; entry.width = size.cx; @@ -260,7 +209,7 @@ void TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStr rc.right = entry.bmWidth; rc.bottom = entry.bmHeight; FillRect(ctx_->hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); - DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &rc, DT_HIDEPREFIX | DT_TOP | dtAlign, 0); + DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &rc, DT_NOPREFIX | DT_TOP | dtAlign, 0); // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format // because we need white. Well, we could using swizzle, but not all our backends support that. @@ -302,116 +251,14 @@ void TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStr } else { _assert_msg_(false, "Bad TextDrawer format"); } + return true; } -void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { - using namespace Draw; - if (!strlen(str)) - return; - - CacheKey key{ std::string(str), fontHash_ }; - target.Flush(true); - - TextStringEntry *entry; - - auto iter = cache_.find(key); - if (iter != cache_.end()) { - entry = iter->second.get(); - entry->lastUsedFrame = frameCount_; - } else { - DataFormat texFormat; - // For our purposes these are equivalent, so just choose the supported one. D3D can emulate them. - if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE) - texFormat = Draw::DataFormat::A4R4G4B4_UNORM_PACK16; - else if (draw_->GetDataFormatSupport(Draw::DataFormat::R4G4B4A4_UNORM_PACK16) & FMT_TEXTURE) - texFormat = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; - else if (draw_->GetDataFormatSupport(Draw::DataFormat::B4G4R4A4_UNORM_PACK16) & FMT_TEXTURE) - texFormat = Draw::DataFormat::B4G4R4A4_UNORM_PACK16; - else - texFormat = Draw::DataFormat::R8G8B8A8_UNORM; - - entry = new TextStringEntry(); - - // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format - // because we need white. Well, we could using swizzle, but not all our backends support that. - TextureDesc desc{}; - std::vector bitmapData; - DrawStringBitmap(bitmapData, *entry, texFormat, str, align); - desc.initData.push_back(&bitmapData[0]); - - desc.type = TextureType::LINEAR2D; - desc.format = texFormat; - desc.width = entry->bmWidth; - desc.height = entry->bmHeight; - desc.depth = 1; - desc.mipLevels = 1; - desc.tag = "TextDrawer"; - entry->texture = draw_->CreateTexture(desc); - cache_[key] = std::unique_ptr(entry); - } - - if (entry->texture) { - draw_->BindTexture(0, entry->texture); - } - - // Okay, the texture is bound, let's draw. - float w = entry->width * fontScaleX_ * dpiScale_; - float h = entry->height * fontScaleY_ * dpiScale_; - float u = entry->width / (float)entry->bmWidth; - float v = entry->height / (float)entry->bmHeight; - DrawBuffer::DoAlign(align, &x, &y, &w, &h); - if (entry->texture) { - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, u, v, color); - target.Flush(true); - } -} - -void TextDrawerWin32::RecreateFonts() { +void TextDrawerWin32::ClearFonts() { for (auto &iter : fontMap_) { - iter.second->dpiScale = dpiScale_; - iter.second->Create(); - } -} - -void TextDrawerWin32::ClearCache() { - for (auto &iter : cache_) { - if (iter.second->texture) - iter.second->texture->Release(); - } - cache_.clear(); - sizeCache_.clear(); -} - -void TextDrawerWin32::OncePerFrame() { - frameCount_++; - // If DPI changed (small-mode, future proper monitor DPI support), drop everything. - float newDpiScale = CalculateDPIScale(); - if (newDpiScale != dpiScale_) { - dpiScale_ = newDpiScale; - ClearCache(); - RecreateFonts(); - } - - // Drop old strings. Use a prime number to reduce clashing with other rhythms - if (frameCount_ % 23 == 0) { - for (auto iter = cache_.begin(); iter != cache_.end();) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - if (iter->second->texture) - iter->second->texture->Release(); - cache_.erase(iter++); - } else { - iter++; - } - } - - for (auto iter = sizeCache_.begin(); iter != sizeCache_.end(); ) { - if (frameCount_ - iter->second->lastUsedFrame > 100) { - sizeCache_.erase(iter++); - } else { - iter++; - } - } + iter.second->Destroy(); } + fontMap_.clear(); } #endif diff --git a/Common/Render/Text/draw_text_win.h b/Common/Render/Text/draw_text_win.h index c59fa91db4..24a84a5aef 100644 --- a/Common/Render/Text/draw_text_win.h +++ b/Common/Render/Text/draw_text_win.h @@ -21,23 +21,15 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(const char *str, size_t len, float *w, float *h) override; - void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; - void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; - // Use for housekeeping like throwing out old strings. - void OncePerFrame() override; + void MeasureString(std::string_view str, float *w, float *h) override; + bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void ClearCache() override; - void RecreateFonts(); // On DPI change + bool SupportsColorEmoji() const override { return false; } + void ClearFonts() override; TextDrawerContext *ctx_; std::map> fontMap_; - - uint32_t fontHash_; - std::map> cache_; - std::map> sizeCache_; }; #endif diff --git a/Common/RiscVCPUDetect.cpp b/Common/RiscVCPUDetect.cpp index cb006238ae..f0aee40191 100644 --- a/Common/RiscVCPUDetect.cpp +++ b/Common/RiscVCPUDetect.cpp @@ -27,7 +27,9 @@ #include #include #include +#ifndef __OpenBSD__ #include +#endif #include #include "Common/Common.h" #include "Common/CPUDetect.h" @@ -201,6 +203,15 @@ void CPUInfo::Detect() } #endif +#ifdef __OpenBSD__ + /* OpenBSD uses RV64GC */ + RiscV_M = true; + RiscV_A = true; + RiscV_F = true; + RiscV_D = true; + RiscV_C = true; + RiscV_V = false; +#else unsigned long hwcap = getauxval(AT_HWCAP); RiscV_M = ExtensionSupported(hwcap, 'M'); RiscV_A = ExtensionSupported(hwcap, 'A'); @@ -208,6 +219,7 @@ void CPUInfo::Detect() RiscV_D = ExtensionSupported(hwcap, 'D'); RiscV_C = ExtensionSupported(hwcap, 'C'); RiscV_V = ExtensionSupported(hwcap, 'V'); +#endif // We assume as in RVA20U64 that F means Zicsr is available. RiscV_Zicsr = RiscV_F; diff --git a/Common/RiscVEmitter.cpp b/Common/RiscVEmitter.cpp index 08cc327105..f90f7d04c1 100644 --- a/Common/RiscVEmitter.cpp +++ b/Common/RiscVEmitter.cpp @@ -121,7 +121,7 @@ enum class Opcode32 { BRANCH = 0b1100011, JALR = 0b1100111, JAL = 0b1101111, - SYSTEM = 0b1110011, + System = 0b1110011, }; enum class Opcode16 { @@ -1853,11 +1853,11 @@ void RiscVEmitter::FENCE_TSO() { } void RiscVEmitter::ECALL() { - Write32(EncodeI(Opcode32::SYSTEM, R_ZERO, Funct3::PRIV, R_ZERO, Funct12::ECALL)); + Write32(EncodeI(Opcode32::System, R_ZERO, Funct3::PRIV, R_ZERO, Funct12::ECALL)); } void RiscVEmitter::EBREAK() { - Write32(EncodeI(Opcode32::SYSTEM, R_ZERO, Funct3::PRIV, R_ZERO, Funct12::EBREAK)); + Write32(EncodeI(Opcode32::System, R_ZERO, Funct3::PRIV, R_ZERO, Funct12::EBREAK)); } void RiscVEmitter::LWU(RiscVReg rd, RiscVReg rs1, s32 simm12) { @@ -2506,40 +2506,40 @@ void RiscVEmitter::QuickFLI(int bits, RiscVReg rd, float v, RiscVReg scratchReg) void RiscVEmitter::CSRRW(RiscVReg rd, Csr csr, RiscVReg rs1) { _assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__); _assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__); - Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRW, rs1, (Funct12)csr)); + Write32(EncodeGI(Opcode32::System, rd, Funct3::CSRRW, rs1, (Funct12)csr)); } void RiscVEmitter::CSRRS(RiscVReg rd, Csr csr, RiscVReg rs1) { _assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__); _assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__); - Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRS, rs1, (Funct12)csr)); + Write32(EncodeGI(Opcode32::System, rd, Funct3::CSRRS, rs1, (Funct12)csr)); } void RiscVEmitter::CSRRC(RiscVReg rd, Csr csr, RiscVReg rs1) { _assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__); _assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__); - Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRC, rs1, (Funct12)csr)); + Write32(EncodeGI(Opcode32::System, rd, Funct3::CSRRC, rs1, (Funct12)csr)); } void RiscVEmitter::CSRRWI(RiscVReg rd, Csr csr, u8 uimm5) { _assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__); _assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__); _assert_msg_((u32)uimm5 <= 0x1F, "%s can only specify lowest 5 bits", __func__); - Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRWI, (RiscVReg)uimm5, (Funct12)csr)); + Write32(EncodeGI(Opcode32::System, rd, Funct3::CSRRWI, (RiscVReg)uimm5, (Funct12)csr)); } void RiscVEmitter::CSRRSI(RiscVReg rd, Csr csr, u8 uimm5) { _assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__); _assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__); _assert_msg_((u32)uimm5 <= 0x1F, "%s can only set lowest 5 bits", __func__); - Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRSI, (RiscVReg)uimm5, (Funct12)csr)); + Write32(EncodeGI(Opcode32::System, rd, Funct3::CSRRSI, (RiscVReg)uimm5, (Funct12)csr)); } void RiscVEmitter::CSRRCI(RiscVReg rd, Csr csr, u8 uimm5) { _assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__); _assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__); _assert_msg_((u32)uimm5 <= 0x1F, "%s can only clear lowest 5 bits", __func__); - Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRCI, (RiscVReg)uimm5, (Funct12)csr)); + Write32(EncodeGI(Opcode32::System, rd, Funct3::CSRRCI, (RiscVReg)uimm5, (Funct12)csr)); } void RiscVEmitter::VSETVLI(RiscVReg rd, RiscVReg rs1, VType vtype) { diff --git a/Common/Serialize/SerializeFuncs.h b/Common/Serialize/SerializeFuncs.h index c2919de799..7e32c76f3f 100644 --- a/Common/Serialize/SerializeFuncs.h +++ b/Common/Serialize/SerializeFuncs.h @@ -71,6 +71,17 @@ void DoClass(PointerWrap &p, T *&x) { x->DoState(p); } +template +void DoSubClass(PointerWrap &p, T *&x) { + if (p.mode == PointerWrap::MODE_READ) { + if (x != nullptr) + delete x; + x = new S(); + } + x->DoState(p); +} + + template void DoArray(PointerWrap &p, T *x, int count) { DoHelper_::DoArray(p, x, count); diff --git a/Common/Serialize/SerializeList.h b/Common/Serialize/SerializeList.h index ae0fc2edc9..d42ddc80f5 100644 --- a/Common/Serialize/SerializeList.h +++ b/Common/Serialize/SerializeList.h @@ -75,7 +75,7 @@ void DoLinkedList(PointerWrap &p, LinkedListItem *&list_start, LinkedListItem } } else { if (shouldExist != 0) { - WARN_LOG(SAVESTATE, "Savestate failure: incorrect item marker %d", shouldExist); + WARN_LOG(Log::SaveState, "Savestate failure: incorrect item marker %d", shouldExist); p.SetError(p.ERROR_FAILURE); } if (p.mode == PointerWrap::MODE_READ) { diff --git a/Common/Serialize/Serializer.cpp b/Common/Serialize/Serializer.cpp index 71f5168c3b..868231d2d2 100644 --- a/Common/Serialize/Serializer.cpp +++ b/Common/Serialize/Serializer.cpp @@ -46,11 +46,11 @@ bool PointerWrap::CheckAfterWrite() { _assert_(error != ERROR_NONE || mode == MODE_WRITE); size_t offset = Offset(); if (measuredSize_ != 0 && offset != measuredSize_) { - WARN_LOG(SAVESTATE, "CheckAfterWrite: Size mismatch! %d but expected %d", (int)offset, (int)measuredSize_); + WARN_LOG(Log::SaveState, "CheckAfterWrite: Size mismatch! %d but expected %d", (int)offset, (int)measuredSize_); return false; } if (!checkpoints_.empty() && curCheckpoint_ != checkpoints_.size()) { - WARN_LOG(SAVESTATE, "Checkpoint count mismatch!"); + WARN_LOG(Log::SaveState, "Checkpoint count mismatch!"); return false; } return true; @@ -60,6 +60,8 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) char marker[16] = {0}; int foundVersion = ver; + curTitle_ = title; + // This is strncpy because we rely on its weird non-null-terminating zero-filling truncation behaviour. // Can't replace it with the more sensible truncate_cpy because that would break savestates. strncpy(marker, title, sizeof(marker)); @@ -71,20 +73,20 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) } else if (mode == MODE_WRITE) { if (!checkpoints_.empty()) { if (checkpoints_.size() <= curCheckpoint_) { - WARN_LOG(SAVESTATE, "Write: Not enough checkpoints from measure pass (%d). cur section: %s", (int)checkpoints_.size(), title); + WARN_LOG(Log::SaveState, "Write: Not enough checkpoints from measure pass (%d). cur section: %s", (int)checkpoints_.size(), title); SetError(ERROR_FAILURE); return PointerWrapSection(*this, -1, title); } if (!checkpoints_[curCheckpoint_].Matches(marker, offset)) { - WARN_LOG(SAVESTATE, "Checkpoint mismatch during write! Section %s but expected %s, offset %d but expected %d", title, marker, (int)offset, (int)checkpoints_[curCheckpoint_].offset); + WARN_LOG(Log::SaveState, "Checkpoint mismatch during write! Section %s but expected %s, offset %d but expected %d", title, marker, (int)offset, (int)checkpoints_[curCheckpoint_].offset); if (curCheckpoint_ > 1) { - WARN_LOG(SAVESTATE, "Previous checkpoint: %s (%d)", checkpoints_[curCheckpoint_ - 1].title, (int)checkpoints_[curCheckpoint_ - 1].offset); + WARN_LOG(Log::SaveState, "Previous checkpoint: %s (%d)", checkpoints_[curCheckpoint_ - 1].title, (int)checkpoints_[curCheckpoint_ - 1].offset); } SetError(ERROR_FAILURE); return PointerWrapSection(*this, -1, title); } } else { - WARN_LOG(SAVESTATE, "Writing savestate without checkpoints. This is OK but should be fixed."); + WARN_LOG(Log::SaveState, "Writing savestate without checkpoints. This is OK but should be fixed."); } curCheckpoint_++; } @@ -106,7 +108,7 @@ PointerWrapSection PointerWrap::Section(const char *title, int minVer, int ver) firstBadSectionTitle_ = title; } if (mode != MODE_NOOP) { - WARN_LOG(SAVESTATE, "Savestate failure: wrong version %d found for section '%s'", foundVersion, title); + WARN_LOG(Log::SaveState, "Savestate failure: wrong version %d found for section '%s'", foundVersion, title); SetError(ERROR_FAILURE); } return PointerWrapSection(*this, -1, title); @@ -122,6 +124,8 @@ void PointerWrap::SetError(Error error_) { // For the rest of this run, do nothing, to avoid running off the end of memory or something, // and also not logspam like MEASURE will do in an error case. mode = PointerWrap::MODE_NOOP; + // Also, remember the bad section. + firstBadSectionTitle_ = curTitle_; } } @@ -162,7 +166,7 @@ void Do(PointerWrap &p, std::string &x) { Do(p, stringLen); if (stringLen < 0 || stringLen > MAX_SANE_STRING_LENGTH) { - WARN_LOG(SAVESTATE, "Savestate failure: bad stringLen %d", stringLen); + WARN_LOG(Log::SaveState, "Savestate failure: bad stringLen %d", stringLen); p.SetError(PointerWrap::ERROR_FAILURE); return; } @@ -182,7 +186,7 @@ void Do(PointerWrap &p, std::wstring &x) { Do(p, stringLen); if (stringLen < 0 || stringLen > MAX_SANE_STRING_LENGTH) { - WARN_LOG(SAVESTATE, "Savestate failure: bad stringLen %d", stringLen); + WARN_LOG(Log::SaveState, "Savestate failure: bad stringLen %d", stringLen); p.SetError(PointerWrap::ERROR_FAILURE); return; } @@ -210,7 +214,7 @@ void Do(PointerWrap &p, std::u16string &x) { Do(p, stringLen); if (stringLen < 0 || stringLen > MAX_SANE_STRING_LENGTH) { - WARN_LOG(SAVESTATE, "Savestate failure: bad stringLen %d", stringLen); + WARN_LOG(Log::SaveState, "Savestate failure: bad stringLen %d", stringLen); p.SetError(PointerWrap::ERROR_FAILURE); return; } @@ -271,7 +275,7 @@ void PointerWrap::DoMarker(const char *prevName, u32 arbitraryNumber) { u32 cookie = arbitraryNumber; Do(*this, cookie); if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) { - ERROR_LOG(SAVESTATE, "Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); + ERROR_LOG(Log::SaveState, "Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); SetError(ERROR_FAILURE); } } @@ -284,31 +288,31 @@ PointerWrapSection::~PointerWrapSection() { CChunkFileReader::Error CChunkFileReader::LoadFileHeader(File::IOFile &pFile, SChunkHeader &header, std::string *title) { if (!pFile) { - ERROR_LOG(SAVESTATE, "ChunkReader: Can't open file for reading"); + ERROR_LOG(Log::SaveState, "ChunkReader: Can't open file for reading"); return ERROR_BAD_FILE; } const u64 fileSize = pFile.GetSize(); u64 headerSize = sizeof(SChunkHeader); if (fileSize < headerSize) { - ERROR_LOG(SAVESTATE, "ChunkReader: File too small"); + ERROR_LOG(Log::SaveState, "ChunkReader: File too small"); return ERROR_BAD_FILE; } if (!pFile.ReadArray(&header, 1)) { - ERROR_LOG(SAVESTATE, "ChunkReader: Bad header size"); + ERROR_LOG(Log::SaveState, "ChunkReader: Bad header size"); return ERROR_BAD_FILE; } if (header.Revision < REVISION_MIN) { - ERROR_LOG(SAVESTATE, "ChunkReader: Wrong file revision, got %d expected >= %d", header.Revision, REVISION_MIN); + ERROR_LOG(Log::SaveState, "ChunkReader: Wrong file revision, got %d expected >= %d", header.Revision, REVISION_MIN); return ERROR_BAD_FILE; } if (header.Revision >= REVISION_TITLE) { char titleFixed[128]; if (!pFile.ReadArray(titleFixed, sizeof(titleFixed))) { - ERROR_LOG(SAVESTATE, "ChunkReader: Unable to read title"); + ERROR_LOG(Log::SaveState, "ChunkReader: Unable to read title"); return ERROR_BAD_FILE; } @@ -323,7 +327,7 @@ CChunkFileReader::Error CChunkFileReader::LoadFileHeader(File::IOFile &pFile, SC u32 sz = (u32)(fileSize - headerSize); if (header.ExpectedSize != sz) { - ERROR_LOG(SAVESTATE, "ChunkReader: Bad file size, got %u expected %u", sz, header.ExpectedSize); + ERROR_LOG(Log::SaveState, "ChunkReader: Bad file size, got %u expected %u", sz, header.ExpectedSize); return ERROR_BAD_FILE; } @@ -332,7 +336,7 @@ CChunkFileReader::Error CChunkFileReader::LoadFileHeader(File::IOFile &pFile, SC CChunkFileReader::Error CChunkFileReader::GetFileTitle(const Path &filename, std::string *title) { if (!File::Exists(filename)) { - ERROR_LOG(SAVESTATE, "ChunkReader: File doesn't exist"); + ERROR_LOG(Log::SaveState, "ChunkReader: File doesn't exist"); return ERROR_BAD_FILE; } @@ -344,7 +348,7 @@ CChunkFileReader::Error CChunkFileReader::GetFileTitle(const Path &filename, std CChunkFileReader::Error CChunkFileReader::LoadFile(const Path &filename, std::string *gitVersion, u8 *&_buffer, size_t &sz, std::string *failureReason) { if (!File::Exists(filename)) { *failureReason = "LoadStateDoesntExist"; - ERROR_LOG(SAVESTATE, "ChunkReader: File doesn't exist"); + ERROR_LOG(Log::SaveState, "ChunkReader: File doesn't exist"); return ERROR_BAD_FILE; } @@ -360,7 +364,7 @@ CChunkFileReader::Error CChunkFileReader::LoadFile(const Path &filename, std::st u8 *buffer = new u8[sz]; if (!pFile.ReadBytes(buffer, sz)) { - ERROR_LOG(SAVESTATE, "ChunkReader: Error reading file"); + ERROR_LOG(Log::SaveState, "ChunkReader: Error reading file"); delete [] buffer; return ERROR_BAD_FILE; } @@ -379,16 +383,16 @@ CChunkFileReader::Error CChunkFileReader::LoadFile(const Path &filename, std::st uncomp_size = status; } } else { - ERROR_LOG(SAVESTATE, "ChunkReader: Unexpected compression type %d", header.Compress); + ERROR_LOG(Log::SaveState, "ChunkReader: Unexpected compression type %d", header.Compress); } if (!success) { - ERROR_LOG(SAVESTATE, "ChunkReader: Failed to decompress file"); + ERROR_LOG(Log::SaveState, "ChunkReader: Failed to decompress file"); delete [] uncomp_buffer; delete [] buffer; return ERROR_BAD_FILE; } if ((u32)uncomp_size != header.UncompressedSize) { - ERROR_LOG(SAVESTATE, "Size mismatch: file: %u calc: %u", header.UncompressedSize, (u32)uncomp_size); + ERROR_LOG(Log::SaveState, "Size mismatch: file: %u calc: %u", header.UncompressedSize, (u32)uncomp_size); delete [] uncomp_buffer; delete [] buffer; return ERROR_BAD_FILE; @@ -411,11 +415,11 @@ CChunkFileReader::Error CChunkFileReader::LoadFile(const Path &filename, std::st // Takes ownership of buffer. CChunkFileReader::Error CChunkFileReader::SaveFile(const Path &filename, const std::string &title, const char *gitVersion, u8 *buffer, size_t sz) { - INFO_LOG(SAVESTATE, "ChunkReader: Writing %s", filename.c_str()); + INFO_LOG(Log::SaveState, "ChunkReader: Writing %s", filename.c_str()); File::IOFile pFile(filename, "wb"); if (!pFile) { - ERROR_LOG(SAVESTATE, "ChunkReader: Error opening file for write"); + ERROR_LOG(Log::SaveState, "ChunkReader: Error opening file for write"); free(buffer); return ERROR_BAD_FILE; } @@ -438,7 +442,7 @@ CChunkFileReader::Error CChunkFileReader::SaveFile(const Path &filename, const s u8 *write_buffer = buffer; if (!compressed_buffer) { if (write_len != 0) - ERROR_LOG(SAVESTATE, "ChunkReader: Unable to allocate compressed buffer"); + ERROR_LOG(Log::SaveState, "ChunkReader: Unable to allocate compressed buffer"); // We'll save uncompressed. Better than not saving... write_len = sz; usedType = SerializeCompressType::NONE; @@ -473,7 +477,7 @@ CChunkFileReader::Error CChunkFileReader::SaveFile(const Path &filename, const s free(buffer); write_buffer = compressed_buffer; } else { - ERROR_LOG(SAVESTATE, "ChunkReader: Compression failed"); + ERROR_LOG(Log::SaveState, "ChunkReader: Compression failed"); free(compressed_buffer); // We can still save uncompressed. @@ -496,25 +500,25 @@ CChunkFileReader::Error CChunkFileReader::SaveFile(const Path &filename, const s // Now let's start writing out the file... if (!pFile.WriteArray(&header, 1)) { - ERROR_LOG(SAVESTATE, "ChunkReader: Failed writing header"); + ERROR_LOG(Log::SaveState, "ChunkReader: Failed writing header"); free(write_buffer); return ERROR_BAD_FILE; } if (!pFile.WriteArray(titleFixed, sizeof(titleFixed))) { - ERROR_LOG(SAVESTATE, "ChunkReader: Failed writing title"); + ERROR_LOG(Log::SaveState, "ChunkReader: Failed writing title"); free(write_buffer); return ERROR_BAD_FILE; } if (!pFile.WriteBytes(write_buffer, write_len)) { - ERROR_LOG(SAVESTATE, "ChunkReader: Failed writing compressed data"); + ERROR_LOG(Log::SaveState, "ChunkReader: Failed writing compressed data"); free(write_buffer); return ERROR_BAD_FILE; } else if (sz != write_len) { - INFO_LOG(SAVESTATE, "Savestate: Compressed %i bytes into %i", (int)sz, (int)write_len); + INFO_LOG(Log::SaveState, "Savestate: Compressed %i bytes into %i", (int)sz, (int)write_len); } free(write_buffer); - INFO_LOG(SAVESTATE, "ChunkReader: Done writing %s", filename.c_str()); + INFO_LOG(Log::SaveState, "ChunkReader: Done writing %s", filename.c_str()); return ERROR_NONE; } diff --git a/Common/Serialize/Serializer.h b/Common/Serialize/Serializer.h index 808967b518..4c1b4c050b 100644 --- a/Common/Serialize/Serializer.h +++ b/Common/Serialize/Serializer.h @@ -121,6 +121,10 @@ public: } } + bool Failed() const { + return error == ERROR_FAILURE; + } + void RewindForWrite(u8 *writePtr); bool CheckAfterWrite(); @@ -156,6 +160,7 @@ public: private: const char *firstBadSectionTitle_ = nullptr; + const char *curTitle_; u8 *ptrStart_; std::vector checkpoints_; size_t curCheckpoint_ = 0; @@ -269,9 +274,9 @@ public: failureReason->clear(); error = LoadPtr(ptr, _class, failureReason); delete [] ptr; - INFO_LOG(SAVESTATE, "ChunkReader: Done loading '%s'", filename.c_str()); + INFO_LOG(Log::SaveState, "ChunkReader: Done loading '%s'", filename.c_str()); } else { - WARN_LOG(SAVESTATE, "ChunkReader: Error found during load of '%s'", filename.c_str()); + WARN_LOG(Log::SaveState, "ChunkReader: Error found during load of '%s'", filename.c_str()); } return error; } diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index abf2970ce5..2f797a71dc 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -40,6 +40,7 @@ #include #include +#include #include "Common/Buffer.h" #include "Common/StringUtils.h" @@ -93,6 +94,12 @@ long parseLong(std::string s) { return value; } +bool containsNoCase(std::string_view haystack, std::string_view needle) { + auto pred = [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }; + auto found = std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end(), pred); + return found != haystack.end(); +} + bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) { int writtenCount = vsnprintf(out, outsize, format, args); @@ -171,6 +178,14 @@ std::string IndentString(const std::string &str, const std::string &sep, bool sk return output.str(); } +std::string_view StripPrefix(std::string_view prefix, std::string_view s) { + if (startsWith(s, prefix)) { + return s.substr(prefix.size(), s.size() - prefix.size()); + } else { + return s; + } +} + void SkipSpace(const char **ptr) { while (**ptr && isspace(**ptr)) { (*ptr)++; @@ -334,7 +349,7 @@ void SplitString(std::string_view str, const char delim, std::vector &output) { +void GetQuotedStrings(std::string_view str, std::vector &output) { size_t next = 0; bool even = 0; for (size_t pos = 0, len = str.length(); pos < len; ++pos) { @@ -372,11 +387,11 @@ void GetQuotedStrings(const std::string& str, std::vector &output) } } +// TODO: this is quite inefficient. std::string ReplaceAll(std::string_view input, std::string_view src, std::string_view dest) { size_t pos = 0; std::string result(input); - if (src == dest) return result; diff --git a/Common/StringUtils.h b/Common/StringUtils.h index da1ddf7468..aa331e0f93 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -69,6 +69,8 @@ inline bool equalsNoCase(std::string_view str, std::string_view key) { return strncasecmp(str.data(), key.data(), key.size()) == 0; } +bool containsNoCase(std::string_view haystack, std::string_view needle); + void DataToHexString(const uint8_t *data, size_t size, std::string *output); void DataToHexString(int indent, uint32_t startAddr, const uint8_t* data, size_t size, std::string* output); @@ -81,12 +83,14 @@ std::string StripQuotes(const std::string &s); std::string_view StripSpaces(std::string_view s); std::string_view StripQuotes(std::string_view s); +std::string_view StripPrefix(std::string_view prefix, std::string_view s); + // NOTE: str must live at least as long as all uses of output. void SplitString(std::string_view str, const char delim, std::vector &output); // Try to avoid this when possible, in favor of the string_view version. void SplitString(std::string_view str, const char delim, std::vector &output); -void GetQuotedStrings(const std::string& str, std::vector& output); +void GetQuotedStrings(std::string_view str, std::vector &output); std::string ReplaceAll(std::string_view input, std::string_view src, std::string_view dest); @@ -102,6 +106,10 @@ inline size_t truncate_cpy(char(&out)[Count], const char *src) { return truncate_cpy(out, Count, src); } size_t truncate_cpy(char *dest, size_t destSize, std::string_view src); +template +inline size_t truncate_cpy(char(&out)[Count], std::string_view src) { + return truncate_cpy(out, Count, src); +} const char* safe_string(const char* s); diff --git a/Common/System/OSD.cpp b/Common/System/OSD.cpp index 704b4367e9..b20a8bc572 100644 --- a/Common/System/OSD.cpp +++ b/Common/System/OSD.cpp @@ -12,12 +12,29 @@ OnScreenDisplay g_OSD; // Effectively forever. constexpr double forever_s = 10000000000.0; +OnScreenDisplay::~OnScreenDisplay() { + std::lock_guard guard(mutex_); + + double now = time_now_d(); + for (auto &iter : entries_) { + if (iter.clickCallback) { + // Wasn't clicked, but let it free any data. + iter.clickCallback(false, iter.clickUserData); + } + } +} + void OnScreenDisplay::Update() { std::lock_guard guard(mutex_); double now = time_now_d(); for (auto iter = entries_.begin(); iter != entries_.end(); ) { if (now >= iter->endTime) { + if (iter->clickCallback) { + // Wasn't clicked, but let it free any data. + iter->clickCallback(false, iter->clickUserData); + iter->clickCallback = nullptr; + } iter = entries_.erase(iter); } else { iter++; @@ -41,10 +58,13 @@ float OnScreenDisplay::SidebarAlpha() const { return saturatef(1.0f - ((float)timeSinceNudge - 0.1f) * 4.0f); } -void OnScreenDisplay::DismissEntry(size_t index, double now) { +void OnScreenDisplay::ClickEntry(size_t index, double now) { std::lock_guard guard(mutex_); if (index < entries_.size() && entries_[index].type != OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR) { entries_[index].endTime = std::min(now + FadeoutTime(), entries_[index].endTime); + if (entries_[index].clickCallback) { + entries_[index].clickCallback(true, entries_[index].clickUserData); + } } } @@ -90,7 +110,7 @@ void OnScreenDisplay::Show(OSDType type, std::string_view text, std::string_view } } - Entry msg; + Entry msg{}; msg.text = text; msg.text2 = text2; msg.iconName = icon; @@ -116,7 +136,7 @@ void OnScreenDisplay::ShowAchievementUnlocked(int achievementID) { double duration_s = 5.0; - Entry msg; + Entry msg{}; msg.numericID = achievementID; msg.type = OSDType::ACHIEVEMENT_UNLOCKED; msg.startTime = now; @@ -149,7 +169,7 @@ void OnScreenDisplay::ShowAchievementProgress(int achievementID, bool show) { } // OK, let's make a new side-entry. - Entry entry; + Entry entry{}; entry.numericID = achievementID; entry.type = OSDType::ACHIEVEMENT_PROGRESS; entry.startTime = now; @@ -175,7 +195,7 @@ void OnScreenDisplay::ShowChallengeIndicator(int achievementID, bool show) { } // OK, let's make a new side-entry. - Entry entry; + Entry entry{}; entry.numericID = achievementID; entry.type = OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR; entry.startTime = now; @@ -208,7 +228,7 @@ void OnScreenDisplay::ShowLeaderboardTracker(int leaderboardTrackerID, const cha } // OK, let's make a new side-entry. - Entry entry; + Entry entry{}; entry.numericID = leaderboardTrackerID; entry.type = OSDType::LEADERBOARD_TRACKER; entry.startTime = now; @@ -247,7 +267,7 @@ void OnScreenDisplay::SetProgressBar(std::string_view id, std::string_view messa } } - Entry bar; + Entry bar{}; bar.id = id; bar.type = OSDType::PROGRESS_BAR; bar.text = message; @@ -298,3 +318,14 @@ void OnScreenDisplay::ClearAchievementStuff() { } } } + +void OnScreenDisplay::SetClickCallback(const char *id, void (*callback)(bool, void *), void *userdata) { + _dbg_assert_(callback != nullptr); + for (auto &ent : entries_) { + // protect against dupes. + if (ent.id == id && !ent.clickCallback) { + ent.clickCallback = callback; + ent.clickUserData = userdata; + } + } +} diff --git a/Common/System/OSD.h b/Common/System/OSD.h index 24cb4b4ab2..fdd513f02c 100644 --- a/Common/System/OSD.h +++ b/Common/System/OSD.h @@ -35,6 +35,8 @@ enum class OSDType { // Data holder for on-screen messages. class OnScreenDisplay { public: + ~OnScreenDisplay(); + // If you specify 0.0f as duration, a duration will be chosen automatically depending on type. void Show(OSDType type, std::string_view text, float duration_s = 0.0f, const char *id = nullptr) { Show(type, text, "", duration_s, id); @@ -72,6 +74,9 @@ public: // Fades out everything related to achievements. Should be used on game shutdown. void ClearAchievementStuff(); + // Can't add an infinite number of "Show" functions, so starting to offer post-modification. + void SetClickCallback(const char *id, void (*callback)(bool, void *), void *userdata); + struct Entry { OSDType type; std::string text; @@ -79,6 +84,12 @@ public: std::string iconName; int numericID; std::string id; + + // We could use std::function, but prefer to do it the oldschool way. + void (*clickCallback)(bool, void *); + void *clickUserData; + + int instanceID; double startTime; double endTime; @@ -91,7 +102,7 @@ public: std::vector Entries(); // TODO: Use something more stable than the index. - void DismissEntry(size_t index, double now); + void ClickEntry(size_t index, double now); static float FadeinTime() { return 0.1f; } static float FadeoutTime() { return 0.25f; } diff --git a/Common/System/Request.cpp b/Common/System/Request.cpp index ccaf5622f1..23f15f796e 100644 --- a/Common/System/Request.cpp +++ b/Common/System/Request.cpp @@ -31,7 +31,7 @@ const char *RequestTypeAsString(SystemRequestType type) { } } -bool RequestManager::MakeSystemRequest(SystemRequestType type, RequesterToken token, RequestCallback callback, RequestFailedCallback failedCallback, std::string_view param1, std::string_view param2, int param3) { +bool RequestManager::MakeSystemRequest(SystemRequestType type, RequesterToken token, RequestCallback callback, RequestFailedCallback failedCallback, std::string_view param1, std::string_view param2, int64_t param3, int64_t param4) { if (token == NO_REQUESTER_TOKEN) { _dbg_assert_(!callback); _dbg_assert_(!failedCallback); @@ -48,25 +48,24 @@ bool RequestManager::MakeSystemRequest(SystemRequestType type, RequesterToken to callbackMap_[requestId] = { callback, failedCallback, token }; } - VERBOSE_LOG(SYSTEM, "Making system request %s: id %d", RequestTypeAsString(type), requestId); + VERBOSE_LOG(Log::System, "Making system request %s: id %d", RequestTypeAsString(type), requestId); std::string p1(param1); std::string p2(param2); // TODO: Convert to string_view - if (!System_MakeRequest(type, requestId, p1, p2, param3)) { + if (!System_MakeRequest(type, requestId, p1, p2, param3, param4)) { if (callback || failedCallback) { std::lock_guard guard(callbackMutex_); callbackMap_.erase(requestId); } return false; } - return true; } void RequestManager::ForgetRequestsWithToken(RequesterToken token) { for (auto &iter : callbackMap_) { if (iter.second.token == token) { - INFO_LOG(SYSTEM, "Forgetting about requester with token %d", token); + INFO_LOG(Log::System, "Forgetting about requester with token %d", token); iter.second.callback = nullptr; iter.second.failedCallback = nullptr; } @@ -77,7 +76,7 @@ void RequestManager::PostSystemSuccess(int requestId, const char *responseString std::lock_guard guard(callbackMutex_); auto iter = callbackMap_.find(requestId); if (iter == callbackMap_.end()) { - ERROR_LOG(SYSTEM, "PostSystemSuccess: Unexpected request ID %d (responseString=%s)", requestId, responseString); + ERROR_LOG(Log::System, "PostSystemSuccess: Unexpected request ID %d (responseString=%s)", requestId, responseString); return; } @@ -87,7 +86,7 @@ void RequestManager::PostSystemSuccess(int requestId, const char *responseString response.responseString = responseString; response.responseValue = responseValue; pendingSuccesses_.push_back(response); - DEBUG_LOG(SYSTEM, "PostSystemSuccess: Request %d (%s, %d)", requestId, responseString, responseValue); + DEBUG_LOG(Log::System, "PostSystemSuccess: Request %d (%s, %d)", requestId, responseString, responseValue); callbackMap_.erase(iter); } @@ -95,11 +94,11 @@ void RequestManager::PostSystemFailure(int requestId) { std::lock_guard guard(callbackMutex_); auto iter = callbackMap_.find(requestId); if (iter == callbackMap_.end()) { - ERROR_LOG(SYSTEM, "PostSystemFailure: Unexpected request ID %d", requestId); + ERROR_LOG(Log::System, "PostSystemFailure: Unexpected request ID %d", requestId); return; } - WARN_LOG(SYSTEM, "PostSystemFailure: Request %d failed", requestId); + WARN_LOG(Log::System, "PostSystemFailure: Request %d failed", requestId); std::lock_guard responseGuard(responseMutex_); PendingFailure response; @@ -145,3 +144,9 @@ void System_ShowFileInFolder(const Path &path) { void System_BrowseForFolder(RequesterToken token, std::string_view title, const Path &initialPath, RequestCallback callback, RequestFailedCallback failedCallback) { g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FOLDER, token, callback, failedCallback, title, initialPath.ToCString(), 0); } + +void System_RunCallbackInWndProc(void (*callback)(void *, void *), void *userdata) { + int64_t castPtr = (int64_t)callback; + int64_t castUserData = (int64_t)userdata; + g_requestManager.MakeSystemRequest(SystemRequestType::RUN_CALLBACK_IN_WNDPROC, NO_REQUESTER_TOKEN, nullptr, nullptr, "", "", castPtr, castUserData); +} diff --git a/Common/System/Request.h b/Common/System/Request.h index ec82214884..c7947f0c6e 100644 --- a/Common/System/Request.h +++ b/Common/System/Request.h @@ -27,7 +27,8 @@ public: // The callback you pass in will be called on the main thread later. // Params are at the end since it's the part most likely to recieve additions in the future, // now that we have both callbacks. - bool MakeSystemRequest(SystemRequestType type, RequesterToken token, RequestCallback callback, RequestFailedCallback failedCallback, std::string_view param1, std::string_view param2, int param3); + // Pointers can be passed through param3 and param4 if needed, by casting. + bool MakeSystemRequest(SystemRequestType type, RequesterToken token, RequestCallback callback, RequestFailedCallback failedCallback, std::string_view param1, std::string_view param2, int64_t param3, int64_t param4 = 0); // Called by the platform implementation, when it's finished with a request. void PostSystemSuccess(int requestId, const char *responseString, int responseValue = 0); @@ -159,8 +160,12 @@ inline void System_ShareText(std::string_view text) { g_requestManager.MakeSystemRequest(SystemRequestType::SHARE_TEXT, NO_REQUESTER_TOKEN, nullptr, nullptr, text, "", 0); } -inline void System_NotifyUIState(std::string_view state) { - g_requestManager.MakeSystemRequest(SystemRequestType::NOTIFY_UI_STATE, NO_REQUESTER_TOKEN, nullptr, nullptr, state, "", 0); +inline void System_NotifyUIEvent(UIEventNotification notification) { + g_requestManager.MakeSystemRequest(SystemRequestType::NOTIFY_UI_EVENT, NO_REQUESTER_TOKEN, nullptr, nullptr, "", "", (int64_t)notification, 0); +} + +inline void System_SetKeepScreenBright(bool keepScreenBright) { + g_requestManager.MakeSystemRequest(SystemRequestType::SET_KEEP_SCREEN_BRIGHT, NO_REQUESTER_TOKEN, nullptr, nullptr, "", "", (int64_t)keepScreenBright); } inline void System_SetWindowTitle(std::string_view param) { @@ -175,6 +180,8 @@ inline void System_SendDebugScreenshot(std::string_view data, int height) { g_requestManager.MakeSystemRequest(SystemRequestType::SEND_DEBUG_SCREENSHOT, NO_REQUESTER_TOKEN, nullptr, nullptr, data, "", height); } +void System_RunCallbackInWndProc(void (*callback)(void *, void *), void *userdata); + // Non-inline to avoid including Path.h void System_CreateGameShortcut(const Path &path, std::string_view title); void System_ShowFileInFolder(const Path &path); diff --git a/Common/System/System.h b/Common/System/System.h index 0812930090..fdd7a81874 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -56,6 +56,13 @@ void System_LaunchUrl(LaunchUrlType urlType, const char *url); // Going forward, "optional" things (PPSSPP will still function alright without it) will be requests, // to make implementations simpler in the default case. +enum class UIEventNotification { + MENU_RETURN, + POPUP_CLOSED, + TEXT_GOTFOCUS, + TEXT_LOSTFOCUS, +}; + enum class SystemRequestType { INPUT_TEXT_MODAL, ASK_USERNAME_PASSWORD, @@ -79,13 +86,16 @@ enum class SystemRequestType { // Note: height specified as param3, width based on param1.size() / param3. SEND_DEBUG_SCREENSHOT, - NOTIFY_UI_STATE, // Used on Android only. Not a SystemNotification since it takes a parameter. + NOTIFY_UI_EVENT, // Used to manage events that are useful for popup virtual keyboards. + SET_KEEP_SCREEN_BRIGHT, // High-level hardware control CAMERA_COMMAND, GPS_COMMAND, INFRARED_COMMAND, MICROPHONE_COMMAND, + + RUN_CALLBACK_IN_WNDPROC, }; // Implementations are supposed to process the request, and post the response to the g_RequestManager (see Message.h). @@ -93,7 +103,7 @@ enum class SystemRequestType { // This can return false if it's known that the platform doesn't support the request, the app is supposed to handle // or ignore that cleanly. // Some requests don't use responses. -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3); +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4); PermissionStatus System_GetPermissionStatus(SystemPermission permission); void System_AskForPermission(SystemPermission permission); @@ -114,6 +124,7 @@ enum SystemKeyboardLayout { enum SystemProperty { SYSPROP_NAME, + SYSPROP_SYSTEMBUILD, SYSPROP_LANGREGION, SYSPROP_CPUINFO, SYSPROP_BOARDNAME, @@ -132,9 +143,11 @@ enum SystemProperty { SYSPROP_HAS_IMAGE_BROWSER, SYSPROP_HAS_BACK_BUTTON, SYSPROP_HAS_KEYBOARD, + SYSPROP_KEYBOARD_IS_SOFT, SYSPROP_HAS_ACCELEROMETER, // Used to enable/disable tilt input settings SYSPROP_HAS_OPEN_DIRECTORY, SYSPROP_HAS_LOGIN_DIALOG, + SYSPROP_HAS_TEXT_CLIPBOARD, SYSPROP_HAS_TEXT_INPUT_DIALOG, // Indicates that System_InputBoxGetString is available. SYSPROP_CAN_CREATE_SHORTCUT, @@ -191,7 +204,13 @@ enum SystemProperty { SYSPROP_USER_DOCUMENTS_DIR, + // iOS app store limitation: The documents directory should be the only browsable directory. + // We'll not return true for this in non-app-store builds. + SYSPROP_LIMITED_FILE_BROWSING, + SYSPROP_OK_BUTTON_LEFT, + + SYSPROP_MAIN_WINDOW_HANDLE, }; enum class SystemNotification { @@ -212,6 +231,9 @@ enum class SystemNotification { TEST_JAVA_EXCEPTION, KEEP_SCREEN_AWAKE, ACTIVITY, + UI_STATE_CHANGED, + AUDIO_MODE_CHANGED, + APP_SWITCH_MODE_CHANGED, }; // I guess it's not super great architecturally to centralize this, since it's not general - but same with a lot of @@ -252,7 +274,7 @@ enum class UIMessage { std::string System_GetProperty(SystemProperty prop); std::vector System_GetPropertyStringVec(SystemProperty prop); -int System_GetPropertyInt(SystemProperty prop); +int64_t System_GetPropertyInt(SystemProperty prop); float System_GetPropertyFloat(SystemProperty prop); bool System_GetPropertyBool(SystemProperty prop); diff --git a/Common/Thread/ThreadManager.cpp b/Common/Thread/ThreadManager.cpp index 7bacb69494..f1224a64a8 100644 --- a/Common/Thread/ThreadManager.cpp +++ b/Common/Thread/ThreadManager.cpp @@ -99,7 +99,7 @@ void ThreadManager::Teardown() { global_->threads_.clear(); if (global_->compute_queue_size > 0 || global_->io_queue_size > 0) { - WARN_LOG(SYSTEM, "ThreadManager::Teardown() with tasks still enqueued"); + WARN_LOG(Log::System, "ThreadManager::Teardown() with tasks still enqueued"); } } @@ -222,7 +222,7 @@ void ThreadManager::Init(int numRealCores, int numLogicalCoresPerCpu) { int numThreads = numComputeThreads_ + std::max(MIN_IO_BLOCKING_THREADS, numComputeThreads_); numThreads_ = numThreads; - INFO_LOG(SYSTEM, "ThreadManager::Init(compute threads: %d, all: %d)", numComputeThreads_, numThreads_); + INFO_LOG(Log::System, "ThreadManager::Init(compute threads: %d, all: %d)", numComputeThreads_, numThreads_); for (int i = 0; i < numThreads; i++) { TaskThreadContext *thread = new TaskThreadContext(); diff --git a/Common/Thread/ThreadUtil.cpp b/Common/Thread/ThreadUtil.cpp index 338dfa1a86..0e0badb084 100644 --- a/Common/Thread/ThreadUtil.cpp +++ b/Common/Thread/ThreadUtil.cpp @@ -218,7 +218,7 @@ void SetCurrentThreadNameThroughException(const char *threadName) { void AssertCurrentThreadName(const char *threadName) { #ifdef TLS_SUPPORTED if (strcmp(curThreadName, threadName) != 0) { - ERROR_LOG(SYSTEM, "Thread name assert failed: Expected %s, was %s", threadName, curThreadName); + ERROR_LOG(Log::System, "Thread name assert failed: Expected %s, was %s", threadName, curThreadName); } #endif } diff --git a/Common/TimeUtil.cpp b/Common/TimeUtil.cpp index b24a1da4e3..116e91813e 100644 --- a/Common/TimeUtil.cpp +++ b/Common/TimeUtil.cpp @@ -4,6 +4,7 @@ #include #include "Common/TimeUtil.h" +#include "Common/Log.h" #ifdef HAVE_LIBNX #include @@ -31,8 +32,8 @@ // TODO: https://github.com/floooh/sokol/blob/9a6237fcdf213e6da48e4f9201f144bcb2dcb46f/sokol_time.h#L229-L248 -static const double micros = 1000000.0; -static const double nanos = 1000000000.0; +constexpr double micros = 1000000.0; +constexpr double nanos = 1000000000.0; #if PPSSPP_PLATFORM(WINDOWS) @@ -40,16 +41,29 @@ static LARGE_INTEGER frequency; static double frequencyMult; static LARGE_INTEGER startTime; +HANDLE Timer; +int SchedulerPeriodMs = 10; +INT64 QpcPerSecond; + +void TimeInit() { + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&startTime); + QpcPerSecond = frequency.QuadPart; + frequencyMult = 1.0 / static_cast(frequency.QuadPart); + + Timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); +#if !PPSSPP_PLATFORM(UWP) + TIMECAPS caps; + timeGetDevCaps(&caps, sizeof caps); + timeBeginPeriod(caps.wPeriodMin); + SchedulerPeriodMs = (int)caps.wPeriodMin; +#endif +} + double time_now_d() { - if (frequency.QuadPart == 0) { - QueryPerformanceFrequency(&frequency); - QueryPerformanceCounter(&startTime); - frequencyMult = 1.0 / static_cast(frequency.QuadPart); - } LARGE_INTEGER time; QueryPerformanceCounter(&time); - double elapsed = static_cast(time.QuadPart - startTime.QuadPart); - return elapsed * frequencyMult; + return static_cast(time.QuadPart - startTime.QuadPart) * frequencyMult; } // Fake, but usable in a pinch. Don't, though. @@ -86,8 +100,28 @@ void yield() { YieldProcessor(); } +Instant::Instant() { + _dbg_assert_(frequencyMult != 0.0); + QueryPerformanceCounter(reinterpret_cast(&nativeStart_)); +} + +double Instant::ElapsedSeconds() const { + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + double elapsed = static_cast(time.QuadPart - nativeStart_); + return elapsed * frequencyMult; +} + +int64_t Instant::ElapsedNanos() const { + return (int64_t)(ElapsedSeconds() * 1000000000.0); +} + #elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) +void TimeInit() { + // Nothing to do. +} + // The only intended use is to match the timings in VK_GOOGLE_display_timing uint64_t time_now_raw() { struct timespec tp; @@ -128,10 +162,38 @@ void yield() { #endif } +Instant::Instant() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + nativeStart_ = ts.tv_sec; + nsecs_ = ts.tv_nsec; +} + +int64_t Instant::ElapsedNanos() const { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + int64_t secs = ts.tv_sec - nativeStart_; + int64_t nsecs = ts.tv_nsec - nsecs_; + if (nsecs < 0) { + secs--; + nsecs += 1000000000; + } + return secs * 1000000000ULL + nsecs; +} + +double Instant::ElapsedSeconds() const { + return (double)ElapsedNanos() * (1.0 / nanos); +} + #else +void TimeInit() { + // Nothing to do. +} + +static time_t start; + double time_now_d() { - static time_t start; struct timeval tv; gettimeofday(&tv, nullptr); if (start == 0) { @@ -141,7 +203,6 @@ double time_now_d() { } uint64_t time_now_raw() { - static time_t start; struct timeval tv; gettimeofday(&tv, nullptr); if (start == 0) { @@ -164,6 +225,30 @@ double time_now_unix_utc() { return time_now_raw(); } +Instant::Instant() { + struct timeval tv; + gettimeofday(&tv, nullptr); + nativeStart_ = tv.tv_sec; + nsecs_ = tv.tv_usec; +} + +int64_t Instant::ElapsedNanos() const { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + + int64_t secs = ts.tv_sec - nativeStart_; + int64_t usecs = ts.tv_nsec - nsecs_; + if (usecs < 0) { + secs--; + usecs += 1000000; + } + return secs * 1000000000 + usecs * 1000; +} + +double Instant::ElapsedSeconds() const { + return (double)ElapsedNanos() * (1.0 / 1000000000.0); +} + #endif void sleep_ms(int ms) { @@ -178,9 +263,58 @@ void sleep_ms(int ms) { #endif } +// Precise Windows sleep function from: https://github.com/blat-blatnik/Snippets/blob/main/precise_sleep.c +// Described in: https://blog.bearcats.nl/perfect-sleep-function/ + +void sleep_precise(double seconds) { +#ifdef _WIN32 + LARGE_INTEGER qpc; + QueryPerformanceCounter(&qpc); + INT64 targetQpc = (INT64)(qpc.QuadPart + seconds * QpcPerSecond); + + if (Timer) { // Try using a high resolution timer first. + const double TOLERANCE = 0.001'02; + INT64 maxTicks = (INT64)SchedulerPeriodMs * 9'500; + for (;;) // Break sleep up into parts that are lower than scheduler period. + { + double remainingSeconds = (targetQpc - qpc.QuadPart) / (double)QpcPerSecond; + INT64 sleepTicks = (INT64)((remainingSeconds - TOLERANCE) * 10'000'000); + if (sleepTicks <= 0) + break; + LARGE_INTEGER due; + due.QuadPart = -(sleepTicks > maxTicks ? maxTicks : sleepTicks); + // Note: SetWaitableTimerEx is not available on Vista. + SetWaitableTimer(Timer, &due, 0, NULL, NULL, NULL); + WaitForSingleObject(Timer, INFINITE); + QueryPerformanceCounter(&qpc); + } + } else { // Fallback to Sleep. + const double TOLERANCE = 0.000'02; + double sleepMs = (seconds - TOLERANCE) * 1000 - SchedulerPeriodMs; // Sleep for 1 scheduler period less than requested. + int sleepSlices = (int)(sleepMs / SchedulerPeriodMs); + if (sleepSlices > 0) + Sleep((DWORD)sleepSlices * SchedulerPeriodMs); + QueryPerformanceCounter(&qpc); + } + while (qpc.QuadPart < targetQpc) // Spin for any remaining time. + { + YieldProcessor(); + QueryPerformanceCounter(&qpc); + } +#else +#if defined(HAVE_LIBNX) + svcSleepThread((int64_t)(seconds * 1000000000.0)); +#elif defined(__EMSCRIPTEN__) + emscripten_sleep(seconds * 1000.0); +#else + usleep(seconds * 1000000.0); +#endif +#endif +} + // Return the current time formatted as Minutes:Seconds:Milliseconds // in the form 00:00:000. -void GetTimeFormatted(char formattedTime[13]) { +void GetCurrentTimeFormatted(char formattedTime[13]) { time_t sysTime; time(&sysTime); diff --git a/Common/TimeUtil.h b/Common/TimeUtil.h index 779ba07d21..1e89a4a24f 100644 --- a/Common/TimeUtil.h +++ b/Common/TimeUtil.h @@ -1,7 +1,8 @@ #pragma once - #include +void TimeInit(); + // Seconds. double time_now_d(); @@ -19,21 +20,26 @@ double time_now_unix_utc(); // Sleep. Does not necessarily have millisecond granularity, especially on Windows. void sleep_ms(int ms); +// Precise sleep. Can consume a little bit of CPU on Windows at least. +void sleep_precise(double seconds); + // Yield. Signals that this thread is busy-waiting but wants to allow other hyperthreads to run. void yield(); -void GetTimeFormatted(char formattedTime[13]); +void GetCurrentTimeFormatted(char formattedTime[13]); -// Rust-style Instant for clear and easy timing. +// Most accurate timer possible - no extra double conversions. Only for spans. class Instant { public: static Instant Now() { - return Instant(time_now_d()); - } - double Elapsed() const { - return time_now_d() - instantTime_; + return Instant(); } + double ElapsedSeconds() const; + int64_t ElapsedNanos() const; private: - explicit Instant(double initTime) : instantTime_(initTime) {} - double instantTime_; + Instant(); + uint64_t nativeStart_; +#ifndef _WIN32 + int64_t nsecs_; +#endif }; diff --git a/Common/UI/AsyncImageFileView.cpp b/Common/UI/AsyncImageFileView.cpp index 3fa627b900..540bf9142b 100644 --- a/Common/UI/AsyncImageFileView.cpp +++ b/Common/UI/AsyncImageFileView.cpp @@ -96,8 +96,8 @@ void AsyncImageFileView::Draw(UIContext &dc) { dc.Flush(); dc.RebindTexture(); if (!text_.empty()) { - dc.DrawText(text_.c_str(), bounds_.centerX() + 1, bounds_.centerY() + 1, 0x80000000, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); - dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + dc.DrawText(text_, bounds_.centerX() + 1, bounds_.centerY() + 1, 0x80000000, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + dc.DrawText(text_, bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); } } else { if (!texture_ || texture_->Failed()) { @@ -110,7 +110,7 @@ void AsyncImageFileView::Draw(UIContext &dc) { } } if (!text_.empty()) { - dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); + dc.DrawText(text_, bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII); } } } diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index a60325a61c..bab93547e0 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -59,7 +59,7 @@ void UIContext::BeginFrame() { // Load the smaller ascii font only, like on Android. For debug ui etc. fontTexture_ = CreateTextureFromFile(draw_, "asciifont_atlas.zim", ImageFileType::ZIM, false); if (!fontTexture_) { - WARN_LOG(SYSTEM, "Failed to load font_atlas.zim or asciifont_atlas.zim"); + WARN_LOG(Log::System, "Failed to load font_atlas.zim or asciifont_atlas.zim"); } } } @@ -171,7 +171,7 @@ void UIContext::ActivateTopScissor() { int w = std::max(0.0f, ceilf(scale_x * bounds.w)); int h = std::max(0.0f, ceilf(scale_y * bounds.h)); if (x < 0 || y < 0 || x + w > g_display.pixel_xres || y + h > g_display.pixel_yres) { - DEBUG_LOG(G3D, "UI scissor out of bounds: %d,%d-%d,%d / %d,%d", x, y, w, h, g_display.pixel_xres, g_display.pixel_yres); + DEBUG_LOG(Log::G3D, "UI scissor out of bounds: %d,%d-%d,%d / %d,%d", x, y, w, h, g_display.pixel_xres, g_display.pixel_yres); if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } if (x >= g_display.pixel_xres) { x = g_display.pixel_xres - 1; } @@ -206,41 +206,36 @@ void UIContext::SetFontStyle(const UI::FontStyle &fontStyle) { } } -void UIContext::MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, float *x, float *y, int align) const { - _dbg_assert_(str != nullptr); - MeasureTextCount(style, scaleX, scaleY, str, (int)strlen(str), x, y, align); -} - -void UIContext::MeasureTextCount(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, float *x, float *y, int align) const { - _dbg_assert_(str != nullptr); +void UIContext::MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, float *x, float *y, int align) const { + _dbg_assert_(str.data() != nullptr); if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { float sizeFactor = (float)style.sizePts / 24.0f; Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor); - Draw()->MeasureTextCount(style.atlasFont, str, count, x, y); + Draw()->MeasureText(style.atlasFont, str, x, y); } else { textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags); textDrawer_->SetFontScale(scaleX, scaleY); - textDrawer_->MeasureString(str, count, x, y); + textDrawer_->MeasureString(str, x, y); textDrawer_->SetFont(fontStyle_->fontName.c_str(), fontStyle_->sizePts, fontStyle_->flags); } } -void UIContext::MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, const Bounds &bounds, float *x, float *y, int align) const { - _dbg_assert_(str != nullptr); +void UIContext::MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, float *x, float *y, int align) const { + _dbg_assert_(str.data() != nullptr); if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { float sizeFactor = (float)style.sizePts / 24.0f; Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor); - Draw()->MeasureTextRect(style.atlasFont, str, count, bounds, x, y, align); + Draw()->MeasureTextRect(style.atlasFont, str, bounds, x, y, align); } else { textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags); textDrawer_->SetFontScale(scaleX, scaleY); - textDrawer_->MeasureStringRect(str, count, bounds, x, y, align); + textDrawer_->MeasureStringRect(str, bounds, x, y, align); textDrawer_->SetFont(fontStyle_->fontName.c_str(), fontStyle_->sizePts, fontStyle_->flags); } } -void UIContext::DrawText(const char *str, float x, float y, uint32_t color, int align) { - _dbg_assert_(str != nullptr); +void UIContext::DrawText(std::string_view str, float x, float y, uint32_t color, int align) { + _dbg_assert_(str.data() != nullptr); if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { // Use the font texture if this font is in that texture instead. bool useFontTexture = Draw()->GetFontAtlas()->getFont(fontStyle_->atlasFont) != nullptr; @@ -260,13 +255,13 @@ void UIContext::DrawText(const char *str, float x, float y, uint32_t color, int RebindTexture(); } -void UIContext::DrawTextShadow(const char *str, float x, float y, uint32_t color, int align) { +void UIContext::DrawTextShadow(std::string_view str, float x, float y, uint32_t color, int align) { uint32_t alpha = (color >> 1) & 0xFF000000; DrawText(str, x + 2, y + 2, alpha, align); DrawText(str, x, y, color, align); } -void UIContext::DrawTextRect(const char *str, const Bounds &bounds, uint32_t color, int align) { +void UIContext::DrawTextRect(std::string_view str, const Bounds &bounds, uint32_t color, int align) { if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { // Use the font texture if this font is in that texture instead. bool useFontTexture = Draw()->GetFontAtlas()->getFont(fontStyle_->atlasFont) != nullptr; @@ -291,17 +286,17 @@ void UIContext::DrawTextRect(const char *str, const Bounds &bounds, uint32_t col static constexpr float MIN_TEXT_SCALE = 0.7f; -float UIContext::CalculateTextScale(const char *text, float availWidth, float availHeight) const { +float UIContext::CalculateTextScale(std::string_view str, float availWidth, float availHeight) const { float actualWidth, actualHeight; Bounds availBounds(0, 0, availWidth, availHeight); - MeasureTextRect(theme->uiFont, 1.0f, 1.0f, text, (int)strlen(text), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER); + MeasureTextRect(theme->uiFont, 1.0f, 1.0f, str, availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER); if (actualWidth > availWidth) { return std::max(MIN_TEXT_SCALE, availWidth / actualWidth); } return 1.0f; } -void UIContext::DrawTextRectSqueeze(const char *str, const Bounds &bounds, uint32_t color, int align) { +void UIContext::DrawTextRectSqueeze(std::string_view str, const Bounds &bounds, uint32_t color, int align) { float origScaleX = fontScaleX_; float origScaleY = fontScaleY_; float scale = CalculateTextScale(str, bounds.w / origScaleX, bounds.h / origScaleY); @@ -311,7 +306,7 @@ void UIContext::DrawTextRectSqueeze(const char *str, const Bounds &bounds, uint3 SetFontScale(origScaleX, origScaleY); } -void UIContext::DrawTextShadowRect(const char *str, const Bounds &bounds, uint32_t color, int align) { +void UIContext::DrawTextShadowRect(std::string_view str, const Bounds &bounds, uint32_t color, int align) { uint32_t alpha = (color >> 1) & 0xFF000000; Bounds shadowBounds(bounds.x+2, bounds.y+2, bounds.w, bounds.h); DrawTextRect(str, shadowBounds, alpha, align); diff --git a/Common/UI/Context.h b/Common/UI/Context.h index b64fd1f1ad..849de045fb 100644 --- a/Common/UI/Context.h +++ b/Common/UI/Context.h @@ -82,17 +82,16 @@ public: void SetFontStyle(const UI::FontStyle &style); const UI::FontStyle &GetFontStyle() { return *fontStyle_; } void SetFontScale(float scaleX, float scaleY); - void MeasureTextCount(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, float *x, float *y, int align = 0) const; - void MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, float *x, float *y, int align = 0) const; - void MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, const Bounds &bounds, float *x, float *y, int align = 0) const; - void DrawText(const char *str, float x, float y, uint32_t color, int align = 0); - void DrawTextShadow(const char *str, float x, float y, uint32_t color, int align = 0); - void DrawTextRect(const char *str, const Bounds &bounds, uint32_t color, int align = 0); - void DrawTextShadowRect(const char *str, const Bounds &bounds, uint32_t color, int align = 0); + void MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, float *x, float *y, int align = 0) const; + void MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, float *x, float *y, int align = 0) const; + void DrawText(std::string_view str, float x, float y, uint32_t color, int align = 0); + void DrawTextShadow(std::string_view str, float x, float y, uint32_t color, int align = 0); + void DrawTextRect(std::string_view str, const Bounds &bounds, uint32_t color, int align = 0); + void DrawTextShadowRect(std::string_view str, const Bounds &bounds, uint32_t color, int align = 0); // Will squeeze the text into the bounds if needed. - void DrawTextRectSqueeze(const char *str, const Bounds &bounds, uint32_t color, int align = 0); + void DrawTextRectSqueeze(std::string_view str, const Bounds &bounds, uint32_t color, int align = 0); - float CalculateTextScale(const char *text, float availWidth, float availHeight) const; + float CalculateTextScale(std::string_view str, float availWidth, float availHeight) const; void FillRect(const UI::Drawable &drawable, const Bounds &bounds); void DrawRectDropShadow(const Bounds &bounds, float radius, float alpha, uint32_t color = 0); diff --git a/Common/UI/IconCache.cpp b/Common/UI/IconCache.cpp index 7b5bd0a8b8..125f7cc32c 100644 --- a/Common/UI/IconCache.cpp +++ b/Common/UI/IconCache.cpp @@ -242,7 +242,7 @@ bool IconCache::InsertIcon(const std::string &key, IconFormat format, std::strin if (data.empty()) { _dbg_assert_(false); - ERROR_LOG(G3D, "Can't insert empty data into icon cache"); + ERROR_LOG(Log::G3D, "Can't insert empty data into icon cache"); return false; } @@ -253,7 +253,7 @@ bool IconCache::InsertIcon(const std::string &key, IconFormat format, std::strin } if (data.size() > 1024 * 512) { - WARN_LOG(G3D, "Unusually large icon inserted in icon cache: %s (%d bytes)", key.c_str(), (int)data.size()); + WARN_LOG(Log::G3D, "Unusually large icon inserted in icon cache: %s (%d bytes)", key.c_str(), (int)data.size()); } pending_.erase(key); @@ -299,7 +299,7 @@ Draw::Texture *IconCache::BindIconTexture(UIContext *context, const std::string &height, &buffer); if (result != 1) { - ERROR_LOG(G3D, "IconCache: Failed to load png (%d bytes) for key %s", (int)iter->second.data.size(), key.c_str()); + ERROR_LOG(Log::G3D, "IconCache: Failed to load png (%d bytes) for key %s", (int)iter->second.data.size(), key.c_str()); iter->second.badData = true; return nullptr; } diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 5f0094caff..a8715591d1 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -248,9 +248,9 @@ std::string PopupSliderChoice::ValueText() const { char temp[256]; temp[0] = '\0'; if (zeroLabel_.size() && *value_ == 0) { - truncate_cpy(temp, zeroLabel_.c_str()); + truncate_cpy(temp, zeroLabel_); } else if (negativeLabel_.size() && *value_ < 0) { - truncate_cpy(temp, negativeLabel_.c_str()); + truncate_cpy(temp, negativeLabel_); } else { // Would normally be dangerous to have user-controlled format strings! // However, let's check that there's only one % sign, and that it's not followed by an S. @@ -290,7 +290,7 @@ std::string PopupSliderChoiceFloat::ValueText() const { char temp[256]; temp[0] = '\0'; if (zeroLabel_.size() && *value_ == 0.0f) { - truncate_cpy(temp, zeroLabel_.c_str()); + truncate_cpy(temp, zeroLabel_); } else if (IsValidNumberFormatString(fmt_)) { snprintf(temp, sizeof(temp), fmt_.c_str(), *value_); } else { @@ -537,6 +537,9 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) { } TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, ChopTitle(text_), maxLen_); + if (System_GetPropertyBool(SYSPROP_KEYBOARD_IS_SOFT)) { + popupScreen->SetAlignTop(true); + } popupScreen->OnChange.Handle(this, &PopupTextInputChoice::HandleChange); if (e.v) popupScreen->SetPopupOrigin(e.v); @@ -593,7 +596,7 @@ void AbstractChoiceWithValueDisplay::GetContentDimensionsBySpec(const UIContext Bounds availBounds(0, 0, availWidth, vert.size); float valueW, valueH; - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &valueW, &valueH, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText, availBounds, &valueW, &valueH, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); valueW += paddingX; // Give the choice itself less space to grow in, so it shrinks if needed. @@ -632,13 +635,13 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) { // If there is a label, assume we want at least 20% of the size for it, at a minimum. - if (!text_.empty()) { + if (!text_.empty() && !hideTitle_) { float availWidth = (bounds_.w - paddingX * 2) * 0.8f; float scale = CalculateValueScale(dc, valueText, availWidth); float w, h; Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText, availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); textPadding_.right = w + paddingX; Choice::Draw(dc); @@ -648,21 +651,21 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) { } dc.SetFontScale(scale, scale); Bounds valueBounds(bounds_.x2() - textPadding_.right - imagePadding, bounds_.y, w, bounds_.h); - dc.DrawTextRect(valueText.c_str(), valueBounds, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.DrawTextRect(valueText, valueBounds, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); dc.SetFontScale(1.0f, 1.0f); } else { Choice::Draw(dc); float scale = CalculateValueScale(dc, valueText, bounds_.w); dc.SetFontScale(scale, scale); - dc.DrawTextRect(valueText.c_str(), bounds_.Expand(-paddingX, 0.0f), style.fgColor, ALIGN_LEFT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.DrawTextRect(valueText, bounds_.Expand(-paddingX, 0.0f), style.fgColor, ALIGN_LEFT | ALIGN_VCENTER | FLAG_WRAP_TEXT); dc.SetFontScale(1.0f, 1.0f); } } -float AbstractChoiceWithValueDisplay::CalculateValueScale(const UIContext &dc, const std::string &valueText, float availWidth) const { +float AbstractChoiceWithValueDisplay::CalculateValueScale(const UIContext &dc, std::string_view valueText, float availWidth) const { float actualWidth, actualHeight; Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, valueText.c_str(), (int)valueText.size(), availBounds, &actualWidth, &actualHeight); + dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, valueText, availBounds, &actualWidth, &actualHeight); if (actualWidth > availWidth) { return std::max(0.8f, availWidth / actualWidth); } diff --git a/Common/UI/Root.cpp b/Common/UI/Root.cpp index 9bb84218bf..41dadf3d16 100644 --- a/Common/UI/Root.cpp +++ b/Common/UI/Root.cpp @@ -98,7 +98,7 @@ bool IsFocusMovementEnabled() { void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root, bool ignoreInsets) { if (!root) { - ERROR_LOG(SYSTEM, "Tried to layout a view hierarchy from a zero pointer root"); + ERROR_LOG(Log::System, "Tried to layout a view hierarchy from a zero pointer root"); return; } @@ -378,7 +378,7 @@ void UpdateViewHierarchy(ViewGroup *root) { frameCount++; if (!root) { - ERROR_LOG(SYSTEM, "Tried to update a view hierarchy from a zero pointer root"); + ERROR_LOG(Log::System, "Tried to update a view hierarchy from a zero pointer root"); return; } diff --git a/Common/UI/Screen.cpp b/Common/UI/Screen.cpp index 12c360d6f5..28943fb6a8 100644 --- a/Common/UI/Screen.cpp +++ b/Common/UI/Screen.cpp @@ -19,7 +19,7 @@ void Screen::focusChanged(ScreenFocusChange focusChange) { case ScreenFocusChange::FOCUS_LOST_TOP: eventName = "FOCUS_LOST_TOP"; break; case ScreenFocusChange::FOCUS_BECAME_TOP: eventName = "FOCUS_BECAME_TOP"; break; } - DEBUG_LOG(SYSTEM, "Screen %s got %s", this->tag(), eventName); + DEBUG_LOG(Log::System, "Screen %s got %s", this->tag(), eventName); } int Screen::GetRequesterToken() { @@ -45,7 +45,7 @@ void ScreenManager::switchScreen(Screen *screen) { // TODO: inputLock_ ? if (!nextStack_.empty() && screen == nextStack_.front().screen) { - ERROR_LOG(SYSTEM, "Already switching to this screen"); + ERROR_LOG(Log::System, "Already switching to this screen"); return; } // Note that if a dialog is found, this will be a silent background switch that @@ -53,12 +53,12 @@ void ScreenManager::switchScreen(Screen *screen) { // until that switch. // TODO: is this still true? if (!nextStack_.empty()) { - ERROR_LOG(SYSTEM, "Already had a nextStack_! Asynchronous open while doing something? Deleting the new screen."); + ERROR_LOG(Log::System, "Already had a nextStack_! Asynchronous open while doing something? Deleting the new screen."); delete screen; return; } if (screen == nullptr) { - WARN_LOG(SYSTEM, "Switching to a zero screen, this can't be good"); + WARN_LOG(Log::System, "Switching to a zero screen, this can't be good"); } if (stack_.empty() || screen != stack_.back().screen) { screen->setScreenManager(this); @@ -85,7 +85,7 @@ void ScreenManager::update() { void ScreenManager::switchToNext() { std::lock_guard guard(inputLock_); if (nextStack_.empty()) { - ERROR_LOG(SYSTEM, "switchToNext: No nextStack_!"); + ERROR_LOG(Log::System, "switchToNext: No nextStack_!"); } Layer temp = {nullptr, 0}; @@ -161,7 +161,7 @@ void ScreenManager::deviceRestored() { } void ScreenManager::resized() { - INFO_LOG(SYSTEM, "ScreenManager::resized(dp: %dx%d)", g_display.dp_xres, g_display.dp_yres); + INFO_LOG(Log::System, "ScreenManager::resized(dp: %dx%d)", g_display.dp_xres, g_display.dp_yres); std::lock_guard guard(inputLock_); // Have to notify the whole stack, otherwise there will be problems when going back // to non-top screens. @@ -185,9 +185,11 @@ ScreenRenderFlags ScreenManager::render() { Screen *coveringScreen = nullptr; Screen *foundBackgroundScreen = nullptr; bool first = true; + do { --iter; - if (!foundBackgroundScreen && iter->screen->canBeBackground(first)) { + ScreenRenderRole role = iter->screen->renderRole(first); + if (!foundBackgroundScreen && (role & ScreenRenderRole::CAN_BE_BACKGROUND)) { // There still might be a screen that wants to be background - generally the EmuScreen if present. layers.push_back(iter->screen); foundBackgroundScreen = iter->screen; @@ -198,6 +200,9 @@ ScreenRenderFlags ScreenManager::render() { coveringScreen = iter->screen; } first = false; + if (role & ScreenRenderRole::MUST_BE_FIRST) { + break; + } } while (iter != stack_.begin()); if (backgroundScreen_ && !foundBackgroundScreen) { @@ -234,7 +239,7 @@ ScreenRenderFlags ScreenManager::render() { postRenderCb_(getUIContext(), postRenderUserdata_); } } else { - ERROR_LOG(SYSTEM, "No current screen!"); + ERROR_LOG(Log::System, "No current screen!"); } processFinishDialog(); @@ -329,7 +334,7 @@ void ScreenManager::pop() { stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); } } else { - ERROR_LOG(SYSTEM, "Can't pop when stack empty"); + ERROR_LOG(Log::System, "Can't pop when stack empty"); } } @@ -342,11 +347,11 @@ void ScreenManager::RecreateAllViews() { void ScreenManager::finishDialog(Screen *dialog, DialogResult result) { if (stack_.empty()) { - ERROR_LOG(SYSTEM, "Must be in a dialog to finishDialog"); + ERROR_LOG(Log::System, "Must be in a dialog to finishDialog"); return; } if (dialog != stack_.back().screen) { - ERROR_LOG(SYSTEM, "Wrong dialog being finished!"); + ERROR_LOG(Log::System, "Wrong dialog being finished!"); return; } dialog->onFinish(result); @@ -385,10 +390,10 @@ void ScreenManager::processFinishDialog() { } if (!caller) { - ERROR_LOG(SYSTEM, "ERROR: no top screen when finishing dialog"); + ERROR_LOG(Log::System, "ERROR: no top screen when finishing dialog"); } else if (caller != topScreen()) { // The caller may get confused if we call dialogFinished() now. - WARN_LOG(SYSTEM, "Skipping non-top dialog when finishing dialog."); + WARN_LOG(Log::System, "Skipping non-top dialog when finishing dialog."); } else { caller->dialogFinished(dialogFinished_, dialogResult_); } diff --git a/Common/UI/Screen.h b/Common/UI/Screen.h index de40bae684..8b015c925a 100644 --- a/Common/UI/Screen.h +++ b/Common/UI/Screen.h @@ -61,6 +61,14 @@ enum class ScreenRenderFlags { }; ENUM_CLASS_BITOPS(ScreenRenderFlags); + +enum class ScreenRenderRole { + NONE = 0, + CAN_BE_BACKGROUND = 1, + MUST_BE_FIRST = 2, +}; +ENUM_CLASS_BITOPS(ScreenRenderRole); + class Screen { public: Screen() : screenManager_(nullptr) { } @@ -74,7 +82,7 @@ public: virtual void sendMessage(UIMessage message, const char *value) {} virtual void deviceLost() {} virtual void deviceRestored() {} - virtual bool canBeBackground(bool isTop) const { return false; } + virtual ScreenRenderRole renderRole(bool isTop) const { return ScreenRenderRole::NONE; } virtual bool wantBrightBackground() const { return false; } // special hack for DisplayLayoutScreen. virtual void focusChanged(ScreenFocusChange focusChange); diff --git a/Common/UI/ScrollView.cpp b/Common/UI/ScrollView.cpp index 728bbc7278..c18566d518 100644 --- a/Common/UI/ScrollView.cpp +++ b/Common/UI/ScrollView.cpp @@ -288,7 +288,7 @@ bool ScrollView::SubviewFocused(View *view) { return true; } -NeighborResult ScrollView::FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) { +NeighborResult ScrollView::FindScrollNeighbor(View *view, const Point2D &target, FocusDirection direction, NeighborResult best) { if (ContainsSubview(view) && views_[0]->IsViewGroup()) { ViewGroup *vg = static_cast(views_[0]); int found = -1; @@ -315,7 +315,7 @@ NeighborResult ScrollView::FindScrollNeighbor(View *view, const Point &target, F } // Okay, now where is our ideal target? - Point targetPos = view->GetBounds().Center(); + Point2D targetPos = view->GetBounds().Center(); if (orientation_ == ORIENT_VERTICAL) targetPos.y += mult * bounds_.h; else diff --git a/Common/UI/ScrollView.h b/Common/UI/ScrollView.h index a5c31a2feb..99c7304e56 100644 --- a/Common/UI/ScrollView.h +++ b/Common/UI/ScrollView.h @@ -44,7 +44,7 @@ public: alignOpposite_ = alignOpposite; } - NeighborResult FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) override; + NeighborResult FindScrollNeighbor(View *view, const Point2D &target, FocusDirection direction, NeighborResult best) override; private: float HardClampedScrollPos(float pos) const; diff --git a/Common/UI/Tween.cpp b/Common/UI/Tween.cpp index bbe819e915..bf7e29026e 100644 --- a/Common/UI/Tween.cpp +++ b/Common/UI/Tween.cpp @@ -67,7 +67,7 @@ void TweenBase::PersistData(PersistStatus status, std::string anonId, Per template void TweenBase::PersistData(PersistStatus status, std::string anonId, PersistMap &storage); template void TweenBase::PersistData(PersistStatus status, std::string anonId, PersistMap &storage); -template void TweenBase::PersistData(PersistStatus status, std::string anonId, PersistMap &storage); +template void TweenBase::PersistData(PersistStatus status, std::string anonId, PersistMap &storage); uint32_t ColorTween::Current(float pos) { return colorBlend(to_, from_, pos); @@ -99,7 +99,7 @@ Visibility VisibilityTween::Current(float p) { } void AnchorTranslateTween::DoApply(View *view, float pos) { - Point cur = Current(pos); + Point2D cur = Current(pos); auto prev = view->GetLayoutParams()->As(); auto lp = new AnchorLayoutParams(prev ? *prev : AnchorLayoutParams(FILL_PARENT, FILL_PARENT)); @@ -108,9 +108,9 @@ void AnchorTranslateTween::DoApply(View *view, float pos) { view->ReplaceLayoutParams(lp); } -Point AnchorTranslateTween::Current(float p) { +Point2D AnchorTranslateTween::Current(float p) { float inv = 1.0f - p; - return Point(from_.x * inv + to_.x * p, from_.y * inv + to_.y * p); + return Point2D(from_.x * inv + to_.x * p, from_.y * inv + to_.y * p); } } // namespace diff --git a/Common/UI/Tween.h b/Common/UI/Tween.h index 2786963d55..c3e4c1181e 100644 --- a/Common/UI/Tween.h +++ b/Common/UI/Tween.h @@ -182,14 +182,14 @@ protected: Visibility Current(float pos) override; }; -class AnchorTranslateTween : public TweenBase { +class AnchorTranslateTween : public TweenBase { public: using TweenBase::TweenBase; protected: void DoApply(View *view, float pos) override; - Point Current(float pos) override; + Point2D Current(float pos) override; }; } // namespace diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index 9f8338ec93..8e9a793a1f 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -84,11 +84,11 @@ bool UIScreen::key(const KeyInput &key) { bool UIScreen::UnsyncTouch(const TouchInput &touch) { if (ClickDebug && root_ && (touch.flags & TOUCH_DOWN)) { - INFO_LOG(SYSTEM, "Touch down!"); + INFO_LOG(Log::System, "Touch down!"); std::vector views; root_->Query(touch.x, touch.y, views); for (auto view : views) { - INFO_LOG(SYSTEM, "%s", view->DescribeLog().c_str()); + INFO_LOG(Log::System, "%s", view->DescribeLog().c_str()); } } @@ -167,11 +167,11 @@ void UIScreen::update() { break; case QueuedEventType::TOUCH: if (ClickDebug && (ev.touch.flags & TOUCH_DOWN)) { - INFO_LOG(SYSTEM, "Touch down!"); + INFO_LOG(Log::System, "Touch down!"); std::vector views; root_->Query(ev.touch.x, ev.touch.y, views); for (auto view : views) { - INFO_LOG(SYSTEM, "%s", view->DescribeLog().c_str()); + INFO_LOG(Log::System, "%s", view->DescribeLog().c_str()); } } touch(ev.touch); @@ -262,7 +262,7 @@ bool UIDialogScreen::key(const KeyInput &key) { bool retval = UIScreen::key(key); if (!retval && (key.flags & KEY_DOWN) && UI::IsEscapeKey(key)) { if (finished_) { - ERROR_LOG(SYSTEM, "Screen already finished"); + ERROR_LOG(Log::System, "Screen already finished"); } else { finished_ = true; TriggerFinish(DR_BACK); @@ -385,10 +385,6 @@ void PopupScreen::SetPopupOrigin(const UI::View *view) { popupOrigin_ = view->GetBounds().Center(); } -void PopupScreen::SetPopupOffset(float y) { - offsetY_ = y; -} - void PopupScreen::TriggerFinish(DialogResult result) { if (CanComplete(result)) { ignoreInput_ = true; @@ -398,7 +394,7 @@ void PopupScreen::TriggerFinish(DialogResult result) { OnCompleted(result); } // Inform UI that popup close to hide OSK (if visible) - System_NotifyUIState("popup_closed"); + System_NotifyUIEvent(UIEventNotification::POPUP_CLOSED); } void PopupScreen::CreateViews() { @@ -411,8 +407,18 @@ void PopupScreen::CreateViews() { float yres = screenManager()->getUIContext()->GetBounds().h; - box_ = new LinearLayout(ORIENT_VERTICAL, - new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, dc.GetBounds().centerX(), dc.GetBounds().centerY() + offsetY_, NONE, NONE, true)); + AnchorLayoutParams *anchorParams; + if (!alignTop_) { + // Standard centering etc. + anchorParams = new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, + dc.GetBounds().centerX(), dc.GetBounds().centerY() + offsetY_, NONE, NONE, true); + } else { + // Top-aligned, for dialogs where we need to pop a keyboard below. + anchorParams = new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, + NONE, 0, NONE, NONE, false); + } + + box_ = new LinearLayout(ORIENT_VERTICAL, anchorParams); root_->Add(box_); box_->SetBG(dc.theme->popupStyle.background); diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index 12c71cb831..2918d2676e 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -108,7 +108,9 @@ public: void TriggerFinish(DialogResult result) override; void SetPopupOrigin(const UI::View *view); - void SetPopupOffset(float y); + void SetPopupOffset(float y) { offsetY_ = y; } + + void SetAlignTop(bool alignTop) { alignTop_ = alignTop; } void SetHasDropShadow(bool has) { hasDropShadow_ = has; } @@ -142,8 +144,9 @@ private: int finishFrame_ = -1; DialogResult finishResult_ = DR_CANCEL; bool hasPopupOrigin_ = false; - Point popupOrigin_; + Point2D popupOrigin_; float offsetY_ = 0.0f; + bool alignTop_ = false; bool hasDropShadow_ = true; }; diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 18c573fcb2..09084b0516 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -168,25 +168,25 @@ void View::PersistData(PersistStatus status, std::string anonId, PersistMap &sto } } -Point View::GetFocusPosition(FocusDirection dir) const { +Point2D View::GetFocusPosition(FocusDirection dir) const { // The +2/-2 is some extra fudge factor to cover for views sitting right next to each other. // Distance zero yields strange results otherwise. switch (dir) { - case FOCUS_LEFT: return Point(bounds_.x + 2, bounds_.centerY()); - case FOCUS_RIGHT: return Point(bounds_.x2() - 2, bounds_.centerY()); - case FOCUS_UP: return Point(bounds_.centerX(), bounds_.y + 2); - case FOCUS_DOWN: return Point(bounds_.centerX(), bounds_.y2() - 2); + case FOCUS_LEFT: return Point2D(bounds_.x + 2, bounds_.centerY()); + case FOCUS_RIGHT: return Point2D(bounds_.x2() - 2, bounds_.centerY()); + case FOCUS_UP: return Point2D(bounds_.centerX(), bounds_.y + 2); + case FOCUS_DOWN: return Point2D(bounds_.centerX(), bounds_.y2() - 2); default: return bounds_.Center(); } } -Point CollapsibleHeader::GetFocusPosition(FocusDirection dir) const { +Point2D CollapsibleHeader::GetFocusPosition(FocusDirection dir) const { // Bias the focus position to the left. switch (dir) { - case FOCUS_UP: return Point(bounds_.x + 50, bounds_.y + 2); - case FOCUS_DOWN: return Point(bounds_.x + 50, bounds_.y2() - 2); + case FOCUS_UP: return Point2D(bounds_.x + 50, bounds_.y + 2); + case FOCUS_DOWN: return Point2D(bounds_.x + 50, bounds_.y2() - 2); default: return View::GetFocusPosition(dir); } @@ -483,10 +483,10 @@ void Choice::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, } if (horiz.type != EXACTLY && layoutParams_->width > 0.0f && availWidth > layoutParams_->width) availWidth = layoutParams_->width; - float scale = dc.CalculateTextScale(text_.c_str(), availWidth, bounds_.h); + float scale = dc.CalculateTextScale(text_, availWidth, bounds_.h); Bounds availBounds(0, 0, availWidth, vert.size); float textW = 0.0f, textH = 0.0f; - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &textW, &textH, FLAG_WRAP_TEXT); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_, availBounds, &textW, &textH, FLAG_WRAP_TEXT); totalH = std::max(totalH, textH); totalW += textW; } @@ -506,7 +506,7 @@ void Choice::Draw(UIContext &dc) { if (image_.isValid() && text_.empty()) { dc.Draw()->DrawImageRotated(image_, bounds_.centerX(), bounds_.centerY(), imgScale_, imgRot_, style.fgColor, imgFlipH_); - } else if (!text_.empty()) { + } else if (!text_.empty() && !hideTitle_) { dc.SetFontStyle(dc.theme->uiFont); int paddingX = 12; @@ -524,14 +524,14 @@ void Choice::Draw(UIContext &dc) { } if (centered_) { - dc.DrawTextRectSqueeze(text_.c_str(), bounds_, style.fgColor, ALIGN_CENTER | FLAG_WRAP_TEXT | drawTextFlags_); + dc.DrawTextRectSqueeze(text_, bounds_, style.fgColor, ALIGN_CENTER | FLAG_WRAP_TEXT | drawTextFlags_); } else { if (rightIconImage_.isValid()) { uint32_t col = rightIconKeepColor_ ? 0xffffffff : style.fgColor; // Don't apply theme to gold icon dc.Draw()->DrawImageRotated(rightIconImage_, bounds_.x2() - 32 - paddingX, bounds_.centerY(), rightIconScale_, rightIconRot_, col, rightIconFlipH_); } Bounds textBounds(bounds_.x + paddingX + textPadding_.left, bounds_.y, availWidth, bounds_.h); - dc.DrawTextRectSqueeze(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT | drawTextFlags_); + dc.DrawTextRectSqueeze(text_, textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT | drawTextFlags_); } dc.SetFontScale(1.0f, 1.0f); } @@ -580,13 +580,13 @@ void InfoItem::Draw(UIContext &dc) { Bounds padBounds = bounds_.Expand(-paddingX, 0); float leftWidth, leftHeight; - dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), (int)text_.size(), padBounds, &leftWidth, &leftHeight, ALIGN_VCENTER); + dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, text_, padBounds, &leftWidth, &leftHeight, ALIGN_VCENTER); dc.SetFontStyle(dc.theme->uiFont); - dc.DrawTextRect(text_.c_str(), padBounds, style.fgColor, ALIGN_VCENTER); + dc.DrawTextRect(text_, padBounds, style.fgColor, ALIGN_VCENTER); Bounds rightBounds(padBounds.x + leftWidth, padBounds.y, padBounds.w - leftWidth, padBounds.h); - dc.DrawTextRect(rightText_.c_str(), rightBounds, style.fgColor, ALIGN_VCENTER | ALIGN_RIGHT | FLAG_WRAP_TEXT); + dc.DrawTextRect(rightText_, rightBounds, style.fgColor, ALIGN_VCENTER | ALIGN_RIGHT | FLAG_WRAP_TEXT); } std::string InfoItem::DescribeText() const { @@ -602,7 +602,7 @@ ItemHeader::ItemHeader(std::string_view text, LayoutParams *layoutParams) void ItemHeader::Draw(UIContext &dc) { dc.SetFontStyle(large_ ? dc.theme->uiFont : dc.theme->uiFontSmall); - dc.DrawText(text_.c_str(), bounds_.x + 4, bounds_.centerY(), dc.theme->headerStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); + dc.DrawText(text_, bounds_.x + 4, bounds_.centerY(), dc.theme->headerStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); dc.Draw()->DrawImageCenterTexel(dc.theme->whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.theme->headerStyle.fgColor); } @@ -616,7 +616,7 @@ void ItemHeader::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec hor bounds.h = vert.size == 0 ? MAX_ITEM_SIZE : vert.size; } ApplyBoundsBySpec(bounds, horiz, vert); - dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_.c_str(), (int)text_.length(), bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); + dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_, bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); } std::string ItemHeader::DescribeText() const { @@ -641,7 +641,7 @@ void CollapsibleHeader::Draw(UIContext &dc) { float xoff = 37.0f; dc.SetFontStyle(dc.theme->uiFontSmall); - dc.DrawText(text_.c_str(), bounds_.x + 4 + xoff, bounds_.centerY(), dc.theme->headerStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); + dc.DrawText(text_, bounds_.x + 4 + xoff, bounds_.centerY(), dc.theme->headerStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); dc.Draw()->DrawImageCenterTexel(dc.theme->whiteImage, bounds_.x, bounds_.y2() - 2, bounds_.x2(), bounds_.y2(), dc.theme->headerStyle.fgColor); if (hasSubItems_) { dc.Draw()->DrawImageRotated(ImageID("I_ARROW"), bounds_.x + 20.0f, bounds_.y + 20.0f, 1.0f, *toggle_ ? -M_PI / 2 : M_PI); @@ -658,7 +658,7 @@ void CollapsibleHeader::GetContentDimensionsBySpec(const UIContext &dc, MeasureS bounds.h = vert.size == 0 ? MAX_ITEM_SIZE : vert.size; } ApplyBoundsBySpec(bounds, horiz, vert); - dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_.c_str(), (int)text_.length(), bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); + dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_, bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); } void CollapsibleHeader::GetContentDimensions(const UIContext &dc, float &w, float &h) const { @@ -703,7 +703,7 @@ void PopupHeader::Draw(UIContext &dc) { float tw, th; dc.SetFontStyle(dc.theme->uiFont); - dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text_.c_str(), &tw, &th, 0); + dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text_, &tw, &th, 0); float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f; @@ -717,7 +717,7 @@ void PopupHeader::Draw(UIContext &dc) { dc.PushScissor(tb); } - dc.DrawText(text_.c_str(), bounds_.x + tx, bounds_.centerY(), dc.theme->itemStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); + dc.DrawText(text_, bounds_.x + tx, bounds_.centerY(), dc.theme->itemStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); dc.Draw()->DrawImageCenterTexel(dc.theme->whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.theme->itemStyle.fgColor); if (availableWidth < tw) { @@ -798,7 +798,7 @@ void CheckBox::Draw(UIContext &dc) { if (!text_.empty()) { Bounds textBounds(bounds_.x + paddingX, bounds_.y, availWidth, bounds_.h); - dc.DrawTextRectSqueeze(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.DrawTextRectSqueeze(text_, textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT); } dc.Draw()->DrawImage(image, bounds_.x2() - paddingX, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); dc.SetFontScale(1.0f, 1.0f); @@ -840,11 +840,11 @@ void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) con } if (!text_.empty()) { - float scale = dc.CalculateTextScale(text_.c_str(), availWidth, bounds_.h); + float scale = dc.CalculateTextScale(text_, availWidth, bounds_.h); float actualWidth, actualHeight; Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_, availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT); h = std::max(actualHeight, ITEM_HEIGHT); } else { h = std::max(imageH, ITEM_HEIGHT); @@ -852,6 +852,11 @@ void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) con w = bounds_.w; } +BitCheckBox::BitCheckBox(uint32_t *bitfield, uint32_t bit, std::string_view text, std::string_view smallText, LayoutParams *layoutParams) + : CheckBox(nullptr, text, smallText, layoutParams), bitfield_(bitfield), bit_(bit) { + _dbg_assert_msg_(bit != 0, "bit is a mask, not a bit index"); +} + void BitCheckBox::Toggle() { if (bitfield_) { *bitfield_ = *bitfield_ ^ bit_; @@ -880,7 +885,7 @@ void Button::GetContentDimensions(const UIContext &dc, float &w, float &h) const if (!text_.empty() && !ignoreText_) { float width = 0.0f; float height = 0.0f; - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &width, &height); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_, &width, &height); w += width; if (imageID_.isValid()) { @@ -917,7 +922,7 @@ void Button::Draw(UIContext &dc) { // dc.Draw()->DrawImage4Grid(style.image, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), style.bgColor); DrawBG(dc, style); float tw, th; - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &tw, &th); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_, &tw, &th); tw *= scale_; th *= scale_; @@ -937,7 +942,7 @@ void Button::Draw(UIContext &dc) { textX += img->w / 2.0f; } } - dc.DrawText(text_.c_str(), textX, bounds_.centerY(), style.fgColor, ALIGN_CENTER); + dc.DrawText(text_, textX, bounds_.centerY(), style.fgColor, ALIGN_CENTER); } dc.SetFontScale(1.0f, 1.0f); @@ -951,7 +956,7 @@ void RadioButton::GetContentDimensions(const UIContext &dc, float &w, float &h) h = 0.0f; if (!text_.empty()) { - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &w, &h); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_, &w, &h); } // Add some internal padding to not look totally ugly @@ -991,7 +996,7 @@ void RadioButton::Draw(UIContext &dc) { dc.Begin(); float tw, th; - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &tw, &th); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_, &tw, &th); if (tw > bounds_.w) { dc.PushScissor(bounds_); @@ -1001,7 +1006,7 @@ void RadioButton::Draw(UIContext &dc) { if (!text_.empty()) { float textX = bounds_.x + paddingW_ * 2.0f + radioRadius_ * 2.0f; - dc.DrawText(text_.c_str(), textX, bounds_.centerY(), style.fgColor, ALIGN_LEFT | ALIGN_VCENTER); + dc.DrawText(text_, textX, bounds_.centerY(), style.fgColor, ALIGN_LEFT | ALIGN_VCENTER); } if (tw > bounds_.w) { @@ -1038,7 +1043,13 @@ void TextView::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz if (bullet_) { bounds.w -= bulletOffset; } - dc.MeasureTextRect(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), (int)text_.length(), bounds, &w, &h, textAlign_); + const FontStyle *style = &dc.theme->uiFont; + if (small_) { + style = &dc.theme->uiFontSmall; + } else if (big_) { + style = &dc.theme->uiFontBig; + } + dc.MeasureTextRect(*style, 1.0f, 1.0f, text_, bounds, &w, &h, textAlign_); w += pad_ * 2.0f; h += pad_ * 2.0f; if (bullet_) { @@ -1069,7 +1080,13 @@ void TextView::Draw(UIContext &dc) { style.background.color &= 0x7fffffff; dc.FillRect(style.background, bounds_); } - dc.SetFontStyle(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont); + const FontStyle *style = &dc.theme->uiFont; + if (small_) { + style = &dc.theme->uiFontSmall; + } else if (big_) { + style = &dc.theme->uiFontBig; + } + dc.SetFontStyle(*style); Bounds textBounds = bounds_; @@ -1086,10 +1103,10 @@ void TextView::Draw(UIContext &dc) { if (shadow_) { uint32_t shadowColor = 0x80000000; - dc.DrawTextRect(text_.c_str(), textBounds.Offset(1.0f + pad_, 1.0f + pad_), shadowColor, textAlign_); + dc.DrawTextRect(text_, textBounds.Offset(1.0f + pad_, 1.0f + pad_), shadowColor, textAlign_); } - dc.DrawTextRect(text_.c_str(), textBounds.Offset(pad_, pad_), textColor, textAlign_); - if (small_) { + dc.DrawTextRect(text_, textBounds.Offset(pad_, pad_), textColor, textAlign_); + if (small_ || big_) { // If we changed font style, reset it. dc.SetFontStyle(dc.theme->uiFont); } @@ -1105,14 +1122,12 @@ TextEdit::TextEdit(std::string_view text, std::string_view title, std::string_vi } void TextEdit::FocusChanged(int focusFlags) { -#if PPSSPP_PLATFORM(UWP) if (focusFlags == FF_GOTFOCUS) { - System_NotifyUIState("text_gotfocus"); + System_NotifyUIEvent(UIEventNotification::TEXT_GOTFOCUS); } else { - System_NotifyUIState("text_lostfocus"); + System_NotifyUIEvent(UIEventNotification::TEXT_LOSTFOCUS); } -#endif } void TextEdit::Draw(UIContext &dc) { @@ -1130,15 +1145,15 @@ void TextEdit::Draw(UIContext &dc) { if (text_.empty()) { if (placeholderText_.size()) { uint32_t c = textColor & 0x50FFFFFF; - dc.DrawTextRect(placeholderText_.c_str(), bounds_, c, ALIGN_CENTER); + dc.DrawTextRect(placeholderText_, bounds_, c, ALIGN_CENTER); } } else { - dc.DrawTextRect(text_.c_str(), textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_); + dc.DrawTextRect(text_, textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_); } if (HasFocus()) { // Hack to find the caret position. Might want to find a better way... - dc.MeasureTextCount(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.substr(0, caret_), &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_); float caretX = w - scrollPos_; if (caretX > bounds_.w) { scrollPos_ += caretX - bounds_.w; @@ -1153,7 +1168,7 @@ void TextEdit::Draw(UIContext &dc) { } void TextEdit::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, !text_.empty() ? text_.c_str() : "Wj", &w, &h, align_); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, !text_.empty() ? text_ : "Wj", &w, &h, align_); w += 2; h += 2; } diff --git a/Common/UI/View.h b/Common/UI/View.h index 2372d1ad06..e38c0fc819 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -93,7 +93,7 @@ struct FontStyle { struct Theme { FontStyle uiFont; FontStyle uiFontSmall; - FontStyle uiFontSmaller; + FontStyle uiFontBig; ImageID checkOn; ImageID checkOff; @@ -462,13 +462,13 @@ public: Visibility GetVisibility() const { return visibility_; } const std::string &Tag() const { return tag_; } - void SetTag(const std::string &str) { tag_ = str; } + void SetTag(std::string_view str) { tag_ = str; } // Fake RTTI virtual bool IsViewGroup() const { return false; } virtual bool ContainsSubview(const View *view) const { return false; } - virtual Point GetFocusPosition(FocusDirection dir) const; + virtual Point2D GetFocusPosition(FocusDirection dir) const; template T *AddTween(T *t) { @@ -732,6 +732,10 @@ public: rightIconFlipH_ = flipH; rightIconImage_ = iconImage; } + // Only useful for things that extend Choice. + void SetHideTitle(bool hide) { + hideTitle_ = hide; + } protected: // hackery @@ -751,6 +755,7 @@ protected: float imgRot_ = 0.0f; bool imgFlipH_ = false; u32 drawTextFlags_ = 0; + bool hideTitle_ = false; private: bool selected_ = false; @@ -822,11 +827,10 @@ public: void SetPasswordDisplay() { passwordDisplay_ = true; } - protected: virtual std::string ValueText() const = 0; - float CalculateValueScale(const UIContext &dc, const std::string &valueText, float availWidth) const; + float CalculateValueScale(const UIContext &dc, std::string_view valueText, float availWidth) const; bool passwordDisplay_ = false; }; @@ -904,7 +908,7 @@ public: void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; - Point GetFocusPosition(FocusDirection dir) const override; + Point2D GetFocusPosition(FocusDirection dir) const override; void SetHasSubitems(bool hasSubItems) { hasSubItems_ = hasSubItems; } void SetOpenPtr(bool *open) { @@ -916,10 +920,8 @@ private: class BitCheckBox : public CheckBox { public: - BitCheckBox(uint32_t *bitfield, uint32_t bit, std::string_view text, std::string_view smallText = "", LayoutParams *layoutParams = nullptr) - : CheckBox(nullptr, text, smallText, layoutParams), bitfield_(bitfield), bit_(bit) { - } - + // bit is a bitmask (should only have a single bit set), not a bit index. + BitCheckBox(uint32_t *bitfield, uint32_t bit, std::string_view text, std::string_view smallText = "", LayoutParams *layoutParams = nullptr); BitCheckBox(int *bitfield, int bit, std::string_view text, std::string_view smallText = "", LayoutParams *layoutParams = nullptr) : BitCheckBox((uint32_t *)bitfield, (uint32_t)bit, text, smallText, layoutParams) {} void Toggle() override; @@ -980,10 +982,10 @@ private: class TextView : public InertView { public: TextView(std::string_view text, LayoutParams *layoutParams = 0) - : InertView(layoutParams), text_(text), textAlign_(0), textColor_(0xFFFFFFFF), small_(false), shadow_(false), focusable_(false), clip_(true) {} + : InertView(layoutParams), text_(text), textAlign_(0), textColor_(0xFFFFFFFF), small_(false) {} TextView(std::string_view text, int textAlign, bool small, LayoutParams *layoutParams = 0) - : InertView(layoutParams), text_(text), textAlign_(textAlign), textColor_(0xFFFFFFFF), small_(small), shadow_(false), focusable_(false), clip_(true) {} + : InertView(layoutParams), text_(text), textAlign_(textAlign), textColor_(0xFFFFFFFF), small_(small) {} void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; void Draw(UIContext &dc) override; @@ -992,6 +994,7 @@ public: const std::string &GetText() const { return text_; } std::string DescribeText() const override { return GetText(); } void SetSmall(bool small) { small_ = small; } + void SetBig(bool big) { big_ = big; } void SetTextColor(uint32_t color) { textColor_ = color; hasTextColor_ = true; } void SetShadow(bool shadow) { shadow_ = shadow; } void SetFocusable(bool focusable) { focusable_ = focusable; } @@ -1007,9 +1010,10 @@ private: uint32_t textColor_; bool hasTextColor_ = false; bool small_; - bool shadow_; - bool focusable_; - bool clip_; + bool big_ = false; + bool shadow_ = false; + bool focusable_ = false; + bool clip_ = true; bool bullet_ = false; float pad_ = 0.0f; }; diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 45797d30ce..d85406201c 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -67,6 +67,16 @@ bool ViewGroup::ContainsSubview(const View *view) const { return false; } +int ViewGroup::IndexOfSubview(const View *view) const { + int index = 0; + for (const View *subview : views_) { + if (subview == view) + return index; + index++; + } + return -1; +} + void ViewGroup::Clear() { for (View *view : views_) { delete view; @@ -284,7 +294,7 @@ static float VerticalOverlap(const Bounds &a, const Bounds &b) { return std::min(1.0f, overlap / minH); } -float GetTargetScore(const Point &originPos, int originIndex, const View *origin, const View *destination, FocusDirection direction) { +float GetTargetScore(const Point2D &originPos, int originIndex, const View *origin, const View *destination, FocusDirection direction) { // Skip labels and things like that. if (!destination->CanBeFocused()) return 0.0f; @@ -293,7 +303,7 @@ float GetTargetScore(const Point &originPos, int originIndex, const View *origin if (destination->GetVisibility() != V_VISIBLE) return 0.0f; - Point destPos = destination->GetFocusPosition(Opposite(direction)); + Point2D destPos = destination->GetFocusPosition(Opposite(direction)); float dx = destPos.x - originPos.x; float dy = destPos.y - originPos.y; @@ -312,7 +322,7 @@ float GetTargetScore(const Point &originPos, int originIndex, const View *origin float vertOverlap = VerticalOverlap(origin->GetBounds(), destination->GetBounds()); if (horizOverlap == 1.0f && vertOverlap == 1.0f) { if (direction != FOCUS_PREV_PAGE && direction != FOCUS_NEXT_PAGE) { - INFO_LOG(SYSTEM, "Contain overlap"); + INFO_LOG(Log::System, "Contain overlap"); return 0.0; } } @@ -369,7 +379,7 @@ float GetTargetScore(const Point &originPos, int originIndex, const View *origin break; case FOCUS_PREV: case FOCUS_NEXT: - ERROR_LOG(SYSTEM, "Invalid focus direction"); + ERROR_LOG(Log::System, "Invalid focus direction"); break; } @@ -385,13 +395,13 @@ float GetTargetScore(const Point &originPos, int originIndex, const View *origin } static float GetDirectionScore(int originIndex, const View *origin, View *destination, FocusDirection direction) { - Point originPos = origin->GetFocusPosition(direction); + Point2D originPos = origin->GetFocusPosition(direction); return GetTargetScore(originPos, originIndex, origin, destination, direction); } NeighborResult ViewGroup::FindNeighbor(View *view, FocusDirection direction, NeighborResult result) { if (!IsEnabled()) { - INFO_LOG(SCECTRL, "Not enabled"); + INFO_LOG(Log::sceCtrl, "Not enabled"); return result; } if (GetVisibility() != V_VISIBLE) { @@ -444,7 +454,7 @@ NeighborResult ViewGroup::FindNeighbor(View *view, FocusDirection direction, Nei } case FOCUS_PREV_PAGE: case FOCUS_NEXT_PAGE: - return FindScrollNeighbor(view, Point(INFINITY, INFINITY), direction, result); + return FindScrollNeighbor(view, Point2D(INFINITY, INFINITY), direction, result); case FOCUS_PREV: // If view not found, no neighbor to find. if (num == -1) @@ -457,12 +467,12 @@ NeighborResult ViewGroup::FindNeighbor(View *view, FocusDirection direction, Nei return NeighborResult(views_[(num + 1) % views_.size()], 0.0f); default: - ERROR_LOG(SYSTEM, "Bad focus direction %d", (int)direction); + ERROR_LOG(Log::System, "Bad focus direction %d", (int)direction); return result; } } -NeighborResult ViewGroup::FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) { +NeighborResult ViewGroup::FindScrollNeighbor(View *view, const Point2D &target, FocusDirection direction, NeighborResult best) { if (!IsEnabled()) return best; if (GetVisibility() != V_VISIBLE) @@ -872,7 +882,7 @@ void AnchorLayout::Layout() { GridLayout::GridLayout(GridLayoutSettings settings, LayoutParams *layoutParams) : ViewGroup(layoutParams), settings_(settings) { if (settings.orientation != ORIENT_HORIZONTAL) - ERROR_LOG(SYSTEM, "GridLayout: Vertical layouts not yet supported"); + ERROR_LOG(Log::System, "GridLayout: Vertical layouts not yet supported"); } void GridLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) { @@ -1015,21 +1025,21 @@ void TabHolder::SetCurrentTab(int tab, bool skipTween) { // Currently displayed, so let's reset it. if (skipTween) { tabs_[currentTab_]->SetVisibility(V_GONE); - tabTweens_[tab]->Reset(Point(0.0f, 0.0f)); + tabTweens_[tab]->Reset(Point2D(0.0f, 0.0f)); tabTweens_[tab]->Apply(tabs_[tab]); } else { - tabTweens_[currentTab_]->Reset(Point(0.0f, 0.0f)); + tabTweens_[currentTab_]->Reset(Point2D(0.0f, 0.0f)); if (orient == ORIENT_HORIZONTAL) { - tabTweens_[tab]->Reset(Point(bounds_.w * dir, 0.0f)); - tabTweens_[currentTab_]->Divert(Point(bounds_.w * -dir, 0.0f)); + tabTweens_[tab]->Reset(Point2D(bounds_.w * dir, 0.0f)); + tabTweens_[currentTab_]->Divert(Point2D(bounds_.w * -dir, 0.0f)); } else { - tabTweens_[tab]->Reset(Point(0.0f, bounds_.h * dir)); - tabTweens_[currentTab_]->Divert(Point(0.0f, bounds_.h * -dir)); + tabTweens_[tab]->Reset(Point2D(0.0f, bounds_.h * dir)); + tabTweens_[currentTab_]->Divert(Point2D(0.0f, bounds_.h * -dir)); } // Actually move it to the initial position now, just to avoid any flicker. tabTweens_[tab]->Apply(tabs_[tab]); - tabTweens_[tab]->Divert(Point(0.0f, 0.0f)); + tabTweens_[tab]->Divert(Point2D(0.0f, 0.0f)); } tabs_[tab]->SetVisibility(V_VISIBLE); @@ -1194,8 +1204,10 @@ void CollapsibleSection::Update() { } void CollapsibleSection::UpdateVisibility() { + const bool open = *open_; + // Skipping over the header, we start from 1, not 0. for (size_t i = 1; i < views_.size(); i++) { - views_[i]->SetVisibility(*open_ ? V_VISIBLE : V_GONE); + views_[i]->SetVisibility(open ? V_VISIBLE : V_GONE); } } diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index c5f3d9208d..da2e4e5fd0 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -60,11 +60,12 @@ public: // Assumes that layout has taken place. NeighborResult FindNeighbor(View *view, FocusDirection direction, NeighborResult best); - virtual NeighborResult FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best); + virtual NeighborResult FindScrollNeighbor(View *view, const Point2D &target, FocusDirection direction, NeighborResult best); bool CanBeFocused() const override { return false; } bool IsViewGroup() const override { return true; } bool ContainsSubview(const View *view) const override; + int IndexOfSubview(const View *view) const; virtual void SetBG(const Drawable &bg) { bg_ = bg; } @@ -332,10 +333,13 @@ public: void Update() override; void SetOpen(bool open) { + _dbg_assert_(open_); *open_ = open; UpdateVisibility(); } void SetOpenPtr(bool *open) { + _dbg_assert_(header_); + _dbg_assert_(open); header_->SetOpenPtr(open); open_ = open; UpdateVisibility(); @@ -344,8 +348,8 @@ public: private: void UpdateVisibility(); bool localOpen_ = true; - bool *open_; - CollapsibleHeader *header_; + bool *open_ = nullptr; + CollapsibleHeader *header_ = nullptr; }; } // namespace UI diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 84c76e970b..a77bce6663 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -26,6 +26,13 @@ #include "Core/KeyMap.h" #include "Core/System.h" +enum VRMatrix { + VR_PROJECTION_MATRIX, + VR_VIEW_MATRIX_LEFT_EYE, + VR_VIEW_MATRIX_RIGHT_EYE, + VR_MATRIX_COUNT +}; + enum VRMirroring { VR_MIRRORING_AXIS_X, VR_MIRRORING_AXIS_Y, @@ -44,10 +51,9 @@ static int vr3DGeometryCount = 0; static long vrCompat[VR_COMPAT_MAX]; static bool vrFlatForced = false; static bool vrFlatGame = false; -static double vrFov[2] = {}; +static float vrMatrix[VR_MATRIX_COUNT][16]; static bool vrMirroring[VR_MIRRORING_COUNT]; static int vrMirroringVariant = 0; -static float vrViewMatrix[2][16]; static XrView vrView[2]; static void (*cbNativeAxis)(const AxisInput *axis, size_t count); @@ -106,11 +112,6 @@ static std::vector controllerMapping[2] = { leftControllerMapping, rightControllerMapping }; -static bool controllerMotion[2][5] = {}; -static bool hmdMotion[4] = {}; -static float hmdMotionLast[2] = {}; -static float hmdMotionDiff[2] = {}; -static float hmdMotionDiffLast[2] = {}; static int mouseController = 1; static bool mousePressed = false; @@ -154,11 +155,12 @@ void InitVROnAndroid(void* vm, void* activity, const char* system, int version, if (strcmp(vendor, "PICO") == 0) { VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO, true); VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_INSTANCE, true); - } else if ((strcmp(vendor, "META") == 0) || (strcmp(vendor, "OCULUS") == 0)) { + VR_SetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING, 1.0f); + } else { VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST, true); - VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_FOVEATION, true); VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_PASSTHROUGH, true); VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_PERFORMANCE, true); + VR_SetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING, 1.3f); } VR_SetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN, (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN); @@ -268,103 +270,6 @@ void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) { } } - //motion control - if (g_Config.bEnableMotions) { - for (int j = 0; j < 2; j++) { - bool activate; - float limit = g_Config.fMotionLength; //length of needed movement in meters - XrVector3f axis = {0, 1, 0}; - float center = ToRadians(VR_GetConfigFloat(VR_CONFIG_MENU_YAW)); - XrQuaternionf orientation = XrQuaternionf_CreateFromVectorAngle(axis, center); - XrVector3f position = XrQuaternionf_Rotate(orientation, IN_VRGetPose(j).position); - - //up - activate = position.y > limit; - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_UP; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][0] != activate) cbNativeKey(keyInput); - controllerMotion[j][0] = activate; - - //down - activate = position.y < -limit * 1.5f; - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_DOWN; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][1] != activate) cbNativeKey(keyInput); - controllerMotion[j][1] = activate; - - //left - activate = position.x < -limit * (j == 0 ? 1.0f : 0.25f); - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_LEFT; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][2] != activate) cbNativeKey(keyInput); - controllerMotion[j][2] = activate; - - //right - activate = position.x > limit * (j == 1 ? 1.0f : 0.25f); - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_RIGHT; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][3] != activate) cbNativeKey(keyInput); - controllerMotion[j][3] = activate; - - //forward - activate = position.z < -limit; - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_MOTION_FORWARD; - keyInput.deviceId = controllerIds[j]; - if (controllerMotion[j][4] != activate) cbNativeKey(keyInput); - controllerMotion[j][4] = activate; - } - } - - // Head control - if (g_Config.bHeadRotationEnabled) { - float pitch = -VR_GetHMDAngles().x; - float yaw = -VR_GetHMDAngles().y; - bool disable = vrFlatForced || appMode == VR_MENU_MODE; - bool isVR = !IsFlatVRScene(); - - // calculate delta angles of the rotation - if (isVR) { - float f = g_Config.bHeadRotationSmoothing ? 0.5f : 1.0f; - float deltaPitch = pitch - hmdMotionLast[0]; - float deltaYaw = yaw - hmdMotionLast[1]; - while (deltaYaw >= 180) deltaYaw -= 360; - while (deltaYaw < -180) deltaYaw += 360; - hmdMotionLast[0] = pitch; - hmdMotionLast[1] = yaw; - hmdMotionDiffLast[0] = hmdMotionDiffLast[0] * (1-f) + hmdMotionDiff[0] * f; - hmdMotionDiffLast[1] = hmdMotionDiffLast[1] * (1-f) + hmdMotionDiff[1] * f; - hmdMotionDiff[0] += deltaPitch; - hmdMotionDiff[1] += deltaYaw; - pitch = hmdMotionDiff[0]; - yaw = hmdMotionDiff[1]; - } - - bool activate; - float limit = isVR ? g_Config.fHeadRotationScale : 20; - keyInput.deviceId = DEVICE_ID_XR_HMD; - - //left - activate = !disable && yaw < -limit; - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_ROTATION_LEFT; - if (hmdMotion[2] != activate) cbNativeKey(keyInput); - if (isVR && activate) hmdMotionDiff[1] += limit; - hmdMotion[2] = activate; - - //right - activate = !disable && yaw > limit; - keyInput.flags = activate ? KEY_DOWN : KEY_UP; - keyInput.keyCode = NKCODE_EXT_ROTATION_RIGHT; - if (hmdMotion[3] != activate) cbNativeKey(keyInput); - if (isVR && activate) hmdMotionDiff[1] -= limit; - hmdMotion[3] = activate; - } - // Camera adjust if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST]) { for (auto& device : pspAxis) { @@ -381,15 +286,9 @@ void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) { g_Config.fCameraHeight = clampFloat(g_Config.fCameraHeight, -150.0f, 150.0f); break; case JOYSTICK_AXIS_Z: - if (g_Config.bEnableVR) { - if (axis.second < -0.75f) g_Config.fHeadUpDisplayScale -= 0.01f; - if (axis.second > 0.75f) g_Config.fHeadUpDisplayScale += 0.01f; - g_Config.fHeadUpDisplayScale = clampFloat(g_Config.fHeadUpDisplayScale, 0.0f, 1.5f); - } else { - if (axis.second < -0.75f) g_Config.fCanvas3DDistance += 0.1f; - if (axis.second > 0.75f) g_Config.fCanvas3DDistance -= 0.1f; - g_Config.fCanvas3DDistance = clampFloat(g_Config.fCanvas3DDistance, 1.0f, 15.0f); - } + if (axis.second < -0.75f) g_Config.fCameraPitch -= 0.5f; + if (axis.second > 0.75f) g_Config.fCameraPitch += 0.5f; + g_Config.fCameraPitch = clampFloat(g_Config.fCameraPitch, -90.0f, 90.0f); break; case JOYSTICK_AXIS_RZ: if (axis.second > 0.75f) g_Config.fCameraDistance -= 0.1f; @@ -427,6 +326,8 @@ void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) { float speed = (cx + cy) / 2; float x = cx - tan(ToRadians(angles.y - VR_GetConfigFloat(VR_CONFIG_MENU_YAW))) * speed; float y = cy - tan(ToRadians(angles.x)) * speed * VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); + x *= VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING); + y *= VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING); //set renderer VR_SetConfig(VR_CONFIG_MOUSE_X, (int)x); @@ -530,11 +431,10 @@ bool UpdateVRKeys(const KeyInput &key) { // Reset camera adjust if (pspKeys[VIRTKEY_VR_CAMERA_ADJUST] && pspKeys[VIRTKEY_VR_CAMERA_RESET]) { - g_Config.fCanvas3DDistance = 3.0f; g_Config.fCameraHeight = 0; g_Config.fCameraSide = 0; g_Config.fCameraDistance = 0; - g_Config.fHeadUpDisplayScale = 0.3f; + g_Config.fCameraPitch = 0; } //block keys by camera adjust @@ -619,7 +519,7 @@ void* BindVRFramebuffer() { bool StartVRRender() { if (!VR_GetConfig(VR_CONFIG_VIEWPORT_VALID)) { - VR_InitRenderer(VR_GetEngine(), IsMultiviewSupported()); + VR_InitRenderer(VR_GetEngine()); VR_SetConfig(VR_CONFIG_VIEWPORT_VALID, true); } @@ -627,6 +527,7 @@ bool StartVRRender() { // VR flags bool vrIncompatibleGame = PSP_CoreParameter().compat.vrCompat().ForceFlatScreen; + bool vrMode = (g_Config.bEnableVR || IsImmersiveVRMode()) && !vrIncompatibleGame; bool vrScene = !vrFlatForced && (g_Config.bManualForceVR || (vr3DGeometryCount > 15)); bool vrStereo = !PSP_CoreParameter().compat.vrCompat().ForceMono && g_Config.bEnableStereo; @@ -636,27 +537,45 @@ bool StartVRRender() { } UpdateVRViewMatrices(); - // Calculate field of view + // Update projection matrix XrFovf fov = {}; - for (auto & eye : vrView) { - fov.angleLeft += eye.fov.angleLeft / 2.0f; - fov.angleRight += eye.fov.angleRight / 2.0f; - fov.angleUp += eye.fov.angleUp / 2.0f; - fov.angleDown += eye.fov.angleDown / 2.0f; + for (int eye = 0; eye < ovrMaxNumEyes; eye++) { + fov.angleLeft += vrView[eye].fov.angleLeft / 2.0f; + fov.angleRight += vrView[eye].fov.angleRight / 2.0f; + fov.angleUp += vrView[eye].fov.angleUp / 2.0f; + fov.angleDown += vrView[eye].fov.angleDown / 2.0f; } - vrFov[0] = 2.0 / (tan(fov.angleRight) - tan(fov.angleLeft)); - vrFov[1] = 2.0 / (tan(fov.angleUp) - tan(fov.angleDown)); + float nearZ = 0.01f; + float tanAngleLeft = tanf(fov.angleLeft); + float tanAngleRight = tanf(fov.angleRight); + float tanAngleDown = tanf(fov.angleDown); + float tanAngleUp = tanf(fov.angleUp); + float M[16] = {}; + M[0] = 2 / (tanAngleRight - tanAngleLeft); + M[5] = 2 / (tanAngleUp - tanAngleDown); + M[8] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft); + M[9] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown); + M[10] = -1; + M[11] = -1; + M[14] = -(nearZ + nearZ); + if (IsImmersiveVRMode()) { + M[0] /= 2.0f; + } + memcpy(vrMatrix[VR_PROJECTION_MATRIX], M, sizeof(float) * 16); // Decide if the scene is 3D or not VR_SetConfigFloat(VR_CONFIG_CANVAS_ASPECT, 480.0f / 272.0f); - if (g_Config.bEnableVR && !vrIncompatibleGame && (appMode == VR_GAME_MODE) && vrScene) { + if (vrMode && vrScene && (appMode == VR_GAME_MODE)) { VR_SetConfig(VR_CONFIG_MODE, vrStereo ? VR_MODE_STEREO_6DOF : VR_MODE_MONO_6DOF); + VR_SetConfig(VR_CONFIG_REPROJECTION, IsImmersiveVRMode() ? 0 : 1); vrFlatGame = false; - } else { + } else if (appMode == VR_GAME_MODE) { VR_SetConfig(VR_CONFIG_MODE, vrStereo ? VR_MODE_STEREO_SCREEN : VR_MODE_MONO_SCREEN); if (IsGameVRScene()) { vrFlatGame = true; } + } else { + VR_SetConfig(VR_CONFIG_MODE, VR_MODE_MONO_SCREEN); } vr3DGeometryCount /= 2; @@ -664,9 +583,8 @@ bool StartVRRender() { vrCompat[VR_COMPAT_SKYPLANE] = PSP_CoreParameter().compat.vrCompat().Skyplane; // Set customizations - __DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60); VR_SetConfigFloat(VR_CONFIG_CANVAS_DISTANCE, vrScene && (appMode == VR_GAME_MODE) ? g_Config.fCanvas3DDistance : g_Config.fCanvasDistance); - VR_SetConfig(VR_CONFIG_PASSTHROUGH, g_Config.bPassthrough); + VR_SetConfig(VR_CONFIG_PASSTHROUGH, g_Config.bPassthrough && IsPassthroughSupported()); return true; } return false; @@ -691,15 +609,7 @@ int GetVRFBOIndex() { int GetVRPassesCount() { bool vrStereo = !PSP_CoreParameter().compat.vrCompat().ForceMono && g_Config.bEnableStereo; - if (!IsMultiviewSupported() && vrStereo) { - return 2; - } else { - return 1; - } -} - -bool IsMultiviewSupported() { - return false; + return vrStereo ? 2 : 1; } bool IsPassthroughSupported() { @@ -711,6 +621,9 @@ bool IsFlatVRGame() { } bool IsFlatVRScene() { + if (g_Config.bForceVR && (!vrFlatForced || !g_Config.bManualForceVR)) { + return false; + } int vrMode = VR_GetConfig(VR_CONFIG_MODE); return (vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN); } @@ -719,6 +632,10 @@ bool IsGameVRScene() { return (appMode == VR_GAME_MODE) || (appMode == VR_DIALOG_MODE); } +bool IsImmersiveVRMode() { + return g_Config.bEnableImmersiveVR && !PSP_CoreParameter().compat.vrCompat().IdentityViewHack; +} + bool Is2DVRObject(float* projMatrix, bool ortho) { // Quick analyze if the object is in 2D @@ -789,17 +706,27 @@ void UpdateVRParams(float* projMatrix) { } } -void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye) { - float hmdProjection[16]; - memcpy(hmdProjection, projMatrix, 16 * sizeof(float)); - hmdProjection[0] = vrFov[0]; - hmdProjection[5] = vrFov[1]; - memcpy(leftEye, hmdProjection, 16 * sizeof(float)); - memcpy(rightEye, hmdProjection, 16 * sizeof(float)); +void UpdateVRProjection(float* projMatrix, float* output) { + for (int i = 0; i < 16; i++) { + if (!IsVREnabled()) { + output[i] = projMatrix[i]; + } else if (PSP_CoreParameter().compat.vrCompat().ProjectionHack && ((i == 8) || (i == 9))) { + output[i] = 0; + } else if (fabs(projMatrix[i]) > 0) { + output[i] = vrMatrix[VR_PROJECTION_MATRIX][i]; + if ((output[i] > 0) != (projMatrix[i] > 0)) { + output[i] *= -1.0f; + } + } else { + output[i] = 0; + } + } + output[11] *= g_Config.fFieldOfViewPercentage / 100.0f; } void UpdateVRView(float* leftEye, float* rightEye) { float* dst[] = {leftEye, rightEye}; + float* matrix[] = {vrMatrix[VR_VIEW_MATRIX_LEFT_EYE], vrMatrix[VR_VIEW_MATRIX_RIGHT_EYE]}; for (int index = 0; index < 2; index++) { // Validate the view matrix @@ -813,7 +740,7 @@ void UpdateVRView(float* leftEye, float* rightEye) { // Get view matrix from the headset Lin::Matrix4x4 hmdView = {}; - memcpy(hmdView.m, vrViewMatrix[index], 16 * sizeof(float)); + memcpy(hmdView.m, matrix[index], 16 * sizeof(float)); // Combine the matrices Lin::Matrix4x4 renderView = hmdView * gameView; @@ -830,8 +757,11 @@ void UpdateVRViewMatrices() { } // Get input + XrPosef invView = XrPosef_Identity(); + if (IsVREnabled()) { + invView = vrView[0].pose; + } bool flatScreen = false; - XrPosef invView = vrView[0].pose; int vrMode = VR_GetConfig(VR_CONFIG_MODE); if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { invView = XrPosef_Identity(); @@ -852,23 +782,13 @@ void UpdateVRViewMatrices() { invView = XrPosef_Inverse(invView); } - // apply camera pitch offset + // apply camera pitch + float s = sin(ToRadians(g_Config.fCameraPitch)); + float c = cos(ToRadians(g_Config.fCameraPitch)); XrVector3f positionOffset = {g_Config.fCameraSide, g_Config.fCameraHeight, g_Config.fCameraDistance}; - if (!flatScreen) { - float pitchOffset = 0; - switch (g_Config.iCameraPitch) { - case 1: //Top view -> First person - pitchOffset = 90; - positionOffset = {positionOffset.x, positionOffset.z, -positionOffset.y}; - break; - case 2: //First person -> Top view - pitchOffset = -90; - positionOffset = {positionOffset.x, -positionOffset.z + 20, positionOffset.y}; - break; - } - XrQuaternionf rotationOffset = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, ToRadians(pitchOffset)); - invView.orientation = XrQuaternionf_Multiply(rotationOffset, invView.orientation); - } + positionOffset = {positionOffset.x, s * positionOffset.z + c * positionOffset.y, c * positionOffset.z - s * positionOffset.y}; + XrQuaternionf rotationOffset = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, ToRadians(g_Config.fCameraPitch)); + invView.orientation = XrQuaternionf_Multiply(rotationOffset, invView.orientation); // decompose rotation XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); @@ -876,20 +796,21 @@ void UpdateVRViewMatrices() { float mYaw = my * ToRadians(rotation.y); float mRoll = mz * ToRadians(rotation.z); - // use in-game camera interpolated rotation - if (g_Config.bHeadRotationEnabled) mYaw = -my * ToRadians(hmdMotionDiffLast[1]); // horizontal - // create updated quaternion XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mPitch); XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, mYaw); XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mRoll); invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); + if (!VR_GetConfig(VR_CONFIG_REPROJECTION)) { + float axis = vrMirroring[VR_MIRRORING_PITCH] ? -1.0f : 1.0f; + invView.orientation = XrQuaternionf_CreateFromVectorAngle({axis, 0, 0}, ToRadians(g_Config.fCameraPitch)); + } float M[16]; XrQuaternionf_ToMatrix4f(&invView.orientation, M); // Apply 6Dof head movement - if (g_Config.bEnable6DoF && !g_Config.bHeadRotationEnabled && (g_Config.iCameraPitch == 0)) { + if (g_Config.bEnable6DoF && IsVREnabled()) { M[3] -= vrView[0].pose.position.x * (vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f) * scale; M[7] -= vrView[0].pose.position.y * (vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f) * scale; M[11] -= vrView[0].pose.position.z * (vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f) * scale; @@ -922,12 +843,12 @@ void UpdateVRViewMatrices() { M[11] += side.z; } - for (int eye = 0; eye < ovrMaxNumEyes; eye++) { + for (int matrix = VR_VIEW_MATRIX_LEFT_EYE; matrix <= VR_VIEW_MATRIX_RIGHT_EYE; matrix++) { // Stereoscopy bool vrStereo = !PSP_CoreParameter().compat.vrCompat().ForceMono && g_Config.bEnableStereo; - if (vrStereo) { - bool mirrored = vrMirroring[VR_MIRRORING_AXIS_Z] ^ (eye == 1); + if (vrStereo && IsVREnabled()) { + bool mirrored = vrMirroring[VR_MIRRORING_AXIS_Z] ^ (matrix == VR_VIEW_MATRIX_RIGHT_EYE); float dx = fabs(vrView[1].pose.position.x - vrView[0].pose.position.x); float dy = fabs(vrView[1].pose.position.y - vrView[0].pose.position.y); float dz = fabs(vrView[1].pose.position.z - vrView[0].pose.position.z); @@ -940,6 +861,6 @@ void UpdateVRViewMatrices() { M[11] += separation.z; } - memcpy(vrViewMatrix[eye], M, sizeof(float) * 16); + memcpy(vrMatrix[matrix], M, sizeof(float) * 16); } } diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index b78000e4e1..e77f5a0d07 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -52,13 +52,13 @@ void PreVRFrameRender(int fboIndex); void PostVRFrameRender(); int GetVRFBOIndex(); int GetVRPassesCount(); -bool IsMultiviewSupported(); bool IsPassthroughSupported(); bool IsFlatVRGame(); bool IsFlatVRScene(); bool IsGameVRScene(); +bool IsImmersiveVRMode(); bool Is2DVRObject(float* projMatrix, bool ortho); void UpdateVRParams(float* projMatrix); -void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye); +void UpdateVRProjection(float* projMatrix, float* output); void UpdateVRView(float* leftEye, float* rightEye); void UpdateVRViewMatrices(); diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 6a22203586..37e5ff0153 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -49,15 +49,6 @@ void VR_Init( void* system, const char* name, int version ) { } extensions.push_back(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME); #ifdef ANDROID - if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_FOVEATION)) { - extensions.push_back(XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME); - extensions.push_back(XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME); - extensions.push_back(XR_FB_FOVEATION_EXTENSION_NAME); - extensions.push_back(XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME); - if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { - extensions.push_back(XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME); - } - } if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_INSTANCE)) { extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME); } @@ -77,7 +68,7 @@ void VR_Init( void* system, const char* name, int version ) { strcpy(appInfo.engineName, name); appInfo.applicationVersion = version; appInfo.engineVersion = version; - appInfo.apiVersion = XR_CURRENT_API_VERSION; + appInfo.apiVersion = XR_API_VERSION_1_0; XrInstanceCreateInfo instanceCreateInfo; memset(&instanceCreateInfo, 0, sizeof(instanceCreateInfo)); diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index e8f41d4b6b..8340b25673 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -65,20 +65,17 @@ typedef struct { uint32_t TextureSwapChainLength; uint32_t TextureSwapChainIndex; ovrSwapChain ColorSwapChain; - ovrSwapChain DepthSwapChain; void* ColorSwapChainImage; - void* DepthSwapChainImage; + unsigned int* GLDepthBuffers; unsigned int* GLFrameBuffers; VkFramebuffer* VKFrameBuffers; VkImageView* VKColorImages; - VkImageView* VKDepthImages; bool Acquired; XrGraphicsBindingVulkanKHR* VKContext; } ovrFramebuffer; typedef struct { - bool Multiview; ovrFramebuffer FrameBuffer[ovrMaxNumEyes]; } ovrRenderer; @@ -124,7 +121,6 @@ typedef struct { enum VRPlatformFlag { VR_PLATFORM_CONTROLLER_PICO, VR_PLATFORM_CONTROLLER_QUEST, - VR_PLATFORM_EXTENSION_FOVEATION, VR_PLATFORM_EXTENSION_INSTANCE, VR_PLATFORM_EXTENSION_PASSTHROUGH, VR_PLATFORM_EXTENSION_PERFORMANCE, diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index ba7e656f33..0a91bd2082 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -1,11 +1,19 @@ #include "VRFramebuffer.h" -#if XR_USE_GRAPHICS_API_OPENGL_ES +#if XR_USE_GRAPHICS_API_OPENGL || XR_USE_GRAPHICS_API_OPENGL_ES #include "Common/GPU/OpenGL/GLCommon.h" #endif +#if XR_USE_GRAPHICS_API_OPENGL_ES +#define XR_GL_IMAGE XrSwapchainImageOpenGLESKHR +#define XR_GL_SWAPCHAIN XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR +#else +#define XR_GL_IMAGE XrSwapchainImageOpenGLKHR +#define XR_GL_SWAPCHAIN XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR +#endif + #include #include #include @@ -39,11 +47,8 @@ void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) { frameBuffer->ColorSwapChain.Width = 0; frameBuffer->ColorSwapChain.Height = 0; frameBuffer->ColorSwapChainImage = NULL; - frameBuffer->DepthSwapChain.Handle = XR_NULL_HANDLE; - frameBuffer->DepthSwapChain.Width = 0; - frameBuffer->DepthSwapChain.Height = 0; - frameBuffer->DepthSwapChainImage = NULL; + frameBuffer->GLDepthBuffers = NULL; frameBuffer->GLFrameBuffers = NULL; frameBuffer->Acquired = false; } @@ -81,23 +86,12 @@ void GLCheckErrors(const char* file, int line) { #endif -#if XR_USE_GRAPHICS_API_OPENGL_ES +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL -static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, bool multiview) { +static bool ovrFramebuffer_CreateGL(XrSession session, ovrFramebuffer* frameBuffer, int width, int height) { frameBuffer->Width = width; frameBuffer->Height = height; - if (strstr((const char*)glGetString(GL_EXTENSIONS), "GL_OVR_multiview2") == nullptr) - { - ALOGE("OpenGL implementation does not support GL_OVR_multiview2 extension.\n"); - } - - typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei); - PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR glFramebufferTextureMultiviewOVR = nullptr; - glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)eglGetProcAddress ("glFramebufferTextureMultiviewOVR"); - if (!glFramebufferTextureMultiviewOVR) { - ALOGE("Can not get proc address for glFramebufferTextureMultiviewOVR.\n"); - } XrSwapchainCreateInfo swapChainCreateInfo; memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo)); swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO; @@ -106,70 +100,46 @@ static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBu swapChainCreateInfo.height = height; swapChainCreateInfo.faceCount = 1; swapChainCreateInfo.mipCount = 1; - swapChainCreateInfo.arraySize = multiview ? 2 : 1; - -#ifdef ANDROID - XrSwapchainCreateInfoFoveationFB swapChainFoveationCreateInfo; - if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_FOVEATION)) { - memset(&swapChainFoveationCreateInfo, 0, sizeof(swapChainFoveationCreateInfo)); - swapChainFoveationCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB; - swapChainCreateInfo.next = &swapChainFoveationCreateInfo; - } -#endif + swapChainCreateInfo.arraySize = 1; frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width; frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height; - frameBuffer->DepthSwapChain.Width = swapChainCreateInfo.width; - frameBuffer->DepthSwapChain.Height = swapChainCreateInfo.height; // Create the color swapchain. swapChainCreateInfo.format = GL_SRGB8_ALPHA8; swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->ColorSwapChain.Handle)); OXR(xrEnumerateSwapchainImages(frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL)); - frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); - - // Create the depth swapchain. - swapChainCreateInfo.format = GL_DEPTH24_STENCIL8; - swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle)); - frameBuffer->DepthSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR)); + frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XR_GL_IMAGE)); // Populate the swapchain image array. for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { - ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; - ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].next = NULL; - ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; - ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].next = NULL; + ((XR_GL_IMAGE*)frameBuffer->ColorSwapChainImage)[i].type = XR_GL_SWAPCHAIN; + ((XR_GL_IMAGE*)frameBuffer->ColorSwapChainImage)[i].next = NULL; } OXR(xrEnumerateSwapchainImages( frameBuffer->ColorSwapChain.Handle, frameBuffer->TextureSwapChainLength, &frameBuffer->TextureSwapChainLength, (XrSwapchainImageBaseHeader*)frameBuffer->ColorSwapChainImage)); - OXR(xrEnumerateSwapchainImages( - frameBuffer->DepthSwapChain.Handle, - frameBuffer->TextureSwapChainLength, - &frameBuffer->TextureSwapChainLength, - (XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage)); + frameBuffer->GLDepthBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint)); frameBuffer->GLFrameBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint)); for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { - const GLuint colorTexture = ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].image; - const GLuint depthTexture = ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].image; + const GLuint colorTexture = ((XR_GL_IMAGE*)frameBuffer->ColorSwapChainImage)[i].image; + + // Create the depth buffer. + GL(glGenRenderbuffers(1, &frameBuffer->GLDepthBuffers[i])); + GL(glBindRenderbuffer(GL_RENDERBUFFER, frameBuffer->GLDepthBuffers[i])); + GL(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height)); + GL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); // Create the frame buffer. GL(glGenFramebuffers(1, &frameBuffer->GLFrameBuffers[i])); GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[i])); - if (multiview) { - GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexture, 0, 0, 2)); - GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0, 2)); - GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, 0, 2)); - } else { - GL(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0)); - GL(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0)); - GL(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0)); - } + GL(glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, frameBuffer->GLDepthBuffers[i])); + GL(glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, frameBuffer->GLDepthBuffers[i])); + GL(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0)); GL(GLenum renderFramebufferStatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)); GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); if (renderFramebufferStatus != GL_FRAMEBUFFER_COMPLETE) { @@ -186,7 +156,7 @@ static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBu #if XR_USE_GRAPHICS_API_VULKAN static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuffer, int width, int height, - bool multiview, void* context) { + void* context) { frameBuffer->Width = width; frameBuffer->Height = height; @@ -200,21 +170,10 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff swapChainCreateInfo.height = height; swapChainCreateInfo.faceCount = 1; swapChainCreateInfo.mipCount = 1; - swapChainCreateInfo.arraySize = multiview ? 2 : 1; - -#ifdef ANDROID - XrSwapchainCreateInfoFoveationFB swapChainFoveationCreateInfo; - if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_FOVEATION)) { - memset(&swapChainFoveationCreateInfo, 0, sizeof(swapChainFoveationCreateInfo)); - swapChainFoveationCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB; - swapChainCreateInfo.next = &swapChainFoveationCreateInfo; - } -#endif + swapChainCreateInfo.arraySize = 1; frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width; frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height; - frameBuffer->DepthSwapChain.Width = swapChainCreateInfo.width; - frameBuffer->DepthSwapChain.Height = swapChainCreateInfo.height; // Create the color swapchain. swapChainCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; @@ -223,32 +182,18 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff OXR(xrEnumerateSwapchainImages(frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL)); frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageVulkanKHR)); - // Create the depth swapchain. - swapChainCreateInfo.format = VK_FORMAT_D24_UNORM_S8_UINT; - swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle)); - frameBuffer->DepthSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageVulkanKHR)); - // Populate the swapchain image array. for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR; ((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].next = NULL; - ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR; - ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].next = NULL; } OXR(xrEnumerateSwapchainImages( frameBuffer->ColorSwapChain.Handle, frameBuffer->TextureSwapChainLength, &frameBuffer->TextureSwapChainLength, (XrSwapchainImageBaseHeader*)frameBuffer->ColorSwapChainImage)); - OXR(xrEnumerateSwapchainImages( - frameBuffer->DepthSwapChain.Handle, - frameBuffer->TextureSwapChainLength, - &frameBuffer->TextureSwapChainLength, - (XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage)); frameBuffer->VKColorImages = new VkImageView[frameBuffer->TextureSwapChainLength]; - frameBuffer->VKDepthImages = new VkImageView[frameBuffer->TextureSwapChainLength]; frameBuffer->VKFrameBuffers = new VkFramebuffer[frameBuffer->TextureSwapChainLength]; for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) { VkImageViewCreateInfo createInfo{}; @@ -270,16 +215,8 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff return false; } - createInfo.image = ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].image; - createInfo.format = VK_FORMAT_D24_UNORM_S8_UINT; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - if (vkCreateImageView(frameBuffer->VKContext->device, &createInfo, nullptr, &frameBuffer->VKDepthImages[i]) != VK_SUCCESS) { - ALOGE("failed to create depth image view!"); - return false; - } - // Create the frame buffer. - VkImageView attachments[] = { frameBuffer->VKColorImages[i], frameBuffer->VKDepthImages[i] }; + VkImageView attachments[] = { frameBuffer->VKColorImages[i] }; VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = VK_NULL_HANDLE; //TODO:This is probably wrong @@ -303,22 +240,20 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) { if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { for (int i = 0; i < (int)frameBuffer->TextureSwapChainLength; i++) { vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKColorImages[i], nullptr); - vkDestroyImageView(frameBuffer->VKContext->device, frameBuffer->VKDepthImages[i], nullptr); vkDestroyFramebuffer(frameBuffer->VKContext->device, frameBuffer->VKFrameBuffers[i], nullptr); } delete[] frameBuffer->VKColorImages; - delete[] frameBuffer->VKDepthImages; delete[] frameBuffer->VKFrameBuffers; } else { #if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL + GL(glDeleteRenderbuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLDepthBuffers)); GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers)); + free(frameBuffer->GLDepthBuffers); free(frameBuffer->GLFrameBuffers); #endif } OXR(xrDestroySwapchain(frameBuffer->ColorSwapChain.Handle)); - OXR(xrDestroySwapchain(frameBuffer->DepthSwapChain.Handle)); free(frameBuffer->ColorSwapChainImage); - free(frameBuffer->DepthSwapChainImage); ovrFramebuffer_Clear(frameBuffer); } @@ -355,7 +290,7 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) { GL(glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height )); GL(glClearColor( 0.0f, 0.0f, 0.0f, 1.0f )); GL(glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height )); - GL(glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )); + GL(glClear( GL_COLOR_BUFFER_BIT )); GL(glScissor( 0, 0, 0, 0 )); GL(glDisable( GL_SCISSOR_TEST )); #endif @@ -396,25 +331,20 @@ void ovrRenderer_Clear(ovrRenderer* renderer) { } } -void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext) { - renderer->Multiview = multiview; - int instances = renderer->Multiview ? 1 : ovrMaxNumEyes; - for (int i = 0; i < instances; i++) { +void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, void* vulkanContext) { + for (int i = 0; i < ovrMaxNumEyes; i++) { if (vulkanContext) { - ovrFramebuffer_CreateVK(session, &renderer->FrameBuffer[i], width, height, multiview, vulkanContext); + ovrFramebuffer_CreateVK(session, &renderer->FrameBuffer[i], width, height, vulkanContext); } else { -#if XR_USE_GRAPHICS_API_OPENGL_ES - ovrFramebuffer_CreateGLES(session, &renderer->FrameBuffer[i], width, height, multiview); -#elif XR_USE_GRAPHICS_API_OPENGL - // TODO +#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL + ovrFramebuffer_CreateGL(session, &renderer->FrameBuffer[i], width, height); #endif } } } void ovrRenderer_Destroy(ovrRenderer* renderer) { - int instances = renderer->Multiview ? 1 : ovrMaxNumEyes; - for (int i = 0; i < instances; i++) { + for (int i = 0; i < ovrMaxNumEyes; i++) { ovrFramebuffer_Destroy(&renderer->FrameBuffer[i]); } } @@ -434,47 +364,6 @@ void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int sx, int sy } } -#ifdef ANDROID -void ovrRenderer_SetFoveation(XrInstance* instance, XrSession* session, ovrRenderer* renderer, XrFoveationLevelFB level, float verticalOffset, XrFoveationDynamicFB dynamic) { - PFN_xrCreateFoveationProfileFB pfnCreateFoveationProfileFB; - OXR(xrGetInstanceProcAddr(*instance, "xrCreateFoveationProfileFB", (PFN_xrVoidFunction*)(&pfnCreateFoveationProfileFB))); - - PFN_xrDestroyFoveationProfileFB pfnDestroyFoveationProfileFB; - OXR(xrGetInstanceProcAddr(*instance, "xrDestroyFoveationProfileFB", (PFN_xrVoidFunction*)(&pfnDestroyFoveationProfileFB))); - - PFN_xrUpdateSwapchainFB pfnUpdateSwapchainFB; - OXR(xrGetInstanceProcAddr(*instance, "xrUpdateSwapchainFB", (PFN_xrVoidFunction*)(&pfnUpdateSwapchainFB))); - - int instances = renderer->Multiview ? 1 : ovrMaxNumEyes; - for (int eye = 0; eye < instances; eye++) { - XrFoveationLevelProfileCreateInfoFB levelProfileCreateInfo; - memset(&levelProfileCreateInfo, 0, sizeof(levelProfileCreateInfo)); - levelProfileCreateInfo.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB; - levelProfileCreateInfo.level = level; - levelProfileCreateInfo.verticalOffset = verticalOffset; - levelProfileCreateInfo.dynamic = dynamic; - - XrFoveationProfileCreateInfoFB profileCreateInfo; - memset(&profileCreateInfo, 0, sizeof(profileCreateInfo)); - profileCreateInfo.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB; - profileCreateInfo.next = &levelProfileCreateInfo; - - XrFoveationProfileFB foveationProfile; - - pfnCreateFoveationProfileFB(*session, &profileCreateInfo, &foveationProfile); - - XrSwapchainStateFoveationFB foveationUpdateState; - memset(&foveationUpdateState, 0, sizeof(foveationUpdateState)); - foveationUpdateState.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB; - foveationUpdateState.profile = foveationProfile; - - pfnUpdateSwapchainFB(renderer->FrameBuffer[eye].ColorSwapChain.Handle, (XrSwapchainStateBaseHeaderFB*)(&foveationUpdateState)); - - pfnDestroyFoveationProfileFB(foveationProfile); - } -} -#endif - /* ================================================================================ @@ -627,6 +516,7 @@ int ovrApp_HandleXrEvents(ovrApp* app) { default: break; } + recenter = true; } break; default: ALOGV("xrPollEvent: Unknown event"); diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h index 49f7484c99..c49594b21e 100644 --- a/Common/VR/VRFramebuffer.h +++ b/Common/VR/VRFramebuffer.h @@ -10,9 +10,6 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer); void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer); void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer); -void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext); +void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, void* vulkanContext); void ovrRenderer_Destroy(ovrRenderer* renderer); void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int sx, int sy); -#ifdef ANDROID -void ovrRenderer_SetFoveation(XrInstance* instance, XrSession* session, ovrRenderer* renderer, XrFoveationLevelFB level, float verticalOffset, XrFoveationDynamicFB dynamic); -#endif diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 76184844d1..36052af4ad 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -38,14 +38,10 @@ void VR_UpdateStageBounds(ovrApp* pappState) { XrResult result; OXR(result = xrGetReferenceSpaceBoundsRect(pappState->Session, XR_REFERENCE_SPACE_TYPE_STAGE, &stageBounds)); if (result != XR_SUCCESS) { - ALOGV("Stage bounds query failed: using small defaults"); stageBounds.width = 1.0f; stageBounds.height = 1.0f; - pappState->CurrentSpace = pappState->FakeStageSpace; } - - ALOGV("Stage bounds: width = %f, depth %f", stageBounds.width, stageBounds.height); } void VR_GetResolution(engine_t* engine, int *pWidth, int *pHeight) { @@ -131,6 +127,9 @@ void VR_GetResolution(engine_t* engine, int *pWidth, int *pHeight) { *pWidth = width; *pHeight = height; } + + *pWidth = (int)(*pWidth * VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING)); + *pHeight = (int)(*pHeight * VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING)); } void VR_Recenter(engine_t* engine) { @@ -164,6 +163,8 @@ void VR_Recenter(engine_t* engine) { // Create a default stage space to use if SPACE_TYPE_STAGE is not // supported, or calls to xrGetReferenceSpaceBoundsRect fail. spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; + spaceCreateInfo.poseInReferenceSpace = {}; + spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0; if (VR_GetPlatformFlag(VR_PLATFORM_TRACKING_FLOOR)) { spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f; } @@ -173,7 +174,8 @@ void VR_Recenter(engine_t* engine) { if (stageSupported) { spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE; - spaceCreateInfo.poseInReferenceSpace.position.y = 0.0; + spaceCreateInfo.poseInReferenceSpace = {}; + spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0; OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace)); ALOGV("Created stage space"); if (VR_GetPlatformFlag(VR_PLATFORM_TRACKING_FLOOR)) { @@ -186,7 +188,7 @@ void VR_Recenter(engine_t* engine) { VR_SetConfigFloat(VR_CONFIG_MENU_YAW, 0.0f); } -void VR_InitRenderer( engine_t* engine, bool multiview ) { +void VR_InitRenderer( engine_t* engine ) { if (initialized) { VR_DestroyRenderer(engine); } @@ -239,15 +241,7 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) { vulkanContext = &engine->graphicsBindingVulkan; } - ovrRenderer_Create(engine->appState.Session, &engine->appState.Renderer, - engine->appState.ViewConfigurationView[0].recommendedImageRectWidth, - engine->appState.ViewConfigurationView[0].recommendedImageRectHeight, - multiview, vulkanContext); -#ifdef ANDROID - if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_FOVEATION)) { - ovrRenderer_SetFoveation(&engine->appState.Instance, &engine->appState.Session, &engine->appState.Renderer, XR_FOVEATION_LEVEL_HIGH_FB, 0, XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB); - } -#endif + ovrRenderer_Create(engine->appState.Session, &engine->appState.Renderer, eyeW, eyeH, vulkanContext); if (VR_GetPlatformFlag(VRPlatformFlag::VR_PLATFORM_EXTENSION_PASSTHROUGH)) { XrPassthroughCreateInfoFB ptci = {XR_TYPE_PASSTHROUGH_CREATE_INFO_FB}; @@ -295,13 +289,13 @@ bool VR_InitFrame( engine_t* engine ) { } // Update passthrough - if (passthroughRunning != VR_GetConfig(VR_CONFIG_PASSTHROUGH)) { + if (passthroughRunning != (VR_GetConfig(VR_CONFIG_PASSTHROUGH) != 0)) { if (VR_GetConfig(VR_CONFIG_PASSTHROUGH)) { OXR(xrPassthroughLayerResumeFB(passthroughLayer)); } else { OXR(xrPassthroughLayerPauseFB(passthroughLayer)); } - passthroughRunning = VR_GetConfig(VR_CONFIG_PASSTHROUGH); + passthroughRunning = (VR_GetConfig(VR_CONFIG_PASSTHROUGH) != 0); } // NOTE: OpenXR does not use the concept of frame indices. Instead, @@ -389,19 +383,20 @@ void VR_EndFrame( engine_t* engine ) { void VR_FinishFrame( engine_t* engine ) { int vrMode = vrConfig[VR_CONFIG_MODE]; XrCompositionLayerProjectionView projection_layer_elements[2] = {}; - if ((vrMode == VR_MODE_MONO_6DOF) || (vrMode == VR_MODE_STEREO_6DOF)) { + bool headTracking = (vrMode == VR_MODE_MONO_6DOF) || (vrMode == VR_MODE_SBS_6DOF) || (vrMode == VR_MODE_STEREO_6DOF); + bool reprojection = vrConfig[VR_CONFIG_REPROJECTION]; + if (headTracking && reprojection) { VR_SetConfigFloat(VR_CONFIG_MENU_YAW, hmdorientation.y); - for (int eye = 0; eye < ovrMaxNumEyes; eye++) { - int imageLayer = engine->appState.Renderer.Multiview ? eye : 0; + for (int eye = 0; eye < ovrMaxNumEyes; eye++) {; ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[0]; XrPosef pose = invViewTransform[0]; if (vrMode != VR_MODE_MONO_6DOF) { - if (!engine->appState.Renderer.Multiview) { - frameBuffer = &engine->appState.Renderer.FrameBuffer[eye]; - } pose = invViewTransform[eye]; } + if (vrMode == VR_MODE_STEREO_6DOF) { + frameBuffer = &engine->appState.Renderer.FrameBuffer[eye]; + } memset(&projection_layer_elements[eye], 0, sizeof(XrCompositionLayerProjectionView)); projection_layer_elements[eye].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; @@ -414,7 +409,14 @@ void VR_FinishFrame( engine_t* engine ) { projection_layer_elements[eye].subImage.imageRect.offset.y = 0; projection_layer_elements[eye].subImage.imageRect.extent.width = frameBuffer->ColorSwapChain.Width; projection_layer_elements[eye].subImage.imageRect.extent.height = frameBuffer->ColorSwapChain.Height; - projection_layer_elements[eye].subImage.imageArrayIndex = imageLayer; + projection_layer_elements[eye].subImage.imageArrayIndex = 0; + + if (vrMode == VR_MODE_SBS_6DOF) { + projection_layer_elements[eye].subImage.imageRect.extent.width /= 2; + if (eye == 1) { + projection_layer_elements[eye].subImage.imageRect.offset.x += frameBuffer->ColorSwapChain.Width / 2; + } + } } XrCompositionLayerProjection projection_layer = {}; @@ -426,7 +428,7 @@ void VR_FinishFrame( engine_t* engine ) { projection_layer.views = projection_layer_elements; engine->appState.Layers[engine->appState.LayerCount++].Projection = projection_layer; - } else if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) { + } else { // Flat screen pose float distance = VR_GetConfigFloat(VR_CONFIG_CANVAS_DISTANCE) / 4.0f - 1.0f; @@ -458,16 +460,23 @@ void VR_FinishFrame( engine_t* engine ) { cylinder_layer.radius = 2.0f; cylinder_layer.centralAngle = (float)(M_PI * 0.5); cylinder_layer.aspectRatio = VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT); + if (headTracking && !reprojection) { + float width = (float)engine->appState.ViewConfigurationView[0].recommendedImageRectWidth; + float height = (float)engine->appState.ViewConfigurationView[0].recommendedImageRectHeight; + cylinder_layer.aspectRatio = 2.0f * width / height; + cylinder_layer.centralAngle = (float)(M_PI); + } // Build the cylinder layer - if (vrMode == VR_MODE_MONO_SCREEN) { + if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_MONO_6DOF)) { cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; - } else if (engine->appState.Renderer.Multiview) { + } else if ((vrMode == VR_MODE_SBS_SCREEN) || (vrMode == VR_MODE_SBS_6DOF)) { cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT; + cylinder_layer.subImage.imageRect.extent.width /= 2; engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT; - cylinder_layer.subImage.imageArrayIndex = 1; + cylinder_layer.subImage.imageRect.offset.x += cylinder_layer.subImage.imageRect.extent.width; engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; } else { cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT; @@ -476,8 +485,6 @@ void VR_FinishFrame( engine_t* engine ) { cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[1].ColorSwapChain.Handle; engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer; } - } else { - assert(false); } // Compose the layers for this frame. diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 7a0b3a87ae..0c7fe4edb5 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -5,7 +5,7 @@ enum VRConfig { //switching between mode - VR_CONFIG_MODE, VR_CONFIG_PASSTHROUGH, VR_CONFIG_CANVAS_6DOF, + VR_CONFIG_MODE, VR_CONFIG_PASSTHROUGH, VR_CONFIG_CANVAS_6DOF, VR_CONFIG_REPROJECTION, //mouse cursor VR_CONFIG_MOUSE_SIZE, VR_CONFIG_MOUSE_X, VR_CONFIG_MOUSE_Y, //viewport setup @@ -22,18 +22,23 @@ enum VRConfigFloat { VR_CONFIG_CANVAS_DISTANCE, VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW, VR_CONFIG_CANVAS_ASPECT, + //viewport setup + VR_CONFIG_VIEWPORT_SUPERSAMPLING, + VR_CONFIG_FLOAT_MAX }; enum VRMode { VR_MODE_MONO_SCREEN, + VR_MODE_SBS_SCREEN, VR_MODE_STEREO_SCREEN, VR_MODE_MONO_6DOF, + VR_MODE_SBS_6DOF, VR_MODE_STEREO_6DOF }; void VR_GetResolution( engine_t* engine, int *pWidth, int *pHeight ); -void VR_InitRenderer( engine_t* engine, bool multiview ); +void VR_InitRenderer( engine_t* engine ); void VR_DestroyRenderer( engine_t* engine ); bool VR_InitFrame( engine_t* engine ); diff --git a/Common/x64Analyzer.cpp b/Common/x64Analyzer.cpp index b0bc65403f..04662498b5 100644 --- a/Common/x64Analyzer.cpp +++ b/Common/x64Analyzer.cpp @@ -188,7 +188,7 @@ bool X86AnalyzeMOV(const unsigned char *codePtr, LSInstructionInfo &info) break; default: - ERROR_LOG(CPU, "Unhandled disasm case in write handler!\n\nPlease implement or avoid."); + ERROR_LOG(Log::CPU, "Unhandled disasm case in write handler!\n\nPlease implement or avoid."); return false; } } diff --git a/Common/x64Emitter.cpp b/Common/x64Emitter.cpp index 814fc7e0d6..2dbe577c29 100644 --- a/Common/x64Emitter.cpp +++ b/Common/x64Emitter.cpp @@ -1322,7 +1322,7 @@ void XEmitter::XOR (int bits, const OpArg &a1, const OpArg &a2) {CheckFlags(); W void XEmitter::MOV (int bits, const OpArg &a1, const OpArg &a2) { if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) - ERROR_LOG(JIT, "Redundant MOV @ %p - bug in JIT?", code); + ERROR_LOG(Log::JIT, "Redundant MOV @ %p - bug in JIT?", code); WriteNormalOp(this, bits, nrmMOV, a1, a2); } void XEmitter::TEST(int bits, const OpArg &a1, const OpArg &a2) {CheckFlags(); WriteNormalOp(this, bits, nrmTEST, a1, a2);} diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index aa81165031..ebc140c389 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -109,7 +109,7 @@ bool AVIDump::CreateAVI() { const char *filename = s_format_context->filename; snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", video_file_name.c_str()); #endif - INFO_LOG(COMMON, "Recording Video to: %s", video_file_name.ToVisualString().c_str()); + INFO_LOG(Log::Common, "Recording Video to: %s", video_file_name.ToVisualString().c_str()); // Make sure that the path exists if (!File::Exists(GetSysDirectory(DIRECTORY_VIDEO))) @@ -168,9 +168,9 @@ bool AVIDump::CreateAVI() { return false; #endif - NOTICE_LOG(G3D, "Opening file %s for dumping", filename); + NOTICE_LOG(Log::G3D, "Opening file %s for dumping", filename); if (avio_open(&s_format_context->pb, filename, AVIO_FLAG_WRITE) < 0 || avformat_write_header(s_format_context, nullptr)) { - WARN_LOG(G3D, "Could not open %s", filename); + WARN_LOG(Log::G3D, "Could not open %s", filename); return false; } @@ -264,10 +264,10 @@ void AVIDump::AddFrame() { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) av_packet_unref(&pkt); if (error < 0 && error != AVERROR(EAGAIN) && error != AVERROR_EOF) - ERROR_LOG(G3D, "Error while encoding video: %d", error); + ERROR_LOG(Log::G3D, "Error while encoding video: %d", error); #else if (error < 0) - ERROR_LOG(G3D, "Error while encoding video: %d", error); + ERROR_LOG(Log::G3D, "Error while encoding video: %d", error); #endif #endif delete[] flipbuffer; @@ -280,7 +280,7 @@ void AVIDump::Stop() { CloseFile(); s_file_index = 0; #endif - NOTICE_LOG(G3D, "Stopping frame dump"); + NOTICE_LOG(Log::G3D, "Stopping frame dump"); } void AVIDump::CloseFile() { diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 6494760a24..f0d00747a6 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -83,6 +83,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "ClearToRAM", &flags_.ClearToRAM); CheckSetting(iniFile, gameID, "Force04154000Download", &flags_.Force04154000Download); CheckSetting(iniFile, gameID, "DrawSyncEatCycles", &flags_.DrawSyncEatCycles); + CheckSetting(iniFile, gameID, "DrawSyncInstant", &flags_.DrawSyncInstant); CheckSetting(iniFile, gameID, "FakeMipmapChange", &flags_.FakeMipmapChange); CheckSetting(iniFile, gameID, "RequireBufferedRendering", &flags_.RequireBufferedRendering); CheckSetting(iniFile, gameID, "RequireBlockTransfer", &flags_.RequireBlockTransfer); @@ -96,7 +97,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "ForceUMDDelay", &flags_.ForceUMDDelay); CheckSetting(iniFile, gameID, "ForceMax60FPS", &flags_.ForceMax60FPS); CheckSetting(iniFile, gameID, "GoWFramerateHack60", &flags_.GoWFramerateHack60); - CheckSetting(iniFile, gameID, "GoWFramerateHack30", &flags_.GoWFramerateHack30); + CheckSetting(iniFile, gameID, "FramerateHack30", &flags_.FramerateHack30); CheckSetting(iniFile, gameID, "JitInvalidationHack", &flags_.JitInvalidationHack); CheckSetting(iniFile, gameID, "HideISOFiles", &flags_.HideISOFiles); CheckSetting(iniFile, gameID, "MoreAccurateVMMUL", &flags_.MoreAccurateVMMUL); @@ -138,6 +139,8 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "TacticsOgreEliminateDebugReadback", &flags_.TacticsOgreEliminateDebugReadback); CheckSetting(iniFile, gameID, "FramebufferAllowLargeVerticalOffset", &flags_.FramebufferAllowLargeVerticalOffset); CheckSetting(iniFile, gameID, "DisableMemcpySlicing", &flags_.DisableMemcpySlicing); + CheckSetting(iniFile, gameID, "ForceEnableGPUReadback", &flags_.ForceEnableGPUReadback); + CheckSetting(iniFile, gameID, "UseFFMPEGFindStreamInfo", &flags_.UseFFMPEGFindStreamInfo); } void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { @@ -145,10 +148,11 @@ void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) CheckSetting(iniFile, gameID, "ForceMono", &vrCompat_.ForceMono); CheckSetting(iniFile, gameID, "IdentityViewHack", &vrCompat_.IdentityViewHack); CheckSetting(iniFile, gameID, "MirroringVariant", &vrCompat_.MirroringVariant); + CheckSetting(iniFile, gameID, "ProjectionHack", &vrCompat_.ProjectionHack); CheckSetting(iniFile, gameID, "Skyplane", &vrCompat_.Skyplane); CheckSetting(iniFile, gameID, "UnitsPerMeter", &vrCompat_.UnitsPerMeter); - NOTICE_LOG(G3D, "UnitsPerMeter for %s: %f", gameID.c_str(), vrCompat_.UnitsPerMeter); + NOTICE_LOG(Log::G3D, "UnitsPerMeter for %s: %f", gameID.c_str(), vrCompat_.UnitsPerMeter); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 1739112d36..75939a5340 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -22,7 +22,7 @@ #include // Compatibility flags are controlled by assets/compat.ini. -// Alternatively, if PSP/SYSTEM/compat.ini exists, it is merged on top, to enable editing +// Alternatively, if PSP/System/compat.ini exists, it is merged on top, to enable editing // the file on Android for tests. // // This file is not meant to be user-editable, although is kept as a separate ini @@ -53,6 +53,7 @@ struct CompatFlags { bool ClearToRAM; bool Force04154000Download; bool DrawSyncEatCycles; + bool DrawSyncInstant; bool FakeMipmapChange; bool RequireBufferedRendering; bool RequireBlockTransfer; @@ -66,7 +67,7 @@ struct CompatFlags { bool ForceUMDDelay; bool ForceMax60FPS; bool GoWFramerateHack60; - bool GoWFramerateHack30; + bool FramerateHack30; bool JitInvalidationHack; bool HideISOFiles; bool MoreAccurateVMMUL; @@ -108,6 +109,8 @@ struct CompatFlags { bool TacticsOgreEliminateDebugReadback; bool FramebufferAllowLargeVerticalOffset; bool DisableMemcpySlicing; + bool ForceEnableGPUReadback; + bool UseFFMPEGFindStreamInfo; }; struct VRCompat { @@ -115,6 +118,7 @@ struct VRCompat { bool ForceFlatScreen; bool IdentityViewHack; int MirroringVariant; + bool ProjectionHack; bool Skyplane; float UnitsPerMeter; }; diff --git a/Core/Config.cpp b/Core/Config.cpp index f4d77b1de7..3c28b1e26e 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -39,7 +39,7 @@ #include "Common/CPUDetect.h" #include "Common/File/FileUtil.h" #include "Common/File/VFS/VFS.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Common/OSVersion.h" #include "Common/System/Display.h" #include "Common/System/System.h" @@ -81,6 +81,8 @@ static const char * const logSectionName = "LogDebug"; static const char * const logSectionName = "Log"; #endif +static bool TryUpdateSavedPath(Path *path); + std::string GPUBackendToString(GPUBackend backend) { switch (backend) { case GPUBackend::OPENGL: @@ -213,6 +215,7 @@ static const ConfigSetting generalSettings[] = { ConfigSetting("DisableHTTPS", &g_Config.bDisableHTTPS, false, CfgFlag::DONT_SAVE), ConfigSetting("AutoLoadSaveState", &g_Config.iAutoLoadSaveState, 0, CfgFlag::PER_GAME), ConfigSetting("EnableCheats", &g_Config.bEnableCheats, false, CfgFlag::PER_GAME | CfgFlag::REPORT), + ConfigSetting("EnablePlugins", &g_Config.bEnablePlugins, true, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("CwCheatRefreshRate", &g_Config.iCwCheatRefreshIntervalMs, 77, CfgFlag::PER_GAME), ConfigSetting("CwCheatScrollPosition", &g_Config.fCwCheatScrollPosition, 0.0f, CfgFlag::PER_GAME), ConfigSetting("GameListScrollPosition", &g_Config.fGameListScrollPosition, 0.0f, CfgFlag::DEFAULT), @@ -300,11 +303,13 @@ static const ConfigSetting generalSettings[] = { ConfigSetting("ShowMenuBar", &g_Config.bShowMenuBar, true, CfgFlag::DEFAULT), ConfigSetting("MemStickInserted", &g_Config.bMemStickInserted, true, CfgFlag::PER_GAME | CfgFlag::REPORT), - ConfigSetting("EnablePlugins", &g_Config.bLoadPlugins, true, CfgFlag::PER_GAME), + ConfigSetting("LoadPlugins", &g_Config.bLoadPlugins, true, CfgFlag::PER_GAME), ConfigSetting("IgnoreCompatSettings", &g_Config.sIgnoreCompatSettings, "", CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("RunBehindPauseMenu", &g_Config.bRunBehindPauseMenu, false, CfgFlag::DEFAULT), + + ConfigSetting("ShowGPOLEDs", &g_Config.bShowGPOLEDs, false, CfgFlag::PER_GAME), }; static bool DefaultSasThread() { @@ -314,7 +319,8 @@ static bool DefaultSasThread() { static const ConfigSetting achievementSettings[] = { // Core settings ConfigSetting("AchievementsEnable", &g_Config.bAchievementsEnable, true, CfgFlag::DEFAULT), - ConfigSetting("AchievementsChallengeMode", &g_Config.bAchievementsChallengeMode, true, CfgFlag::PER_GAME | CfgFlag::DEFAULT), + ConfigSetting("AchievementsEnableRAIntegration", &g_Config.bAchievementsEnableRAIntegration, false, CfgFlag::DEFAULT), + ConfigSetting("AchievementsChallengeMode", &g_Config.bAchievementsHardcoreMode, true, CfgFlag::PER_GAME | CfgFlag::DEFAULT), ConfigSetting("AchievementsEncoreMode", &g_Config.bAchievementsEncoreMode, false, CfgFlag::PER_GAME | CfgFlag::DEFAULT), ConfigSetting("AchievementsUnofficial", &g_Config.bAchievementsUnofficial, false, CfgFlag::PER_GAME | CfgFlag::DEFAULT), ConfigSetting("AchievementsLogBadMemReads", &g_Config.bAchievementsLogBadMemReads, false, CfgFlag::DEFAULT), @@ -353,16 +359,18 @@ static const ConfigSetting cpuSettings[] = { }; static int DefaultInternalResolution() { - // Auto on Windows and Linux, 2x on large screens, 1x elsewhere. + // Auto on Windows and Linux, 2x on large screens and iOS, 1x elsewhere. #if defined(USING_WIN_UI) || defined(USING_QT_UI) return 0; +#elif PPSSPP_PLATFORM(IOS) + return 2; #else if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { return 4; } int longestDisplaySide = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)); int scale = longestDisplaySide >= 1000 ? 2 : 1; - INFO_LOG(G3D, "Longest display side: %d pixels. Choosing scale %d", longestDisplaySide, scale); + INFO_LOG(Log::G3D, "Longest display side: %d pixels. Choosing scale %d", longestDisplaySide, scale); return scale; #endif } @@ -376,7 +384,7 @@ static int DefaultFastForwardMode() { } static int DefaultAndroidHwScale() { -#ifdef __ANDROID__ +#if PPSSPP_PLATFORM(ANDROID) if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19 || System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_TV) { // Arbitrary cutoff at Kitkat - modern devices are usually powerful enough that hw scaling // doesn't really help very much and mostly causes problems. See #11151 @@ -415,7 +423,7 @@ static int DefaultGPUBackend() { #if PPSSPP_PLATFORM(WINDOWS) // If no Vulkan, use Direct3D 11 on Windows 8+ (most importantly 10.) - if (DoesVersionMatchWindows(6, 2, 0, 0, true)) { + if (IsWin8OrHigher()) { return (int)GPUBackend::DIRECT3D11; } #elif PPSSPP_PLATFORM(ANDROID) @@ -440,13 +448,18 @@ static int DefaultGPUBackend() { return (int)GPUBackend::VULKAN; } #endif + #elif PPSSPP_PLATFORM(MAC) + #if PPSSPP_ARCH(ARM64) return (int)GPUBackend::VULKAN; #else // On Intel (generally older Macs) default to OpenGL. return (int)GPUBackend::OPENGL; #endif + +#elif PPSSPP_PLATFORM(IOS_APP_STORE) + return (int)GPUBackend::VULKAN; #endif // TODO: On some additional Linux platforms, we should also default to Vulkan. @@ -473,7 +486,7 @@ int Config::NextValidBackend() { } if (failed.count((GPUBackend)iGPUBackend)) { - ERROR_LOG(LOADER, "Graphics backend failed for %d, trying another", iGPUBackend); + ERROR_LOG(Log::Loader, "Graphics backend failed for %d, trying another", iGPUBackend); #if !PPSSPP_PLATFORM(UWP) if (!failed.count(GPUBackend::VULKAN) && VulkanMayBeAvailable()) { @@ -481,7 +494,7 @@ int Config::NextValidBackend() { } #endif #if PPSSPP_PLATFORM(WINDOWS) - if (!failed.count(GPUBackend::DIRECT3D11) && DoesVersionMatchWindows(6, 1, 0, 0, true)) { + if (!failed.count(GPUBackend::DIRECT3D11) && IsWin7OrHigher()) { return (int)GPUBackend::DIRECT3D11; } #endif @@ -498,7 +511,7 @@ int Config::NextValidBackend() { // They've all failed. Let them try the default - or on Android, OpenGL. sFailedGPUBackends += ",ALL"; - ERROR_LOG(LOADER, "All graphics backends failed"); + ERROR_LOG(Log::Loader, "All graphics backends failed"); #if PPSSPP_PLATFORM(ANDROID) return (int)GPUBackend::OPENGL; #else @@ -509,7 +522,7 @@ int Config::NextValidBackend() { return iGPUBackend; } -bool Config::IsBackendEnabled(GPUBackend backend, bool validate) { +bool Config::IsBackendEnabled(GPUBackend backend) { std::vector split; SplitString(sDisabledGPUBackends, ',', split); @@ -528,10 +541,8 @@ bool Config::IsBackendEnabled(GPUBackend backend, bool validate) { if (backend != GPUBackend::OPENGL) return false; #elif PPSSPP_PLATFORM(WINDOWS) - if (validate) { - if (backend == GPUBackend::DIRECT3D11 && !DoesVersionMatchWindows(6, 0, 0, 0, true)) - return false; - } + if (backend == GPUBackend::DIRECT3D11 && !IsVistaOrHigher()) + return false; #else if (backend == GPUBackend::DIRECT3D11 || backend == GPUBackend::DIRECT3D9) return false; @@ -541,11 +552,8 @@ bool Config::IsBackendEnabled(GPUBackend backend, bool validate) { if (backend == GPUBackend::OPENGL) return false; #endif - if (validate) { - if (backend == GPUBackend::VULKAN && !VulkanMayBeAvailable()) - return false; - } - + if (backend == GPUBackend::VULKAN && !VulkanMayBeAvailable()) + return false; return true; } @@ -601,6 +609,7 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", CfgFlag::DEFAULT), #endif ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", CfgFlag::DEFAULT), + ConfigSetting("CameraMirrorHorizontal", &g_Config.bCameraMirrorHorizontal, false, CfgFlag::DEFAULT), ConfigSetting("AndroidFramerateMode", &g_Config.iDisplayFramerateMode, 1, CfgFlag::DEFAULT), ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, CfgFlag::DONT_SAVE), ConfigSetting("UseGeometryShader", &g_Config.bUseGeometryShader, false, CfgFlag::PER_GAME), @@ -640,6 +649,10 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("FullScreenMulti", &g_Config.bFullScreenMulti, false, CfgFlag::DEFAULT), #endif +#if PPSSPP_PLATFORM(IOS) + ConfigSetting("AppSwitchMode", &g_Config.iAppSwitchMode, (int)AppSwitchMode::DOUBLE_SWIPE_INDICATOR, CfgFlag::DEFAULT), +#endif + ConfigSetting("BufferFiltering", &g_Config.iDisplayFilter, SCALE_LINEAR, CfgFlag::PER_GAME), ConfigSetting("DisplayOffsetX", &g_Config.fDisplayOffsetX, 0.5f, CfgFlag::PER_GAME), ConfigSetting("DisplayOffsetY", &g_Config.fDisplayOffsetY, 0.5f, CfgFlag::PER_GAME), @@ -685,6 +698,8 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("UberShaderVertex", &g_Config.bUberShaderVertex, true, CfgFlag::DEFAULT), ConfigSetting("UberShaderFragment", &g_Config.bUberShaderFragment, true, CfgFlag::DEFAULT), + + ConfigSetting("DisplayRefreshRate", &g_Config.iDisplayRefreshRate, g_Config.iDisplayRefreshRate, CfgFlag::PER_GAME), }; static const ConfigSetting soundSettings[] = { @@ -697,6 +712,9 @@ static const ConfigSetting soundSettings[] = { ConfigSetting("AchievementSoundVolume", &g_Config.iAchievementSoundVolume, 6, CfgFlag::PER_GAME), ConfigSetting("AudioDevice", &g_Config.sAudioDevice, "", CfgFlag::DEFAULT), ConfigSetting("AutoAudioDevice", &g_Config.bAutoAudioDevice, true, CfgFlag::DEFAULT), + ConfigSetting("AudioMixWithOthers", &g_Config.bAudioMixWithOthers, true, CfgFlag::DEFAULT), + ConfigSetting("AudioRespectSilentMode", &g_Config.bAudioRespectSilentMode, false, CfgFlag::DEFAULT), + ConfigSetting("UseNewAtrac", &g_Config.bUseNewAtrac, false, CfgFlag::DEFAULT), }; static bool DefaultShowTouchControls() { @@ -941,24 +959,22 @@ static const ConfigSetting themeSettings[] = { static const ConfigSetting vrSettings[] = { ConfigSetting("VREnable", &g_Config.bEnableVR, true, CfgFlag::PER_GAME), - ConfigSetting("VREnable6DoF", &g_Config.bEnable6DoF, true, CfgFlag::PER_GAME), + ConfigSetting("VREnable6DoF", &g_Config.bEnable6DoF, false, CfgFlag::PER_GAME), ConfigSetting("VREnableStereo", &g_Config.bEnableStereo, false, CfgFlag::PER_GAME), - ConfigSetting("VREnableMotions", &g_Config.bEnableMotions, true, CfgFlag::PER_GAME), ConfigSetting("VRForce72Hz", &g_Config.bForce72Hz, true, CfgFlag::PER_GAME), + ConfigSetting("VRForce", &g_Config.bForceVR, false, CfgFlag::DEFAULT), + ConfigSetting("VRImmersiveMode", &g_Config.bEnableImmersiveVR, true, CfgFlag::PER_GAME), ConfigSetting("VRManualForceVR", &g_Config.bManualForceVR, false, CfgFlag::PER_GAME), ConfigSetting("VRPassthrough", &g_Config.bPassthrough, false, CfgFlag::PER_GAME), ConfigSetting("VRRescaleHUD", &g_Config.bRescaleHUD, true, CfgFlag::PER_GAME), ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f, CfgFlag::PER_GAME), ConfigSetting("VRCameraHeight", &g_Config.fCameraHeight, 0.0f, CfgFlag::PER_GAME), ConfigSetting("VRCameraSide", &g_Config.fCameraSide, 0.0f, CfgFlag::PER_GAME), - ConfigSetting("VRCameraPitch", &g_Config.iCameraPitch, 0, CfgFlag::PER_GAME), + ConfigSetting("VRCameraPitch", &g_Config.fCameraPitch, 0.0f, CfgFlag::PER_GAME), ConfigSetting("VRCanvasDistance", &g_Config.fCanvasDistance, 12.0f, CfgFlag::DEFAULT), ConfigSetting("VRCanvas3DDistance", &g_Config.fCanvas3DDistance, 3.0f, CfgFlag::DEFAULT), + ConfigSetting("VRFieldOfView", &g_Config.fFieldOfViewPercentage, 100.0f, CfgFlag::PER_GAME), ConfigSetting("VRHeadUpDisplayScale", &g_Config.fHeadUpDisplayScale, 0.3f, CfgFlag::PER_GAME), - ConfigSetting("VRMotionLength", &g_Config.fMotionLength, 0.5f, CfgFlag::DEFAULT), - ConfigSetting("VRHeadRotationScale", &g_Config.fHeadRotationScale, 5.0f, CfgFlag::PER_GAME), - ConfigSetting("VRHeadRotationEnabled", &g_Config.bHeadRotationEnabled, false, CfgFlag::PER_GAME), - ConfigSetting("VRHeadRotationSmoothing", &g_Config.bHeadRotationSmoothing, false, CfgFlag::PER_GAME), }; static const ConfigSectionSettings sections[] = { @@ -1084,7 +1100,7 @@ void Config::UpdateIniLocation(const char *iniFileName, const char *controllerIn bool Config::LoadAppendedConfig() { IniFile iniFile; if (!iniFile.Load(appendedConfigFileName_)) { - ERROR_LOG(LOADER, "Failed to read appended config '%s'.", appendedConfigFileName_.c_str()); + ERROR_LOG(Log::Loader, "Failed to read appended config '%s'.", appendedConfigFileName_.c_str()); return false; } @@ -1093,7 +1109,7 @@ bool Config::LoadAppendedConfig() { setting.Get(section); }); - INFO_LOG(LOADER, "Loaded appended config '%s'.", appendedConfigFileName_.c_str()); + INFO_LOG(Log::Loader, "Loaded appended config '%s'.", appendedConfigFileName_.c_str()); Save("Loaded appended config"); // Let's prevent reset return true; @@ -1125,12 +1141,12 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { UpdateIniLocation(iniFileName, controllerIniFilename); - INFO_LOG(LOADER, "Loading config: %s", iniFilename_.c_str()); + INFO_LOG(Log::Loader, "Loading config: %s", iniFilename_.c_str()); bSaveSettings = true; IniFile iniFile; if (!iniFile.Load(iniFilename_)) { - ERROR_LOG(LOADER, "Failed to read '%s'. Setting config to default.", iniFilename_.c_str()); + ERROR_LOG(Log::Loader, "Failed to read '%s'. Setting config to default.", iniFilename_.c_str()); // Continue anyway to initialize the config. } @@ -1140,6 +1156,9 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { iRunCount++; + // For iOS, issue #19211 + TryUpdateSavedPath(¤tDirectory); + // This check is probably not really necessary here anyway, you can always // press Home or Browse if you're in a bad directory. if (!File::Exists(currentDirectory)) @@ -1161,6 +1180,14 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { if (iMaxRecent == 0) iMaxRecent = 60; + // Fix JIT setting if no longer available. + if (!System_GetPropertyBool(SYSPROP_CAN_JIT)) { + if (iCpuCore == (int)CPUCore::JIT || iCpuCore == (int)CPUCore::JIT_IR) { + WARN_LOG(Log::Loader, "Forcing JIT off due to unavailablility"); + iCpuCore = (int)CPUCore::IR_INTERPRETER; + } + } + if (iMaxRecent > 0) { private_->ResetRecentIsosThread(); std::lock_guard guard(private_->recentIsosLock); @@ -1223,6 +1250,13 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { ResetControlLayout(); } + // Force JIT setting to a valid value for the current system configuration. + if (!System_GetPropertyBool(SYSPROP_CAN_JIT)) { + if (g_Config.iCpuCore == (int)CPUCore::JIT || g_Config.iCpuCore == (int)CPUCore::JIT_IR) { + g_Config.iCpuCore = (int)CPUCore::IR_INTERPRETER; + } + } + const char *gitVer = PPSSPP_GIT_VERSION; Version installed(gitVer); Version upgrade(upgradeVersion); @@ -1245,7 +1279,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { g_DownloadManager.StartDownloadWithCallback(versionUrl, Path(), http::ProgressBarMode::NONE, &DownloadCompletedCallback, "version", acceptMime); } - INFO_LOG(LOADER, "Loading controller config: %s", controllerIniFilename_.c_str()); + INFO_LOG(Log::Loader, "Loading controller config: %s", controllerIniFilename_.c_str()); bSaveSettings = true; LoadStandardControllerIni(); @@ -1261,7 +1295,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { PostLoadCleanup(false); - INFO_LOG(LOADER, "Config loaded: '%s' (%0.1f ms)", iniFilename_.c_str(), (time_now_d() - startTime) * 1000.0); + INFO_LOG(Log::Loader, "Config loaded: '%s' (%0.1f ms)", iniFilename_.c_str(), (time_now_d() - startTime) * 1000.0); } bool Config::Save(const char *saveReason) { @@ -1269,7 +1303,7 @@ bool Config::Save(const char *saveReason) { if (!IsFirstInstance()) { // TODO: Should we allow saving config if started from a different directory? // How do we tell? - WARN_LOG(LOADER, "Not saving config - secondary instances don't."); + WARN_LOG(Log::Loader, "Not saving config - secondary instances don't."); // Don't want to retry or something. return true; @@ -1283,7 +1317,7 @@ bool Config::Save(const char *saveReason) { CleanRecent(); IniFile iniFile; if (!iniFile.Load(iniFilename_)) { - WARN_LOG(LOADER, "Likely saving config for first time - couldn't read ini '%s'", iniFilename_.c_str()); + WARN_LOG(Log::Loader, "Likely saving config for first time - couldn't read ini '%s'", iniFilename_.c_str()); } // Need to do this somewhere... @@ -1345,28 +1379,28 @@ bool Config::Save(const char *saveReason) { playTimeTracker_.Save(playTime); if (!iniFile.Save(iniFilename_)) { - ERROR_LOG(LOADER, "Error saving config (%s)- can't write ini '%s'", saveReason, iniFilename_.c_str()); + ERROR_LOG(Log::Loader, "Error saving config (%s) - can't write ini '%s'", saveReason, iniFilename_.c_str()); return false; } - INFO_LOG(LOADER, "Config saved (%s): '%s' (%0.1f ms)", saveReason, iniFilename_.c_str(), (time_now_d() - startTime) * 1000.0); + INFO_LOG(Log::Loader, "Config saved (%s): '%s' (%0.1f ms)", saveReason, iniFilename_.c_str(), (time_now_d() - startTime) * 1000.0); if (!bGameSpecific) //otherwise we already did this in saveGameConfig() { IniFile controllerIniFile; if (!controllerIniFile.Load(controllerIniFilename_)) { - ERROR_LOG(LOADER, "Error saving controller config - can't read ini first '%s'", controllerIniFilename_.c_str()); + ERROR_LOG(Log::Loader, "Error saving controller config - can't read ini first '%s'", controllerIniFilename_.c_str()); } KeyMap::SaveToIni(controllerIniFile); if (!controllerIniFile.Save(controllerIniFilename_)) { - ERROR_LOG(LOADER, "Error saving config - can't write ini '%s'", controllerIniFilename_.c_str()); + ERROR_LOG(Log::Loader, "Error saving config - can't write ini '%s'", controllerIniFilename_.c_str()); return false; } - INFO_LOG(LOADER, "Controller config saved: %s", controllerIniFilename_.c_str()); + INFO_LOG(Log::Loader, "Controller config saved: %s", controllerIniFilename_.c_str()); } PostSaveCleanup(false); } else { - INFO_LOG(LOADER, "Not saving config"); + INFO_LOG(Log::Loader, "Not saving config"); } return true; @@ -1438,20 +1472,20 @@ void Config::NotifyUpdatedCpuCore() { void Config::DownloadCompletedCallback(http::Request &download) { if (download.ResultCode() != 200) { - ERROR_LOG(LOADER, "Failed to download %s: %d", download.url().c_str(), download.ResultCode()); + ERROR_LOG(Log::Loader, "Failed to download %s: %d", download.url().c_str(), download.ResultCode()); return; } std::string data; download.buffer().TakeAll(&data); if (data.empty()) { - ERROR_LOG(LOADER, "Version check: Empty data from server!"); + ERROR_LOG(Log::Loader, "Version check: Empty data from server!"); return; } json::JsonReader reader(data.c_str(), data.size()); const json::JsonGet root = reader.root(); if (!root) { - ERROR_LOG(LOADER, "Failed to parse json"); + ERROR_LOG(Log::Loader, "Failed to parse json"); return; } @@ -1464,16 +1498,16 @@ void Config::DownloadCompletedCallback(http::Request &download) { Version dismissed(g_Config.dismissedVersion); if (!installed.IsValid()) { - ERROR_LOG(LOADER, "Version check: Local version string invalid. Build problems? %s", PPSSPP_GIT_VERSION); + ERROR_LOG(Log::Loader, "Version check: Local version string invalid. Build problems? %s", PPSSPP_GIT_VERSION); return; } if (!upgrade.IsValid()) { - ERROR_LOG(LOADER, "Version check: Invalid server version: %s", version.c_str()); + ERROR_LOG(Log::Loader, "Version check: Invalid server version: %s", version.c_str()); return; } if (installed >= upgrade) { - INFO_LOG(LOADER, "Version check: Already up to date, erasing any upgrade message"); + INFO_LOG(Log::Loader, "Version check: Already up to date, erasing any upgrade message"); g_Config.upgradeMessage.clear(); g_Config.upgradeVersion = upgrade.ToString(); g_Config.dismissedVersion.clear(); @@ -1515,11 +1549,41 @@ void Config::RemoveRecent(const std::string &file) { private_->ResetRecentIsosThread(); std::lock_guard guard(private_->recentIsosLock); - const auto &filename = File::ResolvePath(file); - std::remove_if(recentIsos.begin(), recentIsos.end(), [filename](const auto &str) { - const auto &recent = File::ResolvePath(str); + const std::string filename = File::ResolvePath(file); + auto iter = std::remove_if(recentIsos.begin(), recentIsos.end(), [filename](const auto &str) { + const std::string recent = File::ResolvePath(str); return filename == recent; }); + // remove_if is weird. + recentIsos.erase(iter, recentIsos.end()); +} + +// On iOS, the path to the app documents directory changes on each launch. +// Example path: +// /var/mobile/Containers/Data/Application/0E0E89DE-8D8E-485A-860C-700D8BC87B86/Documents/PSP/GAME/SuicideBarbie +// The GUID part changes on each launch. +static bool TryUpdateSavedPath(Path *path) { +#if PPSSPP_PLATFORM(IOS) + INFO_LOG(Log::Loader, "Original path: %s", path->c_str()); + std::string pathStr = path->ToString(); + + const std::string_view applicationRoot = "/var/mobile/Containers/Data/Application/"; + if (startsWith(pathStr, applicationRoot)) { + size_t documentsPos = pathStr.find("/Documents/"); + if (documentsPos == std::string::npos) { + return false; + } + std::string memstick = g_Config.memStickDirectory.ToString(); + size_t memstickDocumentsPos = memstick.find("/Documents"); // Note: No trailing slash, or we won't find it. + *path = Path(memstick.substr(0, memstickDocumentsPos) + pathStr.substr(documentsPos)); + return true; + } else { + // Path can't be auto-updated. + return false; + } +#else + return false; +#endif } void Config::CleanRecent() { @@ -1532,6 +1596,10 @@ void Config::CleanRecent() { std::lock_guard guard(private_->recentIsosLock); std::vector cleanedRecent; + if (recentIsos.empty()) { + INFO_LOG(Log::Loader, "No recents list found."); + } + for (size_t i = 0; i < recentIsos.size(); i++) { bool exists = false; Path path = Path(recentIsos[i]); @@ -1539,6 +1607,12 @@ void Config::CleanRecent() { case PathType::CONTENT_URI: case PathType::NATIVE: exists = File::Exists(path); + if (!exists) { + if (TryUpdateSavedPath(&path)) { + exists = File::Exists(path); + INFO_LOG(Log::Loader, "Exists=%d when checking updated path: %s", exists, path.c_str()); + } + } break; default: FileLoader *loader = ConstructFileLoader(path); @@ -1548,17 +1622,20 @@ void Config::CleanRecent() { } if (exists) { + std::string pathStr = path.ToString(); // Make sure we don't have any redundant items. - auto duplicate = std::find(cleanedRecent.begin(), cleanedRecent.end(), recentIsos[i]); + auto duplicate = std::find(cleanedRecent.begin(), cleanedRecent.end(), pathStr); if (duplicate == cleanedRecent.end()) { - cleanedRecent.push_back(recentIsos[i]); + cleanedRecent.push_back(pathStr); } + } else { + DEBUG_LOG(Log::Loader, "Removed %s from recent. errno=%d", path.c_str(), errno); } } double recentTime = time_now_d() - startTime; if (recentTime > 0.1) { - INFO_LOG(SYSTEM, "CleanRecent took %0.2f", recentTime); + INFO_LOG(Log::System, "CleanRecent took %0.2f", recentTime); } recentIsos = cleanedRecent; }); @@ -1717,7 +1794,7 @@ bool Config::loadGameConfig(const std::string &pGameId, const std::string &title Path iniFileNameFull = getGameConfigFile(pGameId); if (!hasGameConfig(pGameId)) { - DEBUG_LOG(LOADER, "No game-specific settings found in %s. Using global defaults.", iniFileNameFull.c_str()); + DEBUG_LOG(Log::Loader, "No game-specific settings found in %s. Using global defaults.", iniFileNameFull.c_str()); return false; } @@ -1732,7 +1809,7 @@ bool Config::loadGameConfig(const std::string &pGameId, const std::string &title if (sscanf(it.second.c_str(), "%f", &value)) { mPostShaderSetting[it.first] = value; } else { - WARN_LOG(LOADER, "Invalid float value string for param %s: '%s'", it.first.c_str(), it.second.c_str()); + WARN_LOG(Log::Loader, "Invalid float value string for param %s: '%s'", it.first.c_str(), it.second.c_str()); } } @@ -1797,7 +1874,7 @@ void Config::unloadGameConfig() { void Config::LoadStandardControllerIni() { IniFile controllerIniFile; if (!controllerIniFile.Load(controllerIniFilename_)) { - ERROR_LOG(LOADER, "Failed to read %s. Setting controller config to default.", controllerIniFilename_.c_str()); + ERROR_LOG(Log::Loader, "Failed to read %s. Setting controller config to default.", controllerIniFilename_.c_str()); KeyMap::RestoreDefault(); } else { // Continue anyway to initialize the config. It will just restore the defaults. @@ -1861,7 +1938,7 @@ void PlayTimeTracker::Start(const std::string &gameId) { if (gameId.empty()) { return; } - INFO_LOG(SYSTEM, "GameTimeTracker::Start(%s)", gameId.c_str()); + INFO_LOG(Log::System, "GameTimeTracker::Start(%s)", gameId.c_str()); auto iter = tracker_.find(std::string(gameId)); if (iter != tracker_.end()) { @@ -1884,7 +1961,7 @@ void PlayTimeTracker::Stop(const std::string &gameId) { return; } - INFO_LOG(SYSTEM, "GameTimeTracker::Stop(%s)", gameId.c_str()); + INFO_LOG(Log::System, "GameTimeTracker::Stop(%s)", gameId.c_str()); auto iter = tracker_.find(std::string(gameId)); if (iter != tracker_.end()) { @@ -1897,7 +1974,7 @@ void PlayTimeTracker::Stop(const std::string &gameId) { } // Shouldn't happen, ignore this case. - WARN_LOG(SYSTEM, "GameTimeTracker::Stop called without corresponding GameTimeTracker::Start"); + WARN_LOG(Log::System, "GameTimeTracker::Stop called without corresponding GameTimeTracker::Start"); } void PlayTimeTracker::Load(const Section *section) { diff --git a/Core/Config.h b/Core/Config.h index c6f6e55a9a..6767eb3725 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -158,7 +158,9 @@ public: std::string sD3D11Device; // Windows only std::string sCameraDevice; std::string sMicDevice; + bool bCameraMirrorHorizontal; int iDisplayFramerateMode; // enum DisplayFramerateMode. Android-only. + int iDisplayRefreshRate = 60; bool bSoftwareRendering; bool bSoftwareRenderingJit; @@ -209,6 +211,7 @@ public: bool bTextureBackoffCache; bool bVertexDecoderJit; + int iAppSwitchMode; bool bFullScreen; bool bFullScreenMulti; int iForceFullScreen = -1; // -1 = nope, 0 = force off, 1 = force on (not saved.) @@ -237,6 +240,7 @@ public: int iAutoLoadSaveState; // 0 = off, 1 = oldest, 2 = newest, >2 = slot number + 3 bool bEnableCheats; bool bReloadCheats; + bool bEnablePlugins; int iCwCheatRefreshIntervalMs; float fCwCheatScrollPosition; float fGameListScrollPosition; @@ -263,6 +267,9 @@ public: bool bRenderDuplicateFrames; bool bRenderMultiThreading; + // HW debug + bool bShowGPOLEDs; + // Sound bool bEnableSound; int iAudioBackend; @@ -273,6 +280,11 @@ public: bool bExtraAudioBuffering; // For bluetooth std::string sAudioDevice; bool bAutoAudioDevice; + bool bUseNewAtrac; + + // iOS only for now + bool bAudioMixWithOthers; + bool bAudioRespectSilentMode; // UI bool bShowDebuggerOnLoad; @@ -469,22 +481,20 @@ public: bool bEnableVR; bool bEnable6DoF; bool bEnableStereo; - bool bEnableMotions; + bool bEnableImmersiveVR; bool bForce72Hz; + bool bForceVR; bool bManualForceVR; bool bPassthrough; bool bRescaleHUD; float fCameraDistance; float fCameraHeight; float fCameraSide; + float fCameraPitch; float fCanvasDistance; float fCanvas3DDistance; + float fFieldOfViewPercentage; float fHeadUpDisplayScale; - float fMotionLength; - float fHeadRotationScale; - bool bHeadRotationEnabled; - bool bHeadRotationSmoothing; - int iCameraPitch; // Debugger int iDisasmWindowX; @@ -522,12 +532,13 @@ public: // Retro Achievement settings // Copied from Duckstation, we might want to remove some. bool bAchievementsEnable; - bool bAchievementsChallengeMode; + bool bAchievementsHardcoreMode; bool bAchievementsEncoreMode; bool bAchievementsUnofficial; bool bAchievementsSoundEffects; bool bAchievementsLogBadMemReads; bool bAchievementsSaveStateInHardcoreMode; + bool bAchievementsEnableRAIntegration; // Positioning of the various notifications int iAchievementsLeaderboardTrackerPos; @@ -594,7 +605,7 @@ public: bool IsPortrait() const; int NextValidBackend(); - bool IsBackendEnabled(GPUBackend backend, bool validate = true); + bool IsBackendEnabled(GPUBackend backend); bool UseFullScreen() const { if (iForceFullScreen != -1) diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 3e762d632c..38b111ca2e 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -126,6 +126,12 @@ enum class BackgroundAnimation { MOVING_BACKGROUND = 4, }; +// iOS only +enum class AppSwitchMode { + SINGLE_SWIPE_NO_INDICATOR = 0, + DOUBLE_SWIPE_INDICATOR = 1, +}; + // for Config.iShowStatusFlags enum class ShowStatusFlags { FPS_COUNTER = 1 << 1, @@ -164,7 +170,7 @@ enum class DebugOverlay : int { FRAME_PROFILE, #endif CONTROL, - AUDIO, + Audio, GPU_PROFILE, GPU_ALLOCATOR, FRAMEBUFFER_LIST, diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index 94765edd64..ad38aeca91 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -57,7 +57,7 @@ float ControlMapper::GetDeviceAxisThreshold(int device, const InputMapping &mapp if (absCoValue > 0.0f) { // Bias down the threshold if the other axis is active. float biasedThreshold = AXIS_BIND_THRESHOLD * (1.0f - absCoValue * 0.35f); - // INFO_LOG(SYSTEM, "coValue: %f threshold: %f", absCoValue, biasedThreshold); + // INFO_LOG(Log::System, "coValue: %f threshold: %f", absCoValue, biasedThreshold); return biasedThreshold; } } @@ -309,7 +309,7 @@ float ControlMapper::MapAxisValue(float value, int vkId, const InputMapping &map if (direction == -1) { ranged = 1.0f - ranged; } - // NOTICE_LOG(SYSTEM, "rawValue: %f other: %f signed: %f ranged: %f", iter->second, valueOther, signedValue, ranged); + // NOTICE_LOG(Log::System, "rawValue: %f other: %f signed: %f ranged: %f", iter->second, valueOther, signedValue, ranged); return ranged; } else { return value; @@ -506,13 +506,13 @@ bool ControlMapper::UpdatePSPState(const InputMapping &changedMapping, double no bool bValue = value >= threshold; if (virtKeys_[i] != value) { - // INFO_LOG(G3D, "vkeyanalog %s : %f", KeyMap::GetVirtKeyName(vkId), value); + // INFO_LOG(Log::G3D, "vkeyanalog %s : %f", KeyMap::GetVirtKeyName(vkId), value); onVKeyAnalog(changedMapping.deviceId, vkId, value); virtKeys_[i] = value; } if (!bPrevValue && bValue) { - // INFO_LOG(G3D, "vkeyon %s", KeyMap::GetVirtKeyName(vkId)); + // INFO_LOG(Log::G3D, "vkeyon %s", KeyMap::GetVirtKeyName(vkId)); onVKey(vkId, true); virtKeyOn_[vkId - VIRTKEY_FIRST] = true; @@ -520,7 +520,7 @@ bool ControlMapper::UpdatePSPState(const InputMapping &changedMapping, double no updateAnalogSticks = true; } } else if (bPrevValue && !bValue) { - // INFO_LOG(G3D, "vkeyoff %s", KeyMap::GetVirtKeyName(vkId)); + // INFO_LOG(Log::G3D, "vkeyoff %s", KeyMap::GetVirtKeyName(vkId)); onVKey(vkId, false); virtKeyOn_[vkId - VIRTKEY_FIRST] = false; @@ -563,7 +563,7 @@ bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) { // TODO: See if this can be simplified further somehow. if ((key.flags & KEY_DOWN) && key.keyCode == NKCODE_BACK) { bool mappingFound = KeyMap::InputMappingToPspButton(mapping, nullptr); - DEBUG_LOG(SYSTEM, "Key: %d DeviceId: %d", key.keyCode, key.deviceId); + DEBUG_LOG(Log::System, "Key: %d DeviceId: %d", key.keyCode, key.deviceId); if (!mappingFound || key.deviceId == DEVICE_ID_DEFAULT) { *pauseTrigger = true; return true; @@ -577,7 +577,7 @@ bool ControlMapper::Key(const KeyInput &key, bool *pauseTrigger) { } void ControlMapper::ToggleSwapAxes() { - std::lock_guard guard(mutex_); + // Note: The lock is already locked here. swapAxes_ = !swapAxes_; @@ -682,7 +682,7 @@ void ControlMapper::PSPKey(int deviceId, int pspKeyCode, int flags) { onVKeyAnalog(deviceId, pspKeyCode, 0.0f); } } else { - // INFO_LOG(SYSTEM, "pspKey %d %d", pspKeyCode, flags); + // INFO_LOG(Log::System, "pspKey %d %d", pspKeyCode, flags); if (flags & KEY_DOWN) updatePSPButtons_(pspKeyCode, 0); if (flags & KEY_UP) @@ -715,7 +715,7 @@ void ControlMapper::onVKeyAnalog(int deviceId, int vkey, float value) { float oppVal = virtKeys_[oppositeVKey - VIRTKEY_FIRST]; if (oppVal != 0.0f) { value -= oppVal; - // NOTICE_LOG(SCECTRL, "Reducing %f by %f (from %08x : %s)", value, oppVal, oppositeVKey, KeyMap::GetPspButtonName(oppositeVKey).c_str()); + // NOTICE_LOG(Log::sceCtrl, "Reducing %f by %f (from %08x : %s)", value, oppVal, oppositeVKey, KeyMap::GetPspButtonName(oppositeVKey).c_str()); } } SetPSPAxis(deviceId, stick, axis, sign * value); diff --git a/Core/Core.cpp b/Core/Core.cpp index aad45dabbd..e30f5825d8 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -43,6 +43,7 @@ #include "Core/MIPS/MIPS.h" #include "Core/HLE/sceNetAdhoc.h" #include "GPU/Debugger/Stepping.h" +#include "Core/MIPS/MIPSTracer.h" #ifdef _WIN32 #include "Common/CommonWindows.h" @@ -334,6 +335,9 @@ bool Core_Run(GraphicsContext *ctx) { void Core_EnableStepping(bool step, const char *reason, u32 relatedAddress) { if (step) { + // Stop the tracer + mipsTracer.stop_tracing(); + Core_UpdateState(CORE_STEPPING); steppingCounter++; _assert_msg_(reason != nullptr, "No reason specified for break"); @@ -404,16 +408,16 @@ void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionTy const char *desc = MemoryExceptionTypeAsString(type); // In jit, we only flush PC when bIgnoreBadMemAccess is off. if ((g_Config.iCpuCore == (int)CPUCore::JIT || g_Config.iCpuCore == (int)CPUCore::JIT_IR) && g_Config.bIgnoreBadMemAccess) { - WARN_LOG(MEMMAP, "%s: Invalid access at %08x (size %08x)", desc, address, accessSize); + WARN_LOG(Log::MemMap, "%s: Invalid access at %08x (size %08x)", desc, address, accessSize); } else { - WARN_LOG(MEMMAP, "%s: Invalid access at %08x (size %08x) PC %08x LR %08x", desc, address, accessSize, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); + WARN_LOG(Log::MemMap, "%s: Invalid access at %08x (size %08x) PC %08x LR %08x", desc, address, accessSize, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); } if (!g_Config.bIgnoreBadMemAccess) { // Try to fetch a call stack, to start with. std::vector stackFrames = WalkCurrentStack(-1); std::string stackTrace = FormatStackTrace(stackFrames); - WARN_LOG(MEMMAP, "\n%s", stackTrace.c_str()); + WARN_LOG(Log::MemMap, "\n%s", stackTrace.c_str()); MIPSExceptionInfo &e = g_exceptionInfo; e = {}; @@ -432,16 +436,16 @@ void Core_MemoryExceptionInfo(u32 address, u32 accessSize, u32 pc, MemoryExcepti const char *desc = MemoryExceptionTypeAsString(type); // In jit, we only flush PC when bIgnoreBadMemAccess is off. if ((g_Config.iCpuCore == (int)CPUCore::JIT || g_Config.iCpuCore == (int)CPUCore::JIT_IR) && g_Config.bIgnoreBadMemAccess) { - WARN_LOG(MEMMAP, "%s: Invalid access at %08x (size %08x). %.*s", desc, address, accessSize, (int)additionalInfo.length(), additionalInfo.data()); + WARN_LOG(Log::MemMap, "%s: Invalid access at %08x (size %08x). %.*s", desc, address, accessSize, (int)additionalInfo.length(), additionalInfo.data()); } else { - WARN_LOG(MEMMAP, "%s: Invalid access at %08x (size %08x) PC %08x LR %08x %.*s", desc, address, accessSize, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA], (int)additionalInfo.length(), additionalInfo.data()); + WARN_LOG(Log::MemMap, "%s: Invalid access at %08x (size %08x) PC %08x LR %08x %.*s", desc, address, accessSize, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA], (int)additionalInfo.length(), additionalInfo.data()); } if (!g_Config.bIgnoreBadMemAccess || forceReport) { // Try to fetch a call stack, to start with. std::vector stackFrames = WalkCurrentStack(-1); std::string stackTrace = FormatStackTrace(stackFrames); - WARN_LOG(MEMMAP, "\n%s", stackTrace.c_str()); + WARN_LOG(Log::MemMap, "\n%s", stackTrace.c_str()); MIPSExceptionInfo &e = g_exceptionInfo; e = {}; @@ -459,7 +463,7 @@ void Core_MemoryExceptionInfo(u32 address, u32 accessSize, u32 pc, MemoryExcepti // Can't be ignored void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) { const char *desc = ExecExceptionTypeAsString(type); - WARN_LOG(MEMMAP, "%s: Invalid exec address %08x PC %08x LR %08x", desc, address, pc, currentMIPS->r[MIPS_REG_RA]); + WARN_LOG(Log::MemMap, "%s: Invalid exec address %08x PC %08x LR %08x", desc, address, pc, currentMIPS->r[MIPS_REG_RA]); MIPSExceptionInfo &e = g_exceptionInfo; e = {}; @@ -475,7 +479,7 @@ void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) { } void Core_Break(u32 pc) { - ERROR_LOG(CPU, "BREAK!"); + ERROR_LOG(Log::CPU, "BREAK!"); MIPSExceptionInfo &e = g_exceptionInfo; e = {}; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index c9acd32dc1..b73d036daf 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -139,7 +139,7 @@ Level3 ..\ffmpeg\WindowsInclude;..\ext\libchdr\include;..\ffmpeg\Windows\x86\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext;../ext/zstd/lib - _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WITH_UPNP;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;MINIUPNP_STATICLIB;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions) + RC_CLIENT_SUPPORTS_RAINTEGRATION;_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WITH_UPNP;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;MINIUPNP_STATICLIB;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions) StreamingSIMDExtensions2 Precise true @@ -166,7 +166,7 @@ Level3 ..\ffmpeg\WindowsInclude;..\ext\libchdr\include;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/glew;../ext/snappy;../ext/libpng17;../ext/zlib;../ext;../ext/zstd/lib;../ext/zstd/lib - _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WITH_UPNP;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;MINIUPNP_STATICLIB;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions) + RC_CLIENT_SUPPORTS_RAINTEGRATION;_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WITH_UPNP;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;MINIUPNP_STATICLIB;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions) NotSet Precise false @@ -257,7 +257,7 @@ false StreamingSIMDExtensions2 Precise - USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WITH_UPNP;WIN32;_ARCH_32=1;_M_IX86=1;_LIB;NDEBUG;_UNICODE;UNICODE;MINIUPNP_STATICLIB;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions) + RC_CLIENT_SUPPORTS_RAINTEGRATION;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WITH_UPNP;WIN32;_ARCH_32=1;_M_IX86=1;_LIB;NDEBUG;_UNICODE;UNICODE;MINIUPNP_STATICLIB;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions) Speed MultiThreaded true @@ -294,7 +294,7 @@ Speed false true - USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WITH_UPNP;WIN32;_ARCH_64=1;_M_X64=1;_LIB;NDEBUG;_UNICODE;UNICODE;MINIUPNP_STATICLIB;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions) + RC_CLIENT_SUPPORTS_RAINTEGRATION;USING_WIN_UI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WITH_UPNP;WIN32;_ARCH_64=1;_M_X64=1;_LIB;NDEBUG;_UNICODE;UNICODE;MINIUPNP_STATICLIB;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions) false MultiThreaded true @@ -566,6 +566,8 @@ + + @@ -573,6 +575,7 @@ + @@ -989,6 +992,7 @@ + true true @@ -1173,6 +1177,8 @@ + + @@ -1181,6 +1187,7 @@ + @@ -1400,6 +1407,7 @@ + true true diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 0918b045f4..e00f5b24ba 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -123,6 +123,9 @@ MIPS + + MIPS + MIPS @@ -1306,6 +1309,15 @@ Util + + HW + + + HLE\Libraries + + + HLE\Libraries + @@ -1338,6 +1350,9 @@ MIPS + + MIPS + MIPS @@ -2088,6 +2103,15 @@ Util + + HW + + + HLE\Libraries + + + HLE\Libraries + diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index e9fbea956d..b357dc2404 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -152,7 +152,7 @@ int RegisterEvent(const char *name, TimedCallback callback) { } void AntiCrashCallback(u64 userdata, int cyclesLate) { - ERROR_LOG(SAVESTATE, "Savestate broken: an unregistered event was called."); + ERROR_LOG(Log::SaveState, "Savestate broken: an unregistered event was called."); Core_EnableStepping(true, "savestate.crash", 0); } @@ -366,7 +366,7 @@ void RemoveEvent(int event_type) void ProcessEvents() { while (first) { if (first->time <= (s64)GetTicks()) { - // INFO_LOG(CPU, "%s (%lld, %lld) ", first->name ? first->name : "?", (u64)GetTicks(), (u64)first->time); + // INFO_LOG(Log::CPU, "%s (%lld, %lld) ", first->name ? first->name : "?", (u64)GetTicks(), (u64)first->time); Event *evt = first; first = first->next; if (evt->type >= 0 && evt->type < event_types.size()) { @@ -425,7 +425,7 @@ void Advance() { void LogPendingEvents() { Event *ptr = first; while (ptr) { - //INFO_LOG(CPU, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type); + //INFO_LOG(Log::CPU, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type); ptr = ptr->next; } } @@ -447,7 +447,7 @@ void Idle(int maxIdle) { if (cyclesDown < 0) cyclesDown = 0; - // VERBOSE_LOG(CPU, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(CPU_HZ * 0.001f)); + // VERBOSE_LOG(Log::CPU, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(CPU_HZ * 0.001f)); idledCycles += cyclesDown; currentMIPS->downcount -= cyclesDown; @@ -499,7 +499,7 @@ void DoState(PointerWrap &p) { int current = n; Do(p, n); if (n > current) { - WARN_LOG(SAVESTATE, "Savestate failure: more events than current (can't ever remove an event)"); + WARN_LOG(Log::SaveState, "Savestate failure: more events than current (can't ever remove an event)"); p.SetError(p.ERROR_FAILURE); return; } diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index 1789cb2c94..0f0d344cff 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -47,11 +47,11 @@ void MemCheck::Log(u32 addr, bool write, int size, u32 pc, const char *reason) { if (result & BREAK_ACTION_LOG) { const char *type = write ? "Write" : "Read"; if (logFormat.empty()) { - NOTICE_LOG(MEMMAP, "CHK %s%i(%s) at %08x (%s), PC=%08x (%s)", type, size * 8, reason, addr, g_symbolMap->GetDescription(addr).c_str(), pc, g_symbolMap->GetDescription(pc).c_str()); + NOTICE_LOG(Log::MemMap, "CHK %s%i(%s) at %08x (%s), PC=%08x (%s)", type, size * 8, reason, addr, g_symbolMap->GetDescription(addr).c_str(), pc, g_symbolMap->GetDescription(pc).c_str()); } else { std::string formatted; CBreakPoints::EvaluateLogFormat(currentDebugMIPS, logFormat, formatted); - NOTICE_LOG(MEMMAP, "CHK %s%i(%s) at %08x: %s", type, size * 8, reason, addr, formatted.c_str()); + NOTICE_LOG(Log::MemMap, "CHK %s%i(%s) at %08x: %s", type, size * 8, reason, addr, formatted.c_str()); } } } @@ -323,11 +323,11 @@ BreakAction CBreakPoints::ExecBreakPoint(u32 addr) { if (info.result & BREAK_ACTION_LOG) { if (info.logFormat.empty()) { - NOTICE_LOG(JIT, "BKP PC=%08x (%s)", addr, g_symbolMap->GetDescription(addr).c_str()); + NOTICE_LOG(Log::JIT, "BKP PC=%08x (%s)", addr, g_symbolMap->GetDescription(addr).c_str()); } else { std::string formatted; CBreakPoints::EvaluateLogFormat(currentDebugMIPS, info.logFormat, formatted); - NOTICE_LOG(JIT, "BKP PC=%08x: %s", addr, formatted.c_str()); + NOTICE_LOG(Log::JIT, "BKP PC=%08x: %s", addr, formatted.c_str()); } } if ((info.result & BREAK_ACTION_PAUSE) && coreState != CORE_POWERUP) { @@ -686,7 +686,7 @@ bool CBreakPoints::EvaluateLogFormat(DebugInterface *cpu, const std::string &fmt size_t pos = 0; while (pos < fmt.size()) { - size_t next = fmt.find_first_of("{", pos); + size_t next = fmt.find_first_of('{', pos); if (next == fmt.npos) { // End of the string. result += fmt.substr(pos); @@ -697,7 +697,7 @@ bool CBreakPoints::EvaluateLogFormat(DebugInterface *cpu, const std::string &fmt pos = next; } - size_t end = fmt.find_first_of("}", next + 1); + size_t end = fmt.find_first_of('}', next + 1); if (end == fmt.npos) { // Invalid: every expression needs a { and a }. return false; diff --git a/Core/Debugger/MemBlockInfo.cpp b/Core/Debugger/MemBlockInfo.cpp index f90634dee9..e3a51305fb 100644 --- a/Core/Debugger/MemBlockInfo.cpp +++ b/Core/Debugger/MemBlockInfo.cpp @@ -280,7 +280,7 @@ void MemSlabMap::Clear() { delete s; s = next; } - delete bulkStorage_; + delete [] bulkStorage_; bulkStorage_ = nullptr; first_ = nullptr; lastFind_ = nullptr; diff --git a/Core/Debugger/SymbolMap.cpp b/Core/Debugger/SymbolMap.cpp index 78efc1777e..aa4006bba7 100644 --- a/Core/Debugger/SymbolMap.cpp +++ b/Core/Debugger/SymbolMap.cpp @@ -165,7 +165,7 @@ bool SymbolMap::LoadSymbolMap(const Path &filename) { type = (SymbolType) typeInt; if (!hasModules) { if (!Memory::IsValidAddress(vaddress)) { - ERROR_LOG(LOADER, "Invalid address in symbol file: %08x (%s)", vaddress, name); + ERROR_LOG(Log::Loader, "Invalid address in symbol file: %08x (%s)", vaddress, name); continue; } } else { @@ -173,7 +173,7 @@ bool SymbolMap::LoadSymbolMap(const Path &filename) { moduleIndex = vaddress; vaddress = GetModuleAbsoluteAddr(address, moduleIndex); if (!Memory::IsValidAddress(vaddress)) { - ERROR_LOG(LOADER, "Invalid address in symbol file: %08x (%s)", vaddress, name); + ERROR_LOG(Log::Loader, "Invalid address in symbol file: %08x (%s)", vaddress, name); continue; } } diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp index 4da6366d24..7f1f1aac69 100644 --- a/Core/Debugger/WebSocket.cpp +++ b/Core/Debugger/WebSocket.cpp @@ -108,7 +108,7 @@ static void WebSocketNotifyLifecycle(CoreLifecycle stage) { case CoreLifecycle::STOPPING: case CoreLifecycle::MEMORY_REINITING: if (debuggersConnected > 0) { - DEBUG_LOG(SYSTEM, "Waiting for debugger to complete on shutdown"); + DEBUG_LOG(Log::System, "Waiting for debugger to complete on shutdown"); } lifecycleLock.lock(); break; @@ -118,7 +118,7 @@ static void WebSocketNotifyLifecycle(CoreLifecycle stage) { case CoreLifecycle::MEMORY_REINITED: lifecycleLock.unlock(); if (debuggersConnected > 0) { - DEBUG_LOG(SYSTEM, "Debugger ready for shutdown"); + DEBUG_LOG(Log::System, "Debugger ready for shutdown"); } break; } diff --git a/Core/Debugger/WebSocket/GameSubscriber.cpp b/Core/Debugger/WebSocket/GameSubscriber.cpp index dae7f871a7..94b62bf53f 100644 --- a/Core/Debugger/WebSocket/GameSubscriber.cpp +++ b/Core/Debugger/WebSocket/GameSubscriber.cpp @@ -51,7 +51,7 @@ void WebSocketGameReset(DebuggerRequest &req) { std::string resetError; if (!PSP_Reboot(&resetError)) { - ERROR_LOG(BOOT, "Error resetting: %s", resetError.c_str()); + ERROR_LOG(Log::Boot, "Error resetting: %s", resetError.c_str()); return req.Fail("Could not reset"); } diff --git a/Core/Debugger/WebSocket/LogBroadcaster.cpp b/Core/Debugger/WebSocket/LogBroadcaster.cpp index b3d4359c89..61a0a9afa1 100644 --- a/Core/Debugger/WebSocket/LogBroadcaster.cpp +++ b/Core/Debugger/WebSocket/LogBroadcaster.cpp @@ -17,7 +17,7 @@ #include #include -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Core/Debugger/WebSocket/LogBroadcaster.h" #include "Core/Debugger/WebSocket/WebSocketUtils.h" diff --git a/Core/Dialog/PSPDialog.cpp b/Core/Dialog/PSPDialog.cpp index cbd6b42426..8697e71b13 100644 --- a/Core/Dialog/PSPDialog.cpp +++ b/Core/Dialog/PSPDialog.cpp @@ -43,7 +43,7 @@ void PSPDialog::InitCommon() { UpdateCommon(); if (GetCommonParam() && GetCommonParam()->language != g_Config.GetPSPLanguage()) { - WARN_LOG(SCEUTILITY, "Game requested language %d, ignoring and using user language", GetCommonParam()->language); + WARN_LOG(Log::sceUtility, "Game requested language %d, ignoring and using user language", GetCommonParam()->language); } } diff --git a/Core/Dialog/PSPGamedataInstallDialog.cpp b/Core/Dialog/PSPGamedataInstallDialog.cpp index 2ec44086e5..f03e3bb5c6 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.cpp +++ b/Core/Dialog/PSPGamedataInstallDialog.cpp @@ -70,7 +70,7 @@ PSPGamedataInstallDialog::~PSPGamedataInstallDialog() { int PSPGamedataInstallDialog::Init(u32 paramAddr) { if (GetStatus() != SCE_UTILITY_STATUS_NONE) { - ERROR_LOG_REPORT(SCEUTILITY, "A game install request is already running, not starting a new one"); + ERROR_LOG_REPORT(Log::sceUtility, "A game install request is already running, not starting a new one"); return SCE_ERROR_UTILITY_INVALID_STATUS; } @@ -89,14 +89,14 @@ int PSPGamedataInstallDialog::Init(u32 paramAddr) { } if (allFilesSize == 0) { - ERROR_LOG_REPORT(SCEUTILITY, "Game install with no files / data"); + ERROR_LOG_REPORT(Log::sceUtility, "Game install with no files / data"); // TODO: What happens here? return -1; } int size = Memory::Read_U32(paramAddr); if (size != 1424 && size != 1432) { - ERROR_LOG_REPORT(SCEUTILITY, "sceGamedataInstallInitStart: invalid param size %d", size); + ERROR_LOG_REPORT(Log::sceUtility, "sceGamedataInstallInitStart: invalid param size %d", size); return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; } @@ -117,7 +117,7 @@ int PSPGamedataInstallDialog::Update(int animSpeed) { param->common.result = ERROR_UTILITY_GAMEDATA_INVALID_MODE; param.NotifyWrite("DialogResult"); ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); - WARN_LOG_REPORT(SCEUTILITY, "sceUtilityGamedataInstallUpdate: invalid mode %d", param->mode); + WARN_LOG_REPORT(Log::sceUtility, "sceUtilityGamedataInstallUpdate: invalid mode %d", param->mode); return 0; } @@ -158,7 +158,7 @@ void PSPGamedataInstallDialog::OpenNextFile() { currentInputFile = pspFileSystem.OpenFile(inputFileName, FILEACCESS_READ); if (currentInputFile < 0) { // TODO: Generate an error code? - ERROR_LOG_REPORT(SCEUTILITY, "Unable to read from install file: %s", inFileNames[readFiles].c_str()); + ERROR_LOG_REPORT(Log::sceUtility, "Unable to read from install file: %s", inFileNames[readFiles].c_str()); ++readFiles; currentInputFile = 0; return; @@ -166,7 +166,7 @@ void PSPGamedataInstallDialog::OpenNextFile() { currentOutputFile = pspFileSystem.OpenFile(outputFileName, (FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE | FILEACCESS_TRUNCATE)); if (currentOutputFile < 0) { // TODO: Generate an error code? - ERROR_LOG(SCEUTILITY, "Unable to write to install file: %s", inFileNames[readFiles].c_str()); + ERROR_LOG(Log::sceUtility, "Unable to write to install file: %s", inFileNames[readFiles].c_str()); pspFileSystem.CloseFile(currentInputFile); currentInputFile = 0; currentOutputFile = 0; diff --git a/Core/Dialog/PSPMsgDialog.cpp b/Core/Dialog/PSPMsgDialog.cpp index ba73d40076..2e7a8efe4c 100755 --- a/Core/Dialog/PSPMsgDialog.cpp +++ b/Core/Dialog/PSPMsgDialog.cpp @@ -44,7 +44,7 @@ PSPMsgDialog::~PSPMsgDialog() { int PSPMsgDialog::Init(unsigned int paramAddr) { // Ignore if already running if (GetStatus() != SCE_UTILITY_STATUS_NONE) { - ERROR_LOG_REPORT(SCEUTILITY, "sceUtilityMsgDialogInitStart: invalid status"); + ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityMsgDialogInitStart: invalid status"); return SCE_ERROR_UTILITY_INVALID_STATUS; } @@ -62,7 +62,7 @@ int PSPMsgDialog::Init(unsigned int paramAddr) { int optionsNotCoded = messageDialog.options & ~SCE_UTILITY_MSGDIALOG_OPTION_SUPPORTED; if(optionsNotCoded) { - ERROR_LOG_REPORT(SCEUTILITY, "PSPMsgDialog options not coded : 0x%08x", optionsNotCoded); + ERROR_LOG_REPORT(Log::sceUtility, "PSPMsgDialog options not coded : 0x%08x", optionsNotCoded); } flag = 0; diff --git a/Core/Dialog/PSPNpSigninDialog.cpp b/Core/Dialog/PSPNpSigninDialog.cpp index 57d8cce705..0770a0a90e 100644 --- a/Core/Dialog/PSPNpSigninDialog.cpp +++ b/Core/Dialog/PSPNpSigninDialog.cpp @@ -61,7 +61,7 @@ int PSPNpSigninDialog::Init(u32 paramAddr) { // Only copy the right size to support different request format Memory::Memcpy(&request, paramAddr, size); - WARN_LOG_REPORT_ONCE(PSPNpSigninDialogInit, SCENET, "NpSignin Init Params: %08x, %08x, %08x, %08x", request.npSigninStatus, request.unknown1, request.unknown2, request.unknown3); + WARN_LOG_REPORT_ONCE(PSPNpSigninDialogInit, Log::sceNet, "NpSignin Init Params: %08x, %08x, %08x, %08x", request.npSigninStatus, request.unknown1, request.unknown2, request.unknown3); ChangeStatusInit(NP_INIT_DELAY_US); diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index dfcd4a634f..2ce00f4f48 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -298,32 +298,32 @@ static bool IsKeyboardShiftValid(s32 inputType, OskKeyboardLanguage lang, OskKey int PSPOskDialog::Init(u32 oskPtr) { // Ignore if already running if (GetStatus() != SCE_UTILITY_STATUS_NONE) { - ERROR_LOG_REPORT(SCEUTILITY, "sceUtilityOskInitStart: invalid status"); + ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: invalid status"); return SCE_ERROR_UTILITY_INVALID_STATUS; } // Seems like this should crash? if (!Memory::IsValidAddress(oskPtr)) { - ERROR_LOG_REPORT(SCEUTILITY, "sceUtilityOskInitStart: invalid params (%08x)", oskPtr); + ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: invalid params (%08x)", oskPtr); return -1; } oskParams = oskPtr; if (oskParams->base.size != sizeof(SceUtilityOskParams)) { - ERROR_LOG_REPORT(SCEUTILITY, "sceUtilityOskInitStart: invalid size %d", oskParams->base.size); + ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: invalid size %d", oskParams->base.size); return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; } // Also seems to crash. if (!oskParams->fields.IsValid()) { - ERROR_LOG_REPORT(SCEUTILITY, "sceUtilityOskInitStart: invalid field data (%08x)", oskParams->fields.ptr); + ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: invalid field data (%08x)", oskParams->fields.ptr); return -1; } if (oskParams->unk_60 != 0) - WARN_LOG_REPORT(SCEUTILITY, "sceUtilityOskInitStart: unknown param is non-zero (%08x)", oskParams->unk_60); + WARN_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: unknown param is non-zero (%08x)", oskParams->unk_60); if (oskParams->fieldCount != 1) - WARN_LOG_REPORT(SCEUTILITY, "sceUtilityOskInitStart: unsupported field count %d", oskParams->fieldCount); + WARN_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: unsupported field count %d", oskParams->fieldCount); ChangeStatusInit(OSK_INIT_DELAY_US); selectedChar = 0; @@ -923,7 +923,7 @@ int PSPOskDialog::NativeKeyboard() { u32 maxLength = FieldMaxLength(); if (inputChars.length() > maxLength) { - ERROR_LOG(SCEUTILITY, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxLength); + ERROR_LOG(Log::sceUtility, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxLength); inputChars.erase(maxLength, std::string::npos); } ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index f60f60c6f3..144336e507 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -95,7 +95,7 @@ int PSPSaveDialog::Init(int paramAddr) { // Ignore if already running if (GetStatus() != SCE_UTILITY_STATUS_NONE) { - ERROR_LOG_REPORT(SCEUTILITY, "A save request is already running, not starting a new one"); + ERROR_LOG_REPORT(Log::sceUtility, "A save request is already running, not starting a new one"); return SCE_ERROR_UTILITY_INVALID_STATUS; } @@ -107,20 +107,20 @@ int PSPSaveDialog::Init(int paramAddr) memset(&request, 0, sizeof(request)); // Only copy the right size to support different save request format if (size != SAVEDATA_DIALOG_SIZE_V1 && size != SAVEDATA_DIALOG_SIZE_V2 && size != SAVEDATA_DIALOG_SIZE_V3) { - ERROR_LOG_REPORT(SCEUTILITY, "sceUtilitySavedataInitStart: invalid size %d", size); + ERROR_LOG_REPORT(Log::sceUtility, "sceUtilitySavedataInitStart: invalid size %d", size); return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; } Memory::Memcpy(&request, requestAddr, size); Memory::Memcpy(&originalRequest, requestAddr, size); param.SetIgnoreTextures(IsNotVisibleAction((SceUtilitySavedataType)(u32)request.mode)); - param.ClearCaches(); + param.ClearSFOCache(); int retval = param.SetPspParam(&request); const u32 mode = (u32)param.GetPspParam()->mode; const char *modeName = mode < ARRAY_SIZE(utilitySavedataTypeNames) ? utilitySavedataTypeNames[mode] : "UNKNOWN"; - INFO_LOG(SCEUTILITY,"sceUtilitySavedataInitStart(%08x) - %s (%d)", paramAddr, modeName, mode); - INFO_LOG(SCEUTILITY,"sceUtilitySavedataInitStart(%08x) : Game key (hex): %s", paramAddr, param.GetKey(param.GetPspParam()).c_str()); + INFO_LOG(Log::sceUtility,"sceUtilitySavedataInitStart(%08x) - %s (%d)", paramAddr, modeName, mode); + INFO_LOG(Log::sceUtility,"sceUtilitySavedataInitStart(%08x) : Game key (hex): %s", paramAddr, param.GetKey(param.GetPspParam()).c_str()); yesnoChoice = 1; switch ((SceUtilitySavedataFocus)(u32)param.GetPspParam()->focus) @@ -153,7 +153,7 @@ int PSPSaveDialog::Init(int paramAddr) currentSelectedSave = param.GetLastEmptySave(); break; default: - WARN_LOG(SCEUTILITY, "Unknown save list focus option: %d", param.GetPspParam()->focus); + WARN_LOG(Log::sceUtility, "Unknown save list focus option: %d", param.GetPspParam()->focus); currentSelectedSave = 0; break; } @@ -164,7 +164,7 @@ int PSPSaveDialog::Init(int paramAddr) switch ((SceUtilitySavedataType)(u32)param.GetPspParam()->mode) { case SCE_UTILITY_SAVEDATA_TYPE_LOAD: - DEBUG_LOG(SCEUTILITY, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetSaveName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetSaveName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); if (param.GetFileInfo(0).size != 0) { if (param.GetFileInfo(0).broken) { param.GetPspParam()->common.result = SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN; @@ -176,20 +176,20 @@ int PSPSaveDialog::Init(int paramAddr) display = DS_LOAD_NODATA; break; case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD: - DEBUG_LOG(SCEUTILITY, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetSaveName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetSaveName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); display = DS_NONE; // Is this necessary? // currentSelectedSave = param.GetSelectedSave(); break; case SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD: - DEBUG_LOG(SCEUTILITY, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); if(param.GetFilenameCount() == 0) display = DS_LOAD_NODATA; else display = DS_LOAD_LIST_CHOICE; break; case SCE_UTILITY_SAVEDATA_TYPE_SAVE: - DEBUG_LOG(SCEUTILITY, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); if (param.GetFileInfo(0).size != 0) { yesnoChoice = 0; @@ -199,17 +199,17 @@ int PSPSaveDialog::Init(int paramAddr) display = DS_SAVE_CONFIRM; break; case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE: - DEBUG_LOG(SCEUTILITY, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); display = DS_NONE; // Is this necessary? // currentSelectedSave = param.GetSelectedSave(); break; case SCE_UTILITY_SAVEDATA_TYPE_LISTSAVE: - DEBUG_LOG(SCEUTILITY, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); display = DS_SAVE_LIST_CHOICE; break; case SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE: - DEBUG_LOG(SCEUTILITY, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); if(param.GetFilenameCount() == 0) display = DS_DELETE_NODATA; else @@ -232,7 +232,7 @@ int PSPSaveDialog::Init(int paramAddr) break; case SCE_UTILITY_SAVEDATA_TYPE_DELETE: - DEBUG_LOG(SCEUTILITY, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); if (param.GetFileInfo(0).size != 0) { yesnoChoice = 0; display = DS_DELETE_CONFIRM; @@ -241,12 +241,12 @@ int PSPSaveDialog::Init(int paramAddr) break; case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE: - DEBUG_LOG(SCEUTILITY, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); display = DS_NONE; break; case SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE: - DEBUG_LOG(SCEUTILITY, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + DEBUG_LOG(Log::sceUtility, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); if (param.GetFilenameCount() == 0) display = DS_DELETE_NODATA; else @@ -254,7 +254,7 @@ int PSPSaveDialog::Init(int paramAddr) break; default: { - ERROR_LOG_REPORT(SCEUTILITY, "Load/Save function %d not coded. Title: %s Save: %s File: %s", (SceUtilitySavedataType)(u32)param.GetPspParam()->mode, param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); + ERROR_LOG_REPORT(Log::sceUtility, "Load/Save function %d not coded. Title: %s Save: %s File: %s", (SceUtilitySavedataType)(u32)param.GetPspParam()->mode, param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str()); param.GetPspParam()->common.result = 0; ChangeStatusInit(SAVEDATA_INIT_DELAY_US); display = DS_NONE; @@ -269,42 +269,43 @@ int PSPSaveDialog::Init(int paramAddr) ChangeStatusInit(SAVEDATA_INIT_DELAY_US); } - param.ClearCaches(); + param.ClearSFOCache(); InitCommon(); UpdateButtons(); StartFade(true); - /*INFO_LOG(SCEUTILITY,"Dump Param :"); - INFO_LOG(SCEUTILITY,"size : %d",param.GetPspParam()->common.size); - INFO_LOG(SCEUTILITY,"language : %d",param.GetPspParam()->common.language); - INFO_LOG(SCEUTILITY,"buttonSwap : %d",param.GetPspParam()->common.buttonSwap); - INFO_LOG(SCEUTILITY,"result : %d",param.GetPspParam()->common.result); - INFO_LOG(SCEUTILITY,"mode : %d",param.GetPspParam()->mode); - INFO_LOG(SCEUTILITY,"bind : %d",param.GetPspParam()->bind); - INFO_LOG(SCEUTILITY,"overwriteMode : %d",param.GetPspParam()->overwriteMode); - INFO_LOG(SCEUTILITY,"gameName : %s",param.GetGameName(param.GetPspParam()).c_str()); - INFO_LOG(SCEUTILITY,"saveName : %s",param.GetPspParam()->saveName); - INFO_LOG(SCEUTILITY,"saveNameList : %08x",*((unsigned int*)¶m.GetPspParam()->saveNameList)); - INFO_LOG(SCEUTILITY,"fileName : %s",param.GetPspParam()->fileName); - INFO_LOG(SCEUTILITY,"dataBuf : %08x",*((unsigned int*)¶m.GetPspParam()->dataBuf)); - INFO_LOG(SCEUTILITY,"dataBufSize : %u",param.GetPspParam()->dataBufSize); - INFO_LOG(SCEUTILITY,"dataSize : %u",param.GetPspParam()->dataSize); + /*INFO_LOG(Log::sceUtility,"Dump Param :"); + INFO_LOG(Log::sceUtility,"size : %d",param.GetPspParam()->common.size); + INFO_LOG(Log::sceUtility,"language : %d",param.GetPspParam()->common.language); + INFO_LOG(Log::sceUtility,"buttonSwap : %d",param.GetPspParam()->common.buttonSwap); + INFO_LOG(Log::sceUtility,"result : %d",param.GetPspParam()->common.result); + INFO_LOG(Log::sceUtility,"mode : %d",param.GetPspParam()->mode); + INFO_LOG(Log::sceUtility,"bind : %d",param.GetPspParam()->bind); + INFO_LOG(Log::sceUtility,"overwriteMode : %d",param.GetPspParam()->overwriteMode); + INFO_LOG(Log::sceUtility,"gameName : %s",param.GetGameName(param.GetPspParam()).c_str()); + INFO_LOG(Log::sceUtility,"saveName : %s",param.GetPspParam()->saveName); + INFO_LOG(Log::sceUtility,"saveNameList : %08x",*((unsigned int*)¶m.GetPspParam()->saveNameList)); + INFO_LOG(Log::sceUtility,"fileName : %s",param.GetPspParam()->fileName); + INFO_LOG(Log::sceUtility,"dataBuf : %08x",*((unsigned int*)¶m.GetPspParam()->dataBuf)); + INFO_LOG(Log::sceUtility,"dataBufSize : %u",param.GetPspParam()->dataBufSize); + INFO_LOG(Log::sceUtility,"dataSize : %u",param.GetPspParam()->dataSize); - INFO_LOG(SCEUTILITY,"sfo title : %s",param.GetPspParam()->sfoParam.title); - INFO_LOG(SCEUTILITY,"sfo savedataTitle : %s",param.GetPspParam()->sfoParam.savedataTitle); - INFO_LOG(SCEUTILITY,"sfo detail : %s",param.GetPspParam()->sfoParam.detail); + INFO_LOG(Log::sceUtility,"sfo title : %s",param.GetPspParam()->sfoParam.title); + INFO_LOG(Log::sceUtility,"sfo savedataTitle : %s",param.GetPspParam()->sfoParam.savedataTitle); + INFO_LOG(Log::sceUtility,"sfo detail : %s",param.GetPspParam()->sfoParam.detail); - INFO_LOG(SCEUTILITY,"icon0 data : %08x",*((unsigned int*)¶m.GetPspParam()->icon0FileData.buf)); - INFO_LOG(SCEUTILITY,"icon0 size : %u",param.GetPspParam()->icon0FileData.bufSize); + INFO_LOG(Log::sceUtility,"icon0 data : %08x",*((unsigned int*)¶m.GetPspParam()->icon0FileData.buf)); + INFO_LOG(Log::sceUtility,"icon0 size : %u",param.GetPspParam()->icon0FileData.bufSize); - INFO_LOG(SCEUTILITY,"icon1 data : %08x",*((unsigned int*)¶m.GetPspParam()->icon1FileData.buf)); - INFO_LOG(SCEUTILITY,"icon1 size : %u",param.GetPspParam()->icon1FileData.bufSize); + INFO_LOG(Log::sceUtility,"icon1 data : %08x",*((unsigned int*)¶m.GetPspParam()->icon1FileData.buf)); + INFO_LOG(Log::sceUtility,"icon1 size : %u",param.GetPspParam()->icon1FileData.bufSize); - INFO_LOG(SCEUTILITY,"pic1 data : %08x",*((unsigned int*)¶m.GetPspParam()->pic1FileData.buf)); - INFO_LOG(SCEUTILITY,"pic1 size : %u",param.GetPspParam()->pic1FileData.bufSize); + INFO_LOG(Log::sceUtility,"pic1 data : %08x",*((unsigned int*)¶m.GetPspParam()->pic1FileData.buf)); + INFO_LOG(Log::sceUtility,"pic1 size : %u",param.GetPspParam()->pic1FileData.bufSize); - INFO_LOG(SCEUTILITY,"snd0 data : %08x",*((unsigned int*)¶m.GetPspParam()->snd0FileData.buf)); - INFO_LOG(SCEUTILITY,"snd0 size : %u",param.GetPspParam()->snd0FileData.bufSize);*/ + INFO_LOG(Log::sceUtility,"snd0 data : %08x",*((unsigned int*)¶m.GetPspParam()->snd0FileData.buf)); + INFO_LOG(Log::sceUtility,"snd0 size : %u",param.GetPspParam()->snd0FileData.bufSize);*/ + INFO_LOG(Log::sceUtility, "Return value: %d", retval); return retval; } @@ -650,7 +651,7 @@ int PSPSaveDialog::Update(int animSpeed) param.SetPspParam(&request); } - param.ClearCaches(); + param.ClearSFOCache(); UpdateButtons(); UpdateFade(animSpeed); @@ -1059,13 +1060,13 @@ int PSPSaveDialog::Update(int animSpeed) if (ReadStatus() == SCE_UTILITY_STATUS_FINISHED || pendingStatus == SCE_UTILITY_STATUS_FINISHED) Memory::Memcpy(requestAddr, &request, request.common.size, "SaveDialogParam"); - param.ClearCaches(); + param.ClearSFOCache(); return 0; } void PSPSaveDialog::ExecuteIOAction() { - param.ClearCaches(); + param.ClearSFOCache(); auto &result = param.GetPspParam()->common.result; std::lock_guard guard(paramLock); switch (display) { @@ -1104,14 +1105,15 @@ void PSPSaveDialog::ExecuteIOAction() { } ioThreadStatus = SAVEIO_DONE; - param.ClearCaches(); + param.ClearSFOCache(); } void PSPSaveDialog::ExecuteNotVisibleIOAction() { - param.ClearCaches(); + param.ClearSFOCache(); auto &result = param.GetPspParam()->common.result; - switch ((SceUtilitySavedataType)(u32)param.GetPspParam()->mode) { + SceUtilitySavedataType utilityMode = (SceUtilitySavedataType)(u32)param.GetPspParam()->mode; + switch (utilityMode) { case SCE_UTILITY_SAVEDATA_TYPE_LOAD: // Only load and exit case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD: result = param.Load(param.GetPspParam(), GetSelectedSaveDirName(), currentSelectedSave); @@ -1145,7 +1147,7 @@ void PSPSaveDialog::ExecuteNotVisibleIOAction() { } break; case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA: - DEBUG_LOG(SCEUTILITY, "sceUtilitySavedata DELETEDATA: %s", param.GetPspParam()->saveName); + DEBUG_LOG(Log::sceUtility, "sceUtilitySavedata DELETEDATA: %s", param.GetPspParam()->saveName); if (param.Delete(param.GetPspParam(), param.GetSelectedSave())) { result = 0; } else { @@ -1190,7 +1192,7 @@ void PSPSaveDialog::ExecuteNotVisibleIOAction() { break; } - param.ClearCaches(); + param.ClearSFOCache(); } void PSPSaveDialog::JoinIOThread() { @@ -1210,7 +1212,7 @@ static void DoExecuteIOAction(PSPSaveDialog *dialog) { void PSPSaveDialog::StartIOThread() { if (ioThread) { - WARN_LOG_REPORT(SCEUTILITY, "Starting a save io thread when one already pending, uh oh."); + WARN_LOG_REPORT(Log::sceUtility, "Starting a save io thread when one already pending, uh oh."); JoinIOThread(); } @@ -1230,7 +1232,7 @@ int PSPSaveDialog::Shutdown(bool force) { ChangeStatusShutdown(SAVEDATA_SHUTDOWN_DELAY_US); } param.SetPspParam(0); - param.ClearCaches(); + param.ClearSFOCache(); return 0; } diff --git a/Core/Dialog/PSPScreenshotDialog.cpp b/Core/Dialog/PSPScreenshotDialog.cpp index 6615e84252..9437d578bb 100644 --- a/Core/Dialog/PSPScreenshotDialog.cpp +++ b/Core/Dialog/PSPScreenshotDialog.cpp @@ -61,13 +61,13 @@ PSPScreenshotDialog::~PSPScreenshotDialog() { int PSPScreenshotDialog::Init(u32 paramAddr) { // Already running if (ReadStatus() != SCE_UTILITY_STATUS_NONE && ReadStatus() != SCE_UTILITY_STATUS_SHUTDOWN) { - ERROR_LOG_REPORT(HLE, "sceUtilityScreenshotInitStart(%08x): invalid status", paramAddr); + ERROR_LOG_REPORT(Log::HLE, "sceUtilityScreenshotInitStart(%08x): invalid status", paramAddr); return SCE_ERROR_UTILITY_INVALID_STATUS; } params_ = PSPPointer::Create(paramAddr); if (!params_.IsValid()) { - ERROR_LOG_REPORT(HLE, "sceUtilityScreenshotInitStart(%08x): invalid pointer", paramAddr); + ERROR_LOG_REPORT(Log::HLE, "sceUtilityScreenshotInitStart(%08x): invalid pointer", paramAddr); return SCE_KERNEL_ERROR_INVALID_POINTER; } @@ -78,7 +78,7 @@ int PSPScreenshotDialog::Init(u32 paramAddr) { break; default: - ERROR_LOG_REPORT(HLE, "sceUtilityScreenshotInitStart(%08x): invalid size %d", paramAddr, (u32)params_->base.size); + ERROR_LOG_REPORT(Log::HLE, "sceUtilityScreenshotInitStart(%08x): invalid size %d", paramAddr, (u32)params_->base.size); return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; } diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index fc944483ee..a0cbad3996 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -110,32 +110,31 @@ namespace return info; } - bool PSPMatch(const std::string &text, const std::string ®exp) - { - if(text.empty() && regexp.empty()) + bool PSPMatch(std::string_view text, std::string_view regexp) { + if (text.empty() && regexp.empty()) return true; - else if(regexp == "*") + else if (regexp == "*") return true; - else if(text.empty()) + else if (text.empty()) return false; - else if(regexp.empty()) + else if (regexp.empty()) return false; - else if(regexp == "?" && text.length() == 1) + else if (regexp == "?" && text.length() == 1) return true; - else if(text == regexp) + else if (text == regexp) return true; - else if(regexp.data()[0] == '*') + else if (regexp.data()[0] == '*') { bool res = PSPMatch(text.substr(1),regexp.substr(1)); if(!res) res = PSPMatch(text.substr(1),regexp); return res; } - else if(regexp.data()[0] == '?') + else if (regexp.data()[0] == '?') { return PSPMatch(text.substr(1),regexp.substr(1)); } - else if(regexp.data()[0] == text.data()[0]) + else if (regexp.data()[0] == text.data()[0]) { return PSPMatch(text.substr(1),regexp.substr(1)); } @@ -145,7 +144,7 @@ namespace int align16(int address) { - return ((address + 0xF) >> 4) << 4; + return (address + 15) & ~15; } int GetSDKMainVersion(int sdkVersion) @@ -222,7 +221,7 @@ void SavedataParam::Init() if (handle >= 0) { pspFileSystem.CloseFile(handle); } else { - INFO_LOG(IO, "Failed to create .nomedia file (might be ok if it already exists)"); + INFO_LOG(Log::IO, "Failed to create .nomedia file (might be ok if it already exists)"); } #endif } @@ -332,13 +331,13 @@ bool SavedataParam::Delete(SceUtilitySavedataParam* param, int saveId) { // Sanity check, preventing full delete of savedata/ in MGS PW demo (!) if (!strlen(param->gameName) && param->mode != SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE) { - ERROR_LOG(SCEUTILITY, "Bad param with gameName empty - cannot delete save directory"); + ERROR_LOG(Log::sceUtility, "Bad param with gameName empty - cannot delete save directory"); return false; } std::string dirPath = GetSaveFilePath(param, GetSaveDir(saveId)); if (dirPath.size() == 0) { - ERROR_LOG(SCEUTILITY, "GetSaveFilePath returned empty - cannot delete save directory"); + ERROR_LOG(Log::sceUtility, "GetSaveFilePath returned empty - cannot delete save directory"); return false; } @@ -346,7 +345,7 @@ bool SavedataParam::Delete(SceUtilitySavedataParam* param, int saveId) { return false; } - ClearCaches(); + ClearSFOCache(); pspFileSystem.RmDir(dirPath); return true; } @@ -378,11 +377,11 @@ int SavedataParam::DeleteData(SceUtilitySavedataParam* param) { } if (!subFolder.size()) { - ERROR_LOG(SCEUTILITY, "Bad subfolder, ignoring delete of %s", filePath.c_str()); + ERROR_LOG(Log::sceUtility, "Bad subfolder, ignoring delete of %s", filePath.c_str()); return 0; } - ClearCaches(); + ClearSFOCache(); pspFileSystem.RemoveFile(filePath); // Update PARAM.SFO to remove the file, if it was in the list. @@ -412,7 +411,7 @@ int SavedataParam::DeleteData(SceUtilitySavedataParam* param) { size_t sfoSize; sfoFile->WriteSFO(&sfoData, &sfoSize); - ClearCaches(); + ClearSFOCache(); WritePSPFile(sfoPath, sfoData, (SceSize)sfoSize); delete[] sfoData; } @@ -426,12 +425,12 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD return SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE; } if (param->dataSize > param->dataBufSize) { - ERROR_LOG_REPORT(SCEUTILITY, "Savedata buffer overflow: %d / %d", param->dataSize, param->dataBufSize); + ERROR_LOG_REPORT(Log::sceUtility, "Savedata buffer overflow: %d / %d", param->dataSize, param->dataBufSize); return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS; } auto validateSize = [](const PspUtilitySavedataFileData &data) { if (data.buf.IsValid() && data.bufSize < data.size) { - ERROR_LOG_REPORT(SCEUTILITY, "Savedata subdata buffer overflow: %d / %d", data.size, data.bufSize); + ERROR_LOG_REPORT(Log::sceUtility, "Savedata subdata buffer overflow: %d / %d", data.size, data.bufSize); return false; } return true; @@ -441,14 +440,14 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD } if (param->secureVersion > 3) { - ERROR_LOG_REPORT(SCEUTILITY, "Savedata version requested on save: %d", param->secureVersion); + ERROR_LOG_REPORT(Log::sceUtility, "Savedata version requested on save: %d", param->secureVersion); return SCE_UTILITY_SAVEDATA_ERROR_SAVE_PARAM; } else if (param->secureVersion != 0) { if (param->secureVersion != 1 && !HasKey(param) && secureMode) { - ERROR_LOG_REPORT(SCEUTILITY, "Savedata version with missing key on save: %d", param->secureVersion); + ERROR_LOG_REPORT(Log::sceUtility, "Savedata version with missing key on save: %d", param->secureVersion); return SCE_UTILITY_SAVEDATA_ERROR_SAVE_PARAM; } - WARN_LOG(SCEUTILITY, "Savedata version requested on save: %d", param->secureVersion); + WARN_LOG(Log::sceUtility, "Savedata version requested on save: %d", param->secureVersion); } std::string dirPath = GetSaveFilePath(param, GetSaveDir(param, saveDirName)); @@ -468,13 +467,21 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD if (param->dataBuf.IsValid() && g_Config.bEncryptSave && secureMode) { cryptedSize = param->dataSize; - if(cryptedSize == 0 || (SceSize)cryptedSize > param->dataBufSize) + if (cryptedSize == 0 || (SceSize)cryptedSize > param->dataBufSize) { + ERROR_LOG(Log::sceUtility, "Bad cryptedSize %d", cryptedSize); cryptedSize = param->dataBufSize; // fallback, should never use this + } u8 *data_ = param->dataBuf; int aligned_len = align16(cryptedSize); - cryptedData = new u8[aligned_len + 0x10]; + if (aligned_len != cryptedSize) { + WARN_LOG(Log::sceUtility, "cryptedSize unaligned: %d (%d)", cryptedSize, cryptedSize & 15); + } + + cryptedData = new u8[aligned_len + 0x10](); memcpy(cryptedData, data_, cryptedSize); + // EncryptData will do a memmove to make room for the key in front. + // Technically we could just copy it into place here to avoid that. int decryptMode = DetermineCryptMode(param); bool hasKey = decryptMode > 1; @@ -486,7 +493,7 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD if (EncryptData(decryptMode, cryptedData, &cryptedSize, &aligned_len, cryptedHash, (hasKey ? param->key : 0)) != 0) { auto err = GetI18NCategory(I18NCat::ERRORS); g_OSD.Show(OSDType::MESSAGE_WARNING, err->T("Save encryption failed. This save won't work on real PSP"), 6.0f); - ERROR_LOG(SCEUTILITY,"Save encryption failed. This save won't work on real PSP"); + ERROR_LOG(Log::sceUtility,"Save encryption failed. This save won't work on real PSP"); delete[] cryptedData; cryptedData = 0; } @@ -496,11 +503,13 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD std::string sfopath = dirPath + "/" + SFO_FILENAME; std::shared_ptr sfoFile = LoadCachedSFO(sfopath, true); + // This was added in #18430, see below. bool subWrite = param->mode == SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE || param->mode == SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA; bool wasCrypted = GetSaveCryptMode(param, saveDirName) != 0; - // Update values - if(!subWrite){ + // Update values. NOTE! #18430 made this conditional on !subWrite, but this is not correct, as it causes #18687. + // So now we do a hacky trick and just check for a valid title before we proceed with updating the sfoFile. + if (strnlen(param->sfoParam.title, sizeof(param->sfoParam.title)) > 0) { sfoFile->SetValue("TITLE", param->sfoParam.title, 128); sfoFile->SetValue("SAVEDATA_TITLE", param->sfoParam.savedataTitle, 128); sfoFile->SetValue("SAVEDATA_DETAIL", param->sfoParam.detail, 1024); @@ -537,10 +546,8 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD delete[] updatedList; // Init param with 0. This will be used to detect crypted save or not on loading - u8 *tmpData = new u8[128]; - memset(tmpData, 0, 128); - sfoFile->SetValue("SAVEDATA_PARAMS", tmpData, 128, 128); - delete[] tmpData; + u8 zeroes[128]{}; + sfoFile->SetValue("SAVEDATA_PARAMS", zeroes, 128, 128); u8 *sfoData; size_t sfoSize; @@ -549,11 +556,11 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD // Calc SFO hash for PSP. if (cryptedData != 0 || (subWrite && wasCrypted)) { int offset = sfoFile->GetDataOffset(sfoData, "SAVEDATA_PARAMS"); - if(offset >= 0) + if (offset >= 0) UpdateHash(sfoData, (int)sfoSize, offset, DetermineCryptMode(param)); } - ClearCaches(); + ClearSFOCache(); WritePSPFile(sfopath, sfoData, (SceSize)sfoSize); delete[] sfoData; sfoData = nullptr; @@ -578,24 +585,21 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD saveSize = cryptedSize; } - INFO_LOG(SCEUTILITY,"Saving file with size %u in %s",saveSize,filePath.c_str()); + INFO_LOG(Log::sceUtility,"Saving file with size %u in %s",saveSize,filePath.c_str()); // copy back save name in request strncpy(param->saveName, saveDirName.c_str(), 20); - if (fileName.empty()) { - delete[] cryptedData; - } else { + if (!fileName.empty()) { if (!WritePSPFile(filePath, data_, saveSize)) { - ERROR_LOG(SCEUTILITY, "Error writing file %s", filePath.c_str()); + ERROR_LOG(Log::sceUtility, "Error writing file %s", filePath.c_str()); delete[] cryptedData; return SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE; } - delete[] cryptedData; } + delete[] cryptedData; } - // SAVE ICON0 if (param->icon0FileData.buf.IsValid()) { @@ -651,6 +655,7 @@ int SavedataParam::Load(SceUtilitySavedataParam *param, const std::string &saveD // Load sfo if (!LoadSFO(param, dirPath)) { + WARN_LOG(Log::sceUtility, "Load: Failed to load SFO from %s", dirPath.c_str()); return isRWMode ? SCE_UTILITY_SAVEDATA_ERROR_RW_DATA_BROKEN : SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN; } @@ -673,14 +678,14 @@ int SavedataParam::Load(SceUtilitySavedataParam *param, const std::string &saveD int SavedataParam::LoadSaveData(SceUtilitySavedataParam *param, const std::string &saveDirName, const std::string &dirPath, bool secureMode) { if (param->secureVersion > 3) { - ERROR_LOG_REPORT(SCEUTILITY, "Savedata version requested: %d", param->secureVersion); + ERROR_LOG_REPORT(Log::sceUtility, "Savedata version requested: %d", param->secureVersion); return SCE_UTILITY_SAVEDATA_ERROR_LOAD_PARAM; } else if (param->secureVersion != 0) { if (param->secureVersion != 1 && !HasKey(param) && secureMode) { - ERROR_LOG_REPORT(SCEUTILITY, "Savedata version with missing key: %d", param->secureVersion); + ERROR_LOG_REPORT(Log::sceUtility, "Savedata version with missing key: %d", param->secureVersion); return SCE_UTILITY_SAVEDATA_ERROR_LOAD_PARAM; } - WARN_LOG_REPORT(SCEUTILITY, "Savedata version requested: %d", param->secureVersion); + WARN_LOG_REPORT(Log::sceUtility, "Savedata version requested: %d", param->secureVersion); } std::string filename = GetFileName(param); @@ -690,11 +695,11 @@ int SavedataParam::LoadSaveData(SceUtilitySavedataParam *param, const std::strin return 0; s64 readSize; - INFO_LOG(SCEUTILITY, "Loading file with size %u in %s", param->dataBufSize, filePath.c_str()); + INFO_LOG(Log::sceUtility, "Loading file with size %u in %s", param->dataBufSize, filePath.c_str()); u8 *saveData = nullptr; int saveSize = -1; if (!ReadPSPFile(filePath, &saveData, saveSize, &readSize)) { - ERROR_LOG(SCEUTILITY,"Error reading file %s",filePath.c_str()); + ERROR_LOG(Log::sceUtility,"Error reading file %s",filePath.c_str()); return SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA; } saveSize = (int)readSize; @@ -707,9 +712,9 @@ int SavedataParam::LoadSaveData(SceUtilitySavedataParam *param, const std::strin bool saveDone = false; u32 loadedSize = 0; if (isCrypted) { - if (DetermineCryptMode(param) > 1 && !HasKey(param)) + if (DetermineCryptMode(param) > 1 && !HasKey(param)) { return SCE_UTILITY_SAVEDATA_ERROR_LOAD_PARAM; - + } u8 hash[16]; bool hasExpectedHash = GetExpectedHash(dirPath, filename, hash); loadedSize = LoadCryptedSave(param, param->dataBuf, saveData, saveSize, prevCryptMode, hasExpectedHash ? hash : nullptr, saveDone); @@ -774,7 +779,7 @@ u32 SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, con if (decryptMode != prevCryptMode) { if (prevCryptMode == 1 && param->key[0] == 0) { // Backwards compat for a bug we used to have. - WARN_LOG(SCEUTILITY, "Savedata loading with hashmode %d instead of detected %d", prevCryptMode, decryptMode); + WARN_LOG(Log::sceUtility, "Savedata loading with hashmode %d instead of detected %d", prevCryptMode, decryptMode); decryptMode = prevCryptMode; // Don't notify the user if we're not going to upgrade the save. @@ -785,9 +790,9 @@ u32 SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, con } } else { if (decryptMode == 5 && prevCryptMode == 3) { - WARN_LOG(SCEUTILITY, "Savedata loading with detected hashmode %d instead of file's %d", decryptMode, prevCryptMode); + WARN_LOG(Log::sceUtility, "Savedata loading with detected hashmode %d instead of file's %d", decryptMode, prevCryptMode); } else { - WARN_LOG_REPORT(SCEUTILITY, "Savedata loading with detected hashmode %d instead of file's %d", decryptMode, prevCryptMode); + WARN_LOG_REPORT(Log::sceUtility, "Savedata loading with detected hashmode %d instead of file's %d", decryptMode, prevCryptMode); } if (g_Config.bSavedataUpgrade) { decryptMode = prevCryptMode; @@ -799,17 +804,17 @@ u32 SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, con hasKey = decryptMode > 1; } - int err = DecryptSave(decryptMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, expectedHash); + int err = DecryptData(decryptMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, expectedHash); // Perhaps the file had the wrong mode.... if (err != 0 && detectedMode != decryptMode) { resetData(detectedMode); - err = DecryptSave(detectedMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, expectedHash); + err = DecryptData(detectedMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, expectedHash); } // TODO: Should return an error, but let's just try with a bad hash. if (err != 0 && expectedHash != nullptr) { - WARN_LOG(SCEUTILITY, "Incorrect hash on save data, likely corrupt"); + WARN_LOG(Log::sceUtility, "Incorrect hash on save data, likely corrupt"); resetData(decryptMode); - err = DecryptSave(decryptMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, nullptr); + err = DecryptData(decryptMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, nullptr); } u32 sz = 0; @@ -912,9 +917,13 @@ void SavedataParam::LoadFile(const std::string& dirPath, const std::string& file fileData->size = readSize; const std::string tag = "SavedataLoad/" + filePath; NotifyMemInfo(MemBlockFlags::WRITE, fileData->buf.ptr, fileData->size, tag.c_str(), tag.size()); + INFO_LOG(Log::sceUtility, "Loaded subfile %s (size: %d bytes) into %08x", filePath.c_str(), fileData->size, fileData->buf.ptr); + } else { + WARN_LOG(Log::sceUtility, "Failed to load subfile %s into %08x", filePath.c_str(), fileData->buf.ptr); } } +// Note: The work is done in-place, hence the memmove etc. int SavedataParam::EncryptData(unsigned int mode, unsigned char *data, int *dataLen, @@ -922,16 +931,18 @@ int SavedataParam::EncryptData(unsigned int mode, unsigned char *hash, unsigned char *cryptkey) { - pspChnnlsvContext1 ctx1; - pspChnnlsvContext2 ctx2; + pspChnnlsvContext1 ctx1{}; + pspChnnlsvContext2 ctx2{}; + + INFO_LOG(Log::sceUtility, "EncryptData(mode=%d, *dataLen=%d, *alignedLen=%d)", mode, *dataLen, *alignedLen); /* Make room for the IV in front of the data. */ memmove(data + 0x10, data, *alignedLen); /* Set up buffers */ - memset(&ctx1, 0, sizeof(pspChnnlsvContext1)); - memset(&ctx2, 0, sizeof(pspChnnlsvContext2)); memset(hash, 0, 0x10); + + // Zero out the IV before we begin. memset(data, 0, 0x10); /* Build the 0x10-byte IV and setup encryption */ @@ -967,9 +978,10 @@ int SavedataParam::EncryptData(unsigned int mode, return 0; } -int SavedataParam::DecryptSave(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, unsigned char *cryptkey, const u8 *expectedHash) { - pspChnnlsvContext1 ctx1; - pspChnnlsvContext2 ctx2; +// Note: The work is done in-place, hence the memmove etc. +int SavedataParam::DecryptData(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, unsigned char *cryptkey, const u8 *expectedHash) { + pspChnnlsvContext1 ctx1{}; + pspChnnlsvContext2 ctx2{}; /* Need a 16-byte IV plus some data */ if (*alignedLen <= 0x10) @@ -977,10 +989,6 @@ int SavedataParam::DecryptSave(unsigned int mode, unsigned char *data, int *data *dataLen -= 0x10; *alignedLen -= 0x10; - /* Set up buffers */ - memset(&ctx1, 0, sizeof(pspChnnlsvContext1)); - memset(&ctx2, 0, sizeof(pspChnnlsvContext2)); - /* Perform the magic */ if (sceSdSetIndex_(ctx1, mode) < 0) return -2; @@ -1010,10 +1018,11 @@ int SavedataParam::DecryptSave(unsigned int mode, unsigned char *data, int *data return 0; } +// Requires sfoData to be padded with zeroes to the next 16-byte boundary (due to BuildHash) int SavedataParam::UpdateHash(u8* sfoData, int sfoSize, int sfoDataParamsOffset, int encryptmode) { int alignedLen = align16(sfoSize); - memset(sfoData+sfoDataParamsOffset, 0, 128); + memset(sfoData + sfoDataParamsOffset, 0, 128); u8 filehash[16]; int ret = 0; @@ -1032,8 +1041,8 @@ int SavedataParam::UpdateHash(u8* sfoData, int sfoSize, int sfoDataParamsOffset, } // Copy 11D0 hash to param.sfo and set flag indicating it's there - memcpy(sfoData+sfoDataParamsOffset + 0x20, filehash, 0x10); - *(sfoData+sfoDataParamsOffset) |= 0x01; + memcpy(sfoData + sfoDataParamsOffset + 0x20, filehash, 0x10); + *(sfoData + sfoDataParamsOffset) |= 0x01; // If new encryption mode, compute and insert the 1220 hash. if (encryptmode & 6) @@ -1059,19 +1068,18 @@ int SavedataParam::UpdateHash(u8* sfoData, int sfoSize, int sfoDataParamsOffset, return 0; } -int SavedataParam::BuildHash(unsigned char *output, - unsigned char *data, +// Requires sfoData to be padded with zeroes to the next 16-byte boundary. +int SavedataParam::BuildHash(uint8_t *output, + const uint8_t *data, unsigned int len, unsigned int alignedLen, int mode, - unsigned char *cryptkey) -{ + const uint8_t *cryptkey) { pspChnnlsvContext1 ctx1; /* Set up buffers */ memset(&ctx1, 0, sizeof(pspChnnlsvContext1)); memset(output, 0, 0x10); - memset(data + len, 0, alignedLen - len); /* Perform the magic */ if (sceSdSetIndex_(ctx1, mode & 0xFF) < 0) @@ -1110,6 +1118,10 @@ std::string SavedataParam::GetSpaceText(u64 size, bool roundUp) return std::string(text); } +inline std::string FmtPspTime(const ScePspDateTime &dt) { + return StringFromFormat("%04d-%02d-%02d %02d:%02d:%02d.%06d", dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond); +} + int SavedataParam::GetSizes(SceUtilitySavedataParam *param) { if (!param) { @@ -1197,9 +1209,13 @@ int SavedataParam::GetSizes(SceUtilitySavedataParam *param) // TODO: Maybe these are rounded to the nearest 32KB? Or something? param->utilityData->usedSpace32KB = total_size / 0x400; - spaceTxt = SavedataParam::GetSpaceText(total_size, true); + std::string spaceTxt32 = SavedataParam::GetSpaceText(total_size, true); memset(param->utilityData->usedSpace32Str, 0, sizeof(param->utilityData->usedSpace32Str)); - strncpy(param->utilityData->usedSpace32Str, spaceTxt.c_str(), sizeof(param->utilityData->usedSpace32Str)); + strncpy(param->utilityData->usedSpace32Str, spaceTxt32.c_str(), sizeof(param->utilityData->usedSpace32Str)); + + INFO_LOG(Log::sceUtility, "GetSize: usedSpaceKB: %d (str: %s) (clusters: %d)", param->utilityData->usedSpaceKB, spaceTxt.c_str(), param->utilityData->usedClusters); + INFO_LOG(Log::sceUtility, "GetSize: usedSpace32KB: %d (str32: %s)", param->utilityData->usedSpace32KB, spaceTxt32.c_str()); + NotifyMemInfo(MemBlockFlags::WRITE, param->utilityData.ptr, sizeof(SceUtilitySavedataUsedDataInfo), "SavedataGetSizes"); } return ret; @@ -1213,18 +1229,16 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param) if (param->idList.IsValid()) { - u32 maxFile = param->idList->maxCount; + u32 maxFileCount = param->idList->maxCount; std::vector validDir; std::vector sfoFiles; std::vector allDir = pspFileSystem.GetDirListing(savePath); std::string searchString = GetGameName(param) + GetSaveName(param); - for (size_t i = 0; i < allDir.size() && validDir.size() < maxFile; i++) - { + for (size_t i = 0; i < allDir.size() && validDir.size() < maxFileCount; i++) { std::string dirName = allDir[i].name; - if (PSPMatch(dirName, searchString)) - { + if (PSPMatch(dirName, searchString)) { validDir.push_back(allDir[i]); } } @@ -1257,7 +1271,14 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param) } // Save num of folder found param->idList->resultCount = (u32)validDir.size(); - + // Log out the listing. + if (GenericLogEnabled(LogLevel::LINFO, Log::sceUtility)) { + INFO_LOG(Log::sceUtility, "LIST (searchstring=%s): %d files (max: %d)", searchString.c_str(), param->idList->resultCount, maxFileCount); + for (int i = 0; i < validDir.size(); i++) { + INFO_LOG(Log::sceUtility, "%s: mode %08x, ctime: %s, atime: %s, mtime: %s", + entries[i].name, entries[i].st_mode, FmtPspTime(entries[i].st_ctime).c_str(), FmtPspTime(entries[i].st_atime).c_str(), FmtPspTime(entries[i].st_mtime).c_str()); + } + } NotifyMemInfo(MemBlockFlags::WRITE, param->idList.ptr, sizeof(SceUtilitySavedataIdListInfo), "SavedataGetList"); NotifyMemInfo(MemBlockFlags::WRITE, param->idList->entries.ptr, (uint32_t)validDir.size() * sizeof(SceUtilitySavedataIdListEntry), "SavedataGetList"); } @@ -1270,23 +1291,23 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) } if (!param->fileList.IsValid()) { - ERROR_LOG_REPORT(SCEUTILITY, "SavedataParam::GetFilesList(): bad fileList address %08x", param->fileList.ptr); + ERROR_LOG_REPORT(Log::sceUtility, "SavedataParam::GetFilesList(): bad fileList address %08x", param->fileList.ptr); // Should crash. return -1; } auto &fileList = param->fileList; if (fileList->secureEntries.IsValid() && fileList->maxSecureEntries > 99) { - ERROR_LOG_REPORT(SCEUTILITY, "SavedataParam::GetFilesList(): too many secure entries, %d", fileList->maxSecureEntries); + ERROR_LOG_REPORT(Log::sceUtility, "SavedataParam::GetFilesList(): too many secure entries, %d", fileList->maxSecureEntries); return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS; } if (fileList->normalEntries.IsValid() && fileList->maxNormalEntries > 8192) { - ERROR_LOG_REPORT(SCEUTILITY, "SavedataParam::GetFilesList(): too many normal entries, %d", fileList->maxNormalEntries); + ERROR_LOG_REPORT(Log::sceUtility, "SavedataParam::GetFilesList(): too many normal entries, %d", fileList->maxNormalEntries); return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS; } if (sceKernelGetCompiledSdkVersion() >= 0x02060000) { if (fileList->systemEntries.IsValid() && fileList->maxSystemEntries > 5) { - ERROR_LOG_REPORT(SCEUTILITY, "SavedataParam::GetFilesList(): too many system entries, %d", fileList->maxSystemEntries); + ERROR_LOG_REPORT(Log::sceUtility, "SavedataParam::GetFilesList(): too many system entries, %d", fileList->maxSystemEntries); return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS; } } @@ -1295,7 +1316,7 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) bool dirPathExists = false; auto files = pspFileSystem.GetDirListing(dirPath, &dirPathExists); if (!dirPathExists) { - DEBUG_LOG(SCEUTILITY, "SavedataParam::GetFilesList(): directory %s does not exist", dirPath.c_str()); + DEBUG_LOG(Log::sceUtility, "SavedataParam::GetFilesList(): directory %s does not exist", dirPath.c_str()); return SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; } @@ -1329,7 +1350,7 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) } // TODO: What are the exact rules? It definitely skips lowercase, and allows FILE or FILE.EXT. if (file->name.find_first_of("abcdefghijklmnopqrstuvwxyz") != file->name.npos) { - DEBUG_LOG(SCEUTILITY, "SavedataParam::GetFilesList(): skipping file %s with lowercase", file->name.c_str()); + DEBUG_LOG(Log::sceUtility, "SavedataParam::GetFilesList(): skipping file %s with lowercase", file->name.c_str()); continue; } @@ -1371,6 +1392,15 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) entry->name[15] = '\0'; } + if (GenericLogEnabled(LogLevel::LINFO, Log::sceUtility)) { + INFO_LOG(Log::sceUtility, "FILES: %d files listed", fileList->resultNumNormalEntries); + for (int i = 0; i < (int)fileList->resultNumNormalEntries; i++) { + const SceUtilitySavedataFileListEntry &info = fileList->systemEntries[i]; + INFO_LOG(Log::sceUtility, "%s: mode %08x, ctime: %s, atime: %s, mtime: %s", + info.name, info.st_mode, FmtPspTime(info.st_ctime).c_str(), FmtPspTime(info.st_atime).c_str(), FmtPspTime(info.st_mtime).c_str()); + } + } + NotifyMemInfo(MemBlockFlags::WRITE, fileList.ptr, sizeof(SceUtilitySavedataFileListInfo), "SavedataGetFilesList"); if (fileList->resultNumSystemEntries != 0) NotifyMemInfo(MemBlockFlags::WRITE, fileList->systemEntries.ptr, fileList->resultNumSystemEntries * sizeof(SceUtilitySavedataFileListEntry), "SavedataGetFilesList"); @@ -1382,18 +1412,15 @@ int SavedataParam::GetFilesList(SceUtilitySavedataParam *param, u32 requestAddr) return 0; } -bool SavedataParam::GetSize(SceUtilitySavedataParam *param) -{ - if (!param) - { +bool SavedataParam::GetSize(SceUtilitySavedataParam *param) { + if (!param) { return false; } const std::string saveDir = savePath + GetGameName(param) + GetSaveName(param); bool exists = false; - if (param->sizeInfo.IsValid()) - { + if (param->sizeInfo.IsValid()) { auto listing = pspFileSystem.GetDirListing(saveDir, &exists); const u64 freeBytes = MemoryStick_FreeSpace(); @@ -1425,27 +1452,30 @@ bool SavedataParam::GetSize(SceUtilitySavedataParam *param) param->sizeInfo->overwriteKB = 0; spaceTxt = GetSpaceText(0, true); - truncate_cpy(param->sizeInfo->neededString, spaceTxt.c_str()); - truncate_cpy(param->sizeInfo->overwriteString, spaceTxt.c_str()); + truncate_cpy(param->sizeInfo->neededString, spaceTxt); + truncate_cpy(param->sizeInfo->overwriteString, spaceTxt); } else { // Bytes needed to save additional data. s64 neededBytes = writeBytes - freeBytes; param->sizeInfo->neededKB = (neededBytes + 1023) / 1024; spaceTxt = GetSpaceText(neededBytes, true); - truncate_cpy(param->sizeInfo->neededString, spaceTxt.c_str()); + truncate_cpy(param->sizeInfo->neededString, spaceTxt); if (writeBytes - overwriteBytes < (s64)freeBytes) { param->sizeInfo->overwriteKB = 0; spaceTxt = GetSpaceText(0, true); - truncate_cpy(param->sizeInfo->overwriteString, spaceTxt.c_str()); + truncate_cpy(param->sizeInfo->overwriteString, spaceTxt); } else { s64 neededOverwriteBytes = writeBytes - freeBytes - overwriteBytes; param->sizeInfo->overwriteKB = (neededOverwriteBytes + 1023) / 1024; spaceTxt = GetSpaceText(neededOverwriteBytes, true); - truncate_cpy(param->sizeInfo->overwriteString, spaceTxt.c_str()); + truncate_cpy(param->sizeInfo->overwriteString, spaceTxt); } } + INFO_LOG(Log::sceUtility, "SectorSize: %d FreeSectors: %d FreeKB: %d neededKb: %d overwriteKb: %d", + param->sizeInfo->sectorSize, param->sizeInfo->freeSectors, param->sizeInfo->freeKB, param->sizeInfo->neededKB, param->sizeInfo->overwriteKB); + NotifyMemInfo(MemBlockFlags::WRITE, param->sizeInfo.ptr, sizeof(PspUtilitySavedataSizeInfo), "SavedataGetSize"); } @@ -1543,7 +1573,7 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) std::string fileDataPath = savePath + it->name; if (it->exists) { SetFileInfo(realCount, *it, saveName); - DEBUG_LOG(SCEUTILITY, "%s Exist", fileDataPath.c_str()); + DEBUG_LOG(Log::sceUtility, "%s Exist", fileDataPath.c_str()); ++realCount; } else { if (listEmptyFile) { @@ -1563,15 +1593,15 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) PSPFileInfo info = GetSaveInfo(fileDataDir); if (info.exists) { SetFileInfo(realCount, info, thisSaveName); - DEBUG_LOG(SCEUTILITY, "Save data exists: %s = %s", thisSaveName.c_str(), fileDataDir.c_str()); + INFO_LOG(Log::sceUtility, "Save data exists: %s = %s", thisSaveName.c_str(), fileDataDir.c_str()); realCount++; } else { if (listEmptyFile) { ClearFileInfo(saveDataList[realCount], thisSaveName); - DEBUG_LOG(SCEUTILITY, "Listing missing save data: %s = %s", thisSaveName.c_str(), fileDataDir.c_str()); + INFO_LOG(Log::sceUtility, "Listing missing save data: %s = %s", thisSaveName.c_str(), fileDataDir.c_str()); realCount++; } else { - DEBUG_LOG(SCEUTILITY, "Save data not found: %s = %s", thisSaveName.c_str(), fileDataDir.c_str()); + INFO_LOG(Log::sceUtility, "Save data not found: %s = %s", thisSaveName.c_str(), fileDataDir.c_str()); } } } @@ -1591,14 +1621,14 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) PSPFileInfo info = GetSaveInfo(fileDataDir); if (info.exists) { SetFileInfo(0, info, GetSaveName(param)); - DEBUG_LOG(SCEUTILITY, "Save data exists: %s = %s", GetSaveName(param).c_str(), fileDataDir.c_str()); + INFO_LOG(Log::sceUtility, "Save data exists: %s = %s", GetSaveName(param).c_str(), fileDataDir.c_str()); saveNameListDataCount = 1; } else { if (listEmptyFile) { ClearFileInfo(saveDataList[0], GetSaveName(param)); - DEBUG_LOG(SCEUTILITY, "Listing missing save data: %s = %s", GetSaveName(param).c_str(), fileDataDir.c_str()); + INFO_LOG(Log::sceUtility, "Listing missing save data: %s = %s", GetSaveName(param).c_str(), fileDataDir.c_str()); } else { - DEBUG_LOG(SCEUTILITY, "Save data not found: %s = %s", GetSaveName(param).c_str(), fileDataDir.c_str()); + INFO_LOG(Log::sceUtility, "Save data not found: %s = %s", GetSaveName(param).c_str(), fileDataDir.c_str()); } saveNameListDataCount = 0; return 0; @@ -1643,7 +1673,7 @@ void SavedataParam::SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, const SetStringFromSFO(*sfoFile, "SAVEDATA_DETAIL", saveInfo.saveDetail, sizeof(saveInfo.saveDetail)); } else { saveInfo.broken = true; - truncate_cpy(saveInfo.title, saveDir.c_str()); + truncate_cpy(saveInfo.title, saveDir); } } @@ -1913,7 +1943,7 @@ void SavedataParam::DoState(PointerWrap &p) { } } -void SavedataParam::ClearCaches() { +void SavedataParam::ClearSFOCache() { std::lock_guard guard(cacheLock_); sfoCache_.clear(); } @@ -1922,7 +1952,7 @@ std::shared_ptr SavedataParam::LoadCachedSFO(const std::string &pa std::lock_guard guard(cacheLock_); if (sfoCache_.find(path) == sfoCache_.end()) { std::vector data; - if (pspFileSystem.ReadEntireFile(path, data) < 0) { + if (pspFileSystem.ReadEntireFile(path, data, true) < 0) { // Mark as not existing for later. sfoCache_[path].reset(); } else { @@ -1963,7 +1993,7 @@ int SavedataParam::GetSaveCryptMode(const SceUtilitySavedataParam *param, const return 5; default: // Well, it's not zero, so yes. - ERROR_LOG_REPORT(SCEUTILITY, "Unexpected SAVEDATA_PARAMS hash flag: %02x", tmpDataOrig[0]); + ERROR_LOG_REPORT(Log::sceUtility, "Unexpected SAVEDATA_PARAMS hash flag: %02x", tmpDataOrig[0]); return 1; } } diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 04c8dca5e4..5f643dd4fb 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -21,6 +21,8 @@ #include #include #include +#include + #include "Common/CommonTypes.h" #include "Core/ELF/ParamSFO.h" #include "Core/MemMap.h" @@ -355,7 +357,7 @@ public: bool WouldHaveMultiSaveName(const SceUtilitySavedataParam *param); - void ClearCaches(); + void ClearSFOCache(); void DoState(PointerWrap &p); @@ -372,10 +374,12 @@ private: bool LoadSFO(SceUtilitySavedataParam *param, const std::string& dirPath); void LoadFile(const std::string& dirPath, const std::string& filename, PspUtilitySavedataFileData *fileData); - int DecryptSave(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, unsigned char *cryptkey, const u8 *expectedHash); + int DecryptData(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, unsigned char *cryptkey, const u8 *expectedHash); int EncryptData(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, unsigned char *hash, unsigned char *cryptkey); int UpdateHash(u8* sfoData, int sfoSize, int sfoDataParamsOffset, int encryptmode); - int BuildHash(unsigned char *output, unsigned char *data, unsigned int len, unsigned int alignedLen, int mode, unsigned char *cryptkey); + + // data must be zero-padded from len to alignedLen (which should be the next multiply of 16)! + int BuildHash(uint8_t *output, const uint8_t *data, unsigned int len, unsigned int alignedLen, int mode, const uint8_t *cryptkey); int DetermineCryptMode(const SceUtilitySavedataParam *param) const; std::vector GetSFOEntries(const std::string &dirPath); diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index 2eec38aa86..7adceca25d 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -37,7 +37,7 @@ const char *ElfReader::GetSectionName(int section) const { int stringsOffset = GetSectionDataOffset(header->e_shstrndx); int nameOffset = sections[section].sh_name; if (nameOffset < 0 || (size_t)nameOffset + stringsOffset >= size_) { - ERROR_LOG(LOADER, "ELF: Bad name offset %d + %d in section %d (max = %d)", nameOffset, stringsOffset, section, (int)size_); + ERROR_LOG(Log::Loader, "ELF: Bad name offset %d + %d in section %d (max = %d)", nameOffset, stringsOffset, section, (int)size_); return nullptr; } const char *ptr = (const char *)GetSectionDataPtr(header->e_shstrndx); @@ -56,7 +56,7 @@ void addrToHiLo(u32 addr, u16 &hi, s16 &lo) u32 test = (hi<<16) + lo; if (test != addr) { - WARN_LOG_REPORT(LOADER, "HI16/LO16 relocation failure?"); + WARN_LOG_REPORT(Log::Loader, "HI16/LO16 relocation failure?"); } } @@ -64,7 +64,7 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { std::vector relocOps; relocOps.resize(numRelocs); - DEBUG_LOG(LOADER, "Loading %i relocations...", numRelocs); + DEBUG_LOG(Log::Loader, "Loading %i relocations...", numRelocs); std::atomic numErrors; numErrors.store(0); @@ -79,7 +79,7 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { int readwrite = (info >> 8) & 0xff; if (readwrite >= (int)ARRAY_SIZE(segmentVAddr)) { if (numErrors < 10) { - ERROR_LOG_REPORT(LOADER, "Bad segment number %i", readwrite); + ERROR_LOG_REPORT(Log::Loader, "Bad segment number %i", readwrite); } numErrors++; continue; @@ -90,9 +90,9 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { // It appears that misaligned relocations are allowed. if (((addr & 3) && type != R_MIPS_32) || !Memory::IsValidAddress(addr)) { if (numErrors < 10) { - WARN_LOG_REPORT(LOADER, "Suspicious address %08x, skipping reloc, type = %d", addr, type); + WARN_LOG_REPORT(Log::Loader, "Suspicious address %08x, skipping reloc, type = %d", addr, type); } else if (numErrors == 10) { - WARN_LOG(LOADER, "Too many bad relocations, skipping logging"); + WARN_LOG(Log::Loader, "Too many bad relocations, skipping logging"); } numErrors++; continue; @@ -104,7 +104,7 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { ParallelRangeLoop(&g_threadManager, [&](int l, int h) { for (int r = l; r < h; r++) { - VERBOSE_LOG(LOADER, "Loading reloc %i (%p)...", r, rels + r); + VERBOSE_LOG(Log::Loader, "Loading reloc %i (%p)...", r, rels + r); u32 info = rels[r].r_info; u32 addr = rels[r].r_offset; @@ -126,14 +126,14 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { const bool log = false; //log=true; if (log) { - DEBUG_LOG(LOADER, "rel at: %08x info: %08x type: %i", addr, info, type); + DEBUG_LOG(Log::Loader, "rel at: %08x info: %08x type: %i", addr, info, type); } u32 relocateTo = relative >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[relative]; switch (type) { case R_MIPS_32: if (log) - DEBUG_LOG(LOADER, "Full address reloc %08x", addr); + DEBUG_LOG(Log::Loader, "Full address reloc %08x", addr); //full address, no problemo op += relocateTo; break; @@ -141,14 +141,14 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { case R_MIPS_26: //j, jal //add on to put in correct address space if (log) - DEBUG_LOG(LOADER, "j/jal reloc %08x", addr); + DEBUG_LOG(Log::Loader, "j/jal reloc %08x", addr); op = (op & 0xFC000000) | (((op & 0x03FFFFFF) + (relocateTo >> 2)) & 0x03FFFFFF); break; case R_MIPS_HI16: //lui part of lui-addiu pairs { if (log) - DEBUG_LOG(LOADER, "HI reloc %08x", addr); + DEBUG_LOG(Log::Loader, "HI reloc %08x", addr); u32 cur = (op & 0xFFFF) << 16; u16 hi = 0; @@ -165,19 +165,19 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { if (t_type != R_MIPS_LO16) { if (t_type != R_MIPS_16) { // Let's play it safe for now and skip. We've only seen this type. - ERROR_LOG_REPORT(LOADER, "ELF relocation HI16/%d pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr); + ERROR_LOG_REPORT(Log::Loader, "ELF relocation HI16/%d pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr); continue; } else { - WARN_LOG_REPORT(LOADER, "ELF relocation HI16/%d(16) pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr); + WARN_LOG_REPORT(Log::Loader, "ELF relocation HI16/%d(16) pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr); } } // Should have matching index and segment info, according to llvm, which makes sense. if ((rels[t].r_info >> 8) != (rels[r].r_info >> 8)) { - WARN_LOG_REPORT(LOADER, "ELF relocation HI16/LO16 with mismatching r_info lo=%08x, hi=%08x", rels[t].r_info, rels[r].r_info); + WARN_LOG_REPORT(Log::Loader, "ELF relocation HI16/LO16 with mismatching r_info lo=%08x, hi=%08x", rels[t].r_info, rels[r].r_info); } if (log) { - DEBUG_LOG(LOADER, "Corresponding lo found at %08x", corrLoAddr); + DEBUG_LOG(Log::Loader, "Corresponding lo found at %08x", corrLoAddr); } if (Memory::IsValidAddress(corrLoAddr)) { s16 lo = (s16)relocOps[t]; @@ -187,11 +187,11 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { found = true; break; } else { - ERROR_LOG(LOADER, "Bad corrLoAddr %08x", corrLoAddr); + ERROR_LOG(Log::Loader, "Bad corrLoAddr %08x", corrLoAddr); } } if (!found) { - ERROR_LOG_REPORT(LOADER, "R_MIPS_HI16: could not find R_MIPS_LO16 (r=%d of %d, addr=%08x)", r, numRelocs, addr); + ERROR_LOG_REPORT(Log::Loader, "R_MIPS_HI16: could not find R_MIPS_LO16 (r=%d of %d, addr=%08x)", r, numRelocs, addr); } op = (op & 0xFFFF0000) | hi; } @@ -200,7 +200,7 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { case R_MIPS_LO16: //addiu part of lui-addiu pairs { if (log) - DEBUG_LOG(LOADER, "LO reloc %08x", addr); + DEBUG_LOG(Log::Loader, "LO reloc %08x", addr); u32 cur = op & 0xFFFF; cur += relocateTo; cur &= 0xFFFF; @@ -224,7 +224,7 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { { char temp[256]; MIPSDisAsm(MIPSOpcode(op), 0, temp, sizeof(temp)); - ERROR_LOG_REPORT(LOADER, "ARGH IT'S AN UNKNOWN RELOCATION!!!!!!!! %08x, type=%d : %s", addr, type, temp); + ERROR_LOG_REPORT(Log::Loader, "ARGH IT'S AN UNKNOWN RELOCATION!!!!!!!! %08x, type=%d : %s", addr, type, temp); } break; } @@ -235,7 +235,7 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) { }, 0, numRelocs, 128, TaskPriority::HIGH); if (numErrors) { - WARN_LOG(LOADER, "%i bad relocations found!!!", numErrors.load()); + WARN_LOG(Log::Loader, "%i bad relocations found!!!", numErrors.load()); } return numErrors == 0; } @@ -256,7 +256,7 @@ void ElfReader::LoadRelocations2(int rel_seg) buf = (u8*)GetSegmentPtr(rel_seg); if (!buf) { - ERROR_LOG_REPORT(LOADER, "Rel2 segment invalid"); + ERROR_LOG_REPORT(Log::Loader, "Rel2 segment invalid"); return; } end = buf+ph->p_filesz; @@ -303,14 +303,14 @@ void ElfReader::LoadRelocations2(int rel_seg) rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24); buf += 4; }else{ - ERROR_LOG_REPORT(LOADER, "Rel2: invalid size flag! %x", flag); + ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid size flag! %x", flag); rel_base = 0; } }else{ addr_seg = seg; relocate_to = addr_seg >= (int)ARRAY_SIZE(segmentVAddr) ? 0 : segmentVAddr[addr_seg]; if (!Memory::IsValidAddress(relocate_to)) { - ERROR_LOG_REPORT(LOADER, "ELF: Bad address to relocate to: %08x (segment %d)", relocate_to, addr_seg); + ERROR_LOG_REPORT(Log::Loader, "ELF: Bad address to relocate to: %08x (segment %d)", relocate_to, addr_seg); continue; } @@ -336,13 +336,13 @@ void ElfReader::LoadRelocations2(int rel_seg) rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24); buf += 4; }else{ - ERROR_LOG_REPORT(LOADER, "Rel2: invalid relocat size flag! %x", flag); + ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid relocat size flag! %x", flag); } rel_offset = rel_base+segmentVAddr[off_seg]; if (!Memory::IsValidAddress(rel_offset)) { - ERROR_LOG_REPORT(LOADER, "ELF: Bad rel_offset: %08x", rel_offset); + ERROR_LOG_REPORT(Log::Loader, "ELF: Bad rel_offset: %08x", rel_offset); continue; } @@ -357,11 +357,11 @@ void ElfReader::LoadRelocations2(int rel_seg) lo16 |= 0xffff0000; buf += 2; }else{ - ERROR_LOG_REPORT(LOADER, "Rel2: invalid lo16 type! %x", flag); + ERROR_LOG_REPORT(Log::Loader, "Rel2: invalid lo16 type! %x", flag); } op = Memory::Read_Instruction(rel_offset, true).encoding; - DEBUG_LOG(LOADER, "Rel2: %5d: CMD=0x%04X flag=%x type=%d off_seg=%d offset=%08x addr_seg=%d op=%08x\n", rcount, cmd, flag, type, off_seg, rel_base, addr_seg, op); + DEBUG_LOG(Log::Loader, "Rel2: %5d: CMD=0x%04X flag=%x type=%d off_seg=%d offset=%08x addr_seg=%d op=%08x\n", rcount, cmd, flag, type, off_seg, rel_base, addr_seg, op); switch(type){ case 0: @@ -390,7 +390,7 @@ void ElfReader::LoadRelocations2(int rel_seg) op = (op&0xffff0000) | (((op&0xffff)+relocate_to)&0xffff); break; default: - ERROR_LOG_REPORT(LOADER, "Rel2: unexpected relocation type! %x", type); + ERROR_LOG_REPORT(Log::Loader, "Rel2: unexpected relocation type! %x", type); break; } @@ -405,10 +405,10 @@ void ElfReader::LoadRelocations2(int rel_seg) int ElfReader::LoadInto(u32 loadAddress, bool fromTop) { - DEBUG_LOG(LOADER,"String section: %i", header->e_shstrndx); + DEBUG_LOG(Log::Loader,"String section: %i", header->e_shstrndx); if (size_ < sizeof(Elf32_Ehdr)) { - ERROR_LOG(LOADER, "Truncated ELF header, %d bytes", (int)size_); + ERROR_LOG(Log::Loader, "Truncated ELF header, %d bytes", (int)size_); // Probably not the right error code. return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; } @@ -423,14 +423,14 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; } - ERROR_LOG(LOADER, "Bad ELF, EI_CLASS (fifth byte) is 0x00, should be 0x01 - would lock up a PSP."); + ERROR_LOG(Log::Loader, "Bad ELF, EI_CLASS (fifth byte) is 0x00, should be 0x01 - would lock up a PSP."); } if (header->e_ident[EI_DATA] != ELFDATA2LSB) return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; if (size_ < header->e_phoff + sizeof(Elf32_Phdr) * GetNumSegments() || size_ < header->e_shoff + sizeof(Elf32_Shdr) * GetNumSections()) { - ERROR_LOG(LOADER, "Truncated ELF, %d bytes with %d sections and %d segments", (int)size_, GetNumSections(), GetNumSegments()); + ERROR_LOG(Log::Loader, "Truncated ELF, %d bytes with %d sections and %d segments", (int)size_, GetNumSections(), GetNumSegments()); // Probably not the right error code. return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; } @@ -498,19 +498,19 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) } if (vaddr == (u32)-1) { - ERROR_LOG_REPORT(LOADER, "Failed to allocate memory for ELF!"); + ERROR_LOG_REPORT(Log::Loader, "Failed to allocate memory for ELF!"); return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; } if (bRelocate) { - DEBUG_LOG(LOADER,"Relocatable module"); + DEBUG_LOG(Log::Loader,"Relocatable module"); if (entryPoint != (u32)-1) entryPoint += vaddr; } else { - DEBUG_LOG(LOADER,"Prerelocated executable"); + DEBUG_LOG(Log::Loader,"Prerelocated executable"); } - DEBUG_LOG(LOADER,"%i segments:", header->e_phnum); + DEBUG_LOG(Log::Loader,"%i segments:", header->e_phnum); // First pass : Get the damn bits into RAM u32 baseAddress = bRelocate ? vaddr : 0; @@ -518,7 +518,7 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) for (int i = 0; i < header->e_phnum; i++) { const Elf32_Phdr *p = segments + i; - DEBUG_LOG(LOADER, "Type: %08x Vaddr: %08x Filesz: %08x Memsz: %08x ", (int)p->p_type, (u32)p->p_vaddr, (int)p->p_filesz, (int)p->p_memsz); + DEBUG_LOG(Log::Loader, "Type: %08x Vaddr: %08x Filesz: %08x Memsz: %08x ", (int)p->p_type, (u32)p->p_vaddr, (int)p->p_filesz, (int)p->p_memsz); if (p->p_type == PT_LOAD) { @@ -527,7 +527,7 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) const u8 *src = GetSegmentPtr(i); if (!src || p->p_offset + p->p_filesz > size_) { - ERROR_LOG(LOADER, "Segment %d pointer invalid - truncated?", i); + ERROR_LOG(Log::Loader, "Segment %d pointer invalid - truncated?", i); continue; } u32 srcSize = p->p_filesz; @@ -542,15 +542,15 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) memcpy(dst, src, srcSize); std::string tag = StringFromFormat("ELFLoad/%08x", writeAddr); NotifyMemInfo(MemBlockFlags::WRITE, writeAddr, srcSize, tag.c_str(), tag.size()); - DEBUG_LOG(LOADER, "Loadable Segment Copied to %08x, size %08x", writeAddr, (u32)p->p_memsz); + DEBUG_LOG(Log::Loader, "Loadable Segment Copied to %08x, size %08x", writeAddr, (u32)p->p_memsz); } else { - ERROR_LOG(LOADER, "Bad ELF segment. Trying to write %d bytes to %08x", dstSize, writeAddr); + ERROR_LOG(Log::Loader, "Bad ELF segment. Trying to write %d bytes to %08x", dstSize, writeAddr); } } } memblock.ListBlocks(); - DEBUG_LOG(LOADER,"%i sections:", header->e_shnum); + DEBUG_LOG(Log::Loader,"%i sections:", header->e_shnum); sectionOffsets = new u32[GetNumSections()]; sectionAddrs = new u32[GetNumSections()]; @@ -568,15 +568,15 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) { std::string tag = name && name[0] ? StringFromFormat("%s/%s", modName.c_str(), name) : StringFromFormat("%s/%08x", modName.c_str(), writeAddr); NotifyMemInfo(MemBlockFlags::SUB_ALLOC, writeAddr, s->sh_size, tag.c_str(), tag.size()); - DEBUG_LOG(LOADER,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, (u32)s->sh_size); + DEBUG_LOG(Log::Loader,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, (u32)s->sh_size); } else { - DEBUG_LOG(LOADER,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, (u32)s->sh_size, (u32)s->sh_flags); + DEBUG_LOG(Log::Loader,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, (u32)s->sh_size, (u32)s->sh_flags); } } - DEBUG_LOG(LOADER, "Relocations:"); + DEBUG_LOG(Log::Loader, "Relocations:"); // Second pass: Do necessary relocations for (int i = 0; i < GetNumSections(); i++) @@ -592,7 +592,7 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) { if (!(sections[sectionToModify].sh_flags & SHF_ALLOC)) { - ERROR_LOG_REPORT(LOADER, "Trying to relocate non-loaded section %s", GetSectionName(sectionToModify)); + ERROR_LOG_REPORT(Log::Loader, "Trying to relocate non-loaded section %s", GetSectionName(sectionToModify)); continue; } @@ -602,22 +602,22 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) if (GetSectionDataOffset(i) + sizeof(Elf32_Rel) * numRelocs > size_) rels = nullptr; - DEBUG_LOG(LOADER,"%s: Performing %i relocations on %s : offset = %08x", name, numRelocs, GetSectionName(sectionToModify), sections[i].sh_offset); + DEBUG_LOG(Log::Loader,"%s: Performing %i relocations on %s : offset = %08x", name, numRelocs, GetSectionName(sectionToModify), sections[i].sh_offset); if (!rels || !LoadRelocations(rels, numRelocs)) { - WARN_LOG(LOADER, "LoadInto: Relocs failed, trying anyway"); + WARN_LOG(Log::Loader, "LoadInto: Relocs failed, trying anyway"); } } else { - WARN_LOG_REPORT(LOADER, "sectionToModify = %i - ignoring PSP relocation sector %i", sectionToModify, i); + WARN_LOG_REPORT(Log::Loader, "sectionToModify = %i - ignoring PSP relocation sector %i", sectionToModify, i); } } else if (s->sh_type == SHT_REL) { - DEBUG_LOG(LOADER, "Traditional relocation section found."); + DEBUG_LOG(Log::Loader, "Traditional relocation section found."); if (!bRelocate) { - DEBUG_LOG(LOADER, "Binary is prerelocated. Skipping relocations."); + DEBUG_LOG(Log::Loader, "Binary is prerelocated. Skipping relocations."); } else { @@ -628,15 +628,15 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) if (!(sections[sectionToModify].sh_flags & SHF_ALLOC)) { // Generally stuff like debug info. We don't need it. - INFO_LOG(LOADER, "Skipping relocation of non-loaded section %s", GetSectionName(sectionToModify)); + INFO_LOG(Log::Loader, "Skipping relocation of non-loaded section %s", GetSectionName(sectionToModify)); continue; } } else { - WARN_LOG_REPORT(LOADER, "sectionToModify = %i - ignoring relocation sector %i", sectionToModify, i); + WARN_LOG_REPORT(Log::Loader, "sectionToModify = %i - ignoring relocation sector %i", sectionToModify, i); } - ERROR_LOG_REPORT(LOADER, "Traditional relocations unsupported."); + ERROR_LOG_REPORT(Log::Loader, "Traditional relocations unsupported."); } } } @@ -647,17 +647,17 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) { const Elf32_Phdr *p = &segments[i]; if (p->p_type == PT_PSPREL1) { - INFO_LOG(LOADER,"Loading segment relocations"); + INFO_LOG(Log::Loader,"Loading segment relocations"); int numRelocs = p->p_filesz / sizeof(Elf32_Rel); Elf32_Rel *rels = (Elf32_Rel *)GetSegmentPtr(i); if (p->p_offset + p->p_filesz > size_) rels = nullptr; if (!rels || !LoadRelocations(rels, numRelocs)) { - ERROR_LOG(LOADER, "LoadInto: Relocs failed, trying anyway (2)"); + ERROR_LOG(Log::Loader, "LoadInto: Relocs failed, trying anyway (2)"); } } else if (p->p_type == PT_PSPREL2) { - INFO_LOG(LOADER,"Loading segment relocations2"); + INFO_LOG(Log::Loader,"Loading segment relocations2"); LoadRelocations2(i); } } @@ -749,7 +749,7 @@ bool ElfReader::LoadSymbols() int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); if (!stringBase || !symtab || symtabOffset + sections[sec].sh_size > size_) { - ERROR_LOG(LOADER, "Symbols truncated - ignoring"); + ERROR_LOG(Log::Loader, "Symbols truncated - ignoring"); return false; } diff --git a/Core/ELF/PBPReader.cpp b/Core/ELF/PBPReader.cpp index 6bf9157813..72cab6df8d 100644 --- a/Core/ELF/PBPReader.cpp +++ b/Core/ELF/PBPReader.cpp @@ -25,26 +25,26 @@ PBPReader::PBPReader(FileLoader *fileLoader) : file_(nullptr), header_(), isELF_(false) { if (!fileLoader->Exists()) { - ERROR_LOG(LOADER, "Failed to open PBP file %s", fileLoader->GetPath().c_str()); + ERROR_LOG(Log::Loader, "Failed to open PBP file %s", fileLoader->GetPath().c_str()); return; } fileSize_ = (size_t)fileLoader->FileSize(); if (fileLoader->ReadAt(0, sizeof(header_), (u8 *)&header_) != sizeof(header_)) { - ERROR_LOG(LOADER, "PBP is too small to be valid: %s", fileLoader->GetPath().c_str()); + ERROR_LOG(Log::Loader, "PBP is too small to be valid: %s", fileLoader->GetPath().c_str()); return; } if (memcmp(header_.magic, "\0PBP", 4) != 0) { if (memcmp(header_.magic, "\nFLE", 4) != 0) { - VERBOSE_LOG(LOADER, "%s: File actually an ELF, not a PBP", fileLoader->GetPath().c_str()); + VERBOSE_LOG(Log::Loader, "%s: File actually an ELF, not a PBP", fileLoader->GetPath().c_str()); isELF_ = true; } else { - ERROR_LOG(LOADER, "Magic number in %s indicated no PBP: %s", fileLoader->GetPath().c_str(), header_.magic); + ERROR_LOG(Log::Loader, "Magic number in %s indicated no PBP: %s", fileLoader->GetPath().c_str(), header_.magic); } return; } - VERBOSE_LOG(LOADER, "Loading PBP, version = %08x", header_.version); + VERBOSE_LOG(Log::Loader, "Loading PBP, version = %08x", header_.version); file_ = fileLoader; } @@ -59,7 +59,7 @@ bool PBPReader::GetSubFile(PBPSubFile file, std::vector *out) { out->resize(expected); size_t bytes = file_->ReadAt(off, expected, &(*out)[0]); if (bytes != expected) { - ERROR_LOG(LOADER, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes); + ERROR_LOG(Log::Loader, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes); if (bytes < expected) { out->resize(bytes); } @@ -79,7 +79,7 @@ void PBPReader::GetSubFileAsString(PBPSubFile file, std::string *out) { out->resize(expected); size_t bytes = file_->ReadAt(off, expected, (void *)out->data()); if (bytes != expected) { - ERROR_LOG(LOADER, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes); + ERROR_LOG(Log::Loader, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes); if (bytes < expected) { out->resize(bytes); } diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index bbd14ca454..e9e96be1a6 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -62,24 +62,28 @@ void ParamSFOData::SetValue(const std::string &key, const u8 *value, unsigned in int ParamSFOData::GetValueInt(const std::string &key) const { std::map::const_iterator it = values.find(key); - if(it == values.end() || it->second.type != VT_INT) + if (it == values.end() || it->second.type != VT_INT) return 0; return it->second.i_value; } std::string ParamSFOData::GetValueString(const std::string &key) const { std::map::const_iterator it = values.find(key); - if(it == values.end() || (it->second.type != VT_UTF8)) + if (it == values.end() || (it->second.type != VT_UTF8)) return ""; return it->second.s_value; } +bool ParamSFOData::HasKey(const std::string &key) const { + return values.find(key) != values.end(); +} + const u8 *ParamSFOData::GetValueData(const std::string &key, unsigned int *size) const { std::map::const_iterator it = values.find(key); - if(it == values.end() || (it->second.type != VT_UTF8_SPE)) + if (it == values.end() || (it->second.type != VT_UTF8_SPE)) { return 0; - if(size) - { + } + if (size) { *size = it->second.u_size; } return it->second.u_value; @@ -97,7 +101,7 @@ std::string ParamSFOData::GetDiscID() { const std::string discID = GetValueString("DISC_ID"); if (discID.empty()) { std::string fakeID = GenerateFakeID(Path()); - WARN_LOG(LOADER, "No DiscID found - generating a fake one: '%s' (from %s)", fakeID.c_str(), PSP_CoreParameter().fileToStart.c_str()); + WARN_LOG(Log::Loader, "No DiscID found - generating a fake one: '%s' (from %s)", fakeID.c_str(), PSP_CoreParameter().fileToStart.c_str()); ValueData data; data.type = VT_UTF8; data.s_value = fakeID; @@ -115,7 +119,7 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { if (header->magic != 0x46535000) return false; if (header->version != 0x00000101) - WARN_LOG(LOADER, "Unexpected SFO header version: %08x", header->version); + WARN_LOG(Log::Loader, "Unexpected SFO header version: %08x", header->version); const IndexTable *indexTables = (const IndexTable *)(paramsfo + sizeof(Header)); @@ -165,7 +169,7 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { // Unsigned int const u32_le *data = (const u32_le *)(paramsfo + data_offset); SetValue(key, *data, indexTables[i].param_max_len); - VERBOSE_LOG(LOADER, "%s %08x", key.c_str(), *data); + VERBOSE_LOG(Log::Loader, "%s %08x", key.c_str(), *data); } break; case 0x0004: @@ -174,7 +178,7 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { if (data_offset + indexTables[i].param_len > size) continue; const u8 *utfdata = (const u8 *)(paramsfo + data_offset); - VERBOSE_LOG(LOADER, "%s %s", key.c_str(), utfdata); + VERBOSE_LOG(Log::Loader, "%s %s", key.c_str(), utfdata); SetValue(key, utfdata, indexTables[i].param_len, indexTables[i].param_max_len); } break; @@ -183,7 +187,7 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { { // TODO: Likely should use param_len here, but there's gotta be a reason we avoided it before. std::string str = readStringCapped(data_offset, indexTables[i].param_max_len); - VERBOSE_LOG(LOADER, "%s %s", key.c_str(), str.c_str()); + VERBOSE_LOG(Log::Loader, "%s %s", key.c_str(), str.c_str()); SetValue(key, str, indexTables[i].param_max_len); } break; @@ -195,12 +199,12 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { return true; } -int ParamSFOData::GetDataOffset(const u8 *paramsfo, const std::string &dataName) { +int ParamSFOData::GetDataOffset(const u8 *paramsfo, const char *dataName) { const Header *header = (const Header *)paramsfo; if (header->magic != 0x46535000) return -1; if (header->version != 0x00000101) - WARN_LOG(LOADER, "Unexpected SFO header version: %08x", header->version); + WARN_LOG(Log::Loader, "Unexpected SFO header version: %08x", header->version); const IndexTable *indexTables = (const IndexTable *)(paramsfo + sizeof(Header)); @@ -210,7 +214,7 @@ int ParamSFOData::GetDataOffset(const u8 *paramsfo, const std::string &dataName) for (u32 i = 0; i < header->index_table_entries; i++) { const char *key = (const char *)(key_start + indexTables[i].key_table_offset); - if (!strcmp(key, dataName.c_str())) + if (!strcmp(key, dataName)) { return data_start + indexTables[i].data_table_offset; } @@ -219,7 +223,7 @@ int ParamSFOData::GetDataOffset(const u8 *paramsfo, const std::string &dataName) return -1; } -bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) const { +void ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) const { size_t total_size = 0; size_t key_size = 0; size_t data_size = 0; @@ -251,9 +255,10 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) const { total_size += data_size; *size = total_size; - u8* data = new u8[total_size]; + size_t aligned_size = (total_size + 15) & ~15; + u8* data = new u8[aligned_size]; *paramsfo = data; - memset(data, 0, total_size); + memset(data, 0, aligned_size); memcpy(data, &header, sizeof(Header)); // Now fill @@ -300,8 +305,6 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) const { index_ptr++; } - - return true; } void ParamSFOData::Clear() { diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index 23af2f0c3f..cb76cde4a6 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -35,6 +35,7 @@ public: int GetValueInt(const std::string &key) const; std::string GetValueString(const std::string &key) const; + bool HasKey(const std::string &key) const; const u8 *GetValueData(const std::string &key, unsigned int *size) const; std::vector GetKeys() const; @@ -42,9 +43,11 @@ public: std::string GetDiscID(); - bool ReadSFO(const u8 *paramsfo, size_t size); - bool WriteSFO(u8 **paramsfo, size_t *size) const; + // This allocates a buffer (*paramsfo) using new[], whose size is zero-filled up to a multiple of 16 bytes. + // This is required for SavedataParam::BuildHash. + void WriteSFO(u8 **paramsfo, size_t *size) const; + bool ReadSFO(const u8 *paramsfo, size_t size); bool ReadSFO(const std::vector ¶msfo) { if (!paramsfo.empty()) { return ReadSFO(¶msfo[0], paramsfo.size()); @@ -53,7 +56,8 @@ public: } } - int GetDataOffset(const u8 *paramsfo, const std::string &dataName); + // If not found, returns a negative value. + int GetDataOffset(const u8 *paramsfo, const char *dataName); void Clear(); diff --git a/Core/ELF/PrxDecrypter.cpp b/Core/ELF/PrxDecrypter.cpp index 3b21bf2cec..bf987f6fa7 100644 --- a/Core/ELF/PrxDecrypter.cpp +++ b/Core/ELF/PrxDecrypter.cpp @@ -713,7 +713,7 @@ static_assert(sizeof(PRXType6) == 0x150, "inconsistent size of PRX Type 6"); static int pspDecryptType0(const u8 *inbuf, u8 *outbuf, u32 size) { - INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); + INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); const auto decryptSize = *(s32_le*)&inbuf[0xB0]; const auto pti = GetTagInfo((u32)*(u32_le *)&inbuf[0xD0]); @@ -767,7 +767,7 @@ static int pspDecryptType0(const u8 *inbuf, u8 *outbuf, u32 size) static int pspDecryptType1(const u8 *inbuf, u8 *outbuf, u32 size) { - INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); + INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); const auto decryptSize = *(s32_le*)&inbuf[0xB0]; const auto pti = GetTagInfo((u32)*(u32_le *)&inbuf[0xD0]); @@ -822,7 +822,7 @@ static int pspDecryptType1(const u8 *inbuf, u8 *outbuf, u32 size) static int pspDecryptType2(const u8 *inbuf, u8 *outbuf, u32 size) { - INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); + INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); const auto decryptSize = *(s32_le*)&inbuf[0xB0]; const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]); @@ -886,7 +886,7 @@ static int pspDecryptType2(const u8 *inbuf, u8 *outbuf, u32 size) static int pspDecryptType5(const u8 *inbuf, u8 *outbuf, u32 size, const u8 *seed) { - INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); + INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); const auto decryptSize = *(s32_le*)&inbuf[0xB0]; const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]); @@ -950,7 +950,7 @@ static int pspDecryptType5(const u8 *inbuf, u8 *outbuf, u32 size, const u8 *seed static int pspDecryptType6(const u8 *inbuf, u8 *outbuf, u32 size) { - INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); + INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); const auto decryptSize = *(s32_le*)&inbuf[0xB0]; const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]); diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index 74df741201..12b715072c 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -212,7 +212,7 @@ void DiskCachingFileLoaderCache::ShutdownCache() { } if (failed) { // Leave it locked, it's broken. - ERROR_LOG(LOADER, "Unable to flush disk cache."); + ERROR_LOG(Log::Loader, "Unable to flush disk cache."); } else { LockCacheFile(false); } @@ -475,7 +475,7 @@ bool DiskCachingFileLoaderCache::ReadBlockData(u8 *dest, BlockInfo &info, size_t #endif if (failed) { - ERROR_LOG(LOADER, "Unable to read disk cache data entry."); + ERROR_LOG(Log::Loader, "Unable to read disk cache data entry."); CloseFileHandle(); } return !failed; @@ -503,7 +503,7 @@ void DiskCachingFileLoaderCache::WriteBlockData(BlockInfo &info, const u8 *src) #endif if (failed) { - ERROR_LOG(LOADER, "Unable to write disk cache data entry."); + ERROR_LOG(Log::Loader, "Unable to write disk cache data entry."); CloseFileHandle(); } } @@ -523,7 +523,7 @@ void DiskCachingFileLoaderCache::WriteIndexData(u32 indexPos, BlockInfo &info) { } if (failed) { - ERROR_LOG(LOADER, "Unable to write disk cache index entry."); + ERROR_LOG(Log::Loader, "Unable to write disk cache index entry."); CloseFileHandle(); } } @@ -564,7 +564,7 @@ bool DiskCachingFileLoaderCache::LoadCacheFile(const Path &path) { flags_ = header.flags; LoadCacheIndex(); } else { - ERROR_LOG(LOADER, "Disk cache file header did not match, recreating cache file"); + ERROR_LOG(Log::Loader, "Disk cache file header did not match, recreating cache file"); fclose(fp); } @@ -621,14 +621,14 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const Path &path) { if (maxBlocks_ < MAX_BLOCKS_LOWER_BOUND) { // There's not enough free space to cache, disable. f_ = nullptr; - ERROR_LOG(LOADER, "Not enough free space; disabling disk cache"); + ERROR_LOG(Log::Loader, "Not enough free space; disabling disk cache"); return; } flags_ = 0; f_ = File::OpenCFile(path, "wb+"); if (!f_) { - ERROR_LOG(LOADER, "Could not create disk cache file"); + ERROR_LOG(Log::Loader, "Could not create disk cache file"); return; } #ifdef __ANDROID__ @@ -666,7 +666,7 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const Path &path) { return; } - INFO_LOG(LOADER, "Created new disk cache file for %s", origPath_.c_str()); + INFO_LOG(Log::Loader, "Created new disk cache file for %s", origPath_.c_str()); } bool DiskCachingFileLoaderCache::LockCacheFile(bool lockStatus) { @@ -684,7 +684,7 @@ bool DiskCachingFileLoaderCache::LockCacheFile(bool lockStatus) { } if (failed) { - ERROR_LOG(LOADER, "Unable to read current flags during disk cache locking"); + ERROR_LOG(Log::Loader, "Unable to read current flags during disk cache locking"); CloseFileHandle(); return false; } @@ -692,13 +692,13 @@ bool DiskCachingFileLoaderCache::LockCacheFile(bool lockStatus) { // TODO: Also use flock where supported? if (lockStatus) { if ((flags_ & FLAG_LOCKED) != 0) { - ERROR_LOG(LOADER, "Could not lock disk cache file for %s (already locked)", origPath_.c_str()); + ERROR_LOG(Log::Loader, "Could not lock disk cache file for %s (already locked)", origPath_.c_str()); return false; } flags_ |= FLAG_LOCKED; } else { if ((flags_ & FLAG_LOCKED) == 0) { - ERROR_LOG(LOADER, "Could not unlock disk cache file for %s", origPath_.c_str()); + ERROR_LOG(Log::Loader, "Could not unlock disk cache file for %s", origPath_.c_str()); return false; } flags_ &= ~FLAG_LOCKED; @@ -713,15 +713,15 @@ bool DiskCachingFileLoaderCache::LockCacheFile(bool lockStatus) { } if (failed) { - ERROR_LOG(LOADER, "Unable to write updated flags during disk cache locking"); + ERROR_LOG(Log::Loader, "Unable to write updated flags during disk cache locking"); CloseFileHandle(); return false; } if (lockStatus) { - INFO_LOG(LOADER, "Locked disk cache file for %s", origPath_.c_str()); + INFO_LOG(Log::Loader, "Locked disk cache file for %s", origPath_.c_str()); } else { - INFO_LOG(LOADER, "Unlocked disk cache file for %s", origPath_.c_str()); + INFO_LOG(Log::Loader, "Unlocked disk cache file for %s", origPath_.c_str()); } return true; } diff --git a/Core/FileLoaders/HTTPFileLoader.cpp b/Core/FileLoaders/HTTPFileLoader.cpp index 1aba908484..2d9d966cdc 100644 --- a/Core/FileLoaders/HTTPFileLoader.cpp +++ b/Core/FileLoaders/HTTPFileLoader.cpp @@ -50,7 +50,7 @@ void HTTPFileLoader::Prepare() { url = url.Relative(redirectURL); if (url.ToString() == url_.ToString() || url.ToString() == resourceURL.ToString()) { - ERROR_LOG(LOADER, "HTTP request failed, hit a redirect loop"); + ERROR_LOG(Log::Loader, "HTTP request failed, hit a redirect loop"); latestError_ = "Could not connect (redirect loop)"; return; } @@ -61,14 +61,14 @@ void HTTPFileLoader::Prepare() { } // No Location header? - ERROR_LOG(LOADER, "HTTP request failed, invalid redirect"); + ERROR_LOG(Log::Loader, "HTTP request failed, invalid redirect"); latestError_ = "Could not connect (invalid response)"; return; } if (code != 200) { // Leave size at 0, invalid. - ERROR_LOG(LOADER, "HTTP request failed, got %03d for %s", code, filename_.c_str()); + ERROR_LOG(Log::Loader, "HTTP request failed, got %03d for %s", code, filename_.c_str()); latestError_ = "Could not connect (invalid response)"; Disconnect(); return; @@ -105,10 +105,10 @@ void HTTPFileLoader::Prepare() { Disconnect(); if (!acceptsRange) { - WARN_LOG(LOADER, "HTTP server did not advertise support for range requests."); + WARN_LOG(Log::Loader, "HTTP server did not advertise support for range requests."); } if (filesize_ == 0) { - ERROR_LOG(LOADER, "Could not determine file size for %s", filename_.c_str()); + ERROR_LOG(Log::Loader, "Could not determine file size for %s", filename_.c_str()); } // If we didn't end up with a filesize_ (e.g. chunked response), give up. File invalid. @@ -117,13 +117,13 @@ void HTTPFileLoader::Prepare() { int HTTPFileLoader::SendHEAD(const Url &url, std::vector &responseHeaders) { if (!url.Valid()) { - ERROR_LOG(LOADER, "HTTP request failed, invalid URL: '%s'", url.ToString().c_str()); + ERROR_LOG(Log::Loader, "HTTP request failed, invalid URL: '%s'", url.ToString().c_str()); latestError_ = "Invalid URL"; return -400; } if (!client_.Resolve(url.Host().c_str(), url.Port())) { - ERROR_LOG(LOADER, "HTTP request failed, unable to resolve: |%s| port %d", url.Host().c_str(), url.Port()); + ERROR_LOG(Log::Loader, "HTTP request failed, unable to resolve: |%s| port %d", url.Host().c_str(), url.Port()); latestError_ = "Could not connect (name not resolved)"; return -400; } @@ -133,7 +133,7 @@ int HTTPFileLoader::SendHEAD(const Url &url, std::vector &responseH client_.SetDataTimeout(timeout); Connect(10.0); if (!connected_) { - ERROR_LOG(LOADER, "HTTP request failed, failed to connect: %s port %d (resource: '%s')", url.Host().c_str(), url.Port(), url.Resource().c_str()); + ERROR_LOG(Log::Loader, "HTTP request failed, failed to connect: %s port %d (resource: '%s')", url.Host().c_str(), url.Port(), url.Resource().c_str()); latestError_ = "Could not connect (refused to connect)"; return -400; } @@ -141,7 +141,7 @@ int HTTPFileLoader::SendHEAD(const Url &url, std::vector &responseH http::RequestParams req(url.Resource(), "*/*"); int err = client_.SendRequest("HEAD", req, nullptr, &progress_); if (err < 0) { - ERROR_LOG(LOADER, "HTTP request failed, failed to send request: %s port %d", url.Host().c_str(), url.Port()); + ERROR_LOG(Log::Loader, "HTTP request failed, failed to send request: %s port %d", url.Host().c_str(), url.Port()); latestError_ = "Could not connect (could not request data)"; Disconnect(); return -400; @@ -210,7 +210,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f std::vector responseHeaders; int code = client_.ReadResponseHeaders(&readbuf, responseHeaders, &progress_); if (code != 206) { - ERROR_LOG(LOADER, "HTTP server did not respond with range, received code=%03d", code); + ERROR_LOG(Log::Loader, "HTTP server did not respond with range, received code=%03d", code); latestError_ = "Invalid response reading data"; Disconnect(); return 0; @@ -229,10 +229,10 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f if (first == absolutePos && last == absoluteEnd - 1) { supportedResponse = true; } else { - ERROR_LOG(LOADER, "Unexpected HTTP range: got %lld-%lld, wanted %lld-%lld.", first, last, absolutePos, absoluteEnd - 1); + ERROR_LOG(Log::Loader, "Unexpected HTTP range: got %lld-%lld, wanted %lld-%lld.", first, last, absolutePos, absoluteEnd - 1); } } else { - ERROR_LOG(LOADER, "Unexpected HTTP range response: %s", header.c_str()); + ERROR_LOG(Log::Loader, "Unexpected HTTP range response: %s", header.c_str()); } } } @@ -241,7 +241,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f net::Buffer output; int res = client_.ReadResponseEntity(&readbuf, responseHeaders, &output, &progress_); if (res != 0) { - ERROR_LOG(LOADER, "Unable to read HTTP response entity: %d", res); + ERROR_LOG(Log::Loader, "Unable to read HTTP response entity: %d", res); // Let's take anything we got anyway. Not worse than returning nothing? } @@ -249,7 +249,7 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f Disconnect(); if (!supportedResponse) { - ERROR_LOG(LOADER, "HTTP server did not respond with the range we wanted."); + ERROR_LOG(Log::Loader, "HTTP server did not respond with the range we wanted."); latestError_ = "Invalid response reading data"; return 0; } diff --git a/Core/FileLoaders/LocalFileLoader.cpp b/Core/FileLoaders/LocalFileLoader.cpp index 3a329cc36d..05f55f73e3 100644 --- a/Core/FileLoaders/LocalFileLoader.cpp +++ b/Core/FileLoaders/LocalFileLoader.cpp @@ -60,7 +60,7 @@ void LocalFileLoader::DetectSizeFd() { LocalFileLoader::LocalFileLoader(const Path &filename) : filesize_(0), filename_(filename) { if (filename.empty()) { - ERROR_LOG(FILESYS, "LocalFileLoader can't load empty filenames"); + ERROR_LOG(Log::FileSystem, "LocalFileLoader can't load empty filenames"); return; } @@ -76,9 +76,9 @@ LocalFileLoader::LocalFileLoader(const Path &filename) #if PPSSPP_PLATFORM(ANDROID) && !defined(HAVE_LIBRETRO_VFS) if (filename.Type() == PathType::CONTENT_URI) { int fd = Android_OpenContentUriFd(filename.ToString(), Android_OpenContentUriMode::READ); - VERBOSE_LOG(SYSTEM, "LocalFileLoader Fd %d for content URI: '%s'", fd, filename.c_str()); + VERBOSE_LOG(Log::System, "LocalFileLoader Fd %d for content URI: '%s'", fd, filename.c_str()); if (fd < 0) { - ERROR_LOG(FILESYS, "LocalFileLoader failed to open content URI: '%s'", filename.c_str()); + ERROR_LOG(Log::FileSystem, "LocalFileLoader failed to open content URI: '%s'", filename.c_str()); return; } fd_ = fd; @@ -180,7 +180,7 @@ size_t LocalFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void return 0; if (filesize_ == 0) { - ERROR_LOG(FILESYS, "ReadAt from 0-sized file: %s", filename_.c_str()); + ERROR_LOG(Log::FileSystem, "ReadAt from 0-sized file: %s", filename_.c_str()); return 0; } diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index 7c590e21d7..4b2d72ccaa 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -44,7 +44,7 @@ BlockDevice *constructBlockDevice(FileLoader *fileLoader) { return nullptr; } if (fileLoader->IsDirectory()) { - ERROR_LOG(LOADER, "Can't open directory directly as block device: %s", fileLoader->GetPath().c_str()); + ERROR_LOG(Log::Loader, "Can't open directory directly as block device: %s", fileLoader->GetPath().c_str()); return nullptr; } @@ -91,7 +91,7 @@ bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) { FileLoader::Flags flags = uncached ? FileLoader::Flags::HINT_UNCACHED : FileLoader::Flags::NONE; size_t retval = fileLoader_->ReadAt((u64)blockNumber * (u64)GetBlockSize(), 1, 2048, outPtr, flags); if (retval != 2048) { - DEBUG_LOG(FILESYS, "Could not read 2048 byte block, at block offset %d. Only got %d bytes", blockNumber, (int)retval); + DEBUG_LOG(Log::FileSystem, "Could not read 2048 byte block, at block offset %d. Only got %d bytes", blockNumber, (int)retval); return false; } @@ -101,7 +101,7 @@ bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) { bool FileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr) { size_t retval = fileLoader_->ReadAt((u64)minBlock * (u64)GetBlockSize(), 2048, count, outPtr); if (retval != (size_t)count) { - ERROR_LOG(FILESYS, "Could not read %d blocks, at block offset %d. Only got %d blocks", count, minBlock, (int)retval); + ERROR_LOG(Log::FileSystem, "Could not read %d blocks, at block offset %d. Only got %d blocks", count, minBlock, (int)retval); return false; } return true; @@ -145,17 +145,17 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader) CISO_H hdr; size_t readSize = fileLoader->ReadAt(0, sizeof(CISO_H), 1, &hdr); if (readSize != 1 || memcmp(hdr.magic, "CISO", 4) != 0) { - WARN_LOG(LOADER, "Invalid CSO!"); + WARN_LOG(Log::Loader, "Invalid CSO!"); } if (hdr.ver > 1) { - WARN_LOG(LOADER, "CSO version too high!"); + WARN_LOG(Log::Loader, "CSO version too high!"); } frameSize = hdr.block_size; if ((frameSize & (frameSize - 1)) != 0) - ERROR_LOG(LOADER, "CSO block size %i unsupported, must be a power of two", frameSize); + ERROR_LOG(Log::Loader, "CSO block size %i unsupported, must be a power of two", frameSize); else if (frameSize < 0x800) - ERROR_LOG(LOADER, "CSO block size %i unsupported, must be at least one sector", frameSize); + ERROR_LOG(Log::Loader, "CSO block size %i unsupported, must be at least one sector", frameSize); // Determine the translation from block to frame. blockShift = 0; @@ -166,7 +166,7 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader) const u64 totalSize = hdr.total_bytes; numFrames = (u32)((totalSize + frameSize - 1) / frameSize); numBlocks = (u32)(totalSize / GetBlockSize()); - VERBOSE_LOG(LOADER, "CSO numBlocks=%i numFrames=%i align=%i", numBlocks, numFrames, indexShift); + VERBOSE_LOG(Log::Loader, "CSO numBlocks=%i numFrames=%i align=%i", numBlocks, numFrames, indexShift); // We might read a bit of alignment too, so be prepared. if (frameSize + (1 << indexShift) < CSO_READ_BUFFER_SIZE) @@ -207,7 +207,7 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader) u64 lastIndexPos = index[indexSize - 1] & 0x7FFFFFFF; u64 expectedFileSize = lastIndexPos << indexShift; if (expectedFileSize > fileSize) { - ERROR_LOG(LOADER, "Expected CSO to at least be %lld bytes, but file is %lld bytes. File: '%s'", + ERROR_LOG(Log::Loader, "Expected CSO to at least be %lld bytes, but file is %lld bytes. File: '%s'", expectedFileSize, fileSize, fileLoader->GetPath().c_str()); NotifyReadError(); } @@ -258,7 +258,7 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) z.zfree = Z_NULL; z.opaque = Z_NULL; if (inflateInit2(&z, -15) != Z_OK) { - ERROR_LOG(LOADER, "GetBlockSize() ERROR: %s\n", (z.msg) ? z.msg : "?"); + ERROR_LOG(Log::Loader, "GetBlockSize() ERROR: %s\n", (z.msg) ? z.msg : "?"); NotifyReadError(); return false; } @@ -269,14 +269,14 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) int status = inflate(&z, Z_FINISH); if (status != Z_STREAM_END) { - ERROR_LOG(LOADER, "block %d: inflate : %s[%d]\n", blockNumber, (z.msg) ? z.msg : "error", status); + ERROR_LOG(Log::Loader, "block %d: inflate : %s[%d]\n", blockNumber, (z.msg) ? z.msg : "error", status); NotifyReadError(); inflateEnd(&z); memset(outPtr, 0, GetBlockSize()); return false; } if (z.total_out != frameSize) { - ERROR_LOG(LOADER, "block %d: block size error %d != %d\n", blockNumber, (u32)z.total_out, frameSize); + ERROR_LOG(Log::Loader, "block %d: block size error %d != %d\n", blockNumber, (u32)z.total_out, frameSize); NotifyReadError(); inflateEnd(&z); memset(outPtr, 0, GetBlockSize()); @@ -314,7 +314,7 @@ bool CISOFileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr) { z_stream z{}; if (inflateInit2(&z, -15) != Z_OK) { - ERROR_LOG(LOADER, "Unable to initialize inflate: %s\n", (z.msg) ? z.msg : "?"); + ERROR_LOG(Log::Loader, "Unable to initialize inflate: %s\n", (z.msg) ? z.msg : "?"); return false; } @@ -358,11 +358,11 @@ bool CISOFileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr) { int status = inflate(&z, Z_FINISH); if (status != Z_STREAM_END) { - ERROR_LOG(LOADER, "Inflate frame %d: failed - %s[%d]\n", frame, (z.msg) ? z.msg : "error", status); + ERROR_LOG(Log::Loader, "Inflate frame %d: failed - %s[%d]\n", frame, (z.msg) ? z.msg : "error", status); NotifyReadError(); memset(outPtr, 0, frameBlocks * GetBlockSize()); } else if (z.total_out != frameSize) { - ERROR_LOG(LOADER, "Inflate frame %d: block size error %d != %d\n", frame, (u32)z.total_out, frameSize); + ERROR_LOG(Log::Loader, "Inflate frame %d: block size error %d != %d\n", frame, (u32)z.total_out, frameSize); NotifyReadError(); memset(outPtr, 0, frameBlocks * GetBlockSize()); } else if (frameBlocks != blocksPerFrame) { @@ -395,7 +395,7 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader) fileLoader_->ReadAt(0x24, 1, 4, &psarOffset); size_t readSize = fileLoader_->ReadAt(psarOffset, 1, 256, &np_header); if (readSize != 256){ - ERROR_LOG(LOADER, "Invalid NPUMDIMG header!"); + ERROR_LOG(Log::Loader, "Invalid NPUMDIMG header!"); } kirk_init(); @@ -428,7 +428,7 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader) readSize = fileLoader_->ReadAt(psarOffset + tableOffset, 1, tableSize, table); if(readSize!=tableSize){ - ERROR_LOG(LOADER, "Invalid NPUMDIMG table!"); + ERROR_LOG(Log::Loader, "Invalid NPUMDIMG table!"); } u32 *p = (u32*)table; @@ -510,7 +510,7 @@ bool NPDRMDemoBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) if(table[block].sizeGetPath().c_str()); + ERROR_LOG(Log::Loader, "Error loading CHD '%s': parents not found", fileLoader->GetPath().c_str()); NotifyReadError(); return; } @@ -636,7 +636,7 @@ CHDFileBlockDevice::CHDFileBlockDevice(FileLoader *fileLoader) chd_file *file = nullptr; chd_error err = chd_open_core_file(&core_file_->core, CHD_OPEN_READ, NULL, &file); if (err != CHDERR_NONE) { - ERROR_LOG(LOADER, "Error loading CHD '%s': %s", paths[depth].c_str(), chd_error_string(err)); + ERROR_LOG(Log::Loader, "Error loading CHD '%s': %s", paths[depth].c_str(), chd_error_string(err)); NotifyReadError(); return; } @@ -661,7 +661,7 @@ CHDFileBlockDevice::~CHDFileBlockDevice() bool CHDFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) { if (!impl_->chd) { - ERROR_LOG(LOADER, "ReadBlock: CHD not open. %s", fileLoader_->GetPath().c_str()); + ERROR_LOG(Log::Loader, "ReadBlock: CHD not open. %s", fileLoader_->GetPath().c_str()); return false; } if ((u32)blockNumber >= numBlocks) { @@ -674,7 +674,7 @@ bool CHDFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) if (currentHunk != hunk) { chd_error err = chd_read(impl_->chd, hunk, readBuffer); if (err != CHDERR_NONE) { - ERROR_LOG(LOADER, "CHD read failed: %d %d %s", blockNumber, hunk, chd_error_string(err)); + ERROR_LOG(Log::Loader, "CHD read failed: %d %d %s", blockNumber, hunk, chd_error_string(err)); NotifyReadError(); } currentHunk = hunk; diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index 9c39ece529..bdbd1a554a 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -123,7 +123,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File #if HOST_IS_CASE_SENSITIVE if (access & (FILEACCESS_APPEND | FILEACCESS_CREATE | FILEACCESS_WRITE)) { - DEBUG_LOG(FILESYS, "Checking case for path %s", fileName.c_str()); + DEBUG_LOG(Log::FileSystem, "Checking case for path %s", fileName.c_str()); if (!FixPathCase(basePath, fileName, FPC_PATH_MUST_EXIST)) { error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; return false; // or go on and attempt (for a better error code than just 0?) @@ -225,7 +225,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File // Success return true; } else { - ERROR_LOG(FILESYS, "File::OpenFD returned an error"); + ERROR_LOG(Log::FileSystem, "File::OpenFD returned an error"); // TODO: Need better error codes from OpenFD so we can distinguish // disk full. Just set not found for now. error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; @@ -262,7 +262,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File return false; } fullName = GetLocalPath(basePath, fileName); - DEBUG_LOG(FILESYS, "Case may have been incorrect, second try opening %s (%s)", fullName.c_str(), fileName.c_str()); + DEBUG_LOG(Log::FileSystem, "Case may have been incorrect, second try opening %s (%s)", fullName.c_str(), fileName.c_str()); // And try again with the correct case this time #ifdef _WIN32 @@ -361,7 +361,7 @@ size_t DirectoryFileHandle::Write(const u8* pointer, s64 size) MemoryStick_NotifyWrite(); if (diskFull) { - ERROR_LOG(FILESYS, "Disk full"); + ERROR_LOG(Log::FileSystem, "Disk full"); auto err = GetI18NCategory(I18NCat::ERRORS); g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Disk full while writing data")); // We only return an error when the disk is actually full. @@ -382,7 +382,7 @@ size_t DirectoryFileHandle::Seek(s32 position, FileMove type) // The actual, underlying file hasn't been truncated (yet.) if (type == FILEMOVE_END) { type = FILEMOVE_BEGIN; - position = needsTrunc_ + position; + position = (s32)(needsTrunc_ + position); } } @@ -419,12 +419,12 @@ void DirectoryFileHandle::Close() #ifdef _WIN32 Seek((s32)needsTrunc_, FILEMOVE_BEGIN); if (SetEndOfFile(hFile) == 0) { - ERROR_LOG_REPORT(FILESYS, "Failed to truncate file."); + ERROR_LOG_REPORT(Log::FileSystem, "Failed to truncate file."); } #elif !PPSSPP_PLATFORM(SWITCH) // Note: it's not great that Switch cannot truncate appropriately... if (ftruncate(hFile, (off_t)needsTrunc_) != 0) { - ERROR_LOG_REPORT(FILESYS, "Failed to truncate file."); + ERROR_LOG_REPORT(Log::FileSystem, "Failed to truncate file."); } #endif } @@ -439,7 +439,7 @@ void DirectoryFileHandle::Close() void DirectoryFileSystem::CloseAll() { for (auto iter = entries.begin(); iter != entries.end(); ++iter) { - INFO_LOG(FILESYS, "DirectoryFileSystem::CloseAll(): Force closing %d (%s)", (int)iter->first, iter->second.guestFilename.c_str()); + INFO_LOG(Log::FileSystem, "DirectoryFileSystem::CloseAll(): Force closing %d (%s)", (int)iter->first, iter->second.guestFilename.c_str()); iter->second.hFile.Close(); } entries.clear(); @@ -577,7 +577,7 @@ int DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const logError = (int)errno; #endif if (!(access & FILEACCESS_PPSSPP_QUIET)) { - ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile('%s'): FAILED, %d - access = %d '%s'", filename.c_str(), logError, (int)(access & FILEACCESS_PSP_FLAGS), errorString.c_str()); + ERROR_LOG(Log::FileSystem, "DirectoryFileSystem::OpenFile('%s'): FAILED, %d - access = %d '%s'", filename.c_str(), logError, (int)(access & FILEACCESS_PSP_FLAGS), errorString.c_str()); } return err; } else { @@ -606,7 +606,7 @@ void DirectoryFileSystem::CloseFile(u32 handle) { entries.erase(iter); } else { //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot close file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"Cannot close file that hasn't been opened: %08x", handle); } } @@ -632,7 +632,7 @@ size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &use EntryMap::iterator iter = entries.find(handle); if (iter != entries.end()) { if (size < 0) { - ERROR_LOG_REPORT(FILESYS, "Invalid read for %lld bytes from disk %s", size, iter->second.guestFilename.c_str()); + ERROR_LOG_REPORT(Log::FileSystem, "Invalid read for %lld bytes from disk %s", size, iter->second.guestFilename.c_str()); return 0; } @@ -640,7 +640,7 @@ size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &use return bytesRead; } else { // This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot read file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"Cannot read file that hasn't been opened: %08x", handle); return 0; } } @@ -657,7 +657,7 @@ size_t DirectoryFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, i return bytesWritten; } else { //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot write to file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"Cannot write to file that hasn't been opened: %08x", handle); return 0; } } @@ -668,7 +668,7 @@ size_t DirectoryFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { return iter->second.hFile.Seek(position,type); } else { //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot seek in file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"Cannot seek in file that hasn't been opened: %08x", handle); return 0; } } @@ -697,15 +697,15 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { if (x.type != FILETYPE_DIRECTORY) { x.size = info.size; - x.access = info.access; - time_t atime = info.atime; - time_t ctime = info.ctime; - time_t mtime = info.mtime; - - localtime_r((time_t*)&atime, &x.atime); - localtime_r((time_t*)&ctime, &x.ctime); - localtime_r((time_t*)&mtime, &x.mtime); } + x.access = info.access; + time_t atime = info.atime; + time_t ctime = info.ctime; + time_t mtime = info.mtime; + + localtime_r((time_t*)&atime, &x.atime); + localtime_r((time_t*)&ctime, &x.ctime); + localtime_r((time_t*)&mtime, &x.mtime); return ReplayApplyDiskFileInfo(x, CoreTiming::GetGlobalTimeUs()); } @@ -774,7 +774,7 @@ static std::string SimulateVFATBug(std::string filename) { } if (apply_hack) { - VERBOSE_LOG(FILESYS, "Applying VFAT hack to filename: %s", filename.c_str()); + VERBOSE_LOG(Log::FileSystem, "Applying VFAT hack to filename: %s", filename.c_str()); // In this situation, NT would write UPPERCASE, and just set a flag to say "actually lowercase". // That VFAT flag isn't read by the PSP firmware, so let's pretend to "not read it." std::transform(filename.begin(), filename.end(), filename.begin(), toupper); @@ -920,13 +920,13 @@ void DirectoryFileSystem::DoState(PointerWrap &p) { u32 err; bool brokenFile = false; if (!entry.hFile.Open(basePath,entry.guestFilename,entry.access, err)) { - ERROR_LOG(FILESYS, "Failed to reopen file while loading state: %s", entry.guestFilename.c_str()); + ERROR_LOG(Log::FileSystem, "Failed to reopen file while loading state: %s", entry.guestFilename.c_str()); brokenFile = true; } u32 position; Do(p, position); if (position != entry.hFile.Seek(position, FILEMOVE_BEGIN)) { - ERROR_LOG(FILESYS, "Failed to restore seek position while loading state: %s", entry.guestFilename.c_str()); + ERROR_LOG(Log::FileSystem, "Failed to restore seek position while loading state: %s", entry.guestFilename.c_str()); brokenFile = true; } if (s >= 2) { @@ -990,18 +990,18 @@ bool VFSFileSystem::RemoveFile(const std::string &filename) { int VFSFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) { if (access != FILEACCESS_READ) { - ERROR_LOG(FILESYS, "VFSFileSystem only supports plain reading"); + ERROR_LOG(Log::FileSystem, "VFSFileSystem only supports plain reading"); return SCE_KERNEL_ERROR_ERRNO_INVALID_FLAG; } std::string fullName = GetLocalPath(filename); const char *fullNameC = fullName.c_str(); - VERBOSE_LOG(FILESYS, "VFSFileSystem actually opening %s (%s)", fullNameC, filename.c_str()); + VERBOSE_LOG(Log::FileSystem, "VFSFileSystem actually opening %s (%s)", fullNameC, filename.c_str()); size_t size; u8 *data = g_VFS.ReadFile(fullNameC, &size); if (!data) { - ERROR_LOG(FILESYS, "VFSFileSystem failed to open %s", filename.c_str()); + ERROR_LOG(Log::FileSystem, "VFSFileSystem failed to open %s", filename.c_str()); return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; } @@ -1040,7 +1040,7 @@ void VFSFileSystem::CloseFile(u32 handle) { entries.erase(iter); } else { //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot close file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"Cannot close file that hasn't been opened: %08x", handle); } } @@ -1063,7 +1063,7 @@ size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) { } size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { - DEBUG_LOG(FILESYS,"VFSFileSystem::ReadFile %08x %p %i", handle, pointer, (u32)size); + DEBUG_LOG(Log::FileSystem,"VFSFileSystem::ReadFile %08x %p %i", handle, pointer, (u32)size); EntryMap::iterator iter = entries.find(handle); if (iter != entries.end()) { @@ -1075,7 +1075,7 @@ size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { iter->second.seekPos += size; return bytesRead; } else { - ERROR_LOG(FILESYS,"Cannot read file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"Cannot read file that hasn't been opened: %08x", handle); return 0; } } @@ -1101,7 +1101,7 @@ size_t VFSFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { return iter->second.seekPos; } else { //This shouldn't happen... - ERROR_LOG(FILESYS,"Cannot seek in file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"Cannot seek in file that hasn't been opened: %08x", handle); return 0; } } @@ -1125,6 +1125,6 @@ void VFSFileSystem::DoState(PointerWrap &p) { if (num != 0) { p.SetError(p.ERROR_WARNING); - ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly."); + ERROR_LOG(Log::FileSystem, "FIXME: Open files during savestate, could go badly."); } } diff --git a/Core/FileSystems/ISOFileSystem.cpp b/Core/FileSystems/ISOFileSystem.cpp index f070ff362f..49574702f3 100644 --- a/Core/FileSystems/ISOFileSystem.cpp +++ b/Core/FileSystems/ISOFileSystem.cpp @@ -164,7 +164,7 @@ ISOFileSystem::ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevic treeroot->valid = false; if (memcmp(desc.cd001, "CD001", 5)) { - ERROR_LOG(FILESYS, "ISO looks bogus, expected CD001 signature not present? Giving up..."); + ERROR_LOG(Log::FileSystem, "ISO looks bogus, expected CD001 signature not present? Giving up..."); return; } @@ -190,7 +190,7 @@ void ISOFileSystem::ReadDirectory(TreeEntry *root) { u8 theSector[2048]; if (!blockDevice->ReadBlock(secnum, theSector)) { blockDevice->NotifyReadError(); - ERROR_LOG(FILESYS, "Error reading block for directory '%s' in sector %d - skipping", root->name.c_str(), secnum); + ERROR_LOG(Log::FileSystem, "Error reading block for directory '%s' in sector %d - skipping", root->name.c_str(), secnum); root->valid = true; // Prevents re-reading return; } @@ -207,7 +207,7 @@ void ISOFileSystem::ReadDirectory(TreeEntry *root) { const int IDENTIFIER_OFFSET = 33; if (offset + IDENTIFIER_OFFSET + dir.identifierLength > 2048) { blockDevice->NotifyReadError(); - ERROR_LOG(FILESYS, "Directory entry crosses sectors, corrupt iso?"); + ERROR_LOG(Log::FileSystem, "Directory entry crosses sectors, corrupt iso?"); return; } @@ -236,18 +236,18 @@ void ISOFileSystem::ReadDirectory(TreeEntry *root) { entry->startsector = dir.firstDataSector; entry->dirsize = dir.dataLength; entry->valid = isFile; // Can pre-mark as valid if file, as we don't recurse into those. - VERBOSE_LOG(FILESYS, "%s: %s %08x %08x %d", entry->isDirectory ? "D" : "F", entry->name.c_str(), (u32)dir.firstDataSector, entry->startingPosition, entry->startingPosition); + VERBOSE_LOG(Log::FileSystem, "%s: %s %08x %08x %d", entry->isDirectory ? "D" : "F", entry->name.c_str(), (u32)dir.firstDataSector, entry->startingPosition, entry->startingPosition); // Round down to avoid any false reports. if (isFile && dir.firstDataSector + (dir.dataLength / 2048) > blockDevice->GetNumBlocks()) { blockDevice->NotifyReadError(); - ERROR_LOG(FILESYS, "File '%s' starts or ends outside ISO. firstDataSector: %d len: %d", entry->BuildPath().c_str(), (int)dir.firstDataSector, (int)dir.dataLength); + ERROR_LOG(Log::FileSystem, "File '%s' starts or ends outside ISO. firstDataSector: %d len: %d", entry->BuildPath().c_str(), (int)dir.firstDataSector, (int)dir.dataLength); } if (entry->isDirectory && !relative) { if (entry->startsector == root->startsector) { blockDevice->NotifyReadError(); - ERROR_LOG(FILESYS, "WARNING: Appear to have a recursive file system, breaking recursion. Probably corrupt ISO."); + ERROR_LOG(Log::FileSystem, "WARNING: Appear to have a recursive file system, breaking recursion. Probably corrupt ISO."); } } root->children.push_back(entry); @@ -313,7 +313,7 @@ ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(const std::string &path, bo return entry; } else { if (catchError) - ERROR_LOG(FILESYS, "File '%s' not found", path.c_str()); + ERROR_LOG(Log::FileSystem, "File '%s' not found", path.c_str()); return 0; } @@ -326,7 +326,7 @@ int ISOFileSystem::OpenFile(std::string filename, FileAccess access, const char entry.isBlockSectorMode = false; if (access & FILEACCESS_WRITE) { - ERROR_LOG(FILESYS, "Can't open file '%s' with write access on an ISO partition", filename.c_str()); + ERROR_LOG(Log::FileSystem, "Can't open file '%s' with write access on an ISO partition", filename.c_str()); return SCE_KERNEL_ERROR_ERRNO_INVALID_FLAG; } @@ -335,15 +335,15 @@ int ISOFileSystem::OpenFile(std::string filename, FileAccess access, const char u32 sectorStart = 0xFFFFFFFF, readSize = 0xFFFFFFFF; parseLBN(filename, §orStart, &readSize); if (sectorStart > blockDevice->GetNumBlocks()) { - WARN_LOG(FILESYS, "Unable to open raw sector, out of range: '%s', sector %08x, max %08x", filename.c_str(), sectorStart, blockDevice->GetNumBlocks()); + WARN_LOG(Log::FileSystem, "Unable to open raw sector, out of range: '%s', sector %08x, max %08x", filename.c_str(), sectorStart, blockDevice->GetNumBlocks()); return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; } else if (sectorStart == blockDevice->GetNumBlocks()) { - ERROR_LOG(FILESYS, "Should not be able to open the block after the last on disc! %08x", sectorStart); + ERROR_LOG(Log::FileSystem, "Should not be able to open the block after the last on disc! %08x", sectorStart); } - DEBUG_LOG(FILESYS, "Got a raw sector open: '%s', sector %08x, size %08x", filename.c_str(), sectorStart, readSize); + DEBUG_LOG(Log::FileSystem, "Got a raw sector open: '%s', sector %08x, size %08x", filename.c_str(), sectorStart, readSize); u32 newHandle = hAlloc->GetNewHandle(); entry.seekPos = 0; entry.file = 0; @@ -383,7 +383,7 @@ void ISOFileSystem::CloseFile(u32 handle) { entries.erase(iter); } else { //This shouldn't happen... - ERROR_LOG(FILESYS, "Hey, what are you doing? Closing non-open files?"); + ERROR_LOG(Log::FileSystem, "Hey, what are you doing? Closing non-open files?"); } } @@ -395,7 +395,7 @@ bool ISOFileSystem::OwnsHandle(u32 handle) { int ISOFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) { EntryMap::iterator iter = entries.find(handle); if (iter == entries.end()) { - ERROR_LOG(FILESYS, "Ioctl on a bad file handle"); + ERROR_LOG(Log::FileSystem, "Ioctl on a bad file handle"); return SCE_KERNEL_ERROR_BADF; } @@ -405,23 +405,23 @@ int ISOFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outd // Get ISO9660 volume descriptor (from open ISO9660 file.) case 0x01020001: if (e.isBlockSectorMode) { - ERROR_LOG(FILESYS, "Unsupported read volume descriptor command on a umd block device"); + ERROR_LOG(Log::FileSystem, "Unsupported read volume descriptor command on a umd block device"); return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } if (!Memory::IsValidRange(outdataPtr, 0x800) || outlen < 0x800) { - WARN_LOG_REPORT(FILESYS, "sceIoIoctl: Invalid out pointer %08x while reading ISO9660 volume descriptor", outdataPtr); + WARN_LOG_REPORT(Log::FileSystem, "sceIoIoctl: Invalid out pointer %08x while reading ISO9660 volume descriptor", outdataPtr); return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } - INFO_LOG(SCEIO, "sceIoIoctl: reading ISO9660 volume descriptor read"); + INFO_LOG(Log::sceIo, "sceIoIoctl: reading ISO9660 volume descriptor read"); blockDevice->ReadBlock(16, Memory::GetPointerWriteUnchecked(outdataPtr)); return 0; // Get ISO9660 path table (from open ISO9660 file.) case 0x01020002: if (e.isBlockSectorMode) { - ERROR_LOG(FILESYS, "Unsupported read path table command on a umd block device"); + ERROR_LOG(Log::FileSystem, "Unsupported read path table command on a umd block device"); return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED; } @@ -479,7 +479,7 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { OpenFileEntry &e = iter->second; if (size < 0) { - ERROR_LOG_REPORT(FILESYS, "Invalid read for %lld bytes from umd %s", size, e.file ? e.file->name.c_str() : "device"); + ERROR_LOG_REPORT(Log::FileSystem, "Invalid read for %lld bytes from umd %s", size, e.file ? e.file->name.c_str() : "device"); return 0; } @@ -501,7 +501,7 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { positionOnIso = e.sectorStart * 2048ULL + e.seekPos; fileSize = (s64)e.openSize; } else if (e.file == nullptr) { - ERROR_LOG(FILESYS, "File no longer exists (loaded savestate with different ISO?)"); + ERROR_LOG(Log::FileSystem, "File no longer exists (loaded savestate with different ISO?)"); return 0; } else { positionOnIso = e.file->startingPosition + e.seekPos; @@ -509,7 +509,7 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { } if ((s64)e.seekPos > fileSize) { - WARN_LOG(FILESYS, "Read starting outside of file, at %lld / %lld", (s64)e.seekPos, fileSize); + WARN_LOG(Log::FileSystem, "Read starting outside of file, at %lld / %lld", (s64)e.seekPos, fileSize); return 0; } if ((s64)e.seekPos + size > fileSize) { @@ -518,9 +518,9 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { // Reading beyond the file is really quite normal behavior (if return value handled correctly), so // not doing WARN here. Still, can potentially be useful to see so leaving at INFO. if (newSize == 0) { - INFO_LOG(FILESYS, "Attempted read at end of file, 0-size read simulated"); + INFO_LOG(Log::FileSystem, "Attempted read at end of file, 0-size read simulated"); } else { - INFO_LOG(FILESYS, "Reading beyond end of file from seekPos %d, clamping size %lld to %lld", e.seekPos, size, newSize); + INFO_LOG(Log::FileSystem, "Reading beyond end of file from seekPos %d, clamping size %lld to %lld", e.seekPos, size, newSize); } size = newSize; } @@ -534,7 +534,7 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { u8 theSector[2048]; if ((middleSize & 2047) != 0) { - ERROR_LOG(FILESYS, "Remaining size should be aligned"); + ERROR_LOG(Log::FileSystem, "Remaining size should be aligned"); } const u8 *const start = pointer; @@ -565,18 +565,18 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) { return (size_t)totalBytes; } else { //This shouldn't happen... - ERROR_LOG(FILESYS, "Hey, what are you doing? Reading non-open files?"); + ERROR_LOG(Log::FileSystem, "Hey, what are you doing? Reading non-open files?"); return 0; } } size_t ISOFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) { - ERROR_LOG(FILESYS, "Hey, what are you doing? You can't write to an ISO!"); + ERROR_LOG(Log::FileSystem, "Hey, what are you doing? You can't write to an ISO!"); return 0; } size_t ISOFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) { - ERROR_LOG(FILESYS, "Hey, what are you doing? You can't write to an ISO!"); + ERROR_LOG(Log::FileSystem, "Hey, what are you doing? You can't write to an ISO!"); return 0; } @@ -602,7 +602,7 @@ size_t ISOFileSystem::SeekFile(u32 handle, s32 position, FileMove type) { return (size_t)e.seekPos; } else { //This shouldn't happen... - ERROR_LOG(FILESYS, "Hey, what are you doing? Seeking in non-open files?"); + ERROR_LOG(Log::FileSystem, "Hey, what are you doing? Seeking in non-open files?"); return 0; } } diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 5dece8e210..adc86c0ebb 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -53,7 +53,7 @@ static bool ApplyPathStringToComponentsVector(std::vector &vector, else { // The PSP silently ignores attempts to .. to parent of root directory - WARN_LOG(FILESYS, "RealPath: ignoring .. beyond root - root directory is its own parent: \"%s\"", pathString.c_str()); + WARN_LOG(Log::FileSystem, "RealPath: ignoring .. beyond root - root directory is its own parent: \"%s\"", pathString.c_str()); } } else @@ -102,26 +102,26 @@ static bool RealPath(const std::string ¤tDirectory, const std::string &inP size_t curDirLen = currentDirectory.length(); if (curDirLen == 0) { - ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory is empty", inPath.c_str()); + ERROR_LOG(Log::FileSystem, "RealPath: inPath \"%s\" is relative, but current directory is empty", inPath.c_str()); return false; } size_t curDirColon = currentDirectory.find(':'); if (curDirColon == std::string::npos) { - ERROR_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" has no prefix", inPath.c_str(), currentDirectory.c_str()); + ERROR_LOG(Log::FileSystem, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" has no prefix", inPath.c_str(), currentDirectory.c_str()); return false; } if (curDirColon + 1 == curDirLen) { - WARN_LOG(FILESYS, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" is all prefix and no path. Using \"/\" as path for current directory.", inPath.c_str(), currentDirectory.c_str()); + WARN_LOG(Log::FileSystem, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" is all prefix and no path. Using \"/\" as path for current directory.", inPath.c_str(), currentDirectory.c_str()); } else { const std::string curDirAfter = currentDirectory.substr(curDirColon + 1); if (! ApplyPathStringToComponentsVector(cmpnts, curDirAfter) ) { - ERROR_LOG(FILESYS,"RealPath: currentDirectory is not a valid path: \"%s\"", currentDirectory.c_str()); + ERROR_LOG(Log::FileSystem,"RealPath: currentDirectory is not a valid path: \"%s\"", currentDirectory.c_str()); return false; } @@ -146,7 +146,7 @@ static bool RealPath(const std::string ¤tDirectory, const std::string &inP if (! ApplyPathStringToComponentsVector(cmpnts, inAfterColon) ) { - WARN_LOG(FILESYS, "RealPath: inPath is not a valid path: \"%s\"", inPath.c_str()); + WARN_LOG(Log::FileSystem, "RealPath: inPath is not a valid path: \"%s\"", inPath.c_str()); return false; } @@ -200,7 +200,7 @@ int MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath // Special handling: host0:command.txt (as seen in Super Monkey Ball Adventures, for example) // appears to mean the current directory on the UMD. Let's just assume the current directory. if (strncasecmp(inpath.c_str(), "host0:", strlen("host0:")) == 0) { - INFO_LOG(FILESYS, "Host0 path detected, stripping: %s", inpath.c_str()); + INFO_LOG(Log::FileSystem, "Host0 path detected, stripping: %s", inpath.c_str()); // However, this causes trouble when running tests, since our test framework uses host0:. // Maybe it's really just supposed to map to umd0 or something? if (PSP_CoreParameter().headLess) { @@ -220,7 +220,7 @@ int MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath if (inpath.find(':') == std::string::npos /* means path is relative */) { error = SCE_KERNEL_ERROR_NOCWD; - WARN_LOG(FILESYS, "Path is relative, but current directory not set for thread %i. returning 8002032C(SCE_KERNEL_ERROR_NOCWD) instead.", currentThread); + WARN_LOG(Log::FileSystem, "Path is relative, but current directory not set for thread %i. returning 8002032C(SCE_KERNEL_ERROR_NOCWD) instead.", currentThread); } } else @@ -243,7 +243,7 @@ int MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath outpath = realpath.substr(prefixPos + 1); *system = &(fileSystems[i]); - VERBOSE_LOG(FILESYS, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str()); + VERBOSE_LOG(Log::FileSystem, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str()); return error == SCE_KERNEL_ERROR_NOCWD ? error : 0; } @@ -252,7 +252,7 @@ int MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpath error = SCE_KERNEL_ERROR_NODEV; } - DEBUG_LOG(FILESYS, "MapFilePath: failed mapping \"%s\", returning false", inpath.c_str()); + DEBUG_LOG(Log::FileSystem, "MapFilePath: failed mapping \"%s\", returning false", inpath.c_str()); return error; } @@ -292,12 +292,14 @@ void MetaFileSystem::Mount(const std::string &prefix, std::shared_ptr guard(lock); for (auto iter = fileSystems.begin(); iter != fileSystems.end(); iter++) { if (iter->prefix == prefix) { fileSystems.erase(iter); @@ -325,6 +327,7 @@ IFileSystem *MetaFileSystem::GetSystemFromFilename(const std::string &filename) } IFileSystem *MetaFileSystem::GetSystem(const std::string &prefix) { + std::lock_guard guard(lock); for (auto it = fileSystems.begin(); it != fileSystems.end(); ++it) { if (it->prefix == NormalizePrefix(prefix)) return it->system.get(); @@ -414,13 +417,13 @@ int MetaFileSystem::ChDir(const std::string &dir) if (strncasecmp(prefix.c_str(), dir.c_str(), prefix.size()) == 0) { // The PSP is completely happy with invalid current dirs as long as they have a valid device. - WARN_LOG(FILESYS, "ChDir failed to map path \"%s\", saving as current directory anyway", dir.c_str()); + WARN_LOG(Log::FileSystem, "ChDir failed to map path \"%s\", saving as current directory anyway", dir.c_str()); currentDir[curThread] = dir; return 0; } } - WARN_LOG_REPORT(FILESYS, "ChDir failed to map device for \"%s\", failing", dir.c_str()); + WARN_LOG_REPORT(Log::FileSystem, "ChDir failed to map device for \"%s\", failing", dir.c_str()); return SCE_KERNEL_ERROR_NODEV; } } @@ -637,7 +640,7 @@ void MetaFileSystem::DoState(PointerWrap &p) skipPfat0 = true; } else { p.SetError(p.ERROR_FAILURE); - ERROR_LOG(FILESYS, "Savestate failure: number of filesystems doesn't match."); + ERROR_LOG(Log::FileSystem, "Savestate failure: number of filesystems doesn't match."); return; } } diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index a735106f68..0a2255566f 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -43,8 +43,9 @@ private: currentDir_t currentDir; std::string startingDirectory; - std::recursive_mutex lock; // must be recursive + std::recursive_mutex lock; // must be recursive. TODO: fix that + // Assumes the lock is held void Reset() { // This used to be 6, probably an attempt to replicate PSP handles. // However, that's an artifact of using psplink anyway... diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index df73ad544d..c4501705e8 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -104,7 +104,7 @@ void VirtualDiscFileSystem::LoadFileListIndex() { // Syntax: HEXPOS filename or HEXPOS filename:handler size_t filename_pos = line.find(' '); if (filename_pos == line.npos) { - ERROR_LOG(FILESYS, "Unexpected line in %s: %s", INDEX_FILENAME.c_str(), line.c_str()); + ERROR_LOG(Log::FileSystem, "Unexpected line in %s: %s", INDEX_FILENAME.c_str(), line.c_str()); continue; } @@ -135,14 +135,14 @@ void VirtualDiscFileSystem::LoadFileListIndex() { if (trunc != entry.fileName.npos && trunc != entry.fileName.size()) entry.fileName.resize(trunc + 1); - entry.firstBlock = strtol(line.c_str(), NULL, 16); + entry.firstBlock = (u32)strtol(line.c_str(), NULL, 16); if (entry.handler != NULL && entry.handler->IsValid()) { HandlerFileHandle temp = entry.handler; if (temp.Open(basePath.ToString(), entry.fileName, FILEACCESS_READ)) { entry.totalSize = (u32)temp.Seek(0, FILEMOVE_END); temp.Close(); } else { - ERROR_LOG(FILESYS, "Unable to open virtual file: %s", entry.fileName.c_str()); + ERROR_LOG(Log::FileSystem, "Unable to open virtual file: %s", entry.fileName.c_str()); } } else { entry.totalSize = File::GetFileSize(GetLocalPath(entry.fileName)); @@ -207,7 +207,7 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p) bool success = of.Open(basePath, fileList[of.fileIndex].fileName, FILEACCESS_READ); if (!success) { - ERROR_LOG(FILESYS, "Failed to create file handle for %s.", fileList[of.fileIndex].fileName.c_str()); + ERROR_LOG(Log::FileSystem, "Failed to create file handle for %s.", fileList[of.fileIndex].fileName.c_str()); } else { if (of.type == VFILETYPE_LBN) { of.Seek(of.curOffset + of.startOffset, FILEMOVE_BEGIN); @@ -352,7 +352,7 @@ int VirtualDiscFileSystem::OpenFile(std::string filename, FileAccess access, con int fileIndex = getFileListIndex(sectorStart,readSize); if (fileIndex == -1) { - ERROR_LOG(FILESYS, "VirtualDiscFileSystem: sce_lbn used without calling fileinfo."); + ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem: sce_lbn used without calling fileinfo."); return 0; } entry.fileIndex = (u32)fileIndex; @@ -368,9 +368,9 @@ int VirtualDiscFileSystem::OpenFile(std::string filename, FileAccess access, con if (!success) { if (!(access & FILEACCESS_PPSSPP_QUIET)) { #ifdef _WIN32 - ERROR_LOG(FILESYS, "VirtualDiscFileSystem::OpenFile: FAILED, %i", (int)GetLastError()); + ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem::OpenFile: FAILED, %i", (int)GetLastError()); #else - ERROR_LOG(FILESYS, "VirtualDiscFileSystem::OpenFile: FAILED"); + ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem::OpenFile: FAILED"); #endif } return 0; @@ -396,9 +396,9 @@ int VirtualDiscFileSystem::OpenFile(std::string filename, FileAccess access, con if (!success) { if (!(access & FILEACCESS_PPSSPP_QUIET)) { #ifdef _WIN32 - ERROR_LOG(FILESYS, "VirtualDiscFileSystem::OpenFile: FAILED, %i - access = %i", (int)GetLastError(), (int)access); + ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem::OpenFile: FAILED, %i - access = %i", (int)GetLastError(), (int)access); #else - ERROR_LOG(FILESYS, "VirtualDiscFileSystem::OpenFile: FAILED, access = %i", (int)access); + ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem::OpenFile: FAILED, access = %i", (int)access); #endif } return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND; @@ -448,7 +448,7 @@ size_t VirtualDiscFileSystem::SeekFile(u32 handle, s32 position, FileMove type) return 0; } else { //This shouldn't happen... - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot seek in file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot seek in file that hasn't been opened: %08x", handle); return 0; } } @@ -462,7 +462,7 @@ size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &u EntryMap::iterator iter = entries.find(handle); if (iter != entries.end()) { if (size < 0) { - ERROR_LOG_REPORT(FILESYS, "Invalid read for %lld bytes from virtual umd", size); + ERROR_LOG_REPORT(Log::FileSystem, "Invalid read for %lld bytes from virtual umd", size); return 0; } @@ -474,7 +474,7 @@ size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &u int fileIndex = getFileListIndex(iter->second.curOffset,size*2048,true); if (fileIndex == -1) { - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Reading from unknown address in %08x at %08llx", handle, iter->second.curOffset); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Reading from unknown address in %08x at %08llx", handle, iter->second.curOffset); return 0; } @@ -486,7 +486,7 @@ size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &u if (!success) { - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Error opening file %s", fileList[fileIndex].fileName.c_str()); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Error opening file %s", fileList[fileIndex].fileName.c_str()); return 0; } @@ -521,7 +521,7 @@ size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &u if (iter->second.type == VFILETYPE_LBN && iter->second.curOffset + size > iter->second.size) { // Clamp to the remaining size, but read what we can. const s64 newSize = iter->second.size - iter->second.curOffset; - WARN_LOG(FILESYS, "VirtualDiscFileSystem: Reading beyond end of file, clamping size %lld to %lld", size, newSize); + WARN_LOG(Log::FileSystem, "VirtualDiscFileSystem: Reading beyond end of file, clamping size %lld to %lld", size, newSize); size = newSize; } @@ -530,7 +530,7 @@ size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &u return bytesRead; } else { //This shouldn't happen... - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot read file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot read file that hasn't been opened: %08x", handle); return 0; } } @@ -543,7 +543,7 @@ void VirtualDiscFileSystem::CloseFile(u32 handle) { entries.erase(iter); } else { //This shouldn't happen... - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot close file that hasn't been opened: %08x", handle); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot close file that hasn't been opened: %08x", handle); } } @@ -631,7 +631,7 @@ PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) { if (x.type != FILETYPE_DIRECTORY) { File::FileInfo details; if (!File::GetFileInfo(fullName, &details)) { - ERROR_LOG(FILESYS, "DirectoryFileSystem::GetFileInfo: GetFileInfo failed: %s", fullName.c_str()); + ERROR_LOG(Log::FileSystem, "DirectoryFileSystem::GetFileInfo: GetFileInfo failed: %s", fullName.c_str()); x.size = 0; x.access = 0; } else { @@ -735,7 +735,7 @@ std::vector VirtualDiscFileSystem::GetDirListing(const std::string #endif if (dp == NULL) { - ERROR_LOG(FILESYS,"Error opening directory %s\n", path.c_str()); + ERROR_LOG(Log::FileSystem,"Error opening directory %s\n", path.c_str()); if (exists) *exists = false; return myVector; @@ -779,37 +779,37 @@ std::vector VirtualDiscFileSystem::GetDirListing(const std::string size_t VirtualDiscFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) { - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot write to file on virtual disc"); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot write to file on virtual disc"); return 0; } size_t VirtualDiscFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) { - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot write to file on virtual disc"); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot write to file on virtual disc"); return 0; } bool VirtualDiscFileSystem::MkDir(const std::string &dirname) { - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot create directory on virtual disc"); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot create directory on virtual disc"); return false; } bool VirtualDiscFileSystem::RmDir(const std::string &dirname) { - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot remove directory on virtual disc"); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot remove directory on virtual disc"); return false; } int VirtualDiscFileSystem::RenameFile(const std::string &from, const std::string &to) { - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot rename file on virtual disc"); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot rename file on virtual disc"); return -1; } bool VirtualDiscFileSystem::RemoveFile(const std::string &filename) { - ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot remove file on virtual disc"); + ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot remove file on virtual disc"); return false; } @@ -826,9 +826,9 @@ void VirtualDiscFileSystem::HandlerLogger(void *arg, HandlerHandle handle, LogLe } if (filename != NULL) { - GENERIC_LOG(LogType::FILESYS, level, "%s: %s", filename, msg); + GENERIC_LOG(Log::FileSystem, level, "%s: %s", filename, msg); } else { - GENERIC_LOG(LogType::FILESYS, level, "%s", msg); + GENERIC_LOG(Log::FileSystem, level, "%s", msg); } } @@ -862,16 +862,16 @@ VirtualDiscFileSystem::Handler::Handler(const char *filename, VirtualDiscFileSys } if (!Init || !Shutdown || !Open || !Seek || !Read || !Close) { - ERROR_LOG(FILESYS, "Unable to find all handler functions: %s", filename); + ERROR_LOG(Log::FileSystem, "Unable to find all handler functions: %s", filename); dlclose(library); library = NULL; } else if (!Init(&HandlerLogger, sys)) { - ERROR_LOG(FILESYS, "Unable to initialize handler: %s", filename); + ERROR_LOG(Log::FileSystem, "Unable to initialize handler: %s", filename); dlclose(library); library = NULL; } } else { - ERROR_LOG(FILESYS, "Unable to load handler '%s': %s", filename, GetLastErrorMsg().c_str()); + ERROR_LOG(Log::FileSystem, "Unable to load handler '%s': %s", filename, GetLastErrorMsg().c_str()); } #ifdef _WIN32 #undef dlopen diff --git a/Core/Font/PGF.cpp b/Core/Font/PGF.cpp index a01b47225c..e79bf18dfa 100644 --- a/Core/Font/PGF.cpp +++ b/Core/Font/PGF.cpp @@ -186,7 +186,7 @@ bool PGF::ReadPtr(const u8 *ptr, size_t dataSize) { return false; } - DEBUG_LOG(SCEFONT, "Reading %d bytes of PGF header", (int)sizeof(header)); + DEBUG_LOG(Log::sceFont, "Reading %d bytes of PGF header", (int)sizeof(header)); memcpy(&header, ptr, sizeof(header)); ptr += sizeof(header); @@ -570,13 +570,13 @@ void PGF::DrawCharacter(const GlyphImage *image, int clipX, int clipY, int clipW } if (glyph.w <= 0 || glyph.h <= 0) { - DEBUG_LOG(SCEFONT, "Glyph with negative size, not rendering"); + DEBUG_LOG(Log::sceFont, "Glyph with negative size, not rendering"); return; } if (((glyph.flags & FONT_PGF_BMP_OVERLAY) != FONT_PGF_BMP_H_ROWS) && ((glyph.flags & FONT_PGF_BMP_OVERLAY) != FONT_PGF_BMP_V_ROWS)) { - ERROR_LOG_REPORT(SCEFONT, "Nonsense glyph bitmap direction flag"); + ERROR_LOG_REPORT(Log::sceFont, "Nonsense glyph bitmap direction flag"); return; } @@ -680,7 +680,7 @@ void PGF::SetFontPixel(u32 base, int bpl, int bufWidth, int bufHeight, int x, in static const u8 fontPixelSizeInBytes[] = { 0, 0, 1, 3, 4 }; // 0 means 2 pixels per byte if (pixelformat < 0 || pixelformat > PSP_FONT_PIXELFORMAT_32) { - ERROR_LOG_REPORT_ONCE(pfgbadformat, SCEFONT, "Invalid image format in image: %d", (int)pixelformat); + ERROR_LOG_REPORT_ONCE(pfgbadformat, Log::sceFont, "Invalid image format in image: %d", (int)pixelformat); return; } int pixelBytes = fontPixelSizeInBytes[pixelformat]; diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp new file mode 100644 index 0000000000..8837d57816 --- /dev/null +++ b/Core/HLE/AtracCtx.cpp @@ -0,0 +1,1146 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Log.h" +#include "Core/Reporting.h" +#include "Core/MemMapHelpers.h" +#include "Core/System.h" +#include "Core/HLE/HLE.h" +#include "Core/HLE/FunctionWrappers.h" +#include "Core/HLE/sceAtrac.h" +#include "Core/HLE/AtracCtx.h" +#include "Core/HW/Atrac3Standalone.h" +#include "Core/HLE/sceKernelMemory.h" + +const size_t overAllocBytes = 16384; + +const int RIFF_CHUNK_MAGIC = 0x46464952; +const int RIFF_WAVE_MAGIC = 0x45564157; +const int FMT_CHUNK_MAGIC = 0x20746D66; +const int DATA_CHUNK_MAGIC = 0x61746164; +const int SMPL_CHUNK_MAGIC = 0x6C706D73; +const int FACT_CHUNK_MAGIC = 0x74636166; + +void Atrac::DoState(PointerWrap &p) { + auto s = p.Section("Atrac", 1, 9); + if (!s) + return; + + Do(p, track_.channels); + Do(p, outputChannels_); + if (s >= 5) { + Do(p, track_.jointStereo); + } + + Do(p, atracID_); + if (p.mode != p.MODE_READ) { + first_._filesize_dontuse = track_.fileSize; + } + Do(p, first_); + if (p.mode == p.MODE_READ) { + track_.fileSize = first_._filesize_dontuse; + } + + Do(p, bufferMaxSize_); + Do(p, track_.codecType); + + Do(p, currentSample_); + Do(p, track_.endSample); + Do(p, track_.firstSampleOffset); + if (s >= 3) { + Do(p, track_.dataByteOffset); + } else { + track_.dataByteOffset = track_.firstSampleOffset; + } + + u32 hasDataBuf = dataBuf_ != nullptr; + Do(p, hasDataBuf); + if (hasDataBuf) { + if (p.mode == p.MODE_READ) { + if (dataBuf_) + delete[] dataBuf_; + dataBuf_ = new u8[track_.fileSize + overAllocBytes]; + memset(dataBuf_, 0, track_.fileSize + overAllocBytes); + } + DoArray(p, dataBuf_, track_.fileSize); + } + Do(p, second_); + + Do(p, decodePos_); + if (s < 9) { + u32 oldDecodeEnd = 0; + Do(p, oldDecodeEnd); + } + if (s >= 4) { + Do(p, bufferPos_); + } else { + bufferPos_ = decodePos_; + } + + Do(p, track_.bitrate); + Do(p, track_.bytesPerFrame); + + Do(p, track_.loopinfo); + if (s < 9) { + int oldLoopInfoNum = 42; + Do(p, oldLoopInfoNum); + } + + Do(p, track_.loopStartSample); + Do(p, track_.loopEndSample); + Do(p, loopNum_); + + Do(p, context_); + if (s >= 6) { + Do(p, bufferState_); + } else { + if (dataBuf_ == nullptr) { + bufferState_ = ATRAC_STATUS_NO_DATA; + } else { + UpdateBufferState(); + } + } + + if (s >= 7) { + Do(p, ignoreDataBuf_); + } else { + ignoreDataBuf_ = false; + } + + if (s >= 9) { + Do(p, bufferValidBytes_); + Do(p, bufferHeaderSize_); + } else { + bufferHeaderSize_ = track_.dataByteOffset; + bufferValidBytes_ = std::min(first_.size - track_.dataByteOffset, StreamBufferEnd() - track_.dataByteOffset); + if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) { + bufferPos_ = track_.dataByteOffset; + } + } + + if (s < 8 && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { + // We didn't actually allow the second buffer to be set this far back. + // Pretend it's a regular loop, we'll just try our best. + bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END; + } + + // Make sure to do this late; it depends on things like bytesPerFrame_. + if (p.mode == p.MODE_READ && bufferState_ != ATRAC_STATUS_NO_DATA) { + CreateDecoder(); + } + + if (s >= 2 && s < 9) { + bool oldResetBuffer = false; + Do(p, oldResetBuffer); + } +} + +void Atrac::ResetData() { + delete decoder_; + decoder_ = nullptr; + + if (dataBuf_) + delete[] dataBuf_; + dataBuf_ = 0; + ignoreDataBuf_ = false; + bufferState_ = ATRAC_STATUS_NO_DATA; + + if (context_.IsValid()) + kernelMemory.Free(context_.ptr); +} + +void Atrac::AnalyzeReset() { + // Reset some values. + track_.AnalyzeReset(); + + currentSample_ = 0; + loopNum_ = 0; + decodePos_ = 0; + bufferPos_ = 0; +} + +u8 *Atrac::BufferStart() { + return ignoreDataBuf_ ? Memory::GetPointerWrite(first_.addr) : dataBuf_; +} + +void AtracBase::UpdateContextFromPSPMem() { + if (!context_.IsValid()) { + return; + } + + // Read in any changes from the game to the context. + // TODO: Might be better to just always track in RAM. + bufferState_ = context_->info.state; + // This value is actually abused by games to store the SAS voice number. + loopNum_ = context_->info.loopNum; +} + +void Atrac::WriteContextToPSPMem() { + if (!context_.IsValid()) { + return; + } + // context points into PSP memory. + SceAtracContext *context = context_; + context->info.buffer = first_.addr; + context->info.bufferByte = bufferMaxSize_; + context->info.secondBuffer = second_.addr; + context->info.secondBufferByte = second_.size; + context->info.codec = track_.codecType; + context->info.loopNum = loopNum_; + context->info.loopStart = track_.loopStartSample > 0 ? track_.loopStartSample : 0; + context->info.loopEnd = track_.loopEndSample > 0 ? track_.loopEndSample : 0; + + // Note that we read in the state when loading the atrac object, so it's safe + // to update it back here all the time. Some games, like Sol Trigger, change it. + // TODO: Should we just keep this in PSP ram then, or something? + context->info.state = bufferState_; + if (track_.firstSampleOffset != 0) { + context->info.samplesPerChan = track_.FirstSampleOffsetFull(); + } else { + context->info.samplesPerChan = (track_.codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + } + context->info.sampleSize = track_.bytesPerFrame; + context->info.numChan = track_.channels; + context->info.dataOff = track_.dataByteOffset; + context->info.endSample = track_.endSample + track_.FirstSampleOffsetFull(); + context->info.dataEnd = track_.fileSize; + context->info.curOff = first_.fileoffset; + context->info.decodePos = track_.DecodePosBySample(currentSample_); + context->info.streamDataByte = first_.size - track_.dataByteOffset; + + u8 *buf = (u8 *)context; + *(u32_le *)(buf + 0xfc) = atracID_; + + NotifyMemInfo(MemBlockFlags::WRITE, context_.ptr, sizeof(SceAtracContext), "AtracContext"); +} + +void Track::DebugLog() { + DEBUG_LOG(Log::ME, "ATRAC analyzed: %s channels: %d filesize: %d bitrate: %d kbps jointStereo: %d", + codecType == PSP_MODE_AT_3 ? "AT3" : "AT3Plus", channels, fileSize, bitrate / 1024, jointStereo); + DEBUG_LOG(Log::ME, "dataoff: %d firstSampleOffset: %d endSample: %d", dataByteOffset, firstSampleOffset, endSample); + DEBUG_LOG(Log::ME, "loopStartSample: %d loopEndSample: %d", loopStartSample, loopEndSample); +} + +int Atrac::Analyze(u32 addr, u32 size) { + track_ = {}; + first_ = {}; + first_.addr = addr; + first_.size = size; + + AnalyzeReset(); + + // 72 is about the size of the minimum required data to even be valid. + if (size < 72) { + return hleReportError(Log::ME, ATRAC_ERROR_SIZE_TOO_SMALL, "buffer too small"); + } + + // TODO: Check the range (addr, size) instead. + if (!Memory::IsValidAddress(addr)) { + return hleReportWarning(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "invalid buffer address"); + } + + // TODO: Validate stuff. + if (Memory::ReadUnchecked_U32(addr) != RIFF_CHUNK_MAGIC) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid RIFF header"); + } + + int retval = AnalyzeAtracTrack(addr, size, &track_); + first_._filesize_dontuse = track_.fileSize; + track_.DebugLog(); + return retval; +} + +int AnalyzeAtracTrack(u32 addr, u32 size, Track *track) { + struct RIFFFmtChunk { + u16_le fmtTag; + u16_le channels; + u32_le samplerate; + u32_le avgBytesPerSec; + u16_le blockAlign; + }; + + u32 offset = 8; + track->firstSampleOffset = 0; + + while (Memory::Read_U32(addr + offset) != RIFF_WAVE_MAGIC) { + // Get the size preceding the magic. + int chunk = Memory::Read_U32(addr + offset - 4); + // Round the chunk size up to the nearest 2. + offset += chunk + (chunk & 1); + if (offset + 12 > size) { + return hleReportError(Log::ME, ATRAC_ERROR_SIZE_TOO_SMALL, "too small for WAVE chunk at %d", offset); + } + if (Memory::Read_U32(addr + offset) != RIFF_CHUNK_MAGIC) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "RIFF chunk did not contain WAVE"); + } + offset += 8; + } + offset += 4; + + if (offset != 12) { + WARN_LOG_REPORT(Log::ME, "RIFF chunk at offset: %d", offset); + } + + // RIFF size excluding chunk header. + track->fileSize = Memory::Read_U32(addr + offset - 8) + 8; + + // Even if the RIFF size is too low, it may simply be incorrect. This works on real firmware. + u32 maxSize = std::max(track->fileSize, size); + + bool bfoundData = false; + u32 dataChunkSize = 0; + int sampleOffsetAdjust = 0; + + while (maxSize >= offset + 8 && !bfoundData) { + int chunkMagic = Memory::Read_U32(addr + offset); + u32 chunkSize = Memory::Read_U32(addr + offset + 4); + // Account for odd sized chunks. + if (chunkSize & 1) { + WARN_LOG_REPORT_ONCE(oddchunk, Log::ME, "RIFF chunk had uneven size"); + } + chunkSize += (chunkSize & 1); + offset += 8; + if (chunkSize > maxSize - offset) + break; + switch (chunkMagic) { + case FMT_CHUNK_MAGIC: + { + if (track->codecType != 0) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "multiple fmt definitions"); + } + + auto at3fmt = PSPPointer::Create(addr + offset); + if (chunkSize < 32 || (at3fmt->fmtTag == AT3_PLUS_MAGIC && chunkSize < 52)) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "fmt definition too small (%d)", chunkSize); + } + + if (at3fmt->fmtTag == AT3_MAGIC) + track->codecType = PSP_MODE_AT_3; + else if (at3fmt->fmtTag == AT3_PLUS_MAGIC) + track->codecType = PSP_MODE_AT_3_PLUS; + else { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid fmt magic: %04x", at3fmt->fmtTag); + } + track->channels = at3fmt->channels; + if (track->channels != 1 && track->channels != 2) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid channel count: %d", track->channels); + } + if (at3fmt->samplerate != 44100) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "unsupported sample rate: %d", at3fmt->samplerate); + } + track->bitrate = at3fmt->avgBytesPerSec * 8; + track->bytesPerFrame = at3fmt->blockAlign; + if (track->bytesPerFrame == 0) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid bytes per frame: %d", track->bytesPerFrame); + } + + // TODO: There are some format specific bytes here which seem to have fixed values? + // Probably don't need them. + + if (at3fmt->fmtTag == AT3_MAGIC) { + // This is the offset to the jointStereo_ field. + track->jointStereo = Memory::Read_U32(addr + offset + 24); + } + } + break; + case FACT_CHUNK_MAGIC: + { + track->endSample = Memory::Read_U32(addr + offset); + if (chunkSize >= 8) { + track->firstSampleOffset = Memory::Read_U32(addr + offset + 4); + } + if (chunkSize >= 12) { + u32 largerOffset = Memory::Read_U32(addr + offset + 8); + sampleOffsetAdjust = track->firstSampleOffset - largerOffset; + } + } + break; + case SMPL_CHUNK_MAGIC: + { + if (chunkSize < 32) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "smpl chunk too small (%d)", chunkSize); + } + int checkNumLoops = Memory::Read_U32(addr + offset + 28); + if (checkNumLoops != 0 && chunkSize < 36 + 20) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "smpl chunk too small for loop (%d, %d)", checkNumLoops, chunkSize); + } + if (checkNumLoops < 0) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "bad checkNumLoops (%d)", checkNumLoops); + } + + track->loopinfo.resize(checkNumLoops); + u32 loopinfoAddr = addr + offset + 36; + // The PSP only cares about the first loop start and end, it seems. + // Most likely can skip the rest of this data, but it's not hurting anyone. + for (int i = 0; i < checkNumLoops && 36 + (u32)i < chunkSize; i++, loopinfoAddr += 24) { + track->loopinfo[i].cuePointID = Memory::Read_U32(loopinfoAddr); + track->loopinfo[i].type = Memory::Read_U32(loopinfoAddr + 4); + track->loopinfo[i].startSample = Memory::Read_U32(loopinfoAddr + 8); + track->loopinfo[i].endSample = Memory::Read_U32(loopinfoAddr + 12); + track->loopinfo[i].fraction = Memory::Read_U32(loopinfoAddr + 16); + track->loopinfo[i].playCount = Memory::Read_U32(loopinfoAddr + 20); + + if (track->loopinfo[i].startSample >= track->loopinfo[i].endSample) { + return hleReportError(Log::ME, ATRAC_ERROR_BAD_CODEC_PARAMS, "loop starts after it ends"); + } + } + } + break; + case DATA_CHUNK_MAGIC: + { + bfoundData = true; + track->dataByteOffset = offset; + dataChunkSize = chunkSize; + if (track->fileSize < offset + chunkSize) { + WARN_LOG_REPORT(Log::ME, "Atrac data chunk extends beyond riff chunk"); + track->fileSize = offset + chunkSize; + } + } + break; + } + offset += chunkSize; + } + + if (track->codecType == 0) { + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "could not detect codec"); + } + + if (!bfoundData) { + return hleReportError(Log::ME, ATRAC_ERROR_SIZE_TOO_SMALL, "no data chunk"); + } + + // set the loopStartSample_ and loopEndSample_ by loopinfo_ + if (track->loopinfo.size() > 0) { + track->loopStartSample = track->loopinfo[0].startSample + track->FirstOffsetExtra() + sampleOffsetAdjust; + track->loopEndSample = track->loopinfo[0].endSample + track->FirstOffsetExtra() + sampleOffsetAdjust; + } else { + track->loopStartSample = -1; + track->loopEndSample = -1; + } + + // if there is no correct endsample, try to guess it + if (track->endSample <= 0 && track->bytesPerFrame != 0) { + track->endSample = (dataChunkSize / track->bytesPerFrame) * track->SamplesPerFrame(); + track->endSample -= track->FirstSampleOffsetFull(); + } + track->endSample -= 1; + + if (track->loopEndSample != -1 && track->loopEndSample > track->endSample + track->FirstSampleOffsetFull()) { + return hleReportError(Log::ME, ATRAC_ERROR_BAD_CODEC_PARAMS, "loop after end of data"); + } + + return 0; +} + +int Atrac::AnalyzeAA3(u32 addr, u32 size, u32 fileSize) { + first_.addr = addr; + first_.size = size; + first_._filesize_dontuse = fileSize; + + AnalyzeReset(); + + return AnalyzeAA3Track(addr, size, fileSize, &track_); +} + +int AnalyzeAA3Track(u32 addr, u32 size, u32 fileSize, Track *track) { + if (size < 10) { + return hleReportError(Log::ME, ATRAC_ERROR_AA3_SIZE_TOO_SMALL, "buffer too small"); + } + // TODO: Make sure this validation is correct, more testing. + + const u8 *buffer = Memory::GetPointer(addr); + if (buffer[0] != 'e' || buffer[1] != 'a' || buffer[2] != '3') { + return hleReportError(Log::ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid ea3 magic bytes"); + } + + // It starts with an id3 header (replaced with ea3.) This is the size. + u32 tagSize = buffer[9] | (buffer[8] << 7) | (buffer[7] << 14) | (buffer[6] << 21); + if (size < tagSize + 36) { + return hleReportError(Log::ME, ATRAC_ERROR_AA3_SIZE_TOO_SMALL, "truncated before id3 end"); + } + + // EA3 header starts at id3 header (10) + tagSize. + buffer = Memory::GetPointer(addr + 10 + tagSize); + if (buffer[0] != 'E' || buffer[1] != 'A' || buffer[2] != '3') { + return hleReportError(Log::ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid EA3 magic bytes"); + } + + track->fileSize = fileSize; + + // Based on FFmpeg's code. + u32 codecParams = buffer[35] | (buffer[34] << 8) | (buffer[35] << 16); + const u32 at3SampleRates[8] = { 32000, 44100, 48000, 88200, 96000, 0 }; + + switch (buffer[32]) { + case 0: + track->codecType = PSP_MODE_AT_3; + track->bytesPerFrame = (codecParams & 0x03FF) * 8; + track->bitrate = at3SampleRates[(codecParams >> 13) & 7] * track->bytesPerFrame * 8 / 1024; + track->channels = 2; + track->jointStereo = (codecParams >> 17) & 1; + break; + case 1: + track->codecType = PSP_MODE_AT_3_PLUS; + track->bytesPerFrame = ((codecParams & 0x03FF) * 8) + 8; + track->bitrate = at3SampleRates[(codecParams >> 13) & 7] * track->bytesPerFrame * 8 / 2048; + track->channels = (codecParams >> 10) & 7; + break; + case 3: + case 4: + case 5: + return hleReportError(Log::ME, ATRAC_ERROR_AA3_INVALID_DATA, "unsupported codec type %d", buffer[32]); + default: + return hleReportError(Log::ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid codec type %d", buffer[32]); + } + + track->dataByteOffset = 10 + tagSize + 96; + track->firstSampleOffset = 0; + if (track->endSample < 0 && track->bytesPerFrame != 0) { + track->endSample = ((track->fileSize - track->dataByteOffset) / track->bytesPerFrame) * track->SamplesPerFrame(); + } + track->endSample -= 1; + return 0; +} + +void Atrac::CalculateStreamInfo(u32 *outReadOffset) { + u32 readOffset = first_.fileoffset; + if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { + // Nothing to write. + readOffset = 0; + first_.offset = 0; + first_.writableBytes = 0; + } else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) { + // If we're buffering the entire file, just give the same as readOffset. + first_.offset = readOffset; + // In this case, the bytes writable are just the remaining bytes, always. + first_.writableBytes = track_.fileSize - readOffset; + } else { + u32 bufferEnd = StreamBufferEnd(); + u32 bufferValidExtended = bufferPos_ + bufferValidBytes_; + if (bufferValidExtended < bufferEnd) { + first_.offset = bufferValidExtended; + first_.writableBytes = bufferEnd - bufferValidExtended; + } else { + u32 bufferStartUsed = bufferValidExtended - bufferEnd; + first_.offset = bufferStartUsed; + first_.writableBytes = bufferPos_ - bufferStartUsed; + } + + if (readOffset >= track_.fileSize) { + if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) { + // We don't need anything more, so all 0s. + readOffset = 0; + first_.offset = 0; + first_.writableBytes = 0; + } else { + readOffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2); + } + } + + if (readOffset + first_.writableBytes > track_.fileSize) { + // Never ask for past the end of file, even when the space is free. + first_.writableBytes = track_.fileSize - readOffset; + } + + // If you don't think this should be here, remove it. It's just a temporary safety check. + if (first_.offset + first_.writableBytes > bufferMaxSize_) { + ERROR_LOG_REPORT(Log::ME, "Somehow calculated too many writable bytes: %d + %d > %d", first_.offset, first_.writableBytes, bufferMaxSize_); + first_.offset = 0; + first_.writableBytes = bufferMaxSize_; + } + } + + if (outReadOffset) { + *outReadOffset = readOffset; + } +} + +void AtracBase::CreateDecoder() { + if (decoder_) { + delete decoder_; + } + + // First, init the standalone decoder. Only used for low-level-decode initially, but simple. + if (track_.codecType == PSP_MODE_AT_3) { + // We don't pull this from the RIFF so that we can support OMA also. + uint8_t extraData[14]{}; + // The only thing that changes are the jointStereo_ values. + extraData[0] = 1; + extraData[3] = track_.channels << 3; + extraData[6] = track_.jointStereo; + extraData[8] = track_.jointStereo; + extraData[10] = 1; + decoder_ = CreateAtrac3Audio(track_.channels, track_.bytesPerFrame, extraData, sizeof(extraData)); + } else { + decoder_ = CreateAtrac3PlusAudio(track_.channels, track_.bytesPerFrame); + } +} + +void Atrac::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) { + if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { + bufferInfo->first.writePosPtr = first_.addr; + // Everything is loaded, so nothing needs to be read. + bufferInfo->first.writableBytes = 0; + bufferInfo->first.minWriteBytes = 0; + bufferInfo->first.filePos = 0; + } else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) { + // Here the message is: you need to read at least this many bytes to get to that position. + // This is because we're filling the buffer start to finish, not streaming. + bufferInfo->first.writePosPtr = first_.addr + first_.size; + bufferInfo->first.writableBytes = track_.fileSize - first_.size; + int minWriteBytes = track_.FileOffsetBySample(sample) - first_.size; + if (minWriteBytes > 0) { + bufferInfo->first.minWriteBytes = minWriteBytes; + } else { + bufferInfo->first.minWriteBytes = 0; + } + bufferInfo->first.filePos = first_.size; + } else { + // This is without the sample offset. The file offset also includes the previous batch of samples? + int sampleFileOffset = track_.FileOffsetBySample(sample - track_.firstSampleOffset - track_.SamplesPerFrame()); + + // Update the writable bytes. When streaming, this is just the number of bytes until the end. + const u32 bufSizeAligned = (bufferMaxSize_ / track_.bytesPerFrame) * track_.bytesPerFrame; + const int needsMoreFrames = track_.FirstOffsetExtra(); // ? + + bufferInfo->first.writePosPtr = first_.addr; + bufferInfo->first.writableBytes = std::min(track_.fileSize - sampleFileOffset, bufSizeAligned); + if (((sample + track_.firstSampleOffset) % (int)track_.SamplesPerFrame()) >= (int)track_.SamplesPerFrame() - needsMoreFrames) { + // Not clear why, but it seems it wants a bit extra in case the sample is late? + bufferInfo->first.minWriteBytes = track_.bytesPerFrame * 3; + } else { + bufferInfo->first.minWriteBytes = track_.bytesPerFrame * 2; + } + if ((u32)sample < (u32)track_.firstSampleOffset && sampleFileOffset != track_.dataByteOffset) { + sampleFileOffset -= track_.bytesPerFrame; + } + bufferInfo->first.filePos = sampleFileOffset; + + if (second_.size != 0) { + // TODO: We have a second buffer. Within it, minWriteBytes should be zero. + // The filePos should be after the end of the second buffer (or zero.) + // We actually need to ensure we READ from the second buffer before implementing that. + } + } + + // It seems like this is always the same as the first buffer's pos, weirdly. + bufferInfo->second.writePosPtr = first_.addr; + // Reset never needs a second buffer write, since the loop is in a fixed place. + bufferInfo->second.writableBytes = 0; + bufferInfo->second.minWriteBytes = 0; + bufferInfo->second.filePos = 0; +} + +int Atrac::SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) { + outputChannels_ = outputChannels; + + first_.addr = buffer; + first_.size = readSize; + + if (first_.size > track_.fileSize) + first_.size = track_.fileSize; + first_.fileoffset = first_.size; + + // got the size of temp buf, and calculate offset + bufferMaxSize_ = bufferSize; + first_.offset = first_.size; + + // some games may reuse an atracID for playing sound + ResetData(); + UpdateBufferState(); + + if (track_.codecType != PSP_MODE_AT_3 && track_.codecType != PSP_MODE_AT_3_PLUS) { + // Shouldn't have gotten here, Analyze() checks this. + bufferState_ = ATRAC_STATUS_NO_DATA; + return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "unexpected codec type in set data"); + } + + if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED || bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) { + // This says, don't use the dataBuf_ array, use the PSP RAM. + // This way, games can load data async into the buffer, and it still works. + // TODO: Support this always, even for streaming. + ignoreDataBuf_ = true; + } + if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP || bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END || bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { + bufferHeaderSize_ = track_.dataByteOffset; + bufferPos_ = track_.dataByteOffset + track_.bytesPerFrame; + bufferValidBytes_ = first_.size - bufferPos_; + } + + const char *codecName = track_.codecType == PSP_MODE_AT_3 ? "atrac3" : "atrac3+"; + const char *channelName = track_.channels == 1 ? "mono" : "stereo"; + + // Over-allocate databuf to prevent going off the end if the bitstream is bad or if there are + // bugs in the decoder. This happens, see issue #15788. Arbitrary, but let's make it a whole page on the popular + // architecture that has the largest pages (M1). + dataBuf_ = new u8[track_.fileSize + overAllocBytes]; + memset(dataBuf_, 0, track_.fileSize + overAllocBytes); + if (!ignoreDataBuf_) { + u32 copybytes = std::min(bufferSize, track_.fileSize); + Memory::Memcpy(dataBuf_, buffer, copybytes, "AtracSetData"); + } + CreateDecoder(); + return hleLogSuccessInfoI(Log::ME, successCode, "%s %s audio", codecName, channelName); +} + +u32 Atrac::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) { + u32 secondFileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset); + u32 desiredSize = track_.fileSize - secondFileOffset; + + // 3 seems to be the number of frames required to handle a loop. + if (secondBufferSize < desiredSize && secondBufferSize < (u32)track_.BytesPerFrame() * 3) { + return hleReportError(Log::ME, ATRAC_ERROR_SIZE_TOO_SMALL, "too small"); + } + if (BufferState() != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { + return hleReportError(Log::ME, ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED, "not needed"); + } + + second_.addr = secondBuffer; + second_.size = secondBufferSize; + second_.fileoffset = secondFileOffset; + return hleLogSuccessI(Log::ME, 0); +} + +int AtracBase::GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) { + if (BufferState() != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { + // Writes zeroes in this error case. + *fileOffset = 0; + *desiredSize = 0; + return hleLogWarning(Log::ME, ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED, "not needed"); + } + + *fileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset); + *desiredSize = track_.fileSize - *fileOffset; + return hleLogSuccessI(Log::ME, 0); +} + +void Atrac::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) { + u32 calculatedReadOffset; + // TODO: Feels like this should already have been computed? + CalculateStreamInfo(&calculatedReadOffset); + + *writePtr = first_.addr + first_.offset; + *writableBytes = first_.writableBytes; + *readOffset = calculatedReadOffset; +} + +void Atrac::UpdateBufferState() { + if (bufferMaxSize_ >= track_.fileSize) { + if (first_.size < track_.fileSize) { + // The buffer is big enough, but we don't have all the data yet. + bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER; + } else { + bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; + } + } else { + if (track_.loopEndSample <= 0) { + // There's no looping, but we need to stream the data in our buffer. + bufferState_ = ATRAC_STATUS_STREAMED_WITHOUT_LOOP; + } else if (track_.loopEndSample == track_.endSample + track_.FirstSampleOffsetFull()) { + bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END; + } else { + bufferState_ = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER; + } + } +} + +int Atrac::AddStreamData(u32 bytesToAdd) { + u32 readOffset; + CalculateStreamInfo(&readOffset); + if (bytesToAdd > first_.writableBytes) + return hleLogWarning(Log::ME, ATRAC_ERROR_ADD_DATA_IS_TOO_BIG, "too many bytes"); + + if (bytesToAdd > 0) { + first_.fileoffset = readOffset; + int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset); + if (!ignoreDataBuf_) { + Memory::Memcpy(dataBuf_ + first_.fileoffset, first_.addr + first_.offset, addbytes, "AtracAddStreamData"); + } + first_.fileoffset += addbytes; + } + first_.size += bytesToAdd; + if (first_.size >= track_.fileSize) { + first_.size = track_.fileSize; + if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) + bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; + WriteContextToPSPMem(); + } + + first_.offset += bytesToAdd; + bufferValidBytes_ += bytesToAdd; + + if (PSP_CoreParameter().compat.flags().AtracLoopHack && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && RemainingFrames() > 2) { + loopNum_++; + SeekToSample(track_.loopStartSample - track_.FirstSampleOffsetFull()); + } + + return 0; +} + +u32 Atrac::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) { + int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset - track_.FirstOffsetExtra()); + Memory::Memcpy(dataBuf_ + first_.fileoffset + track_.FirstOffsetExtra(), bufPtr, addbytes, "AtracAddStreamData"); + first_.size += bytesToAdd; + if (first_.size >= track_.fileSize) { + first_.size = track_.fileSize; + if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) + bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; + } + first_.fileoffset += addbytes; + // refresh context_ + WriteContextToPSPMem(); + return 0; +} + +u32 Atrac::GetNextSamples() { + // It seems like the PSP aligns the sample position to 0x800...? + u32 skipSamples = track_.FirstSampleOffsetFull(); + u32 firstSamples = (track_.SamplesPerFrame() - skipSamples) % track_.SamplesPerFrame(); + u32 numSamples = track_.endSample + 1 - currentSample_; + if (currentSample_ == 0 && firstSamples != 0) { + numSamples = firstSamples; + } + u32 unalignedSamples = (skipSamples + currentSample_) % track_.SamplesPerFrame(); + if (unalignedSamples != 0) { + // We're off alignment, possibly due to a loop. Force it back on. + numSamples = track_.SamplesPerFrame() - unalignedSamples; + } + if (numSamples > track_.SamplesPerFrame()) + numSamples = track_.SamplesPerFrame(); + if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && (int)numSamples + currentSample_ > track_.endSample) { + bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; + } + return numSamples; +} + +void Atrac::ForceSeekToSample(int sample) { + if (decoder_) { + decoder_->FlushBuffers(); + } + currentSample_ = sample; +} + +void Atrac::SeekToSample(int sample) { + // It seems like the PSP aligns the sample position to 0x800...? + const u32 offsetSamples = track_.FirstSampleOffsetFull(); + const u32 unalignedSamples = (offsetSamples + sample) % track_.SamplesPerFrame(); + int seekFrame = sample + offsetSamples - unalignedSamples; + + if ((sample != currentSample_ || sample == 0) && decoder_ != nullptr) { + // Prefill the decode buffer with packets before the first sample offset. + decoder_->FlushBuffers(); + + int adjust = 0; + if (sample == 0) { + int offsetSamples = track_.FirstSampleOffsetFull(); + adjust = -(int)(offsetSamples % track_.SamplesPerFrame()); + } + const u32 off = track_.FileOffsetBySample(sample + adjust); + const u32 backfill = track_.bytesPerFrame * 2; + const u32 start = off - track_.dataByteOffset < backfill ? track_.dataByteOffset : off - backfill; + + for (u32 pos = start; pos < off; pos += track_.bytesPerFrame) { + decoder_->Decode(BufferStart() + pos, track_.bytesPerFrame, nullptr, 2, nullptr, nullptr); + } + } + + currentSample_ = sample; +} + +int Atrac::RemainingFrames() const { + if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { + // Meaning, infinite I guess? We've got it all. + return PSP_ATRAC_ALLDATA_IS_ON_MEMORY; + } + + u32 currentFileOffset = track_.FileOffsetBySample(currentSample_ - track_.SamplesPerFrame() + track_.FirstOffsetExtra()); + if (first_.fileoffset >= track_.fileSize) { + if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) { + return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY; + } + int loopEndAdjusted = track_.loopEndSample - track_.FirstOffsetExtra() - track_.firstSampleOffset; + if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && currentSample_ > loopEndAdjusted) { + // No longer looping in this case, outside the loop. + return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY; + } + if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK && loopNum_ == 0) { + return PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY; + } + } + + if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) { + // Since we're streaming, the remaining frames are what's valid in the buffer. + return bufferValidBytes_ / track_.bytesPerFrame; + } + + // Since the first frame is shorter by this offset, add to round up at this offset. + const int remainingBytes = first_.fileoffset - currentFileOffset; + if (remainingBytes < 0) { + // Just in case. Shouldn't happen, but once did by mistake. + return 0; + } + return remainingBytes / track_.bytesPerFrame; +} + +void Atrac::ConsumeFrame() { + bufferPos_ += track_.bytesPerFrame; + if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) { + if (bufferValidBytes_ > track_.bytesPerFrame) { + bufferValidBytes_ -= track_.bytesPerFrame; + } else { + bufferValidBytes_ = 0; + } + } + if (bufferPos_ >= StreamBufferEnd()) { + // Wrap around... theoretically, this should only happen at exactly StreamBufferEnd. + bufferPos_ -= StreamBufferEnd(); + bufferHeaderSize_ = 0; + } +} + +u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) { + int loopNum = loopNum_; + if (bufferState_ == ATRAC_STATUS_FOR_SCESAS) { + // TODO: Might need more testing. + loopNum = 0; + } + + // We already passed the end - return an error (many games check for this.) + if (currentSample_ >= track_.endSample && loopNum == 0) { + *SamplesNum = 0; + *finish = 1; + // refresh context_ + WriteContextToPSPMem(); + return ATRAC_ERROR_ALL_DATA_DECODED; + } + + // TODO: This isn't at all right, but at least it makes the music "last" some time. + u32 numSamples = 0; + + // It seems like the PSP aligns the sample position to 0x800...? + int offsetSamples = track_.FirstSampleOffsetFull(); + int skipSamples = 0; + u32 maxSamples = track_.endSample + 1 - currentSample_; + u32 unalignedSamples = (offsetSamples + currentSample_) % track_.SamplesPerFrame(); + if (unalignedSamples != 0) { + // We're off alignment, possibly due to a loop. Force it back on. + maxSamples = track_.SamplesPerFrame() - unalignedSamples; + skipSamples = unalignedSamples; + } + + if (skipSamples != 0 && bufferHeaderSize_ == 0) { + // Skip the initial frame used to load state for the looped frame. + // TODO: We will want to actually read this in. + // TODO again: This seems to happen on the first frame of playback regardless of loops. + // Can't be good. + ConsumeFrame(); + } + + SeekToSample(currentSample_); + + bool gotFrame = false; + u32 off = track_.FileOffsetBySample(currentSample_ - skipSamples); + if (off < first_.size) { + uint8_t *indata = BufferStart() + off; + int bytesConsumed = 0; + int outSamples = track_.SamplesPerFrame(); + int outBytes = outSamples * outputChannels_ * sizeof(int16_t); + gotFrame = true; + + numSamples = outSamples; + uint32_t packetAddr = CurBufferAddress(-skipSamples); + // got a frame + int skipped = std::min((u32)skipSamples, numSamples); + skipSamples -= skipped; + numSamples = numSamples - skipped; + // If we're at the end, clamp to samples we want. It always returns a full chunk. + numSamples = std::min(maxSamples, numSamples); + + outSamples = numSamples; + if (!decoder_->Decode(indata, track_.bytesPerFrame, &bytesConsumed, outputChannels_, (int16_t *)outbuf, &outSamples)) { + // Decode failed. + *SamplesNum = 0; + *finish = 1; + return ATRAC_ERROR_ALL_DATA_DECODED; + } + + if (packetAddr != 0 && MemBlockInfoDetailed()) { + char tagData[128]; + size_t tagSize = FormatMemWriteTagAt(tagData, sizeof(tagData), "AtracDecode/", packetAddr, track_.bytesPerFrame); + NotifyMemInfo(MemBlockFlags::READ, packetAddr, track_.bytesPerFrame, tagData, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, tagData, tagSize); + } else { + NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode"); + } + // We only want one frame per call, let's continue the next time. + } + + if (!gotFrame && currentSample_ < track_.endSample) { + // Never got a frame. We may have dropped a GHA frame or otherwise have a bug. + // For now, let's try to provide an extra "frame" if possible so games don't infinite loop. + if (track_.FileOffsetBySample(currentSample_) < track_.fileSize) { + numSamples = std::min(maxSamples, track_.SamplesPerFrame()); + u32 outBytes = numSamples * outputChannels_ * sizeof(s16); + if (outbuf != nullptr) { + memset(outbuf, 0, outBytes); + NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode"); + } + } + } + + *SamplesNum = numSamples; + // update current sample and decodePos + currentSample_ += numSamples; + decodePos_ = track_.DecodePosBySample(currentSample_); + + ConsumeFrame(); + + int finishFlag = 0; + // TODO: Verify. + bool hitEnd = currentSample_ >= track_.endSample || (numSamples == 0 && first_.size >= track_.fileSize); + int loopEndAdjusted = track_.loopEndSample - track_.FirstSampleOffsetFull(); + if ((hitEnd || currentSample_ > loopEndAdjusted) && loopNum != 0) { + SeekToSample(track_.loopStartSample - track_.FirstSampleOffsetFull()); + if (bufferState_ != ATRAC_STATUS_FOR_SCESAS) { + if (loopNum_ > 0) + loopNum_--; + } + if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) { + // Whatever bytes we have left were added from the loop. + u32 loopOffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2); + // TODO: Hmm, need to manage the buffer better. But don't move fileoffset if we already have valid data. + if (loopOffset > first_.fileoffset || loopOffset + bufferValidBytes_ < first_.fileoffset) { + // Skip the initial frame at the start. + first_.fileoffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2); + } + } + } else if (hitEnd) { + finishFlag = 1; + + // Still move forward, so we know that we've read everything. + // This seems to be reflected in the context as well. + currentSample_ += track_.SamplesPerFrame() - numSamples; + } + + *finish = finishFlag; + *remains = RemainingFrames(); + // refresh context_ + WriteContextToPSPMem(); + return 0; +} + +void AtracBase::SetLoopNum(int loopNum) { + // Spammed in MHU + loopNum_ = loopNum; + if (loopNum != 0 && track_.loopinfo.size() == 0) { + // Just loop the whole audio + // This is a rare modification of track_ after the fact. + // Maybe we can get away with setting these by default. + track_.loopStartSample = track_.FirstSampleOffsetFull(); + track_.loopEndSample = track_.endSample + track_.FirstSampleOffsetFull(); + } + WriteContextToPSPMem(); +} + +u32 Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) { + // Reuse the same calculation as before. + AtracResetBufferInfo bufferInfo; + GetResetBufferInfo(&bufferInfo, sample); + + if ((u32)bytesWrittenFirstBuf < bufferInfo.first.minWriteBytes || (u32)bytesWrittenFirstBuf > bufferInfo.first.writableBytes) { + return hleLogError(Log::ME, ATRAC_ERROR_BAD_FIRST_RESET_SIZE, "first byte count not in valid range"); + } + if ((u32)bytesWrittenSecondBuf < bufferInfo.second.minWriteBytes || (u32)bytesWrittenSecondBuf > bufferInfo.second.writableBytes) { + return hleLogError(Log::ME, ATRAC_ERROR_BAD_SECOND_RESET_SIZE, "second byte count not in valid range"); + } + + if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { + // Always adds zero bytes. + } else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) { + // Okay, it's a valid number of bytes. Let's set them up. + if (bytesWrittenFirstBuf != 0) { + if (!ignoreDataBuf_) { + Memory::Memcpy(dataBuf_ + first_.size, first_.addr + first_.size, bytesWrittenFirstBuf, "AtracResetPlayPosition"); + } + first_.fileoffset += bytesWrittenFirstBuf; + first_.size += bytesWrittenFirstBuf; + first_.offset += bytesWrittenFirstBuf; + } + + // Did we transition to a full buffer? + if (first_.size >= track_.fileSize) { + first_.size = track_.fileSize; + bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; + } + } else { + if (bufferInfo.first.filePos > track_.fileSize) { + return hleDelayResult(hleLogError(Log::ME, ATRAC_ERROR_API_FAIL, "invalid file position"), "reset play pos", 200); + } + + // Move the offset to the specified position. + first_.fileoffset = bufferInfo.first.filePos; + + if (bytesWrittenFirstBuf != 0) { + if (!ignoreDataBuf_) { + Memory::Memcpy(dataBuf_ + first_.fileoffset, first_.addr, bytesWrittenFirstBuf, "AtracResetPlayPosition"); + } + first_.fileoffset += bytesWrittenFirstBuf; + } + first_.size = first_.fileoffset; + first_.offset = bytesWrittenFirstBuf; + + bufferHeaderSize_ = 0; + bufferPos_ = track_.bytesPerFrame; + bufferValidBytes_ = bytesWrittenFirstBuf - bufferPos_; + } + + if (track_.codecType == PSP_MODE_AT_3 || track_.codecType == PSP_MODE_AT_3_PLUS) { + SeekToSample(sample); + } + + WriteContextToPSPMem(); + return 0; +} + +void Atrac::InitLowLevel(u32 paramsAddr, bool jointStereo) { + track_.channels = Memory::Read_U32(paramsAddr); + outputChannels_ = Memory::Read_U32(paramsAddr + 4); + bufferMaxSize_ = Memory::Read_U32(paramsAddr + 8); + track_.bytesPerFrame = bufferMaxSize_; + first_.writableBytes = track_.bytesPerFrame; + ResetData(); + + if (track_.codecType == PSP_MODE_AT_3) { + track_.bitrate = (track_.bytesPerFrame * 352800) / 1000; + track_.bitrate = (track_.bitrate + 511) >> 10; + track_.jointStereo = false; + } else if (track_.codecType == PSP_MODE_AT_3_PLUS) { + track_.bitrate = (track_.bytesPerFrame * 352800) / 1000; + track_.bitrate = ((track_.bitrate >> 11) + 8) & 0xFFFFFFF0; + track_.jointStereo = false; + } + + track_.dataByteOffset = 0; + first_.size = 0; + track_.fileSize = track_.bytesPerFrame; // not really meaningful + bufferState_ = ATRAC_STATUS_LOW_LEVEL; + currentSample_ = 0; + CreateDecoder(); + WriteContextToPSPMem(); +} diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h new file mode 100644 index 0000000000..8f2bf38fda --- /dev/null +++ b/Core/HLE/AtracCtx.h @@ -0,0 +1,351 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include + +#include "Common/CommonTypes.h" +#include "Common/Swap.h" + +#include "Core/MemMap.h" +#include "Core/HLE/sceAtrac.h" + +struct AtracSingleResetBufferInfo { + u32_le writePosPtr; + u32_le writableBytes; + u32_le minWriteBytes; + u32_le filePos; +}; + +struct AtracResetBufferInfo { + AtracSingleResetBufferInfo first; + AtracSingleResetBufferInfo second; +}; + +#define AT3_MAGIC 0x0270 +#define AT3_PLUS_MAGIC 0xFFFE +#define PSP_MODE_AT_3_PLUS 0x00001000 +#define PSP_MODE_AT_3 0x00001001 + +#define ATRAC_ERROR_API_FAIL 0x80630002 +#define ATRAC_ERROR_NO_ATRACID 0x80630003 +#define ATRAC_ERROR_INVALID_CODECTYPE 0x80630004 +#define ATRAC_ERROR_BAD_ATRACID 0x80630005 +#define ATRAC_ERROR_UNKNOWN_FORMAT 0x80630006 +#define ATRAC_ERROR_WRONG_CODECTYPE 0x80630007 +#define ATRAC_ERROR_BAD_CODEC_PARAMS 0x80630008 +#define ATRAC_ERROR_ALL_DATA_LOADED 0x80630009 +#define ATRAC_ERROR_NO_DATA 0x80630010 +#define ATRAC_ERROR_SIZE_TOO_SMALL 0x80630011 +#define ATRAC_ERROR_SECOND_BUFFER_NEEDED 0x80630012 +#define ATRAC_ERROR_INCORRECT_READ_SIZE 0x80630013 +#define ATRAC_ERROR_BAD_SAMPLE 0x80630015 +#define ATRAC_ERROR_BAD_FIRST_RESET_SIZE 0x80630016 +#define ATRAC_ERROR_BAD_SECOND_RESET_SIZE 0x80630017 +#define ATRAC_ERROR_ADD_DATA_IS_TOO_BIG 0x80630018 +#define ATRAC_ERROR_NOT_MONO 0x80630019 +#define ATRAC_ERROR_NO_LOOP_INFORMATION 0x80630021 +#define ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED 0x80630022 +#define ATRAC_ERROR_BUFFER_IS_EMPTY 0x80630023 +#define ATRAC_ERROR_ALL_DATA_DECODED 0x80630024 +#define ATRAC_ERROR_IS_LOW_LEVEL 0x80630031 +#define ATRAC_ERROR_IS_FOR_SCESAS 0x80630040 +#define ATRAC_ERROR_AA3_INVALID_DATA 0x80631003 +#define ATRAC_ERROR_AA3_SIZE_TOO_SMALL 0x80631004 + +const u32 ATRAC3_MAX_SAMPLES = 0x400; +const u32 ATRAC3PLUS_MAX_SAMPLES = 0x800; + +const int PSP_ATRAC_ALLDATA_IS_ON_MEMORY = -1; +const int PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY = -2; +const int PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY = -3; + +// This is not a PSP-native struct. +// But, it's stored in its entirety in savestates, which makes it awkward to change it. +struct InputBuffer { + // Address of the buffer. + u32 addr; + // Size of data read so far into dataBuf_ (to be removed.) + u32 size; + // Offset into addr at which new data is added. + u32 offset; + // Last writableBytes number (to be removed.) + u32 writableBytes; + // Unused, always 0. + u32 neededBytes; + // Total size of the entire file data. + u32 _filesize_dontuse; + // Offset into the file at which new data is read. + u32 fileoffset; +}; + +struct AtracLoopInfo { + int cuePointID; + int type; + int startSample; + int endSample; + int fraction; + int playCount; +}; + +class AudioDecoder; + +struct Track { + // This both does and doesn't belong in Track - it's fixed for an Atrac instance. Oh well. + u32 codecType = 0; + + // Size of the full track being streamed or played. Can be a lot larger than the in-memory buffer in the streaming modes. + u32 fileSize = 0; + + // Not really used for much except queries, this keeps track of the bitrate of the track. + u32 bitrate = 64; + + // Signifies whether to use a more efficient coding mode with less stereo separation. For our purposes, just metadata. + int jointStereo = 0; + + // Number of audio channels in the track. + u16 channels = 0; + + // The size of an encoded frame in bytes. + u16 bytesPerFrame = 0; + + // Byte offset of the first encoded frame in the input buffer. Note: Some samples may be skipped according to firstSampleOffset. + int dataByteOffset = 0; + + // How many samples to skip from the beginning of a track when decoding. + // Actually, the real number is this added to FirstOffsetExtra(codecType). You can call + // FirstSampleOffset2() to get that. + // Some use of these offsets around the code seem to be inconsistent, sometimes the extra is included, + // sometimes not. + int firstSampleOffset = 0; + + // Last sample number. Though, we made it so in Analyze, it's exclusive in the file. + // Does not take firstSampleOffset into account. + int endSample = 0; + + // Loop configuration. The PSP only supports one loop but we store them all. + std::vector loopinfo; + // The actual used loop offsets. These appear to be raw offsets, not taking FirstSampleOffset2() into account. + int loopStartSample = -1; + int loopEndSample = -1; + + // Input frame size + int BytesPerFrame() const { + return bytesPerFrame; + } + + inline int FirstOffsetExtra() const { + return codecType == PSP_MODE_AT_3_PLUS ? 368 : 69; + } + + // Includes the extra offset. See firstSampleOffset comment above. + int FirstSampleOffsetFull() const { + return FirstOffsetExtra() + firstSampleOffset; + } + + // Output frame size, different between the two supported codecs. + u32 SamplesPerFrame() const { + return codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES; + } + + void UpdateBitrate() { + bitrate = (bytesPerFrame * 352800) / 1000; + if (codecType == PSP_MODE_AT_3_PLUS) + bitrate = ((bitrate >> 11) + 8) & 0xFFFFFFF0; + else + bitrate = (bitrate + 511) >> 10; + } + + // This appears to be buggy, should probably include FirstOffsetExtra? + // Actually the units don't even make sense here. + u32 DecodePosBySample(int sample) const { + return (u32)(firstSampleOffset + sample / (int)SamplesPerFrame() * bytesPerFrame); + } + + // This appears to be buggy, should probably include FirstOffsetExtra? + u32 FileOffsetBySample(int sample) const { + int offsetSample = sample + firstSampleOffset; + int frameOffset = offsetSample / (int)SamplesPerFrame(); + return (u32)(dataByteOffset + bytesPerFrame + frameOffset * bytesPerFrame); + } + + void AnalyzeReset() { + endSample = -1; + loopinfo.clear(); + loopStartSample = -1; + loopEndSample = -1; + channels = 2; + // TODO: Could probably reset more. + } + + void DebugLog(); +}; + +int AnalyzeAA3Track(u32 addr, u32 size, u32 filesize, Track *track); +int AnalyzeAtracTrack(u32 addr, u32 size, Track *track); + +class AtracBase { +public: + virtual ~AtracBase() {} + + virtual void DoState(PointerWrap &p) = 0; + + const Track &GetTrack() const { + return track_; + } + // This should be rare. + Track &GetTrackMut() { + return track_; + } + + int GetOutputChannels() const { + return outputChannels_; + } + void SetOutputChannels(int channels) { + // Only used for sceSas audio. To be refactored away in the future. + outputChannels_ = channels; + } + + int atracID_ = -1; + + PSPPointer context_{}; + + AtracStatus BufferState() const { + return bufferState_; + } + + int LoopNum() const { + return loopNum_; + } + u32 CodecType() const { + return track_.codecType; + } + AudioDecoder *Decoder() const { + return decoder_; + } + + void CreateDecoder(); + + virtual int CurrentSample() const = 0; + virtual int RemainingFrames() const = 0; + virtual u32 SecondBufferSize() const = 0; + + virtual int Analyze(u32 addr, u32 size) = 0; + virtual int AnalyzeAA3(u32 addr, u32 size, u32 filesize) = 0; + + void UpdateContextFromPSPMem(); + virtual void WriteContextToPSPMem() = 0; + + virtual void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) = 0; + virtual int AddStreamData(u32 bytesToAdd) = 0; + virtual u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) = 0; + virtual void SetLoopNum(int loopNum); + virtual u32 ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) = 0; + virtual void GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) = 0; + virtual int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) = 0; + + virtual int GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize); + virtual u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) = 0; + virtual u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) = 0; + virtual u32 GetNextSamples() = 0; + virtual void InitLowLevel(u32 paramsAddr, bool jointStereo) = 0; + +protected: + Track track_{}; + u16 outputChannels_ = 2; + int loopNum_ = 0; + + // TODO: Save the internal state of this, now technically possible. + AudioDecoder *decoder_ = nullptr; + AtracStatus bufferState_ = ATRAC_STATUS_NO_DATA; +}; + +class Atrac : public AtracBase { +public: + ~Atrac() { + ResetData(); + } + + uint32_t CurBufferAddress(int adjust = 0) const { + u32 off = track_.FileOffsetBySample(currentSample_ + adjust); + if (off < first_.size && ignoreDataBuf_) { + return first_.addr + off; + } + // If it's in dataBug, it's not in PSP memory. + return 0; + } + + u8 *BufferStart(); + void DoState(PointerWrap &p) override; + void WriteContextToPSPMem() override; + + int Analyze(u32 addr, u32 size) override; + int AnalyzeAA3(u32 addr, u32 size, u32 filesize) override; + + int CurrentSample() const override { + return currentSample_; + } + int RemainingFrames() const override; + u32 SecondBufferSize() const override { + return second_.size; + } + + void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; + int AddStreamData(u32 bytesToAdd) override; + u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) override; + u32 ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) override; + void GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) override; + int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) override; + u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) override; + u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) override; + u32 GetNextSamples() override; + void InitLowLevel(u32 paramsAddr, bool jointStereo) override; + +protected: + void AnalyzeReset(); + +private: + void UpdateBufferState(); + void ResetData(); + void SeekToSample(int sample); + void ForceSeekToSample(int sample); + u32 StreamBufferEnd() const { + // The buffer is always aligned to a frame in size, not counting an optional header. + // The header will only initially exist after the data is first set. + u32 framesAfterHeader = (bufferMaxSize_ - bufferHeaderSize_) / track_.bytesPerFrame; + return framesAfterHeader * track_.bytesPerFrame + bufferHeaderSize_; + } + void ConsumeFrame(); + void CalculateStreamInfo(u32 *readOffset); + + InputBuffer first_{}; + InputBuffer second_{}; // only addr, size, fileoffset are used (incomplete) + + u8 *dataBuf_ = nullptr; + // Indicates that the dataBuf_ array should not be used. + bool ignoreDataBuf_ = false; + + int currentSample_ = 0; + u32 decodePos_ = 0; + u32 bufferMaxSize_ = 0; + + // Used to track streaming. + u32 bufferPos_ = 0; + u32 bufferValidBytes_ = 0; + u32 bufferHeaderSize_ = 0; +}; diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp new file mode 100644 index 0000000000..5ecbf5b7c0 --- /dev/null +++ b/Core/HLE/AtracCtx2.cpp @@ -0,0 +1,166 @@ +#include "Common/Log.h" +#include "Core/MemMapHelpers.h" +#include "Core/HLE/HLE.h" +#include "Core/HLE/FunctionWrappers.h" +#include "Core/HLE/AtracCtx2.h" +#include "Core/HW/Atrac3Standalone.h" + +// Convenient command line: +// Windows\x64\debug\PPSSPPHeadless.exe --root pspautotests/tests/../ --compare --timeout=5 --new-atrac --graphics=software pspautotests/tests/audio/atrac/decode.prx + +// See the big comment in sceAtrac.cpp for an overview of the different modes of operation. +// +// Test cases +// +// Halfway buffer +// +// * None found yet +// +// All-data-loaded +// +// * MotoGP (menu music with specified loop). Simple repeated calls to sceAtracDecodeData +// * Archer MacLean's Mercury (in-game, not menu) +// * Crisis Core +// +// Streaming +// +// - Good ones (early) +// * Everybody's Golf 2 (0x2000 buffer size, loop from end) +// * Burnout Legends (no loop, 0x1800 buffer size) +// * Suicide Barbie +// - Others +// * Bleach +// * God of War: Chains of Olympus +// * Ape Academy 2 (bufsize 8192) +// * Half Minute Hero (bufsize 65536) +// * Flatout (tricky! needs investigation) + +void Atrac2::DoState(PointerWrap &p) { + _assert_msg_(false, "Savestates not yet support with new Atrac implementation.\n\nTurn it off in Developer settings.\n\n"); +} + +void Atrac2::WriteContextToPSPMem() { + if (!context_.IsValid()) { + return; + } + // context points into PSP memory. + SceAtracContext *context = context_; + context->info.buffer = 0; // bufferAddr_; // first_.addr; + context->info.bufferByte = 0; // bufferMaxSize_; + context->info.secondBuffer = 0; // TODO + context->info.secondBufferByte = 0; // TODO + context->info.codec = track_.codecType; + context->info.loopNum = loopNum_; + context->info.loopStart = track_.loopStartSample > 0 ? track_.loopStartSample : 0; + context->info.loopEnd = track_.loopEndSample > 0 ? track_.loopEndSample : 0; + + // Note that we read in the state when loading the atrac object, so it's safe + // to update it back here all the time. Some games, like Sol Trigger, change it. + // TODO: Should we just keep this in PSP ram then, or something? + context->info.state = bufferState_; + if (track_.firstSampleOffset != 0) { + context->info.samplesPerChan = track_.FirstSampleOffsetFull(); + } else { + context->info.samplesPerChan = (track_.codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + } + context->info.sampleSize = track_.bytesPerFrame; + context->info.numChan = track_.channels; + context->info.dataOff = track_.dataByteOffset; + context->info.endSample = track_.endSample + track_.FirstSampleOffsetFull(); + context->info.dataEnd = track_.fileSize; + context->info.curOff = 0; // first_.fileoffset; + context->info.decodePos = track_.DecodePosBySample(currentSample_); + context->info.streamDataByte = 0; // first_.size - track_.dataOff; + + u8 *buf = (u8 *)context; + *(u32_le *)(buf + 0xfc) = atracID_; + + NotifyMemInfo(MemBlockFlags::WRITE, context_.ptr, sizeof(SceAtracContext), "AtracContext"); +} + +int Atrac2::Analyze(u32 addr, u32 size) { + int retval = AnalyzeAtracTrack(addr, size, &track_); + if (retval < 0) { + return retval; + } + return 0; +} +int Atrac2::AnalyzeAA3(u32 addr, u32 size, u32 filesize) { + int retval = AnalyzeAA3Track(addr, size, filesize, &track_); + if (retval < 0) { + return retval; + } + + return 0; +} + +int Atrac2::RemainingFrames() const { + return 0; +} + +u32 Atrac2::SecondBufferSize() const { + return 0; +} + +void Atrac2::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) { + +} + +int Atrac2::AddStreamData(u32 bytesToAdd) { + return 0; +} + +u32 Atrac2::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) { + return 0; +} + +u32 Atrac2::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) { + return 0; +} + +void Atrac2::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) { + +} + +int Atrac2::SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) { + if (readSize == bufferSize) { + bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; + } else { + bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER; + } + return hleLogSuccessI(Log::ME, successCode); +} + +u32 Atrac2::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) { + return 0; +} + +u32 Atrac2::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) { + + return 0; +} + +u32 Atrac2::GetNextSamples() { + return 0; +} + +void Atrac2::InitLowLevel(u32 paramsAddr, bool jointStereo) { + track_.AnalyzeReset(); + track_.channels = Memory::Read_U32(paramsAddr); + outputChannels_ = Memory::Read_U32(paramsAddr + 4); + track_.bytesPerFrame = Memory::Read_U32(paramsAddr + 8); + if (track_.codecType == PSP_MODE_AT_3) { + track_.bitrate = (track_.bytesPerFrame * 352800) / 1000; + track_.bitrate = (track_.bitrate + 511) >> 10; + track_.jointStereo = false; + } else if (track_.codecType == PSP_MODE_AT_3_PLUS) { + track_.bitrate = (track_.bytesPerFrame * 352800) / 1000; + track_.bitrate = ((track_.bitrate >> 11) + 8) & 0xFFFFFFF0; + track_.jointStereo = false; + } + track_.dataByteOffset = 0; + bufferState_ = ATRAC_STATUS_LOW_LEVEL; + currentSample_ = 0; + CreateDecoder(); + WriteContextToPSPMem(); +} diff --git a/Core/HLE/AtracCtx2.h b/Core/HLE/AtracCtx2.h new file mode 100644 index 0000000000..aeebec399f --- /dev/null +++ b/Core/HLE/AtracCtx2.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "Core/HLE/AtracCtx.h" + + +class Atrac2 : public AtracBase { +public: + void DoState(PointerWrap &p) override; + void WriteContextToPSPMem() override; + + int Analyze(u32 addr, u32 size) override; + int AnalyzeAA3(u32 addr, u32 size, u32 filesize) override; + + int CurrentSample() const override { return currentSample_; } + int RemainingFrames() const override; + + void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; + int AddStreamData(u32 bytesToAdd) override; + u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) override; + u32 ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) override; + void GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) override; + int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) override; + u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) override; + u32 SecondBufferSize() const override; + + u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) override; + u32 GetNextSamples() override; + void InitLowLevel(u32 paramsAddr, bool jointStereo) override; + +private: + int currentSample_ = 0; +}; diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 5fd835d1be..b771503a21 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -111,7 +111,7 @@ void hleDelayResultFinish(u64 userdata, int cycleslate) __KernelReSchedule("woke from hle delay"); } else - WARN_LOG(HLE, "Someone else woke up HLE-blocked thread %d?", threadID); + WARN_LOG(Log::HLE, "Someone else woke up HLE-blocked thread %d?", threadID); } void HLEInit() { @@ -239,13 +239,13 @@ u32 GetSyscallOp(const char *moduleName, u32 nib) { if (funcindex != -1) { return (0x0000000c | (modindex<<18) | (funcindex<<6)); } else { - INFO_LOG(HLE, "Syscall (%s, %08x) unknown", moduleName, nib); + INFO_LOG(Log::HLE, "Syscall (%s, %08x) unknown", moduleName, nib); return (0x0003FFCC | (modindex<<18)); // invalid syscall } } else { - ERROR_LOG(HLE, "Unknown module %s!", moduleName); + ERROR_LOG(Log::HLE, "Unknown module %s!", moduleName); return (0x03FFFFCC); // invalid syscall } } @@ -275,7 +275,7 @@ bool WriteSyscall(const char *moduleName, u32 nib, u32 address) { if (nib == 0) { - WARN_LOG_REPORT(HLE, "Wrote patched out nid=0 syscall (%s)", moduleName); + WARN_LOG_REPORT(Log::HLE, "Wrote patched out nid=0 syscall (%s)", moduleName); Memory::Write_U32(MIPS_MAKE_JR_RA(), address); //patched out? Memory::Write_U32(MIPS_MAKE_NOP(), address+4); //patched out? return true; @@ -289,7 +289,7 @@ bool WriteSyscall(const char *moduleName, u32 nib, u32 address) } else { - ERROR_LOG_REPORT(HLE, "Unable to write unknown syscall: %s/%08x", moduleName, nib); + ERROR_LOG_REPORT(Log::HLE, "Unable to write unknown syscall: %s/%08x", moduleName, nib); return false; } } @@ -367,11 +367,11 @@ bool hleExecuteDebugBreak(const HLEFunction &func) u32 hleDelayResult(u32 result, const char *reason, int usec) { if (!__KernelIsDispatchEnabled()) { - WARN_LOG(HLE, "%s: Dispatch disabled, not delaying HLE result (right thing to do?)", latestSyscall ? latestSyscall->name : "?"); + WARN_LOG(Log::HLE, "%s: Dispatch disabled, not delaying HLE result (right thing to do?)", latestSyscall ? latestSyscall->name : "?"); } else { SceUID thread = __KernelGetCurThread(); if (KernelIsThreadWaiting(thread)) - ERROR_LOG(HLE, "%s: Delaying a thread that's already waiting", latestSyscall ? latestSyscall->name : "?"); + ERROR_LOG(Log::HLE, "%s: Delaying a thread that's already waiting", latestSyscall ? latestSyscall->name : "?"); CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, thread); __KernelWaitCurThread(WAITTYPE_HLEDELAY, 1, result, 0, false, reason); } @@ -380,11 +380,11 @@ u32 hleDelayResult(u32 result, const char *reason, int usec) { u64 hleDelayResult(u64 result, const char *reason, int usec) { if (!__KernelIsDispatchEnabled()) { - WARN_LOG(HLE, "%s: Dispatch disabled, not delaying HLE result (right thing to do?)", latestSyscall ? latestSyscall->name : "?"); + WARN_LOG(Log::HLE, "%s: Dispatch disabled, not delaying HLE result (right thing to do?)", latestSyscall ? latestSyscall->name : "?"); } else { SceUID thread = __KernelGetCurThread(); if (KernelIsThreadWaiting(thread)) - ERROR_LOG(HLE, "%s: Delaying a thread that's already waiting", latestSyscall ? latestSyscall->name : "?"); + ERROR_LOG(Log::HLE, "%s: Delaying a thread that's already waiting", latestSyscall ? latestSyscall->name : "?"); u64 param = (result & 0xFFFFFFFF00000000) | thread; CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, param); __KernelWaitCurThread(WAITTYPE_HLEDELAY, 1, (u32)result, 0, false, reason); @@ -418,7 +418,7 @@ void hleEnqueueCall(u32 func, int argc, const u32 *argv, PSPAction *afterAction) void hleFlushCalls() { u32 &sp = currentMIPS->r[MIPS_REG_SP]; PSPPointer stackData; - VERBOSE_LOG(HLE, "Flushing %d HLE mips calls from %s, sp=%08x", (int)enqueuedMipsCalls.size(), latestSyscall ? latestSyscall->name : "?", sp); + VERBOSE_LOG(Log::HLE, "Flushing %d HLE mips calls from %s, sp=%08x", (int)enqueuedMipsCalls.size(), latestSyscall ? latestSyscall->name : "?", sp); // First, we'll add a marker for the final return. sp -= sizeof(HLEMipsCallStack); @@ -459,7 +459,7 @@ void hleFlushCalls() { } enqueuedMipsCalls.clear(); - DEBUG_LOG(HLE, "Executing HLE mips call at %08x, sp=%08x", currentMIPS->pc, sp); + DEBUG_LOG(Log::HLE, "Executing HLE mips call at %08x, sp=%08x", currentMIPS->pc, sp); } void HLEReturnFromMipsCall() { @@ -470,14 +470,14 @@ void HLEReturnFromMipsCall() { stackData.ptr = sp; if ((stackData->nextOff & 0x0000000F) != 0 || !Memory::IsValidAddress(sp + stackData->nextOff)) { - ERROR_LOG(HLE, "Corrupt stack on HLE mips call return: %08x", stackData->nextOff); + ERROR_LOG(Log::HLE, "Corrupt stack on HLE mips call return: %08x", stackData->nextOff); Core_UpdateState(CORE_RUNTIME_ERROR); return; } if (stackData->actionIndex != 0xFFFFFFFF && stackData->actionIndex < (u32)mipsCallActions.size()) { PSPAction *&action = mipsCallActions[stackData->actionIndex]; - VERBOSE_LOG(HLE, "Executing action for HLE mips call at %08x, sp=%08x", stackData->func, sp); + VERBOSE_LOG(Log::HLE, "Executing action for HLE mips call at %08x, sp=%08x", stackData->func, sp); // Search for the saved v0/v1 values, to preserve the PSPAction API... PSPPointer finalMarker = stackData; @@ -486,7 +486,7 @@ void HLEReturnFromMipsCall() { } if (finalMarker->nextOff != 0xFFFFFFFF) { - ERROR_LOG(HLE, "Corrupt stack on HLE mips call return action: %08x", finalMarker->nextOff); + ERROR_LOG(Log::HLE, "Corrupt stack on HLE mips call return action: %08x", finalMarker->nextOff); Core_UpdateState(CORE_RUNTIME_ERROR); return; } @@ -523,7 +523,7 @@ void HLEReturnFromMipsCall() { mipsCallActions.clear(); } - VERBOSE_LOG(HLE, "Finished HLE mips calls, v0=%08x, sp=%08x", currentMIPS->r[MIPS_REG_V0], sp); + VERBOSE_LOG(Log::HLE, "Finished HLE mips calls, v0=%08x, sp=%08x", currentMIPS->r[MIPS_REG_V0], sp); return; } @@ -534,7 +534,7 @@ void HLEReturnFromMipsCall() { for (int i = 0; i < (int)stackData->argc; i++) { currentMIPS->r[MIPS_REG_A0 + i] = Memory::Read_U32(sp + sizeof(HLEMipsCallStack) + i * sizeof(u32)); } - DEBUG_LOG(HLE, "Executing next HLE mips call at %08x, sp=%08x", currentMIPS->pc, sp); + DEBUG_LOG(Log::HLE, "Executing next HLE mips call at %08x, sp=%08x", currentMIPS->pc, sp); } const static u32 deadbeefRegs[12] = {0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF}; @@ -639,9 +639,9 @@ inline void CallSyscallWithFlags(const HLEFunction *info) } if ((flags & HLE_NOT_DISPATCH_SUSPENDED) && !__KernelIsDispatchEnabled()) { - RETURN(hleLogDebug(HLE, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch suspended")); + RETURN(hleLogDebug(Log::HLE, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch suspended")); } else if ((flags & HLE_NOT_IN_INTERRUPT) && __IsInInterrupt()) { - RETURN(hleLogDebug(HLE, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt")); + RETURN(hleLogDebug(Log::HLE, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt")); } else { info->func(); } @@ -670,15 +670,15 @@ const HLEFunction *GetSyscallFuncPointer(MIPSOpcode op) int funcnum = callno & 0xFFF; int modulenum = (callno & 0xFF000) >> 12; if (funcnum == 0xfff) { - ERROR_LOG(HLE, "Unknown syscall: Module: %s (module: %d func: %d)", modulenum > (int)moduleDB.size() ? "(unknown)" : moduleDB[modulenum].name, modulenum, funcnum); + ERROR_LOG(Log::HLE, "Unknown syscall: Module: %s (module: %d func: %d)", modulenum > (int)moduleDB.size() ? "(unknown)" : moduleDB[modulenum].name, modulenum, funcnum); return NULL; } if (modulenum >= (int)moduleDB.size()) { - ERROR_LOG(HLE, "Syscall had bad module number %d - probably executing garbage", modulenum); + ERROR_LOG(Log::HLE, "Syscall had bad module number %d - probably executing garbage", modulenum); return NULL; } if (funcnum >= moduleDB[modulenum].numFunctions) { - ERROR_LOG(HLE, "Syscall had bad function number %d in module %d - probably executing garbage", funcnum, modulenum); + ERROR_LOG(Log::HLE, "Syscall had bad function number %d in module %d - probably executing garbage", funcnum, modulenum); return NULL; } return &moduleDB[modulenum].funcTable[funcnum]; @@ -691,7 +691,7 @@ void *GetQuickSyscallFunc(MIPSOpcode op) { const HLEFunction *info = GetSyscallFuncPointer(op); if (!info || !info->func) return nullptr; - DEBUG_LOG(HLE, "Compiling syscall to %s", info->name); + DEBUG_LOG(Log::HLE, "Compiling syscall to %s", info->name); // TODO: Do this with a flag? if (op == idleOp) @@ -735,7 +735,7 @@ void CallSyscall(MIPSOpcode op) } else { RETURN(SCE_KERNEL_ERROR_LIBRARY_NOT_YET_LINKED); - ERROR_LOG_REPORT(HLE, "Unimplemented HLE function %s", info->name ? info->name : "(\?\?\?)"); + ERROR_LOG_REPORT(Log::HLE, "Unimplemented HLE function %s", info->name ? info->name : "(\?\?\?)"); } if (coreCollectDebugStats) { @@ -853,7 +853,7 @@ size_t hleFormatLogArgs(char *message, size_t sz, const char *argmask) { return used; } -void hleDoLogInternal(LogType t, LogLevel level, u64 res, const char *file, int line, const char *reportTag, char retmask, const char *reason, const char *formatted_reason) { +void hleDoLogInternal(Log t, LogLevel level, u64 res, const char *file, int line, const char *reportTag, char retmask, const char *reason, const char *formatted_reason) { char formatted_args[4096]; const char *funcName = "?"; u32 funcFlags = 0; diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index b11efca78e..ba96ef4570 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -155,10 +155,10 @@ const HLEFunction *GetSyscallFuncPointer(MIPSOpcode op); // For jit, takes arg: const HLEFunction * void *GetQuickSyscallFunc(MIPSOpcode op); -void hleDoLogInternal(LogType t, LogLevel level, u64 res, const char *file, int line, const char *reportTag, char retmask, const char *reason, const char *formatted_reason); +void hleDoLogInternal(Log t, LogLevel level, u64 res, const char *file, int line, const char *reportTag, char retmask, const char *reason, const char *formatted_reason); template -T hleDoLog(LogType t, LogLevel level, T res, const char *file, int line, const char *reportTag, char retmask, const char *reason, ...) { +T hleDoLog(Log t, LogLevel level, T res, const char *file, int line, const char *reportTag, char retmask, const char *reason, ...) { if ((int)level > MAX_LOGLEVEL || !GenericLogEnabled(level, t)) { return res; } @@ -186,7 +186,7 @@ T hleDoLog(LogType t, LogLevel level, T res, const char *file, int line, const c } template -T hleDoLog(LogType t, LogLevel level, T res, const char *file, int line, const char *reportTag, char retmask) { +T hleDoLog(Log t, LogLevel level, T res, const char *file, int line, const char *reportTag, char retmask) { if (((int)level > MAX_LOGLEVEL || !GenericLogEnabled(level, t)) && !reportTag) { return res; } @@ -216,7 +216,7 @@ T hleDoLog(LogType t, LogLevel level, T res, const char *file, int line, const c #define HLE_LOG_LVERBOSE LVERBOSE #endif -#define hleLogHelper(t, level, res, retmask, ...) hleDoLog(LogType::t, LogLevel::level, res, __FILE__, __LINE__, nullptr, retmask, ##__VA_ARGS__) +#define hleLogHelper(t, level, res, retmask, ...) hleDoLog(t, LogLevel::level, res, __FILE__, __LINE__, nullptr, retmask, ##__VA_ARGS__) #define hleLogError(t, res, ...) hleLogHelper(t, LERROR, res, 'x', ##__VA_ARGS__) #define hleLogWarning(t, res, ...) hleLogHelper(t, LWARNING, res, 'x', ##__VA_ARGS__) #define hleLogDebug(t, res, ...) hleLogHelper(t, HLE_LOG_LDEBUG, res, 'x', ##__VA_ARGS__) @@ -228,7 +228,6 @@ T hleDoLog(LogType t, LogLevel level, T res, const char *file, int line, const c #define hleLogSuccessVerboseX(t, res, ...) hleLogHelper(t, HLE_LOG_LVERBOSE, res, 'x', ##__VA_ARGS__) #define hleLogSuccessVerboseI(t, res, ...) hleLogHelper(t, HLE_LOG_LVERBOSE, res, 'i', ##__VA_ARGS__) -#define hleReportError(t, res, ...) hleDoLog(LogType::t, LogLevel::LERROR, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__) -#define hleReportWarning(t, res, ...) hleDoLog(LogType::t, LogLevel::LWARNING, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__) -#define hleReportDebug(t, res, ...) hleDoLog(LogType::t, LogLevel::HLE_LOG_LDEBUG, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__) -#define hleReportVerbose(t, res, ...) hleDoLog(LogType::t, LogLevel::HLE_LOG_LVERBOSE, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__) +#define hleReportError(t, res, ...) hleDoLog(t, LogLevel::LERROR, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__) +#define hleReportWarning(t, res, ...) hleDoLog(t, LogLevel::LWARNING, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__) +#define hleReportDebug(t, res, ...) hleDoLog(t, LogLevel::HLE_LOG_LDEBUG, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__) diff --git a/Core/HLE/HLEHelperThread.cpp b/Core/HLE/HLEHelperThread.cpp index 60f7efb759..f37868c17f 100644 --- a/Core/HLE/HLEHelperThread.cpp +++ b/Core/HLE/HLEHelperThread.cpp @@ -97,7 +97,7 @@ void HLEHelperThread::ChangePriority(u32 prio) { void HLEHelperThread::Resume(WaitType waitType, SceUID uid, int result) { bool res = HLEKernel::ResumeFromWait(id_, waitType, uid, result); if (!res) { - ERROR_LOG(HLE, "Failed to wake helper thread from wait"); + ERROR_LOG(Log::HLE, "Failed to wake helper thread from wait"); } } diff --git a/Core/HLE/KUBridge.cpp b/Core/HLE/KUBridge.cpp index dd643c5896..763efcf3a3 100644 --- a/Core/HLE/KUBridge.cpp +++ b/Core/HLE/KUBridge.cpp @@ -26,13 +26,13 @@ #include "Core/Config.h" static int kuKernelLoadModule(const char *path, uint32_t flags, uint32_t lmOptionAddr) { - INFO_LOG(SCEKERNEL, "kuKernelLoadModule - forwarding to sceKernelLoadModule"); + INFO_LOG(Log::sceKernel, "kuKernelLoadModule - forwarding to sceKernelLoadModule"); // Simply forward the call, like JPSCP does. return sceKernelLoadModule(path, flags, lmOptionAddr); } static int kuKernelGetModel() { - INFO_LOG(SCEKERNEL, "kuKernelGetModel()"); + INFO_LOG(Log::sceKernel, "kuKernelGetModel()"); return g_Config.iPSPModel; } diff --git a/Core/HLE/Plugins.cpp b/Core/HLE/Plugins.cpp index 91e29fba04..acc57d48fa 100644 --- a/Core/HLE/Plugins.cpp +++ b/Core/HLE/Plugins.cpp @@ -41,18 +41,6 @@ std::map PluginDataKeys; static bool anyEnabled = false; static std::vector prxPlugins; -enum class PluginType { - INVALID = 0, - PRX, -}; - -struct PluginInfo { - PluginType type; - std::string filename; - int version; - uint32_t memory; -}; - static PluginInfo ReadPluginIni(const std::string &subdir, IniFile &ini) { PluginInfo info; @@ -66,30 +54,35 @@ static PluginInfo ReadPluginIni(const std::string &subdir, IniFile &ini) { } if (options->Get("filename", &value, "")) { + info.name = value; info.filename = "ms0:/PSP/PLUGINS/" + subdir + "/" + value; } else { info.type = PluginType::INVALID; } + if (options->Get("name", &value, "")) { + info.name = value; + } + options->Get("version", &info.version, 0); options->Get("memory", &info.memory, 0); if (info.memory > 93) { - ERROR_LOG(SYSTEM, "Plugin memory too high, using 93 MB"); + ERROR_LOG(Log::System, "Plugin memory too high, using 93 MB"); info.memory = 93; } if (info.version == 0) { - ERROR_LOG(SYSTEM, "Plugin without version ignored: %s", subdir.c_str()); + ERROR_LOG(Log::System, "Plugin without version ignored: %s", subdir.c_str()); info.type = PluginType::INVALID; info.memory = 0; } else if (info.type == PluginType::INVALID && !info.filename.empty()) { - ERROR_LOG(SYSTEM, "Plugin without valid type: %s", subdir.c_str()); + ERROR_LOG(Log::System, "Plugin without valid type: %s", subdir.c_str()); } return info; } -static std::vector FindPlugins(const std::string &gameID, const std::string &lang) { +std::vector FindPlugins(const std::string &gameID, const std::string &lang) { std::vector pluginDirs; GetFilesInDir(GetSysDirectory(DIRECTORY_PLUGINS), &pluginDirs); @@ -101,7 +94,7 @@ static std::vector FindPlugins(const std::string &gameID, const std: IniFile ini; if (!ini.Load(subdirFullName / "plugin.ini")) { - ERROR_LOG(SYSTEM, "Failed to load plugin ini: %s/plugin.ini", subdirFullName.c_str()); + ERROR_LOG(Log::System, "Failed to load plugin ini: %s/plugin.ini", subdirFullName.c_str()); continue; } @@ -110,30 +103,31 @@ static std::vector FindPlugins(const std::string &gameID, const std: std::string gameIni; // TODO: Should just use getsection and fail the ini if not found, I guess. - Section *games = ini.GetOrCreateSection("games"); - - if (games->Get(gameID.c_str(), &gameIni, "")) { - if (!strcasecmp(gameIni.c_str(), "true")) { - matches.insert("plugin.ini"); - } else if (!strcasecmp(gameIni.c_str(), "false")){ - continue; - } else if (!gameIni.empty()) { - matches.insert(gameIni); + const Section *games = ini.GetSection("games"); + if (games) { + if (games->Get(gameID.c_str(), &gameIni, "")) { + if (!strcasecmp(gameIni.c_str(), "true")) { + matches.insert("plugin.ini"); + } else if (!strcasecmp(gameIni.c_str(), "false")) { + continue; + } else if (!gameIni.empty()) { + matches.insert(gameIni); + } } - } - if (games->Get("ALL", &gameIni, "")) { - if (!strcasecmp(gameIni.c_str(), "true")) { - matches.insert("plugin.ini"); - } else if (!gameIni.empty()) { - matches.insert(gameIni); + if (games->Get("ALL", &gameIni, "")) { + if (!strcasecmp(gameIni.c_str(), "true")) { + matches.insert("plugin.ini"); + } else if (!gameIni.empty()) { + matches.insert(gameIni); + } } } std::set langMatches; for (const std::string &subini : matches) { if (!ini.Load(subdirFullName / subini)) { - ERROR_LOG(SYSTEM, "Failed to load plugin ini: %s/%s", subdirFullName.c_str(), subini.c_str()); + ERROR_LOG(Log::System, "Failed to load plugin ini: %s/%s", subdirFullName.c_str(), subini.c_str()); continue; } @@ -148,7 +142,7 @@ static std::vector FindPlugins(const std::string &gameID, const std: for (const std::string &subini : langMatches) { if (!ini.Load(subdirFullName / subini)) { - ERROR_LOG(SYSTEM, "Failed to load plugin ini: %s/%s", subdirFullName.c_str(), subini.c_str()); + ERROR_LOG(Log::System, "Failed to load plugin ini: %s/%s", subdirFullName.c_str(), subini.c_str()); continue; } @@ -184,23 +178,28 @@ bool Load() { auto sy = GetI18NCategory(I18NCat::SYSTEM); for (const std::string &filename : prxPlugins) { + if (!g_Config.bEnablePlugins) { + WARN_LOG(Log::System, "Plugins are disabled, ignoring enabled plugin %s", filename.c_str()); + continue; + } + std::string error_string = ""; SceUID module = KernelLoadModule(filename, &error_string); if (!error_string.empty() || module < 0) { - ERROR_LOG(SYSTEM, "Unable to load plugin %s (module %d): '%s'", filename.c_str(), module, error_string.c_str()); + ERROR_LOG(Log::System, "Unable to load plugin %s (module %d): '%s'", filename.c_str(), module, error_string.c_str()); continue; } int ret = KernelStartModule(module, 0, 0, 0, nullptr, nullptr); if (ret < 0) { - ERROR_LOG(SYSTEM, "Unable to start plugin %s: %08x", filename.c_str(), ret); + ERROR_LOG(Log::System, "Unable to start plugin %s: %08x", filename.c_str(), ret); } else { std::string shortName = Path(filename).GetFilename(); - g_OSD.Show(OSDType::MESSAGE_SUCCESS, ApplySafeSubstitutions(sy->T("Loaded plugin: %1"), shortName)); + g_OSD.Show(OSDType::MESSAGE_SUCCESS, ApplySafeSubstitutions(sy->T("Loaded plugin: %1"), shortName), 6.0f); started = true; } - INFO_LOG(SYSTEM, "Loaded plugin: %s", filename.c_str()); + INFO_LOG(Log::System, "Loaded plugin: %s", filename.c_str()); } std::lock_guard guard(g_inputMutex); diff --git a/Core/HLE/Plugins.h b/Core/HLE/Plugins.h index 3b5a2bd029..4c179fcf56 100644 --- a/Core/HLE/Plugins.h +++ b/Core/HLE/Plugins.h @@ -18,6 +18,7 @@ #pragma once #include +#include #include "Input/KeyCodes.h" class PointerWrap; @@ -34,6 +35,21 @@ void DoState(PointerWrap &p); bool HasEnabled(); +enum class PluginType { + INVALID = 0, + PRX, +}; + +struct PluginInfo { + PluginType type; + std::string name; + std::string filename; // PSP-space path. So we can't use a Path object. + int version; + uint32_t memory; +}; + +std::vector FindPlugins(const std::string &gameID, const std::string &lang); + void SetKey(int key, uint8_t value); uint8_t GetKey(int key); diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 1d25417750..c80c804c3e 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -1377,7 +1377,7 @@ static int Hook_starocean_clear_framebuf_after() { int y = (s16)Memory::Read_U16(y_address); int h = (s16)Memory::Read_U16(h_address); - DEBUG_LOG(HLE, "starocean_clear_framebuf() - %08x y=%d-%d", framebuf, y, h); + DEBUG_LOG(Log::HLE, "starocean_clear_framebuf() - %08x y=%d-%d", framebuf, y, h); // TODO: This is always clearing to 0, actually, which could be faster than an upload. gpu->PerformWriteColorFromMemory(framebuf + 512 * y * 4, 512 * h * 4); } @@ -1435,8 +1435,8 @@ static int Hook_soltrigger_render_ucschar() { } static int Hook_gow_fps_hack() { - if (PSP_CoreParameter().compat.flags().GoWFramerateHack60 || PSP_CoreParameter().compat.flags().GoWFramerateHack30) { - if (PSP_CoreParameter().compat.flags().GoWFramerateHack30) { + if (PSP_CoreParameter().compat.flags().GoWFramerateHack60 || PSP_CoreParameter().compat.flags().FramerateHack30) { + if (PSP_CoreParameter().compat.flags().FramerateHack30) { __DisplayWaitForVblanks("vblank start waited", 2); } else { __DisplayWaitForVblanks("vblank start waited", 1); @@ -1445,6 +1445,20 @@ static int Hook_gow_fps_hack() { return 0; } +static int Hook_blitz_fps_hack() { + if (PSP_CoreParameter().compat.flags().FramerateHack30) { + __DisplayWaitForVblanks("vblank start waited", 1); + } + return 0; +} + +static int Hook_brian_lara_fps_hack() { + if (PSP_CoreParameter().compat.flags().FramerateHack30) { + __DisplayWaitForVblanks("vblank start waited", 1); + } + return 0; +} + static int Hook_gow_vortex_hack() { if (PSP_CoreParameter().compat.flags().GoWFramerateHack60) { // from my tests both ==0x3F800000 and !=0x3F800000 takes around 1:40-1:50, that seems to match correct behaviour @@ -1584,6 +1598,8 @@ static const ReplacementTableEntry entries[] = { { "gow_fps_hack", &Hook_gow_fps_hack, 0, REPFLAG_HOOKEXIT , 0 }, { "gow_vortex_hack", &Hook_gow_vortex_hack, 0, REPFLAG_HOOKENTER, 0x60 }, { "ZZT3_select_hack", &Hook_ZZT3_select_hack, 0, REPFLAG_HOOKENTER, 0xC4 }, + { "blitz_fps_hack", &Hook_blitz_fps_hack, 0, REPFLAG_HOOKEXIT , 0 }, + { "brian_lara_fps_hack", &Hook_brian_lara_fps_hack, 0, REPFLAG_HOOKEXIT , 0 }, {} }; @@ -1639,13 +1655,13 @@ static bool WriteReplaceInstruction(u32 address, int index) { if (prevIndex == index) { return false; } - WARN_LOG(HLE, "Replacement func changed at %08x (%d -> %d)", address, prevIndex, index); + WARN_LOG(Log::HLE, "Replacement func changed at %08x (%d -> %d)", address, prevIndex, index); // Make sure we don't save the old replacement. prevInstr = replacedInstructions[address]; } if (MIPS_IS_RUNBLOCK(Memory::Read_U32(address))) { - WARN_LOG(HLE, "Replacing jitted func address %08x", address); + WARN_LOG(Log::HLE, "Replacing jitted func address %08x", address); } replacedInstructions[address] = prevInstr; Memory::Write_U32(MIPS_EMUHACK_CALL_REPLACEMENT | index, address); @@ -1656,7 +1672,7 @@ void WriteReplaceInstructions(u32 address, u64 hash, int size) { std::vector indexes = GetReplacementFuncIndexes(hash, size); for (int index : indexes) { bool didReplace = false; - auto entry = GetReplacementFunc(index); + const ReplacementTableEntry *entry = GetReplacementFunc(index); if (entry->flags & REPFLAG_HOOKEXIT) { // When hooking func exit, we search for jr ra, and replace those. for (u32 offset = 0; offset < (u32)size; offset += 4) { @@ -1678,7 +1694,7 @@ void WriteReplaceInstructions(u32 address, u64 hash, int size) { } if (didReplace) { - INFO_LOG(HLE, "Replaced %s at %08x with hash %016llx", entries[index].name, address, hash); + INFO_LOG(Log::HLE, "Replaced %s at %08x with hash %016llx", entries[index].name, address, hash); } } } @@ -1687,9 +1703,9 @@ void RestoreReplacedInstruction(u32 address) { const u32 curInstr = Memory::Read_U32(address); if (MIPS_IS_REPLACEMENT(curInstr)) { Memory::Write_U32(replacedInstructions[address], address); - NOTICE_LOG(HLE, "Restored replaced func at %08x", address); + NOTICE_LOG(Log::HLE, "Restored replaced func at %08x", address); } else { - NOTICE_LOG(HLE, "Replaced func changed at %08x", address); + NOTICE_LOG(Log::HLE, "Replaced func changed at %08x", address); } replacedInstructions.erase(address); } @@ -1711,7 +1727,7 @@ void RestoreReplacedInstructions(u32 startAddr, u32 endAddr) { ++restored; } } - INFO_LOG(HLE, "Restored %d replaced funcs between %08x-%08x", restored, startAddr, endAddr); + INFO_LOG(Log::HLE, "Restored %d replaced funcs between %08x-%08x", restored, startAddr, endAddr); replacedInstructions.erase(start, end); } @@ -1772,7 +1788,7 @@ bool CanReplaceJalTo(u32 dest, const ReplacementTableEntry **entry, u32 *funcSiz int index = op.encoding & MIPS_EMUHACK_VALUE_MASK; *entry = GetReplacementFunc(index); if (!*entry) { - ERROR_LOG(HLE, "ReplaceJalTo: Invalid replacement op %08x at %08x", op.encoding, dest); + ERROR_LOG(Log::HLE, "ReplaceJalTo: Invalid replacement op %08x at %08x", op.encoding, dest); return false; } diff --git a/Core/HLE/ThreadQueueList.h b/Core/HLE/ThreadQueueList.h index 72282e2a3f..2e5e76c2c8 100644 --- a/Core/HLE/ThreadQueueList.h +++ b/Core/HLE/ThreadQueueList.h @@ -187,7 +187,7 @@ struct ThreadQueueList { Do(p, numQueues); if (numQueues != NUM_QUEUES) { p.SetError(p.ERROR_FAILURE); - ERROR_LOG(SCEKERNEL, "Savestate loading error: invalid data"); + ERROR_LOG(Log::sceKernel, "Savestate loading error: invalid data"); return; } diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index ed4cec8da2..4ce1199672 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -163,7 +163,7 @@ void __AudioDoState(PointerWrap &p) { Do(p, chanCount); if (chanCount != ARRAY_SIZE(chans)) { - ERROR_LOG(SCEAUDIO, "Savestate failure: different number of audio channels."); + ERROR_LOG(Log::sceAudio, "Savestate failure: different number of audio channels."); p.SetError(p.ERROR_FAILURE); return; } @@ -292,7 +292,7 @@ inline void __AudioWakeThreads(AudioChannel &chan, int result, int step) { // If it's done (there will still be samples on queue) and actually still waiting, wake it up. u32 waitID = __KernelGetWaitID(waitInfo.threadID, WAITTYPE_AUDIOCHANNEL, error); if (waitInfo.numSamples <= 0 && waitID != 0) { - // DEBUG_LOG(SCEAUDIO, "Woke thread %i for some buffer filling", waitingThread); + // DEBUG_LOG(Log::sceAudio, "Woke thread %i for some buffer filling", waitingThread); u32 ret = result == 0 ? __KernelGetWaitValue(waitInfo.threadID, error) : SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; __KernelResumeThreadFromWait(waitInfo.threadID, ret); wokeThreads = true; @@ -315,9 +315,9 @@ void __AudioWakeThreads(AudioChannel &chan, int result) { void __AudioSetOutputFrequency(int freq) { if (freq != 44100) { - WARN_LOG_REPORT(SCEAUDIO, "Switching audio frequency to %i", freq); + WARN_LOG_REPORT(Log::sceAudio, "Switching audio frequency to %i", freq); } else { - DEBUG_LOG(SCEAUDIO, "Switching audio frequency to %i", freq); + DEBUG_LOG(Log::sceAudio, "Switching audio frequency to %i", freq); } mixFrequency = freq; } @@ -328,7 +328,7 @@ void __AudioSetSRCFrequency(int freq) { // Mix samples from the various audio channels into a single sample queue, managed by the backend implementation. void __AudioUpdate(bool resetRecording) { - // Audio throttle doesn't really work on the PSP since the mixing intervals are so closely tied + // AUDIO throttle doesn't really work on the PSP since the mixing intervals are so closely tied // to the CPU. Much better to throttle the frame rate on frame display and just throw away audio // if the buffer somehow gets full. bool firstChannel = true; @@ -348,7 +348,7 @@ void __AudioUpdate(bool resetRecording) { bool needsResample = i == PSP_AUDIO_CHANNEL_SRC && srcFrequency != 0 && srcFrequency != mixFrequency; size_t sz = needsResample ? (srcBufferSize * srcFrequency) / mixFrequency : srcBufferSize; if (sz > chanSampleQueues[i].size()) { - ERROR_LOG(SCEAUDIO, "Channel %i buffer underrun at %i of %i", i, (int)chanSampleQueues[i].size() / 2, (int)sz / 2); + ERROR_LOG(Log::sceAudio, "Channel %i buffer underrun at %i of %i", i, (int)chanSampleQueues[i].size() / 2, (int)sz / 2); } const s16 *buf1 = 0, *buf2 = 0; @@ -424,7 +424,7 @@ void __AudioUpdate(bool resetRecording) { __StopLogAudio(); std::string discID = g_paramSFO.GetDiscID(); Path audio_file_name = GetSysDirectory(DIRECTORY_AUDIO) / StringFromFormat("%s_%s.wav", discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); - INFO_LOG(COMMON, "Restarted audio recording to: %s", audio_file_name.c_str()); + INFO_LOG(Log::Common, "Restarted audio recording to: %s", audio_file_name.c_str()); if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); File::CreateEmptyFile(audio_file_name); @@ -435,7 +435,7 @@ void __AudioUpdate(bool resetRecording) { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); Path audio_file_name = GetSysDirectory(DIRECTORY_AUDIO) / StringFromFormat("%s_%s.wav", discID.c_str(), KernelTimeNowFormatted().c_str()); - INFO_LOG(COMMON,"Recording audio to: %s", audio_file_name.c_str()); + INFO_LOG(Log::Common,"Recording audio to: %s", audio_file_name.c_str()); // Create the path just in case it doesn't exist if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); @@ -462,9 +462,9 @@ void __StartLogAudio(const Path& filename) { m_logAudio = true; g_wave_writer.Start(filename, 44100); g_wave_writer.SetSkipSilence(false); - NOTICE_LOG(SCEAUDIO, "Starting Audio logging"); + NOTICE_LOG(Log::sceAudio, "Starting Audio logging"); } else { - WARN_LOG(SCEAUDIO, "Audio logging has already been started"); + WARN_LOG(Log::sceAudio, "Audio logging has already been started"); } } @@ -472,9 +472,9 @@ void __StopLogAudio() { if (m_logAudio) { m_logAudio = false; g_wave_writer.Stop(); - NOTICE_LOG(SCEAUDIO, "Stopping Audio logging"); + NOTICE_LOG(Log::sceAudio, "Stopping Audio logging"); } else { - WARN_LOG(SCEAUDIO, "Audio logging has already been stopped"); + WARN_LOG(Log::sceAudio, "Audio logging has already been stopped"); } } #endif diff --git a/Core/HLE/__sceAudio.h b/Core/HLE/__sceAudio.h index d757e1d8bd..cf1426d3b3 100644 --- a/Core/HLE/__sceAudio.h +++ b/Core/HLE/__sceAudio.h @@ -46,7 +46,7 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking); void __AudioWakeThreads(AudioChannel &chan, int result, int step); void __AudioWakeThreads(AudioChannel &chan, int result); -// Audio Dumping stuff +// AUDIO Dumping stuff void __StartLogAudio(const Path &filename); void __StopLogAudio(); diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 8e932d598f..28dfbb43d9 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -62,7 +62,17 @@ #include "Common/Serialize/SerializeFuncs.h" #include "Common/TimeUtil.h" + +#include "Core/HLE/sceKernelThread.h" +#include "Core/HLE/sceKernel.h" +#include "Core/HLE/sceKernelMutex.h" +#include "Core/HLE/sceUtility.h" + +#include "Core/MemMap.h" +#include "Core/HLE/HLE.h" +#include "Core/HLE/HLEHelperThread.h" #include "Core/Config.h" +#include "Core/CoreTiming.h" #include "Core/Core.h" #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceKernelThread.h" @@ -196,7 +206,7 @@ SceNetAdhocMatchingMemberInternal* addMember(SceNetAdhocMatchingContext * contex SceNetAdhocMatchingMemberInternal * peer = findPeer(context, mac); // Already existed if (peer != NULL) { - WARN_LOG(SCENET, "Member Peer Already Existed! Updating [%s]", mac2str(mac).c_str()); + WARN_LOG(Log::sceNet, "Member Peer Already Existed! Updating [%s]", mac2str(mac).c_str()); peer->state = 0; peer->sending = 0; peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); @@ -227,7 +237,7 @@ void addFriend(SceNetAdhocctlConnectPacketS2C * packet) { // Already existed if (peer != NULL) { u32 tmpip = packet->ip; - WARN_LOG(SCENET, "Friend Peer Already Existed! Updating [%s][%s][%s]", mac2str(&packet->mac).c_str(), ip2str(*(struct in_addr*)&tmpip).c_str(), packet->name.data); //inet_ntoa(*(in_addr*)&packet->ip) + WARN_LOG(Log::sceNet, "Friend Peer Already Existed! Updating [%s][%s][%s]", mac2str(&packet->mac).c_str(), ip2str(*(struct in_addr*)&tmpip).c_str(), packet->name.data); //inet_ntoa(*(in_addr*)&packet->ip) peer->nickname = packet->name; peer->mac_addr = packet->mac; peer->ip_addr = packet->ip; @@ -429,7 +439,11 @@ void deleteAllAdhocSockets() { if (fd > 0) { // Close Socket - shutdown(fd, SD_BOTH); + struct linger sl {}; + sl.l_onoff = 1; // non-zero value enables linger option in kernel + sl.l_linger = 0; // timeout interval in seconds + setsockopt(fd, SOL_SOCKET, SO_LINGER, (const char*)&sl, sizeof(sl)); + shutdown(fd, SD_RECEIVE); closesocket(fd); } // Free Memory @@ -485,7 +499,7 @@ void deleteFriendByIP(uint32_t ip) { */ u32 tmpip = peer->ip_addr; - INFO_LOG(SCENET, "Removing Friend Peer %s [%s]", mac2str(&peer->mac_addr).c_str(), ip2str(*(struct in_addr *)&tmpip).c_str()); //inet_ntoa(*(in_addr*)&peer->ip_addr) + INFO_LOG(Log::sceNet, "Removing Friend Peer %s [%s]", mac2str(&peer->mac_addr).c_str(), ip2str(*(struct in_addr *)&tmpip).c_str()); //inet_ntoa(*(in_addr*)&peer->ip_addr) // Free Memory //free(peer); @@ -592,7 +606,7 @@ void postAcceptCleanPeerList(SceNetAdhocMatchingContext * context) // Free Peer Lock peerlock.unlock(); - INFO_LOG(SCENET, "Removing Unneeded Peers (%i/%i)", delcount, peercount); + INFO_LOG(Log::sceNet, "Removing Unneeded Peers (%i/%i)", delcount, peercount); } /** @@ -621,7 +635,7 @@ void postAcceptAddSiblings(SceNetAdhocMatchingContext * context, int siblingcoun peer->state = PSP_ADHOC_MATCHING_PEER_CHILD; peer->sending = 0; peer->lastping = CoreTiming::GetGlobalTimeUsScaled(); - WARN_LOG(SCENET, "Updating Sibling Peer %s", mac2str(mac).c_str()); + WARN_LOG(Log::sceNet, "Updating Sibling Peer %s", mac2str(mac).c_str()); } else { // Allocate Memory @@ -649,7 +663,7 @@ void postAcceptAddSiblings(SceNetAdhocMatchingContext * context, int siblingcoun // Spawn Established Event. FIXME: ESTABLISHED event should only be triggered for Parent/P2P peer? //spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_ESTABLISHED, &sibling->mac, 0, NULL); - INFO_LOG(SCENET, "Accepting Sibling Peer %s", mac2str(&sibling->mac).c_str()); + INFO_LOG(Log::sceNet, "Accepting Sibling Peer %s", mac2str(&sibling->mac).c_str()); } } } @@ -780,7 +794,7 @@ void deletePeer(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberI // Beginning Item else context->peerlist = item->next; - INFO_LOG(SCENET, "Removing Member Peer %s", mac2str(&peer->mac).c_str()); + INFO_LOG(Log::sceNet, "Removing Member Peer %s", mac2str(&peer->mac).c_str()); } // Free Peer Memory @@ -1055,7 +1069,7 @@ void handleTimeout(SceNetAdhocMatchingContext * context) // FIXME: TIMEOUT event should only be triggered on Parent/P2P mode and for Parent/P2P peer? spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_TIMEOUT, &peer->mac, 0, NULL); - INFO_LOG(SCENET, "TimedOut Member Peer %s (%lld - %lld = %lld > %lld us)", mac2str(&peer->mac).c_str(), now, peer->lastping, (now - peer->lastping), context->timeout); + INFO_LOG(Log::sceNet, "TimedOut Member Peer %s (%lld - %lld = %lld > %lld us)", mac2str(&peer->mac).c_str(), now, peer->lastping, (now - peer->lastping), context->timeout); if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) sendDeathMessage(context, peer); @@ -1175,9 +1189,9 @@ void AfterMatchingMipsCall::run(MipsCall &call) { peerlock.unlock(); } u32 v0 = currentMIPS->r[MIPS_REG_V0]; - if (__IsInInterrupt()) ERROR_LOG(SCENET, "AfterMatchingMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", contextID, EventID); + if (__IsInInterrupt()) ERROR_LOG(Log::sceNet, "AfterMatchingMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", contextID, EventID); //SetMatchingInCallback(context, false); - DEBUG_LOG(SCENET, "AfterMatchingMipsCall::run [ID=%i][Event=%d][%s] [cbId: %u][retV0: %08x]", contextID, EventID, mac2str((SceNetEtherAddr*)Memory::GetPointer(bufAddr)).c_str(), call.cbId, v0); + DEBUG_LOG(Log::sceNet, "AfterMatchingMipsCall::run [ID=%i][Event=%d][%s] [cbId: %u][retV0: %08x]", contextID, EventID, mac2str((SceNetEtherAddr*)Memory::GetPointer(bufAddr)).c_str(), call.cbId, v0); if (Memory::IsValidAddress(bufAddr)) userMemory.Free(bufAddr); //call.setReturnValue(v0); } @@ -1225,10 +1239,10 @@ void AfterAdhocMipsCall::DoState(PointerWrap & p) { void AfterAdhocMipsCall::run(MipsCall& call) { u32 v0 = currentMIPS->r[MIPS_REG_V0]; - if (__IsInInterrupt()) ERROR_LOG(SCENET, "AfterAdhocMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", HandlerID, EventID); + if (__IsInInterrupt()) ERROR_LOG(Log::sceNet, "AfterAdhocMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", HandlerID, EventID); SetAdhocctlInCallback(false); isAdhocctlBusy = false; - DEBUG_LOG(SCENET, "AfterAdhocMipsCall::run [ID=%i][Event=%d] [cbId: %u][retV0: %08x]", HandlerID, EventID, call.cbId, v0); + DEBUG_LOG(Log::sceNet, "AfterAdhocMipsCall::run [ID=%i][Event=%d] [cbId: %u][retV0: %08x]", HandlerID, EventID, call.cbId, v0); //call.setReturnValue(v0); } @@ -1322,8 +1336,8 @@ void sendChat(const std::string &chatString) { strcpy(chat.message, message.c_str()); //Send Chat Messages if (IsSocketReady((int)metasocket, false, true) > 0) { - int chatResult = send((int)metasocket, (const char*)&chat, sizeof(chat), MSG_NOSIGNAL); - NOTICE_LOG(SCENET, "Send Chat %s to Adhoc Server", chat.message); + int chatResult = (int)send((int)metasocket, (const char*)&chat, sizeof(chat), MSG_NOSIGNAL); + NOTICE_LOG(Log::sceNet, "Send Chat %s to Adhoc Server", chat.message); std::string name = g_Config.sNickName; std::lock_guard guard(chatLogLock); @@ -1377,14 +1391,14 @@ int friendFinder(){ uint64_t now; // Log Startup - INFO_LOG(SCENET, "FriendFinder: Begin of Friend Finder Thread"); + INFO_LOG(Log::sceNet, "FriendFinder: Begin of Friend Finder Thread"); // Resolve and cache AdhocServer DNS addrinfo* resolved = nullptr; std::string err; g_adhocServerIP.in.sin_addr.s_addr = INADDR_NONE; if (g_Config.bEnableWlan && !net::DNSResolve(g_Config.proAdhocServer, "", &resolved, err)) { - ERROR_LOG(SCENET, "DNS Error Resolving %s\n", g_Config.proAdhocServer.c_str()); + ERROR_LOG(Log::sceNet, "DNS Error Resolving %s\n", g_Config.proAdhocServer.c_str()); g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("DNS Error Resolving ")) + g_Config.proAdhocServer); } if (resolved) { @@ -1410,7 +1424,7 @@ int friendFinder(){ if (g_Config.bEnableWlan) { if (initNetwork(&product_code) == 0) { networkInited = true; - INFO_LOG(SCENET, "FriendFinder: Network [RE]Initialized"); + INFO_LOG(Log::sceNet, "FriendFinder: Network [RE]Initialized"); // At this point we are most-likely not in a Group within the Adhoc Server, so we should probably reset AdhocctlState adhocctlState = ADHOCCTL_STATE_DISCONNECTED; netAdhocGameModeEntered = false; @@ -1437,11 +1451,11 @@ int friendFinder(){ // Send Ping to Server, may failed with socket error 10054/10053 if someone else with the same IP already connected to AdHoc Server (the server might need to be modified to differentiate MAC instead of IP) if (IsSocketReady((int)metasocket, false, true) > 0) { - int iResult = send((int)metasocket, (const char*)&opcode, 1, MSG_NOSIGNAL); + int iResult = (int)send((int)metasocket, (const char*)&opcode, 1, MSG_NOSIGNAL); int error = errno; // KHBBS seems to be getting error 10053 often if (iResult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "FriendFinder: Socket Error (%i) when sending OPCODE_PING", error); + ERROR_LOG(Log::sceNet, "FriendFinder: Socket Error (%i) when sending OPCODE_PING", error); if (error != EAGAIN && error != EWOULDBLOCK) { networkInited = false; shutdown((int)metasocket, SD_BOTH); @@ -1457,14 +1471,14 @@ int friendFinder(){ else { // Update Ping Time lastping = now; - VERBOSE_LOG(SCENET, "FriendFinder: Sending OPCODE_PING (%llu)", static_cast(now)); + VERBOSE_LOG(Log::sceNet, "FriendFinder: Sending OPCODE_PING (%llu)", static_cast(now)); } } } // Check for Incoming Data if (IsSocketReady((int)metasocket, true, false) > 0) { - int received = recv((int)metasocket, (char*)(rx + rxpos), sizeof(rx) - rxpos, MSG_NOSIGNAL); + int received = (int)recv((int)metasocket, (char*)(rx + rxpos), sizeof(rx) - rxpos, MSG_NOSIGNAL); // Free Network Lock //_freeNetworkLock(); @@ -1476,7 +1490,7 @@ int friendFinder(){ // Log Incoming Traffic //printf("Received %d Bytes of Data from Server\n", received); - INFO_LOG(SCENET, "Received %d Bytes of Data from Adhoc Server", received); + INFO_LOG(Log::sceNet, "Received %d Bytes of Data from Adhoc Server", received); } } @@ -1495,7 +1509,7 @@ int friendFinder(){ // Cast Packet SceNetAdhocctlConnectBSSIDPacketS2C* packet = (SceNetAdhocctlConnectBSSIDPacketS2C*)rx; - INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT_BSSID [%s]", mac2str(&packet->mac).c_str()); + INFO_LOG(Log::sceNet, "FriendFinder: Incoming OPCODE_CONNECT_BSSID [%s]", mac2str(&packet->mac).c_str()); // Update User BSSID parameter.bssid.mac_addr = packet->mac; // This packet seems to contains Adhoc Group Creator's BSSID (similar to AP's BSSID) so it shouldn't get mixed up with local MAC address @@ -1517,7 +1531,7 @@ int friendFinder(){ } } else - WARN_LOG(SCENET, "GameMode SelfMember [%s] Already Existed!", mac2str(&localMac).c_str()); + WARN_LOG(Log::sceNet, "GameMode SelfMember [%s] Already Existed!", mac2str(&localMac).c_str()); } else { //adhocctlState = ADHOCCTL_STATE_CONNECTED; @@ -1542,14 +1556,14 @@ int friendFinder(){ if (rxpos >= (int)sizeof(SceNetAdhocctlChatPacketS2C)) { // Cast Packet SceNetAdhocctlChatPacketS2C* packet = (SceNetAdhocctlChatPacketS2C*)rx; - INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CHAT"); + INFO_LOG(Log::sceNet, "FriendFinder: Incoming OPCODE_CHAT"); // Fix strings with null-terminated packet->name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; packet->base.message[ADHOCCTL_MESSAGE_LEN - 1] = 0; // Add Incoming Chat to HUD - NOTICE_LOG(SCENET, "Received chat message %s", packet->base.message); + NOTICE_LOG(Log::sceNet, "Received chat message %s", packet->base.message); std::string incoming = ""; std::string name = (char*)packet->name.data; incoming.append(name.substr(0, 8)); @@ -1581,7 +1595,7 @@ int friendFinder(){ // Log Incoming Peer u32_le ipaddr = packet->ip; - INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT [%s][%s][%s]", mac2str(&packet->mac).c_str(), ip2str(*(in_addr*)&ipaddr).c_str(), packet->name.data); + INFO_LOG(Log::sceNet, "FriendFinder: Incoming OPCODE_CONNECT [%s][%s][%s]", mac2str(&packet->mac).c_str(), ip2str(*(in_addr*)&ipaddr).c_str(), packet->name.data); // Add User addFriend(packet); @@ -1616,7 +1630,7 @@ int friendFinder(){ } } else - WARN_LOG(SCENET, "GameMode Member [%s] Already Existed!", mac2str(&packet->mac).c_str()); + WARN_LOG(Log::sceNet, "GameMode Member [%s] Already Existed!", mac2str(&packet->mac).c_str()); } // Update HUD User Count @@ -1652,10 +1666,10 @@ int friendFinder(){ // Cast Packet SceNetAdhocctlDisconnectPacketS2C* packet = (SceNetAdhocctlDisconnectPacketS2C*)rx; - DEBUG_LOG(SCENET, "FriendFinder: OPCODE_DISCONNECT"); + DEBUG_LOG(Log::sceNet, "FriendFinder: OPCODE_DISCONNECT"); // Log Incoming Peer Delete Request - INFO_LOG(SCENET, "FriendFinder: Incoming Peer Data Delete Request..."); + INFO_LOG(Log::sceNet, "FriendFinder: Incoming Peer Data Delete Request..."); if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) { auto peer = findFriendByIP(packet->ip); @@ -1691,10 +1705,10 @@ int friendFinder(){ // Cast Packet SceNetAdhocctlScanPacketS2C* packet = (SceNetAdhocctlScanPacketS2C*)rx; - DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN"); + DEBUG_LOG(Log::sceNet, "FriendFinder: OPCODE_SCAN"); // Log Incoming Network Information - INFO_LOG(SCENET, "Incoming Group Information..."); + INFO_LOG(Log::sceNet, "Incoming Group Information..."); // Multithreading Lock peerlock.lock(); @@ -1739,9 +1753,9 @@ int friendFinder(){ // Scan Complete Packet else if (rx[0] == OPCODE_SCAN_COMPLETE) { - DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN_COMPLETE"); + DEBUG_LOG(Log::sceNet, "FriendFinder: OPCODE_SCAN_COMPLETE"); // Log Scan Completion - INFO_LOG(SCENET, "FriendFinder: Incoming Scan complete response..."); + INFO_LOG(Log::sceNet, "FriendFinder: Incoming Scan complete response..."); // Reset current networks to prevent disbanded host to be listed again peerlock.lock(); @@ -1777,7 +1791,7 @@ int friendFinder(){ friendFinderRunning = false; // Log Shutdown - INFO_LOG(SCENET, "FriendFinder: End of Friend Finder Thread"); + INFO_LOG(Log::sceNet, "FriendFinder: End of Friend Finder Thread"); // Return Success return 0; @@ -1929,7 +1943,7 @@ void getLocalMac(SceNetEtherAddr * addr){ } else if (!ParseMacAddress(g_Config.sMACAddress, mac)) { - ERROR_LOG(SCENET, "Error parsing mac address %s", g_Config.sMACAddress.c_str()); + ERROR_LOG(Log::sceNet, "Error parsing mac address %s", g_Config.sMACAddress.c_str()); memset(&mac, 0, sizeof(mac)); } memcpy(addr, mac, ETHER_ADDR_LEN); @@ -2166,7 +2180,7 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ metasocket = (int)INVALID_SOCKET; metasocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (metasocket == INVALID_SOCKET){ - ERROR_LOG(SCENET, "Invalid socket"); + ERROR_LOG(Log::sceNet, "Invalid socket"); return SOCKET_ERROR; } setSockKeepAlive((int)metasocket, true); @@ -2189,7 +2203,7 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ // Bind Local Address to Socket iResult = bind((int)metasocket, &g_localhostIP.addr, sizeof(g_localhostIP.addr)); if (iResult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "Bind to alternate localhost[%s] failed(%i).", ip2str(g_localhostIP.in.sin_addr).c_str(), iResult); + ERROR_LOG(Log::sceNet, "Bind to alternate localhost[%s] failed(%i).", ip2str(g_localhostIP.in.sin_addr).c_str(), iResult); g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to Bind Localhost IP")) + " " + ip2str(g_localhostIP.in.sin_addr).c_str()); } } @@ -2218,7 +2232,7 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ // Connect to Adhoc Server int errorcode = 0; int cnt = 0; - DEBUG_LOG(SCENET, "InitNetwork: Connecting to AdhocServer"); + DEBUG_LOG(Log::sceNet, "InitNetwork: Connecting to AdhocServer"); iResult = connect((int)metasocket, &g_adhocServerIP.addr, sizeof(g_adhocServerIP)); errorcode = errno; @@ -2244,7 +2258,7 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ sleep_ms(10); } if (!done) { - ERROR_LOG(SCENET, "Socket error (%i) when connecting to AdhocServer [%s/%s:%u]", errorcode, g_Config.proAdhocServer.c_str(), ip2str(g_adhocServerIP.in.sin_addr).c_str(), ntohs(g_adhocServerIP.in.sin_port)); + ERROR_LOG(Log::sceNet, "Socket error (%i) when connecting to AdhocServer [%s/%s:%u]", errorcode, g_Config.proAdhocServer.c_str(), ip2str(g_adhocServerIP.in.sin_addr).c_str(), ntohs(g_adhocServerIP.in.sin_port)); g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to connect to Adhoc Server")) + " (" + std::string(n->T("Error")) + ": " + std::to_string(errorcode) + ")"); return iResult; } @@ -2261,8 +2275,8 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN); IsSocketReady((int)metasocket, false, true, nullptr, adhocDefaultTimeout); - DEBUG_LOG(SCENET, "InitNetwork: Sending LOGIN OPCODE %d", packet.base.opcode); - int sent = send((int)metasocket, (char*)&packet, sizeof(packet), MSG_NOSIGNAL); + DEBUG_LOG(Log::sceNet, "InitNetwork: Sending LOGIN OPCODE %d", packet.base.opcode); + int sent = (int)send((int)metasocket, (char*)&packet, sizeof(packet), MSG_NOSIGNAL); if (sent > 0) { socklen_t addrLen = sizeof(LocalIP); memset(&LocalIP, 0, addrLen); diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 49ab5c8e48..96a59df152 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -39,17 +39,13 @@ #endif #include -#include #include #include +#include #include "Common/Net/Resolve.h" #include "Common/Serialize/Serializer.h" - -#include "Core/CoreTiming.h" #include "Core/MemMap.h" -#include "Core/HLE/HLE.h" -#include "Core/HLE/HLEHelperThread.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelMutex.h" @@ -111,6 +107,10 @@ inline bool isDisconnected(int errcode) { return (errcode == EPIPE || errcode == #define POLLPRI POLL_PRI #endif +#ifndef SD_RECEIVE +#define SD_RECEIVE SHUT_RD //0x00 +#endif + #ifndef SD_BOTH #define SD_BOTH SHUT_RDWR //0x02 #endif diff --git a/Core/HLE/proAdhocServer.cpp b/Core/HLE/proAdhocServer.cpp index ca4e460897..f58f00ca76 100644 --- a/Core/HLE/proAdhocServer.cpp +++ b/Core/HLE/proAdhocServer.cpp @@ -517,7 +517,7 @@ void login_user_stream(int fd, uint32_t ip) while(u != NULL && u->resolver.ip != ip) u = u->next; if (u != NULL) { // IP Already existed - WARN_LOG(SCENET, "AdhocServer: Already Existing IP: %s\n", ip2str(*(in_addr*)&u->resolver.ip).c_str()); + WARN_LOG(Log::sceNet, "AdhocServer: Already Existing IP: %s\n", ip2str(*(in_addr*)&u->resolver.ip).c_str()); } // Unique IP Address @@ -547,7 +547,7 @@ void login_user_stream(int fd, uint32_t ip) user->last_recv = time(NULL); // Notify User - INFO_LOG(SCENET, "AdhocServer: New Connection from %s", ip2str(*(in_addr*)&user->resolver.ip).c_str()); + INFO_LOG(Log::sceNet, "AdhocServer: New Connection from %s", ip2str(*(in_addr*)&user->resolver.ip).c_str()); // Fix User Counter _db_user_count++; @@ -590,7 +590,7 @@ void login_user_data(SceNetAdhocctlUserNode * user, SceNetAdhocctlLoginPacketC2S while (u != NULL && !IsMatch(u->resolver.mac, data->mac)) u = u->next; if (u != NULL) { // MAC Already existed - WARN_LOG(SCENET, "AdhocServer: Already Existing MAC: %s [%s]\n", mac2str(&data->mac).c_str(), ip2str(*(in_addr*)&u->resolver.ip).c_str()); + WARN_LOG(Log::sceNet, "AdhocServer: Already Existing MAC: %s [%s]\n", mac2str(&data->mac).c_str(), ip2str(*(in_addr*)&u->resolver.ip).c_str()); } // Game Product Override @@ -641,7 +641,7 @@ void login_user_data(SceNetAdhocctlUserNode * user, SceNetAdhocctlLoginPacketC2S char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, game->game.data, PRODUCT_CODE_LENGTH); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) started playing %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr); + INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) started playing %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr); // Update Status Log update_status(); @@ -655,7 +655,7 @@ void login_user_data(SceNetAdhocctlUserNode * user, SceNetAdhocctlLoginPacketC2S else { // Notify User - WARN_LOG(SCENET, "AdhocServer: Invalid Login Packet Contents from %s", ip2str(*(in_addr*)&user->resolver.ip).c_str()); + WARN_LOG(Log::sceNet, "AdhocServer: Invalid Login Packet Contents from %s", ip2str(*(in_addr*)&user->resolver.ip).c_str()); } // Logout User - Out of Memory or Invalid Arguments @@ -690,7 +690,7 @@ void logout_user(SceNetAdhocctlUserNode * user) char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) stopped playing %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr); + INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) stopped playing %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr); // Fix Game Player Count user->game->playercount--; @@ -716,7 +716,7 @@ void logout_user(SceNetAdhocctlUserNode * user) else { // Notify User - WARN_LOG(SCENET, "AdhocServer: Dropped Connection to %s", ip2str(*(in_addr*)&user->resolver.ip).c_str()); + WARN_LOG(Log::sceNet, "AdhocServer: Dropped Connection to %s", ip2str(*(in_addr*)&user->resolver.ip).c_str()); } // Free Memory @@ -859,8 +859,8 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group packet.ip = user->resolver.ip; // Send Data - int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); - if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: connect_user[send peer] (Socket error %d)", errno); + int iResult = (int)send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); + if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: connect_user[send peer] (Socket error %d)", errno); // Set Player Name packet.name = peer->resolver.name; @@ -872,8 +872,8 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group packet.ip = peer->resolver.ip; // Send Data - iResult = send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); - if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: connect_user[send user] (Socket error %d)", errno); + iResult = (int)send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); + if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: connect_user[send user] (Socket error %d)", errno); // Set BSSID if(peer->group_next == NULL) bssid.mac = peer->resolver.mac; @@ -894,8 +894,8 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group g->playercount++; // Send Network BSSID to User - int iResult = send(user->stream, (const char*)&bssid, sizeof(bssid), MSG_NOSIGNAL); - if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: connect_user[send user bssid] (Socket error %d)", errno); + int iResult = (int)send(user->stream, (const char*)&bssid, sizeof(bssid), MSG_NOSIGNAL); + if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: connect_user[send user bssid] (Socket error %d)", errno); // Notify User char safegamestr[10]; @@ -904,7 +904,7 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) joined %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr); + INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) joined %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr); // Update Status Log update_status(); @@ -927,7 +927,7 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group char safegroupstr2[9]; memset(safegroupstr2, 0, sizeof(safegroupstr2)); strncpy(safegroupstr2, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - WARN_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) attempted to join %s group %s without disconnecting from %s first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr, safegroupstr2); + WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to join %s group %s without disconnecting from %s first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr, safegroupstr2); } } @@ -941,7 +941,7 @@ void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)group->data, ADHOCCTL_GROUPNAME_LEN); - WARN_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) attempted to join invalid %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr); + WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to join invalid %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr); } // Invalid State, Out of Memory or Invalid Group Name @@ -986,8 +986,8 @@ void disconnect_user(SceNetAdhocctlUserNode * user) packet.ip = user->resolver.ip; // Send Data - int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); - if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: disconnect_user[send peer] (Socket error %d)", errno); + int iResult = (int)send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); + if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: disconnect_user[send peer] (Socket error %d)", errno); // Move Pointer peer = peer->group_next; @@ -1000,7 +1000,7 @@ void disconnect_user(SceNetAdhocctlUserNode * user) char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) left %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr); + INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) left %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr); // Empty Group if(user->group->playercount == 0) @@ -1040,7 +1040,7 @@ void disconnect_user(SceNetAdhocctlUserNode * user) char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); - WARN_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) attempted to leave %s group without joining one first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr); + WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to leave %s group without joining one first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr); } // Delete User @@ -1085,20 +1085,20 @@ void send_scan_results(SceNetAdhocctlUserNode * user) } // Send Group Packet - int iResult = send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); - if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: send_scan_result[send user] (Socket error %d)", errno); + int iResult = (int)send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); + if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: send_scan_result[send user] (Socket error %d)", errno); } // Notify Player of End of Scan uint8_t opcode = OPCODE_SCAN_COMPLETE; - int iResult = send(user->stream, (const char*)&opcode, 1, MSG_NOSIGNAL); - if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: send_scan_result[send peer complete] (Socket error %d)", errno); + int iResult = (int)send(user->stream, (const char*)&opcode, 1, MSG_NOSIGNAL); + if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: send_scan_result[send peer complete] (Socket error %d)", errno); // Notify User char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) requested information on %d %s groups", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), user->game->groupcount, safegamestr); + INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) requested information on %d %s groups", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), user->game->groupcount, safegamestr); // Exit Function return; @@ -1114,7 +1114,7 @@ void send_scan_results(SceNetAdhocctlUserNode * user) char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - WARN_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) attempted to scan for %s groups without disconnecting from %s first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr); + WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to scan for %s groups without disconnecting from %s first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr); } // Delete User @@ -1150,8 +1150,8 @@ void spread_message(SceNetAdhocctlUserNode *user, const char *message) strcpy(packet.base.message, message); // Send Data - int iResult = send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); - if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: spread_message[send user chat] (Socket error %d)", errno); + int iResult = (int)send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); + if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: spread_message[send user chat] (Socket error %d)", errno); } } @@ -1192,8 +1192,8 @@ void spread_message(SceNetAdhocctlUserNode *user, const char *message) packet.name = user->resolver.name; // Send Data - int iResult = send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); - if (iResult < 0) ERROR_LOG(SCENET, "AdhocServer: spread_message[send peer chat] (Socket error %d)", errno); + int iResult = (int)send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL); + if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: spread_message[send peer chat] (Socket error %d)", errno); // Move Pointer peer = peer->group_next; @@ -1212,7 +1212,7 @@ void spread_message(SceNetAdhocctlUserNode *user, const char *message) char safegroupstr[9]; memset(safegroupstr, 0, sizeof(safegroupstr)); strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN); - INFO_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) sent \"%s\" to %d players in %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), message, counter, safegamestr, safegroupstr); + INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) sent \"%s\" to %d players in %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), message, counter, safegamestr, safegroupstr); } // Exit Function @@ -1226,7 +1226,7 @@ void spread_message(SceNetAdhocctlUserNode *user, const char *message) char safegamestr[10]; memset(safegamestr, 0, sizeof(safegamestr)); strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH); - WARN_LOG(SCENET, "AdhocServer: %s (MAC: %s - IP: %s) attempted to send a text message without joining a %s group first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr); + WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to send a text message without joining a %s group first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr); } // Delete User @@ -1327,7 +1327,7 @@ void game_product_override(SceNetAdhocctlProductCode * product) strncpy(product->data, crosslink, PRODUCT_CODE_LENGTH); // Log Crosslink - INFO_LOG(SCENET, "Crosslinked %s to %s", productid, crosslink); + INFO_LOG(Log::sceNet, "Crosslinked %s to %s", productid, crosslink); // Set Crosslinked Flag crosslinked = 1; @@ -1348,7 +1348,7 @@ void game_product_override(SceNetAdhocctlProductCode * product) strncpy(product->data, it->id_to, PRODUCT_CODE_LENGTH); // Log Crosslink - INFO_LOG(SCENET, "AdhocServer: Crosslinked %s to %s", productid, crosslink); + INFO_LOG(Log::sceNet, "AdhocServer: Crosslinked %s to %s", productid, crosslink); // Set Crosslinked Flag crosslinked = 1; @@ -1397,7 +1397,7 @@ void game_product_override(SceNetAdhocctlProductCode * product) if(sqlite3_step(statement) == SQLITE_DONE) { // Log Addition - INFO_LOG(SCENET, "Added Unknown Product ID %s to Database", productid); + INFO_LOG(Log::sceNet, "Added Unknown Product ID %s to Database", productid); } } @@ -1409,7 +1409,7 @@ void game_product_override(SceNetAdhocctlProductCode * product) strncpy(unkproduct.name, productid, sizeof(productid)); productids.push_back(unkproduct); //productids[productids.size()] = unkproduct; // Log Addition - INFO_LOG(SCENET, "AdhocServer: Added Unknown Product ID %s to Database", productid); + INFO_LOG(Log::sceNet, "AdhocServer: Added Unknown Product ID %s to Database", productid); } } @@ -1680,7 +1680,7 @@ int proAdhocServerThread(int port) // (int argc, char * argv[]) // Result int result = 0; - INFO_LOG(SCENET, "AdhocServer: Begin of AdhocServer Thread"); + INFO_LOG(Log::sceNet, "AdhocServer: Begin of AdhocServer Thread"); // Create Signal Receiver for CTRL + C //signal(SIGINT, interrupt); @@ -1695,7 +1695,7 @@ int proAdhocServerThread(int port) // (int argc, char * argv[]) if(server != SOCKET_ERROR) { // Notify User - INFO_LOG(SCENET, "AdhocServer: Listening for Connections on TCP Port %u", port); //SERVER_PORT + INFO_LOG(Log::sceNet, "AdhocServer: Listening for Connections on TCP Port %u", port); //SERVER_PORT // Port forward UPnP_Add(IP_PROTOCOL_TCP, port); // g_PortManager.Add(IP_PROTOCOL_TCP, port); @@ -1707,13 +1707,13 @@ int proAdhocServerThread(int port) // (int argc, char * argv[]) UPnP_Remove(IP_PROTOCOL_TCP, port); // g_PortManager.Remove(IP_PROTOCOL_TCP, port); // Notify User - INFO_LOG(SCENET, "AdhocServer: Shutdown complete"); + INFO_LOG(Log::sceNet, "AdhocServer: Shutdown complete"); } //_status = 0; adhocServerRunning = false; - INFO_LOG(SCENET, "AdhocServer: End of AdhocServer Thread"); + INFO_LOG(Log::sceNet, "AdhocServer: End of AdhocServer Thread"); // Return Result return result; @@ -1726,7 +1726,7 @@ int proAdhocServerThread(int port) // (int argc, char * argv[]) void interrupt(int sig) { // Notify User - INFO_LOG(SCENET, "AdhocServer: Shutting down... please wait"); + INFO_LOG(Log::sceNet, "AdhocServer: Shutting down... please wait"); // Trigger Shutdown //_status = 0; @@ -1856,7 +1856,7 @@ int create_listen_socket(uint16_t port) // Notify User else { - ERROR_LOG(SCENET, "AdhocServer: Bind returned %i (Socket error %d)", bindresult, errno); + ERROR_LOG(Log::sceNet, "AdhocServer: Bind returned %i (Socket error %d)", bindresult, errno); auto n = GetI18NCategory(I18NCat::NETWORKING); g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("AdhocServer Failed to Bind Port")) + " " + std::to_string(port)); } @@ -1866,7 +1866,7 @@ int create_listen_socket(uint16_t port) } // Notify User - else ERROR_LOG(SCENET, "AdhocServer: Socket returned %i (Socket error %d)", fd, errno); + else ERROR_LOG(Log::sceNet, "AdhocServer: Socket returned %i (Socket error %d)", fd, errno); // Return Error return -1; @@ -1923,7 +1923,7 @@ int server_loop(int server) u8 *pip = (u8*)&sip; if (gethostbyname(str)->h_addrtype == AF_INET && gethostbyname(str)->h_addr_list[0] != NULL) pip = (u8*)gethostbyname(str)->h_addr_list[0]; sip = *(u32_le*)pip; - WARN_LOG(SCENET, "AdhocServer: Replacing IP %s with %s", inet_ntoa(addr.sin_addr), inet_ntoa(*(in_addr*)&pip)); + WARN_LOG(Log::sceNet, "AdhocServer: Replacing IP %s with %s", inet_ntoa(addr.sin_addr), inet_ntoa(*(in_addr*)&pip)); } */ login_user_stream(loginresult, sip); @@ -1939,7 +1939,7 @@ int server_loop(int server) SceNetAdhocctlUserNode * next = user->next; // Receive Data from User - int recvresult = recv(user->stream, (char*)user->rx + user->rxpos, sizeof(user->rx) - user->rxpos, MSG_NOSIGNAL); + int recvresult = (int)recv(user->stream, (char*)user->rx + user->rxpos, sizeof(user->rx) - user->rxpos, MSG_NOSIGNAL); // Connection Closed or Timed Out if(recvresult == 0 || (recvresult == -1 && errno != EAGAIN && errno != EWOULDBLOCK) || get_user_state(user) == USER_STATE_TIMED_OUT) @@ -1985,7 +1985,7 @@ int server_loop(int server) else { // Notify User - WARN_LOG(SCENET, "AdhocServer: Invalid Opcode 0x%02X in Waiting State from %s", user->rx[0], ip2str(*(in_addr*)&user->resolver.ip).c_str()); + WARN_LOG(Log::sceNet, "AdhocServer: Invalid Opcode 0x%02X in Waiting State from %s", user->rx[0], ip2str(*(in_addr*)&user->resolver.ip).c_str()); // Logout User logout_user(user); @@ -2068,7 +2068,7 @@ int server_loop(int server) else { // Notify User - WARN_LOG(SCENET, "AdhocServer: Invalid Opcode 0x%02X in Logged-In State from %s (MAC: %s - IP: %s)", user->rx[0], (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str()); + WARN_LOG(Log::sceNet, "AdhocServer: Invalid Opcode 0x%02X in Logged-In State from %s (MAC: %s - IP: %s)", user->rx[0], (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str()); // Logout User logout_user(user); diff --git a/Core/HLE/sceAdler.cpp b/Core/HLE/sceAdler.cpp index 59e2570467..fe74d313cf 100644 --- a/Core/HLE/sceAdler.cpp +++ b/Core/HLE/sceAdler.cpp @@ -28,10 +28,10 @@ static u32 sceAdler32(u32 adler, u32 data, u32 datalen) { if (!Memory::IsValidAddress(data) || !Memory::IsValidAddress(data + datalen - 1)) { - ERROR_LOG(SCEMISC, "sceAdler32(adler=%08x, data=%08x, datalen=%08x) - bad address(es)", adler, data, datalen); + ERROR_LOG(Log::sceMisc, "sceAdler32(adler=%08x, data=%08x, datalen=%08x) - bad address(es)", adler, data, datalen); return -1; } - INFO_LOG(SCEMISC, "sceAdler32(adler=%08x, data=%08x, datalen=%08x)", adler, data, datalen); + INFO_LOG(Log::sceMisc, "sceAdler32(adler=%08x, data=%08x, datalen=%08x)", adler, data, datalen); u8 *buf = Memory::GetPointerWriteUnchecked(data); u32 ret = adler32(adler, buf, datalen); diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index f83d9ffdf1..7ac530bc5b 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -34,6 +34,8 @@ #include "Core/HLE/sceUtility.h" #include "Core/HLE/sceKernelMemory.h" #include "Core/HLE/sceAtrac.h" +#include "Core/HLE/AtracCtx.h" +#include "Core/HLE/AtracCtx2.h" #include "Core/System.h" // Notes about sceAtrac buffer management @@ -71,624 +73,41 @@ // any cache or separate version of the buffer - at most it manages decode state from earlier in // the buffer. -#define ATRAC_ERROR_API_FAIL 0x80630002 -#define ATRAC_ERROR_NO_ATRACID 0x80630003 -#define ATRAC_ERROR_INVALID_CODECTYPE 0x80630004 -#define ATRAC_ERROR_BAD_ATRACID 0x80630005 -#define ATRAC_ERROR_UNKNOWN_FORMAT 0x80630006 -#define ATRAC_ERROR_WRONG_CODECTYPE 0x80630007 -#define ATRAC_ERROR_BAD_CODEC_PARAMS 0x80630008 -#define ATRAC_ERROR_ALL_DATA_LOADED 0x80630009 -#define ATRAC_ERROR_NO_DATA 0x80630010 -#define ATRAC_ERROR_SIZE_TOO_SMALL 0x80630011 -#define ATRAC_ERROR_SECOND_BUFFER_NEEDED 0x80630012 -#define ATRAC_ERROR_INCORRECT_READ_SIZE 0x80630013 -#define ATRAC_ERROR_BAD_SAMPLE 0x80630015 -#define ATRAC_ERROR_BAD_FIRST_RESET_SIZE 0x80630016 -#define ATRAC_ERROR_BAD_SECOND_RESET_SIZE 0x80630017 -#define ATRAC_ERROR_ADD_DATA_IS_TOO_BIG 0x80630018 -#define ATRAC_ERROR_NOT_MONO 0x80630019 -#define ATRAC_ERROR_NO_LOOP_INFORMATION 0x80630021 -#define ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED 0x80630022 -#define ATRAC_ERROR_BUFFER_IS_EMPTY 0x80630023 -#define ATRAC_ERROR_ALL_DATA_DECODED 0x80630024 -#define ATRAC_ERROR_IS_LOW_LEVEL 0x80630031 -#define ATRAC_ERROR_IS_FOR_SCESAS 0x80630040 -#define ATRAC_ERROR_AA3_INVALID_DATA 0x80631003 -#define ATRAC_ERROR_AA3_SIZE_TOO_SMALL 0x80631004 - -#define AT3_MAGIC 0x0270 -#define AT3_PLUS_MAGIC 0xFFFE -#define PSP_MODE_AT_3_PLUS 0x00001000 -#define PSP_MODE_AT_3 0x00001001 - -const int RIFF_CHUNK_MAGIC = 0x46464952; -const int RIFF_WAVE_MAGIC = 0x45564157; -const int FMT_CHUNK_MAGIC = 0x20746D66; -const int DATA_CHUNK_MAGIC = 0x61746164; -const int SMPL_CHUNK_MAGIC = 0x6C706D73; -const int FACT_CHUNK_MAGIC = 0x74636166; - -const int PSP_ATRAC_ALLDATA_IS_ON_MEMORY = -1; -const int PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY = -2; -const int PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY = -3; - -const u32 ATRAC3_MAX_SAMPLES = 0x400; -const u32 ATRAC3PLUS_MAX_SAMPLES = 0x800; - -const size_t overAllocBytes = 16384; - static const int atracDecodeDelay = 2300; -#ifdef USE_FFMPEG - -extern "C" { -#include "libavformat/avformat.h" -#include "libswresample/swresample.h" -#include "libavutil/samplefmt.h" -#include "libavcodec/avcodec.h" -#include "libavutil/version.h" -} -#include "Core/FFMPEGCompat.h" - -#endif // USE_FFMPEG - -enum AtracDecodeResult { - ATDECODE_FAILED = -1, - ATDECODE_FEEDME = 0, - ATDECODE_GOTFRAME = 1, - ATDECODE_BADFRAME = 2, -}; - -struct InputBuffer { - // Address of the buffer. - u32 addr; - // Size of data read so far into dataBuf_ (to be removed.) - u32 size; - // Offset into addr at which new data is added. - u32 offset; - // Last writableBytes number (to be removed.) - u32 writableBytes; - // Unused, always 0. - u32 neededBytes; - // Total size of the entire file data. - u32 filesize; - // Offset into the file at which new data is read. - u32 fileoffset; -}; - -struct Atrac; -int __AtracSetContext(Atrac *atrac); -void _AtracGenerateContext(Atrac *atrac); - -struct AtracLoopInfo { - int cuePointID; - int type; - int startSample; - int endSample; - int fraction; - int playCount; -}; - -#ifndef USE_FFMPEG -struct AVPacket { - uint8_t *data; - int size; - int64_t pos; -}; -#endif - -struct Atrac { - Atrac() : atracID_(-1), dataBuf_(0), decodePos_(0), bufferPos_(0), - channels_(0), outputChannels_(2), bitrate_(64), bytesPerFrame_(0), bufferMaxSize_(0), jointStereo_(0), - currentSample_(0), endSample_(0), firstSampleOffset_(0), dataOff_(0), - loopStartSample_(-1), loopEndSample_(-1), loopNum_(0), - failedDecode_(false), ignoreDataBuf_(false), codecType_(0), - bufferState_(ATRAC_STATUS_NO_DATA) { - memset(&first_, 0, sizeof(first_)); - memset(&second_, 0, sizeof(second_)); -#ifdef USE_FFMPEG - codecCtx_ = nullptr; - swrCtx_ = nullptr; - frame_ = nullptr; - packet_ = nullptr; -#endif // USE_FFMPEG - context_ = 0; - } - - ~Atrac() { - ResetData(); - } - - void ResetData() { -#ifdef USE_FFMPEG - ReleaseFFMPEGContext(); -#endif // USE_FFMPEG - - if (dataBuf_) - delete [] dataBuf_; - dataBuf_ = 0; - ignoreDataBuf_ = false; - bufferState_ = ATRAC_STATUS_NO_DATA; - - if (context_.IsValid()) - kernelMemory.Free(context_.ptr); - - // Clean slate time. - failedDecode_ = false; - } - - void SetBufferState() { - if (bufferMaxSize_ >= first_.filesize) { - if (first_.size < first_.filesize) { - // The buffer is big enough, but we don't have all the data yet. - bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER; - } else { - bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; - } - } else { - if (loopEndSample_ <= 0) { - // There's no looping, but we need to stream the data in our buffer. - bufferState_ = ATRAC_STATUS_STREAMED_WITHOUT_LOOP; - } else if (loopEndSample_ == endSample_ + firstSampleOffset_ + (int)FirstOffsetExtra()) { - bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END; - } else { - bufferState_ = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER; - } - } - } - - void DoState(PointerWrap &p) { - auto s = p.Section("Atrac", 1, 9); - if (!s) - return; - - Do(p, channels_); - Do(p, outputChannels_); - if (s >= 5) { - Do(p, jointStereo_); - } - - Do(p, atracID_); - Do(p, first_); - Do(p, bufferMaxSize_); - Do(p, codecType_); - - Do(p, currentSample_); - Do(p, endSample_); - Do(p, firstSampleOffset_); - if (s >= 3) { - Do(p, dataOff_); - } else { - dataOff_ = firstSampleOffset_; - } - - u32 hasDataBuf = dataBuf_ != nullptr; - Do(p, hasDataBuf); - if (hasDataBuf) { - if (p.mode == p.MODE_READ) { - if (dataBuf_) - delete [] dataBuf_; - dataBuf_ = new u8[first_.filesize + overAllocBytes]; - memset(dataBuf_, 0, first_.filesize + overAllocBytes); - } - DoArray(p, dataBuf_, first_.filesize); - } - Do(p, second_); - - Do(p, decodePos_); - if (s < 9) { - u32 oldDecodeEnd = 0; - Do(p, oldDecodeEnd); - } - if (s >= 4) { - Do(p, bufferPos_); - } else { - bufferPos_ = decodePos_; - } - - Do(p, bitrate_); - Do(p, bytesPerFrame_); - - Do(p, loopinfo_); - if (s < 9) { - int oldLoopInfoNum = 42; - Do(p, oldLoopInfoNum); - } - - Do(p, loopStartSample_); - Do(p, loopEndSample_); - Do(p, loopNum_); - - Do(p, context_); - if (s >= 6) { - Do(p, bufferState_); - } else { - if (dataBuf_ == nullptr) { - bufferState_ = ATRAC_STATUS_NO_DATA; - } else { - SetBufferState(); - } - } - - if (s >= 7) { - Do(p, ignoreDataBuf_); - } else { - ignoreDataBuf_ = false; - } - - if (s >= 9) { - Do(p, bufferValidBytes_); - Do(p, bufferHeaderSize_); - } else { - bufferHeaderSize_ = dataOff_; - bufferValidBytes_ = std::min(first_.size - dataOff_, StreamBufferEnd() - dataOff_); - if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) { - bufferPos_ = dataOff_; - } - } - - if (s < 8 && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { - // We didn't actually allow the second buffer to be set this far back. - // Pretend it's a regular loop, we'll just try our best. - bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END; - } - - // Make sure to do this late; it depends on things like bytesPerFrame_. - if (p.mode == p.MODE_READ && bufferState_ != ATRAC_STATUS_NO_DATA) { - __AtracSetContext(this); - } - - if (s >= 2 && s < 9) { - bool oldResetBuffer = false; - Do(p, oldResetBuffer); - } - } - - int Analyze(u32 addr, u32 size); - int AnalyzeAA3(u32 addr, u32 size, u32 filesize); - - u32 SamplesPerFrame() const { - return codecType_ == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES; - } - - u32 FirstOffsetExtra() const { - return codecType_ == PSP_CODEC_AT3PLUS ? 368 : 69; - } - - u32 DecodePosBySample(int sample) const { - return (u32)(firstSampleOffset_ + sample / (int)SamplesPerFrame() * bytesPerFrame_); - } - - u32 FileOffsetBySample(int sample) const { - int offsetSample = sample + firstSampleOffset_; - int frameOffset = offsetSample / (int)SamplesPerFrame(); - return (u32)(dataOff_ + bytesPerFrame_ + frameOffset * bytesPerFrame_); - } - - int RemainingFrames() const { - if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { - // Meaning, infinite I guess? We've got it all. - return PSP_ATRAC_ALLDATA_IS_ON_MEMORY; - } - - u32 currentFileOffset = FileOffsetBySample(currentSample_ - SamplesPerFrame() + FirstOffsetExtra()); - if (first_.fileoffset >= first_.filesize) { - if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) { - return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY; - } - int loopEndAdjusted = loopEndSample_ - FirstOffsetExtra() - firstSampleOffset_; - if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && currentSample_ > loopEndAdjusted) { - // No longer looping in this case, outside the loop. - return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY; - } - if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK && loopNum_ == 0) { - return PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY; - } - } - - if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) { - // Since we're streaming, the remaining frames are what's valid in the buffer. - return bufferValidBytes_ / bytesPerFrame_; - } - - // Since the first frame is shorter by this offset, add to round up at this offset. - const int remainingBytes = first_.fileoffset - currentFileOffset; - if (remainingBytes < 0) { - // Just in case. Shouldn't happen, but once did by mistake. - return 0; - } - return remainingBytes / bytesPerFrame_; - } - - int atracID_; - u8 *dataBuf_; - - u32 decodePos_; - // Used by low-level decoding and to track streaming. - u32 bufferPos_; - u32 bufferValidBytes_; - u32 bufferHeaderSize_ = 0; - - u16 channels_; - u16 outputChannels_; - u32 bitrate_; - u16 bytesPerFrame_; - u32 bufferMaxSize_; - int jointStereo_; - - int currentSample_; - int endSample_; - int firstSampleOffset_; - // Offset of the first sample in the input buffer - int dataOff_; - - std::vector loopinfo_; - - int loopStartSample_; - int loopEndSample_; - int loopNum_; - - bool failedDecode_; - // Indicates that the dataBuf_ array should not be used. - bool ignoreDataBuf_; - - u32 codecType_; - AtracStatus bufferState_; - - InputBuffer first_; - InputBuffer second_; - - PSPPointer context_; - -#ifdef USE_FFMPEG - AVCodecContext *codecCtx_ = nullptr; - SwrContext *swrCtx_ = nullptr; - AVFrame *frame_ = nullptr; - AVPacket *packet_ = nullptr; -#endif // USE_FFMPEG - -#ifdef USE_FFMPEG - void ReleaseFFMPEGContext() { - // All of these allow null pointers. - av_freep(&frame_); - swr_free(&swrCtx_); -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0) - // If necessary, extradata is automatically freed. - avcodec_free_context(&codecCtx_); -#else - // Future versions may add other things to free, but avcodec_free_context didn't exist yet here. - // Some old versions crash when we try to free extradata and subtitle_header, so let's not. A minor - // leak is better than a segfault. - // av_freep(&codecCtx_->extradata); - // av_freep(&codecCtx_->subtitle_header); - avcodec_close(codecCtx_); - av_freep(&codecCtx_); -#endif -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) - av_packet_free(&packet_); -#else - av_free_packet(packet_); - delete packet_; - packet_ = nullptr; -#endif - } -#endif // USE_FFMPEG - - void ForceSeekToSample(int sample) { -#ifdef USE_FFMPEG - avcodec_flush_buffers(codecCtx_); - - // Discard any pending packet data. - packet_->size = 0; -#endif - - currentSample_ = sample; - } - - u8 *BufferStart() { - return ignoreDataBuf_ ? Memory::GetPointerWrite(first_.addr) : dataBuf_; - } - - void SeekToSample(int sample) { -#ifdef USE_FFMPEG - // Discard any pending packet data. - packet_->size = 0; - - // It seems like the PSP aligns the sample position to 0x800...? - const u32 offsetSamples = firstSampleOffset_ + FirstOffsetExtra(); - const u32 unalignedSamples = (offsetSamples + sample) % SamplesPerFrame(); - int seekFrame = sample + offsetSamples - unalignedSamples; - - if ((sample != currentSample_ || sample == 0) && codecCtx_ != nullptr) { - // Prefill the decode buffer with packets before the first sample offset. - avcodec_flush_buffers(codecCtx_); - - int adjust = 0; - if (sample == 0) { - int offsetSamples = firstSampleOffset_ + FirstOffsetExtra(); - adjust = -(int)(offsetSamples % SamplesPerFrame()); - } - const u32 off = FileOffsetBySample(sample + adjust); - const u32 backfill = bytesPerFrame_ * 2; - const u32 start = off - dataOff_ < backfill ? dataOff_ : off - backfill; - for (u32 pos = start; pos < off; pos += bytesPerFrame_) { - av_init_packet(packet_); - packet_->data = BufferStart() + pos; - packet_->size = bytesPerFrame_; - packet_->pos = pos; - - // Process the packet, we don't care about success. - DecodePacket(); - } - } -#endif // USE_FFMPEG - - currentSample_ = sample; - } - - uint32_t CurBufferAddress(int adjust = 0) { - u32 off = FileOffsetBySample(currentSample_ + adjust); - if (off < first_.size && ignoreDataBuf_) { - return first_.addr + off; - } - // If it's in dataBug, it's not in PSP memory. - return 0; - } - - bool FillPacket(int adjust = 0) { - u32 off = FileOffsetBySample(currentSample_ + adjust); - if (off < first_.size) { -#ifdef USE_FFMPEG - av_init_packet(packet_); - packet_->data = BufferStart() + off; - packet_->size = std::min((u32)bytesPerFrame_, first_.size - off); - packet_->pos = off; -#endif // USE_FFMPEG - - return true; - } else { - return false; - } - - return true; - } - - bool FillLowLevelPacket(u8 *ptr) { -#ifdef USE_FFMPEG - av_init_packet(packet_); - - packet_->data = ptr; - packet_->size = bytesPerFrame_; - packet_->pos = 0; -#endif // USE_FFMPEG - return true; - } - - AtracDecodeResult DecodePacket() { -#ifdef USE_FFMPEG - if (codecCtx_ == nullptr) { - return ATDECODE_FAILED; - } - - int got_frame = 0; -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) - if (packet_->size != 0) { - int err = avcodec_send_packet(codecCtx_, packet_); - if (err < 0) { - ERROR_LOG_REPORT(ME, "avcodec_send_packet: Error decoding audio %d / %08x", err, err); - failedDecode_ = true; - return ATDECODE_FAILED; - } - } - - int err = avcodec_receive_frame(codecCtx_, frame_); - int bytes_read = 0; - if (err >= 0) { - bytes_read = frame_->pkt_size; - got_frame = 1; - } else if (err != AVERROR(EAGAIN)) { - bytes_read = err; - } -#else - int bytes_read = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, packet_); -#endif -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) - av_packet_unref(packet_); -#else - av_free_packet(packet_); -#endif - if (bytes_read == AVERROR_PATCHWELCOME) { - ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); - // Let's try the next packet. - packet_->size = 0; - return ATDECODE_BADFRAME; - } else if (bytes_read < 0) { - ERROR_LOG_REPORT(ME, "avcodec_decode_audio4: Error decoding audio %d / %08x", bytes_read, bytes_read); - failedDecode_ = true; - return ATDECODE_FAILED; - } - - return got_frame ? ATDECODE_GOTFRAME : ATDECODE_FEEDME; -#else - return ATDECODE_BADFRAME; -#endif // USE_FFMPEG - } - - void CalculateStreamInfo(u32 *readOffset); - - u32 StreamBufferEnd() const { - // The buffer is always aligned to a frame in size, not counting an optional header. - // The header will only initially exist after the data is first set. - u32 framesAfterHeader = (bufferMaxSize_ - bufferHeaderSize_) / bytesPerFrame_; - return framesAfterHeader * bytesPerFrame_ + bufferHeaderSize_; - } - - void ConsumeFrame() { - bufferPos_ += bytesPerFrame_; - if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) { - if (bufferValidBytes_ > bytesPerFrame_) { - bufferValidBytes_ -= bytesPerFrame_; - } else { - bufferValidBytes_ = 0; - } - } - if (bufferPos_ >= StreamBufferEnd()) { - // Wrap around... theoretically, this should only happen at exactly StreamBufferEnd. - bufferPos_ -= StreamBufferEnd(); - bufferHeaderSize_ = 0; - } - } - -private: - void AnalyzeReset(); -}; - -struct AtracSingleResetBufferInfo { - u32_le writePosPtr; - u32_le writableBytes; - u32_le minWriteBytes; - u32_le filePos; -}; - -struct AtracResetBufferInfo { - AtracSingleResetBufferInfo first; - AtracSingleResetBufferInfo second; -}; - const int PSP_NUM_ATRAC_IDS = 6; static bool atracInited = true; -static Atrac *atracIDs[PSP_NUM_ATRAC_IDS]; -static u32 atracIDTypes[PSP_NUM_ATRAC_IDS]; +static AtracBase *atracContexts[PSP_NUM_ATRAC_IDS]; +static u32 atracContextTypes[PSP_NUM_ATRAC_IDS]; static int atracLibVersion = 0; static u32 atracLibCrc = 0; void __AtracInit() { + _assert_(sizeof(SceAtracContext) == 256); + atracInited = true; - memset(atracIDs, 0, sizeof(atracIDs)); + memset(atracContexts, 0, sizeof(atracContexts)); // Start with 2 of each in this order. - atracIDTypes[0] = PSP_MODE_AT_3_PLUS; - atracIDTypes[1] = PSP_MODE_AT_3_PLUS; - atracIDTypes[2] = PSP_MODE_AT_3; - atracIDTypes[3] = PSP_MODE_AT_3; - atracIDTypes[4] = 0; - atracIDTypes[5] = 0; + atracContextTypes[0] = PSP_MODE_AT_3_PLUS; + atracContextTypes[1] = PSP_MODE_AT_3_PLUS; + atracContextTypes[2] = PSP_MODE_AT_3; + atracContextTypes[3] = PSP_MODE_AT_3; + atracContextTypes[4] = 0; + atracContextTypes[5] = 0; +} -#ifdef USE_FFMPEG -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100) - avcodec_register_all(); -#endif -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 12, 100) - av_register_all(); -#endif -#endif // USE_FFMPEG +void __AtracShutdown() { + for (size_t i = 0; i < ARRAY_SIZE(atracContexts); ++i) { + delete atracContexts[i]; + atracContexts[i] = nullptr; + } } void __AtracLoadModule(int version, u32 crc) { atracLibVersion = version; atracLibCrc = crc; - INFO_LOG(ME, "AtracInit, atracLibVersion 0x%0x, atracLibcrc %x", atracLibVersion, atracLibCrc); + INFO_LOG(Log::ME, "AtracInit, atracLibVersion 0x%0x, atracLibcrc %x", atracLibVersion, atracLibCrc); } void __AtracDoState(PointerWrap &p) { @@ -698,16 +117,16 @@ void __AtracDoState(PointerWrap &p) { Do(p, atracInited); for (int i = 0; i < PSP_NUM_ATRAC_IDS; ++i) { - bool valid = atracIDs[i] != NULL; + bool valid = atracContexts[i] != nullptr; Do(p, valid); if (valid) { - Do(p, atracIDs[i]); + DoSubClass(p, atracContexts[i]); } else { - delete atracIDs[i]; - atracIDs[i] = NULL; + delete atracContexts[i]; + atracContexts[i] = nullptr; } } - DoArray(p, atracIDTypes, PSP_NUM_ATRAC_IDS); + DoArray(p, atracContextTypes, PSP_NUM_ATRAC_IDS); if (s < 2) { atracLibVersion = 0; atracLibCrc = 0; @@ -718,435 +137,86 @@ void __AtracDoState(PointerWrap &p) { } } -void __AtracShutdown() { - for (size_t i = 0; i < ARRAY_SIZE(atracIDs); ++i) { - delete atracIDs[i]; - atracIDs[i] = NULL; +static AtracBase *allocAtrac(bool forceOld = false) { + if (g_Config.bUseNewAtrac && !forceOld) { + return new Atrac2(); + } else { + return new Atrac(); } } -static Atrac *getAtrac(int atracID) { +static AtracBase *getAtrac(int atracID) { if (atracID < 0 || atracID >= PSP_NUM_ATRAC_IDS) { - return NULL; + return nullptr; } - Atrac *atrac = atracIDs[atracID]; - - if (atrac && atrac->context_.IsValid()) { - // Read in any changes from the game to the context. - // TODO: Might be better to just always track in RAM. - atrac->bufferState_ = atrac->context_->info.state; - // This value is actually abused by games to store the SAS voice number. - atrac->loopNum_ = atrac->context_->info.loopNum; + AtracBase *atrac = atracContexts[atracID]; + if (atrac) { + atrac->UpdateContextFromPSPMem(); } - return atrac; } -static int createAtrac(Atrac *atrac) { - for (int i = 0; i < (int)ARRAY_SIZE(atracIDs); ++i) { - if (atracIDTypes[i] == atrac->codecType_ && atracIDs[i] == 0) { - atracIDs[i] = atrac; +static int createAtrac(AtracBase *atrac) { + for (int i = 0; i < (int)ARRAY_SIZE(atracContexts); ++i) { + if (atracContextTypes[i] == atrac->CodecType() && atracContexts[i] == 0) { + atracContexts[i] = atrac; atrac->atracID_ = i; return i; } } - return ATRAC_ERROR_NO_ATRACID; } static int deleteAtrac(int atracID) { if (atracID >= 0 && atracID < PSP_NUM_ATRAC_IDS) { - if (atracIDs[atracID] != nullptr) { - delete atracIDs[atracID]; - atracIDs[atracID] = nullptr; - + if (atracContexts[atracID] != nullptr) { + delete atracContexts[atracID]; + atracContexts[atracID] = nullptr; return 0; } } - return ATRAC_ERROR_BAD_ATRACID; } -void Atrac::AnalyzeReset() { - // Reset some values. - codecType_ = 0; - currentSample_ = 0; - endSample_ = -1; - loopNum_ = 0; - loopinfo_.clear(); - loopStartSample_ = -1; - loopEndSample_ = -1; - decodePos_ = 0; - bufferPos_ = 0; - channels_ = 2; -} - -struct RIFFFmtChunk { - u16_le fmtTag; - u16_le channels; - u32_le samplerate; - u32_le avgBytesPerSec; - u16_le blockAlign; -}; - -int Atrac::Analyze(u32 addr, u32 size) { - first_.addr = addr; - first_.size = size; - - AnalyzeReset(); - - // 72 is about the size of the minimum required data to even be valid. - if (first_.size < 72) { - return hleReportError(ME, ATRAC_ERROR_SIZE_TOO_SMALL, "buffer too small"); - } - - if (!Memory::IsValidAddress(first_.addr)) { - return hleReportWarning(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "invalid buffer address"); - } - - // TODO: Validate stuff. - - if (Memory::Read_U32(first_.addr) != RIFF_CHUNK_MAGIC) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid RIFF header"); - } - - u32 offset = 8; - firstSampleOffset_ = 0; - - while (Memory::Read_U32(first_.addr + offset) != RIFF_WAVE_MAGIC) { - // Get the size preceding the magic. - int chunk = Memory::Read_U32(first_.addr + offset - 4); - // Round the chunk size up to the nearest 2. - offset += chunk + (chunk & 1); - if (offset + 12 > first_.size) { - return hleReportError(ME, ATRAC_ERROR_SIZE_TOO_SMALL, "too small for WAVE chunk at %d", offset); - } - if (Memory::Read_U32(first_.addr + offset) != RIFF_CHUNK_MAGIC) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "RIFF chunk did not contain WAVE"); - } - offset += 8; - } - offset += 4; - - if (offset != 12) { - WARN_LOG_REPORT(ME, "RIFF chunk at offset: %d", offset); - } - - // RIFF size excluding chunk header. - first_.filesize = Memory::Read_U32(first_.addr + offset - 8) + 8; - // Even if the RIFF size is too low, it may simply be incorrect. This works on real firmware. - u32 maxSize = std::max(first_.filesize, first_.size); - - bool bfoundData = false; - u32 dataChunkSize = 0; - int sampleOffsetAdjust = 0; - while (maxSize >= offset + 8 && !bfoundData) { - int chunkMagic = Memory::Read_U32(first_.addr + offset); - u32 chunkSize = Memory::Read_U32(first_.addr + offset + 4); - // Account for odd sized chunks. - if (chunkSize & 1) { - WARN_LOG_REPORT_ONCE(oddchunk, ME, "RIFF chunk had uneven size"); - } - chunkSize += (chunkSize & 1); - offset += 8; - if (chunkSize > maxSize - offset) - break; - switch (chunkMagic) { - case FMT_CHUNK_MAGIC: - { - if (codecType_ != 0) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "multiple fmt definitions"); - } - - auto at3fmt = PSPPointer::Create(first_.addr + offset); - if (chunkSize < 32 || (at3fmt->fmtTag == AT3_PLUS_MAGIC && chunkSize < 52)) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "fmt definition too small (%d)", chunkSize); - } - - if (at3fmt->fmtTag == AT3_MAGIC) - codecType_ = PSP_MODE_AT_3; - else if (at3fmt->fmtTag == AT3_PLUS_MAGIC) - codecType_ = PSP_MODE_AT_3_PLUS; - else { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid fmt magic: %04x", at3fmt->fmtTag); - } - channels_ = at3fmt->channels; - if (channels_ != 1 && channels_ != 2) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid channel count: %d", channels_); - } - if (at3fmt->samplerate != 44100) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "unsupported sample rate: %d", at3fmt->samplerate); - } - bitrate_ = at3fmt->avgBytesPerSec * 8; - bytesPerFrame_ = at3fmt->blockAlign; - if (bytesPerFrame_ == 0) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid bytes per frame: %d", bytesPerFrame_); - } - - // TODO: There are some format specific bytes here which seem to have fixed values? - // Probably don't need them. - - if (at3fmt->fmtTag == AT3_MAGIC) { - // This is the offset to the jointStereo_ field. - jointStereo_ = Memory::Read_U32(first_.addr + offset + 24); - } - } - break; - case FACT_CHUNK_MAGIC: - { - endSample_ = Memory::Read_U32(first_.addr + offset); - if (chunkSize >= 8) { - firstSampleOffset_ = Memory::Read_U32(first_.addr + offset + 4); - } - if (chunkSize >= 12) { - u32 largerOffset = Memory::Read_U32(first_.addr + offset + 8); - sampleOffsetAdjust = firstSampleOffset_ - largerOffset; - } - } - break; - case SMPL_CHUNK_MAGIC: - { - if (chunkSize < 32) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "smpl chunk too small (%d)", chunkSize); - } - int checkNumLoops = Memory::Read_U32(first_.addr + offset + 28); - if (checkNumLoops != 0 && chunkSize < 36 + 20) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "smpl chunk too small for loop (%d, %d)", checkNumLoops, chunkSize); - } - if (checkNumLoops < 0) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "bad checkNumLoops (%d)", checkNumLoops); - } - - loopinfo_.resize(checkNumLoops); - u32 loopinfoAddr = first_.addr + offset + 36; - // The PSP only cares about the first loop start and end, it seems. - // Most likely can skip the rest of this data, but it's not hurting anyone. - for (int i = 0; i < checkNumLoops && 36 + (u32)i < chunkSize; i++, loopinfoAddr += 24) { - loopinfo_[i].cuePointID = Memory::Read_U32(loopinfoAddr); - loopinfo_[i].type = Memory::Read_U32(loopinfoAddr + 4); - loopinfo_[i].startSample = Memory::Read_U32(loopinfoAddr + 8); - loopinfo_[i].endSample = Memory::Read_U32(loopinfoAddr + 12); - loopinfo_[i].fraction = Memory::Read_U32(loopinfoAddr + 16); - loopinfo_[i].playCount = Memory::Read_U32(loopinfoAddr + 20); - - if (loopinfo_[i].startSample >= loopinfo_[i].endSample) { - return hleReportError(ME, ATRAC_ERROR_BAD_CODEC_PARAMS, "loop starts after it ends"); - } - } - } - break; - case DATA_CHUNK_MAGIC: - { - bfoundData = true; - dataOff_ = offset; - dataChunkSize = chunkSize; - if (first_.filesize < offset + chunkSize) { - WARN_LOG_REPORT(ME, "Atrac data chunk extends beyond riff chunk"); - first_.filesize = offset + chunkSize; - } - } - break; - } - offset += chunkSize; - } - - if (codecType_ == 0) { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "could not detect codec"); - } - - if (!bfoundData) { - return hleReportError(ME, ATRAC_ERROR_SIZE_TOO_SMALL, "no data chunk"); - } - - // set the loopStartSample_ and loopEndSample_ by loopinfo_ - if (loopinfo_.size() > 0) { - loopStartSample_ = loopinfo_[0].startSample + FirstOffsetExtra() + sampleOffsetAdjust; - loopEndSample_ = loopinfo_[0].endSample + FirstOffsetExtra() + sampleOffsetAdjust; - } else { - loopStartSample_ = -1; - loopEndSample_ = -1; - } - - // if there is no correct endsample, try to guess it - if (endSample_ <= 0 && bytesPerFrame_ != 0) { - endSample_ = (dataChunkSize / bytesPerFrame_) * SamplesPerFrame(); - endSample_ -= firstSampleOffset_ + FirstOffsetExtra(); - } - endSample_ -= 1; - - if (loopEndSample_ != -1 && loopEndSample_ > endSample_ + firstSampleOffset_ + (int)FirstOffsetExtra()) { - return hleReportError(ME, ATRAC_ERROR_BAD_CODEC_PARAMS, "loop after end of data"); - } - - return 0; -} - -int Atrac::AnalyzeAA3(u32 addr, u32 size, u32 filesize) { - first_.addr = addr; - first_.size = size; - first_.filesize = filesize; - - AnalyzeReset(); - - if (first_.size < 10) { - return hleReportError(ME, ATRAC_ERROR_AA3_SIZE_TOO_SMALL, "buffer too small"); - } - - // TODO: Make sure this validation is correct, more testing. - - const u8 *buffer = Memory::GetPointer(first_.addr); - if (buffer[0] != 'e' || buffer[1] != 'a' || buffer[2] != '3') { - return hleReportError(ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid ea3 magic bytes"); - } - - // It starts with an id3 header (replaced with ea3.) This is the size. - u32 tagSize = buffer[9] | (buffer[8] << 7) | (buffer[7] << 14) | (buffer[6] << 21); - if (first_.size < tagSize + 36) { - return hleReportError(ME, ATRAC_ERROR_AA3_SIZE_TOO_SMALL, "truncated before id3 end"); - } - - // EA3 header starts at id3 header (10) + tagSize. - buffer = Memory::GetPointer(first_.addr + 10 + tagSize); - if (buffer[0] != 'E' || buffer[1] != 'A' || buffer[2] != '3') { - return hleReportError(ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid EA3 magic bytes"); - } - - // Based on FFmpeg's code. - u32 codecParams = buffer[35] | (buffer[34] << 8) | (buffer[35] << 16); - const u32 at3SampleRates[8] = { 32000, 44100, 48000, 88200, 96000, 0 }; - - switch (buffer[32]) { - case 0: - codecType_ = PSP_MODE_AT_3; - bytesPerFrame_ = (codecParams & 0x03FF) * 8; - bitrate_ = at3SampleRates[(codecParams >> 13) & 7] * bytesPerFrame_ * 8 / 1024; - channels_ = 2; - jointStereo_ = (codecParams >> 17) & 1; - break; - case 1: - codecType_ = PSP_MODE_AT_3_PLUS; - bytesPerFrame_ = ((codecParams & 0x03FF) * 8) + 8; - bitrate_ = at3SampleRates[(codecParams >> 13) & 7] * bytesPerFrame_ * 8 / 2048; - channels_ = (codecParams >> 10) & 7; - break; - case 3: - case 4: - case 5: - return hleReportError(ME, ATRAC_ERROR_AA3_INVALID_DATA, "unsupported codec type %d", buffer[32]); - default: - return hleReportError(ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid codec type %d", buffer[32]); - } - - dataOff_ = 10 + tagSize + 96; - firstSampleOffset_ = 0; - if (endSample_ < 0 && bytesPerFrame_ != 0) { - endSample_ = ((first_.filesize - dataOff_) / bytesPerFrame_) * SamplesPerFrame(); - } - endSample_ -= 1; - - return 0; -} - +// Really, allocate an Atrac context of a specific codec type. +// Useful to initialize a context for low level decode. static u32 sceAtracGetAtracID(int codecType) { if (codecType != PSP_MODE_AT_3 && codecType != PSP_MODE_AT_3_PLUS) { - return hleReportError(ME, ATRAC_ERROR_INVALID_CODECTYPE, "invalid codecType"); + return hleReportError(Log::ME, ATRAC_ERROR_INVALID_CODECTYPE, "invalid codecType"); } - Atrac *atrac = new Atrac(); - atrac->codecType_ = codecType; + AtracBase *atrac = allocAtrac(); + atrac->GetTrackMut().codecType = codecType; int atracID = createAtrac(atrac); if (atracID < 0) { delete atrac; - return hleLogError(ME, atracID, "no free ID"); + return hleLogError(Log::ME, atracID, "no free ID"); } - return hleLogSuccessInfoI(ME, atracID); + return hleLogSuccessInfoI(Log::ME, atracID); } -u32 _AtracAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) - return 0; - int addbytes = std::min(bytesToAdd, atrac->first_.filesize - atrac->first_.fileoffset - atrac->FirstOffsetExtra()); - Memory::Memcpy(atrac->dataBuf_ + atrac->first_.fileoffset + atrac->FirstOffsetExtra(), bufPtr, addbytes, "AtracAddStreamData"); - atrac->first_.size += bytesToAdd; - if (atrac->first_.size >= atrac->first_.filesize) { - atrac->first_.size = atrac->first_.filesize; - if (atrac->bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) - atrac->bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; - } - atrac->first_.fileoffset += addbytes; - if (atrac->context_.IsValid()) { - // refresh context_ - _AtracGenerateContext(atrac); - } - return 0; -} - -static u32 AtracValidateManaged(const Atrac *atrac) { +static u32 AtracValidateData(const AtracBase *atrac) { if (!atrac) { - return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); - } else if (atrac->bufferState_ == ATRAC_STATUS_NO_DATA) { - return hleLogError(ME, ATRAC_ERROR_NO_DATA, "no data"); - } else if (atrac->bufferState_ == ATRAC_STATUS_LOW_LEVEL) { - return hleLogError(ME, ATRAC_ERROR_IS_LOW_LEVEL, "cannot use for low level stream"); - } else if (atrac->bufferState_ == ATRAC_STATUS_FOR_SCESAS) { - return hleLogError(ME, ATRAC_ERROR_IS_FOR_SCESAS, "cannot use for SAS stream"); + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); + } else if (atrac->BufferState() == ATRAC_STATUS_NO_DATA) { + return hleLogError(Log::ME, ATRAC_ERROR_NO_DATA, "no data"); } else { return 0; } } -void Atrac::CalculateStreamInfo(u32 *outReadOffset) { - u32 readOffset = first_.fileoffset; - if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { - // Nothing to write. - readOffset = 0; - first_.offset = 0; - first_.writableBytes = 0; - } else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) { - // If we're buffering the entire file, just give the same as readOffset. - first_.offset = readOffset; - // In this case, the bytes writable are just the remaining bytes, always. - first_.writableBytes = first_.filesize - readOffset; +static u32 AtracValidateManaged(const AtracBase *atrac) { + if (!atrac) { + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); + } else if (atrac->BufferState() == ATRAC_STATUS_NO_DATA) { + return hleLogError(Log::ME, ATRAC_ERROR_NO_DATA, "no data"); + } else if (atrac->BufferState() == ATRAC_STATUS_LOW_LEVEL) { + return hleLogError(Log::ME, ATRAC_ERROR_IS_LOW_LEVEL, "low level stream, can't use"); + } else if (atrac->BufferState() == ATRAC_STATUS_FOR_SCESAS) { + return hleLogError(Log::ME, ATRAC_ERROR_IS_FOR_SCESAS, "SAS stream, can't use"); } else { - u32 bufferEnd = StreamBufferEnd(); - u32 bufferValidExtended = bufferPos_ + bufferValidBytes_; - if (bufferValidExtended < bufferEnd) { - first_.offset = bufferValidExtended; - first_.writableBytes = bufferEnd - bufferValidExtended; - } else { - u32 bufferStartUsed = bufferValidExtended - bufferEnd; - first_.offset = bufferStartUsed; - first_.writableBytes = bufferPos_ - bufferStartUsed; - } - - if (readOffset >= first_.filesize) { - if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) { - // We don't need anything more, so all 0s. - readOffset = 0; - first_.offset = 0; - first_.writableBytes = 0; - } else { - readOffset = FileOffsetBySample(loopStartSample_ - FirstOffsetExtra() - firstSampleOffset_ - SamplesPerFrame() * 2); - } - } - - if (readOffset + first_.writableBytes > first_.filesize) { - // Never ask for past the end of file, even when the space is free. - first_.writableBytes = first_.filesize - readOffset; - } - - // If you don't think this should be here, remove it. It's just a temporary safety check. - if (first_.offset + first_.writableBytes > bufferMaxSize_) { - ERROR_LOG_REPORT(ME, "Somehow calculated too many writable bytes: %d + %d > %d", first_.offset, first_.writableBytes, bufferMaxSize_); - first_.offset = 0; - first_.writableBytes = bufferMaxSize_; - } - } - - if (outReadOffset) { - *outReadOffset = readOffset; + return 0; } } @@ -1155,241 +225,50 @@ void Atrac::CalculateStreamInfo(u32 *outReadOffset) { // // The total size of the buffer is atrac->bufferMaxSize_. static u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. return err; } - if (atrac->bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { + if (atrac->BufferState() == ATRAC_STATUS_ALL_DATA_LOADED) { // Let's avoid spurious warnings. Some games call this with 0 which is pretty harmless. if (bytesToAdd == 0) - return hleLogDebug(ME, ATRAC_ERROR_ALL_DATA_LOADED, "stream entirely loaded"); - return hleLogWarning(ME, ATRAC_ERROR_ALL_DATA_LOADED, "stream entirely loaded"); + return hleLogDebug(Log::ME, ATRAC_ERROR_ALL_DATA_LOADED, "stream entirely loaded"); + return hleLogWarning(Log::ME, ATRAC_ERROR_ALL_DATA_LOADED, "stream entirely loaded"); } - u32 readOffset; - atrac->CalculateStreamInfo(&readOffset); - - if (bytesToAdd > atrac->first_.writableBytes) - return hleLogWarning(ME, ATRAC_ERROR_ADD_DATA_IS_TOO_BIG, "too many bytes"); - - if (bytesToAdd > 0) { - atrac->first_.fileoffset = readOffset; - int addbytes = std::min(bytesToAdd, atrac->first_.filesize - atrac->first_.fileoffset); - if (!atrac->ignoreDataBuf_) { - Memory::Memcpy(atrac->dataBuf_ + atrac->first_.fileoffset, atrac->first_.addr + atrac->first_.offset, addbytes, "AtracAddStreamData"); - } - atrac->first_.fileoffset += addbytes; + int ret = atrac->AddStreamData(bytesToAdd); + if (ret < 0) { + return ret; } - atrac->first_.size += bytesToAdd; - if (atrac->first_.size >= atrac->first_.filesize) { - atrac->first_.size = atrac->first_.filesize; - if (atrac->bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) - atrac->bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; - if (atrac->context_.IsValid()) { - _AtracGenerateContext(atrac); - } - } - - atrac->first_.offset += bytesToAdd; - atrac->bufferValidBytes_ += bytesToAdd; - - if (PSP_CoreParameter().compat.flags().AtracLoopHack && atrac->bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && atrac->RemainingFrames() > 2) { - atrac->loopNum_++; - atrac->SeekToSample(atrac->loopStartSample_ - atrac->FirstOffsetExtra() - atrac->firstSampleOffset_); - } - - return hleLogSuccessI(ME, 0); -} - -u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) { - Atrac *atrac = getAtrac(atracID); - - u32 ret = 0; - if (atrac == NULL) { - ret = ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ret = ATRAC_ERROR_NO_DATA; - } else { - int loopNum = atrac->loopNum_; - if (atrac->bufferState_ == ATRAC_STATUS_FOR_SCESAS) { - // TODO: Might need more testing. - loopNum = 0; - } - - // We already passed the end - return an error (many games check for this.) - if (atrac->currentSample_ >= atrac->endSample_ && loopNum == 0) { - *SamplesNum = 0; - *finish = 1; - ret = ATRAC_ERROR_ALL_DATA_DECODED; - } else { - // TODO: This isn't at all right, but at least it makes the music "last" some time. - u32 numSamples = 0; - - // It seems like the PSP aligns the sample position to 0x800...? - int offsetSamples = atrac->firstSampleOffset_ + atrac->FirstOffsetExtra(); - int skipSamples = 0; - u32 maxSamples = atrac->endSample_ + 1 - atrac->currentSample_; - u32 unalignedSamples = (offsetSamples + atrac->currentSample_) % atrac->SamplesPerFrame(); - if (unalignedSamples != 0) { - // We're off alignment, possibly due to a loop. Force it back on. - maxSamples = atrac->SamplesPerFrame() - unalignedSamples; - skipSamples = unalignedSamples; - } - - if (skipSamples != 0 && atrac->bufferHeaderSize_ == 0) { - // Skip the initial frame used to load state for the looped frame. - // TODO: We will want to actually read this in. - atrac->ConsumeFrame(); - } - - if (!atrac->failedDecode_ && (atrac->codecType_ == PSP_MODE_AT_3 || atrac->codecType_ == PSP_MODE_AT_3_PLUS)) { - atrac->SeekToSample(atrac->currentSample_); - - AtracDecodeResult res = ATDECODE_FEEDME; - while (atrac->FillPacket(-skipSamples)) { - uint32_t packetAddr = atrac->CurBufferAddress(-skipSamples); -#ifdef USE_FFMPEG - int packetSize = atrac->packet_->size; -#endif // USE_FFMPEG - res = atrac->DecodePacket(); - if (res == ATDECODE_FAILED) { - *SamplesNum = 0; - *finish = 1; - return ATRAC_ERROR_ALL_DATA_DECODED; - } - - if (res == ATDECODE_GOTFRAME) { -#ifdef USE_FFMPEG - // got a frame - int skipped = std::min(skipSamples, atrac->frame_->nb_samples); - skipSamples -= skipped; - numSamples = atrac->frame_->nb_samples - skipped; - - // If we're at the end, clamp to samples we want. It always returns a full chunk. - numSamples = std::min(maxSamples, numSamples); - - if (skipped > 0 && numSamples == 0) { - // Wait for the next one. - res = ATDECODE_FEEDME; - } - - if (outbuf != NULL && numSamples != 0) { - int inbufOffset = 0; - if (skipped != 0) { - AVSampleFormat fmt = (AVSampleFormat)atrac->frame_->format; - // We want the offset per channel. - inbufOffset = av_samples_get_buffer_size(NULL, 1, skipped, fmt, 1); - } - - u8 *out = outbuf; - const u8 *inbuf[2] = { - atrac->frame_->extended_data[0] + inbufOffset, - atrac->frame_->extended_data[1] + inbufOffset, - }; - int avret = swr_convert(atrac->swrCtx_, &out, numSamples, inbuf, numSamples); - if (outbufPtr != 0) { - u32 outBytes = numSamples * atrac->outputChannels_ * sizeof(s16); - if (packetAddr != 0 && MemBlockInfoDetailed()) { - char tagData[128]; - size_t tagSize = FormatMemWriteTagAt(tagData, sizeof(tagData), "AtracDecode/", packetAddr, packetSize); - NotifyMemInfo(MemBlockFlags::READ, packetAddr, packetSize, tagData, tagSize); - NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, tagData, tagSize); - } else { - NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode"); - } - } - if (avret < 0) { - ERROR_LOG(ME, "swr_convert: Error while converting %d", avret); - } - } -#endif // USE_FFMPEG - } - if (res == ATDECODE_GOTFRAME || res == ATDECODE_BADFRAME) { - // We only want one frame per call, let's continue the next time. - break; - } - } - - if (res != ATDECODE_GOTFRAME && atrac->currentSample_ < atrac->endSample_) { - // Never got a frame. We may have dropped a GHA frame or otherwise have a bug. - // For now, let's try to provide an extra "frame" if possible so games don't infinite loop. - if (atrac->FileOffsetBySample(atrac->currentSample_) < atrac->first_.filesize) { - numSamples = std::min(maxSamples, atrac->SamplesPerFrame()); - u32 outBytes = numSamples * atrac->outputChannels_ * sizeof(s16); - if (outbuf != nullptr) { - memset(outbuf, 0, outBytes); - NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode"); - } - } - } - } - - *SamplesNum = numSamples; - // update current sample and decodePos - atrac->currentSample_ += numSamples; - atrac->decodePos_ = atrac->DecodePosBySample(atrac->currentSample_); - - atrac->ConsumeFrame(); - - int finishFlag = 0; - // TODO: Verify. - bool hitEnd = atrac->currentSample_ >= atrac->endSample_ || (numSamples == 0 && atrac->first_.size >= atrac->first_.filesize); - int loopEndAdjusted = atrac->loopEndSample_ - atrac->FirstOffsetExtra() - atrac->firstSampleOffset_; - if ((hitEnd || atrac->currentSample_ > loopEndAdjusted) && loopNum != 0) { - atrac->SeekToSample(atrac->loopStartSample_ - atrac->FirstOffsetExtra() - atrac->firstSampleOffset_); - if (atrac->bufferState_ != ATRAC_STATUS_FOR_SCESAS) { - if (atrac->loopNum_ > 0) - atrac->loopNum_--; - } - if ((atrac->bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) { - // Whatever bytes we have left were added from the loop. - u32 loopOffset = atrac->FileOffsetBySample(atrac->loopStartSample_ - atrac->FirstOffsetExtra() - atrac->firstSampleOffset_ - atrac->SamplesPerFrame() * 2); - // TODO: Hmm, need to manage the buffer better. But don't move fileoffset if we already have valid data. - if (loopOffset > atrac->first_.fileoffset || loopOffset + atrac->bufferValidBytes_ < atrac->first_.fileoffset) { - // Skip the initial frame at the start. - atrac->first_.fileoffset = atrac->FileOffsetBySample(atrac->loopStartSample_ - atrac->FirstOffsetExtra() - atrac->firstSampleOffset_ - atrac->SamplesPerFrame() * 2); - } - } - } else if (hitEnd) { - finishFlag = 1; - - // Still move forward, so we know that we've read everything. - // This seems to be reflected in the context as well. - atrac->currentSample_ += atrac->SamplesPerFrame() - numSamples; - } - - *finish = finishFlag; - *remains = atrac->RemainingFrames(); - } - if (atrac->context_.IsValid()) { - // refresh context_ - _AtracGenerateContext(atrac); - } - } - - return ret; + return hleLogSuccessI(Log::ME, 0); } +// Note that outAddr being null is completely valid here, used to skip data. static u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishFlagAddr, u32 remainAddr) { - // Note that outAddr being null is completely valid here, used to skip data. + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; + } u32 numSamples = 0; u32 finish = 0; int remains = 0; - int ret = _AtracDecodeData(atracID, Memory::GetPointerWrite(outAddr), outAddr, &numSamples, &finish, &remains); + int ret = atrac->DecodeData(Memory::GetPointerWrite(outAddr), outAddr, &numSamples, &finish, &remains); if (ret != (int)ATRAC_ERROR_BAD_ATRACID && ret != (int)ATRAC_ERROR_NO_DATA) { if (Memory::IsValidAddress(numSamplesAddr)) - Memory::Write_U32(numSamples, numSamplesAddr); + Memory::WriteUnchecked_U32(numSamples, numSamplesAddr); if (Memory::IsValidAddress(finishFlagAddr)) - Memory::Write_U32(finish, finishFlagAddr); + Memory::WriteUnchecked_U32(finish, finishFlagAddr); // On error, no remaining frame value is written. if (ret == 0 && Memory::IsValidAddress(remainAddr)) - Memory::Write_U32(remains, remainAddr); + Memory::WriteUnchecked_U32(remains, remainAddr); } - DEBUG_LOG(ME, "%08x=sceAtracDecodeData(%i, %08x, %08x[%08x], %08x[%08x], %08x[%d])", ret, atracID, outAddr, + DEBUG_LOG(Log::ME, "%08x=sceAtracDecodeData(%i, %08x, %08x[%08x], %08x[%08x], %08x[%d])", ret, atracID, outAddr, numSamplesAddr, numSamples, finishFlagAddr, finish, remainAddr, remains); @@ -1401,71 +280,16 @@ static u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 } static u32 sceAtracEndEntry() { - ERROR_LOG_REPORT(ME, "UNIMPL sceAtracEndEntry()"); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceAtracEndEntry()"); return 0; } -static void AtracGetResetBufferInfo(Atrac *atrac, AtracResetBufferInfo *bufferInfo, int sample) { - if (atrac->bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { - bufferInfo->first.writePosPtr = atrac->first_.addr; - // Everything is loaded, so nothing needs to be read. - bufferInfo->first.writableBytes = 0; - bufferInfo->first.minWriteBytes = 0; - bufferInfo->first.filePos = 0; - } else if (atrac->bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) { - // Here the message is: you need to read at least this many bytes to get to that position. - // This is because we're filling the buffer start to finish, not streaming. - bufferInfo->first.writePosPtr = atrac->first_.addr + atrac->first_.size; - bufferInfo->first.writableBytes = atrac->first_.filesize - atrac->first_.size; - int minWriteBytes = atrac->FileOffsetBySample(sample) - atrac->first_.size; - if (minWriteBytes > 0) { - bufferInfo->first.minWriteBytes = minWriteBytes; - } else { - bufferInfo->first.minWriteBytes = 0; - } - bufferInfo->first.filePos = atrac->first_.size; - } else { - // This is without the sample offset. The file offset also includes the previous batch of samples? - int sampleFileOffset = atrac->FileOffsetBySample(sample - atrac->firstSampleOffset_ - atrac->SamplesPerFrame()); - - // Update the writable bytes. When streaming, this is just the number of bytes until the end. - const u32 bufSizeAligned = (atrac->bufferMaxSize_ / atrac->bytesPerFrame_) * atrac->bytesPerFrame_; - const int needsMoreFrames = atrac->FirstOffsetExtra(); - - bufferInfo->first.writePosPtr = atrac->first_.addr; - bufferInfo->first.writableBytes = std::min(atrac->first_.filesize - sampleFileOffset, bufSizeAligned); - if (((sample + atrac->firstSampleOffset_) % (int)atrac->SamplesPerFrame()) >= (int)atrac->SamplesPerFrame() - needsMoreFrames) { - // Not clear why, but it seems it wants a bit extra in case the sample is late? - bufferInfo->first.minWriteBytes = atrac->bytesPerFrame_ * 3; - } else { - bufferInfo->first.minWriteBytes = atrac->bytesPerFrame_ * 2; - } - if ((u32)sample < (u32)atrac->firstSampleOffset_ && sampleFileOffset != atrac->dataOff_) { - sampleFileOffset -= atrac->bytesPerFrame_; - } - bufferInfo->first.filePos = sampleFileOffset; - - if (atrac->second_.size != 0) { - // TODO: We have a second buffer. Within it, minWriteBytes should be zero. - // The filePos should be after the end of the second buffer (or zero.) - // We actually need to ensure we READ from the second buffer before implementing that. - } - } - - // It seems like this is always the same as the first buffer's pos, weirdly. - bufferInfo->second.writePosPtr = atrac->first_.addr; - // Reset never needs a second buffer write, since the loop is in a fixed place. - bufferInfo->second.writableBytes = 0; - bufferInfo->second.minWriteBytes = 0; - bufferInfo->second.filePos = 0; -} - // Obtains information about what needs to be in the buffer to seek (or "reset") // Generally called by games right before calling sceAtracResetPlayPosition(). static u32 sceAtracGetBufferInfoForResetting(int atracID, int sample, u32 bufferInfoAddr) { auto bufferInfo = PSPPointer::Create(bufferInfoAddr); - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. @@ -1473,177 +297,142 @@ static u32 sceAtracGetBufferInfoForResetting(int atracID, int sample, u32 buffer } if (!bufferInfo.IsValid()) { - return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid buffer, should crash"); - } else if (atrac->bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && atrac->second_.size == 0) { - return hleReportError(ME, ATRAC_ERROR_SECOND_BUFFER_NEEDED, "no second buffer"); - } else if ((u32)sample + atrac->firstSampleOffset_ > (u32)atrac->endSample_ + atrac->firstSampleOffset_) { - return hleLogWarning(ME, ATRAC_ERROR_BAD_SAMPLE, "invalid sample position"); + return hleReportError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid buffer, should crash"); + } else if (atrac->BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && atrac->SecondBufferSize() == 0) { + return hleReportError(Log::ME, ATRAC_ERROR_SECOND_BUFFER_NEEDED, "no second buffer"); + } else if ((u32)sample + atrac->GetTrack().firstSampleOffset > (u32)atrac->GetTrack().endSample + atrac->GetTrack().firstSampleOffset) { + // NOTE: Above we have to add firstSampleOffset to both sides - we seem to rely on wraparound. + return hleLogWarning(Log::ME, ATRAC_ERROR_BAD_SAMPLE, "invalid sample position"); } else { - AtracGetResetBufferInfo(atrac, bufferInfo, sample); - - return hleLogSuccessInfoI(ME, 0); + atrac->GetResetBufferInfo(bufferInfo, sample); + return hleLogSuccessInfoI(Log::ME, 0); } } static u32 sceAtracGetBitrate(int atracID, u32 outBitrateAddr) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracGetBitrate(%i, %08x): bad atrac ID", atracID, outBitrateAddr); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ERROR_LOG(ME, "sceAtracGetBitrate(%i, %08x): no data", atracID, outBitrateAddr); - return ATRAC_ERROR_NO_DATA; + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; + } + + atrac->GetTrackMut().UpdateBitrate(); + + if (Memory::IsValidAddress(outBitrateAddr)) { + Memory::WriteUnchecked_U32(atrac->GetTrack().bitrate, outBitrateAddr); + return hleLogSuccessI(Log::ME, 0); } else { - atrac->bitrate_ = (atrac->bytesPerFrame_ * 352800) / 1000; - if (atrac->codecType_ == PSP_MODE_AT_3_PLUS) - atrac->bitrate_ = ((atrac->bitrate_ >> 11) + 8) & 0xFFFFFFF0; - else - atrac->bitrate_ = (atrac->bitrate_ + 511) >> 10; - if (Memory::IsValidAddress(outBitrateAddr)) { - Memory::Write_U32(atrac->bitrate_, outBitrateAddr); - DEBUG_LOG(ME, "sceAtracGetBitrate(%i, %08x[%d])", atracID, outBitrateAddr, atrac->bitrate_); - } - else - DEBUG_LOG_REPORT(ME, "sceAtracGetBitrate(%i, %08x[%d]) invalid address", atracID, outBitrateAddr, atrac->bitrate_); + return hleLogError(Log::ME, 0, "invalid address"); } - return 0; } static u32 sceAtracGetChannel(int atracID, u32 channelAddr) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracGetChannel(%i, %08x): bad atrac ID", atracID, channelAddr); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ERROR_LOG(ME, "sceAtracGetChannel(%i, %08x): no data", atracID, channelAddr); - return ATRAC_ERROR_NO_DATA; + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; + } + + if (Memory::IsValidAddress(channelAddr)){ + Memory::WriteUnchecked_U32(atrac->GetTrack().channels, channelAddr); + return hleLogSuccessI(Log::ME, 0); } else { - if (Memory::IsValidAddress(channelAddr)){ - Memory::Write_U32(atrac->channels_, channelAddr); - DEBUG_LOG(ME, "sceAtracGetChannel(%i, %08x[%d])", atracID, channelAddr, atrac->channels_); - } - else - DEBUG_LOG_REPORT(ME, "sceAtracGetChannel(%i, %08x[%d]) invalid address", atracID, channelAddr, atrac->channels_); + return hleLogError(Log::ME, 0, "invalid address"); } - return 0; } static u32 sceAtracGetLoopStatus(int atracID, u32 loopNumAddr, u32 statusAddr) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracGetLoopStatus(%i, %08x, %08x): bad atrac ID", atracID, loopNumAddr, statusAddr); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ERROR_LOG(ME, "sceAtracGetLoopStatus(%i, %08x, %08x): no data", atracID, loopNumAddr, statusAddr); - return ATRAC_ERROR_NO_DATA; + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; + } + + if (Memory::IsValidAddress(loopNumAddr)) + Memory::WriteUnchecked_U32(atrac->LoopNum(), loopNumAddr); + // return audio's loopinfo in at3 file + if (Memory::IsValidAddress(statusAddr)) { + if (atrac->GetTrack().loopinfo.size() > 0) + Memory::WriteUnchecked_U32(1, statusAddr); + else + Memory::WriteUnchecked_U32(0, statusAddr); + return hleLogSuccessI(Log::ME, 0); } else { - DEBUG_LOG(ME, "sceAtracGetLoopStatus(%i, %08x, %08x)", atracID, loopNumAddr, statusAddr); - if (Memory::IsValidAddress(loopNumAddr)) - Memory::Write_U32(atrac->loopNum_, loopNumAddr); - // return audio's loopinfo in at3 file - if (Memory::IsValidAddress(statusAddr)) { - if (atrac->loopinfo_.size() > 0) - Memory::Write_U32(1, statusAddr); - else - Memory::Write_U32(0, statusAddr); - } + return hleLogError(Log::ME, 0, "invalid address"); } - return 0; } static u32 sceAtracGetInternalErrorInfo(int atracID, u32 errorAddr) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracGetInternalErrorInfo(%i, %08x): bad atrac ID", atracID, errorAddr); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - WARN_LOG(ME, "sceAtracGetInternalErrorInfo(%i, %08x): no data", atracID, errorAddr); - return ATRAC_ERROR_NO_DATA; - } else { - ERROR_LOG(ME, "UNIMPL sceAtracGetInternalErrorInfo(%i, %08x)", atracID, errorAddr); - if (Memory::IsValidAddress(errorAddr)) - Memory::Write_U32(0, errorAddr); + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; } + ERROR_LOG(Log::ME, "UNIMPL sceAtracGetInternalErrorInfo(%i, %08x)", atracID, errorAddr); + if (Memory::IsValidAddress(errorAddr)) + Memory::WriteUnchecked_U32(0, errorAddr); return 0; } static u32 sceAtracGetMaxSample(int atracID, u32 maxSamplesAddr) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracGetMaxSample(%i, %08x): bad atrac ID", atracID, maxSamplesAddr); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ERROR_LOG(ME, "sceAtracGetMaxSample(%i, %08x): no data", atracID, maxSamplesAddr); - return ATRAC_ERROR_NO_DATA; + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; + } + + if (Memory::IsValidAddress(maxSamplesAddr)) { + Memory::WriteUnchecked_U32(atrac->GetTrack().SamplesPerFrame(), maxSamplesAddr); + return hleLogSuccessI(Log::ME, 0); } else { - DEBUG_LOG(ME, "sceAtracGetMaxSample(%i, %08x)", atracID, maxSamplesAddr); - if (Memory::IsValidAddress(maxSamplesAddr)) { - Memory::Write_U32(atrac->SamplesPerFrame(), maxSamplesAddr); - } + return hleLogError(Log::ME, 0, "invalid address"); } - return 0; } static u32 sceAtracGetNextDecodePosition(int atracID, u32 outposAddr) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracGetNextDecodePosition(%i, %08x): bad atrac ID", atracID, outposAddr); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ERROR_LOG(ME, "sceAtracGetNextDecodePosition(%i, %08x): no data", atracID, outposAddr); - return ATRAC_ERROR_NO_DATA; - } else { - DEBUG_LOG(ME, "sceAtracGetNextDecodePosition(%i, %08x)", atracID, outposAddr); - if (atrac->currentSample_ >= atrac->endSample_) { - if (Memory::IsValidAddress(outposAddr)) - Memory::Write_U32(0, outposAddr); - return ATRAC_ERROR_ALL_DATA_DECODED; + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; + } + + if (Memory::IsValidAddress(outposAddr)) { + if (atrac->CurrentSample() >= atrac->GetTrack().endSample) { + Memory::WriteUnchecked_U32(0, outposAddr); + return hleLogSuccessI(Log::ME, ATRAC_ERROR_ALL_DATA_DECODED, "all data decoded - beyond endSample"); } else { - if (Memory::IsValidAddress(outposAddr)) - Memory::Write_U32(atrac->currentSample_, outposAddr); + Memory::WriteUnchecked_U32(atrac->CurrentSample(), outposAddr); + return hleLogSuccessI(Log::ME, 0); } + } else { + return hleLogError(Log::ME, 0, "invalid address"); } - return 0; } static u32 sceAtracGetNextSample(int atracID, u32 outNAddr) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracGetNextSample(%i, %08x): bad atrac ID", atracID, outNAddr); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ERROR_LOG(ME, "sceAtracGetNextSample(%i, %08x): no data", atracID, outNAddr); - return ATRAC_ERROR_NO_DATA; - } else { - if (atrac->currentSample_ >= atrac->endSample_) { - if (Memory::IsValidAddress(outNAddr)) - Memory::Write_U32(0, outNAddr); - DEBUG_LOG(ME, "sceAtracGetNextSample(%i, %08x): 0 samples left", atracID, outNAddr); - return 0; - } else { - // It seems like the PSP aligns the sample position to 0x800...? - u32 skipSamples = atrac->firstSampleOffset_ + atrac->FirstOffsetExtra(); - u32 firstSamples = (atrac->SamplesPerFrame() - skipSamples) % atrac->SamplesPerFrame(); - u32 numSamples = atrac->endSample_ + 1 - atrac->currentSample_; - if (atrac->currentSample_ == 0 && firstSamples != 0) { - numSamples = firstSamples; - } - u32 unalignedSamples = (skipSamples + atrac->currentSample_) % atrac->SamplesPerFrame(); - if (unalignedSamples != 0) { - // We're off alignment, possibly due to a loop. Force it back on. - numSamples = atrac->SamplesPerFrame() - unalignedSamples; - } - if (numSamples > atrac->SamplesPerFrame()) - numSamples = atrac->SamplesPerFrame(); - if (atrac->bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && (int)numSamples + atrac->currentSample_ > atrac->endSample_) { - atrac->bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; - } - if (Memory::IsValidAddress(outNAddr)) - Memory::Write_U32(numSamples, outNAddr); - DEBUG_LOG(ME, "sceAtracGetNextSample(%i, %08x): %d samples left", atracID, outNAddr, numSamples); - } + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; } - return 0; + if (atrac->CurrentSample() >= atrac->GetTrack().endSample) { + if (Memory::IsValidAddress(outNAddr)) + Memory::WriteUnchecked_U32(0, outNAddr); + return hleLogSuccessI(Log::ME, 0, "0 samples left"); + } + + u32 numSamples = atrac->GetNextSamples(); + + if (Memory::IsValidAddress(outNAddr)) + Memory::WriteUnchecked_U32(numSamples, outNAddr); + return hleLogSuccessI(Log::ME, 0, "%d samples left", numSamples); } // Obtains the number of frames remaining in the buffer which can be decoded. @@ -1651,7 +440,7 @@ static u32 sceAtracGetNextSample(int atracID, u32 outNAddr) { static u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr) { auto remainingFrames = PSPPointer::Create(remainAddr); - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. @@ -1660,18 +449,18 @@ static u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr) { if (!remainingFrames.IsValid()) { // Would crash. - return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid remainingFrames pointer"); + return hleReportError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid remainingFrames pointer"); } *remainingFrames = atrac->RemainingFrames(); - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 sceAtracGetSecondBufferInfo(int atracID, u32 fileOffsetAddr, u32 desiredSizeAddr) { auto fileOffset = PSPPointer::Create(fileOffsetAddr); auto desiredSize = PSPPointer::Create(desiredSizeAddr); - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. @@ -1680,24 +469,14 @@ static u32 sceAtracGetSecondBufferInfo(int atracID, u32 fileOffsetAddr, u32 desi if (!fileOffset.IsValid() || !desiredSize.IsValid()) { // Would crash. - return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid addresses"); + return hleReportError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid addresses"); } - if (atrac->bufferState_ != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { - // Writes zeroes in this error case. - *fileOffset = 0; - *desiredSize = 0; - return hleLogWarning(ME, ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED, "not needed"); - } - - *fileOffset = atrac->FileOffsetBySample(atrac->loopEndSample_ - atrac->firstSampleOffset_); - *desiredSize = atrac->first_.filesize - *fileOffset; - - return hleLogSuccessI(ME, 0); + return atrac->GetSecondBufferInfo(fileOffset, desiredSize); } static u32 sceAtracGetSoundSample(int atracID, u32 outEndSampleAddr, u32 outLoopStartSampleAddr, u32 outLoopEndSampleAddr) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. @@ -1706,315 +485,104 @@ static u32 sceAtracGetSoundSample(int atracID, u32 outEndSampleAddr, u32 outLoop auto outEndSample = PSPPointer::Create(outEndSampleAddr); if (outEndSample.IsValid()) - *outEndSample = atrac->endSample_; + *outEndSample = atrac->GetTrack().endSample; auto outLoopStart = PSPPointer::Create(outLoopStartSampleAddr); if (outLoopStart.IsValid()) - *outLoopStart = atrac->loopStartSample_ == -1 ? -1 : atrac->loopStartSample_ - atrac->firstSampleOffset_ - atrac->FirstOffsetExtra(); + *outLoopStart = atrac->GetTrack().loopStartSample == -1 ? -1 : atrac->GetTrack().loopStartSample - atrac->GetTrack().FirstSampleOffsetFull(); auto outLoopEnd = PSPPointer::Create(outLoopEndSampleAddr); if (outLoopEnd.IsValid()) - *outLoopEnd = atrac->loopEndSample_ == -1 ? -1 : atrac->loopEndSample_ - atrac->firstSampleOffset_ - atrac->FirstOffsetExtra(); + *outLoopEnd = atrac->GetTrack().loopEndSample == -1 ? -1 : atrac->GetTrack().loopEndSample - atrac->GetTrack().FirstSampleOffsetFull(); if (!outEndSample.IsValid() || !outLoopStart.IsValid() || !outLoopEnd.IsValid()) { - return hleReportError(ME, 0, "invalid address"); + return hleReportError(Log::ME, 0, "invalid address"); } - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } // Games call this function to get some info for add more stream data, // such as where the data read from, where the data add to, // and how many bytes are allowed to add. static u32 sceAtracGetStreamDataInfo(int atracID, u32 writePtrAddr, u32 writableBytesAddr, u32 readOffsetAddr) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. return err; } + u32 writePtr; + u32 writableBytes; u32 readOffset; - atrac->CalculateStreamInfo(&readOffset); + atrac->GetStreamDataInfo(&writePtr, &writableBytes, &readOffset); if (Memory::IsValidAddress(writePtrAddr)) - Memory::Write_U32(atrac->first_.addr + atrac->first_.offset, writePtrAddr); + Memory::WriteUnchecked_U32(writePtr, writePtrAddr); if (Memory::IsValidAddress(writableBytesAddr)) - Memory::Write_U32(atrac->first_.writableBytes, writableBytesAddr); + Memory::WriteUnchecked_U32(writableBytes, writableBytesAddr); if (Memory::IsValidAddress(readOffsetAddr)) - Memory::Write_U32(readOffset, readOffsetAddr); + Memory::WriteUnchecked_U32(readOffset, readOffsetAddr); - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 sceAtracReleaseAtracID(int atracID) { int result = deleteAtrac(atracID); if (result < 0) { - return hleLogError(ME, result, "did not exist"); + if (atracID >= 0) { + return hleLogError(Log::ME, result, "did not exist"); + } else { + return hleLogWarning(Log::ME, result, "did not exist"); + } } - return hleLogSuccessInfoI(ME, result); + return hleLogSuccessInfoI(Log::ME, result); } // This is called when a game wants to seek (or "reset") to a specific position in the audio data. // Normally, sceAtracGetBufferInfoForResetting() is called to determine how to buffer. // The game must add sufficient packets to the buffer in order to complete the seek. static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. return err; } - if (atrac->bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && atrac->second_.size == 0) { - return hleReportError(ME, ATRAC_ERROR_SECOND_BUFFER_NEEDED, "no second buffer"); - } else if ((u32)sample + atrac->firstSampleOffset_ > (u32)atrac->endSample_ + atrac->firstSampleOffset_) { - return hleLogWarning(ME, ATRAC_ERROR_BAD_SAMPLE, "invalid sample position"); - } else { - // Reuse the same calculation as before. - AtracResetBufferInfo bufferInfo; - AtracGetResetBufferInfo(atrac, &bufferInfo, sample); - - if ((u32)bytesWrittenFirstBuf < bufferInfo.first.minWriteBytes || (u32)bytesWrittenFirstBuf > bufferInfo.first.writableBytes) { - return hleLogError(ME, ATRAC_ERROR_BAD_FIRST_RESET_SIZE, "first byte count not in valid range"); - } - if ((u32)bytesWrittenSecondBuf < bufferInfo.second.minWriteBytes || (u32)bytesWrittenSecondBuf > bufferInfo.second.writableBytes) { - return hleLogError(ME, ATRAC_ERROR_BAD_SECOND_RESET_SIZE, "second byte count not in valid range"); - } - - if (atrac->bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { - // Always adds zero bytes. - } else if (atrac->bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) { - // Okay, it's a valid number of bytes. Let's set them up. - if (bytesWrittenFirstBuf != 0) { - if (!atrac->ignoreDataBuf_) { - Memory::Memcpy(atrac->dataBuf_ + atrac->first_.size, atrac->first_.addr + atrac->first_.size, bytesWrittenFirstBuf, "AtracResetPlayPosition"); - } - atrac->first_.fileoffset += bytesWrittenFirstBuf; - atrac->first_.size += bytesWrittenFirstBuf; - atrac->first_.offset += bytesWrittenFirstBuf; - } - - // Did we transition to a full buffer? - if (atrac->first_.size >= atrac->first_.filesize) { - atrac->first_.size = atrac->first_.filesize; - if (atrac->bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) - atrac->bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; - } - } else { - if (bufferInfo.first.filePos > atrac->first_.filesize) { - return hleDelayResult(hleLogError(ME, ATRAC_ERROR_API_FAIL, "invalid file position"), "reset play pos", 200); - } - - // Move the offset to the specified position. - atrac->first_.fileoffset = bufferInfo.first.filePos; - - if (bytesWrittenFirstBuf != 0) { - if (!atrac->ignoreDataBuf_) { - Memory::Memcpy(atrac->dataBuf_ + atrac->first_.fileoffset, atrac->first_.addr, bytesWrittenFirstBuf, "AtracResetPlayPosition"); - } - atrac->first_.fileoffset += bytesWrittenFirstBuf; - } - atrac->first_.size = atrac->first_.fileoffset; - atrac->first_.offset = bytesWrittenFirstBuf; - - atrac->bufferHeaderSize_ = 0; - atrac->bufferPos_ = atrac->bytesPerFrame_; - atrac->bufferValidBytes_ = bytesWrittenFirstBuf - atrac->bufferPos_; - } - - if (atrac->codecType_ == PSP_MODE_AT_3 || atrac->codecType_ == PSP_MODE_AT_3_PLUS) { - atrac->SeekToSample(sample); - } - - if (atrac->context_.IsValid()) { - _AtracGenerateContext(atrac); - } - - return hleDelayResult(hleLogSuccessInfoI(ME, 0), "reset play pos", 3000); - } -} - -#ifdef USE_FFMPEG -static int __AtracUpdateOutputMode(Atrac *atrac, int wanted_channels) { - if (atrac->swrCtx_ && atrac->outputChannels_ == wanted_channels) - return 0; - atrac->outputChannels_ = wanted_channels; - int64_t wanted_channel_layout = av_get_default_channel_layout(wanted_channels); - int64_t dec_channel_layout = av_get_default_channel_layout(atrac->channels_); - - atrac->swrCtx_ = - swr_alloc_set_opts - ( - atrac->swrCtx_, - wanted_channel_layout, - AV_SAMPLE_FMT_S16, - atrac->codecCtx_->sample_rate, - dec_channel_layout, - atrac->codecCtx_->sample_fmt, - atrac->codecCtx_->sample_rate, - 0, - NULL - ); - if (!atrac->swrCtx_) { - ERROR_LOG(ME, "swr_alloc_set_opts: Could not allocate resampler context"); - return -1; - } - if (swr_init(atrac->swrCtx_) < 0) { - ERROR_LOG(ME, "swr_init: Failed to initialize the resampling context"); - return -1; - } - return 0; -} -#endif // USE_FFMPEG - -int __AtracSetContext(Atrac *atrac) { -#ifdef USE_FFMPEG - InitFFmpeg(); - - AVCodecID ff_codec; - if (atrac->codecType_ == PSP_MODE_AT_3) { - ff_codec = AV_CODEC_ID_ATRAC3; - } else if (atrac->codecType_ == PSP_MODE_AT_3_PLUS) { - ff_codec = AV_CODEC_ID_ATRAC3P; - } else { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "unknown codec type in set context"); + if (atrac->BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && atrac->SecondBufferSize() == 0) { + return hleReportError(Log::ME, ATRAC_ERROR_SECOND_BUFFER_NEEDED, "no second buffer"); + } else if ((u32)sample + atrac->GetTrack().firstSampleOffset > (u32)atrac->GetTrack().endSample + atrac->GetTrack().firstSampleOffset) { + // NOTE: Above we have to add firstSampleOffset to both sides - we seem to rely on wraparound. + return hleLogWarning(Log::ME, ATRAC_ERROR_BAD_SAMPLE, "invalid sample position"); } - if (atrac->codecCtx_) { - // Shouldn't happen, but just in case. - atrac->ReleaseFFMPEGContext(); - } - - AVCodec *codec = avcodec_find_decoder(ff_codec); - atrac->codecCtx_ = avcodec_alloc_context3(codec); - - if (atrac->codecType_ == PSP_MODE_AT_3) { - // For ATRAC3, we need the "extradata" in the RIFF header. - atrac->codecCtx_->extradata = (uint8_t *)av_mallocz(14); - atrac->codecCtx_->extradata_size = 14; - - // We don't pull this from the RIFF so that we can support OMA also. - // The only thing that changes are the jointStereo_ values. - atrac->codecCtx_->extradata[0] = 1; - atrac->codecCtx_->extradata[3] = atrac->channels_ << 3; - atrac->codecCtx_->extradata[6] = atrac->jointStereo_; - atrac->codecCtx_->extradata[8] = atrac->jointStereo_; - atrac->codecCtx_->extradata[10] = 1; - } - - // Appears we need to force mono in some cases. (See CPkmn's comments in issue #4248) - if (atrac->channels_ == 1) { - atrac->codecCtx_->channels = 1; - atrac->codecCtx_->channel_layout = AV_CH_LAYOUT_MONO; - } else if (atrac->channels_ == 2) { - atrac->codecCtx_->channels = 2; - atrac->codecCtx_->channel_layout = AV_CH_LAYOUT_STEREO; - } else { - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "unknown channel layout in set context"); - } - - // Explicitly set the block_align value (needed by newer FFmpeg versions, see #5772.) - if (atrac->codecCtx_->block_align == 0) { - atrac->codecCtx_->block_align = atrac->bytesPerFrame_; - } - // Only one supported, it seems? - atrac->codecCtx_->sample_rate = 44100; - - atrac->codecCtx_->request_sample_fmt = AV_SAMPLE_FMT_S16; - int ret; - if ((ret = avcodec_open2(atrac->codecCtx_, codec, nullptr)) < 0) { - // This can mean that the frame size is wrong or etc. - return hleLogError(ME, ATRAC_ERROR_BAD_CODEC_PARAMS, "failed to open decoder %d", ret); - } - - if ((ret = __AtracUpdateOutputMode(atrac, atrac->outputChannels_)) < 0) - return hleLogError(ME, ret, "failed to set the output mode"); - - // alloc audio frame - atrac->frame_ = av_frame_alloc(); -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) - atrac->packet_ = av_packet_alloc(); -#else - atrac->packet_ = new AVPacket; - av_init_packet(atrac->packet_); - atrac->packet_->data = nullptr; - atrac->packet_->size = 0; -#endif - // reinit decodePos, because ffmpeg had changed it. - atrac->decodePos_ = 0; -#endif - - return 0; -} - -static int _AtracSetData(Atrac *atrac, u32 buffer, u32 readSize, u32 bufferSize, int successCode = 0) { - atrac->first_.addr = buffer; - atrac->first_.size = readSize; - - if (atrac->first_.size > atrac->first_.filesize) - atrac->first_.size = atrac->first_.filesize; - atrac->first_.fileoffset = atrac->first_.size; - - // got the size of temp buf, and calculate offset - atrac->bufferMaxSize_ = bufferSize; - atrac->first_.offset = atrac->first_.size; - - // some games may reuse an atracID for playing sound - atrac->ResetData(); - atrac->SetBufferState(); - - if (atrac->codecType_ != PSP_MODE_AT_3 && atrac->codecType_ != PSP_MODE_AT_3_PLUS) { - // Shouldn't have gotten here, Analyze() checks this. - atrac->bufferState_ = ATRAC_STATUS_NO_DATA; - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "unexpected codec type in set data"); - } - - if (atrac->bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED || atrac->bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) { - // This says, don't use the dataBuf_ array, use the PSP RAM. - // This way, games can load data async into the buffer, and it still works. - // TODO: Support this always, even for streaming. - atrac->ignoreDataBuf_ = true; - } - if (atrac->bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP || atrac->bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END || atrac->bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { - atrac->bufferHeaderSize_ = atrac->dataOff_; - atrac->bufferPos_ = atrac->dataOff_ + atrac->bytesPerFrame_; - atrac->bufferValidBytes_ = atrac->first_.size - atrac->bufferPos_; - } - - const char *codecName = atrac->codecType_ == PSP_MODE_AT_3 ? "atrac3" : "atrac3+"; - const char *channelName = atrac->channels_ == 1 ? "mono" : "stereo"; - - // Over-allocate databuf to prevent going off the end if the bitstream is bad or if there are - // bugs in the decoder. This happens, see issue #15788. Arbitrary, but let's make it a whole page on the popular - // architecture that has the largest pages (M1). - atrac->dataBuf_ = new u8[atrac->first_.filesize + overAllocBytes]; - memset(atrac->dataBuf_, 0, atrac->first_.filesize + overAllocBytes); - if (!atrac->ignoreDataBuf_) { - u32 copybytes = std::min(bufferSize, atrac->first_.filesize); - Memory::Memcpy(atrac->dataBuf_, buffer, copybytes, "AtracSetData"); - } - int ret = __AtracSetContext(atrac); - if (ret < 0) { + u32 res = atrac->ResetPlayPosition(sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf); + if (res != 0) { // Already logged. - return ret; + return res; } - return hleLogSuccessInfoI(ME, successCode, "%s %s audio", codecName, channelName); + + return hleDelayResult(hleLogSuccessInfoI(Log::ME, 0), "reset play pos", 3000); } -static int _AtracSetData(int atracID, u32 buffer, u32 readSize, u32 bufferSize, bool needReturnAtracID = false) { - Atrac *atrac = getAtrac(atracID); +static int _AtracSetData(int atracID, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, bool needReturnAtracID) { + AtracBase *atrac = getAtrac(atracID); + // Don't use AtracValidateManaged here. if (!atrac) - return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "invalid atrac ID"); - int ret = _AtracSetData(atrac, buffer, readSize, bufferSize, needReturnAtracID ? atracID : 0); + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "invalid atrac ID"); + int ret = atrac->SetData(buffer, readSize, bufferSize, outputChannels, needReturnAtracID ? atracID : 0); // not sure the real delay time return hleDelayResult(ret, "atrac set data", 100); } static u32 sceAtracSetHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u32 bufferSize) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); + // Don't use AtracValidateManaged here. if (!atrac) { - return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "invalid atrac ID"); } + if (readSize > bufferSize) { - return hleLogError(ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); + return hleLogError(Log::ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); } int ret = atrac->Analyze(buffer, readSize); @@ -2023,40 +591,24 @@ static u32 sceAtracSetHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u32 b return ret; } - atrac->outputChannels_ = 2; - return _AtracSetData(atracID, buffer, readSize, bufferSize); + return _AtracSetData(atracID, buffer, readSize, bufferSize, 2, false); } static u32 sceAtracSetSecondBuffer(int atracID, u32 secondBuffer, u32 secondBufferSize) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. return err; } - u32 secondFileOffset = atrac->FileOffsetBySample(atrac->loopEndSample_ - atrac->firstSampleOffset_); - u32 desiredSize = atrac->first_.filesize - secondFileOffset; - - // 3 seems to be the number of frames required to handle a loop. - if (secondBufferSize < desiredSize && secondBufferSize < (u32)atrac->bytesPerFrame_ * 3) { - return hleReportError(ME, ATRAC_ERROR_SIZE_TOO_SMALL, "too small"); - } - if (atrac->bufferState_ != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { - return hleReportError(ME, ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED, "not needed"); - } - - atrac->second_.addr = secondBuffer; - atrac->second_.size = secondBufferSize; - atrac->second_.fileoffset = secondFileOffset; - - return 0; + return atrac->SetSecondBuffer(secondBuffer, secondBufferSize); } static u32 sceAtracSetData(int atracID, u32 buffer, u32 bufferSize) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); if (!atrac) { - return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); } int ret = atrac->Analyze(buffer, bufferSize); @@ -2065,24 +617,23 @@ static u32 sceAtracSetData(int atracID, u32 buffer, u32 bufferSize) { return ret; } - if (atrac->codecType_ != atracIDTypes[atracID]) { + if (atrac->GetTrack().codecType != atracContextTypes[atracID]) { // TODO: Should this not change the buffer size? - return hleReportError(ME, ATRAC_ERROR_WRONG_CODECTYPE, "atracID uses different codec type than data"); + return hleReportError(Log::ME, ATRAC_ERROR_WRONG_CODECTYPE, "atracID uses different codec type than data"); } - atrac->outputChannels_ = 2; - return _AtracSetData(atracID, buffer, bufferSize, bufferSize); + return _AtracSetData(atracID, buffer, bufferSize, bufferSize, 2, false); } static int sceAtracSetDataAndGetID(u32 buffer, int bufferSize) { // A large value happens in Tales of VS, and isn't handled somewhere properly as a u32. // It's impossible for it to be that big anyway, so cap it. if (bufferSize < 0) { - WARN_LOG(ME, "sceAtracSetDataAndGetID(%08x, %08x): negative bufferSize", buffer, bufferSize); + WARN_LOG(Log::ME, "sceAtracSetDataAndGetID(%08x, %08x): negative bufferSize", buffer, bufferSize); bufferSize = 0x10000000; } - Atrac *atrac = new Atrac(); + AtracBase *atrac = allocAtrac(); int ret = atrac->Analyze(buffer, bufferSize); if (ret < 0) { // Already logged. @@ -2092,18 +643,17 @@ static int sceAtracSetDataAndGetID(u32 buffer, int bufferSize) { int atracID = createAtrac(atrac); if (atracID < 0) { delete atrac; - return hleLogError(ME, atracID, "no free ID"); + return hleLogError(Log::ME, atracID, "no free ID"); } - atrac->outputChannels_ = 2; - return _AtracSetData(atracID, buffer, bufferSize, bufferSize, true); + return _AtracSetData(atracID, buffer, bufferSize, bufferSize, 2, true); } static int sceAtracSetHalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 bufferSize) { if (readSize > bufferSize) { - return hleLogError(ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); + return hleLogError(Log::ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); } - Atrac *atrac = new Atrac(); + AtracBase *atrac = allocAtrac(); int ret = atrac->Analyze(buffer, readSize); if (ret < 0) { // Already logged. @@ -2113,61 +663,51 @@ static int sceAtracSetHalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 buffer int atracID = createAtrac(atrac); if (atracID < 0) { delete atrac; - return hleLogError(ME, atracID, "no free ID"); + return hleLogError(Log::ME, atracID, "no free ID"); } - - atrac->outputChannels_ = 2; - return _AtracSetData(atracID, buffer, readSize, bufferSize, true); + return _AtracSetData(atracID, buffer, readSize, bufferSize, 2, true); } static u32 sceAtracStartEntry() { - ERROR_LOG_REPORT(ME, "UNIMPL sceAtracStartEntry()"); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceAtracStartEntry()"); return 0; } static u32 sceAtracSetLoopNum(int atracID, int loopNum) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracSetLoopNum(%i, %i): bad atrac ID", atracID, loopNum); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ERROR_LOG(ME, "sceAtracSetLoopNum(%i, %i): no data", atracID, loopNum); - return ATRAC_ERROR_NO_DATA; - } else { - if (atrac->loopinfo_.size() == 0) { - DEBUG_LOG(ME, "sceAtracSetLoopNum(%i, %i): error: no loop information", atracID, loopNum); - return ATRAC_ERROR_NO_LOOP_INFORMATION; - } - // Spammed in MHU - DEBUG_LOG(ME, "sceAtracSetLoopNum(%i, %i)", atracID, loopNum); - atrac->loopNum_ = loopNum; - if (loopNum != 0 && atrac->loopinfo_.size() == 0) { - // Just loop the whole audio - atrac->loopStartSample_ = atrac->firstSampleOffset_ + atrac->FirstOffsetExtra(); - atrac->loopEndSample_ = atrac->endSample_ + atrac->firstSampleOffset_ + atrac->FirstOffsetExtra(); - } - if (atrac->context_.IsValid()) { - _AtracGenerateContext(atrac); + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; + } + if (atrac->GetTrack().loopinfo.size() == 0) { + if (loopNum == -1) { + // This is very common and not really a problem. + return hleLogDebug(Log::ME, ATRAC_ERROR_NO_LOOP_INFORMATION, "no loop information to write to!"); + } else { + return hleLogError(Log::ME, ATRAC_ERROR_NO_LOOP_INFORMATION, "no loop information to write to!"); } } - return 0; + + atrac->SetLoopNum(loopNum); + return hleLogSuccessI(Log::ME, 0); } static int sceAtracReinit(int at3Count, int at3plusCount) { for (int i = 0; i < PSP_NUM_ATRAC_IDS; ++i) { - if (atracIDs[i] != NULL) { - ERROR_LOG_REPORT(ME, "sceAtracReinit(%d, %d): cannot reinit while IDs in use", at3Count, at3plusCount); + if (atracContexts[i] != nullptr) { + ERROR_LOG_REPORT(Log::ME, "sceAtracReinit(%d, %d): cannot reinit while IDs in use", at3Count, at3plusCount); return SCE_KERNEL_ERROR_BUSY; } } - memset(atracIDTypes, 0, sizeof(atracIDTypes)); + memset(atracContextTypes, 0, sizeof(atracContextTypes)); int next = 0; int space = PSP_NUM_ATRAC_IDS; // This seems to deinit things. Mostly, it cause a reschedule on next deinit (but -1, -1 does not.) if (at3Count == 0 && at3plusCount == 0) { - INFO_LOG(ME, "sceAtracReinit(%d, %d): deinit", at3Count, at3plusCount); + INFO_LOG(Log::ME, "sceAtracReinit(%d, %d): deinit", at3Count, at3plusCount); atracInited = false; return hleDelayResult(0, "atrac reinit", 200); } @@ -2177,47 +717,44 @@ static int sceAtracReinit(int at3Count, int at3plusCount) { for (int i = 0; i < at3plusCount; ++i) { space -= 2; if (space >= 0) { - atracIDTypes[next++] = PSP_MODE_AT_3_PLUS; + atracContextTypes[next++] = PSP_MODE_AT_3_PLUS; } } for (int i = 0; i < at3Count; ++i) { space -= 1; if (space >= 0) { - atracIDTypes[next++] = PSP_MODE_AT_3; + atracContextTypes[next++] = PSP_MODE_AT_3; } } // If we ran out of space, we still initialize some, but return an error. int result = space >= 0 ? 0 : (int)SCE_KERNEL_ERROR_OUT_OF_MEMORY; if (atracInited || next == 0) { - INFO_LOG(ME, "sceAtracReinit(%d, %d)", at3Count, at3plusCount); atracInited = true; - return result; + return hleLogSuccessInfoI(Log::ME, result); } else { - INFO_LOG(ME, "sceAtracReinit(%d, %d): init", at3Count, at3plusCount); atracInited = true; - return hleDelayResult(result, "atrac reinit", 400); + return hleDelayResult(hleLogSuccessInfoI(Log::ME, result), "atrac reinit", 400); } } static int sceAtracGetOutputChannel(int atracID, u32 outputChanPtr) { - Atrac *atrac = getAtrac(atracID); - if (!atrac) { - ERROR_LOG(ME, "sceAtracGetOutputChannel(%i, %08x): bad atrac ID", atracID, outputChanPtr); - return ATRAC_ERROR_BAD_ATRACID; - } else if (!atrac->dataBuf_) { - ERROR_LOG(ME, "sceAtracGetOutputChannel(%i, %08x): no data", atracID, outputChanPtr); - return ATRAC_ERROR_NO_DATA; + AtracBase *atrac = getAtrac(atracID); + u32 err = AtracValidateData(atrac); + if (err != 0) { + // Already logged. + return err; + } + if (Memory::IsValidAddress(outputChanPtr)) { + Memory::WriteUnchecked_U32(atrac->GetOutputChannels(), outputChanPtr); + return hleLogSuccessI(Log::ME, 0); } else { - DEBUG_LOG(ME, "sceAtracGetOutputChannel(%i, %08x)", atracID, outputChanPtr); - if (Memory::IsValidAddress(outputChanPtr)) - Memory::Write_U32(atrac->outputChannels_, outputChanPtr); + return hleLogError(Log::ME, 0, "invalid address"); } - return 0; } static int sceAtracIsSecondBufferNeeded(int atracID) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); u32 err = AtracValidateManaged(atrac); if (err != 0) { // Already logged. @@ -2225,17 +762,18 @@ static int sceAtracIsSecondBufferNeeded(int atracID) { } // Note that this returns true whether the buffer is already set or not. - int needed = atrac->bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER ? 1 : 0; - return hleLogSuccessI(ME, needed); + int needed = atrac->BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER ? 1 : 0; + return hleLogSuccessI(Log::ME, needed); } static int sceAtracSetMOutHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u32 bufferSize) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); + // Don't use AtracValidate* here. if (!atrac) { - return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); } if (readSize > bufferSize) { - return hleLogError(ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); + return hleLogError(Log::ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); } int ret = atrac->Analyze(buffer, readSize); @@ -2243,23 +781,21 @@ static int sceAtracSetMOutHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u // Already logged. return ret; } - if (atrac->channels_ != 1) { + if (atrac->GetTrack().channels != 1) { // It seems it still sets the data. - atrac->outputChannels_ = 2; - _AtracSetData(atrac, buffer, readSize, bufferSize); - return hleReportError(ME, ATRAC_ERROR_NOT_MONO, "not mono data"); + atrac->SetData(buffer, readSize, bufferSize, 2, 0); + return hleReportError(Log::ME, ATRAC_ERROR_NOT_MONO, "not mono data"); } else { - atrac->outputChannels_ = 1; - ret = _AtracSetData(atracID, buffer, readSize, bufferSize); + return _AtracSetData(atracID, buffer, readSize, bufferSize, 1, false); } - return ret; } // Note: This doesn't seem to be part of any available libatrac3plus library. static u32 sceAtracSetMOutData(int atracID, u32 buffer, u32 bufferSize) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); + // Don't use AtracValidate* here. if (!atrac) { - return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); } int ret = atrac->Analyze(buffer, bufferSize); @@ -2267,68 +803,63 @@ static u32 sceAtracSetMOutData(int atracID, u32 buffer, u32 bufferSize) { // Already logged. return ret; } - if (atrac->channels_ != 1) { + if (atrac->GetTrack().channels != 1) { // It seems it still sets the data. - atrac->outputChannels_ = 2; - _AtracSetData(atrac, buffer, bufferSize, bufferSize); - return hleReportError(ME, ATRAC_ERROR_NOT_MONO, "not mono data"); + atrac->SetData(buffer, bufferSize, bufferSize, 2, 0); + return hleReportError(Log::ME, ATRAC_ERROR_NOT_MONO, "not mono data"); } else { - atrac->outputChannels_ = 1; - ret = _AtracSetData(atracID, buffer, bufferSize, bufferSize); + return _AtracSetData(atracID, buffer, bufferSize, bufferSize, 1, false); } - return ret; } // Note: This doesn't seem to be part of any available libatrac3plus library. static int sceAtracSetMOutDataAndGetID(u32 buffer, u32 bufferSize) { - Atrac *atrac = new Atrac(); + AtracBase *atrac = allocAtrac(); int ret = atrac->Analyze(buffer, bufferSize); if (ret < 0) { // Already logged. delete atrac; return ret; } - if (atrac->channels_ != 1) { + if (atrac->GetTrack().channels != 1) { delete atrac; - return hleReportError(ME, ATRAC_ERROR_NOT_MONO, "not mono data"); + return hleReportError(Log::ME, ATRAC_ERROR_NOT_MONO, "not mono data"); } int atracID = createAtrac(atrac); if (atracID < 0) { delete atrac; - return hleLogError(ME, atracID, "no free ID"); + return hleLogError(Log::ME, atracID, "no free ID"); } - atrac->outputChannels_ = 1; - return _AtracSetData(atracID, buffer, bufferSize, bufferSize, true); + return _AtracSetData(atracID, buffer, bufferSize, bufferSize, 1, true); } static int sceAtracSetMOutHalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 bufferSize) { if (readSize > bufferSize) { - return hleLogError(ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); + return hleLogError(Log::ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); } - Atrac *atrac = new Atrac(); + AtracBase *atrac = allocAtrac(); int ret = atrac->Analyze(buffer, readSize); if (ret < 0) { // Already logged. delete atrac; return ret; } - if (atrac->channels_ != 1) { + if (atrac->GetTrack().channels != 1) { delete atrac; - return hleReportError(ME, ATRAC_ERROR_NOT_MONO, "not mono data"); + return hleReportError(Log::ME, ATRAC_ERROR_NOT_MONO, "not mono data"); } int atracID = createAtrac(atrac); if (atracID < 0) { delete atrac; - return hleLogError(ME, atracID, "no free ID"); + return hleLogError(Log::ME, atracID, "no free ID"); } - atrac->outputChannels_ = 1; - return _AtracSetData(atracID, buffer, readSize, bufferSize, true); + return _AtracSetData(atracID, buffer, readSize, bufferSize, 1, true); } static int sceAtracSetAA3DataAndGetID(u32 buffer, u32 bufferSize, u32 fileSize, u32 metadataSizeAddr) { - Atrac *atrac = new Atrac(); + AtracBase *atrac = allocAtrac(); int ret = atrac->AnalyzeAA3(buffer, bufferSize, fileSize); if (ret < 0) { // Already logged. @@ -2338,77 +869,30 @@ static int sceAtracSetAA3DataAndGetID(u32 buffer, u32 bufferSize, u32 fileSize, int atracID = createAtrac(atrac); if (atracID < 0) { delete atrac; - return hleLogError(ME, atracID, "no free ID"); + return hleLogError(Log::ME, atracID, "no free ID"); } - atrac->outputChannels_ = 2; - return _AtracSetData(atracID, buffer, bufferSize, bufferSize, true); -} - -int _AtracGetIDByContext(u32 contextAddr) { - int atracID = (int)Memory::Read_U32(contextAddr + 0xfc); -#ifdef USE_FFMPEG - Atrac *atrac = getAtrac(atracID); - if (atrac) - __AtracUpdateOutputMode(atrac, 1); -#endif // USE_FFMPEG - return atracID; -} - -void _AtracGenerateContext(Atrac *atrac) { - SceAtracId *context = atrac->context_; - context->info.buffer = atrac->first_.addr; - context->info.bufferByte = atrac->bufferMaxSize_; - context->info.secondBuffer = atrac->second_.addr; - context->info.secondBufferByte = atrac->second_.size; - context->info.codec = atrac->codecType_; - context->info.loopNum = atrac->loopNum_; - context->info.loopStart = atrac->loopStartSample_ > 0 ? atrac->loopStartSample_ : 0; - context->info.loopEnd = atrac->loopEndSample_ > 0 ? atrac->loopEndSample_ : 0; - - // Note that we read in the state when loading the atrac object, so it's safe - // to update it back here all the time. Some games, like Sol Trigger, change it. - // TODO: Should we just keep this in PSP ram then, or something? - context->info.state = atrac->bufferState_; - if (atrac->firstSampleOffset_ != 0) { - context->info.samplesPerChan = atrac->firstSampleOffset_ + atrac->FirstOffsetExtra(); - } else { - context->info.samplesPerChan = (atrac->codecType_ == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); - } - context->info.sampleSize = atrac->bytesPerFrame_; - context->info.numChan = atrac->channels_; - context->info.dataOff = atrac->dataOff_; - context->info.endSample = atrac->endSample_ + atrac->firstSampleOffset_ + atrac->FirstOffsetExtra(); - context->info.dataEnd = atrac->first_.filesize; - context->info.curOff = atrac->first_.fileoffset; - context->info.decodePos = atrac->DecodePosBySample(atrac->currentSample_); - context->info.streamDataByte = atrac->first_.size - atrac->dataOff_; - - u8 *buf = (u8 *)context; - *(u32_le *)(buf + 0xfc) = atrac->atracID_; - - NotifyMemInfo(MemBlockFlags::WRITE, atrac->context_.ptr, sizeof(SceAtracId), "AtracContext"); + return _AtracSetData(atracID, buffer, bufferSize, bufferSize, 2, true); } static u32 _sceAtracGetContextAddress(int atracID) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); if (!atrac) { - ERROR_LOG(ME, "_sceAtracGetContextAddress(%i): bad atrac id", atracID); + ERROR_LOG(Log::ME, "_sceAtracGetContextAddress(%i): bad atrac id", atracID); return 0; } if (!atrac->context_.IsValid()) { // allocate a new context_ - u32 contextsize = 256; - atrac->context_ = kernelMemory.Alloc(contextsize, false, StringFromFormat("AtracCtx/%d", atracID).c_str()); + u32 contextSize = sizeof(SceAtracContext); + // Note that Alloc can increase contextSize to the "grain" size. + atrac->context_ = kernelMemory.Alloc(contextSize, false, StringFromFormat("AtracCtx/%d", atracID).c_str()); if (atrac->context_.IsValid()) - Memory::Memset(atrac->context_.ptr, 0, 256, "AtracContextClear"); - - WARN_LOG(ME, "%08x=_sceAtracGetContextAddress(%i): allocated new context", atrac->context_.ptr, atracID); + Memory::Memset(atrac->context_.ptr, 0, contextSize, "AtracContextClear"); + WARN_LOG(Log::ME, "%08x=_sceAtracGetContextAddress(%i): allocated new context", atrac->context_.ptr, atracID); } else - WARN_LOG(ME, "%08x=_sceAtracGetContextAddress(%i)", atrac->context_.ptr, atracID); - if (atrac->context_.IsValid()) - _AtracGenerateContext(atrac); + WARN_LOG(Log::ME, "%08x=_sceAtracGetContextAddress(%i)", atrac->context_.ptr, atracID); + atrac->WriteContextToPSPMem(); return atrac->context_.ptr; } @@ -2417,8 +901,8 @@ struct At3HeaderMap { u16 channels; u8 jointStereo; - bool Matches(const Atrac *at) const { - return bytes == at->bytesPerFrame_ && channels == at->channels_; + bool Matches(const AtracBase *at) const { + return bytes == at->GetTrack().BytesPerFrame() && channels == at->GetTrack().channels; } }; @@ -2432,136 +916,74 @@ static const At3HeaderMap at3HeaderMap[] = { { 0x00C0, 2, 1 }, // 66 kbps stereo }; -static bool initAT3Decoder(Atrac *atrac) { - atrac->bitrate_ = (atrac->bytesPerFrame_ * 352800) / 1000; - atrac->bitrate_ = (atrac->bitrate_ + 511) >> 10; - atrac->jointStereo_ = false; - - // See if we can match the actual jointStereo value. - for (size_t i = 0; i < ARRAY_SIZE(at3HeaderMap); ++i) { - if (at3HeaderMap[i].Matches(atrac)) { - atrac->jointStereo_ = at3HeaderMap[i].jointStereo; - return true; - } - } - return false; -} - -static void initAT3plusDecoder(Atrac *atrac) { - atrac->bitrate_ = (atrac->bytesPerFrame_ * 352800) / 1000; - atrac->bitrate_ = ((atrac->bitrate_ >> 11) + 8) & 0xFFFFFFF0; - atrac->jointStereo_ = false; -} - static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); if (!atrac) { - return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); - } - - if (atrac->codecType_ != PSP_MODE_AT_3 && atrac->codecType_ != PSP_MODE_AT_3_PLUS) { - // TODO: Error code? Was silently 0 before, and just didn't work. Shouldn't ever happen... - return hleReportError(ME, ATRAC_ERROR_UNKNOWN_FORMAT, "bad codec type"); + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); } if (!Memory::IsValidAddress(paramsAddr)) { // TODO: Returning zero as code was before. Needs testing. - return hleReportError(ME, 0, "invalid pointers"); + return hleReportError(Log::ME, 0, "invalid pointers"); } - atrac->channels_ = Memory::Read_U32(paramsAddr); - atrac->outputChannels_ = Memory::Read_U32(paramsAddr + 4); - atrac->bufferMaxSize_ = Memory::Read_U32(paramsAddr + 8); - atrac->bytesPerFrame_ = atrac->bufferMaxSize_; - atrac->first_.writableBytes = atrac->bytesPerFrame_; - atrac->ResetData(); - - const char *codecName = atrac->codecType_ == PSP_MODE_AT_3 ? "atrac3" : "atrac3+"; - const char *channelName = atrac->channels_ == 1 ? "mono" : "stereo"; - - if (atrac->codecType_ == PSP_MODE_AT_3) { - if (!initAT3Decoder(atrac)) { - ERROR_LOG_REPORT(ME, "AT3 header map lacks entry for bpf: %i channels: %i", atrac->bytesPerFrame_, atrac->channels_); + bool jointStereo = false; + if (atrac->GetTrack().codecType == PSP_MODE_AT_3) { + // See if we can match the actual jointStereo value. + bool found = false; + for (size_t i = 0; i < ARRAY_SIZE(at3HeaderMap); ++i) { + if (at3HeaderMap[i].Matches(atrac)) { + jointStereo = at3HeaderMap[i].jointStereo; + found = true; + } + } + if (!found) { + ERROR_LOG_REPORT(Log::ME, "AT3 header map lacks entry for bpf: %i channels: %i", atrac->GetTrack().BytesPerFrame(), atrac->GetTrack().channels); // TODO: Should we return an error code for these values? } - } else if (atrac->codecType_ == PSP_MODE_AT_3_PLUS) { - initAT3plusDecoder(atrac); } - atrac->dataOff_ = 0; - atrac->first_.size = 0; - atrac->first_.filesize = atrac->bytesPerFrame_; - atrac->bufferState_ = ATRAC_STATUS_LOW_LEVEL; + atrac->InitLowLevel(paramsAddr, jointStereo); - atrac->dataBuf_ = new u8[atrac->first_.filesize + overAllocBytes]; - memset(atrac->dataBuf_, 0, atrac->first_.filesize + overAllocBytes); - atrac->currentSample_ = 0; - int ret = __AtracSetContext(atrac); - - if (atrac->context_.IsValid()) { - _AtracGenerateContext(atrac); - } - - if (ret < 0) { - // Already logged. - return ret; - } - return hleLogSuccessInfoI(ME, ret, "%s %s audio", codecName, channelName); + const char *codecName = atrac->GetTrack().codecType == PSP_MODE_AT_3 ? "atrac3" : "atrac3+"; + const char *channelName = atrac->GetTrack().channels == 1 ? "mono" : "stereo"; + return hleLogSuccessInfoI(Log::ME, 0, "%s %s audio", codecName, channelName); } static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedAddr, u32 samplesAddr, u32 sampleBytesAddr) { auto srcp = PSPPointer::Create(sourceAddr); auto srcConsumed = PSPPointer::Create(sourceBytesConsumedAddr); - auto outp = PSPPointer::Create(samplesAddr); + auto outp = PSPPointer::Create(samplesAddr); auto outWritten = PSPPointer::Create(sampleBytesAddr); - Atrac *atrac = getAtrac(atracID); + AtracBase *atrac = getAtrac(atracID); if (!atrac) { - return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); + return hleLogError(Log::ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); } if (!srcp.IsValid() || !srcConsumed.IsValid() || !outp.IsValid() || !outWritten.IsValid()) { // TODO: Returning zero as code was before. Needs testing. - return hleReportError(ME, 0, "invalid pointers"); + return hleReportError(Log::ME, 0, "invalid pointers"); } - int numSamples = (atrac->codecType_ == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + int bytesConsumed = 0; + int outSamples = 0; + int channels = atrac->GetOutputChannels(); + atrac->Decoder()->Decode(srcp, atrac->GetTrack().BytesPerFrame(), &bytesConsumed, channels, outp, &outSamples); + int bytesWritten = outSamples * channels * sizeof(int16_t); + *srcConsumed = bytesConsumed; + *outWritten = bytesWritten; - if (!atrac->failedDecode_) { - atrac->FillLowLevelPacket(srcp); - - AtracDecodeResult res = atrac->DecodePacket(); - if (res == ATDECODE_GOTFRAME) { -#ifdef USE_FFMPEG - // got a frame - numSamples = atrac->frame_->nb_samples; - - u8 *out = outp; - int avret = swr_convert(atrac->swrCtx_, &out, numSamples, - (const u8**)atrac->frame_->extended_data, numSamples); - u32 outBytes = numSamples * atrac->outputChannels_ * sizeof(s16); - NotifyMemInfo(MemBlockFlags::WRITE, samplesAddr, outBytes, "AtracLowLevelDecode"); - if (avret < 0) { - ERROR_LOG(ME, "swr_convert: Error while converting %d", avret); - } -#endif // USE_FFMPEG - } else { - // TODO: Error code otherwise? - } - } - - *outWritten = numSamples * atrac->outputChannels_ * sizeof(s16); - *srcConsumed = atrac->bytesPerFrame_; - - return hleLogDebug(ME, hleDelayResult(0, "low level atrac decode data", atracDecodeDelay)); + NotifyMemInfo(MemBlockFlags::WRITE, samplesAddr, bytesWritten, "AtracLowLevelDecode"); + return hleLogDebug(Log::ME, hleDelayResult(0, "low level atrac decode data", atracDecodeDelay)); } static int sceAtracSetAA3HalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 bufferSize, u32 fileSize) { if (readSize > bufferSize) { - return hleLogError(ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); + return hleLogError(Log::ME, ATRAC_ERROR_INCORRECT_READ_SIZE, "read size too large"); } - Atrac *atrac = new Atrac(); + AtracBase *atrac = allocAtrac(); int ret = atrac->AnalyzeAA3(buffer, readSize, fileSize); if (ret < 0) { // Already logged. @@ -2571,11 +993,36 @@ static int sceAtracSetAA3HalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 buf int atracID = createAtrac(atrac); if (atracID < 0) { delete atrac; - return hleLogError(ME, atracID, "no free ID"); + return hleLogError(Log::ME, atracID, "no free ID"); } - atrac->outputChannels_ = 2; - return _AtracSetData(atracID, buffer, readSize, bufferSize, true); + return _AtracSetData(atracID, buffer, readSize, bufferSize, 2, true); +} + +// External interface used by sceSas' AT3 integration. + +u32 AtracSasAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) { + AtracBase *atrac = getAtrac(atracID); + if (!atrac) + return 0; + return atrac->AddStreamDataSas(bufPtr, bytesToAdd); +} + +u32 AtracSasDecodeData(int atracID, u8* outbuf, u32 outbufPtr, u32 *SamplesNum, u32* finish, int *remains) { + AtracBase *atrac = getAtrac(atracID); + if (!atrac) + return 0; + return atrac->DecodeData(outbuf, outbufPtr, SamplesNum, finish, remains); +} + +int AtracSasGetIDByContext(u32 contextAddr) { + int atracID = (int)Memory::Read_U32(contextAddr + 0xfc); + // Restored old hack here that forces outputChannels_ to 1, since sceSas expects mono output, unlike normal usage. + // This is for savestate compatibility. + // I think it would be better to simply pass in a 1 as a parameter to atrac->DecodeData in AtracSasDecodeData above. + AtracBase *atrac = getAtrac(atracID); + atrac->SetOutputChannels(1); + return atracID; } const HLEFunction sceAtrac3plus[] = { diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index f0914c1c63..f29c59f798 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -25,6 +25,7 @@ void Register_sceAtrac3plus(); void __AtracInit(); void __AtracDoState(PointerWrap &p); void __AtracShutdown(); +void __AtracLoadModule(int version, u32 crc); enum AtracStatus : u8 { ATRAC_STATUS_NO_DATA = 1, @@ -48,8 +49,7 @@ typedef AtracStatus AtracStatus_le; typedef swap_struct_t > AtracStatus_le; #endif -typedef struct -{ +struct SceAtracIdInfo { u32_le decodePos; // 0 u32_le endSample; // 4 u32_le loopStart; // 8 @@ -76,19 +76,16 @@ typedef struct u32_le secondBufferByte; // 68 // make sure the size is 128 u8 unk[56]; -} SceAtracIdInfo; +}; -typedef struct -{ +struct SceAtracContext { // size 128 SceAudiocodecCodec codec; // size 128 SceAtracIdInfo info; -} SceAtracId; +}; -// provide some decoder interface - -u32 _AtracAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd); -u32 _AtracDecodeData(int atracID, u8* outbuf, u32 outbufPtr, u32 *SamplesNum, u32* finish, int *remains); -int _AtracGetIDByContext(u32 contextAddr); -void __AtracLoadModule(int version, u32 crc); +// External interface used by sceSas. +u32 AtracSasAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd); +u32 AtracSasDecodeData(int atracID, u8* outbuf, u32 outbufPtr, u32 *SamplesNum, u32* finish, int *remains); +int AtracSasGetIDByContext(u32 contextAddr); diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index beb06566dd..cacdb9e315 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -86,16 +86,16 @@ void AudioChannel::clear() // max or 50%? static u32 sceAudioOutputBlocking(u32 chan, int vol, u32 samplePtr) { if (vol > 0xFFFF) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputBlocking() - invalid volume"); + ERROR_LOG(Log::sceAudio, "sceAudioOutputBlocking() - invalid volume"); return SCE_ERROR_AUDIO_INVALID_VOLUME; } else if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputBlocking() - bad channel"); + ERROR_LOG(Log::sceAudio, "sceAudioOutputBlocking() - bad channel"); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } else if (!chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputBlocking() - channel not reserved"); + ERROR_LOG(Log::sceAudio, "sceAudioOutputBlocking() - channel not reserved"); return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT; } else { - DEBUG_LOG(SCEAUDIO, "sceAudioOutputBlocking(%08x, %08x, %08x)", chan, vol, samplePtr); + DEBUG_LOG(Log::sceAudio, "sceAudioOutputBlocking(%08x, %08x, %08x)", chan, vol, samplePtr); if (vol >= 0) { chans[chan].leftVolume = vol; chans[chan].rightVolume = vol; @@ -109,13 +109,13 @@ static u32 sceAudioOutputPannedBlocking(u32 chan, int leftvol, int rightvol, u32 int result = 0; // For some reason, this is the only one that checks for negative. if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputPannedBlocking() - invalid volume"); + ERROR_LOG(Log::sceAudio, "sceAudioOutputPannedBlocking() - invalid volume"); result = SCE_ERROR_AUDIO_INVALID_VOLUME; } else if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputPannedBlocking() - bad channel"); + ERROR_LOG(Log::sceAudio, "sceAudioOutputPannedBlocking() - bad channel"); result = SCE_ERROR_AUDIO_INVALID_CHANNEL; } else if (!chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputPannedBlocking() - channel not reserved"); + ERROR_LOG(Log::sceAudio, "sceAudioOutputPannedBlocking() - channel not reserved"); result = SCE_ERROR_AUDIO_CHANNEL_NOT_INIT; } else { if (leftvol >= 0) { @@ -128,23 +128,23 @@ static u32 sceAudioOutputPannedBlocking(u32 chan, int leftvol, int rightvol, u32 result = __AudioEnqueue(chans[chan], chan, true); } - DEBUG_LOG(SCEAUDIO, "%08x = sceAudioOutputPannedBlocking(%08x, %08x, %08x, %08x)", result, chan, leftvol, rightvol, samplePtr); + DEBUG_LOG(Log::sceAudio, "%08x = sceAudioOutputPannedBlocking(%08x, %08x, %08x, %08x)", result, chan, leftvol, rightvol, samplePtr); return result; } static u32 sceAudioOutput(u32 chan, int vol, u32 samplePtr) { if (vol > 0xFFFF) { - ERROR_LOG(SCEAUDIO, "sceAudioOutput() - invalid volume"); + ERROR_LOG(Log::sceAudio, "sceAudioOutput() - invalid volume"); return SCE_ERROR_AUDIO_INVALID_VOLUME; } else if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioOutput() - bad channel"); + ERROR_LOG(Log::sceAudio, "sceAudioOutput() - bad channel"); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } else if (!chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioOutput(%08x, %08x, %08x) - channel not reserved", chan, vol, samplePtr); + ERROR_LOG(Log::sceAudio, "sceAudioOutput(%08x, %08x, %08x) - channel not reserved", chan, vol, samplePtr); return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT; } else { - DEBUG_LOG(SCEAUDIO, "sceAudioOutput(%08x, %08x, %08x)", chan, vol, samplePtr); + DEBUG_LOG(Log::sceAudio, "sceAudioOutput(%08x, %08x, %08x)", chan, vol, samplePtr); if (vol >= 0) { chans[chan].leftVolume = vol; chans[chan].rightVolume = vol; @@ -156,16 +156,16 @@ static u32 sceAudioOutput(u32 chan, int vol, u32 samplePtr) { static u32 sceAudioOutputPanned(u32 chan, int leftvol, int rightvol, u32 samplePtr) { if (leftvol > 0xFFFF || rightvol > 0xFFFF) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputPanned() - invalid volume"); + ERROR_LOG(Log::sceAudio, "sceAudioOutputPanned() - invalid volume"); return SCE_ERROR_AUDIO_INVALID_VOLUME; } else if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputPanned() - bad channel"); + ERROR_LOG(Log::sceAudio, "sceAudioOutputPanned() - bad channel"); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } else if (!chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioOutputPanned(%08x, %08x, %08x, %08x) - channel not reserved", chan, leftvol, rightvol, samplePtr); + ERROR_LOG(Log::sceAudio, "sceAudioOutputPanned(%08x, %08x, %08x, %08x) - channel not reserved", chan, leftvol, rightvol, samplePtr); return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT; } else { - DEBUG_LOG(SCEAUDIO, "sceAudioOutputPanned(%08x, %08x, %08x, %08x)", chan, leftvol, rightvol, samplePtr); + DEBUG_LOG(Log::sceAudio, "sceAudioOutputPanned(%08x, %08x, %08x, %08x)", chan, leftvol, rightvol, samplePtr); if (leftvol >= 0) { chans[chan].leftVolume = leftvol; } @@ -179,21 +179,21 @@ static u32 sceAudioOutputPanned(u32 chan, int leftvol, int rightvol, u32 sampleP static int sceAudioGetChannelRestLen(u32 chan) { if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioGetChannelRestLen(%08x) - bad channel", chan); + ERROR_LOG(Log::sceAudio, "sceAudioGetChannelRestLen(%08x) - bad channel", chan); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } int remainingSamples = (int)chanSampleQueues[chan].size() / 2; - VERBOSE_LOG(SCEAUDIO, "%d=sceAudioGetChannelRestLen(%08x)", remainingSamples, chan); + VERBOSE_LOG(Log::sceAudio, "%d=sceAudioGetChannelRestLen(%08x)", remainingSamples, chan); return remainingSamples; } static int sceAudioGetChannelRestLength(u32 chan) { if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioGetChannelRestLength(%08x) - bad channel", chan); + ERROR_LOG(Log::sceAudio, "sceAudioGetChannelRestLength(%08x) - bad channel", chan); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } int remainingSamples = (int)chanSampleQueues[chan].size() / 2; - VERBOSE_LOG(SCEAUDIO, "%d=sceAudioGetChannelRestLength(%08x)", remainingSamples, chan); + VERBOSE_LOG(Log::sceAudio, "%d=sceAudioGetChannelRestLength(%08x)", remainingSamples, chan); return remainingSamples; } @@ -209,28 +209,28 @@ static u32 sceAudioChReserve(int chan, u32 sampleCount, u32 format) { if (chan < 0) { chan = GetFreeChannel(); if (chan < 0) { - ERROR_LOG(SCEAUDIO, "sceAudioChReserve - no channels remaining"); + ERROR_LOG(Log::sceAudio, "sceAudioChReserve - no channels remaining"); return SCE_ERROR_AUDIO_NO_CHANNELS_AVAILABLE; } } if ((u32)chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioChReserve(%08x, %08x, %08x) - bad channel", chan, sampleCount, format); + ERROR_LOG(Log::sceAudio, "sceAudioChReserve(%08x, %08x, %08x) - bad channel", chan, sampleCount, format); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } if ((sampleCount & 63) != 0 || sampleCount == 0 || sampleCount > PSP_AUDIO_SAMPLE_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioChReserve(%08x, %08x, %08x) - invalid sample count", chan, sampleCount, format); + ERROR_LOG(Log::sceAudio, "sceAudioChReserve(%08x, %08x, %08x) - invalid sample count", chan, sampleCount, format); return SCE_ERROR_AUDIO_OUTPUT_SAMPLE_DATA_SIZE_NOT_ALIGNED; } if (format != PSP_AUDIO_FORMAT_MONO && format != PSP_AUDIO_FORMAT_STEREO) { - ERROR_LOG(SCEAUDIO, "sceAudioChReserve(%08x, %08x, %08x) - invalid format", chan, sampleCount, format); + ERROR_LOG(Log::sceAudio, "sceAudioChReserve(%08x, %08x, %08x) - invalid format", chan, sampleCount, format); return SCE_ERROR_AUDIO_INVALID_FORMAT; } if (chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioChReserve - reserve channel failed"); + ERROR_LOG(Log::sceAudio, "sceAudioChReserve - reserve channel failed"); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } - DEBUG_LOG(SCEAUDIO, "sceAudioChReserve(%08x, %08x, %08x)", chan, sampleCount, format); + DEBUG_LOG(Log::sceAudio, "sceAudioChReserve(%08x, %08x, %08x)", chan, sampleCount, format); chans[chan].sampleCount = sampleCount; chans[chan].format = format; chans[chan].reserved = true; @@ -241,47 +241,47 @@ static u32 sceAudioChReserve(int chan, u32 sampleCount, u32 format) { static u32 sceAudioChRelease(u32 chan) { if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioChRelease(%i) - bad channel", chan); + ERROR_LOG(Log::sceAudio, "sceAudioChRelease(%i) - bad channel", chan); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } if (!chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioChRelease(%i) - channel not reserved", chan); + ERROR_LOG(Log::sceAudio, "sceAudioChRelease(%i) - channel not reserved", chan); return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; } // TODO: Does this error if busy? chans[chan].reset(); chans[chan].reserved = false; - return hleLogSuccessI(SCEAUDIO, 0); + return hleLogSuccessI(Log::sceAudio, 0); } static u32 sceAudioSetChannelDataLen(u32 chan, u32 len) { int result = 0; if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioSetChannelDataLen(%08x, %08x) - bad channel", chan, len); + ERROR_LOG(Log::sceAudio, "sceAudioSetChannelDataLen(%08x, %08x) - bad channel", chan, len); result = SCE_ERROR_AUDIO_INVALID_CHANNEL; } else if (!chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioSetChannelDataLen(%08x, %08x) - channel not reserved", chan, len); + ERROR_LOG(Log::sceAudio, "sceAudioSetChannelDataLen(%08x, %08x) - channel not reserved", chan, len); result = SCE_ERROR_AUDIO_CHANNEL_NOT_INIT; } else if ((len & 63) != 0 || len == 0 || len > PSP_AUDIO_SAMPLE_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioSetChannelDataLen(%08x, %08x) - invalid sample count", chan, len); + ERROR_LOG(Log::sceAudio, "sceAudioSetChannelDataLen(%08x, %08x) - invalid sample count", chan, len); result = SCE_ERROR_AUDIO_OUTPUT_SAMPLE_DATA_SIZE_NOT_ALIGNED; } else { chans[chan].sampleCount = len; } - DEBUG_LOG(SCEAUDIO, "%08x = sceAudioSetChannelDataLen(%08x, %08x)", result , chan, len); + DEBUG_LOG(Log::sceAudio, "%08x = sceAudioSetChannelDataLen(%08x, %08x)", result , chan, len); return result; } static u32 sceAudioChangeChannelConfig(u32 chan, u32 format) { if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioChangeChannelConfig(%08x, %08x) - invalid channel number", chan, format); + ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelConfig(%08x, %08x) - invalid channel number", chan, format); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } else if (!chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioChangeChannelConfig(%08x, %08x) - channel not reserved", chan, format); + ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelConfig(%08x, %08x) - channel not reserved", chan, format); return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; } else { - DEBUG_LOG(SCEAUDIO, "sceAudioChangeChannelConfig(%08x, %08x)", chan, format); + DEBUG_LOG(Log::sceAudio, "sceAudioChangeChannelConfig(%08x, %08x)", chan, format); chans[chan].format = format; return 0; } @@ -289,16 +289,16 @@ static u32 sceAudioChangeChannelConfig(u32 chan, u32 format) { static u32 sceAudioChangeChannelVolume(u32 chan, u32 leftvol, u32 rightvol) { if (leftvol > 0xFFFF || rightvol > 0xFFFF) { - ERROR_LOG(SCEAUDIO, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - invalid volume", chan, leftvol, rightvol); + ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - invalid volume", chan, leftvol, rightvol); return SCE_ERROR_AUDIO_INVALID_VOLUME; } else if (chan >= PSP_AUDIO_CHANNEL_MAX) { - ERROR_LOG(SCEAUDIO, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - invalid channel number", chan, leftvol, rightvol); + ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - invalid channel number", chan, leftvol, rightvol); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } else if (!chans[chan].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - channel not reserved", chan, leftvol, rightvol); + ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - channel not reserved", chan, leftvol, rightvol); return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; } else { - DEBUG_LOG(SCEAUDIO, "sceAudioChangeChannelVolume(%08x, %08x, %08x)", chan, leftvol, rightvol); + DEBUG_LOG(Log::sceAudio, "sceAudioChangeChannelVolume(%08x, %08x, %08x)", chan, leftvol, rightvol); chans[chan].leftVolume = leftvol; chans[chan].rightVolume = rightvol; return 0; @@ -306,13 +306,13 @@ static u32 sceAudioChangeChannelVolume(u32 chan, u32 leftvol, u32 rightvol) { } static u32 sceAudioInit() { - DEBUG_LOG(SCEAUDIO, "sceAudioInit()"); + DEBUG_LOG(Log::sceAudio, "sceAudioInit()"); // Don't need to do anything return 0; } static u32 sceAudioEnd() { - DEBUG_LOG(SCEAUDIO, "sceAudioEnd()"); + DEBUG_LOG(Log::sceAudio, "sceAudioEnd()"); // Don't need to do anything return 0; } @@ -322,27 +322,27 @@ static u32 sceAudioOutput2Reserve(u32 sampleCount) { // This seems to ignore the MSB, for some reason. sampleCount &= 0x7FFFFFFF; if (sampleCount < 17 || sampleCount > 4111) { - return hleLogError(SCEAUDIO, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count"); + return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count"); } else if (chan.reserved) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved"); } chan.sampleCount = sampleCount; chan.format = PSP_AUDIO_FORMAT_STEREO; chan.reserved = true; __AudioSetSRCFrequency(0); - return hleLogSuccessI(SCEAUDIO, 0); + return hleLogSuccessI(Log::sceAudio, 0); } static u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) { // Note: 0xFFFFF, not 0xFFFF! if (vol > 0xFFFFF) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume"); } auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2]; if (!chan.reserved) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); } chan.leftVolume = vol; @@ -352,58 +352,58 @@ static u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) { hleEatCycles(10000); int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_OUTPUT2, true); if (result < 0) - return hleLogError(SCEAUDIO, result); - return hleLogSuccessI(SCEAUDIO, result); + return hleLogError(Log::sceAudio, result); + return hleLogSuccessI(Log::sceAudio, result); } static u32 sceAudioOutput2ChangeLength(u32 sampleCount) { auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2]; if (!chan.reserved) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); } chan.sampleCount = sampleCount; - return hleLogSuccessI(SCEAUDIO, 0); + return hleLogSuccessI(Log::sceAudio, 0); } static u32 sceAudioOutput2GetRestSample() { auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2]; if (!chan.reserved) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); } u32 size = (u32)chanSampleQueues[PSP_AUDIO_CHANNEL_OUTPUT2].size() / 2; if (size > chan.sampleCount) { // If ChangeLength reduces the size, it still gets output but this return is clamped. size = chan.sampleCount; } - return hleLogSuccessI(SCEAUDIO, size); + return hleLogSuccessI(Log::sceAudio, size); } static u32 sceAudioOutput2Release() { auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2]; if (!chan.reserved) - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); if (!chanSampleQueues[PSP_AUDIO_CHANNEL_OUTPUT2].empty()) - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy"); chan.reset(); chan.reserved = false; - return hleLogSuccessI(SCEAUDIO, 0); + return hleLogSuccessI(Log::sceAudio, 0); } static u32 sceAudioSetFrequency(u32 freq) { // TODO: Not available from user code. if (freq == 44100 || freq == 48000) { - INFO_LOG(SCEAUDIO, "sceAudioSetFrequency(%08x)", freq); + INFO_LOG(Log::sceAudio, "sceAudioSetFrequency(%08x)", freq); __AudioSetOutputFrequency(freq); return 0; } else { - ERROR_LOG(SCEAUDIO, "sceAudioSetFrequency(%08x) - invalid frequency (must be 44.1 or 48 khz)", freq); + ERROR_LOG(Log::sceAudio, "sceAudioSetFrequency(%08x) - invalid frequency (must be 44.1 or 48 khz)", freq); return SCE_ERROR_AUDIO_INVALID_FREQUENCY; } } static u32 sceAudioSetVolumeOffset() { - ERROR_LOG(SCEAUDIO, "UNIMPL sceAudioSetVolumeOffset()"); + ERROR_LOG(Log::sceAudio, "UNIMPL sceAudioSetVolumeOffset()"); return 0; } @@ -420,15 +420,15 @@ static u32 sceAudioSRCChReserve(u32 sampleCount, u32 freq, u32 format) { // This seems to ignore the MSB, for some reason. sampleCount &= 0x7FFFFFFF; if (format == 4) { - return hleReportError(SCEAUDIO, PSP_AUDIO_ERROR_SRC_FORMAT_4, "unexpected format"); + return hleReportError(Log::sceAudio, PSP_AUDIO_ERROR_SRC_FORMAT_4, "unexpected format"); } else if (format != 2) { - return hleLogError(SCEAUDIO, SCE_KERNEL_ERROR_INVALID_SIZE, "unexpected format"); + return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "unexpected format"); } else if (sampleCount < 17 || sampleCount > 4111) { - return hleLogError(SCEAUDIO, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count"); + return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count"); } else if (freq != 0 && !SRCFrequencyAllowed(freq)) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_INVALID_FREQUENCY, "invalid frequency"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_FREQUENCY, "invalid frequency"); } else if (chan.reserved) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved"); } chan.reserved = true; @@ -436,29 +436,29 @@ static u32 sceAudioSRCChReserve(u32 sampleCount, u32 freq, u32 format) { chan.format = format == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO; // Zero means default to 44.1kHz. __AudioSetSRCFrequency(freq); - return hleLogSuccessI(SCEAUDIO, 0); + return hleLogSuccessI(Log::sceAudio, 0); } static u32 sceAudioSRCChRelease() { auto &chan = chans[PSP_AUDIO_CHANNEL_SRC]; if (!chan.reserved) - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); if (!chanSampleQueues[PSP_AUDIO_CHANNEL_SRC].empty()) - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy"); chan.reset(); chan.reserved = false; - return hleLogSuccessI(SCEAUDIO, 0); + return hleLogSuccessI(Log::sceAudio, 0); } static u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) { if (vol > 0xFFFFF) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume"); } auto &chan = chans[PSP_AUDIO_CHANNEL_SRC]; if (!chan.reserved) { - return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); + return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); } chan.leftVolume = vol; @@ -468,57 +468,77 @@ static u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) { hleEatCycles(10000); int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_SRC, true); if (result < 0) - return hleLogError(SCEAUDIO, result); - return hleLogSuccessI(SCEAUDIO, result); + return hleLogError(Log::sceAudio, result); + return hleLogSuccessI(Log::sceAudio, result); } static int sceAudioInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) { if (!Memory::IsValidAddress(bufAddr)) { - ERROR_LOG(HLE, "sceAudioInputBlocking(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr); + ERROR_LOG(Log::HLE, "sceAudioInputBlocking(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr); return -1; } - INFO_LOG(HLE, "sceAudioInputBlocking: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); + INFO_LOG(Log::HLE, "sceAudioInputBlocking: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); return __MicInput(maxSamples, sampleRate, bufAddr, AUDIOINPUT); } static int sceAudioInput(u32 maxSamples, u32 sampleRate, u32 bufAddr) { if (!Memory::IsValidAddress(bufAddr)) { - ERROR_LOG(HLE, "sceAudioInput(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr); + ERROR_LOG(Log::HLE, "sceAudioInput(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr); return -1; } - ERROR_LOG(HLE, "UNTEST sceAudioInput: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); + ERROR_LOG(Log::HLE, "UNTEST sceAudioInput: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); return __MicInput(maxSamples, sampleRate, bufAddr, AUDIOINPUT, false); } +static int sceAudioInputInit(int unknown1, int gain, int unknown2) { + ERROR_LOG(Log::HLE, "UNIMPL sceAudioInputInit: unknown1: %d, gain: %d, unknown2: %d", unknown1, gain, unknown2); + return 0; +} + +static int sceAudioInputInitEx(u32 paramAddr) { + ERROR_LOG(Log::HLE, "UNIMPL sceAudioInputInitEx: paramAddr: %08x", paramAddr); + return 0; +} + +static int sceAudioPollInputEnd() { + ERROR_LOG(Log::HLE, "UNIMPL sceAudioPollInputEnd"); + return 0; +} + +static int sceAudioWaitInputEnd() { + ERROR_LOG(Log::HLE, "UNIMPL sceAudioWaitInputEnd"); + return 0; +} + static int sceAudioGetInputLength() { int ret = Microphone::getReadMicDataLength() / 2; - ERROR_LOG(HLE, "UNTEST sceAudioGetInputLength(ret: %d)", ret); + ERROR_LOG(Log::HLE, "UNTEST sceAudioGetInputLength(ret: %d)", ret); return ret; } static u32 sceAudioRoutingSetMode(u32 mode) { - ERROR_LOG_REPORT(SCEAUDIO, "sceAudioRoutingSetMode(%08x)", mode); + ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingSetMode(%08x)", mode); int previousMode = defaultRoutingMode; defaultRoutingMode = mode; return previousMode; } static u32 sceAudioRoutingGetMode() { - ERROR_LOG_REPORT(SCEAUDIO, "sceAudioRoutingGetMode()"); + ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingGetMode()"); return defaultRoutingMode; } static u32 sceAudioRoutingSetVolumeMode(u32 mode) { - ERROR_LOG_REPORT(SCEAUDIO, "sceAudioRoutingSetVolumeMode(%08x)", mode); + ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingSetVolumeMode(%08x)", mode); int previousMode = defaultRoutingVolMode; defaultRoutingVolMode = mode; return previousMode; } static u32 sceAudioRoutingGetVolumeMode() { - ERROR_LOG_REPORT(SCEAUDIO, "sceAudioRoutingGetVolumeMode()"); + ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingGetVolumeMode()"); return defaultRoutingVolMode; } @@ -559,13 +579,13 @@ const HLEFunction sceAudio[] = {0XB61595C0, nullptr, "sceAudioLoopbackTest", '?', "" }, // Microphone interface - {0X7DE61688, nullptr, "sceAudioInputInit", '?', "" }, - {0XE926D3FB, nullptr, "sceAudioInputInitEx", '?', "" }, + {0X7DE61688, &WrapI_III, "sceAudioInputInit", 'i', "iii" }, + {0XE926D3FB, &WrapI_U, "sceAudioInputInitEx", 'i', "x" }, {0X6D4BEC68, &WrapI_UUU, "sceAudioInput", 'i', "xxx" }, {0X086E5895, &WrapI_UUU, "sceAudioInputBlocking", 'i', "xxx" }, {0XA708C6A6, &WrapI_V, "sceAudioGetInputLength", 'i', "" }, - {0XA633048E, nullptr, "sceAudioPollInputEnd", '?', "" }, - {0X87B2E651, nullptr, "sceAudioWaitInputEnd", '?', "" }, + {0XA633048E, &WrapI_V, "sceAudioPollInputEnd", 'i', "" }, + {0X87B2E651, &WrapI_V, "sceAudioWaitInputEnd", 'i', "" }, {0X36FD8AA9, &WrapU_U, "sceAudioRoutingSetMode", 'x', "x" }, {0X39240E7D, &WrapU_V, "sceAudioRoutingGetMode", 'x', "" }, diff --git a/Core/HLE/sceAudioRouting.cpp b/Core/HLE/sceAudioRouting.cpp index e573da6dae..c2e34221d6 100644 --- a/Core/HLE/sceAudioRouting.cpp +++ b/Core/HLE/sceAudioRouting.cpp @@ -28,24 +28,24 @@ u32 audioRoutingMode = AUDIO_ROUTING_SPEAKER_ON; u32 audioRoutineVolumeMode = AUDIO_ROUTING_SPEAKER_ON; static int sceAudioRoutingGetMode() { - INFO_LOG(SCEAUDIO, "sceAudioRoutingGetMode"); + INFO_LOG(Log::sceAudio, "sceAudioRoutingGetMode"); return 0; } static int sceAudioRoutingSetVolumeMode(int mode) { - INFO_LOG(SCEAUDIO, "sceAudioRoutingSetVolumeMode %d", mode); + INFO_LOG(Log::sceAudio, "sceAudioRoutingSetVolumeMode %d", mode); int previousMode = audioRoutineVolumeMode; audioRoutineVolumeMode = audioRoutingMode; return previousMode; } static int sceAudioRoutingGetVolumeMode() { - INFO_LOG(SCEAUDIO, "sceAudioRoutingGetMode"); + INFO_LOG(Log::sceAudio, "sceAudioRoutingGetMode"); return 0; } static int sceAudioRoutingSetMode(int mode) { - INFO_LOG(SCEAUDIO, "sceAudioRoutingSetMode %d", mode); + INFO_LOG(Log::sceAudio, "sceAudioRoutingSetMode %d", mode); int previousMode = audioRoutingMode; audioRoutingMode = mode; return previousMode; diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp index 296b5bf90e..fd1e770cba 100644 --- a/Core/HLE/sceAudiocodec.cpp +++ b/Core/HLE/sceAudiocodec.cpp @@ -36,12 +36,12 @@ struct AudioCodecContext { }; // audioList is to store current playing audios. -static std::map audioList; +static std::map audioList; static bool oldStateLoaded = false; // find the audio decoder for corresponding ctxPtr in audioList -static SimpleAudio *findDecoder(u32 ctxPtr) { +static AudioDecoder *findDecoder(u32 ctxPtr) { auto it = audioList.find(ctxPtr); if (it != audioList.end()) { return it->second; @@ -77,37 +77,38 @@ void __AudioCodecShutdown() { } static int sceAudiocodecInit(u32 ctxPtr, int codec) { - if (IsValidCodec(codec)) { + PSPAudioType audioType = (PSPAudioType)codec; + if (IsValidCodec(audioType)) { // Create audio decoder for given audio codec and push it into AudioList if (removeDecoder(ctxPtr)) { - WARN_LOG_REPORT(HLE, "sceAudiocodecInit(%08x, %d): replacing existing context", ctxPtr, codec); + WARN_LOG_REPORT(Log::HLE, "sceAudiocodecInit(%08x, %d): replacing existing context", ctxPtr, codec); } - auto decoder = new SimpleAudio(codec); + AudioDecoder *decoder = CreateAudioDecoder(audioType); decoder->SetCtxPtr(ctxPtr); audioList[ctxPtr] = decoder; - INFO_LOG(ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); - DEBUG_LOG(ME, "Number of playing sceAudioCodec audios : %d", (int)audioList.size()); + INFO_LOG(Log::ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(audioType)); + DEBUG_LOG(Log::ME, "Number of playing sceAudioCodec audios : %d", (int)audioList.size()); return 0; } - ERROR_LOG_REPORT(ME, "sceAudiocodecInit(%08x, %i (%s)): Unknown audio codec %i", ctxPtr, codec, GetCodecName(codec), codec); + ERROR_LOG_REPORT(Log::ME, "sceAudiocodecInit(%08x, %i (%s)): Unknown audio codec %i", ctxPtr, codec, GetCodecName(audioType), codec); return 0; } static int sceAudiocodecDecode(u32 ctxPtr, int codec) { + PSPAudioType audioType = (PSPAudioType)codec; if (!ctxPtr){ - ERROR_LOG_REPORT(ME, "sceAudiocodecDecode(%08x, %i (%s)) got NULL pointer", ctxPtr, codec, GetCodecName(codec)); + ERROR_LOG_REPORT(Log::ME, "sceAudiocodecDecode(%08x, %i (%s)) got NULL pointer", ctxPtr, codec, GetCodecName(audioType)); return -1; } - if (IsValidCodec(codec)){ - int outbytes = 0; + if (IsValidCodec(audioType)){ // find a decoder in audioList auto decoder = findDecoder(ctxPtr); if (!decoder && oldStateLoaded) { // We must have loaded an old state that did not have sceAudiocodec information. // Fake it by creating the desired context. - decoder = new SimpleAudio(codec); + decoder = CreateAudioDecoder(audioType); decoder->SetCtxPtr(ctxPtr); audioList[ctxPtr] = decoder; } @@ -116,36 +117,38 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) { // Use SimpleAudioDec to decode audio auto ctx = PSPPointer::Create(ctxPtr); // On stack, no need to allocate. // Decode audio - decoder->Decode(Memory::GetPointer(ctx->inDataPtr), ctx->inDataSize, Memory::GetPointerWrite(ctx->outDataPtr), &outbytes); + int inDataConsumed = 0; + int outSamples = 0; + decoder->Decode(Memory::GetPointer(ctx->inDataPtr), ctx->inDataSize, &inDataConsumed, 2, (int16_t *)Memory::GetPointerWrite(ctx->outDataPtr), &outSamples); } - DEBUG_LOG(ME, "sceAudiocodecDec(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); + DEBUG_LOG(Log::ME, "sceAudiocodecDec(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); return 0; } - ERROR_LOG_REPORT(ME, "UNIMPL sceAudiocodecDecode(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceAudiocodecDecode(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); return 0; } static int sceAudiocodecGetInfo(u32 ctxPtr, int codec) { - ERROR_LOG_REPORT(ME, "UNIMPL sceAudiocodecGetInfo(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceAudiocodecGetInfo(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); return 0; } static int sceAudiocodecCheckNeedMem(u32 ctxPtr, int codec) { - WARN_LOG(ME, "UNIMPL sceAudiocodecCheckNeedMem(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); + WARN_LOG(Log::ME, "UNIMPL sceAudiocodecCheckNeedMem(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); return 0; } static int sceAudiocodecGetEDRAM(u32 ctxPtr, int codec) { - WARN_LOG(ME, "UNIMPL sceAudiocodecGetEDRAM(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); + WARN_LOG(Log::ME, "UNIMPL sceAudiocodecGetEDRAM(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); return 0; } static int sceAudiocodecReleaseEDRAM(u32 ctxPtr, int id) { if (removeDecoder(ctxPtr)){ - INFO_LOG(ME, "sceAudiocodecReleaseEDRAM(%08x, %i)", ctxPtr, id); + INFO_LOG(Log::ME, "sceAudiocodecReleaseEDRAM(%08x, %i)", ctxPtr, id); return 0; } - WARN_LOG(ME, "UNIMPL sceAudiocodecReleaseEDRAM(%08x, %i)", ctxPtr, id); + WARN_LOG(Log::ME, "UNIMPL sceAudiocodecReleaseEDRAM(%08x, %i)", ctxPtr, id); return 0; } @@ -194,7 +197,7 @@ void __sceAudiocodecDoState(PointerWrap &p){ DoArray(p, codec_, s >= 2 ? count : (int)ARRAY_SIZE(codec_)); DoArray(p, ctxPtr_, s >= 2 ? count : (int)ARRAY_SIZE(ctxPtr_)); for (int i = 0; i < count; i++) { - auto decoder = new SimpleAudio(codec_[i]); + auto decoder = CreateAudioDecoder((PSPAudioType)codec_[i]); decoder->SetCtxPtr(ctxPtr_[i]); audioList[ctxPtr_[i]] = decoder; } @@ -214,7 +217,7 @@ void __sceAudiocodecDoState(PointerWrap &p){ auto ctxPtr_ = new u32[count]; int i = 0; for (auto it = audioList.begin(), end = audioList.end(); it != end; it++) { - const SimpleAudio *decoder = it->second; + const AudioDecoder *decoder = it->second; codec_[i] = decoder->GetAudioType(); ctxPtr_[i] = decoder->GetCtxPtr(); i++; diff --git a/Core/HLE/sceAudiocodec.h b/Core/HLE/sceAudiocodec.h index 8f190cb84e..21d9106e82 100644 --- a/Core/HLE/sceAudiocodec.h +++ b/Core/HLE/sceAudiocodec.h @@ -17,6 +17,8 @@ #pragma once +class PointerWrap; + typedef struct { s32_le unk0; s32_le unk4; @@ -58,4 +60,4 @@ typedef struct { void __AudioCodecInit(); void __AudioCodecShutdown(); void Register_sceAudiocodec(); -void __sceAudiocodecDoState(PointerWrap &p); \ No newline at end of file +void __sceAudiocodecDoState(PointerWrap &p); diff --git a/Core/HLE/sceCcc.cpp b/Core/HLE/sceCcc.cpp index b47d805573..780b389af7 100644 --- a/Core/HLE/sceCcc.cpp +++ b/Core/HLE/sceCcc.cpp @@ -86,7 +86,7 @@ static u32 __CccJIStoUCS(u32 c, u32 alt) static void sceCccSetTable(u32 jis2ucs, u32 ucs2jis) { // Both tables jis2ucs and ucs2jis have a size of 0x20000 bytes. - DEBUG_LOG(SCEMISC, "sceCccSetTable(%08x, %08x)", jis2ucs, ucs2jis); + DEBUG_LOG(Log::sceMisc, "sceCccSetTable(%08x, %08x)", jis2ucs, ucs2jis); ucs2jisTable = ucs2jis; jis2ucsTable = jis2ucs; } @@ -97,14 +97,14 @@ static int sceCccUTF8toUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr) auto dst = PSPWCharPointer::Create(dstAddr); if (!dst.IsValid() || !src.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccUTF8toUTF16(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccUTF8toUTF16(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); return 0; } // Round dstSize down if it represents half a character. const auto dstEnd = PSPWCharPointer::Create(dstAddr + (dstSize & ~1)); - DEBUG_LOG(SCEMISC, "sceCccUTF8toUTF16(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); + DEBUG_LOG(Log::sceMisc, "sceCccUTF8toUTF16(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); UTF8 utf(src); int n = 0; while (u32 c = utf.next()) @@ -129,18 +129,18 @@ static int sceCccUTF8toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr) auto dst = PSPCharPointer::Create(dstAddr); if (!dst.IsValid() || !src.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccUTF8toSJIS(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccUTF8toSJIS(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); return 0; } if (!ucs2jisTable.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccUTF8toSJIS(%08x, %d, %08x): table not loaded", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccUTF8toSJIS(%08x, %d, %08x): table not loaded", dstAddr, dstSize, srcAddr); return 0; } const auto dstEnd = PSPCharPointer::Create(dstAddr + dstSize); - DEBUG_LOG(SCEMISC, "sceCccUTF8toSJIS(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); + DEBUG_LOG(Log::sceMisc, "sceCccUTF8toSJIS(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); UTF8 utf(src); int n = 0; while (u32 c = utf.next()) @@ -165,13 +165,13 @@ static int sceCccUTF16toUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr) auto dst = PSPCharPointer::Create(dstAddr); if (!dst.IsValid() || !src.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccUTF16toUTF8(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccUTF16toUTF8(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); return 0; } const auto dstEnd = PSPCharPointer::Create(dstAddr + dstSize); - DEBUG_LOG(SCEMISC, "sceCccUTF16toUTF8(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); + DEBUG_LOG(Log::sceMisc, "sceCccUTF16toUTF8(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); UTF16LE utf(src); int n = 0; while (u32 c = utf.next()) @@ -196,18 +196,18 @@ static int sceCccUTF16toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr) auto dst = PSPCharPointer::Create(dstAddr); if (!dst.IsValid() || !src.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccUTF16toSJIS(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccUTF16toSJIS(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); return 0; } if (!ucs2jisTable.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccUTF16toSJIS(%08x, %d, %08x): table not loaded", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccUTF16toSJIS(%08x, %d, %08x): table not loaded", dstAddr, dstSize, srcAddr); return 0; } const auto dstEnd = PSPCharPointer::Create(dstAddr + dstSize); - DEBUG_LOG(SCEMISC, "sceCccUTF16toSJIS(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); + DEBUG_LOG(Log::sceMisc, "sceCccUTF16toSJIS(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); UTF16LE utf(src); int n = 0; while (u32 c = utf.next()) @@ -232,18 +232,18 @@ static int sceCccSJIStoUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr) auto dst = PSPCharPointer::Create(dstAddr); if (!dst.IsValid() || !src.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccSJIStoUTF8(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccSJIStoUTF8(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); return 0; } if (!jis2ucsTable.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccSJIStoUTF8(%08x, %d, %08x): table not loaded", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccSJIStoUTF8(%08x, %d, %08x): table not loaded", dstAddr, dstSize, srcAddr); return 0; } const auto dstEnd = PSPCharPointer::Create(dstAddr + dstSize); - DEBUG_LOG(SCEMISC, "sceCccSJIStoUTF8(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); + DEBUG_LOG(Log::sceMisc, "sceCccSJIStoUTF8(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); ShiftJIS sjis(src); int n = 0; while (u32 c = sjis.next()) @@ -268,18 +268,18 @@ static int sceCccSJIStoUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr) auto dst = PSPWCharPointer::Create(dstAddr); if (!dst.IsValid() || !src.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccSJIStoUTF16(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccSJIStoUTF16(%08x, %d, %08x): invalid pointers", dstAddr, dstSize, srcAddr); return 0; } if (!jis2ucsTable.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccSJIStoUTF16(%08x, %d, %08x): table not loaded", dstAddr, dstSize, srcAddr); + ERROR_LOG(Log::sceMisc, "sceCccSJIStoUTF16(%08x, %d, %08x): table not loaded", dstAddr, dstSize, srcAddr); return 0; } const auto dstEnd = PSPWCharPointer::Create(dstAddr + (dstSize & ~1)); - DEBUG_LOG(SCEMISC, "sceCccSJIStoUTF16(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); + DEBUG_LOG(Log::sceMisc, "sceCccSJIStoUTF16(%08x, %d, %08x)", dstAddr, dstSize, srcAddr); ShiftJIS sjis(src); int n = 0; while (u32 c = sjis.next()) @@ -303,10 +303,10 @@ static int sceCccStrlenUTF8(u32 strAddr) const auto str = PSPConstCharPointer::Create(strAddr); if (!str.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccStrlenUTF8(%08x): invalid pointer", strAddr); + ERROR_LOG(Log::sceMisc, "sceCccStrlenUTF8(%08x): invalid pointer", strAddr); return 0; } - DEBUG_LOG(SCEMISC, "sceCccStrlenUTF8(%08x): invalid pointer", strAddr); + DEBUG_LOG(Log::sceMisc, "sceCccStrlenUTF8(%08x): invalid pointer", strAddr); return UTF8(str).length(); } @@ -315,10 +315,10 @@ static int sceCccStrlenUTF16(u32 strAddr) const auto str = PSPConstWCharPointer::Create(strAddr); if (!str.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccStrlenUTF16(%08x): invalid pointer", strAddr); + ERROR_LOG(Log::sceMisc, "sceCccStrlenUTF16(%08x): invalid pointer", strAddr); return 0; } - DEBUG_LOG(SCEMISC, "sceCccStrlenUTF16(%08x): invalid pointer", strAddr); + DEBUG_LOG(Log::sceMisc, "sceCccStrlenUTF16(%08x): invalid pointer", strAddr); return UTF16LE(str).length(); } @@ -327,10 +327,10 @@ static int sceCccStrlenSJIS(u32 strAddr) const auto str = PSPCharPointer::Create(strAddr); if (!str.IsValid()) { - ERROR_LOG(SCEMISC, "sceCccStrlenSJIS(%08x): invalid pointer", strAddr); + ERROR_LOG(Log::sceMisc, "sceCccStrlenSJIS(%08x): invalid pointer", strAddr); return 0; } - DEBUG_LOG(SCEMISC, "sceCccStrlenSJIS(%08x): invalid pointer", strAddr); + DEBUG_LOG(Log::sceMisc, "sceCccStrlenSJIS(%08x): invalid pointer", strAddr); return ShiftJIS(str).length(); } @@ -340,10 +340,10 @@ static u32 sceCccEncodeUTF8(u32 dstAddrAddr, u32 ucs) if (!dstp.IsValid() || !dstp->IsValid()) { - ERROR_LOG(SCEMISC, "sceCccEncodeUTF8(%08x, U+%04x): invalid pointer", dstAddrAddr, ucs); + ERROR_LOG(Log::sceMisc, "sceCccEncodeUTF8(%08x, U+%04x): invalid pointer", dstAddrAddr, ucs); return 0; } - DEBUG_LOG(SCEMISC, "sceCccEncodeUTF8(%08x, U+%04x)", dstAddrAddr, ucs); + DEBUG_LOG(Log::sceMisc, "sceCccEncodeUTF8(%08x, U+%04x)", dstAddrAddr, ucs); *dstp += UTF8::encode(*dstp, ucs); return dstp->ptr; } @@ -354,10 +354,10 @@ static void sceCccEncodeUTF16(u32 dstAddrAddr, u32 ucs) if (!dstp.IsValid() || !dstp->IsValid()) { - ERROR_LOG(SCEMISC, "sceCccEncodeUTF16(%08x, U+%04x): invalid pointer", dstAddrAddr, ucs); + ERROR_LOG(Log::sceMisc, "sceCccEncodeUTF16(%08x, U+%04x): invalid pointer", dstAddrAddr, ucs); return; } - DEBUG_LOG(SCEMISC, "sceCccEncodeUTF16(%08x, U+%04x)", dstAddrAddr, ucs); + DEBUG_LOG(Log::sceMisc, "sceCccEncodeUTF16(%08x, U+%04x)", dstAddrAddr, ucs); // Anything above 0x10FFFF is unencodable, and 0xD800 - 0xDFFF are reserved for surrogate pairs. if (ucs > 0x10FFFF || (ucs & 0xD800) == 0xD800) ucs = errorUTF16; @@ -370,10 +370,10 @@ static u32 sceCccEncodeSJIS(u32 dstAddrAddr, u32 jis) if (!dstp.IsValid() || !dstp->IsValid()) { - ERROR_LOG(SCEMISC, "sceCccEncodeSJIS(%08x, U+%04x): invalid pointer", dstAddrAddr, jis); + ERROR_LOG(Log::sceMisc, "sceCccEncodeSJIS(%08x, U+%04x): invalid pointer", dstAddrAddr, jis); return 0; } - DEBUG_LOG(SCEMISC, "sceCccEncodeSJIS(%08x, U+%04x)", dstAddrAddr, jis); + DEBUG_LOG(Log::sceMisc, "sceCccEncodeSJIS(%08x, U+%04x)", dstAddrAddr, jis); *dstp += ShiftJIS::encode(*dstp, jis); return dstp->ptr; } @@ -383,12 +383,12 @@ static u32 sceCccDecodeUTF8(u32 dstAddrAddr) auto dstp = PSPPointer::Create(dstAddrAddr); if (!dstp.IsValid() || !dstp->IsValid()) { - ERROR_LOG(SCEMISC, "sceCccDecodeUTF8(%08x): invalid pointer", dstAddrAddr); + ERROR_LOG(Log::sceMisc, "sceCccDecodeUTF8(%08x): invalid pointer", dstAddrAddr); // Should crash? return 0; } - DEBUG_LOG(SCEMISC, "sceCccDecodeUTF8(%08x)", dstAddrAddr); + DEBUG_LOG(Log::sceMisc, "sceCccDecodeUTF8(%08x)", dstAddrAddr); UTF8 utf(*dstp); u32 result = utf.next(); *dstp += utf.byteIndex(); @@ -403,12 +403,12 @@ static u32 sceCccDecodeUTF16(u32 dstAddrAddr) auto dstp = PSPPointer::Create(dstAddrAddr); if (!dstp.IsValid() || !dstp->IsValid()) { - ERROR_LOG(SCEMISC, "sceCccDecodeUTF16(%08x): invalid pointer", dstAddrAddr); + ERROR_LOG(Log::sceMisc, "sceCccDecodeUTF16(%08x): invalid pointer", dstAddrAddr); // Should crash? return 0; } - DEBUG_LOG(SCEMISC, "sceCccDecodeUTF16(%08x)", dstAddrAddr); + DEBUG_LOG(Log::sceMisc, "sceCccDecodeUTF16(%08x)", dstAddrAddr); // TODO: Does it do any detection of BOM? UTF16LE utf(*dstp); u32 result = utf.next(); @@ -424,12 +424,12 @@ static u32 sceCccDecodeSJIS(u32 dstAddrAddr) auto dstp = PSPPointer::Create(dstAddrAddr); if (!dstp.IsValid() || !dstp->IsValid()) { - ERROR_LOG(SCEMISC, "sceCccDecodeSJIS(%08x): invalid pointer", dstAddrAddr); + ERROR_LOG(Log::sceMisc, "sceCccDecodeSJIS(%08x): invalid pointer", dstAddrAddr); // Should crash? return 0; } - DEBUG_LOG(SCEMISC, "sceCccDecodeSJIS(%08x)", dstAddrAddr); + DEBUG_LOG(Log::sceMisc, "sceCccDecodeSJIS(%08x)", dstAddrAddr); ShiftJIS sjis(*dstp); u32 result = sjis.next(); *dstp += sjis.byteIndex(); @@ -441,49 +441,49 @@ static u32 sceCccDecodeSJIS(u32 dstAddrAddr) static int sceCccIsValidUTF8(u32 c) { - WARN_LOG(SCEMISC, "UNIMPL sceCccIsValidUTF8(%08x)", c); + WARN_LOG(Log::sceMisc, "UNIMPL sceCccIsValidUTF8(%08x)", c); return c != 0; } static int sceCccIsValidUTF16(u32 c) { - WARN_LOG(SCEMISC, "UNIMPL sceCccIsValidUTF16(%08x)", c); + WARN_LOG(Log::sceMisc, "UNIMPL sceCccIsValidUTF16(%08x)", c); return c != 0; } static int sceCccIsValidSJIS(u32 c) { - WARN_LOG(SCEMISC, "UNIMPL sceCccIsValidSJIS(%08x)", c); + WARN_LOG(Log::sceMisc, "UNIMPL sceCccIsValidSJIS(%08x)", c); return c != 0; } static int sceCccIsValidUCS2(u32 c) { - WARN_LOG(SCEMISC, "UNIMPL sceCccIsValidUCS2(%08x)", c); + WARN_LOG(Log::sceMisc, "UNIMPL sceCccIsValidUCS2(%08x)", c); return c != 0; } static int sceCccIsValidUCS4(u32 c) { - WARN_LOG(SCEMISC, "UNIMPL sceCccIsValidUCS4(%08x)", c); + WARN_LOG(Log::sceMisc, "UNIMPL sceCccIsValidUCS4(%08x)", c); return c != 0; } static int sceCccIsValidJIS(u32 c) { - WARN_LOG(SCEMISC, "UNIMPL sceCccIsValidJIS(%08x)", c); + WARN_LOG(Log::sceMisc, "UNIMPL sceCccIsValidJIS(%08x)", c); return c != 0; } static int sceCccIsValidUnicode(u32 c) { - WARN_LOG(SCEMISC, "UNIMPL sceCccIsValidUnicode(%08x)", c); + WARN_LOG(Log::sceMisc, "UNIMPL sceCccIsValidUnicode(%08x)", c); return c != 0; } static u32 sceCccSetErrorCharUTF8(u32 c) { - DEBUG_LOG(SCEMISC, "sceCccSetErrorCharUTF8(%08x)", c); + DEBUG_LOG(Log::sceMisc, "sceCccSetErrorCharUTF8(%08x)", c); int result = errorUTF8; errorUTF8 = c; return result; @@ -491,7 +491,7 @@ static u32 sceCccSetErrorCharUTF8(u32 c) static u32 sceCccSetErrorCharUTF16(u32 c) { - DEBUG_LOG(SCEMISC, "sceCccSetErrorCharUTF16(%08x)", c); + DEBUG_LOG(Log::sceMisc, "sceCccSetErrorCharUTF16(%08x)", c); int result = errorUTF16; errorUTF16 = c; return result; @@ -499,7 +499,7 @@ static u32 sceCccSetErrorCharUTF16(u32 c) static u32 sceCccSetErrorCharSJIS(u32 c) { - DEBUG_LOG(SCEMISC, "sceCccSetErrorCharSJIS(%04x)", c); + DEBUG_LOG(Log::sceMisc, "sceCccSetErrorCharSJIS(%04x)", c); int result = errorSJIS; errorSJIS = c; return result; @@ -509,12 +509,12 @@ static u32 sceCccUCStoJIS(u32 c, u32 alt) { if (ucs2jisTable.IsValid()) { - DEBUG_LOG(SCEMISC, "sceCccUCStoJIS(%08x, %08x)", c, alt); + DEBUG_LOG(Log::sceMisc, "sceCccUCStoJIS(%08x, %08x)", c, alt); return __CccUCStoJIS(c, alt); } else { - ERROR_LOG(SCEMISC, "sceCccUCStoJIS(%08x, %08x): table not loaded", c, alt); + ERROR_LOG(Log::sceMisc, "sceCccUCStoJIS(%08x, %08x): table not loaded", c, alt); return alt; } } @@ -523,12 +523,12 @@ static u32 sceCccJIStoUCS(u32 c, u32 alt) { if (jis2ucsTable.IsValid()) { - DEBUG_LOG(SCEMISC, "sceCccUCStoJIS(%08x, %08x)", c, alt); + DEBUG_LOG(Log::sceMisc, "sceCccUCStoJIS(%08x, %08x)", c, alt); return __CccJIStoUCS(c, alt); } else { - ERROR_LOG(SCEMISC, "sceCccUCStoJIS(%08x, %08x): table not loaded", c, alt); + ERROR_LOG(Log::sceMisc, "sceCccUCStoJIS(%08x, %08x): table not loaded", c, alt); return alt; } } diff --git a/Core/HLE/sceChnnlsv.cpp b/Core/HLE/sceChnnlsv.cpp index b82e447151..5eaf5fab6e 100644 --- a/Core/HLE/sceChnnlsv.cpp +++ b/Core/HLE/sceChnnlsv.cpp @@ -134,7 +134,7 @@ static int sub_15B0(u8* data, int alignedLen, u8* buf, int val) return 0; } -static int sub_0000(u8* data_out, u8* data, int alignedLen, u8* data2, int& data3, int mode) +static int sub_0000(u8* data_out, u8* data, int alignedLen, const u8* data2, int& data3, int mode) { memcpy(data_out+20, data2, 16); // Mode 1:2 is 83, 3:4 is 87, 5:6 is 100 @@ -218,11 +218,11 @@ static int sceSdGetLastIndex(u32 addressCtx, u32 addressHash, u32 addressKey) { auto ctx = PSPPointer::Create(addressCtx); u8 *hash = Memory::GetPointerWrite(addressHash); if (!ctx.IsValid() || !hash) - return hleLogError(SCEMISC, 0, "Invalid pointer"); - return hleLogSuccessI(SCEMISC, sceSdGetLastIndex_(*ctx, hash, Memory::GetPointerWrite(addressKey))); + return hleLogError(Log::sceMisc, 0, "Invalid pointer"); + return hleLogSuccessI(Log::sceMisc, sceSdGetLastIndex_(*ctx, hash, Memory::GetPointerWrite(addressKey))); } -int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, u8* in_key) +int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, const u8* in_key) { if(ctx.keyLength >= 17) return -1026; @@ -327,8 +327,8 @@ int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, u8* in_key) static int sceSdSetIndex(u32 addressCtx, int value) { auto ctx = PSPPointer::Create(addressCtx); if (!ctx.IsValid()) - return hleLogError(SCEMISC, 0, "Invalid pointer"); - return hleLogSuccessI(SCEMISC, sceSdSetIndex_(*ctx, value)); + return hleLogError(Log::sceMisc, 0, "Invalid pointer"); + return hleLogSuccessI(Log::sceMisc, sceSdSetIndex_(*ctx, value)); } int sceSdSetIndex_(pspChnnlsvContext1& ctx, int value) @@ -344,11 +344,11 @@ int sceSdSetIndex_(pspChnnlsvContext1& ctx, int value) static int sceSdRemoveValue(u32 addressCtx, u32 addressData, int length) { auto ctx = PSPPointer::Create(addressCtx); if (!ctx.IsValid() || !Memory::IsValidAddress(addressData)) - return hleLogError(SCEMISC, 0, "Invalid pointer"); - return hleLogSuccessI(SCEMISC, sceSdRemoveValue_(*ctx, Memory::GetPointerWrite(addressData), length)); + return hleLogError(Log::sceMisc, 0, "Invalid pointer"); + return hleLogSuccessI(Log::sceMisc, sceSdRemoveValue_(*ctx, Memory::GetPointerWrite(addressData), length)); } -int sceSdRemoveValue_(pspChnnlsvContext1& ctx, u8* data, int length) +int sceSdRemoveValue_(pspChnnlsvContext1& ctx, const u8* data, int length) { if(ctx.keyLength >= 17) return -1026; @@ -395,12 +395,12 @@ static int sceSdCreateList(u32 ctx2Addr, int mode, int unkwn, u32 dataAddr, u32 u8* data = Memory::GetPointerWrite(dataAddr); u8* cryptkey = Memory::GetPointerWrite(cryptkeyAddr); if (!ctx2.IsValid() || !data) - return hleLogError(SCEMISC, 0, "Invalid pointer"); + return hleLogError(Log::sceMisc, 0, "Invalid pointer"); - return hleLogSuccessI(SCEMISC, sceSdCreateList_(*ctx2, mode, unkwn, data, cryptkey)); + return hleLogSuccessI(Log::sceMisc, sceSdCreateList_(*ctx2, mode, unkwn, data, cryptkey)); } -int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, u8* cryptkey) +int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, const u8* cryptkey) { ctx2.mode = mode; ctx2.unkn = 1; @@ -458,9 +458,9 @@ static int sceSdSetMember(u32 ctxAddr, u32 dataAddr, int alignedLen) { auto ctx = PSPPointer::Create(ctxAddr); u8 *data = Memory::GetPointerWrite(dataAddr); if (!ctx.IsValid() || !data) - return hleLogError(SCEMISC, 0, "Invalid pointer"); + return hleLogError(Log::sceMisc, 0, "Invalid pointer"); - return hleLogSuccessI(SCEMISC, sceSdSetMember_(*ctx, data, alignedLen)); + return hleLogSuccessI(Log::sceMisc, sceSdSetMember_(*ctx, data, alignedLen)); } int sceSdSetMember_(pspChnnlsvContext2& ctx, u8* data, int alignedLen) @@ -500,8 +500,8 @@ int sceSdSetMember_(pspChnnlsvContext2& ctx, u8* data, int alignedLen) static int sceSdCleanList(u32 ctxAddr) { auto ctx = PSPPointer::Create(ctxAddr); if (!ctx.IsValid()) - return hleLogError(SCEMISC, 0, "Invalid pointer"); - return hleLogSuccessI(SCEMISC, sceSdCleanList_(*ctx)); + return hleLogError(Log::sceMisc, 0, "Invalid pointer"); + return hleLogSuccessI(Log::sceMisc, sceSdCleanList_(*ctx)); } int sceSdCleanList_(pspChnnlsvContext2& ctx) diff --git a/Core/HLE/sceChnnlsv.h b/Core/HLE/sceChnnlsv.h index 3636e14b08..d8a030932c 100644 --- a/Core/HLE/sceChnnlsv.h +++ b/Core/HLE/sceChnnlsv.h @@ -35,10 +35,10 @@ typedef struct _pspChnnlsvContext2 { } pspChnnlsvContext2; int sceSdSetIndex_(pspChnnlsvContext1& ctx, int value); -int sceSdRemoveValue_(pspChnnlsvContext1& ctx, u8* data, int length); -int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, u8* cryptkey); +int sceSdRemoveValue_(pspChnnlsvContext1& ctx, const u8* data, int length); +int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, const u8* cryptkey); int sceSdSetMember_(pspChnnlsvContext2& ctx, u8* data, int alignedLen); int sceSdCleanList_(pspChnnlsvContext2& ctx); -int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, u8* in_key); +int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, const u8* in_key); void Register_sceChnnlsv(); diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index d78b59033f..9d86f47bbf 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -225,6 +225,19 @@ void __CtrlSetAnalogXY(int stick, float x, float y) ctrlCurrent.analog[stick][CTRL_ANALOG_Y] = scaledY; } +// not making XY to use these due to mutex guard usage +void __CtrlSetAnalogX(int stick, float x) { + u8 scaledX = clamp_u8((int)ceilf(x * 127.5f + 127.5f)); + std::lock_guard guard(ctrlMutex); + ctrlCurrent.analog[stick][CTRL_ANALOG_X] = scaledX; +} + +void __CtrlSetAnalogY(int stick, float y) { + u8 scaledY = clamp_u8((int)ceilf(-y * 127.5f + 127.5f)); + std::lock_guard guard(ctrlMutex); + ctrlCurrent.analog[stick][CTRL_ANALOG_Y] = scaledY; +} + void __CtrlSetRapidFire(bool state, int interval) { emuRapidFire = state; @@ -417,11 +430,11 @@ void __CtrlShutdown() static u32 sceCtrlSetSamplingCycle(u32 cycle) { - DEBUG_LOG(SCECTRL, "sceCtrlSetSamplingCycle(%u)", cycle); + DEBUG_LOG(Log::sceCtrl, "sceCtrlSetSamplingCycle(%u)", cycle); if ((cycle > 0 && cycle < 5555) || cycle > 20000) { - WARN_LOG(SCECTRL, "SCE_KERNEL_ERROR_INVALID_VALUE=sceCtrlSetSamplingCycle(%u)", cycle); + WARN_LOG(Log::sceCtrl, "SCE_KERNEL_ERROR_INVALID_VALUE=sceCtrlSetSamplingCycle(%u)", cycle); return SCE_KERNEL_ERROR_INVALID_VALUE; } @@ -438,7 +451,7 @@ static u32 sceCtrlSetSamplingCycle(u32 cycle) static int sceCtrlGetSamplingCycle(u32 cyclePtr) { - DEBUG_LOG(SCECTRL, "sceCtrlGetSamplingCycle(%08x)", cyclePtr); + DEBUG_LOG(Log::sceCtrl, "sceCtrlGetSamplingCycle(%08x)", cyclePtr); if (Memory::IsValidAddress(cyclePtr)) Memory::Write_U32(ctrlCycle, cyclePtr); return 0; @@ -448,7 +461,7 @@ static u32 sceCtrlSetSamplingMode(u32 mode) { u32 retVal = 0; - DEBUG_LOG(SCECTRL, "sceCtrlSetSamplingMode(%i)", mode); + DEBUG_LOG(Log::sceCtrl, "sceCtrlSetSamplingMode(%i)", mode); if (mode > 1) return SCE_KERNEL_ERROR_INVALID_MODE; @@ -460,7 +473,7 @@ static u32 sceCtrlSetSamplingMode(u32 mode) static int sceCtrlGetSamplingMode(u32 modePtr) { u32 retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL; - DEBUG_LOG(SCECTRL, "%d=sceCtrlGetSamplingMode(%08x)", retVal, modePtr); + DEBUG_LOG(Log::sceCtrl, "%d=sceCtrlGetSamplingMode(%08x)", retVal, modePtr); if (Memory::IsValidAddress(modePtr)) Memory::Write_U32(retVal, modePtr); @@ -470,7 +483,7 @@ static int sceCtrlGetSamplingMode(u32 modePtr) static int sceCtrlSetIdleCancelThreshold(int idleReset, int idleBack) { - DEBUG_LOG(SCECTRL, "FAKE sceCtrlSetIdleCancelThreshold(%d, %d)", idleReset, idleBack); + DEBUG_LOG(Log::sceCtrl, "FAKE sceCtrlSetIdleCancelThreshold(%d, %d)", idleReset, idleBack); if (idleReset < -1 || idleBack < -1 || idleReset > 128 || idleBack > 128) return SCE_KERNEL_ERROR_INVALID_VALUE; @@ -482,7 +495,7 @@ static int sceCtrlSetIdleCancelThreshold(int idleReset, int idleBack) static int sceCtrlGetIdleCancelThreshold(u32 idleResetPtr, u32 idleBackPtr) { - DEBUG_LOG(SCECTRL, "sceCtrlSetIdleCancelThreshold(%08x, %08x)", idleResetPtr, idleBackPtr); + DEBUG_LOG(Log::sceCtrl, "sceCtrlSetIdleCancelThreshold(%08x, %08x)", idleResetPtr, idleBackPtr); if (idleResetPtr && !Memory::IsValidAddress(idleResetPtr)) return SCE_KERNEL_ERROR_PRIV_REQUIRED; @@ -503,13 +516,13 @@ static int sceCtrlReadBufferPositive(u32 ctrlDataPtr, u32 nBufs) hleEatCycles(330); if (done != 0) { - DEBUG_LOG(SCECTRL, "%d=sceCtrlReadBufferPositive(%08x, %i)", done, ctrlDataPtr, nBufs); + DEBUG_LOG(Log::sceCtrl, "%d=sceCtrlReadBufferPositive(%08x, %i)", done, ctrlDataPtr, nBufs); } else { waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_CTRL, CTRL_WAIT_POSITIVE, ctrlDataPtr, 0, false, "ctrl buffer waited"); - DEBUG_LOG(SCECTRL, "sceCtrlReadBufferPositive(%08x, %i) - waiting", ctrlDataPtr, nBufs); + DEBUG_LOG(Log::sceCtrl, "sceCtrlReadBufferPositive(%08x, %i) - waiting", ctrlDataPtr, nBufs); } return done; } @@ -520,13 +533,13 @@ static int sceCtrlReadBufferNegative(u32 ctrlDataPtr, u32 nBufs) hleEatCycles(330); if (done != 0) { - DEBUG_LOG(SCECTRL, "%d=sceCtrlReadBufferNegative(%08x, %i)", done, ctrlDataPtr, nBufs); + DEBUG_LOG(Log::sceCtrl, "%d=sceCtrlReadBufferNegative(%08x, %i)", done, ctrlDataPtr, nBufs); } else { waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_CTRL, CTRL_WAIT_NEGATIVE, ctrlDataPtr, 0, false, "ctrl buffer waited"); - DEBUG_LOG(SCECTRL, "sceCtrlReadBufferNegative(%08x, %i) - waiting", ctrlDataPtr, nBufs); + DEBUG_LOG(Log::sceCtrl, "sceCtrlReadBufferNegative(%08x, %i) - waiting", ctrlDataPtr, nBufs); } return done; } @@ -535,7 +548,7 @@ static int sceCtrlPeekBufferPositive(u32 ctrlDataPtr, u32 nBufs) { int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, false, true); // Some homebrew call this in a tight loop - so VERBOSE it is. - VERBOSE_LOG(SCECTRL, "%d=sceCtrlPeekBufferPositive(%08x, %i)", done, ctrlDataPtr, nBufs); + VERBOSE_LOG(Log::sceCtrl, "%d=sceCtrlPeekBufferPositive(%08x, %i)", done, ctrlDataPtr, nBufs); hleEatCycles(330); return done; } @@ -544,7 +557,7 @@ static int sceCtrlPeekBufferNegative(u32 ctrlDataPtr, u32 nBufs) { int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, true, true); // Some homebrew call this in a tight loop - so VERBOSE it is. - VERBOSE_LOG(SCECTRL, "%d=sceCtrlPeekBufferNegative(%08x, %i)", done, ctrlDataPtr, nBufs); + VERBOSE_LOG(Log::sceCtrl, "%d=sceCtrlPeekBufferNegative(%08x, %i)", done, ctrlDataPtr, nBufs); hleEatCycles(330); return done; } @@ -564,7 +577,7 @@ static u32 sceCtrlPeekLatch(u32 latchDataPtr) { if (userLatch.IsValid()) { __CtrlWriteUserLatch(userLatch, ctrlLatchBufs); } - return hleLogSuccessI(SCECTRL, ctrlLatchBufs); + return hleLogSuccessI(Log::sceCtrl, ctrlLatchBufs); } static u32 sceCtrlReadLatch(u32 latchDataPtr) { @@ -572,7 +585,7 @@ static u32 sceCtrlReadLatch(u32 latchDataPtr) { if (userLatch.IsValid()) { __CtrlWriteUserLatch(userLatch, ctrlLatchBufs); } - return hleLogSuccessI(SCECTRL, __CtrlResetLatch()); + return hleLogSuccessI(Log::sceCtrl, __CtrlResetLatch()); } static const HLEFunction sceCtrl[] = diff --git a/Core/HLE/sceCtrl.h b/Core/HLE/sceCtrl.h index e633dd62de..f4a65b6760 100644 --- a/Core/HLE/sceCtrl.h +++ b/Core/HLE/sceCtrl.h @@ -71,6 +71,8 @@ void __CtrlUpdateButtons(u32 bitsToSet, u32 bitsToClear); // X and Y values should be from -1 to 1, inclusive, in a square (no need to force to a circle.) // No deadzone filtering is done (but note that this applies to the actual PSP as well.) void __CtrlSetAnalogXY(int stick, float x, float y); +void __CtrlSetAnalogX(int stick, float x); +void __CtrlSetAnalogY(int stick, float y); // Call this to enable rapid-fire. This will cause buttons other than arrows to alternate. void __CtrlSetRapidFire(bool state, int interval); diff --git a/Core/HLE/sceDeflt.cpp b/Core/HLE/sceDeflt.cpp index d1a6da33e1..ba722e9a5c 100644 --- a/Core/HLE/sceDeflt.cpp +++ b/Core/HLE/sceDeflt.cpp @@ -27,12 +27,12 @@ // All the decompress functions are identical with only differing window bits. static int CommonDecompress(int windowBits, u32 OutBuffer, int OutBufferLength, u32 InBuffer, u32 Crc32Addr) { if (!Memory::IsValidAddress(OutBuffer) || !Memory::IsValidAddress(InBuffer)) { - return hleLogError(HLE, 0, "bad address"); + return hleLogError(Log::HLE, 0, "bad address"); } auto crc32Addr = PSPPointer::Create(Crc32Addr); if (Crc32Addr && !crc32Addr.IsValid()) { - return hleLogError(HLE, 0, "bad crc32 address"); + return hleLogError(Log::HLE, 0, "bad crc32 address"); } z_stream stream{}; @@ -45,13 +45,13 @@ static int CommonDecompress(int windowBits, u32 OutBuffer, int OutBufferLength, int err = inflateInit2(&stream, windowBits); if (err != Z_OK) { - return hleLogError(HLE, 0, "inflateInit2 failed %08x", err); + return hleLogError(Log::HLE, 0, "inflateInit2 failed %08x", err); } err = inflate(&stream, Z_FINISH); inflateEnd(&stream); if (err != Z_STREAM_END) { - return hleLogError(HLE, 0, "inflate failed %08x", err); + return hleLogError(Log::HLE, 0, "inflate failed %08x", err); } if (crc32Addr.IsValid()) { uLong crc = crc32(0L, Z_NULL, 0); @@ -65,7 +65,7 @@ static int CommonDecompress(int windowBits, u32 OutBuffer, int OutBufferLength, NotifyMemInfo(MemBlockFlags::WRITE, OutBuffer, stream.total_out, tagData, tagSize); } - return hleLogSuccessI(HLE, stream.total_out); + return hleLogSuccessI(Log::HLE, stream.total_out); } static int sceDeflateDecompress(u32 OutBuffer, int OutBufferLength, u32 InBuffer, u32 Crc32Addr) { diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 55c3a62d1a..cca85b09fd 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -106,10 +106,10 @@ static int height; static bool wasPaused; static bool flippedThisFrame; -static int framerate = 60; +static int framerate; // 1.001f to compensate for the classic 59.94 NTSC framerate that the PSP seems to have. -static double timePerVblank = 1.001 / framerate; +static double timePerVblank; // Don't include this in the state, time increases regardless of state. static double curFrameTime; @@ -131,7 +131,7 @@ const double vblankMs = 0.7315; // These are guesses based on tests. const double vsyncStartMs = 0.5925; const double vsyncEndMs = 0.7265; -double frameMs = 1001.0 / (double)framerate; +double frameMs; enum { PSP_DISPLAY_SETBUF_IMMEDIATE = 0, @@ -152,6 +152,7 @@ void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId); void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId); void __DisplayFlip(int cyclesLate); +static void __DisplaySetFramerate(void); static bool UseLagSync() { return g_Config.bForceLagSync && !g_Config.bAutoFrameSkip; @@ -171,6 +172,7 @@ static void ScheduleLagSync(int over = 0) { } void __DisplayInit() { + __DisplaySetFramerate(); DisplayHWInit(); hasSetMode = false; mode = 0; @@ -316,12 +318,12 @@ void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId) { } if (waitData.threadID != threadID) { - WARN_LOG_REPORT(SCEDISPLAY, "sceDisplayWaitVblankCB: could not find waiting thread info."); + WARN_LOG_REPORT(Log::sceDisplay, "sceDisplayWaitVblankCB: could not find waiting thread info."); return; } vblankPausedWaits[pauseKey] = __DisplayGetVCount() + waitData.vcountUnblock; - DEBUG_LOG(SCEDISPLAY, "sceDisplayWaitVblankCB: Suspending vblank wait for callback"); + DEBUG_LOG(Log::sceDisplay, "sceDisplayWaitVblankCB: Suspending vblank wait for callback"); } void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId) { @@ -342,7 +344,7 @@ void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId) { // Still have to wait a bit longer. vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vcountUnblock - __DisplayGetVCount())); - DEBUG_LOG(SCEDISPLAY, "sceDisplayWaitVblankCB: Resuming vblank wait from callback"); + DEBUG_LOG(Log::sceDisplay, "sceDisplayWaitVblankCB: Resuming vblank wait from callback"); } void __DisplaySetWasPaused() { @@ -385,7 +387,7 @@ static void DoFrameDropLogging(float scaledTimestep) { char stats[4096]; __DisplayGetDebugStats(stats, sizeof(stats)); - NOTICE_LOG(SCEDISPLAY, "Dropping frames - budget = %.2fms / %.1ffps, actual = %.2fms (+%.2fms) / %.1ffps\n%s", scaledTimestep * 1000.0, 1.0 / scaledTimestep, actualTimestep * 1000.0, (actualTimestep - scaledTimestep) * 1000.0, 1.0 / actualTimestep, stats); + NOTICE_LOG(Log::sceDisplay, "Dropping frames - budget = %.2fms / %.1ffps, actual = %.2fms (+%.2fms) / %.1ffps\n%s", scaledTimestep * 1000.0, 1.0 / scaledTimestep, actualTimestep * 1000.0, (actualTimestep - scaledTimestep) * 1000.0, 1.0 / actualTimestep, stats); } } @@ -499,7 +501,7 @@ static void DoFrameIdleTiming() { void hleEnterVblank(u64 userdata, int cyclesLate) { int vbCount = userdata; - VERBOSE_LOG(SCEDISPLAY, "Enter VBlank %i", vbCount); + VERBOSE_LOG(Log::sceDisplay, "Enter VBlank %i", vbCount); DisplayFireVblankStart(); @@ -530,7 +532,7 @@ void hleEnterVblank(u64 userdata, int cyclesLate) { // TODO: Should this be done here or in hleLeaveVblank? if (framebufIsLatched) { - DEBUG_LOG(SCEDISPLAY, "Setting latched framebuffer %08x (prev: %08x)", latchedFramebuf.topaddr, framebuf.topaddr); + DEBUG_LOG(Log::sceDisplay, "Setting latched framebuffer %08x (prev: %08x)", latchedFramebuf.topaddr, framebuf.topaddr); framebuf = latchedFramebuf; framebufIsLatched = false; gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.stride, framebuf.fmt); @@ -562,6 +564,8 @@ static void NotifyUserIfSlow() { } void __DisplayFlip(int cyclesLate) { + __DisplaySetFramerate(); + flippedThisFrame = true; // We flip only if the framebuffer was dirty. This eliminates flicker when using // non-buffered rendering. The interaction with frame skipping seems to need @@ -597,7 +601,7 @@ void __DisplayFlip(int cyclesLate) { } if (!FrameTimingThrottled()) { - // NOTICE_LOG(SYSTEM, "Throttle: %d %d", (int)fastForwardSkipFlip, (int)postEffectRequiresFlip); + // NOTICE_LOG(Log::System, "Throttle: %d %d", (int)fastForwardSkipFlip, (int)postEffectRequiresFlip); } const bool fbDirty = gpu->FramebufferDirty(); @@ -709,7 +713,7 @@ void hleAfterFlip(u64 userdata, int cyclesLate) { void hleLeaveVblank(u64 userdata, int cyclesLate) { flippedThisFrame = false; - VERBOSE_LOG(SCEDISPLAY,"Leave VBlank %i", (int)userdata - 1); + VERBOSE_LOG(Log::sceDisplay,"Leave VBlank %i", (int)userdata - 1); CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs) - cyclesLate, enterVblankEvent, userdata); // Fire the vblank listeners after the vblank completes. @@ -761,7 +765,7 @@ void hleLagSync(u64 userdata, int cyclesLate) { } static u32 sceDisplayIsVblank() { - return hleLogSuccessI(SCEDISPLAY, DisplayIsVblank()); + return hleLogSuccessI(Log::sceDisplay, DisplayIsVblank()); } static int DisplayWaitForVblanks(const char *reason, int vblanks, bool callbacks = false) { @@ -777,7 +781,7 @@ static int DisplayWaitForVblanks(const char *reason, int vblanks, bool callbacks vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vblanks)); __KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, callbacks, reason); - return hleLogSuccessVerboseI(SCEDISPLAY, 0, "waiting for %d vblanks", vblanks); + return hleLogSuccessVerboseI(Log::sceDisplay, 0, "waiting for %d vblanks", vblanks); } void __DisplayWaitForVblanks(const char* reason, int vblanks, bool callbacks) { @@ -786,13 +790,13 @@ void __DisplayWaitForVblanks(const char* reason, int vblanks, bool callbacks) { static u32 sceDisplaySetMode(int displayMode, int displayWidth, int displayHeight) { if (displayMode != PSP_DISPLAY_MODE_LCD || displayWidth != 480 || displayHeight != 272) { - WARN_LOG_REPORT(SCEDISPLAY, "Video out requested, not supported: mode=%d size=%d,%d", displayMode, displayWidth, displayHeight); + WARN_LOG_REPORT(Log::sceDisplay, "Video out requested, not supported: mode=%d size=%d,%d", displayMode, displayWidth, displayHeight); } if (displayMode != PSP_DISPLAY_MODE_LCD) { - return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "invalid mode"); + return hleLogWarning(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_MODE, "invalid mode"); } if (displayWidth != 480 || displayHeight != 272) { - return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid size"); + return hleLogWarning(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid size"); } hasSetMode = true; @@ -800,7 +804,7 @@ static u32 sceDisplaySetMode(int displayMode, int displayWidth, int displayHeigh width = displayWidth; height = displayHeight; - hleLogSuccessI(SCEDISPLAY, 0); + hleLogSuccessI(Log::sceDisplay, 0); // On success, this implicitly waits for a vblank start. return DisplayWaitForVblanks("display mode", 1); } @@ -841,24 +845,24 @@ void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelFormat, int sync) // Some games (GTA) never call this during gameplay, so bad place to put a framerate counter. u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) { if (sync != PSP_DISPLAY_SETBUF_IMMEDIATE && sync != PSP_DISPLAY_SETBUF_NEXTFRAME) { - return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "invalid sync mode"); + return hleLogError(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_MODE, "invalid sync mode"); } if (topaddr != 0 && !Memory::IsRAMAddress(topaddr) && !Memory::IsVRAMAddress(topaddr)) { - return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid address"); + return hleLogError(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid address"); } if ((topaddr & 0xF) != 0) { - return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_POINTER, "misaligned address"); + return hleLogError(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_POINTER, "misaligned address"); } if ((linesize & 0x3F) != 0 || (linesize == 0 && topaddr != 0)) { - return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid stride"); + return hleLogError(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid stride"); } if (pixelformat < 0 || pixelformat > GE_FORMAT_8888) { - return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_FORMAT, "invalid format"); + return hleLogError(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_FORMAT, "invalid format"); } if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) { if ((GEBufferFormat)pixelformat != latchedFramebuf.fmt || linesize != latchedFramebuf.stride) { - return hleReportError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "must change latched framebuf first"); + return hleReportError(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_MODE, "must change latched framebuf first"); } } @@ -905,12 +909,12 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) // Okay, the game is going at too high a frame rate. God of War and Fat Princess both do this. // Simply eating the cycles works and is fast, but breaks other games (like Jeanne d'Arc.) // So, instead, we delay this HLE thread only (a small deviation from correct behavior.) - return hleDelayResult(hleLogSuccessI(SCEDISPLAY, 0, "delaying frame thread"), "set framebuf", cyclesToUs(delayCycles)); + return hleDelayResult(hleLogSuccessI(Log::sceDisplay, 0, "delaying frame thread"), "set framebuf", cyclesToUs(delayCycles)); } else { if (topaddr == 0) { - return hleLogSuccessI(SCEDISPLAY, 0, "disabling display"); + return hleLogSuccessI(Log::sceDisplay, 0, "disabling display"); } else { - return hleLogSuccessI(SCEDISPLAY, 0); + return hleLogSuccessI(Log::sceDisplay, 0); } } } @@ -937,7 +941,7 @@ static u32 sceDisplayGetFramebuf(u32 topaddrPtr, u32 linesizePtr, u32 pixelForma if (Memory::IsValidAddress(pixelFormatPtr)) Memory::Write_U32(fbState.fmt, pixelFormatPtr); - return hleLogSuccessI(SCEDISPLAY, 0); + return hleLogSuccessI(Log::sceDisplay, 0); } static int DisplayWaitForVblanksCB(const char *reason, int vblanks) { @@ -954,18 +958,18 @@ static u32 sceDisplayWaitVblank() { } else { hleEatCycles(1110); hleReSchedule("vblank wait skipped"); - return hleLogSuccessI(SCEDISPLAY, 1, "not waiting since in vblank"); + return hleLogSuccessI(Log::sceDisplay, 1, "not waiting since in vblank"); } } static u32 sceDisplayWaitVblankStartMulti(int vblanks) { if (vblanks <= 0) { - return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid number of vblanks"); + return hleLogWarning(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid number of vblanks"); } if (!__KernelIsDispatchEnabled()) - return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogWarning(Log::sceDisplay, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); if (__IsInInterrupt()) - return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt"); + return hleLogWarning(Log::sceDisplay, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt"); return DisplayWaitForVblanks("vblank start multi waited", vblanks); } @@ -976,7 +980,7 @@ static u32 sceDisplayWaitVblankCB() { } else { hleEatCycles(1110); hleReSchedule("vblank wait skipped"); - return hleLogSuccessI(SCEDISPLAY, 1, "not waiting since in vblank"); + return hleLogSuccessI(Log::sceDisplay, 1, "not waiting since in vblank"); } } @@ -986,12 +990,12 @@ static u32 sceDisplayWaitVblankStartCB() { static u32 sceDisplayWaitVblankStartMultiCB(int vblanks) { if (vblanks <= 0) { - return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid number of vblanks"); + return hleLogWarning(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid number of vblanks"); } if (!__KernelIsDispatchEnabled()) - return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogWarning(Log::sceDisplay, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); if (__IsInInterrupt()) - return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt"); + return hleLogWarning(Log::sceDisplay, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt"); return DisplayWaitForVblanksCB("vblank start multi waited", vblanks); } @@ -999,17 +1003,17 @@ static u32 sceDisplayWaitVblankStartMultiCB(int vblanks) { static u32 sceDisplayGetVcount() { hleEatCycles(150); hleReSchedule("get vcount"); - return hleLogSuccessVerboseI(SCEDISPLAY, __DisplayGetVCount()); + return hleLogSuccessVerboseI(Log::sceDisplay, __DisplayGetVCount()); } static u32 sceDisplayGetCurrentHcount() { hleEatCycles(275); - return hleLogSuccessI(SCEDISPLAY, __DisplayGetCurrentHcount()); + return hleLogSuccessI(Log::sceDisplay, __DisplayGetCurrentHcount()); } static int sceDisplayAdjustAccumulatedHcount(int value) { if (value < 0) { - return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid value"); + return hleLogError(Log::sceDisplay, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid value"); } // Since it includes the current hCount, find the difference to apply to the base. @@ -1017,24 +1021,24 @@ static int sceDisplayAdjustAccumulatedHcount(int value) { int diff = value - accumHCount; DisplayAdjustAccumulatedHcount(diff); - return hleLogSuccessI(SCEDISPLAY, 0); + return hleLogSuccessI(Log::sceDisplay, 0); } static int sceDisplayGetAccumulatedHcount() { u32 accumHCount = __DisplayGetAccumulatedHcount(); hleEatCycles(235); - return hleLogSuccessI(SCEDISPLAY, accumHCount); + return hleLogSuccessI(Log::sceDisplay, accumHCount); } static float sceDisplayGetFramePerSec() { const static float framePerSec = 59.9400599f; - VERBOSE_LOG(SCEDISPLAY,"%f=sceDisplayGetFramePerSec()", framePerSec); + VERBOSE_LOG(Log::sceDisplay,"%f=sceDisplayGetFramePerSec()", framePerSec); return framePerSec; // (9MHz * 1)/(525 * 286) } static u32 sceDisplayIsForeground() { int result = hasSetMode && framebuf.topaddr != 0 ? 1 : 0; - return hleLogSuccessI(SCEDISPLAY, result); + return hleLogSuccessI(Log::sceDisplay, result); } static u32 sceDisplayGetMode(u32 modeAddr, u32 widthAddr, u32 heightAddr) { @@ -1044,7 +1048,7 @@ static u32 sceDisplayGetMode(u32 modeAddr, u32 widthAddr, u32 heightAddr) { Memory::Write_U32(width, widthAddr); if (Memory::IsValidAddress(heightAddr)) Memory::Write_U32(height, heightAddr); - return hleLogSuccessI(SCEDISPLAY, 0); + return hleLogSuccessI(Log::sceDisplay, 0); } static u32 sceDisplayIsVsync() { @@ -1052,19 +1056,19 @@ static u32 sceDisplayIsVsync() { u64 start = DisplayFrameStartTicks() + msToCycles(vsyncStartMs); u64 end = DisplayFrameStartTicks() + msToCycles(vsyncEndMs); - return hleLogSuccessI(SCEDISPLAY, now >= start && now <= end ? 1 : 0); + return hleLogSuccessI(Log::sceDisplay, now >= start && now <= end ? 1 : 0); } static u32 sceDisplayGetResumeMode(u32 resumeModeAddr) { if (Memory::IsValidAddress(resumeModeAddr)) Memory::Write_U32(resumeMode, resumeModeAddr); - return hleLogSuccessI(SCEDISPLAY, 0); + return hleLogSuccessI(Log::sceDisplay, 0); } static u32 sceDisplaySetResumeMode(u32 rMode) { // Not sure what this does, seems to do nothing in tests and accept all values. resumeMode = rMode; - return hleReportError(SCEDISPLAY, 0, "unsupported"); + return hleReportError(Log::sceDisplay, 0, "unsupported"); } static u32 sceDisplayGetBrightness(u32 levelAddr, u32 otherAddr) { @@ -1077,19 +1081,19 @@ static u32 sceDisplayGetBrightness(u32 levelAddr, u32 otherAddr) { if (Memory::IsValidAddress(otherAddr)) { Memory::Write_U32(0, otherAddr); } - return hleLogWarning(SCEDISPLAY, 0); + return hleLogWarning(Log::sceDisplay, 0); } static u32 sceDisplaySetBrightness(int level, int other) { // Note: Only usable in kernel mode. brightnessLevel = level; - return hleLogWarning(SCEDISPLAY, 0); + return hleLogWarning(Log::sceDisplay, 0); } static u32 sceDisplaySetHoldMode(u32 hMode) { // Not sure what this does, seems to do nothing in tests and accept all values. holdMode = hMode; - return hleReportError(SCEDISPLAY, 0, "unsupported"); + return hleReportError(Log::sceDisplay, 0, "unsupported"); } const HLEFunction sceDisplay[] = { @@ -1126,8 +1130,12 @@ void Register_sceDisplay_driver() { RegisterModule("sceDisplay_driver", ARRAY_SIZE(sceDisplay), sceDisplay); } -void __DisplaySetFramerate(int value) { - framerate = value; +static void __DisplaySetFramerate(void) { + if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) + framerate = g_Config.bForce72Hz ? 72 : 60; + else + framerate = g_Config.iDisplayRefreshRate; + timePerVblank = 1.001 / (double)framerate; frameMs = 1001.0 / (double)framerate; } diff --git a/Core/HLE/sceDisplay.h b/Core/HLE/sceDisplay.h index b68133e8a2..bb134af815 100644 --- a/Core/HLE/sceDisplay.h +++ b/Core/HLE/sceDisplay.h @@ -34,5 +34,3 @@ void __DisplaySetWasPaused(); void Register_sceDisplay_driver(); void __DisplayWaitForVblanks(const char* reason, int vblanks, bool callbacks = false); - -void __DisplaySetFramerate(int value); diff --git a/Core/HLE/sceDmac.cpp b/Core/HLE/sceDmac.cpp index 8feb1fc89e..01abc95a0c 100644 --- a/Core/HLE/sceDmac.cpp +++ b/Core/HLE/sceDmac.cpp @@ -73,24 +73,24 @@ static int __DmacMemcpy(u32 dst, u32 src, u32 size) { static u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) { if (size == 0) { // Some games seem to do this frequently. - DEBUG_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size); + DEBUG_LOG(Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size); return SCE_KERNEL_ERROR_INVALID_SIZE; } if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) { - ERROR_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size); + ERROR_LOG(Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size); return SCE_KERNEL_ERROR_INVALID_POINTER; } if (dst + size >= 0x80000000 || src + size >= 0x80000000 || size >= 0x80000000) { - ERROR_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): illegal size", dst, src, size); + ERROR_LOG(Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): illegal size", dst, src, size); return SCE_KERNEL_ERROR_PRIV_REQUIRED; } if (dmacMemcpyDeadline > CoreTiming::GetTicks()) { - WARN_LOG_REPORT_ONCE(overlapDmacMemcpy, HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%d): overlapping read", dst, src, size); + WARN_LOG_REPORT_ONCE(overlapDmacMemcpy, Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%d): overlapping read", dst, src, size); // TODO: Should block, seems like copy doesn't start until previous finishes. // Might matter for overlapping copies. } else { - DEBUG_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); + DEBUG_LOG(Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); } return __DmacMemcpy(dst, src, size); @@ -98,23 +98,23 @@ static u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) { static u32 sceDmacTryMemcpy(u32 dst, u32 src, u32 size) { if (size == 0) { - ERROR_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size); + ERROR_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size); return SCE_KERNEL_ERROR_INVALID_SIZE; } if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) { - ERROR_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size); + ERROR_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size); return SCE_KERNEL_ERROR_INVALID_POINTER; } if (dst + size >= 0x80000000 || src + size >= 0x80000000 || size >= 0x80000000) { - ERROR_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): illegal size", dst, src, size); + ERROR_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): illegal size", dst, src, size); return SCE_KERNEL_ERROR_PRIV_REQUIRED; } if (dmacMemcpyDeadline > CoreTiming::GetTicks()) { - DEBUG_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): busy", dst, src, size); + DEBUG_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): busy", dst, src, size); return SCE_KERNEL_ERROR_BUSY; } else { - DEBUG_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); + DEBUG_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); } return __DmacMemcpy(dst, src, size); diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index cb729b672d..209bca2f10 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -127,7 +127,7 @@ static std::vector internalFonts; // However, these we must save - but we could take a shortcut // for LoadedFonts that point to internal fonts. static std::map fontMap; -static std::map fontLibMap; +static std::map fontLibMap; // We keep this list to avoid ptr references, even before alloc is called. static std::vector fontLibList; @@ -152,7 +152,7 @@ enum FontOpenMode { class Font { public: // For savestates only. - Font() { + Font() : valid_(false) { } Font(const u8 *data, size_t dataSize) { @@ -273,8 +273,7 @@ private: class LoadedFont { public: // For savestates only. - LoadedFont() : font_(NULL) { - } + LoadedFont() {} LoadedFont(Font *font, FontOpenMode mode, u32 fontLibID, u32 handle) : fontLibID_(fontLibID), font_(font), handle_(handle), mode_(mode), open_(true) {} @@ -296,9 +295,18 @@ public: const Font *GetFont() const { return font_; } const PGF *GetPGF() const { return font_->GetPGF(); } - const FontLib *GetFontLib() const { return fontLibList[fontLibID_]; } - FontLib *GetFontLib() { return fontLibList[fontLibID_]; } + const FontLib *GetFontLib() const { + _dbg_assert_(IsValid()); + return fontLibList[fontLibID_]; + } + FontLib *GetFontLib() { + _dbg_assert_(IsValid()); + return fontLibList[fontLibID_]; + } u32 Handle() const { return handle_; } + bool IsValid() const { + return fontLibID_ >= 0 && fontLibID_ < (int)fontLibList.size(); + } bool GetCharInfo(int charCode, PGFCharInfo *charInfo, int glyphType = FONT_PGF_CHARGLYPH) const; void DrawCharacter(const GlyphImage *image, int clipX, int clipY, int clipWidth, int clipHeight, int charCode, int glyphType) const; @@ -319,7 +327,7 @@ public: Do(p, numInternalFonts); // It's okay if numInternalFonts was zero and we've now loaded them. if (numInternalFonts != (int)internalFonts.size() && numInternalFonts != 0) { - ERROR_LOG(SCEFONT, "Unable to load state: different internal font count."); + ERROR_LOG(Log::sceFont, "Unable to load state: different internal font count (%d in save, %d in memory)", numInternalFonts, (int)internalFonts.size()); p.SetError(p.ERROR_FAILURE); return; } @@ -331,7 +339,7 @@ public: Do(p, font_); } else if (p.mode == p.MODE_READ) { if (internalFont < 0 || internalFont >= (int)internalFonts.size()) { - ERROR_LOG(SCEFONT, "Unable to load state: unexpected internal font index."); + ERROR_LOG(Log::sceFont, "Unable to load state: unexpected internal font index."); p.SetError(p.ERROR_FAILURE); return; } @@ -351,11 +359,12 @@ public: } private: - u32 fontLibID_; - Font *font_; - u32 handle_; - FontOpenMode mode_; - bool open_; + int fontLibID_ = -1; + Font *font_ = nullptr; + u32 handle_ = 0; + FontOpenMode mode_ = FONT_OPEN_INTERNAL_STINGY; + bool open_ = false; + DISALLOW_COPY_AND_ASSIGN(LoadedFont); }; @@ -379,8 +388,10 @@ public: void SetFontLib(u32 fontLibID, u32 errorCodePtr) { fontLibID_ = fontLibID; errorCodePtr_ = errorCodePtr; } private: - u32 fontLibID_; - u32 errorCodePtr_; + int fontLibID_ = -1; + u32 errorCodePtr_ = 0; + + DISALLOW_COPY_AND_ASSIGN(PostAllocCallback); }; class PostOpenCallback : public PSPAction { @@ -395,10 +406,12 @@ public: Do(p, fontLibID_); } void run(MipsCall &call) override; - void SetFontLib(u32 fontLibID) { fontLibID_ = fontLibID; } + void SetFontLib(int fontLibID) { fontLibID_ = fontLibID; } private: - u32 fontLibID_; + int fontLibID_ = -1; + + DISALLOW_COPY_AND_ASSIGN(PostOpenCallback); }; class PostOpenAllocCallback : public PSPAction { @@ -415,13 +428,15 @@ public: Do(p, fontIndex_); } void run(MipsCall &call) override; - void SetFontLib(u32 fontLibID) { fontLibID_ = fontLibID; } + void SetFontLib(int fontLibID) { fontLibID_ = fontLibID; } void SetFont(u32 handle, int index) { fontHandle_ = handle; fontIndex_ = index; } private: - u32 fontLibID_; - u32 fontHandle_; - int fontIndex_; + int fontLibID_ = -1; + u32 fontHandle_ = 0; + int fontIndex_ = -1; + + DISALLOW_COPY_AND_ASSIGN(PostOpenAllocCallback); }; class PostCharInfoAllocCallback : public PSPAction { @@ -436,10 +451,12 @@ public: Do(p, fontLibID_); } void run(MipsCall &call) override; - void SetFontLib(u32 fontLibID) { fontLibID_ = fontLibID; } + void SetFontLib(int fontLibID) { fontLibID_ = fontLibID; } private: - u32 fontLibID_; + int fontLibID_ = -1; + + DISALLOW_COPY_AND_ASSIGN(PostCharInfoAllocCallback); }; class PostCharInfoFreeCallback : public PSPAction { @@ -455,18 +472,19 @@ public: Do(p, charInfo_); } void run(MipsCall &call) override; - void SetFontLib(u32 fontLibID) { fontLibID_ = fontLibID; } + void SetFontLib(int fontLibID) { fontLibID_ = fontLibID; } void SetCharInfo(PSPPointer charInfo) { charInfo_ = charInfo; } private: - u32 fontLibID_; + int fontLibID_ = -1; PSPPointer charInfo_; -}; + DISALLOW_COPY_AND_ASSIGN(PostCharInfoFreeCallback); +}; struct NativeFontLib { FontNewLibParams params; - // TODO + // TODO (what?) u32_le fontInfo1; u32_le fontInfo2; u16_le unk1; @@ -485,7 +503,7 @@ struct FontImageRect { }; // A "fontLib" is a container of loaded fonts. -// One can open either "internal" fonts or custom fonts into a fontlib. +// One can open either "internal" fonts or load custom fonts into a fontlib. class FontLib { public: FontLib() { @@ -507,8 +525,8 @@ public: hleEnqueueCall(allocFuncAddr(), 2, args, action); } - u32 GetListID() { - return (u32)(std::find(fontLibList.begin(), fontLibList.end(), this) - fontLibList.begin()); + int GetListID() { + return (int)(std::find(fontLibList.begin(), fontLibList.end(), this) - fontLibList.begin()); } void Done() { @@ -605,12 +623,12 @@ public: if (foundFontIndex < 0 || fontRefCount_[foundFontIndex] >= MAX_FONT_REFS) { error = ERROR_FONT_TOO_MANY_OPEN_FONTS; - hleLogError(SCEFONT, 0, "Too many fonts opened in FontLib"); + hleLogError(Log::sceFont, 0, "Too many fonts opened in FontLib"); return nullptr; } if (!font->IsValid()) { error = ERROR_FONT_INVALID_FONT_DATA; - hleLogError(SCEFONT, 0, "Invalid font data"); + hleLogError(Log::sceFont, 0, "Invalid font data"); return nullptr; } @@ -623,7 +641,7 @@ public: // Before replacing it and forgetting about it, let's free it. delete prevFont->second; } - fontMap[loadedFont->Handle()] = loadedFont; + fontMap.insert_or_assign(loadedFont->Handle(), loadedFont); } else { loadedFont = fontMap[fonts_[foundFontIndex]]; } @@ -770,9 +788,8 @@ private: DISALLOW_COPY_AND_ASSIGN(FontLib); }; - void PostAllocCallback::run(MipsCall &call) { - INFO_LOG(SCEFONT, "Entering PostAllocCallback::run"); + INFO_LOG(Log::sceFont, "Entering PostAllocCallback::run"); u32 v0 = currentMIPS->r[MIPS_REG_V0]; if (v0 == 0) { // TODO: Who deletes fontLib? @@ -780,28 +797,32 @@ void PostAllocCallback::run(MipsCall &call) { Memory::Write_U32(ERROR_FONT_OUT_OF_MEMORY, errorCodePtr_); call.setReturnValue(0); } else { + _dbg_assert_(fontLibID_ >= 0); FontLib *fontLib = fontLibList[fontLibID_]; fontLib->AllocDone(v0); fontLibMap[fontLib->handle()] = fontLibID_; // This is the same as v0 above. call.setReturnValue(fontLib->handle()); } - INFO_LOG(SCEFONT, "Leaving PostAllocCallback::run"); + INFO_LOG(Log::sceFont, "Leaving PostAllocCallback::run"); } void PostOpenCallback::run(MipsCall &call) { + _dbg_assert_(fontLibID_ >= 0); FontLib *fontLib = fontLibList[fontLibID_]; u32 v0 = currentMIPS->r[MIPS_REG_V0]; fontLib->SetFileFontHandle(v0); } void PostOpenAllocCallback::run(MipsCall &call) { + _dbg_assert_(fontLibID_ >= 0); FontLib *fontLib = fontLibList[fontLibID_]; u32 v0 = currentMIPS->r[MIPS_REG_V0]; fontLib->SetOpenAllocatedAddress(fontIndex_, v0); } void PostCharInfoAllocCallback::run(MipsCall &call) { + _dbg_assert_(fontLibID_ >= 0); FontLib *fontLib = fontLibList[fontLibID_]; u32 v0 = currentMIPS->r[MIPS_REG_V0]; if (v0 == 0) { @@ -824,20 +845,23 @@ void PostCharInfoFreeCallback::run(MipsCall &call) { } inline bool LoadedFont::GetCharInfo(int charCode, PGFCharInfo *charInfo, int glyphType) const { + _dbg_assert_(IsValid()); auto fontLib = GetFontLib(); int altCharCode = fontLib == NULL ? -1 : fontLib->GetAltCharCode(); return GetPGF()->GetCharInfo(charCode, charInfo, altCharCode, glyphType); } inline void LoadedFont::DrawCharacter(const GlyphImage *image, int clipX, int clipY, int clipWidth, int clipHeight, int charCode, int glyphType) const { + _dbg_assert_(IsValid()); auto fontLib = GetFontLib(); int altCharCode = fontLib == NULL ? -1 : fontLib->GetAltCharCode(); GetPGF()->DrawCharacter(image, clipX, clipY, clipWidth, clipHeight, charCode, altCharCode, glyphType); } static FontLib *GetFontLib(u32 handle) { - if (fontLibMap.find(handle) != fontLibMap.end()) { - return fontLibList[fontLibMap[handle]]; + auto iter = fontLibMap.find(handle); + if (iter != fontLibMap.end()) { + return fontLibList[iter->second]; } return nullptr; } @@ -848,11 +872,11 @@ static LoadedFont *GetLoadedFont(u32 handle, bool allowClosed) { if (iter->second->IsOpen() || allowClosed) { return fontMap[handle]; } else { - ERROR_LOG(SCEFONT, "Font exists but is closed, which was not allowed in this call."); + ERROR_LOG(Log::sceFont, "Font exists but is closed, which was not allowed in this call."); return 0; } } else { - ERROR_LOG(SCEFONT, "No font with handle %08x", handle); + ERROR_LOG(Log::sceFont, "No font with handle %08x", handle); return 0; } } @@ -875,12 +899,12 @@ static void __LoadInternalFonts() { std::string fontFilename = gameFontPath + entry.fileName; std::vector buffer; if (pspFileSystem.ReadEntireFile(fontFilename, buffer) < 0) { - ERROR_LOG(SCEFONT, "Failed opening font %s", fontFilename.c_str()); + ERROR_LOG(Log::sceFont, "Failed opening font %s", fontFilename.c_str()); continue; } - DEBUG_LOG(SCEFONT, "Loading internal font %s (%i bytes)", fontFilename.c_str(), (int)buffer.size()); + DEBUG_LOG(Log::sceFont, "Loading internal font %s (%i bytes)", fontFilename.c_str(), (int)buffer.size()); internalFonts.push_back(new Font(buffer, entry)); - DEBUG_LOG(SCEFONT, "Loaded font %s", fontFilename.c_str()); + DEBUG_LOG(Log::sceFont, "Loaded font %s", fontFilename.c_str()); return; } } @@ -906,12 +930,12 @@ static void __LoadInternalFonts() { } if (bufferRead) { - DEBUG_LOG(SCEFONT, "Loading internal font %s (%i bytes)", fontFilename.c_str(), (int)buffer.size()); + DEBUG_LOG(Log::sceFont, "Loading internal font %s (%i bytes)", fontFilename.c_str(), (int)buffer.size()); internalFonts.push_back(new Font(buffer, entry)); - DEBUG_LOG(SCEFONT, "Loaded font %s", fontFilename.c_str()); + DEBUG_LOG(Log::sceFont, "Loaded font %s", fontFilename.c_str()); } else if (!entry.ignoreIfMissing) { - WARN_LOG(SCEFONT, "Font file not found: %s", fontFilename.c_str()); + WARN_LOG(Log::sceFont, "Font file not found: %s", fontFilename.c_str()); } } } @@ -935,9 +959,14 @@ void __FontInit() { void __FontShutdown() { for (auto iter = fontMap.begin(); iter != fontMap.end(); iter++) { - FontLib *fontLib = iter->second->GetFontLib(); - if (fontLib) - fontLib->CloseFont(iter->second, true); + if (iter->second->IsValid()) { + FontLib *fontLib = iter->second->GetFontLib(); + if (fontLib) { + fontLib->CloseFont(iter->second, true); + } + } else { + ERROR_LOG(Log::HLE, "__FontShutdown: Bad entry in fontMap"); + } delete iter->second; } fontMap.clear(); @@ -963,7 +992,7 @@ void __FontDoState(PointerWrap &p) { needInternalFonts = !internalFonts.empty(); Do(p, needInternalFonts); } - if (needInternalFonts) + if (needInternalFonts && p.mode == PointerWrap::MODE_READ) __LoadInternalFonts(); Do(p, fontLibList); @@ -994,17 +1023,17 @@ static u32 sceFontNewLib(u32 paramPtr, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!params.IsValid() || !errorCode.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontNewLib(%08x, %08x): invalid addresses", paramPtr, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontNewLib(%08x, %08x): invalid addresses", paramPtr, errorCodePtr); // The PSP would crash in this situation, not a real error code. return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } if (!Memory::IsValidAddress(params->allocFuncAddr) || !Memory::IsValidAddress(params->freeFuncAddr)) { - ERROR_LOG_REPORT(SCEFONT, "sceFontNewLib(%08x, %08x): missing alloc func", paramPtr, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontNewLib(%08x, %08x): missing alloc func", paramPtr, errorCodePtr); *errorCode = ERROR_FONT_INVALID_PARAMETER; return 0; } - INFO_LOG(SCEFONT, "sceFontNewLib(%08x, %08x)", paramPtr, errorCodePtr); + INFO_LOG(Log::sceFont, "sceFontNewLib(%08x, %08x)", paramPtr, errorCodePtr); *errorCode = 0; FontLib *newLib = new FontLib(params, errorCodePtr); @@ -1019,10 +1048,10 @@ static int sceFontDoneLib(u32 fontLibHandle) { FontLib *fl = GetFontLib(fontLibHandle); if (fl) { fl->Done(); - return hleLogSuccessInfoI(SCEFONT, 0); + return hleLogSuccessInfoI(Log::sceFont, 0); } - return hleLogWarning(SCEFONT, 0, "invalid font lib"); + return hleLogWarning(Log::sceFont, 0, "invalid font lib"); } // Open internal font into a FontLib @@ -1030,17 +1059,17 @@ static u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { // Would crash on the PSP. - return hleLogError(SCEFONT, -1, "invalid error address"); + return hleLogError(Log::sceFont, -1, "invalid error address"); } FontLib *fontLib = GetFontLib(libHandle); if (!fontLib) { *errorCode = ERROR_FONT_INVALID_LIBID; - return hleLogDebug(SCEFONT, 0, "invalid font lib"); + return hleLogDebug(Log::sceFont, 0, "invalid font lib"); } if (index >= internalFonts.size()) { *errorCode = ERROR_FONT_INVALID_PARAMETER; - return hleLogDebug(SCEFONT, 0, "invalid font index"); + return hleLogDebug(Log::sceFont, 0, "invalid font index"); } FontOpenMode openMode = mode != 1 ? FONT_OPEN_INTERNAL_STINGY : FONT_OPEN_INTERNAL_FULL; @@ -1049,8 +1078,8 @@ static u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) { *errorCode = 0; // Delay only on the first open. if (fontLib->GetFontRefCount(internalFonts[index]) == 1) - return hleDelayResult(hleLogSuccessX(SCEFONT, font->Handle()), "font open", 10000); - return hleLogSuccessX(SCEFONT, font->Handle()); + return hleDelayResult(hleLogSuccessX(Log::sceFont, font->Handle()), "font open", 10000); + return hleLogSuccessX(Log::sceFont, font->Handle()); } return 0; } @@ -1059,21 +1088,21 @@ static u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) { static u32 sceFontOpenUserMemory(u32 libHandle, u32 memoryFontPtr, u32 memoryFontLength, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - return hleReportError(SCEFONT, -1, "invalid error address"); + return hleReportError(Log::sceFont, -1, "invalid error address"); } if (!Memory::IsValidAddress(memoryFontPtr)) { *errorCode = ERROR_FONT_INVALID_PARAMETER; - return hleReportError(SCEFONT, 0, "invalid address"); + return hleReportError(Log::sceFont, 0, "invalid address"); } FontLib *fontLib = GetFontLib(libHandle); if (!fontLib) { *errorCode = ERROR_FONT_INVALID_LIBID; - return hleReportError(SCEFONT, 0, "invalid font lib"); + return hleReportError(Log::sceFont, 0, "invalid font lib"); } if (memoryFontLength == 0) { *errorCode = ERROR_FONT_INVALID_PARAMETER; - return hleReportError(SCEFONT, 0, "invalid size"); + return hleReportError(Log::sceFont, 0, "invalid size"); } const u8 *fontData = Memory::GetPointer(memoryFontPtr); @@ -1088,7 +1117,7 @@ static u32 sceFontOpenUserMemory(u32 libHandle, u32 memoryFontPtr, u32 memoryFon LoadedFont *font = fontLib->OpenFont(f, FONT_OPEN_USERBUFFER, *errorCode); if (font) { *errorCode = 0; - return hleLogSuccessX(SCEFONT, font->Handle()); + return hleLogSuccessX(Log::sceFont, font->Handle()); } delete f; return 0; @@ -1098,29 +1127,29 @@ static u32 sceFontOpenUserMemory(u32 libHandle, u32 memoryFontPtr, u32 memoryFon static u32 sceFontOpenUserFile(u32 libHandle, const char *fileName, u32 mode, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - return hleReportError(SCEFONT, ERROR_FONT_INVALID_PARAMETER, "invalid error address"); + return hleReportError(Log::sceFont, ERROR_FONT_INVALID_PARAMETER, "invalid error address"); } if (!fileName) { *errorCode = ERROR_FONT_INVALID_PARAMETER; - return hleReportError(SCEFONT, 0, "invalid filename"); + return hleReportError(Log::sceFont, 0, "invalid filename"); } FontLib *fontLib = GetFontLib(libHandle); if (!fontLib) { *errorCode = ERROR_FONT_INVALID_LIBID; - return hleReportError(SCEFONT, 0, "invalid font lib"); + return hleReportError(Log::sceFont, 0, "invalid font lib"); } // TODO: Technically, we only do this if mode = 1. Mode 0 uses the handlers. if (mode != 1) { - WARN_LOG_REPORT(SCEFONT, "Loading file directly instead of using handlers: %s", fileName); + WARN_LOG_REPORT(Log::sceFont, "Loading file directly instead of using handlers: %s", fileName); } std::vector buffer; if (pspFileSystem.ReadEntireFile(fileName, buffer) != 0) { *errorCode = ERROR_FONT_HANDLER_OPEN_FAILED; - return hleLogError(SCEFONT, 0, "file does not exist"); + return hleLogError(Log::sceFont, 0, "file does not exist"); } Font *f = new Font(buffer); @@ -1128,7 +1157,7 @@ static u32 sceFontOpenUserFile(u32 libHandle, const char *fileName, u32 mode, u3 LoadedFont *font = fontLib->OpenFont(f, openMode, *errorCode); if (font) { *errorCode = 0; - return hleLogSuccessInfoX(SCEFONT, font->Handle()); + return hleLogSuccessInfoX(Log::sceFont, font->Handle()); } delete f; @@ -1139,36 +1168,36 @@ static u32 sceFontOpenUserFile(u32 libHandle, const char *fileName, u32 mode, u3 static int sceFontClose(u32 fontHandle) { LoadedFont *font = GetLoadedFont(fontHandle, false); if (font) { - DEBUG_LOG(SCEFONT, "sceFontClose(%x)", fontHandle); + DEBUG_LOG(Log::sceFont, "sceFontClose(%x)", fontHandle); FontLib *fontLib = font->GetFontLib(); if (fontLib) { fontLib->CloseFont(font, false); } } else - ERROR_LOG(SCEFONT, "sceFontClose(%x) - font not open?", fontHandle); + ERROR_LOG(Log::sceFont, "sceFontClose(%x) - font not open?", fontHandle); return 0; } static int sceFontFindOptimumFont(u32 libHandle, u32 fontStylePtr, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - return hleReportError(SCEFONT, SCE_KERNEL_ERROR_INVALID_ARGUMENT, "invalid error address"); + return hleReportError(Log::sceFont, SCE_KERNEL_ERROR_INVALID_ARGUMENT, "invalid error address"); } FontLib *fontLib = GetFontLib(libHandle); if (!fontLib) { *errorCode = ERROR_FONT_INVALID_LIBID; - return hleReportError(SCEFONT, 0, "invalid font lib"); + return hleReportError(Log::sceFont, 0, "invalid font lib"); } if (!Memory::IsValidAddress(fontStylePtr)) { // Yes, actually. Must've been a typo in the library. *errorCode = ERROR_FONT_INVALID_LIBID; - return hleReportError(SCEFONT, 0, "invalid style address"); + return hleReportError(Log::sceFont, 0, "invalid style address"); } auto requestedStyle = PSPPointer::Create(fontStylePtr); - DEBUG_LOG(SCEFONT, "requestedStyle fontAttributes %i,fontCountry %i,fontExpire %i,fontFamily %i,fontFileName %s,fontH %f,fontHRes %f,fontLanguage %i,fontName %s,fontRegion %i,fontStyle %i,fontStyleSub %i,fontV %f,fontVRes %f,fontWeight %f", requestedStyle->fontAttributes, requestedStyle->fontCountry, requestedStyle->fontExpire, requestedStyle->fontFamily, requestedStyle->fontFileName, requestedStyle->fontH, requestedStyle->fontHRes, requestedStyle->fontLanguage, requestedStyle->fontName, requestedStyle->fontRegion, requestedStyle->fontStyle, requestedStyle->fontStyleSub, requestedStyle->fontV, requestedStyle->fontVRes, requestedStyle->fontWeight); + DEBUG_LOG(Log::sceFont, "requestedStyle fontAttributes %i,fontCountry %i,fontExpire %i,fontFamily %i,fontFileName %s,fontH %f,fontHRes %f,fontLanguage %i,fontName %s,fontRegion %i,fontStyle %i,fontStyleSub %i,fontV %f,fontVRes %f,fontWeight %f", requestedStyle->fontAttributes, requestedStyle->fontCountry, requestedStyle->fontExpire, requestedStyle->fontFamily, requestedStyle->fontFileName, requestedStyle->fontH, requestedStyle->fontHRes, requestedStyle->fontLanguage, requestedStyle->fontName, requestedStyle->fontRegion, requestedStyle->fontStyle, requestedStyle->fontStyleSub, requestedStyle->fontV, requestedStyle->fontVRes, requestedStyle->fontWeight); // Find the first nearest match for H/V, OR the last exact match for others. float hRes = requestedStyle->fontHRes > 0.0f ? (float)requestedStyle->fontHRes : fontLib->FontHRes(); @@ -1218,10 +1247,10 @@ static int sceFontFindOptimumFont(u32 libHandle, u32 fontStylePtr, u32 errorCode } if (optimumFont) { *errorCode = 0; - return hleLogSuccessInfoX(SCEFONT, GetInternalFontIndex(optimumFont) ,""); + return hleLogSuccessInfoX(Log::sceFont, GetInternalFontIndex(optimumFont) ,""); } else { *errorCode = 0; - return hleLogSuccessInfoX(SCEFONT, 0, ""); + return hleLogSuccessInfoX(Log::sceFont, 0, ""); } } @@ -1229,27 +1258,27 @@ static int sceFontFindOptimumFont(u32 libHandle, u32 fontStylePtr, u32 errorCode static int sceFontFindFont(u32 libHandle, u32 fontStylePtr, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontFindFont(%x, %x, %x): invalid error address", libHandle, fontStylePtr, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontFindFont(%x, %x, %x): invalid error address", libHandle, fontStylePtr, errorCodePtr); return SCE_KERNEL_ERROR_INVALID_ARGUMENT; } FontLib *fontLib = GetFontLib(libHandle); if (!fontLib) { - ERROR_LOG_REPORT(SCEFONT, "sceFontFindFont(%08x, %08x, %08x): invalid font lib", libHandle, fontStylePtr, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontFindFont(%08x, %08x, %08x): invalid font lib", libHandle, fontStylePtr, errorCodePtr); *errorCode = ERROR_FONT_INVALID_LIBID; return 0; } if (!Memory::IsValidAddress(fontStylePtr)) { - ERROR_LOG_REPORT(SCEFONT, "sceFontFindFont(%08x, %08x, %08x): invalid style address", libHandle, fontStylePtr, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontFindFont(%08x, %08x, %08x): invalid style address", libHandle, fontStylePtr, errorCodePtr); *errorCode = ERROR_FONT_INVALID_PARAMETER; return 0; } - DEBUG_LOG(SCEFONT, "sceFontFindFont(%x, %x, %x)", libHandle, fontStylePtr, errorCodePtr); + DEBUG_LOG(Log::sceFont, "sceFontFindFont(%x, %x, %x)", libHandle, fontStylePtr, errorCodePtr); auto requestedStyle = PSPPointer::Create(fontStylePtr); - DEBUG_LOG(SCEFONT, "requestedStyle fontAttributes %i,fontCountry %i,fontExpire %i,fontFamily %i,fontFileName %s,fontH %f,fontHRes %f,fontLanguage %i,fontName %s,fontRegion %i,fontStyle %i,fontStyleSub %i,fontV %f,fontVRes %f,fontWeight %f", requestedStyle->fontAttributes, requestedStyle->fontCountry, requestedStyle->fontExpire, requestedStyle->fontFamily, requestedStyle->fontFileName, requestedStyle->fontH, requestedStyle->fontHRes, requestedStyle->fontLanguage, requestedStyle->fontName, requestedStyle->fontRegion, requestedStyle->fontStyle, requestedStyle->fontStyleSub, requestedStyle->fontV, requestedStyle->fontVRes, requestedStyle->fontWeight); + DEBUG_LOG(Log::sceFont, "requestedStyle fontAttributes %i,fontCountry %i,fontExpire %i,fontFamily %i,fontFileName %s,fontH %f,fontHRes %f,fontLanguage %i,fontName %s,fontRegion %i,fontStyle %i,fontStyleSub %i,fontV %f,fontVRes %f,fontWeight %f", requestedStyle->fontAttributes, requestedStyle->fontCountry, requestedStyle->fontExpire, requestedStyle->fontFamily, requestedStyle->fontFileName, requestedStyle->fontH, requestedStyle->fontHRes, requestedStyle->fontLanguage, requestedStyle->fontName, requestedStyle->fontRegion, requestedStyle->fontStyle, requestedStyle->fontStyleSub, requestedStyle->fontV, requestedStyle->fontVRes, requestedStyle->fontWeight); // Find the closest exact match for the fields specified. float hRes = requestedStyle->fontHRes > 0.0f ? (float)requestedStyle->fontHRes : fontLib->FontHRes(); @@ -1276,16 +1305,16 @@ static int sceFontFindFont(u32 libHandle, u32 fontStylePtr, u32 errorCodePtr) { static int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr) { if (!Memory::IsValidAddress(fontInfoPtr)) { - ERROR_LOG(SCEFONT, "sceFontGetFontInfo(%x, %x): bad fontInfo pointer", fontHandle, fontInfoPtr); + ERROR_LOG(Log::sceFont, "sceFontGetFontInfo(%x, %x): bad fontInfo pointer", fontHandle, fontInfoPtr); return ERROR_FONT_INVALID_PARAMETER; } LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetFontInfo(%x, %x): bad font", fontHandle, fontInfoPtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetFontInfo(%x, %x): bad font", fontHandle, fontInfoPtr); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetFontInfo(%x, %x)", fontHandle, fontInfoPtr); + DEBUG_LOG(Log::sceFont, "sceFontGetFontInfo(%x, %x)", fontHandle, fontInfoPtr); auto fi = PSPPointer::Create(fontInfoPtr); font->GetPGF()->GetFontInfo(fi); fi->fontStyle = font->GetFont()->GetFontStyle(); @@ -1298,19 +1327,19 @@ static int sceFontGetFontInfoByIndexNumber(u32 libHandle, u32 fontInfoPtr, u32 i auto fontStyle = PSPPointer::Create(fontInfoPtr); FontLib *fl = GetFontLib(libHandle); if (!fl || fl->handle() == 0) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid font lib", libHandle, fontInfoPtr, index); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid font lib", libHandle, fontInfoPtr, index); return !fl ? ERROR_FONT_INVALID_LIBID : ERROR_FONT_INVALID_PARAMETER; } if (index >= internalFonts.size()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid font index", libHandle, fontInfoPtr, index); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid font index", libHandle, fontInfoPtr, index); return ERROR_FONT_INVALID_PARAMETER; } if (!fontStyle.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid info pointer", libHandle, fontInfoPtr, index); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid info pointer", libHandle, fontInfoPtr, index); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetFontInfoByIndexNumber(%08x, %08x, %i)", libHandle, fontInfoPtr, index); + DEBUG_LOG(Log::sceFont, "sceFontGetFontInfoByIndexNumber(%08x, %08x, %i)", libHandle, fontInfoPtr, index); auto font = internalFonts[index]; *fontStyle = font->GetFontStyle(); @@ -1320,17 +1349,17 @@ static int sceFontGetFontInfoByIndexNumber(u32 libHandle, u32 fontInfoPtr, u32 i static int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) { charCode &= 0xffff; if (!Memory::IsValidAddress(charInfoPtr)) { - ERROR_LOG(SCEFONT, "sceFontGetCharInfo(%08x, %i, %08x): bad charInfo pointer", fontHandle, charCode, charInfoPtr); + ERROR_LOG(Log::sceFont, "sceFontGetCharInfo(%08x, %i, %08x): bad charInfo pointer", fontHandle, charCode, charInfoPtr); return ERROR_FONT_INVALID_PARAMETER; } LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { // The PSP crashes, but we assume it'd work like sceFontGetFontInfo(), and not touch charInfo. - ERROR_LOG_REPORT(SCEFONT, "sceFontGetCharInfo(%08x, %i, %08x): bad font", fontHandle, charCode, charInfoPtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetCharInfo(%08x, %i, %08x): bad font", fontHandle, charCode, charInfoPtr); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetCharInfo(%08x, %i, %08x)", fontHandle, charCode, charInfoPtr); + DEBUG_LOG(Log::sceFont, "sceFontGetCharInfo(%08x, %i, %08x)", fontHandle, charCode, charInfoPtr); auto charInfo = PSPPointer::Create(charInfoPtr); font->GetCharInfo(charCode, charInfo); @@ -1361,16 +1390,16 @@ static int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) { static int sceFontGetShadowInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) { charCode &= 0xffff; if (!Memory::IsValidAddress(charInfoPtr)) { - ERROR_LOG(SCEFONT, "sceFontGetShadowInfo(%08x, %i, %08x): bad charInfo pointer", fontHandle, charCode, charInfoPtr); + ERROR_LOG(Log::sceFont, "sceFontGetShadowInfo(%08x, %i, %08x): bad charInfo pointer", fontHandle, charCode, charInfoPtr); return ERROR_FONT_INVALID_PARAMETER; } LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetShadowInfo(%08x, %i, %08x): bad font", fontHandle, charCode, charInfoPtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetShadowInfo(%08x, %i, %08x): bad font", fontHandle, charCode, charInfoPtr); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetShadowInfo(%08x, %i, %08x)", fontHandle, charCode, charInfoPtr); + DEBUG_LOG(Log::sceFont, "sceFontGetShadowInfo(%08x, %i, %08x)", fontHandle, charCode, charInfoPtr); auto charInfo = PSPPointer::Create(charInfoPtr); font->GetCharInfo(charCode, charInfo, FONT_PGF_SHADOWGLYPH); @@ -1382,15 +1411,15 @@ static int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr auto charRect = PSPPointer::Create(charRectPtr); LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetCharImageRect(%08x, %i, %08x): bad font", fontHandle, charCode, charRectPtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetCharImageRect(%08x, %i, %08x): bad font", fontHandle, charCode, charRectPtr); return ERROR_FONT_INVALID_PARAMETER; } if (!charRect.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetCharImageRect(%08x, %i, %08x): invalid rect pointer", fontHandle, charCode, charRectPtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetCharImageRect(%08x, %i, %08x): invalid rect pointer", fontHandle, charCode, charRectPtr); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetCharImageRect(%08x, %i, %08x)", fontHandle, charCode, charRectPtr); + DEBUG_LOG(Log::sceFont, "sceFontGetCharImageRect(%08x, %i, %08x)", fontHandle, charCode, charRectPtr); PGFCharInfo charInfo; font->GetCharInfo(charCode, &charInfo); charRect->width = charInfo.bitmapWidth; @@ -1403,15 +1432,15 @@ static int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectP auto charRect = PSPPointer::Create(charRectPtr); LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetShadowImageRect(%08x, %i, %08x): bad font", fontHandle, charCode, charRectPtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetShadowImageRect(%08x, %i, %08x): bad font", fontHandle, charCode, charRectPtr); return ERROR_FONT_INVALID_PARAMETER; } if (!charRect.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetShadowImageRect(%08x, %i, %08x): invalid rect pointer", fontHandle, charCode, charRectPtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetShadowImageRect(%08x, %i, %08x): invalid rect pointer", fontHandle, charCode, charRectPtr); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetShadowImageRect(%08x, %i, %08x)", fontHandle, charCode, charRectPtr); + DEBUG_LOG(Log::sceFont, "sceFontGetShadowImageRect(%08x, %i, %08x)", fontHandle, charCode, charRectPtr); PGFCharInfo charInfo; font->GetCharInfo(charCode, &charInfo, FONT_PGF_SHADOWGLYPH); charRect->width = charInfo.bitmapWidth; @@ -1422,16 +1451,16 @@ static int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectP static int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) { charCode &= 0xffff; if (!Memory::IsValidAddress(glyphImagePtr)) { - ERROR_LOG(SCEFONT, "sceFontGetCharGlyphImage(%x, %x, %x): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr); + ERROR_LOG(Log::sceFont, "sceFontGetCharGlyphImage(%x, %x, %x): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr); return ERROR_FONT_INVALID_PARAMETER; } LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetCharGlyphImage(%x, %x, %x): bad font", fontHandle, charCode, glyphImagePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetCharGlyphImage(%x, %x, %x): bad font", fontHandle, charCode, glyphImagePtr); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetCharGlyphImage(%x, %x, %x)", fontHandle, charCode, glyphImagePtr); + DEBUG_LOG(Log::sceFont, "sceFontGetCharGlyphImage(%x, %x, %x)", fontHandle, charCode, glyphImagePtr); auto glyph = PSPPointer::Create(glyphImagePtr); font->DrawCharacter(glyph, -1, -1, -1, -1, charCode, FONT_PGF_CHARGLYPH); return 0; @@ -1440,16 +1469,16 @@ static int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImage static int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) { charCode &= 0xffff; if (!Memory::IsValidAddress(glyphImagePtr)) { - ERROR_LOG(SCEFONT, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); + ERROR_LOG(Log::sceFont, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); return ERROR_FONT_INVALID_PARAMETER; } LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad font", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad font", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i)", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); + DEBUG_LOG(Log::sceFont, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i)", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); auto glyph = PSPPointer::Create(glyphImagePtr); font->DrawCharacter(glyph, clipXPos, clipYPos, clipWidth, clipHeight, charCode, FONT_PGF_CHARGLYPH); return 0; @@ -1459,27 +1488,27 @@ static int sceFontSetAltCharacterCode(u32 fontLibHandle, u32 charCode) { charCode &= 0xffff; FontLib *fl = GetFontLib(fontLibHandle); if (!fl) { - ERROR_LOG_REPORT(SCEFONT, "sceFontSetAltCharacterCode(%08x, %08x): invalid font lib", fontLibHandle, charCode); + ERROR_LOG_REPORT(Log::sceFont, "sceFontSetAltCharacterCode(%08x, %08x): invalid font lib", fontLibHandle, charCode); return ERROR_FONT_INVALID_LIBID; } - INFO_LOG(SCEFONT, "sceFontSetAltCharacterCode(%08x, %08x)", fontLibHandle, charCode); + INFO_LOG(Log::sceFont, "sceFontSetAltCharacterCode(%08x, %08x)", fontLibHandle, charCode); fl->SetAltCharCode(charCode & 0xFFFF); return 0; } static int sceFontFlush(u32 fontHandle) { - INFO_LOG(SCEFONT, "sceFontFlush(%i)", fontHandle); + INFO_LOG(Log::sceFont, "sceFontFlush(%i)", fontHandle); LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontFlush(%08x): bad font", fontHandle); + ERROR_LOG_REPORT(Log::sceFont, "sceFontFlush(%08x): bad font", fontHandle); return ERROR_FONT_INVALID_PARAMETER; } - if (font->GetFontLib()) + if (font->GetFontLib()) { font->GetFontLib()->flushFont(); - + } return 0; } @@ -1489,15 +1518,15 @@ static int sceFontGetFontList(u32 fontLibHandle, u32 fontStylePtr, int numFonts) auto fontStyles = PSPPointer::Create(fontStylePtr); FontLib *fl = GetFontLib(fontLibHandle); if (!fl) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetFontList(%08x, %08x, %i): invalid font lib", fontLibHandle, fontStylePtr, numFonts); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetFontList(%08x, %08x, %i): invalid font lib", fontLibHandle, fontStylePtr, numFonts); return ERROR_FONT_INVALID_LIBID; } if (!fontStyles.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetFontList(%08x, %08x, %i): invalid style pointer", fontLibHandle, fontStylePtr, numFonts); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetFontList(%08x, %08x, %i): invalid style pointer", fontLibHandle, fontStylePtr, numFonts); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetFontList(%08x, %08x, %i)", fontLibHandle, fontStylePtr, numFonts); + DEBUG_LOG(Log::sceFont, "sceFontGetFontList(%08x, %08x, %i)", fontLibHandle, fontStylePtr, numFonts); if (fl->handle() != 0) { numFonts = std::min(numFonts, (int)internalFonts.size()); for (int i = 0; i < numFonts; i++) @@ -1510,16 +1539,16 @@ static int sceFontGetFontList(u32 fontLibHandle, u32 fontStylePtr, int numFonts) static int sceFontGetNumFontList(u32 fontLibHandle, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetNumFontList(%08x, %08x): invalid error address", fontLibHandle, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetNumFontList(%08x, %08x): invalid error address", fontLibHandle, errorCodePtr); return ERROR_FONT_INVALID_PARAMETER; } FontLib *fl = GetFontLib(fontLibHandle); if (!fl) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetNumFontList(%08x, %08x): invalid font lib", fontLibHandle, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetNumFontList(%08x, %08x): invalid font lib", fontLibHandle, errorCodePtr); *errorCode = ERROR_FONT_INVALID_LIBID; return 0; } - DEBUG_LOG(SCEFONT, "sceFontGetNumFontList(%08x, %08x)", fontLibHandle, errorCodePtr); + DEBUG_LOG(Log::sceFont, "sceFontGetNumFontList(%08x, %08x)", fontLibHandle, errorCodePtr); *errorCode = 0; return fl->handle() == 0 ? 0 : (int)internalFonts.size(); } @@ -1527,14 +1556,14 @@ static int sceFontGetNumFontList(u32 fontLibHandle, u32 errorCodePtr) { static int sceFontSetResolution(u32 fontLibHandle, float hRes, float vRes) { FontLib *fl = GetFontLib(fontLibHandle); if (!fl) { - ERROR_LOG_REPORT(SCEFONT, "sceFontSetResolution(%08x, %f, %f): invalid font lib", fontLibHandle, hRes, vRes); + ERROR_LOG_REPORT(Log::sceFont, "sceFontSetResolution(%08x, %f, %f): invalid font lib", fontLibHandle, hRes, vRes); return ERROR_FONT_INVALID_LIBID; } if (hRes <= 0.0f || vRes <= 0.0f) { - ERROR_LOG_REPORT(SCEFONT, "sceFontSetResolution(%08x, %f, %f): negative value", fontLibHandle, hRes, vRes); + ERROR_LOG_REPORT(Log::sceFont, "sceFontSetResolution(%08x, %f, %f): negative value", fontLibHandle, hRes, vRes); return ERROR_FONT_INVALID_PARAMETER; } - INFO_LOG(SCEFONT, "sceFontSetResolution(%08x, %f, %f)", fontLibHandle, hRes, vRes); + INFO_LOG(Log::sceFont, "sceFontSetResolution(%08x, %f, %f)", fontLibHandle, hRes, vRes); fl->SetResolution(hRes, vRes); return 0; } @@ -1542,16 +1571,16 @@ static int sceFontSetResolution(u32 fontLibHandle, float hRes, float vRes) { static float sceFontPixelToPointH(int fontLibHandle, float fontPixelsH, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontPixelToPointH(%08x, %f, %08x): invalid error address", fontLibHandle, fontPixelsH, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontPixelToPointH(%08x, %f, %08x): invalid error address", fontLibHandle, fontPixelsH, errorCodePtr); return 0.0f; } FontLib *fl = GetFontLib(fontLibHandle); if (!fl) { - ERROR_LOG_REPORT(SCEFONT, "sceFontPixelToPointH(%08x, %f, %08x): invalid font lib", fontLibHandle, fontPixelsH, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontPixelToPointH(%08x, %f, %08x): invalid font lib", fontLibHandle, fontPixelsH, errorCodePtr); *errorCode = ERROR_FONT_INVALID_LIBID; return 0.0f; } - DEBUG_LOG(SCEFONT, "sceFontPixelToPointH(%08x, %f, %08x)", fontLibHandle, fontPixelsH, errorCodePtr); + DEBUG_LOG(Log::sceFont, "sceFontPixelToPointH(%08x, %f, %08x)", fontLibHandle, fontPixelsH, errorCodePtr); *errorCode = 0; return fontPixelsH * pointDPI / fl->FontHRes(); } @@ -1559,16 +1588,16 @@ static float sceFontPixelToPointH(int fontLibHandle, float fontPixelsH, u32 erro static float sceFontPixelToPointV(int fontLibHandle, float fontPixelsV, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontPixelToPointV(%08x, %f, %08x): invalid error address", fontLibHandle, fontPixelsV, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontPixelToPointV(%08x, %f, %08x): invalid error address", fontLibHandle, fontPixelsV, errorCodePtr); return 0.0f; } FontLib *fl = GetFontLib(fontLibHandle); if (!fl) { - ERROR_LOG_REPORT(SCEFONT, "sceFontPixelToPointV(%08x, %f, %08x): invalid font lib", fontLibHandle, fontPixelsV, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontPixelToPointV(%08x, %f, %08x): invalid font lib", fontLibHandle, fontPixelsV, errorCodePtr); *errorCode = ERROR_FONT_INVALID_LIBID; return 0.0f; } - DEBUG_LOG(SCEFONT, "sceFontPixelToPointV(%08x, %f, %08x)", fontLibHandle, fontPixelsV, errorCodePtr); + DEBUG_LOG(Log::sceFont, "sceFontPixelToPointV(%08x, %f, %08x)", fontLibHandle, fontPixelsV, errorCodePtr); *errorCode = 0; return fontPixelsV * pointDPI / fl->FontVRes(); } @@ -1576,16 +1605,16 @@ static float sceFontPixelToPointV(int fontLibHandle, float fontPixelsV, u32 erro static float sceFontPointToPixelH(int fontLibHandle, float fontPointsH, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontPointToPixelH(%08x, %f, %08x): invalid error address", fontLibHandle, fontPointsH, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontPointToPixelH(%08x, %f, %08x): invalid error address", fontLibHandle, fontPointsH, errorCodePtr); return 0.0f; } FontLib *fl = GetFontLib(fontLibHandle); if (!fl) { - ERROR_LOG_REPORT(SCEFONT, "sceFontPointToPixelH(%08x, %f, %08x): invalid font lib", fontLibHandle, fontPointsH, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontPointToPixelH(%08x, %f, %08x): invalid font lib", fontLibHandle, fontPointsH, errorCodePtr); *errorCode = ERROR_FONT_INVALID_LIBID; return 0.0f; } - DEBUG_LOG(SCEFONT, "sceFontPointToPixelH(%08x, %f, %08x)", fontLibHandle, fontPointsH, errorCodePtr); + DEBUG_LOG(Log::sceFont, "sceFontPointToPixelH(%08x, %f, %08x)", fontLibHandle, fontPointsH, errorCodePtr); *errorCode = 0; return fontPointsH * fl->FontHRes() / pointDPI; } @@ -1593,38 +1622,38 @@ static float sceFontPointToPixelH(int fontLibHandle, float fontPointsH, u32 erro static float sceFontPointToPixelV(int fontLibHandle, float fontPointsV, u32 errorCodePtr) { auto errorCode = PSPPointer::Create(errorCodePtr); if (!errorCode.IsValid()) { - ERROR_LOG_REPORT(SCEFONT, "sceFontPointToPixelV(%08x, %f, %08x): invalid error address", fontLibHandle, fontPointsV, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontPointToPixelV(%08x, %f, %08x): invalid error address", fontLibHandle, fontPointsV, errorCodePtr); return 0.0f; } FontLib *fl = GetFontLib(fontLibHandle); if (!fl) { - ERROR_LOG_REPORT(SCEFONT, "sceFontPointToPixelV(%08x, %f, %08x): invalid font lib", fontLibHandle, fontPointsV, errorCodePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontPointToPixelV(%08x, %f, %08x): invalid font lib", fontLibHandle, fontPointsV, errorCodePtr); *errorCode = ERROR_FONT_INVALID_LIBID; return 0.0f; } - DEBUG_LOG(SCEFONT, "sceFontPointToPixelV(%08x, %f, %08x)", fontLibHandle, fontPointsV, errorCodePtr); + DEBUG_LOG(Log::sceFont, "sceFontPointToPixelV(%08x, %f, %08x)", fontLibHandle, fontPointsV, errorCodePtr); *errorCode = 0; return fontPointsV * fl->FontVRes() / pointDPI; } static int sceFontCalcMemorySize() { - ERROR_LOG_REPORT(SCEFONT, "UNIMPL sceFontCalcMemorySize()"); + ERROR_LOG_REPORT(Log::sceFont, "UNIMPL sceFontCalcMemorySize()"); return 0; } static int sceFontGetShadowGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) { charCode &= 0xffff; if (!Memory::IsValidAddress(glyphImagePtr)) { - ERROR_LOG(SCEFONT, "sceFontGetShadowGlyphImage(%x, %x, %x): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr); + ERROR_LOG(Log::sceFont, "sceFontGetShadowGlyphImage(%x, %x, %x): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr); return ERROR_FONT_INVALID_PARAMETER; } LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetShadowGlyphImage(%x, %x, %x): bad font", fontHandle, charCode, glyphImagePtr); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetShadowGlyphImage(%x, %x, %x): bad font", fontHandle, charCode, glyphImagePtr); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetShadowGlyphImage(%x, %x, %x)", fontHandle, charCode, glyphImagePtr); + DEBUG_LOG(Log::sceFont, "sceFontGetShadowGlyphImage(%x, %x, %x)", fontHandle, charCode, glyphImagePtr); auto glyph = PSPPointer::Create(glyphImagePtr); font->DrawCharacter(glyph, -1, -1, -1, -1, charCode, FONT_PGF_SHADOWGLYPH); return 0; @@ -1633,16 +1662,16 @@ static int sceFontGetShadowGlyphImage(u32 fontHandle, u32 charCode, u32 glyphIma static int sceFontGetShadowGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) { charCode &= 0xffff; if (!Memory::IsValidAddress(glyphImagePtr)) { - ERROR_LOG(SCEFONT, "sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); + ERROR_LOG(Log::sceFont, "sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); return ERROR_FONT_INVALID_PARAMETER; } LoadedFont *font = GetLoadedFont(fontHandle, true); if (!font) { - ERROR_LOG_REPORT(SCEFONT, "sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad font", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); + ERROR_LOG_REPORT(Log::sceFont, "sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad font", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); return ERROR_FONT_INVALID_PARAMETER; } - DEBUG_LOG(SCEFONT, "sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i)", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); + DEBUG_LOG(Log::sceFont, "sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i)", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight); auto glyph = PSPPointer::Create(glyphImagePtr); font->DrawCharacter(glyph, clipXPos, clipYPos, clipWidth, clipHeight, charCode, FONT_PGF_SHADOWGLYPH); return 0; diff --git a/Core/HLE/sceGameUpdate.cpp b/Core/HLE/sceGameUpdate.cpp index d4c0775c23..57314172f2 100644 --- a/Core/HLE/sceGameUpdate.cpp +++ b/Core/HLE/sceGameUpdate.cpp @@ -21,25 +21,25 @@ static u32 sceGameUpdateInit() { - ERROR_LOG(SCEUTILITY, "UNIMPL sceGameUpdateInit()"); + ERROR_LOG(Log::sceUtility, "UNIMPL sceGameUpdateInit()"); return 0; } static u32 sceGameUpdateTerm() { - ERROR_LOG(SCEUTILITY, "UNIMPL sceGameUpdateTerm()"); + ERROR_LOG(Log::sceUtility, "UNIMPL sceGameUpdateTerm()"); return 0; } static u32 sceGameUpdateRun() { - ERROR_LOG(SCEUTILITY, "UNIMPL sceGameUpdateRun()"); + ERROR_LOG(Log::sceUtility, "UNIMPL sceGameUpdateRun()"); return 0; } static u32 sceGameUpdateAbort() { - ERROR_LOG(SCEUTILITY, "UNIMPL sceGameUpdateAbort()"); + ERROR_LOG(Log::sceUtility, "UNIMPL sceGameUpdateAbort()"); return 0; } diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 639791f687..54819eb551 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -66,7 +66,7 @@ public: bool run(PendingInterrupt& pend) override { if (ge_pending_cb.empty()) { - ERROR_LOG_REPORT(SCEGE, "Unable to run GE interrupt: no pending interrupt"); + ERROR_LOG_REPORT(Log::sceGe, "Unable to run GE interrupt: no pending interrupt"); return false; } @@ -74,12 +74,12 @@ public: DisplayList* dl = gpu->getList(intrdata.listid); if (dl == NULL) { - WARN_LOG(SCEGE, "Unable to run GE interrupt: list doesn't exist: %d", intrdata.listid); + WARN_LOG(Log::sceGe, "Unable to run GE interrupt: list doesn't exist: %d", intrdata.listid); return false; } if (!dl->interruptsEnabled) { - ERROR_LOG_REPORT(SCEGE, "Unable to run GE interrupt: list has interrupts disabled, should not happen"); + ERROR_LOG_REPORT(Log::sceGe, "Unable to run GE interrupt: list has interrupts disabled, should not happen"); return false; } @@ -118,7 +118,7 @@ public: SubIntrHandler* handler = get(subintr); if (handler != NULL) { - DEBUG_LOG(CPU, "Entering GE interrupt handler %08x", handler->handlerAddress); + DEBUG_LOG(Log::CPU, "Entering GE interrupt handler %08x", handler->handlerAddress); currentMIPS->pc = handler->handlerAddress; u32 data = dl->subIntrToken; currentMIPS->r[MIPS_REG_A0] = data & 0xFFFF; @@ -142,7 +142,7 @@ public: // Seen in GoW. if (subintr >= 0) - DEBUG_LOG(SCEGE, "Ignoring interrupt for display list %d, already been released.", intrdata.listid); + DEBUG_LOG(Log::sceGe, "Ignoring interrupt for display list %d, already been released.", intrdata.listid); return false; } @@ -152,7 +152,7 @@ public: DisplayList* dl = gpu->getList(intrdata.listid); if (!dl->interruptsEnabled) { - ERROR_LOG_REPORT(SCEGE, "Unable to finish GE interrupt: list has interrupts disabled, should not happen"); + ERROR_LOG_REPORT(Log::sceGe, "Unable to finish GE interrupt: list has interrupts disabled, should not happen"); return; } @@ -163,9 +163,9 @@ public: DisplayListState newState = static_cast(Memory::ReadUnchecked_U32(intrdata.pc - 4) & 0xFF); //dl->status = static_cast(Memory::ReadUnchecked_U32(intrdata.pc) & 0xFF); //if(dl->status < 0 || dl->status > PSP_GE_LIST_PAUSED) - // ERROR_LOG(SCEGE, "Weird DL status after signal suspend %x", dl->status); + // ERROR_LOG(Log::sceGe, "Weird DL status after signal suspend %x", dl->status); if (newState != PSP_GE_DL_STATE_RUNNING) { - DEBUG_LOG_REPORT(SCEGE, "GE Interrupt: newState might be %d", newState); + DEBUG_LOG_REPORT(Log::sceGe, "GE Interrupt: newState might be %d", newState); } if (dl->state != PSP_GE_DL_STATE_NONE && dl->state != PSP_GE_DL_STATE_COMPLETED) { @@ -288,7 +288,7 @@ void __GeWaitCurrentThread(GPUSyncType type, SceUID waitId, const char *reason) listWaitingThreads[waitId].push_back(__KernelGetCurThread()); waitType = WAITTYPE_GELISTSYNC; } else { - ERROR_LOG_REPORT(SCEGE, "__GeWaitCurrentThread: bad wait type"); + ERROR_LOG_REPORT(Log::sceGe, "__GeWaitCurrentThread: bad wait type"); return; } @@ -311,13 +311,13 @@ bool __GeTriggerWait(GPUSyncType type, SceUID waitId) { else if (type == GPU_SYNC_LIST || (WaitType)type == WAITTYPE_GELISTSYNC) return __GeTriggerWait(WAITTYPE_GELISTSYNC, waitId, listWaitingThreads[waitId]); else - ERROR_LOG_REPORT(SCEGE, "__GeTriggerWait: bad wait type"); + ERROR_LOG_REPORT(Log::sceGe, "__GeTriggerWait: bad wait type"); return false; } static u32 sceGeEdramGetAddr() { u32 retVal = 0x04000000; - DEBUG_LOG(SCEGE, "%08x = sceGeEdramGetAddr", retVal); + DEBUG_LOG(Log::sceGe, "%08x = sceGeEdramGetAddr", retVal); hleEatCycles(150); return retVal; } @@ -325,7 +325,7 @@ static u32 sceGeEdramGetAddr() { // TODO: Return a different value for the PS3 enhanced-emulator games? static u32 sceGeEdramGetSize() { const u32 retVal = 0x00200000; - DEBUG_LOG(SCEGE, "%08x = sceGeEdramGetSize()", retVal); + DEBUG_LOG(Log::sceGe, "%08x = sceGeEdramGetSize()", retVal); return retVal; } @@ -334,7 +334,7 @@ static int __GeSubIntrBase(int callbackId) { } u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr) { - DEBUG_LOG(SCEGE, + DEBUG_LOG(Log::sceGe, "sceGeListEnQueue(addr=%08x, stall=%08x, cbid=%08x, param=%08x)", listAddress, stallAddress, callbackId, optParamAddr); auto optParam = PSPPointer::Create(optParamAddr); @@ -345,11 +345,11 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId, u32 optP hleEatCycles(490); CoreTiming::ForceCheck(); - return hleLogSuccessX(SCEGE, listID); + return hleLogSuccessX(Log::sceGe, listID); } u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr) { - DEBUG_LOG(SCEGE, + DEBUG_LOG(Log::sceGe, "sceGeListEnQueueHead(addr=%08x, stall=%08x, cbid=%08x, param=%08x)", listAddress, stallAddress, callbackId, optParamAddr); auto optParam = PSPPointer::Create(optParamAddr); @@ -360,11 +360,11 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId, u32 hleEatCycles(480); CoreTiming::ForceCheck(); - return hleLogSuccessX(SCEGE, listID); + return hleLogSuccessX(Log::sceGe, listID); } static int sceGeListDeQueue(u32 listID) { - WARN_LOG(SCEGE, "sceGeListDeQueue(%08x)", listID); + WARN_LOG(Log::sceGe, "sceGeListDeQueue(%08x)", listID); int result = gpu->DequeueList(LIST_ID_MAGIC ^ listID); hleReSchedule("dlist dequeued"); return result; @@ -376,13 +376,13 @@ static int sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress) { hleEatCycles(190); CoreTiming::ForceCheck(); - DEBUG_LOG(SCEGE, "sceGeListUpdateStallAddr(dlid=%i, stalladdr=%08x)", displayListID, stallAddress); + DEBUG_LOG(Log::sceGe, "sceGeListUpdateStallAddr(dlid=%i, stalladdr=%08x)", displayListID, stallAddress); return gpu->UpdateStall(LIST_ID_MAGIC ^ displayListID, stallAddress); } // 0 : wait for completion. 1:check and return int sceGeListSync(u32 displayListID, u32 mode) { - DEBUG_LOG(SCEGE, "sceGeListSync(dlid=%08x, mode=%08x)", displayListID, mode); + DEBUG_LOG(Log::sceGe, "sceGeListSync(dlid=%08x, mode=%08x)", displayListID, mode); hleEatCycles(220); // Fudged without measuring, copying sceGeContinue. return gpu->ListSync(LIST_ID_MAGIC ^ displayListID, mode); } @@ -391,14 +391,14 @@ static u32 sceGeDrawSync(u32 mode) { //wait/check entire drawing state if (PSP_CoreParameter().compat.flags().DrawSyncEatCycles) hleEatCycles(500000); //HACK(?) : Potential fix for Crash Tag Team Racing and a few Gundam games - else + else if (!PSP_CoreParameter().compat.flags().DrawSyncInstant) hleEatCycles(1240); - DEBUG_LOG(SCEGE, "sceGeDrawSync(mode=%d) (0=wait for completion, 1=peek)", mode); + DEBUG_LOG(Log::sceGe, "sceGeDrawSync(mode=%d) (0=wait for completion, 1=peek)", mode); return gpu->DrawSync(mode); } int sceGeContinue() { - DEBUG_LOG(SCEGE, "sceGeContinue"); + DEBUG_LOG(Log::sceGe, "sceGeContinue"); int ret = gpu->Continue(); hleEatCycles(220); hleReSchedule("ge continue"); @@ -407,19 +407,19 @@ int sceGeContinue() { static int sceGeBreak(u32 mode, u32 unknownPtr) { if (mode > 1) { - WARN_LOG(SCEGE, "sceGeBreak(mode=%d, unknown=%08x): invalid mode", mode, unknownPtr); + WARN_LOG(Log::sceGe, "sceGeBreak(mode=%d, unknown=%08x): invalid mode", mode, unknownPtr); return SCE_KERNEL_ERROR_INVALID_MODE; } // Not sure what this is supposed to be for... if ((int)unknownPtr < 0 || (int)(unknownPtr + 16) < 0) { - WARN_LOG_REPORT(SCEGE, "sceGeBreak(mode=%d, unknown=%08x): invalid ptr", mode, unknownPtr); + WARN_LOG_REPORT(Log::sceGe, "sceGeBreak(mode=%d, unknown=%08x): invalid ptr", mode, unknownPtr); return SCE_KERNEL_ERROR_PRIV_REQUIRED; } else if (unknownPtr != 0) { - WARN_LOG_REPORT(SCEGE, "sceGeBreak(mode=%d, unknown=%08x): unknown ptr (%s)", mode, unknownPtr, Memory::IsValidAddress(unknownPtr) ? "valid" : "invalid"); + WARN_LOG_REPORT(Log::sceGe, "sceGeBreak(mode=%d, unknown=%08x): unknown ptr (%s)", mode, unknownPtr, Memory::IsValidAddress(unknownPtr) ? "valid" : "invalid"); } //mode => 0 : current dlist 1: all drawing - DEBUG_LOG(SCEGE, "sceGeBreak(mode=%d, unknown=%08x)", mode, unknownPtr); + DEBUG_LOG(Log::sceGe, "sceGeBreak(mode=%d, unknown=%08x)", mode, unknownPtr); int result = gpu->Break(mode); if (result >= 0 && mode == 0) { return LIST_ID_MAGIC ^ result; @@ -437,7 +437,7 @@ static u32 sceGeSetCallback(u32 structAddr) { } if (cbID == -1) { - return hleLogWarning(SCEGE, SCE_KERNEL_ERROR_OUT_OF_MEMORY, "out of callback ids"); + return hleLogWarning(Log::sceGe, SCE_KERNEL_ERROR_OUT_OF_MEMORY, "out of callback ids"); } ge_used_callbacks[cbID] = true; @@ -458,14 +458,14 @@ static u32 sceGeSetCallback(u32 structAddr) { sceKernelEnableSubIntr(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL); } - return hleLogSuccessI(SCEGE, cbID); + return hleLogSuccessI(Log::sceGe, cbID); } static int sceGeUnsetCallback(u32 cbID) { - DEBUG_LOG(SCEGE, "sceGeUnsetCallback(cbid=%08x)", cbID); + DEBUG_LOG(Log::sceGe, "sceGeUnsetCallback(cbid=%08x)", cbID); if (cbID >= ARRAY_SIZE(ge_used_callbacks)) { - WARN_LOG(SCEGE, "sceGeUnsetCallback(cbid=%08x): invalid callback id", cbID); + WARN_LOG(Log::sceGe, "sceGeUnsetCallback(cbid=%08x): invalid callback id", cbID); return SCE_KERNEL_ERROR_INVALID_ID; } @@ -475,7 +475,7 @@ static int sceGeUnsetCallback(u32 cbID) { sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH); sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL); } else { - WARN_LOG(SCEGE, "sceGeUnsetCallback(cbid=%08x): ignoring unregistered callback id", cbID); + WARN_LOG(Log::sceGe, "sceGeUnsetCallback(cbid=%08x): ignoring unregistered callback id", cbID); } ge_used_callbacks[cbID] = false; @@ -485,10 +485,10 @@ static int sceGeUnsetCallback(u32 cbID) { // Points to 512 32-bit words, where we can probably layout the context however we want // unless some insane game pokes it and relies on it... u32 sceGeSaveContext(u32 ctxAddr) { - DEBUG_LOG(SCEGE, "sceGeSaveContext(%08x)", ctxAddr); + DEBUG_LOG(Log::sceGe, "sceGeSaveContext(%08x)", ctxAddr); if (gpu->BusyDrawing()) { - WARN_LOG(SCEGE, "sceGeSaveContext(%08x): lists in process, aborting", ctxAddr); + WARN_LOG(Log::sceGe, "sceGeSaveContext(%08x): lists in process, aborting", ctxAddr); // Real error code. return -1; } @@ -504,10 +504,10 @@ u32 sceGeSaveContext(u32 ctxAddr) { } u32 sceGeRestoreContext(u32 ctxAddr) { - DEBUG_LOG(SCEGE, "sceGeRestoreContext(%08x)", ctxAddr); + DEBUG_LOG(Log::sceGe, "sceGeRestoreContext(%08x)", ctxAddr); if (gpu->BusyDrawing()) { - WARN_LOG(SCEGE, "sceGeRestoreContext(%08x): lists in process, aborting", ctxAddr); + WARN_LOG(Log::sceGe, "sceGeRestoreContext(%08x): lists in process, aborting", ctxAddr); return SCE_KERNEL_ERROR_BUSY; } @@ -522,16 +522,16 @@ u32 sceGeRestoreContext(u32 ctxAddr) { static int sceGeGetMtx(int type, u32 matrixPtr) { int size = type == GE_MTX_PROJECTION ? 16 : 12; if (!Memory::IsValidRange(matrixPtr, size * sizeof(float))) { - return hleLogError(SCEGE, -1, "bad matrix ptr"); + return hleLogError(Log::sceGe, -1, "bad matrix ptr"); } u32_le *dest = (u32_le *)Memory::GetPointerWriteUnchecked(matrixPtr); // Note: this reads the CPU-visible matrix values, which may differ from the actual used values. // They only differ when more DATA commands are sent than are valid for a matrix. if (!gpu || !gpu->GetMatrix24(GEMatrixType(type), dest, 0)) - return hleLogError(SCEGE, SCE_KERNEL_ERROR_INVALID_INDEX, "invalid matrix"); + return hleLogError(Log::sceGe, SCE_KERNEL_ERROR_INVALID_INDEX, "invalid matrix"); - return hleLogSuccessInfoI(SCEGE, 0); + return hleLogSuccessInfoI(Log::sceGe, 0); } static u32 sceGeGetCmd(int cmd) { @@ -561,13 +561,13 @@ static u32 sceGeGetCmd(int cmd) { default: break; } - return hleLogSuccessInfoX(SCEGE, val); + return hleLogSuccessInfoX(Log::sceGe, val); } - return hleLogError(SCEGE, SCE_KERNEL_ERROR_INVALID_INDEX); + return hleLogError(Log::sceGe, SCE_KERNEL_ERROR_INVALID_INDEX); } static int sceGeGetStack(int index, u32 stackPtr) { - WARN_LOG_REPORT(SCEGE, "sceGeGetStack(%i, %08x)", index, stackPtr); + WARN_LOG_REPORT(Log::sceGe, "sceGeGetStack(%i, %08x)", index, stackPtr); return gpu->GetStack(index, stackPtr); } @@ -575,13 +575,13 @@ static u32 sceGeEdramSetAddrTranslation(u32 new_size) { bool outsideRange = new_size != 0 && (new_size < 0x200 || new_size > 0x1000); bool notPowerOfTwo = (new_size & (new_size - 1)) != 0; if (outsideRange || notPowerOfTwo) { - return hleLogWarning(SCEGE, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid value"); + return hleLogWarning(Log::sceGe, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid value"); } if (!gpu) { - return hleLogError(SCEGE, -1, "GPUInterface not available"); + return hleLogError(Log::sceGe, -1, "GPUInterface not available"); } - return hleReportDebug(SCEGE, gpu->SetAddrTranslation(new_size)); + return hleReportDebug(Log::sceGe, gpu->SetAddrTranslation(new_size)); } const HLEFunction sceGe_user[] = { diff --git a/Core/HLE/sceHeap.cpp b/Core/HLE/sceHeap.cpp index 5a5ac3065f..69c808f847 100644 --- a/Core/HLE/sceHeap.cpp +++ b/Core/HLE/sceHeap.cpp @@ -81,23 +81,23 @@ void __HeapShutdown() { } static int sceHeapReallocHeapMemory(u32 heapAddr, u32 memPtr, int memSize) { - ERROR_LOG_REPORT(HLE,"UNIMPL sceHeapReallocHeapMemory(%08x, %08x, %08x)", heapAddr, memPtr, memSize); + ERROR_LOG_REPORT(Log::HLE,"UNIMPL sceHeapReallocHeapMemory(%08x, %08x, %08x)", heapAddr, memPtr, memSize); return 0; } static int sceHeapReallocHeapMemoryWithOption(u32 heapPtr, u32 memPtr, int memSize, u32 paramsPtr) { - ERROR_LOG_REPORT(HLE,"UNIMPL sceHeapReallocHeapMemoryWithOption(%08x, %08x, %08x, %08x)", heapPtr, memPtr, memSize, paramsPtr); + ERROR_LOG_REPORT(Log::HLE,"UNIMPL sceHeapReallocHeapMemoryWithOption(%08x, %08x, %08x, %08x)", heapPtr, memPtr, memSize, paramsPtr); return 0; } static int sceHeapFreeHeapMemory(u32 heapAddr, u32 memAddr) { Heap *heap = getHeap(heapAddr); if (!heap) { - ERROR_LOG(HLE, "sceHeapFreeHeapMemory(%08x, %08x): invalid heap", heapAddr, memAddr); + ERROR_LOG(Log::HLE, "sceHeapFreeHeapMemory(%08x, %08x): invalid heap", heapAddr, memAddr); return SCE_KERNEL_ERROR_INVALID_ID; } - DEBUG_LOG(HLE, "sceHeapFreeHeapMemory(%08x, %08x)", heapAddr, memAddr); + DEBUG_LOG(Log::HLE, "sceHeapFreeHeapMemory(%08x, %08x)", heapAddr, memAddr); // An invalid address will crash the PSP, but 0 is always returns success. if (memAddr == 0) { return 0; @@ -110,7 +110,7 @@ static int sceHeapFreeHeapMemory(u32 heapAddr, u32 memAddr) { } static int sceHeapGetMallinfo(u32 heapAddr, u32 infoPtr) { - ERROR_LOG_REPORT(HLE,"UNIMPL sceHeapGetMallinfo(%08x, %08x)", heapAddr, infoPtr); + ERROR_LOG_REPORT(Log::HLE,"UNIMPL sceHeapGetMallinfo(%08x, %08x)", heapAddr, infoPtr); return 0; } @@ -118,7 +118,7 @@ static u32 sceHeapAllocHeapMemoryWithOption(u32 heapAddr, u32 memSize, u32 param Heap *heap = getHeap(heapAddr); u32 grain = 4; if (!heap) { - ERROR_LOG(HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid heap", heapAddr, memSize, paramsPtr); + ERROR_LOG(Log::HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid heap", heapAddr, memSize, paramsPtr); return 0; } @@ -126,16 +126,16 @@ static u32 sceHeapAllocHeapMemoryWithOption(u32 heapAddr, u32 memSize, u32 param if (paramsPtr != 0) { u32 size = Memory::Read_U32(paramsPtr); if (size < 8) { - ERROR_LOG(HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid param size", heapAddr, memSize, paramsPtr); + ERROR_LOG(Log::HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid param size", heapAddr, memSize, paramsPtr); return 0; } if (size > 8) { - WARN_LOG_REPORT(HLE, "sceHeapAllocHeapMemoryWithOption(): unexpected param size %d", size); + WARN_LOG_REPORT(Log::HLE, "sceHeapAllocHeapMemoryWithOption(): unexpected param size %d", size); } grain = Memory::Read_U32(paramsPtr + 4); } - DEBUG_LOG(HLE,"sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x)", heapAddr, memSize, paramsPtr); + DEBUG_LOG(Log::HLE,"sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x)", heapAddr, memSize, paramsPtr); // There's 8 bytes at the end of every block, reserved. memSize += 8; u32 addr = heap->alloc.AllocAligned(memSize, grain, grain, true); @@ -145,11 +145,11 @@ static u32 sceHeapAllocHeapMemoryWithOption(u32 heapAddr, u32 memSize, u32 param static int sceHeapGetTotalFreeSize(u32 heapAddr) { Heap *heap = getHeap(heapAddr); if (!heap) { - ERROR_LOG(HLE, "sceHeapGetTotalFreeSize(%08x): invalid heap", heapAddr); + ERROR_LOG(Log::HLE, "sceHeapGetTotalFreeSize(%08x): invalid heap", heapAddr); return SCE_KERNEL_ERROR_INVALID_ID; } - DEBUG_LOG(HLE, "sceHeapGetTotalFreeSize(%08x)", heapAddr); + DEBUG_LOG(Log::HLE, "sceHeapGetTotalFreeSize(%08x)", heapAddr); u32 free = heap->alloc.GetTotalFreeBytes(); if (free >= 8) { // Every allocation requires an extra 8 bytes. @@ -160,11 +160,11 @@ static int sceHeapGetTotalFreeSize(u32 heapAddr) { static int sceHeapIsAllocatedHeapMemory(u32 heapPtr, u32 memPtr) { if (!Memory::IsValidAddress(memPtr)) { - ERROR_LOG(HLE, "sceHeapIsAllocatedHeapMemory(%08x, %08x): invalid address", heapPtr, memPtr); + ERROR_LOG(Log::HLE, "sceHeapIsAllocatedHeapMemory(%08x, %08x): invalid address", heapPtr, memPtr); return SCE_KERNEL_ERROR_INVALID_POINTER; } - DEBUG_LOG(HLE, "sceHeapIsAllocatedHeapMemory(%08x, %08x)", heapPtr, memPtr); + DEBUG_LOG(Log::HLE, "sceHeapIsAllocatedHeapMemory(%08x, %08x)", heapPtr, memPtr); Heap *heap = getHeap(heapPtr); // An invalid heap is fine, it's not a member of this heap one way or another. // Only an exact address matches. Off by one crashes, and off by 4 says no. @@ -177,11 +177,11 @@ static int sceHeapIsAllocatedHeapMemory(u32 heapPtr, u32 memPtr) { static int sceHeapDeleteHeap(u32 heapAddr) { Heap *heap = getHeap(heapAddr); if (!heap) { - ERROR_LOG(HLE, "sceHeapDeleteHeap(%08x): invalid heap", heapAddr); + ERROR_LOG(Log::HLE, "sceHeapDeleteHeap(%08x): invalid heap", heapAddr); return SCE_KERNEL_ERROR_INVALID_ID; } - DEBUG_LOG(HLE, "sceHeapDeleteHeap(%08x)", heapAddr); + DEBUG_LOG(Log::HLE, "sceHeapDeleteHeap(%08x)", heapAddr); heapList.erase(heapAddr); delete heap; return 0; @@ -190,10 +190,10 @@ static int sceHeapDeleteHeap(u32 heapAddr) { static int sceHeapCreateHeap(const char* name, u32 heapSize, int attr, u32 paramsPtr) { if (paramsPtr != 0) { u32 size = Memory::Read_U32(paramsPtr); - WARN_LOG_REPORT(HLE, "sceHeapCreateHeap(): unsupported options parameter, size = %d", size); + WARN_LOG_REPORT(Log::HLE, "sceHeapCreateHeap(): unsupported options parameter, size = %d", size); } if (name == NULL) { - WARN_LOG_REPORT(HLE, "sceHeapCreateHeap(): name is NULL"); + WARN_LOG_REPORT(Log::HLE, "sceHeapCreateHeap(): name is NULL"); return 0; } int allocSize = (heapSize + 3) & ~3; @@ -203,7 +203,7 @@ static int sceHeapCreateHeap(const char* name, u32 heapSize, int attr, u32 param heap->fromtop = (attr & PSP_HEAP_ATTR_HIGHMEM) != 0; u32 addr = userMemory.Alloc(heap->size, heap->fromtop, StringFromFormat("Heap/%s", name).c_str()); if (addr == (u32)-1) { - ERROR_LOG(HLE, "sceHeapCreateHeap(): Failed to allocate %i bytes memory", allocSize); + ERROR_LOG(Log::HLE, "sceHeapCreateHeap(): Failed to allocate %i bytes memory", allocSize); delete heap; return 0; } @@ -212,19 +212,19 @@ static int sceHeapCreateHeap(const char* name, u32 heapSize, int attr, u32 param // Some of the heap is reserved by the implementation (the first 128 bytes, and 8 after each block.) heap->alloc.Init(heap->address + 128, heap->size - 128, true); heapList[heap->address] = heap; - DEBUG_LOG(HLE, "%08x=sceHeapCreateHeap(%s, %08x, %08x, %08x)", heap->address, name, heapSize, attr, paramsPtr); + DEBUG_LOG(Log::HLE, "%08x=sceHeapCreateHeap(%s, %08x, %08x, %08x)", heap->address, name, heapSize, attr, paramsPtr); return heap->address; } static u32 sceHeapAllocHeapMemory(u32 heapAddr, u32 memSize) { Heap *heap = getHeap(heapAddr); if (!heap) { - ERROR_LOG(HLE, "sceHeapAllocHeapMemory(%08x, %08x): invalid heap", heapAddr, memSize); + ERROR_LOG(Log::HLE, "sceHeapAllocHeapMemory(%08x, %08x): invalid heap", heapAddr, memSize); // Yes, not 0 (returns a pointer), but an error code. Strange. return SCE_KERNEL_ERROR_INVALID_ID; } - DEBUG_LOG(HLE, "sceHeapAllocHeapMemory(%08x, %08x)", heapAddr, memSize); + DEBUG_LOG(Log::HLE, "sceHeapAllocHeapMemory(%08x, %08x)", heapAddr, memSize); // There's 8 bytes at the end of every block, reserved. memSize += 8; // Always goes down, regardless of whether the heap is high or low. diff --git a/Core/HLE/sceHprm.cpp b/Core/HLE/sceHprm.cpp index 44d00f5b3d..bb1e6dd9fe 100644 --- a/Core/HLE/sceHprm.cpp +++ b/Core/HLE/sceHprm.cpp @@ -22,7 +22,7 @@ #include "Core/MIPS/MIPS.h" static u32 sceHprmPeekCurrentKey(u32 keyAddress) { - DEBUG_LOG(HLE,"0=sceHprmPeekCurrentKey(ptr)"); + DEBUG_LOG(Log::HLE,"0=sceHprmPeekCurrentKey(ptr)"); Memory::Write_U32(0, keyAddress); return 0; } @@ -30,37 +30,37 @@ static u32 sceHprmPeekCurrentKey(u32 keyAddress) { // TODO: Might make sense to reflect the headphone status of the host here, // if the games adjust their sound. static u32 sceHprmIsHeadphoneExist() { - DEBUG_LOG(HLE, "sceHprmIsHeadphoneExist()"); + DEBUG_LOG(Log::HLE, "sceHprmIsHeadphoneExist()"); return 0; } static u32 sceHprmIsMicrophoneExist() { - DEBUG_LOG(HLE, "sceHprmIsMicrophoneExist()"); + DEBUG_LOG(Log::HLE, "sceHprmIsMicrophoneExist()"); return 0; } static u32 sceHprmIsRemoteExist() { - DEBUG_LOG(HLE, "sceHprmIsRemoteExist()"); + DEBUG_LOG(Log::HLE, "sceHprmIsRemoteExist()"); return 0; } static u32 sceHprmRegisterCallback() { - ERROR_LOG(HLE, "UNIMPL %s", __FUNCTION__); + ERROR_LOG(Log::HLE, "UNIMPL %s", __FUNCTION__); return 0; } static u32 sceHprmUnregisterCallback() { - ERROR_LOG(HLE, "UNIMPL %s", __FUNCTION__); + ERROR_LOG(Log::HLE, "UNIMPL %s", __FUNCTION__); return 0; } static u32 sceHprmPeekLatch(u32 latchAddr) { - DEBUG_LOG(HLE,"sceHprmPeekLatch latchAddr %08x",latchAddr); + DEBUG_LOG(Log::HLE,"sceHprmPeekLatch latchAddr %08x",latchAddr); return 0; } static u32 sceHprmReadLatch(u32 latchAddr) { - DEBUG_LOG(HLE,"sceHprmReadLatch latchAddr %08x",latchAddr); + DEBUG_LOG(Log::HLE,"sceHprmReadLatch latchAddr %08x",latchAddr); return 0; } diff --git a/Core/HLE/sceHttp.cpp b/Core/HLE/sceHttp.cpp index 0f01636405..b56f2cc9cf 100644 --- a/Core/HLE/sceHttp.cpp +++ b/Core/HLE/sceHttp.cpp @@ -46,229 +46,229 @@ class HTTPRequest { int sceHttpSetResolveRetry(int connectionID, int retryCount) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSetResolveRetry(%d, %d)", connectionID, retryCount); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetResolveRetry(%d, %d)", connectionID, retryCount); return 0; } static int sceHttpInit(int unknown) { - ERROR_LOG(SCENET, "UNIMPL sceHttpInit(%i)", unknown); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpInit(%i)", unknown); return 0; } static int sceHttpEnd() { - ERROR_LOG(SCENET, "UNIMPL sceHttpEnd()"); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpEnd()"); return 0; } static int sceHttpInitCache(int size) { - ERROR_LOG(SCENET, "UNIMPL sceHttpInitCache(%d)", size); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpInitCache(%d)", size); return 0; } static int sceHttpEndCache() { - ERROR_LOG(SCENET, "UNIMPL sceHttpEndCache()"); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpEndCache()"); return 0; } static int sceHttpEnableCache(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpEnableCache(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpEnableCache(%d)", id); return 0; } static int sceHttpDisableCache(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDisableCache(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDisableCache(%d)", id); return 0; } static u32 sceHttpGetProxy(u32 id, u32 activateFlagPtr, u32 modePtr, u32 proxyHostPtr, u32 len, u32 proxyPort) { - ERROR_LOG(SCENET, "UNIMPL sceHttpGetProxy(%d, %x, %x, %x, %d, %x)", id, activateFlagPtr, modePtr, proxyHostPtr, len, proxyPort); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpGetProxy(%d, %x, %x, %x, %d, %x)", id, activateFlagPtr, modePtr, proxyHostPtr, len, proxyPort); return 0; } static int sceHttpGetStatusCode(int requestID, u32 statusCodePtr) { - ERROR_LOG(SCENET, "UNIMPL sceHttpGetStatusCode(%d, %x)", requestID, statusCodePtr); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpGetStatusCode(%d, %x)", requestID, statusCodePtr); return 0; } static int sceHttpReadData(int requestID, u32 dataPtr, u32 dataSize) { - ERROR_LOG(SCENET, "UNIMPL sceHttpReadData(%d, %x, %x)", requestID, dataPtr, dataSize); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpReadData(%d, %x, %x)", requestID, dataPtr, dataSize); return 0; } static int sceHttpSendRequest(int requestID, u32 dataPtr, u32 dataSize) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSendRequest(%d, %x, %x)", requestID, dataPtr, dataSize); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSendRequest(%d, %x, %x)", requestID, dataPtr, dataSize); return 0; } static int sceHttpDeleteRequest(int requestID) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDeleteRequest(%d)", requestID); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDeleteRequest(%d)", requestID); return 0; } static int sceHttpDeleteHeader(int id, const char *name) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDeleteHeader(%d, %s)", id, name); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDeleteHeader(%d, %s)", id, name); return 0; } static int sceHttpDeleteConnection(int connectionID) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDisableCache(%d)", connectionID); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDisableCache(%d)", connectionID); return 0; } static int sceHttpSetConnectTimeOut(int id, u32 timeout) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSetConnectTimeout(%d, %d)", id, timeout); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetConnectTimeout(%d, %d)", id, timeout); return 0; } static int sceHttpSetSendTimeOut(int id, u32 timeout) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSetSendTimeout(%d, %d)", id, timeout); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetSendTimeout(%d, %d)", id, timeout); return 0; } static u32 sceHttpSetProxy(u32 id, u32 activateFlagPtr, u32 mode, u32 newProxyHostPtr, u32 newProxyPort) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSetProxy(%d, %x, %x, %x, %d)", id, activateFlagPtr, mode, newProxyHostPtr, newProxyPort); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetProxy(%d, %x, %x, %x, %d)", id, activateFlagPtr, mode, newProxyHostPtr, newProxyPort); return 0; } static int sceHttpEnableCookie(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpEnableCookie(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpEnableCookie(%d)", id); return 0; } static int sceHttpEnableKeepAlive(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpEnableKeepAlive(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpEnableKeepAlive(%d)", id); return 0; } static int sceHttpDisableCookie(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDisableCookie(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDisableCookie(%d)", id); return 0; } static int sceHttpDisableKeepAlive(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDisableKeepAlive(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDisableKeepAlive(%d)", id); return 0; } static int sceHttpsInit(int unknown1, int unknown2, int unknown3, int unknown4) { - ERROR_LOG(SCENET, "UNIMPL sceHttpsInit(%d, %d, %d, %d)", unknown1, unknown2, unknown3, unknown4); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpsInit(%d, %d, %d, %d)", unknown1, unknown2, unknown3, unknown4); return 0; } static int sceHttpsEnd() { - ERROR_LOG(SCENET, "UNIMPL sceHttpsEnd()"); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpsEnd()"); return 0; } // Parameter "method" should be one of PSPHttpMethod's listed entries static int sceHttpCreateRequest(int connectionID, int method, const char *path, u64 contentLength) { - ERROR_LOG(SCENET, "UNIMPL sceHttpCreateRequest(%d, %d, %s, %llx)", connectionID, method, path, contentLength); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpCreateRequest(%d, %d, %s, %llx)", connectionID, method, path, contentLength); return 0; } static int sceHttpCreateConnection(int templateID, const char *hostString, const char *unknown1, u32 port, int unknown2) { - ERROR_LOG(SCENET, "UNIMPL sceHttpCreateConnection(%d, %s, %s, %d, %d)", templateID, hostString, unknown1, port, unknown2); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpCreateConnection(%d, %s, %s, %d, %d)", templateID, hostString, unknown1, port, unknown2); return 0; } static int sceHttpGetNetworkErrno(int request, u32 errNumPtr) { - ERROR_LOG(SCENET, "UNIMPL sceHttpGetNetworkErrno(%d, %x)", request, errNumPtr); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpGetNetworkErrno(%d, %x)", request, errNumPtr); return 0; } static int sceHttpAddExtraHeader(int id, const char *name, const char *value, int unknown) { - ERROR_LOG(SCENET, "UNIMPL sceHttpAddExtraHeader(%d, %s, %s, %d)", id, name, value, unknown); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpAddExtraHeader(%d, %s, %s, %d)", id, name, value, unknown); return 0; } static int sceHttpAbortRequest(int requestID) { - ERROR_LOG(SCENET, "UNIMPL sceHttpAbortRequest(%d)", requestID); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpAbortRequest(%d)", requestID); return 0; } static int sceHttpDeleteTemplate(int templateID) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDeleteTemplate(%d)", templateID); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDeleteTemplate(%d)", templateID); return 0; } static int sceHttpSetMallocFunction(u32 mallocFuncPtr, u32 freeFuncPtr, u32 reallocFuncPtr) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSetMallocFunction(%x, %x, %x)", mallocFuncPtr, freeFuncPtr, reallocFuncPtr); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetMallocFunction(%x, %x, %x)", mallocFuncPtr, freeFuncPtr, reallocFuncPtr); return 0; } static int sceHttpSetResolveTimeOut(int id, u32 timeout) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSetResolveTimeOut(%d, %d)", id, timeout); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetResolveTimeOut(%d, %d)", id, timeout); return 0; } static int sceHttpSetAuthInfoCB(int id, u32 callbackFuncPtr) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSetAuthInfoCB(%d, %x)", id, callbackFuncPtr); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetAuthInfoCB(%d, %x)", id, callbackFuncPtr); return 0; } static int sceHttpEnableRedirect(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpEnableRedirect(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpEnableRedirect(%d)", id); return 0; } static int sceHttpEnableAuth(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpEnableAuth(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpEnableAuth(%d)", id); return 0; } static int sceHttpDisableRedirect(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDisableRedirect(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDisableRedirect(%d)", id); return 0; } static int sceHttpDisableAuth(int id) { - ERROR_LOG(SCENET, "UNIMPL sceHttpDisableAuth(%d)", id); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpDisableAuth(%d)", id); return 0; } static int sceHttpSaveSystemCookie() { - ERROR_LOG(SCENET, "UNIMPL sceHttpSaveSystemCookie()"); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSaveSystemCookie()"); return 0; } static int sceHttpsLoadDefaultCert(int unknown1, int unknown2) { - ERROR_LOG(SCENET, "UNIMPL sceHttpLoadDefaultCert(%d, %d)", unknown1, unknown2); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpLoadDefaultCert(%d, %d)", unknown1, unknown2); return 0; } static int sceHttpLoadSystemCookie() { - ERROR_LOG(SCENET, "UNIMPL sceHttpLoadSystemCookie()"); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpLoadSystemCookie()"); return 0; } static int sceHttpCreateTemplate(const char *agent, int unknown1, int unknown2) { - ERROR_LOG(SCENET, "UNIMPL sceHttpCreateTemplate(%s, %d, %d)", agent, unknown1, unknown2); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpCreateTemplate(%s, %d, %d)", agent, unknown1, unknown2); return 0; } // Parameter "method" should be one of PSPHttpMethod's listed entries static int sceHttpCreateRequestWithURL(int connectionID, int method, const char *url, u64 contentLength) { - ERROR_LOG(SCENET, "UNIMPL sceHttpCreateRequestWithURL(%d, %d, %s, %llx)", connectionID, method, url, contentLength); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpCreateRequestWithURL(%d, %d, %s, %llx)", connectionID, method, url, contentLength); return 0; } static int sceHttpCreateConnectionWithURL(int templateID, const char *url, int unknown1) { - ERROR_LOG(SCENET, "UNIMPL sceHttpCreateConnectionWithURL(%d, %s, %d)", templateID, url, unknown1); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpCreateConnectionWithURL(%d, %s, %d)", templateID, url, unknown1); return 0; } static int sceHttpSetRecvTimeOut(int id, u32 timeout) { - ERROR_LOG(SCENET, "UNIMPL sceHttpSetRecvTimeOut(%d, %x)", id, timeout); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetRecvTimeOut(%d, %x)", id, timeout); return 0; } static int sceHttpGetAllHeader(int request, u32 headerPtrToPtr, u32 headerSize) { - ERROR_LOG(SCENET, "UNIMPL sceHttpGetAllHeader(%d, %x, %x)", request, headerPtrToPtr, headerSize); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpGetAllHeader(%d, %x, %x)", request, headerPtrToPtr, headerSize); return 0; } static int sceHttpGetContentLength(int requestID, u64 contentLengthPtr) { - ERROR_LOG(SCENET, "UNIMPL sceHttpGetContentLength(%d, %llx)", requestID, contentLengthPtr); + ERROR_LOG(Log::sceNet, "UNIMPL sceHttpGetContentLength(%d, %llx)", requestID, contentLengthPtr); return 0; } diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp index 5cb102a8d0..c72fea4995 100644 --- a/Core/HLE/sceImpose.cpp +++ b/Core/HLE/sceImpose.cpp @@ -65,7 +65,7 @@ void __ImposeDoState(PointerWrap &p) static u32 sceImposeGetBatteryIconStatus(u32 chargingPtr, u32 iconStatusPtr) { - DEBUG_LOG(SCEUTILITY, "sceImposeGetBatteryIconStatus(%08x, %08x)", chargingPtr, iconStatusPtr); + DEBUG_LOG(Log::sceUtility, "sceImposeGetBatteryIconStatus(%08x, %08x)", chargingPtr, iconStatusPtr); if (Memory::IsValidAddress(chargingPtr)) Memory::Write_U32(PSP_IMPOSE_BATTICON_NONE, chargingPtr); if (Memory::IsValidAddress(iconStatusPtr)) @@ -77,14 +77,14 @@ static u32 sceImposeSetLanguageMode(u32 languageVal, u32 buttonVal) { language = languageVal; buttonValue = buttonVal; if (language != g_Config.GetPSPLanguage()) { - return hleLogWarning(SCEUTILITY, 0, "ignoring requested language"); + return hleLogWarning(Log::sceUtility, 0, "ignoring requested language"); } - return hleLogSuccessI(SCEUTILITY, 0); + return hleLogSuccessI(Log::sceUtility, 0); } static u32 sceImposeGetLanguageMode(u32 languagePtr, u32 btnPtr) { - DEBUG_LOG(SCEUTILITY, "sceImposeGetLanguageMode(%08x, %08x)", languagePtr, btnPtr); + DEBUG_LOG(Log::sceUtility, "sceImposeGetLanguageMode(%08x, %08x)", languagePtr, btnPtr); if (Memory::IsValidAddress(languagePtr)) Memory::Write_U32(language, languagePtr); if (Memory::IsValidAddress(btnPtr)) @@ -93,24 +93,24 @@ static u32 sceImposeGetLanguageMode(u32 languagePtr, u32 btnPtr) } static u32 sceImposeSetUMDPopup(int mode) { - DEBUG_LOG(SCEUTILITY, "sceImposeSetUMDPopup(%i)", mode); + DEBUG_LOG(Log::sceUtility, "sceImposeSetUMDPopup(%i)", mode); umdPopup = mode; return 0; } static u32 sceImposeGetUMDPopup() { - DEBUG_LOG(SCEUTILITY, "sceImposeGetUMDPopup()"); + DEBUG_LOG(Log::sceUtility, "sceImposeGetUMDPopup()"); return umdPopup; } static u32 sceImposeSetBacklightOffTime(int time) { - DEBUG_LOG(SCEUTILITY, "sceImposeSetBacklightOffTime(%i)", time); + DEBUG_LOG(Log::sceUtility, "sceImposeSetBacklightOffTime(%i)", time); backlightOffTime = time; return 0; } static u32 sceImposeGetBacklightOffTime() { - DEBUG_LOG(SCEUTILITY, "sceImposeGetBacklightOffTime()"); + DEBUG_LOG(Log::sceUtility, "sceImposeGetBacklightOffTime()"); return backlightOffTime; } diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 875f807a66..b04dbdce02 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -125,11 +125,11 @@ typedef s64 SceOff; typedef u64 SceIores; const int PSP_COUNT_FDS = 64; -// TODO: Should be 3, and stdin/stdout/stderr are special values aliased to 0? -const int PSP_MIN_FD = 4; +// TODO: stdin/stdout/stderr are special values aliased to 0? +const int PSP_MIN_FD = 3; const int PSP_STDOUT = 1; const int PSP_STDERR = 2; -const int PSP_STDIN = 3; +const int PSP_STDIN = 0; static int asyncNotifyEvent = -1; static int syncNotifyEvent = -1; static SceUID fds[PSP_COUNT_FDS]; @@ -239,7 +239,7 @@ public: if (!infoReady) { info = pspFileSystem.GetFileInfo(fullpath); if (!info.exists) { - ERROR_LOG(IO, "File %s no longer exists when reading info", fullpath.c_str()); + ERROR_LOG(Log::IO, "File %s no longer exists when reading info", fullpath.c_str()); } infoReady = true; } @@ -431,7 +431,7 @@ static void __IoAsyncNotify(u64 userdata, int cyclesLate) { u32 error; FileNode *f = __IoGetFd(fd, error); if (!f) { - ERROR_LOG_REPORT(SCEIO, "__IoAsyncNotify: file no longer exists?"); + ERROR_LOG_REPORT(Log::sceIo, "__IoAsyncNotify: file no longer exists?"); return; } @@ -489,7 +489,7 @@ static void __IoSyncNotify(u64 userdata, int cyclesLate) { u32 error; FileNode *f = __IoGetFd(fd, error); if (!f) { - ERROR_LOG_REPORT(SCEIO, "__IoSyncNotify: file no longer exists?"); + ERROR_LOG_REPORT(Log::sceIo, "__IoSyncNotify: file no longer exists?"); return; } @@ -516,7 +516,7 @@ static void __IoSyncNotify(u64 userdata, int cyclesLate) { if (ioManager.WaitResult(f->handle, managerResult)) { result = managerResult.result; } else { - ERROR_LOG(SCEIO, "Unable to complete IO operation on %s", f->GetName()); + ERROR_LOG(Log::sceIo, "Unable to complete IO operation on %s", f->GetName()); } f->pendingAsyncResult = false; @@ -529,9 +529,9 @@ static void __IoSyncNotify(u64 userdata, int cyclesLate) { static void __IoAsyncBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, -1); if (result == HLEKernel::WAIT_CB_SUCCESS) { - DEBUG_LOG(SCEIO, "sceIoWaitAsync: Suspending wait for callback"); + DEBUG_LOG(Log::sceIo, "sceIoWaitAsync: Suspending wait for callback"); } else if (result == HLEKernel::WAIT_CB_BAD_WAIT_ID) { - WARN_LOG_REPORT(SCEIO, "sceIoWaitAsync: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceIo, "sceIoWaitAsync: beginning callback with bad wait id?"); } } @@ -545,7 +545,7 @@ static bool __IoCheckAsyncWait(FileNode *f, SceUID threadID, u32 &error, int res } } if (fd == -1) { - ERROR_LOG_REPORT(SCEIO, "__IoCheckAsyncWait: could not find io handle"); + ERROR_LOG_REPORT(Log::sceIo, "__IoCheckAsyncWait: could not find io handle"); return true; } @@ -576,7 +576,7 @@ static bool __IoCheckAsyncWait(FileNode *f, SceUID threadID, u32 &error, int res static void __IoAsyncEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, -1, __IoCheckAsyncWait); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) { - DEBUG_LOG(SCEIO, "sceKernelWaitEventFlagCB: Resuming lock wait for callback"); + DEBUG_LOG(Log::sceIo, "sceKernelWaitEventFlagCB: Resuming lock wait for callback"); } } @@ -658,7 +658,7 @@ void __IoInit() { Path pspDir = GetSysDirectory(DIRECTORY_PSP); if (pspDir == g_Config.memStickDirectory) { // Initially tried to do this with dual mounts, but failed due to save state compatibility issues. - INFO_LOG(SCEIO, "Enabling /PSP compatibility mode"); + INFO_LOG(Log::sceIo, "Enabling /PSP compatibility mode"); memstickFlags |= FileSystemFlags::STRIP_PSP; } @@ -677,9 +677,9 @@ void __IoInit() { if (File::Exists(exdataPath)) { auto exdataSystem = std::make_shared(&pspFileSystem, exdataPath, FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD); pspFileSystem.Mount("exdata0:", exdataSystem); - INFO_LOG(SCEIO, "Mounted exdata/%s/ under memstick for exdata0:/", gameId.c_str()); + INFO_LOG(Log::sceIo, "Mounted exdata/%s/ under memstick for exdata0:/", gameId.c_str()); } else { - INFO_LOG(SCEIO, "Did not find exdata/%s/ under memstick for exdata0:/", gameId.c_str()); + INFO_LOG(Log::sceIo, "Did not find exdata/%s/ under memstick for exdata0:/", gameId.c_str()); } } @@ -838,6 +838,12 @@ static void IoStartAsyncThread(int id, FileNode *f) { static u32 sceIoAssign(u32 alias_addr, u32 physical_addr, u32 filesystem_addr, int mode, u32 arg_addr, int argSize) { + if (!Memory::IsValidNullTerminatedString(alias_addr) || + !Memory::IsValidNullTerminatedString(physical_addr) || + !Memory::IsValidNullTerminatedString(filesystem_addr)) { + return hleLogError(Log::sceIo, -1, "Bad parameters"); + } + std::string alias = Memory::GetCharPointer(alias_addr); std::string physical_dev = Memory::GetCharPointer(physical_addr); std::string filesystem_dev = Memory::GetCharPointer(filesystem_addr); @@ -854,28 +860,28 @@ static u32 sceIoAssign(u32 alias_addr, u32 physical_addr, u32 filesystem_addr, i perm = "unhandled"; break; } - WARN_LOG_REPORT(SCEIO, "sceIoAssign(%s, %s, %s, %s, %08x, %i)", alias.c_str(), physical_dev.c_str(), filesystem_dev.c_str(), perm.c_str(), arg_addr, argSize); + WARN_LOG_REPORT(Log::sceIo, "sceIoAssign(%s, %s, %s, %s, %08x, %i)", alias.c_str(), physical_dev.c_str(), filesystem_dev.c_str(), perm.c_str(), arg_addr, argSize); return 0; } static u32 sceIoUnassign(const char *alias) { - WARN_LOG_REPORT(SCEIO, "sceIoUnassign(%s)", alias); + WARN_LOG_REPORT(Log::sceIo, "sceIoUnassign(%s)", alias); return 0; } static u32 sceKernelStdin() { - DEBUG_LOG(SCEIO, "%d=sceKernelStdin()", PSP_STDIN); + DEBUG_LOG(Log::sceIo, "%d=sceKernelStdin()", PSP_STDIN); return PSP_STDIN; } static u32 sceKernelStdout() { - DEBUG_LOG(SCEIO, "%d=sceKernelStdout()", PSP_STDOUT); + DEBUG_LOG(Log::sceIo, "%d=sceKernelStdout()", PSP_STDOUT); return PSP_STDOUT; } static u32 sceKernelStderr() { - DEBUG_LOG(SCEIO, "%d=sceKernelStderr()", PSP_STDERR); + DEBUG_LOG(Log::sceIo, "%d=sceKernelStderr()", PSP_STDERR); return PSP_STDERR; } @@ -961,14 +967,14 @@ static u32 sceIoGetstat(const char *filename, u32 addr) { if (stat.IsValid()) { __IoGetStat(stat, info); stat.NotifyWrite("IoGetstat"); - DEBUG_LOG(SCEIO, "sceIoGetstat(%s, %08x) : sector = %08x", filename, addr, info.startSector); + DEBUG_LOG(Log::sceIo, "sceIoGetstat(%s, %08x) : sector = %08x", filename, addr, info.startSector); return hleDelayResult(0, "io getstat", usec); } else { - ERROR_LOG(SCEIO, "sceIoGetstat(%s, %08x) : bad address", filename, addr); + ERROR_LOG(Log::sceIo, "sceIoGetstat(%s, %08x) : bad address", filename, addr); return hleDelayResult(-1, "io getstat", usec); } } else { - DEBUG_LOG(SCEIO, "sceIoGetstat(%s, %08x) : FILE NOT FOUND", filename, addr); + DEBUG_LOG(Log::sceIo, "sceIoGetstat(%s, %08x) : FILE NOT FOUND", filename, addr); return hleDelayResult(SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "io getstat", usec); } } @@ -976,23 +982,23 @@ static u32 sceIoGetstat(const char *filename, u32 addr) { static u32 sceIoChstat(const char *filename, u32 iostatptr, u32 changebits) { auto iostat = PSPPointer::Create(iostatptr); if (!iostat.IsValid()) - return hleReportError(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad address"); + return hleReportError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad address"); - ERROR_LOG_REPORT(SCEIO, "UNIMPL sceIoChstat(%s, %08x, %08x)", filename, iostatptr, changebits); + ERROR_LOG_REPORT(Log::sceIo, "UNIMPL sceIoChstat(%s, %08x, %08x)", filename, iostatptr, changebits); if (changebits & SCE_CST_MODE) - ERROR_LOG_REPORT(SCEIO, "sceIoChstat: change mode to %03o requested", iostat->st_mode); + ERROR_LOG_REPORT(Log::sceIo, "sceIoChstat: change mode to %03o requested", iostat->st_mode); if (changebits & SCE_CST_ATTR) - ERROR_LOG_REPORT(SCEIO, "sceIoChstat: change attr to %04x requested", iostat->st_attr); + ERROR_LOG_REPORT(Log::sceIo, "sceIoChstat: change attr to %04x requested", iostat->st_attr); if (changebits & SCE_CST_SIZE) - ERROR_LOG(SCEIO, "sceIoChstat: change size requested"); + ERROR_LOG(Log::sceIo, "sceIoChstat: change size requested"); if (changebits & SCE_CST_CT) - ERROR_LOG(SCEIO, "sceIoChstat: change creation time requested"); + ERROR_LOG(Log::sceIo, "sceIoChstat: change creation time requested"); if (changebits & SCE_CST_AT) - ERROR_LOG(SCEIO, "sceIoChstat: change access time requested"); + ERROR_LOG(Log::sceIo, "sceIoChstat: change access time requested"); if (changebits & SCE_CST_MT) - ERROR_LOG_REPORT(SCEIO, "sceIoChstat: change modification time to %04d-%02d-%02d requested", iostat->st_m_time.year, iostat->st_m_time.month, iostat->st_m_time.day); + ERROR_LOG_REPORT(Log::sceIo, "sceIoChstat: change modification time to %04d-%02d-%02d requested", iostat->st_m_time.year, iostat->st_m_time.month, iostat->st_m_time.day); if (changebits & SCE_CST_PRVT) - ERROR_LOG(SCEIO, "sceIoChstat: change private data requested"); + ERROR_LOG(Log::sceIo, "sceIoChstat: change private data requested"); return 0; } @@ -1052,7 +1058,7 @@ static bool __IoRead(int &result, int id, u32 data_addr, int size, int &us) { } if (id == PSP_STDIN) { - DEBUG_LOG(SCEIO, "sceIoRead STDIN"); + DEBUG_LOG(Log::sceIo, "sceIoRead STDIN"); result = 0; //stdin return true; } @@ -1127,11 +1133,11 @@ static u32 sceIoRead(int id, u32 data_addr, int size) { FileNode *f = __IoGetFd(id, error); if (id > 2 && f != NULL) { if (!__KernelIsDispatchEnabled()) { - DEBUG_LOG(SCEIO, "sceIoRead(%d, %08x, %x): dispatch disabled", id, data_addr, size); + DEBUG_LOG(Log::sceIo, "sceIoRead(%d, %08x, %x): dispatch disabled", id, data_addr, size); return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } if (__IsInInterrupt()) { - DEBUG_LOG(SCEIO, "sceIoRead(%d, %08x, %x): inside interrupt", id, data_addr, size); + DEBUG_LOG(Log::sceIo, "sceIoRead(%d, %08x, %x): inside interrupt", id, data_addr, size); return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; } } @@ -1140,17 +1146,17 @@ static u32 sceIoRead(int id, u32 data_addr, int size) { int us; bool complete = __IoRead(result, id, data_addr, size, us); if (!complete) { - DEBUG_LOG(SCEIO, "sceIoRead(%d, %08x, %x): deferring result", id, data_addr, size); + DEBUG_LOG(Log::sceIo, "sceIoRead(%d, %08x, %x): deferring result", id, data_addr, size); __IoSchedSync(f, id, us); __KernelWaitCurThread(WAITTYPE_IO, id, 0, 0, false, "io read"); f->waitingSyncThreads.push_back(__KernelGetCurThread()); return 0; } else if (result >= 0) { - DEBUG_LOG(SCEIO, "%x=sceIoRead(%d, %08x, %x)", result, id, data_addr, size); + DEBUG_LOG(Log::sceIo, "%x=sceIoRead(%d, %08x, %x)", result, id, data_addr, size); return hleDelayResult(result, "io read", us); } else { - WARN_LOG(SCEIO, "sceIoRead(%d, %08x, %x): error %08x", id, data_addr, size, result); + WARN_LOG(Log::sceIo, "sceIoRead(%d, %08x, %x): error %08x", id, data_addr, size, result); return result; } } @@ -1160,7 +1166,7 @@ static u32 sceIoReadAsync(int id, u32 data_addr, int size) { FileNode *f = __IoGetFd(id, error); if (f) { if (f->asyncBusy()) { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); } auto ¶ms = asyncParams[id]; @@ -1168,9 +1174,9 @@ static u32 sceIoReadAsync(int id, u32 data_addr, int size) { params.std.addr = data_addr; params.std.size = size; IoStartAsyncThread(id, f); - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } else { - return hleLogError(SCEIO, error, "bad file descriptor"); + return hleLogError(Log::sceIo, error, "bad file descriptor"); } } @@ -1188,7 +1194,7 @@ static bool __IoWrite(int &result, int id, u32 data_addr, int size, int &us) { if (id == PSP_STDOUT || id == PSP_STDERR) { const char *str = (const char *) data_ptr; const int str_size = size <= 0 ? 0 : (str[validSize - 1] == '\n' ? validSize - 1 : validSize); - INFO_LOG(PRINTF, "%s: %.*s", id == 1 ? "stdout" : "stderr", str_size, str); + INFO_LOG(Log::Printf, "%s: %.*s", id == 1 ? "stdout" : "stderr", str_size, str); result = validSize; return true; } @@ -1214,7 +1220,7 @@ static bool __IoWrite(int &result, int id, u32 data_addr, int size, int &us) { if (f->isTTY) { const char *str = (const char *)data_ptr; const int str_size = size <= 0 ? 0 : (str[validSize - 1] == '\n' ? validSize - 1 : validSize); - INFO_LOG(PRINTF, "%s: %.*s", "tty", str_size, str); + INFO_LOG(Log::Printf, "%s: %.*s", "tty", str_size, str); result = validSize; return true; } @@ -1244,7 +1250,7 @@ static bool __IoWrite(int &result, int id, u32 data_addr, int size, int &us) { } return true; } else { - ERROR_LOG(SCEIO, "sceIoWrite ERROR: no file open"); + ERROR_LOG(Log::sceIo, "sceIoWrite ERROR: no file open"); result = (s32) error; return true; } @@ -1255,11 +1261,11 @@ static u32 sceIoWrite(int id, u32 data_addr, int size) { FileNode *f = __IoGetFd(id, error); if (id > 2 && f != NULL) { if (!__KernelIsDispatchEnabled()) { - DEBUG_LOG(SCEIO, "sceIoWrite(%d, %08x, %x): dispatch disabled", id, data_addr, size); + DEBUG_LOG(Log::sceIo, "sceIoWrite(%d, %08x, %x): dispatch disabled", id, data_addr, size); return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } if (__IsInInterrupt()) { - DEBUG_LOG(SCEIO, "sceIoWrite(%d, %08x, %x): inside interrupt", id, data_addr, size); + DEBUG_LOG(Log::sceIo, "sceIoWrite(%d, %08x, %x): inside interrupt", id, data_addr, size); return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; } } @@ -1268,14 +1274,14 @@ static u32 sceIoWrite(int id, u32 data_addr, int size) { int us; bool complete = __IoWrite(result, id, data_addr, size, us); if (!complete) { - DEBUG_LOG(SCEIO, "sceIoWrite(%d, %08x, %x): deferring result", id, data_addr, size); + DEBUG_LOG(Log::sceIo, "sceIoWrite(%d, %08x, %x): deferring result", id, data_addr, size); __IoSchedSync(f, id, us); __KernelWaitCurThread(WAITTYPE_IO, id, 0, 0, false, "io write"); f->waitingSyncThreads.push_back(__KernelGetCurThread()); return 0; } else if (result >= 0) { - DEBUG_LOG(SCEIO, "%x=sceIoWrite(%d, %08x, %x)", result, id, data_addr, size); + DEBUG_LOG(Log::sceIo, "%x=sceIoWrite(%d, %08x, %x)", result, id, data_addr, size); if (__KernelIsDispatchEnabled()) { // If we wrote to stdout, return an error (even though we did log it) rather than delaying. // On actual hardware, it would just return this... we just want the log output. @@ -1287,7 +1293,7 @@ static u32 sceIoWrite(int id, u32 data_addr, int size) { return result; } } else { - WARN_LOG(SCEIO, "sceIoWrite(%d, %08x, %x): error %08x", id, data_addr, size, result); + WARN_LOG(Log::sceIo, "sceIoWrite(%d, %08x, %x): error %08x", id, data_addr, size, result); return result; } } @@ -1297,7 +1303,7 @@ static u32 sceIoWriteAsync(int id, u32 data_addr, int size) { FileNode *f = __IoGetFd(id, error); if (f) { if (f->asyncBusy()) { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); } auto ¶ms = asyncParams[id]; @@ -1305,15 +1311,15 @@ static u32 sceIoWriteAsync(int id, u32 data_addr, int size) { params.std.addr = data_addr; params.std.size = size; IoStartAsyncThread(id, f); - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } else { - return hleLogError(SCEIO, error, "bad file descriptor"); + return hleLogError(Log::sceIo, error, "bad file descriptor"); } } static u32 sceIoGetDevType(int id) { if (id == PSP_STDOUT || id == PSP_STDERR || id == PSP_STDIN) { - DEBUG_LOG(SCEIO, "sceIoGetDevType(%d)", id); + DEBUG_LOG(Log::sceIo, "sceIoGetDevType(%d)", id); return (u32)PSPDevType::FILE; } @@ -1322,13 +1328,13 @@ static u32 sceIoGetDevType(int id) { int result; if (f) { // TODO: When would this return PSP_DEV_TYPE_ALIAS? - WARN_LOG(SCEIO, "sceIoGetDevType(%d - %s)", id, f->fullpath.c_str()); + WARN_LOG(Log::sceIo, "sceIoGetDevType(%d - %s)", id, f->fullpath.c_str()); if (f->isTTY) result = (u32)PSPDevType::FILE; else result = (u32)pspFileSystem.DevType(f->handle) & (u32)PSPDevType::EMU_MASK; } else { - ERROR_LOG(SCEIO, "sceIoGetDevType: unknown id %d", id); + ERROR_LOG(Log::sceIo, "sceIoGetDevType: unknown id %d", id); result = SCE_KERNEL_ERROR_BADF; } @@ -1341,9 +1347,9 @@ static u32 sceIoCancel(int id) FileNode *f = __IoGetFd(id, error); if (f) { // It seems like this is unsupported for UMDs and memory sticks, based on tests. - return hleReportError(SCEIO, SCE_KERNEL_ERROR_UNSUP, "unimplemented or unsupported"); + return hleReportError(Log::sceIo, SCE_KERNEL_ERROR_UNSUP, "unimplemented or unsupported"); } else { - return hleLogError(SCEIO, SCE_KERNEL_ERROR_BADF, "invalid fd"); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_BADF, "invalid fd"); } } @@ -1406,7 +1412,7 @@ static s64 __IoLseek(SceUID id, s64 offset, int whence) { FileNode *f = __IoGetFd(id, error); if (f) { if (f->asyncBusy()) { - WARN_LOG(SCEIO, "sceIoLseek*(%d, %llx, %i): async busy", id, offset, whence); + WARN_LOG(Log::sceIo, "sceIoLseek*(%d, %llx, %i): async busy", id, offset, whence); return SCE_KERNEL_ERROR_ASYNC_BUSY; } FileMove seek; @@ -1426,26 +1432,26 @@ static s64 __IoLseek(SceUID id, s64 offset, int whence) { static s64 sceIoLseek(int id, s64 offset, int whence) { s64 result = __IoLseek(id, offset, whence); if (result >= 0 || result == -1) { - DEBUG_LOG(SCEIO, "%lli = sceIoLseek(%d, %llx, %i)", result, id, offset, whence); + DEBUG_LOG(Log::sceIo, "%lli = sceIoLseek(%d, %llx, %i)", result, id, offset, whence); // Educated guess at timing. hleEatCycles(1400); hleReSchedule("io seek"); return result; } else { - return hleLogError(SCEIO, result, "bad file descriptor"); + return hleLogError(Log::sceIo, result, "bad file descriptor"); } } static u32 sceIoLseek32(int id, int offset, int whence) { s32 result = (s32) __IoLseek(id, offset, whence); if (result >= 0 || result == -1) { - DEBUG_LOG(SCEIO, "%i = sceIoLseek32(%d, %x, %i)", result, id, offset, whence); + DEBUG_LOG(Log::sceIo, "%i = sceIoLseek32(%d, %x, %i)", result, id, offset, whence); // Educated guess at timing. hleEatCycles(1400); hleReSchedule("io seek"); return result; } else { - return hleLogError(SCEIO, result, "bad file descriptor"); + return hleLogError(Log::sceIo, result, "bad file descriptor"); } } @@ -1454,10 +1460,10 @@ static u32 sceIoLseekAsync(int id, s64 offset, int whence) { FileNode *f = __IoGetFd(id, error); if (f) { if (whence < 0 || whence > 2) { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_INVAL, "invalid whence"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_INVAL, "invalid whence"); } if (f->asyncBusy()) { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); } auto ¶ms = asyncParams[id]; @@ -1465,9 +1471,9 @@ static u32 sceIoLseekAsync(int id, s64 offset, int whence) { params.seek.pos = offset; params.seek.whence = whence; IoStartAsyncThread(id, f); - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } else { - return hleLogError(SCEIO, error, "bad file descriptor"); + return hleLogError(Log::sceIo, error, "bad file descriptor"); } return 0; } @@ -1477,10 +1483,10 @@ static u32 sceIoLseek32Async(int id, int offset, int whence) { FileNode *f = __IoGetFd(id, error); if (f) { if (whence < 0 || whence > 2) { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_INVAL, "invalid whence"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_INVAL, "invalid whence"); } if (f->asyncBusy()) { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); } auto ¶ms = asyncParams[id]; @@ -1488,9 +1494,9 @@ static u32 sceIoLseek32Async(int id, int offset, int whence) { params.seek.pos = offset; params.seek.whence = whence; IoStartAsyncThread(id, f); - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } else { - return hleLogError(SCEIO, error, "bad file descriptor"); + return hleLogError(Log::sceIo, error, "bad file descriptor"); } return 0; } @@ -1558,12 +1564,12 @@ static u32 sceIoOpen(const char *filename, int flags, int mode) { if (!filename) { // Not tested on the PSP. - return hleLogError(SCEIO, SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "nullptr file not found"); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "nullptr file not found"); } if (!__KernelIsDispatchEnabled()) { hleEatCycles(48000); - return hleLogError(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } int error; @@ -1572,49 +1578,49 @@ static u32 sceIoOpen(const char *filename, int flags, int mode) { _assert_(error != 0); if (error == (int)SCE_KERNEL_ERROR_NOCWD) { // TODO: Timing is not accurate. - return hleLogError(SCEIO, hleDelayResult(error, "file opened", 10000), "no current working directory"); + return hleLogError(Log::sceIo, hleDelayResult(error, "file opened", 10000), "no current working directory"); } else if (error == (int)SCE_KERNEL_ERROR_NODEV) { - return hleLogError(SCEIO, error, "device not found"); + return hleLogError(Log::sceIo, error, "device not found"); } else if (error == (int)SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND) { // UMD: Varies between 5-10ms, could take longer if disc spins up. // TODO: Bad filename at root (disc0:/no.exist) should take ~200us. // Card: Path depth matters, but typically between 10-13ms on a standard Pro Duo. // TODO: If a UMD and spun down, this can easily take 1s+. int delay = pspFileSystem.FlagsFromFilename(filename) & FileSystemFlags::UMD ? 6000 : 10000; - return hleLogWarning(SCEIO, hleDelayResult(error, "file opened", delay), "file not found"); + return hleLogWarning(Log::sceIo, hleDelayResult(error, "file opened", delay), "file not found"); } else { - return hleLogError(SCEIO, hleDelayResult(error, "file opened", 10000)); + return hleLogError(Log::sceIo, hleDelayResult(error, "file opened", 10000)); } } int id = __IoAllocFd(f); if (id < 0) { kernelObjects.Destroy(f->GetUID()); - return hleLogError(SCEIO, hleDelayResult(id, "file opened", 1000), "out of fds"); + return hleLogError(Log::sceIo, hleDelayResult(id, "file opened", 1000), "out of fds"); } else { asyncParams[id].priority = asyncDefaultPriority; IFileSystem *sys = pspFileSystem.GetSystemFromFilename(filename); if (sys && !f->isTTY && (sys->DevType(f->handle) & (PSPDevType::BLOCK | PSPDevType::EMU_LBN))) { // These are fast to open, no delay or even rescheduling happens. - return hleLogSuccessI(SCEIO, id); + return hleLogSuccessI(Log::sceIo, id); } // UMD: Speed varies from 1-6ms. // Card: Path depth matters, but typically between 10-13ms on a standard Pro Duo. int delay = pspFileSystem.FlagsFromFilename(filename) & FileSystemFlags::UMD ? 4000 : 10000; - return hleLogSuccessI(SCEIO, hleDelayResult(id, "file opened", delay)); + return hleLogSuccessI(Log::sceIo, hleDelayResult(id, "file opened", delay)); } } static u32 sceIoClose(int id) { u32 error; - DEBUG_LOG(SCEIO, "sceIoClose(%d)", id); + DEBUG_LOG(Log::sceIo, "sceIoClose(%d)", id); __IoFreeFd(id, error); // Timing is not accurate, aiming low for now. return hleDelayResult(error, "file closed", 100); } static u32 sceIoRemove(const char *filename) { - DEBUG_LOG(SCEIO, "sceIoRemove(%s)", filename); + DEBUG_LOG(Log::sceIo, "sceIoRemove(%s)", filename); // TODO: This timing isn't necessarily accurate, low end for now. if(!pspFileSystem.GetFileInfo(filename).exists) @@ -1625,7 +1631,7 @@ static u32 sceIoRemove(const char *filename) { } static u32 sceIoMkdir(const char *dirname, int mode) { - DEBUG_LOG(SCEIO, "sceIoMkdir(%s, %i)", dirname, mode); + DEBUG_LOG(Log::sceIo, "sceIoMkdir(%s, %i)", dirname, mode); // TODO: Improve timing. if (pspFileSystem.MkDir(dirname)) return hleDelayResult(0, "mkdir", 1000); @@ -1634,7 +1640,7 @@ static u32 sceIoMkdir(const char *dirname, int mode) { } static u32 sceIoRmdir(const char *dirname) { - DEBUG_LOG(SCEIO, "sceIoRmdir(%s)", dirname); + DEBUG_LOG(Log::sceIo, "sceIoRmdir(%s)", dirname); // TODO: Improve timing. if (pspFileSystem.RmDir(dirname)) return hleDelayResult(0, "rmdir", 1000); @@ -1643,7 +1649,7 @@ static u32 sceIoRmdir(const char *dirname) { } static u32 sceIoSync(const char *devicename, int flag) { - DEBUG_LOG(SCEIO, "UNIMPL sceIoSync(%s, %i)", devicename, flag); + DEBUG_LOG(Log::sceIo, "UNIMPL sceIoSync(%s, %i)", devicename, flag); return 0; } @@ -1657,7 +1663,7 @@ struct DeviceSize { static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, int outLen) { if (strcmp(name, "emulator:")) { - DEBUG_LOG(SCEIO,"sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd, argAddr, argLen, outPtr, outLen); + DEBUG_LOG(Log::sceIo,"sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd, argAddr, argLen, outPtr, outLen); } // UMD checks @@ -1749,7 +1755,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o case 0x01F100A6: case 0x01F100A8: case 0x01F100A9: - ERROR_LOG_REPORT(SCEIO, "UNIMPL sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd, argAddr, argLen, outPtr, outLen); + ERROR_LOG_REPORT(Log::sceIo, "UNIMPL sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd, argAddr, argLen, outPtr, outLen); return 0; } @@ -1788,10 +1794,10 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o // * 1 = Memory stick inserted // * 2 = Memory stick removed // * 4 = Memory stick mounting? (followed by a 1 about 500ms later) - DEBUG_LOG(SCEIO, "sceIoDevctl: Memstick callback %i registered, notifying immediately", cbId); + DEBUG_LOG(Log::sceIo, "sceIoDevctl: Memstick callback %i registered, notifying immediately", cbId); __KernelNotifyCallback(cbId, MemoryStick_State()); } else { - DEBUG_LOG(SCEIO, "sceIoDevctl: Memstick callback %i registered", cbId); + DEBUG_LOG(Log::sceIo, "sceIoDevctl: Memstick callback %i registered", cbId); } return 0; } else { @@ -1816,7 +1822,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o if (slot != (size_t)-1) { memStickCallbacks.erase(memStickCallbacks.begin() + slot); - DEBUG_LOG(SCEIO, "sceIoDevctl: Unregistered memstick callback %i", cbId); + DEBUG_LOG(Log::sceIo, "sceIoDevctl: Unregistered memstick callback %i", cbId); return 0; } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; @@ -1873,7 +1879,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o Memory::WriteUnchecked_U32(0, outPtr); return 0; } else { - ERROR_LOG(SCEIO, "Failed 0x02425824 fat"); + ERROR_LOG(Log::sceIo, "Failed 0x02425824 fat"); return -1; } break; @@ -1900,10 +1906,10 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o // Values observed: // * 1 = Memory stick inserted // * 2 = Memory stick removed - DEBUG_LOG(SCEIO, "sceIoDevCtl: Memstick FAT callback %i registered, notifying immediately", cbId); + DEBUG_LOG(Log::sceIo, "sceIoDevCtl: Memstick FAT callback %i registered, notifying immediately", cbId); __KernelNotifyCallback(cbId, MemoryStick_FatState()); } else { - DEBUG_LOG(SCEIO, "sceIoDevCtl: Memstick FAT callback %i registered", cbId); + DEBUG_LOG(Log::sceIo, "sceIoDevCtl: Memstick FAT callback %i registered", cbId); } return 0; } else { @@ -1928,7 +1934,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o if (slot != (size_t)-1) { memStickFatCallbacks.erase(memStickFatCallbacks.begin() + slot); - DEBUG_LOG(SCEIO, "sceIoDevCtl: Unregistered memstick FAT callback %i", cbId); + DEBUG_LOG(Log::sceIo, "sceIoDevCtl: Unregistered memstick FAT callback %i", cbId); return 0; } else { return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; @@ -1941,7 +1947,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o MemoryStick_SetFatState((MemStickFatState)Memory::Read_U32(argAddr)); return 0; } else { - ERROR_LOG(SCEIO, "Failed 0x02415823 fat"); + ERROR_LOG(Log::sceIo, "Failed 0x02415823 fat"); return -1; } break; @@ -1949,11 +1955,11 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o // Check if FAT enabled // If the values added together are >= 0x80000000, or less than outPtr, invalid address. if (((int)outPtr + outLen) < (int)outPtr) { - ERROR_LOG(SCEIO, "sceIoDevctl: fatms0: 0x02425823 command, bad address"); + ERROR_LOG(Log::sceIo, "sceIoDevctl: fatms0: 0x02425823 command, bad address"); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } else if (!Memory::IsValidAddress(outPtr)) { // Technically, only checks for NULL, crashes for many bad addresses. - ERROR_LOG(SCEIO, "sceIoDevctl: fatms0: 0x02425823 command, no output address"); + ERROR_LOG(Log::sceIo, "sceIoDevctl: fatms0: 0x02425823 command, no output address"); return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; } else { // Does not care about outLen, even if it's 0. @@ -1971,7 +1977,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o Memory::Write_U32(0, outPtr); return 0; } else { - ERROR_LOG(SCEIO, "Failed 0x02425824 fat"); + ERROR_LOG(Log::sceIo, "Failed 0x02425824 fat"); return -1; } break; @@ -2009,8 +2015,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o { // Emulator special tricks! - enum - { + enum { EMULATOR_DEVCTL__GET_HAS_DISPLAY = 1, EMULATOR_DEVCTL__SEND_OUTPUT, EMULATOR_DEVCTL__IS_EMULATOR, @@ -2031,14 +2036,14 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o Memory::Write_U32(PSP_CoreParameter().headLess ? 0 : 1, outPtr); return 0; case EMULATOR_DEVCTL__SEND_OUTPUT: - { - std::string data(Memory::GetCharPointer(argAddr), argLen); + if (Memory::IsValidRange(argAddr, argLen)) { + std::string data(Memory::GetCharPointerUnchecked(argAddr), argLen); if (!System_SendDebugOutput(data)) - DEBUG_LOG(SCEIO, "%s", data.c_str()); + DEBUG_LOG(Log::sceIo, "%s", data.c_str()); if (PSP_CoreParameter().collectDebugOutput) *PSP_CoreParameter().collectDebugOutput += data; - return 0; } + return 0; case EMULATOR_DEVCTL__IS_EMULATOR: if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(1, outPtr); @@ -2098,7 +2103,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o return 0; } - ERROR_LOG(SCEIO, "sceIoDevCtl: UNKNOWN PARAMETERS"); + ERROR_LOG(Log::sceIo, "sceIoDevCtl: UNKNOWN PARAMETERS"); return 0; } @@ -2108,12 +2113,12 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o 089c6bdc ]: HLE: sceKernelCreateCallback(name= MemoryStick Detection ,entry= 089c7484 ) (z_un_089c6bc4) 089c6c40 ]: HLE: sceKernelCreateCallback(name= MemoryStick Assignment ,entry= 089c7534 ) (z_un_089c6bc4) */ - ERROR_LOG_REPORT(SCEIO, "UNIMPL sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd, argAddr, argLen, outPtr, outLen); + ERROR_LOG_REPORT(Log::sceIo, "UNIMPL sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd, argAddr, argLen, outPtr, outLen); return SCE_KERNEL_ERROR_UNSUP; } static u32 sceIoRename(const char *from, const char *to) { - DEBUG_LOG(SCEIO, "sceIoRename(%s, %s)", from, to); + DEBUG_LOG(Log::sceIo, "sceIoRename(%s, %s)", from, to); // TODO: Timing isn't terribly accurate. if (!pspFileSystem.GetFileInfo(from).exists) @@ -2121,30 +2126,30 @@ static u32 sceIoRename(const char *from, const char *to) { int result = pspFileSystem.RenameFile(from, to); if (result < 0) - WARN_LOG(SCEIO, "Could not move %s to %s", from, to); + WARN_LOG(Log::sceIo, "Could not move %s to %s", from, to); return hleDelayResult(result, "file renamed", 1000); } static u32 sceIoChdir(const char *dirname) { - DEBUG_LOG(SCEIO, "sceIoChdir(%s)", dirname); + DEBUG_LOG(Log::sceIo, "sceIoChdir(%s)", dirname); return pspFileSystem.ChDir(dirname); } static int sceIoChangeAsyncPriority(int id, int priority) { // priority = -1 is valid,means the current thread'priority if (priority != -1 && (priority < 0x08 || priority > 0x77)) { - return hleLogError(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "illegal priority %d", priority); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "illegal priority %d", priority); } if (id == -1) { asyncDefaultPriority = priority; - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } u32 error; FileNode *f = __IoGetFd(id, error); if (!f) { - return hleLogError(SCEIO, error, "bad file descriptor"); + return hleLogError(Log::sceIo, error, "bad file descriptor"); } if (asyncThreads[id] && !asyncThreads[id]->Stopped()) { @@ -2155,17 +2160,17 @@ static int sceIoChangeAsyncPriority(int id, int priority) { } asyncParams[id].priority = priority; - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } static int sceIoCloseAsync(int id) { u32 error; FileNode *f = __IoGetFd(id, error); if (!f) { - return hleLogError(SCEIO, error, "bad file descriptor"); + return hleLogError(Log::sceIo, error, "bad file descriptor"); } if (f->asyncBusy()) { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); } f->closePending = true; @@ -2173,12 +2178,12 @@ static int sceIoCloseAsync(int id) { auto ¶ms = asyncParams[id]; params.op = IoAsyncOp::CLOSE; IoStartAsyncThread(id, f); - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } static u32 sceIoSetAsyncCallback(int id, u32 clbckId, u32 clbckArg) { - DEBUG_LOG(SCEIO, "sceIoSetAsyncCallback(%d, %i, %08x)", id, clbckId, clbckArg); + DEBUG_LOG(Log::sceIo, "sceIoSetAsyncCallback(%d, %i, %08x)", id, clbckId, clbckArg); u32 error; FileNode *f = __IoGetFd(id, error); @@ -2198,7 +2203,7 @@ static u32 sceIoOpenAsync(const char *filename, int flags, int mode) { hleEatCycles(18000); if (!filename) { // Not tested on the PSP. - return hleLogError(SCEIO, SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "nullptr file not found"); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "nullptr file not found"); } // TODO: Use an internal method so as not to pollute the log? @@ -2213,7 +2218,7 @@ static u32 sceIoOpenAsync(const char *filename, int flags, int mode) { if (f == nullptr) { _assert_(error != 0); if (error == SCE_KERNEL_ERROR_NODEV) - return hleLogError(SCEIO, error, "device not found"); + return hleLogError(Log::sceIo, error, "device not found"); f = new FileNode(); kernelObjects.Create(f); @@ -2226,7 +2231,7 @@ static u32 sceIoOpenAsync(const char *filename, int flags, int mode) { int fd = __IoAllocFd(f); if (fd < 0) { kernelObjects.Destroy(f->GetUID()); - return hleLogError(SCEIO, hleDelayResult(fd, "file opened", 1000), "out of fds"); + return hleLogError(Log::sceIo, hleDelayResult(fd, "file opened", 1000), "out of fds"); } auto ¶ms = asyncParams[fd]; @@ -2239,11 +2244,11 @@ static u32 sceIoOpenAsync(const char *filename, int flags, int mode) { if (error != 0) { f->asyncResult = (s64)error; - return hleLogError(SCEIO, fd, "file not found"); + return hleLogError(Log::sceIo, fd, "file not found"); } f->asyncResult = fd; - return hleLogSuccessI(SCEIO, fd); + return hleLogSuccessI(Log::sceIo, fd); } static u32 sceIoGetAsyncStat(int id, u32 poll, u32 address) { @@ -2251,30 +2256,30 @@ static u32 sceIoGetAsyncStat(int id, u32 poll, u32 address) { FileNode *f = __IoGetFd(id, error); if (f) { if (__IsInInterrupt()) { - DEBUG_LOG(SCEIO, "%lli = sceIoGetAsyncStat(%i, %i, %08x): illegal context", f->asyncResult, id, poll, address); + DEBUG_LOG(Log::sceIo, "%lli = sceIoGetAsyncStat(%i, %i, %08x): illegal context", f->asyncResult, id, poll, address); return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; } if (f->pendingAsyncResult) { if (poll) { - DEBUG_LOG(SCEIO, "%lli = sceIoGetAsyncStat(%i, %i, %08x): not ready", f->asyncResult, id, poll, address); + DEBUG_LOG(Log::sceIo, "%lli = sceIoGetAsyncStat(%i, %i, %08x): not ready", f->asyncResult, id, poll, address); return 1; } else { if (!__KernelIsDispatchEnabled()) { - DEBUG_LOG(SCEIO, "%lli = sceIoGetAsyncStat(%i, %i, %08x): dispatch disabled", f->asyncResult, id, poll, address); + DEBUG_LOG(Log::sceIo, "%lli = sceIoGetAsyncStat(%i, %i, %08x): dispatch disabled", f->asyncResult, id, poll, address); return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } - DEBUG_LOG(SCEIO, "%lli = sceIoGetAsyncStat(%i, %i, %08x): waiting", f->asyncResult, id, poll, address); + DEBUG_LOG(Log::sceIo, "%lli = sceIoGetAsyncStat(%i, %i, %08x): waiting", f->asyncResult, id, poll, address); f->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_ASYNCIO, f->GetUID(), address, 0, false, "io waited"); } } else if (f->hasAsyncResult) { if (!__KernelIsDispatchEnabled()) { - DEBUG_LOG(SCEIO, "%lli = sceIoGetAsyncStat(%i, %i, %08x): dispatch disabled", f->asyncResult, id, poll, address); + DEBUG_LOG(Log::sceIo, "%lli = sceIoGetAsyncStat(%i, %i, %08x): dispatch disabled", f->asyncResult, id, poll, address); return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } - DEBUG_LOG(SCEIO, "%lli = sceIoGetAsyncStat(%i, %i, %08x)", f->asyncResult, id, poll, address); + DEBUG_LOG(Log::sceIo, "%lli = sceIoGetAsyncStat(%i, %i, %08x)", f->asyncResult, id, poll, address); Memory::Write_U64((u64) f->asyncResult, address); f->hasAsyncResult = false; @@ -2282,15 +2287,16 @@ static u32 sceIoGetAsyncStat(int id, u32 poll, u32 address) { __IoFreeFd(id, error); } } else { - WARN_LOG(SCEIO, "SCE_KERNEL_ERROR_NOASYNC = sceIoGetAsyncStat(%i, %i, %08x)", id, poll, address); + WARN_LOG(Log::sceIo, "SCE_KERNEL_ERROR_NOASYNC = sceIoGetAsyncStat(%i, %i, %08x)", id, poll, address); return SCE_KERNEL_ERROR_NOASYNC; } return 0; //completed - } - else - { - ERROR_LOG(SCEIO, "ERROR - sceIoGetAsyncStat with invalid id %i", id); - return SCE_KERNEL_ERROR_BADF; + } else { + if (id == 0) { + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_BADF, "ERROR - sceIoGetAsyncStat with invalid id %d", id); + } else { + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_BADF, "ERROR - sceIoGetAsyncStat with invalid id %d", id); + } } } @@ -2299,18 +2305,18 @@ static int sceIoWaitAsync(int id, u32 address) { FileNode *f = __IoGetFd(id, error); if (f) { if (__IsInInterrupt()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "illegal context"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "illegal context"); } if (f->pendingAsyncResult) { if (!__KernelIsDispatchEnabled()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } f->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_ASYNCIO, f->GetUID(), address, 0, false, "io waited"); - return hleLogSuccessI(SCEIO, 0, "waiting"); + return hleLogSuccessI(Log::sceIo, 0, "waiting"); } else if (f->hasAsyncResult) { if (!__KernelIsDispatchEnabled()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } Memory::Write_U64((u64) f->asyncResult, address); f->hasAsyncResult = false; @@ -2319,13 +2325,13 @@ static int sceIoWaitAsync(int id, u32 address) { __IoFreeFd(id, error); } - return hleLogSuccessI(SCEIO, 0, "complete"); + return hleLogSuccessI(Log::sceIo, 0, "complete"); } else { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_NOASYNC, "no async pending"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_NOASYNC, "no async pending"); } return 0; //completed } else { - return hleLogError(SCEIO, SCE_KERNEL_ERROR_BADF, "invalid fd"); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_BADF, "invalid fd"); } } @@ -2335,7 +2341,7 @@ static int sceIoWaitAsyncCB(int id, u32 address) { FileNode *f = __IoGetFd(id, error); if (f) { if (__IsInInterrupt()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "illegal context"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "illegal context"); } hleCheckCurrentCallbacks(); @@ -2343,7 +2349,7 @@ static int sceIoWaitAsyncCB(int id, u32 address) { // TODO: This seems to re-enable dispatch or something? f->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_ASYNCIO, f->GetUID(), address, 0, true, "io waited"); - return hleLogSuccessI(SCEIO, 0, "waiting"); + return hleLogSuccessI(Log::sceIo, 0, "waiting"); } else if (f->hasAsyncResult) { Memory::Write_U64((u64) f->asyncResult, address); f->hasAsyncResult = false; @@ -2352,12 +2358,12 @@ static int sceIoWaitAsyncCB(int id, u32 address) { __IoFreeFd(id, error); } - return hleLogSuccessI(SCEIO, 0, "complete"); + return hleLogSuccessI(Log::sceIo, 0, "complete"); } else { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_NOASYNC, "no async pending"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_NOASYNC, "no async pending"); } } else { - return hleLogError(SCEIO, SCE_KERNEL_ERROR_BADF, "invalid fd"); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_BADF, "invalid fd"); } } @@ -2366,7 +2372,7 @@ static u32 sceIoPollAsync(int id, u32 address) { FileNode *f = __IoGetFd(id, error); if (f) { if (f->pendingAsyncResult) { - return hleLogSuccessVerboseI(SCEIO, 1, "not ready"); + return hleLogSuccessVerboseI(Log::sceIo, 1, "not ready"); } else if (f->hasAsyncResult) { Memory::Write_U64((u64) f->asyncResult, address); f->hasAsyncResult = false; @@ -2374,12 +2380,12 @@ static u32 sceIoPollAsync(int id, u32 address) { if (f->closePending) { __IoFreeFd(id, error); } - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } else { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_NOASYNC, "no async pending"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_NOASYNC, "no async pending"); } } else { - return hleLogError(SCEIO, SCE_KERNEL_ERROR_BADF, "invalid fd"); + return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_BADF, "invalid fd"); } } @@ -2415,7 +2421,7 @@ public: }; static u32 sceIoDopen(const char *path) { - DEBUG_LOG(SCEIO, "sceIoDopen(\"%s\")", path); + DEBUG_LOG(Log::sceIo, "sceIoDopen(\"%s\")", path); double startTime = time_now_d(); @@ -2436,7 +2442,7 @@ static u32 sceIoDopen(const char *path) { double listTime = time_now_d() - startTime; if (listTime > 0.01) { - INFO_LOG(IO, "Dir listing '%s' took %0.3f", path, listTime); + INFO_LOG(Log::IO, "Dir listing '%s' took %0.3f", path, listTime); } // Blacklist some directories that games should not be able to find out about. @@ -2502,7 +2508,7 @@ static u32 sceIoDread(int id, u32 dirent_addr) { SceIoDirEnt *entry = (SceIoDirEnt*) Memory::GetPointer(dirent_addr); if (dir->index == (int) dir->listing.size()) { - DEBUG_LOG(SCEIO, "sceIoDread( %d %08x ) - end", id, dirent_addr); + DEBUG_LOG(Log::sceIo, "sceIoDread( %d %08x ) - end", id, dirent_addr); entry->d_name[0] = '\0'; return 0; } @@ -2542,7 +2548,7 @@ static u32 sceIoDread(int id, u32 dirent_addr) { } } } - DEBUG_LOG(SCEIO, "sceIoDread( %d %08x ) = %s", id, dirent_addr, entry->d_name); + DEBUG_LOG(Log::sceIo, "sceIoDread( %d %08x ) = %s", id, dirent_addr, entry->d_name); // TODO: Improve timing. Only happens on the *first* entry read, ms and umd. if (dir->index++ == 0) { @@ -2550,13 +2556,13 @@ static u32 sceIoDread(int id, u32 dirent_addr) { } return 1; } else { - DEBUG_LOG(SCEIO, "sceIoDread - invalid listing %i, error %08x", id, error); + DEBUG_LOG(Log::sceIo, "sceIoDread - invalid listing %i, error %08x", id, error); return SCE_KERNEL_ERROR_BADF; } } static u32 sceIoDclose(int id) { - DEBUG_LOG(SCEIO, "sceIoDclose(%d)", id); + DEBUG_LOG(Log::sceIo, "sceIoDclose(%d)", id); return kernelObjects.Destroy(id); } @@ -2564,11 +2570,11 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out u32 error; FileNode *f = __IoGetFd(id, error); if (error) { - ERROR_LOG(SCEIO, "%08x=sceIoIoctl id: %08x, cmd %08x, bad file", error, id, cmd); + ERROR_LOG(Log::sceIo, "%08x=sceIoIoctl id: %08x, cmd %08x, bad file", error, id, cmd); return error; } if (f->asyncBusy()) { - ERROR_LOG(SCEIO, "%08x=sceIoIoctl id: %08x, cmd %08x, async busy", error, id, cmd); + ERROR_LOG(Log::sceIo, "%08x=sceIoIoctl id: %08x, cmd %08x, async busy", error, id, cmd); return SCE_KERNEL_ERROR_ASYNC_BUSY; } @@ -2597,21 +2603,20 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out key_ptr = NULL; } - DEBUG_LOG(SCEIO, "Decrypting PGD DRM files"); + DEBUG_LOG(Log::sceIo, "Decrypting PGD DRM files"); pspFileSystem.SeekFile(f->handle, (s32)f->pgd_offset, FILEMOVE_BEGIN); pspFileSystem.ReadFile(f->handle, pgd_header, 0x90); f->pgdInfo = pgd_open(pgd_header, 2, key_ptr); if (!f->pgdInfo) { - ERROR_LOG(SCEIO, "Not a valid PGD file. Examining."); f->npdrm = false; pspFileSystem.SeekFile(f->handle, (s32)0, FILEMOVE_BEGIN); if (memcmp(pgd_header, pgd_magic, 4) == 0) { - ERROR_LOG(SCEIO, "File is PGD file, but there's likely a key mismatch. Returning error."); + ERROR_LOG(Log::sceIo, "%s is PGD file, but there's likely a key mismatch. Returning error.", f->fullpath.c_str()); // File is PGD file, but key mismatch return ERROR_PGD_INVALID_HEADER; } else { - WARN_LOG(SCEIO, "File is not encrypted, proceeding."); - // File is decrypted. + INFO_LOG(Log::sceIo, "%s is not an encrypted PGD file as was expected. Proceeding.", f->fullpath.c_str()); + // File is not encrypted. return 0; } } else { @@ -2640,7 +2645,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01020003: // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Asked for sector size of file %i", id); + INFO_LOG(Log::sceIo, "sceIoIoctl: Asked for sector size of file %i", id); if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { // ISOs always use 2048 sized sectors. Memory::Write_U32(2048, outdataPtr); @@ -2653,7 +2658,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01020004: // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - DEBUG_LOG(SCEIO, "sceIoIoctl: Asked for file offset of file %d", id); + DEBUG_LOG(Log::sceIo, "sceIoIoctl: Asked for file offset of file %d", id); if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { u32 offset = (u32)pspFileSystem.GetSeekPos(f->handle); Memory::Write_U32(offset, outdataPtr); @@ -2665,7 +2670,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01010005: // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Seek for file %i", id); + INFO_LOG(Log::sceIo, "sceIoIoctl: Seek for file %i", id); // Even if the size is 4, it still actually reads a 16 byte struct, it seems. if (Memory::IsValidAddress(indataPtr) && inlen >= 4) { struct SeekInfo { @@ -2690,7 +2695,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01020006: // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Asked for start sector of file %i", id); + INFO_LOG(Log::sceIo, "sceIoIoctl: Asked for start sector of file %i", id); if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { Memory::Write_U32(f->FileInfo().startSector, outdataPtr); } else { @@ -2702,7 +2707,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01020007: // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Asked for size of file %i", id); + INFO_LOG(Log::sceIo, "sceIoIoctl: Asked for size of file %i", id); if (Memory::IsValidAddress(outdataPtr) && outlen >= 8) { Memory::Write_U64(f->FileInfo().size, outdataPtr); } else { @@ -2714,7 +2719,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01030008: // TODO: Should not work for umd0:/, ms0:/, etc. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Read from file %i", id); + INFO_LOG(Log::sceIo, "sceIoIoctl: Read from file %i", id); if (Memory::IsValidAddress(indataPtr) && inlen >= 4) { u32 size = Memory::Read_U32(indataPtr); if (Memory::IsValidAddress(outdataPtr) && size <= outlen) { @@ -2733,7 +2738,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01d20001: // TODO: Should work only for umd0:/, etc. not for ms0:/ or disc0:/. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Sector tell from file %i", id); + INFO_LOG(Log::sceIo, "sceIoIoctl: Sector tell from file %i", id); if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) { Memory::Write_U32((u32)pspFileSystem.GetSeekPos(f->handle), outdataPtr); } else { @@ -2745,7 +2750,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01f30003: // TODO: Should work only for umd0:/, etc. not for ms0:/ or disc0:/. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Sector read from file %i", id); + INFO_LOG(Log::sceIo, "sceIoIoctl: Sector read from file %i", id); if (Memory::IsValidAddress(indataPtr) && inlen >= 4) { u32 size = Memory::Read_U32(indataPtr); // Note that size is specified in sectors, not bytes. @@ -2765,7 +2770,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out case 0x01f100a6: // TODO: Should work only for umd0:/, etc. not for ms0:/ or disc0:/. // TODO: Should probably move this to something common between ISOFileSystem and VirtualDiscSystem. - INFO_LOG(SCEIO, "sceIoIoctl: Sector seek for file %i", id); + INFO_LOG(Log::sceIo, "sceIoIoctl: Sector seek for file %i", id); // Even if the size is 4, it still actually reads a 16 byte struct, it seems. //if (GetIOTimingMethod() == IOTIMING_REALISTIC) // Need a check for io timing method? @@ -2799,7 +2804,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out // We want the reported message to include the cmd, so it's unique. snprintf(temp, sizeof(temp), "sceIoIoctl(%%s, %08x, %%08x, %%x, %%08x, %%x)", cmd); Reporting::ReportMessage(temp, f->fullpath.c_str(), indataPtr, inlen, outdataPtr, outlen); - ERROR_LOG(SCEIO, "UNIMPL 0=sceIoIoctl id: %08x, cmd %08x, indataPtr %08x, inlen %08x, outdataPtr %08x, outLen %08x", id,cmd,indataPtr,inlen,outdataPtr,outlen); + ERROR_LOG(Log::sceIo, "UNIMPL 0=sceIoIoctl id: %08x, cmd %08x, indataPtr %08x, inlen %08x, outdataPtr %08x, outLen %08x", id,cmd,indataPtr,inlen,outdataPtr,outlen); } return result; } @@ -2825,7 +2830,7 @@ static u32 sceIoIoctlAsync(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdat FileNode *f = __IoGetFd(id, error); if (f) { if (f->asyncBusy()) { - return hleLogWarning(SCEIO, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); + return hleLogWarning(Log::sceIo, SCE_KERNEL_ERROR_ASYNC_BUSY, "async busy"); } auto ¶ms = asyncParams[id]; @@ -2836,14 +2841,14 @@ static u32 sceIoIoctlAsync(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdat params.ioctl.outAddr = outdataPtr; params.ioctl.outSize = outlen; IoStartAsyncThread(id, f); - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } else { - return hleLogError(SCEIO, error, "bad file descriptor"); + return hleLogError(Log::sceIo, error, "bad file descriptor"); } } static u32 sceIoGetFdList(u32 outAddr, int outSize, u32 fdNumAddr) { - WARN_LOG(SCEIO, "sceIoGetFdList(%08x, %i, %08x)", outAddr, outSize, fdNumAddr); + WARN_LOG(Log::sceIo, "sceIoGetFdList(%08x, %i, %08x)", outAddr, outSize, fdNumAddr); auto out = PSPPointer::Create(outAddr); int count = 0; @@ -2878,12 +2883,12 @@ static u32 sceIoGetFdList(u32 outAddr, int outSize, u32 fdNumAddr) { // Presumably lets you hook up stderr to a MsgPipe. static u32 sceKernelRegisterStderrPipe(u32 msgPipeUID) { - ERROR_LOG_REPORT(SCEIO, "UNIMPL sceKernelRegisterStderrPipe(%08x)", msgPipeUID); + ERROR_LOG_REPORT(Log::sceIo, "UNIMPL sceKernelRegisterStderrPipe(%08x)", msgPipeUID); return 0; } static u32 sceKernelRegisterStdoutPipe(u32 msgPipeUID) { - ERROR_LOG_REPORT(SCEIO, "UNIMPL sceKernelRegisterStdoutPipe(%08x)", msgPipeUID); + ERROR_LOG_REPORT(Log::sceIo, "UNIMPL sceKernelRegisterStdoutPipe(%08x)", msgPipeUID); return 0; } @@ -2907,9 +2912,9 @@ static int IoAsyncFinish(int id) { complete = __IoRead(result, id, params.std.addr, params.std.size, us); if (complete) { f->asyncResult = (s64)result; - DEBUG_LOG(SCEIO, "ASYNC %llx=sceIoReadAsync(%d, %08x, %x)", f->asyncResult, id, params.std.addr, params.std.size); + DEBUG_LOG(Log::sceIo, "ASYNC %llx=sceIoReadAsync(%d, %08x, %x)", f->asyncResult, id, params.std.addr, params.std.size); } else { - DEBUG_LOG(SCEIO, "ASYNC sceIoReadAsync(%d, %08x, %x): deferring result", id, params.std.addr, params.std.size); + DEBUG_LOG(Log::sceIo, "ASYNC sceIoReadAsync(%d, %08x, %x): deferring result", id, params.std.addr, params.std.size); } break; @@ -2917,9 +2922,9 @@ static int IoAsyncFinish(int id) { complete = __IoWrite(result, id, params.std.addr, params.std.size, us); if (complete) { f->asyncResult = (s64)result; - DEBUG_LOG(SCEIO, "ASYNC %llx=sceIoWriteAsync(%d, %08x, %x)", f->asyncResult, id, params.std.addr, params.std.size); + DEBUG_LOG(Log::sceIo, "ASYNC %llx=sceIoWriteAsync(%d, %08x, %x)", f->asyncResult, id, params.std.addr, params.std.size); } else { - DEBUG_LOG(SCEIO, "ASYNC sceIoWriteAsync(%d, %08x, %x): deferring result", id, params.std.addr, params.std.size); + DEBUG_LOG(Log::sceIo, "ASYNC sceIoWriteAsync(%d, %08x, %x): deferring result", id, params.std.addr, params.std.size); } break; @@ -2927,13 +2932,19 @@ static int IoAsyncFinish(int id) { f->asyncResult = __IoLseek(id, params.seek.pos, params.seek.whence); // Educated guess at timing. us = 100; - DEBUG_LOG(SCEIO, "ASYNC %lli = sceIoLseekAsync(%d, %llx, %i)", f->asyncResult, id, params.seek.pos, params.seek.whence); + DEBUG_LOG(Log::sceIo, "ASYNC %lli = sceIoLseekAsync(%d, %llx, %i)", f->asyncResult, id, params.seek.pos, params.seek.whence); break; case IoAsyncOp::OPEN: { // See notes on timing in sceIoOpen. - const std::string filename = Memory::GetCharPointer(params.open.filenameAddr); + if (!Memory::IsValidNullTerminatedString(params.open.filenameAddr)) { + // Bad + ERROR_LOG(Log::sceIo, "Bad pointer to filename %08x", params.open.filenameAddr); + us = 80; + break; + } + const std::string filename = Memory::GetCharPointerUnchecked(params.open.filenameAddr); IFileSystem *sys = pspFileSystem.GetSystemFromFilename(filename); if (sys) { if (f->asyncResult == (int)SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND) { @@ -2954,17 +2965,17 @@ static int IoAsyncFinish(int id) { f->asyncResult = 0; // CLOSE shouldn't have a delay. See #12549. us = 0; - DEBUG_LOG(SCEIO, "ASYNC %lli = sceIoCloseAsync(%d)", f->asyncResult, id); + DEBUG_LOG(Log::sceIo, "ASYNC %lli = sceIoCloseAsync(%d)", f->asyncResult, id); break; case IoAsyncOp::IOCTL: us = 0; // __IoIoctl will add 100. f->asyncResult = __IoIoctl(id, params.ioctl.cmd, params.ioctl.inAddr, params.ioctl.inSize, params.ioctl.outAddr, params.ioctl.outSize, us); - DEBUG_LOG(SCEIO, "ASYNC sceIoIoctlAsync(%08x, %08x, %08x, %08x, %08x, %08x)", id, params.ioctl.cmd, params.ioctl.inAddr, params.ioctl.inSize, params.ioctl.outAddr, params.ioctl.outSize); + DEBUG_LOG(Log::sceIo, "ASYNC sceIoIoctlAsync(%08x, %08x, %08x, %08x, %08x, %08x)", id, params.ioctl.cmd, params.ioctl.inAddr, params.ioctl.inSize, params.ioctl.outAddr, params.ioctl.outSize); break; default: - ERROR_LOG_REPORT(SCEIO, "Unknown async op %d", (int)params.op); + ERROR_LOG_REPORT(Log::sceIo, "Unknown async op %d", (int)params.op); us = 0; break; } @@ -2976,7 +2987,7 @@ static int IoAsyncFinish(int id) { params.op = IoAsyncOp::NONE; return 0; } else { - return hleLogError(SCEIO, error, "bad file descriptor"); + return hleLogError(Log::sceIo, error, "bad file descriptor"); } } diff --git a/Core/HLE/sceJpeg.cpp b/Core/HLE/sceJpeg.cpp index 8b2e4272de..6b424501c4 100644 --- a/Core/HLE/sceJpeg.cpp +++ b/Core/HLE/sceJpeg.cpp @@ -104,7 +104,7 @@ static u32 convertYCbCrToABGR(int y, int cb, int cr) { static int JpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidth, uint32_t chroma, int &usec) { if ((chroma & 0x000FFFFF) != 0x00020202 && (chroma & 0x000FFFFF) != 0x00020201 && (chroma & 0x000FFFFF) != 0x00020101) - return hleLogError(ME, ERROR_JPEG_INVALID_COLORSPACE, "invalid colorspace"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_COLORSPACE, "invalid colorspace"); if (bufferWidth < 0) bufferWidth = 0; @@ -120,9 +120,9 @@ static int JpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidt uint64_t destSize = ((uint64_t)bufferWidth * (height - 1) + width) * 4; if (destSize > 0x3FFFFFFF || !Memory::IsValidRange(imageAddr, (uint32_t)destSize)) - return hleLogError(ME, ERROR_JPEG_INVALID_VALUE, "invalid dest address or size"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_VALUE, "invalid dest address or size"); if (sizeY > 0x3FFFFFFF || !Memory::IsValidRange(yCbCrAddr, sizeY + sizeCb + sizeCb)) - return hleLogError(ME, ERROR_JPEG_INVALID_VALUE, "invalid src address or size"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_VALUE, "invalid src address or size"); u32_le *imageBuffer = (u32_le *)Memory::GetPointerWriteUnchecked(imageAddr); const u8 *Y = (const u8 *)Memory::GetPointerUnchecked(yCbCrAddr); @@ -164,8 +164,8 @@ static int JpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidt NotifyMemInfo(MemBlockFlags::WRITE, imageAddr, (uint32_t)destSize, "JpegCsc"); if ((widthHeight & 0xFFFF) == 0) - return hleLogSuccessI(ME, -1); - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, -1); + return hleLogSuccessI(Log::ME, 0); } static int JpegMJpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidth, int &usec) { @@ -180,12 +180,12 @@ static int JpegMJpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int buffe int sizeCb = sizeY >> 2; if (width > 720 || height > 480) - return hleLogError(ME, ERROR_JPEG_INVALID_SIZE, "invalid size, max 720x480"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_SIZE, "invalid size, max 720x480"); if (bufferWidth > 1024) - return hleLogError(ME, ERROR_JPEG_INVALID_SIZE, "invalid stride, max 1024"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_SIZE, "invalid stride, max 1024"); uint32_t destSize = (bufferWidth * (height - 1) + width) * 4; if (!Memory::IsValidRange(imageAddr, destSize)) - return hleLogError(ME, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid dest address or size"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid dest address or size"); u32_le *imageBuffer = (u32_le *)Memory::GetPointerWriteUnchecked(imageAddr); const u8 *Y = (const u8 *)Memory::GetPointerUnchecked(yCbCrAddr); @@ -237,12 +237,12 @@ static int JpegMJpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int buffe NotifyMemInfo(MemBlockFlags::WRITE, imageAddr, destSize, "JpegMJpegCsc"); - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static int sceJpegMJpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidth) { if (mjpegInited == 0) - return hleLogError(ME, 0x80000001, "not yet inited"); + return hleLogError(Log::ME, 0x80000001, "not yet inited"); int usec = 0; int result = JpegMJpegCsc(imageAddr, yCbCrAddr, widthHeight, bufferWidth, usec); @@ -263,15 +263,15 @@ static u32 convertARGBtoABGR(u32 argb) { static int DecodeJpeg(u32 jpegAddr, int jpegSize, u32 imageAddr, int &usec) { if (!Memory::IsValidRange(jpegAddr, jpegSize)) - return hleLogError(ME, ERROR_JPEG_NO_SOI, "invalid jpeg address"); + return hleLogError(Log::ME, ERROR_JPEG_NO_SOI, "invalid jpeg address"); if (jpegSize == 0) - return hleLogError(ME, ERROR_JPEG_INVALID_DATA, "invalid jpeg data"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_DATA, "invalid jpeg data"); NotifyMemInfo(MemBlockFlags::READ, jpegAddr, jpegSize, "JpegDecodeMJpeg"); const u8 *buf = Memory::GetPointerUnchecked(jpegAddr); if (jpegSize < 2 || buf[0] != 0xFF || buf[1] != 0xD8) - return hleLogError(ME, ERROR_JPEG_NO_SOI, "no SOI found, invalid data"); + return hleLogError(Log::ME, ERROR_JPEG_NO_SOI, "no SOI found, invalid data"); int width, height, actual_components; unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(buf, jpegSize, &width, &height, &actual_components, 3); @@ -284,24 +284,24 @@ static int DecodeJpeg(u32 jpegAddr, int jpegSize, u32 imageAddr, int &usec) { } if (jpegBuf == nullptr) { - return hleLogError(ME, ERROR_JPEG_INVALID_DATA, "unable to decompress jpeg"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_DATA, "unable to decompress jpeg"); } usec += (width * height) / 14; if (!Memory::IsValidRange(imageAddr, mjpegWidth * mjpegHeight * 4)) { free(jpegBuf); - return hleLogError(ME, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid output address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid output address"); } // Note: even if you Delete, the size is still allowed. if (width > mjpegWidth || height > mjpegHeight) { free(jpegBuf); - return hleLogError(ME, ERROR_JPEG_INVALID_SIZE, "invalid output address"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_SIZE, "invalid output address"); } if (mjpegInited == 0) { // If you finish after setting the size, then call this - you get an interesting error. free(jpegBuf); - return hleLogError(ME, 0x80000001, "mjpeg not inited"); + return hleLogError(Log::ME, 0x80000001, "mjpeg not inited"); } usec += (width * height) / 110; @@ -320,14 +320,14 @@ static int DecodeJpeg(u32 jpegAddr, int jpegSize, u32 imageAddr, int &usec) { } free(jpegBuf); - return hleLogSuccessX(ME, getWidthHeight(width, height)); + return hleLogSuccessX(Log::ME, getWidthHeight(width, height)); } static int sceJpegDecodeMJpeg(u32 jpegAddr, int jpegSize, u32 imageAddr, int dhtMode) { if ((jpegAddr | jpegSize | (jpegAddr + jpegSize)) & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); if (imageAddr & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid output address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid output address"); int usec = 300; int result = DecodeJpeg(jpegAddr, jpegSize, imageAddr, usec); @@ -336,9 +336,9 @@ static int sceJpegDecodeMJpeg(u32 jpegAddr, int jpegSize, u32 imageAddr, int dht static int sceJpegDecodeMJpegSuccessively(u32 jpegAddr, int jpegSize, u32 imageAddr, int dhtMode) { if ((jpegAddr | jpegSize | (jpegAddr + jpegSize)) & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); if (imageAddr & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid output address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid output address"); int usec = 300; int result = DecodeJpeg(jpegAddr, jpegSize, imageAddr, usec); @@ -360,15 +360,15 @@ static int getYCbCrBufferSize(int w, int h) { static int JpegGetOutputInfo(u32 jpegAddr, int jpegSize, u32 colourInfoAddr) { if (!Memory::IsValidRange(jpegAddr, jpegSize)) - return hleLogError(ME, ERROR_JPEG_NO_SOI, "invalid jpeg address"); + return hleLogError(Log::ME, ERROR_JPEG_NO_SOI, "invalid jpeg address"); if (jpegSize == 0) - return hleLogError(ME, ERROR_JPEG_INVALID_DATA, "invalid jpeg data"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_DATA, "invalid jpeg data"); NotifyMemInfo(MemBlockFlags::READ, jpegAddr, jpegSize, "JpegGetOutputInfo"); const u8 *buf = Memory::GetPointerUnchecked(jpegAddr); if (jpegSize < 2 || buf[0] != 0xFF || buf[1] != 0xD8) - return hleLogError(ME, ERROR_JPEG_NO_SOI, "no SOI found, invalid data"); + return hleLogError(Log::ME, ERROR_JPEG_NO_SOI, "no SOI found, invalid data"); int width, height, actual_components; unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(buf, jpegSize, &width, &height, &actual_components, 3); @@ -381,7 +381,7 @@ static int JpegGetOutputInfo(u32 jpegAddr, int jpegSize, u32 colourInfoAddr) { } if (jpegBuf == nullptr) { - return hleLogError(ME, ERROR_JPEG_INVALID_DATA, "unable to decompress jpeg"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_DATA, "unable to decompress jpeg"); } free(jpegBuf); @@ -411,12 +411,12 @@ static int JpegGetOutputInfo(u32 jpegAddr, int jpegSize, u32 colourInfoAddr) { fclose(wfp); #endif //JPEG_DEBUG - return hleLogSuccessX(ME, getYCbCrBufferSize(width, height)); + return hleLogSuccessX(Log::ME, getYCbCrBufferSize(width, height)); } static int sceJpegGetOutputInfo(u32 jpegAddr, int jpegSize, u32 colourInfoAddr, int dhtMode) { if ((jpegAddr | jpegSize | (jpegAddr + jpegSize)) & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); int result = JpegGetOutputInfo(jpegAddr, jpegSize, colourInfoAddr); // Time taken varies a bit, this is the low end. Depends on data. @@ -489,15 +489,15 @@ static int JpegConvertRGBToYCbCr(const void *data, u8 *output, int width, int he static int JpegDecodeMJpegYCbCr(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, int yCbCrSize, int &usec) { if (!Memory::IsValidRange(jpegAddr, jpegSize)) - return hleLogError(ME, ERROR_JPEG_NO_SOI, "invalid jpeg address"); + return hleLogError(Log::ME, ERROR_JPEG_NO_SOI, "invalid jpeg address"); if (jpegSize == 0) - return hleLogError(ME, ERROR_JPEG_INVALID_DATA, "invalid jpeg data"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_DATA, "invalid jpeg data"); NotifyMemInfo(MemBlockFlags::READ, jpegAddr, jpegSize, "JpegDecodeMJpegYCbCr"); const u8 *buf = Memory::GetPointerUnchecked(jpegAddr); if (jpegSize < 2 || buf[0] != 0xFF || buf[1] != 0xD8) - return hleLogError(ME, ERROR_JPEG_NO_SOI, "no SOI found, invalid data"); + return hleLogError(Log::ME, ERROR_JPEG_NO_SOI, "no SOI found, invalid data"); int width, height, actual_components; unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(buf, jpegSize, &width, &height, &actual_components, 3); @@ -510,12 +510,12 @@ static int JpegDecodeMJpegYCbCr(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, int y } if (jpegBuf == nullptr) { - return hleLogError(ME, ERROR_JPEG_INVALID_DATA, "unable to decompress jpeg"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_DATA, "unable to decompress jpeg"); } if (yCbCrSize < getYCbCrBufferSize(width, height)) { free(jpegBuf); - return hleLogError(ME, ERROR_JPEG_OUT_OF_MEMORY, "buffer not large enough"); + return hleLogError(Log::ME, ERROR_JPEG_OUT_OF_MEMORY, "buffer not large enough"); } // Technically, it seems like the PSP doesn't support grayscale, but we might as well. @@ -525,7 +525,7 @@ static int JpegDecodeMJpegYCbCr(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, int y NotifyMemInfo(MemBlockFlags::WRITE, yCbCrAddr, getYCbCrBufferSize(width, height), "JpegDecodeMJpegYCbCr"); } else { // There's some weird behavior on the PSP where it writes data around the last passed address. - WARN_LOG_REPORT(ME, "JpegDecodeMJpegYCbCr: Invalid output address (%08x / %08x) for %dx%d", yCbCrAddr, yCbCrSize, width, height); + WARN_LOG_REPORT(Log::ME, "JpegDecodeMJpegYCbCr: Invalid output address (%08x / %08x) for %dx%d", yCbCrAddr, yCbCrSize, width, height); } } @@ -533,16 +533,16 @@ static int JpegDecodeMJpegYCbCr(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, int y // Rough estimate based on observed timing. usec += (width * height) / 14; - return hleLogSuccessX(ME, getWidthHeight(width, height)); + return hleLogSuccessX(Log::ME, getWidthHeight(width, height)); } static int sceJpegDecodeMJpegYCbCr(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, int yCbCrSize, int dhtMode) { if ((jpegAddr | jpegSize | (jpegAddr + jpegSize)) & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); if ((yCbCrAddr | yCbCrSize | (yCbCrAddr + yCbCrSize)) & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid output address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid output address"); if (!Memory::IsValidRange(jpegAddr, jpegSize)) - return hleLogError(ME, ERROR_JPEG_INVALID_VALUE, "invalid jpeg address"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_VALUE, "invalid jpeg address"); int usec = 300; int result = JpegDecodeMJpegYCbCr(jpegAddr, jpegSize, yCbCrAddr, yCbCrSize, usec); @@ -551,9 +551,9 @@ static int sceJpegDecodeMJpegYCbCr(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, in static int sceJpegDecodeMJpegYCbCrSuccessively(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, int yCbCrSize, int dhtMode) { if ((jpegAddr | jpegSize | (jpegAddr + jpegSize)) & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid jpeg address"); if ((yCbCrAddr | yCbCrSize | (yCbCrAddr + yCbCrSize)) & 0x80000000) - return hleLogError(ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid output address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_PRIV_REQUIRED, "invalid output address"); // Do as same way as sceJpegDecodeMJpegYCbCr() but with smaller block size int usec = 300; @@ -562,63 +562,63 @@ static int sceJpegDecodeMJpegYCbCrSuccessively(u32 jpegAddr, int jpegSize, u32 y } static int sceJpeg_9B36444C() { - ERROR_LOG_REPORT(ME, "UNIMPL sceJpeg_9B36444C()"); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceJpeg_9B36444C()"); return 0; } static int sceJpegCreateMJpeg(int width, int height) { if (mjpegInited == 0) - return hleLogError(ME, ERROR_JPEG_INVALID_STATE, "not yet inited"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_STATE, "not yet inited"); if (mjpegInited == 2) - return hleLogError(ME, ERROR_JPEG_INVALID_STATE, "already created"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_STATE, "already created"); if (width > 1024) - return hleLogError(ME, ERROR_JPEG_INVALID_SIZE, "width outside bounds"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_SIZE, "width outside bounds"); mjpegInited = 2; mjpegWidth = width; mjpegHeight = height; - return hleLogSuccessInfoI(ME, 0); + return hleLogSuccessInfoI(Log::ME, 0); } static int sceJpegDeleteMJpeg() { if (mjpegInited == 0) - return hleLogError(ME, ERROR_JPEG_INVALID_STATE, "not yet inited"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_STATE, "not yet inited"); if (mjpegInited == 1) - return hleLogError(ME, ERROR_JPEG_INVALID_STATE, "not yet created"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_STATE, "not yet created"); mjpegInited = 1; - return hleLogSuccessInfoI(ME, 0); + return hleLogSuccessInfoI(Log::ME, 0); } static int sceJpegInitMJpeg() { if (mjpegInited == 1 || mjpegInited == 2) - return hleLogError(ME, ERROR_JPEG_ALREADY_INIT, "already inited"); + return hleLogError(Log::ME, ERROR_JPEG_ALREADY_INIT, "already inited"); // If it was -1, it's from an old save state, avoid double init error but assume inited. if (mjpegInited == 0) mjpegInited = 1; - return hleLogSuccessI(ME, hleDelayResult(0, "mjpeg init", 130)); + return hleLogSuccessI(Log::ME, hleDelayResult(0, "mjpeg init", 130)); } static int sceJpegFinishMJpeg() { if (mjpegInited == 0) - return hleLogError(ME, ERROR_JPEG_INVALID_STATE, "already inited"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_STATE, "already inited"); if (mjpegInited == 2) - return hleLogError(ME, ERROR_JPEG_INVALID_STATE, "mjpeg not deleted"); + return hleLogError(Log::ME, ERROR_JPEG_INVALID_STATE, "mjpeg not deleted"); // Even from an old save state, if we see this we leave compat mode. mjpegInited = 0; - return hleLogSuccessI(ME, hleDelayResult(0, "mjpeg finish", 120)); + return hleLogSuccessI(Log::ME, hleDelayResult(0, "mjpeg finish", 120)); } static int sceJpegMJpegCscWithColorOption() { - ERROR_LOG_REPORT(ME, "UNIMPL sceJpegMJpegCscWithColorOption()"); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceJpegMJpegCscWithColorOption()"); return 0; } static int sceJpegDecompressAllImage() { - ERROR_LOG_REPORT(ME, "UNIMPL sceJpegDecompressAllImage()"); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceJpegDecompressAllImage()"); return 0; } diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 73aea78a7d..4f90bc94ba 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -16,7 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/Serialize/SerializeFuncs.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Common/System/OSD.h" #include "Core/Core.h" @@ -100,15 +100,17 @@ static bool kernelRunning = false; KernelObjectPool kernelObjects; KernelStats kernelStats; u32 registeredExitCbId; +u32 g_GPOBits; // Really just 8 bits on the real hardware. +u32 g_GPIBits; // Really just 8 bits on the real hardware. void __KernelInit() { if (kernelRunning) { - ERROR_LOG(SCEKERNEL, "Can't init kernel when kernel is running"); + ERROR_LOG(Log::sceKernel, "Can't init kernel when kernel is running"); return; } - INFO_LOG(SCEKERNEL, "Initializing kernel..."); + INFO_LOG(Log::sceKernel, "Initializing kernel..."); __KernelTimeInit(); __InterruptsInit(); @@ -124,6 +126,7 @@ void __KernelInit() __IoInit(); __JpegInit(); __AudioInit(); + __Mp3Init(); __SasInit(); __AtracInit(); __CccInit(); @@ -160,18 +163,19 @@ void __KernelInit() __PPGeInit(); kernelRunning = true; - INFO_LOG(SCEKERNEL, "Kernel initialized."); + g_GPOBits = 0; + INFO_LOG(Log::sceKernel, "Kernel initialized."); } void __KernelShutdown() { if (!kernelRunning) { - ERROR_LOG(SCEKERNEL, "Can't shut down kernel - not running"); + ERROR_LOG(Log::sceKernel, "Can't shut down kernel - not running"); return; } kernelObjects.List(); - INFO_LOG(SCEKERNEL, "Shutting down kernel - %i kernel objects alive", kernelObjects.GetCount()); + INFO_LOG(Log::sceKernel, "Shutting down kernel - %i kernel objects alive", kernelObjects.GetCount()); hleCurrentThreadName = NULL; kernelObjects.Clear(); @@ -314,16 +318,16 @@ std::string __KernelStateSummary() { void sceKernelExitGame() { - INFO_LOG(SCEKERNEL, "sceKernelExitGame"); + INFO_LOG(Log::sceKernel, "sceKernelExitGame"); __KernelSwitchOffThread("game exited"); Core_Stop(); - g_OSD.Show(OSDType::MESSAGE_INFO, "sceKernelExitGame()"); + g_OSD.Show(OSDType::MESSAGE_INFO, "sceKernelExitGame()", 0.0f, "kernelexit"); } void sceKernelExitGameWithStatus() { - INFO_LOG(SCEKERNEL, "sceKernelExitGameWithStatus"); + INFO_LOG(Log::sceKernel, "sceKernelExitGameWithStatus"); __KernelSwitchOffThread("game exited"); Core_Stop(); @@ -338,34 +342,35 @@ u32 sceKernelDevkitVersion() int revision = firmwareVersion % 10; int devkitVersion = (major << 24) | (minor << 16) | (revision << 8) | 0x10; - DEBUG_LOG(SCEKERNEL, "%08x=sceKernelDevkitVersion()", devkitVersion); + DEBUG_LOG(Log::sceKernel, "%08x=sceKernelDevkitVersion()", devkitVersion); return devkitVersion; } u32 sceKernelRegisterKprintfHandler() { - ERROR_LOG(SCEKERNEL, "UNIMPL sceKernelRegisterKprintfHandler()"); + ERROR_LOG(Log::sceKernel, "UNIMPL sceKernelRegisterKprintfHandler()"); return 0; } int sceKernelRegisterDefaultExceptionHandler() { - ERROR_LOG(SCEKERNEL, "UNIMPL sceKernelRegisterDefaultExceptionHandler()"); + ERROR_LOG(Log::sceKernel, "UNIMPL sceKernelRegisterDefaultExceptionHandler()"); return 0; } -void sceKernelSetGPO(u32 ledAddr) +void sceKernelSetGPO(u32 ledBits) { - // Sets debug LEDs. - // Not really interesting, and a few games really spam it - // DEBUG_LOG(SCEKERNEL, "sceKernelSetGPO(%02x)", ledAddr); + // Sets debug LEDs. Some games do interesting stuff with this, like a metronome in Parappa. + // Shows up as a vertical strip of LEDs at the side of the screen, if enabled. + g_GPOBits = ledBits; } u32 sceKernelGetGPI() { // Always returns 0 on production systems. - DEBUG_LOG(SCEKERNEL, "0=sceKernelGetGPI()"); - return 0; + // On developer systems, there are 8 switches that control the lower 8 bits of the return value. + DEBUG_LOG(Log::sceKernel, "%d=sceKernelGetGPI()", g_GPIBits); + return g_GPIBits; } // #define LOG_CACHE @@ -377,7 +382,7 @@ u32 sceKernelGetGPI() int sceKernelDcacheInvalidateRange(u32 addr, int size) { #ifdef LOG_CACHE - NOTICE_LOG(CPU,"sceKernelDcacheInvalidateRange(%08x, %i)", addr, size); + NOTICE_LOG(Log::CPU,"sceKernelDcacheInvalidateRange(%08x, %i)", addr, size); #endif if (size < 0 || (int) addr + size < 0) return SCE_KERNEL_ERROR_ILLEGAL_ADDR; @@ -395,7 +400,7 @@ int sceKernelDcacheInvalidateRange(u32 addr, int size) } int sceKernelIcacheInvalidateRange(u32 addr, int size) { - DEBUG_LOG(CPU, "sceKernelIcacheInvalidateRange(%08x, %i)", addr, size); + DEBUG_LOG(Log::CPU, "sceKernelIcacheInvalidateRange(%08x, %i)", addr, size); if (size != 0) currentMIPS->InvalidateICache(addr, size); return 0; @@ -404,7 +409,7 @@ int sceKernelIcacheInvalidateRange(u32 addr, int size) { int sceKernelDcacheWritebackAll() { #ifdef LOG_CACHE - NOTICE_LOG(CPU,"sceKernelDcacheWritebackAll()"); + NOTICE_LOG(Log::CPU,"sceKernelDcacheWritebackAll()"); #endif // Some games seem to use this a lot, it doesn't make sense // to zap the whole texture cache. @@ -417,7 +422,7 @@ int sceKernelDcacheWritebackAll() int sceKernelDcacheWritebackRange(u32 addr, int size) { #ifdef LOG_CACHE - NOTICE_LOG(CPU,"sceKernelDcacheWritebackRange(%08x, %i)", addr, size); + NOTICE_LOG(Log::CPU,"sceKernelDcacheWritebackRange(%08x, %i)", addr, size); #endif if (size < 0) return SCE_KERNEL_ERROR_INVALID_SIZE; @@ -432,7 +437,7 @@ int sceKernelDcacheWritebackRange(u32 addr, int size) int sceKernelDcacheWritebackInvalidateRange(u32 addr, int size) { #ifdef LOG_CACHE - NOTICE_LOG(CPU,"sceKernelDcacheInvalidateRange(%08x, %i)", addr, size); + NOTICE_LOG(Log::CPU,"sceKernelDcacheInvalidateRange(%08x, %i)", addr, size); #endif if (size < 0) return SCE_KERNEL_ERROR_INVALID_SIZE; @@ -447,7 +452,7 @@ int sceKernelDcacheWritebackInvalidateRange(u32 addr, int size) int sceKernelDcacheWritebackInvalidateAll() { #ifdef LOG_CACHE - NOTICE_LOG(CPU,"sceKernelDcacheInvalidateAll()"); + NOTICE_LOG(Log::CPU,"sceKernelDcacheInvalidateAll()"); #endif gpu->InvalidateCache(0, -1, GPU_INVALIDATE_ALL); hleEatCycles(1165); @@ -458,7 +463,7 @@ int sceKernelDcacheWritebackInvalidateAll() u32 sceKernelIcacheInvalidateAll() { #ifdef LOG_CACHE - NOTICE_LOG(CPU, "Icache invalidated - should clear JIT someday"); + NOTICE_LOG(Log::CPU, "Icache invalidated - should clear JIT someday"); #endif // Note that this doesn't actually fully invalidate all with such a large range. currentMIPS->InvalidateICache(0, 0x3FFFFFFF); @@ -468,9 +473,9 @@ u32 sceKernelIcacheInvalidateAll() u32 sceKernelIcacheClearAll() { #ifdef LOG_CACHE - NOTICE_LOG(CPU, "Icache cleared - should clear JIT someday"); + NOTICE_LOG(Log::CPU, "Icache cleared - should clear JIT someday"); #endif - DEBUG_LOG(CPU, "Icache cleared - should clear JIT someday"); + DEBUG_LOG(Log::CPU, "Icache cleared - should clear JIT someday"); // Note that this doesn't actually fully invalidate all with such a large range. currentMIPS->InvalidateICache(0, 0x3FFFFFFF); return 0; @@ -501,7 +506,7 @@ SceUID KernelObjectPool::Create(KernelObject *obj, int rangeBottom, int rangeTop } } - ERROR_LOG_REPORT(SCEKERNEL, "Unable to allocate kernel object, too many objects slots in use."); + ERROR_LOG_REPORT(Log::sceKernel, "Unable to allocate kernel object, too many objects slots in use."); return 0; } @@ -530,9 +535,9 @@ void KernelObjectPool::List() { char buffer[256]; if (pool[i]) { pool[i]->GetQuickInfo(buffer, sizeof(buffer)); - DEBUG_LOG(SCEKERNEL, "KO %i: %s \"%s\": %s", i + handleOffset, pool[i]->GetTypeName(), pool[i]->GetName(), buffer); + DEBUG_LOG(Log::sceKernel, "KO %i: %s \"%s\": %s", i + handleOffset, pool[i]->GetTypeName(), pool[i]->GetName(), buffer); } else { - ERROR_LOG(SCEKERNEL, "KO %i: bad object", i + handleOffset); + ERROR_LOG(Log::sceKernel, "KO %i: bad object", i + handleOffset); } } } @@ -557,7 +562,7 @@ void KernelObjectPool::DoState(PointerWrap &p) { if (_maxCount != maxCount) { p.SetError(p.ERROR_FAILURE); - ERROR_LOG(SCEKERNEL, "Unable to load state: different kernel object storage."); + ERROR_LOG(Log::sceKernel, "Unable to load state: different kernel object storage."); return; } @@ -634,7 +639,7 @@ KernelObject *KernelObjectPool::CreateByIDType(int type) { return __KernelThreadEventHandlerObject(); default: - ERROR_LOG(SAVESTATE, "Unable to load state: could not find object type %d.", type); + ERROR_LOG(Log::SaveState, "Unable to load state: could not find object type %d.", type); return NULL; } } @@ -650,7 +655,7 @@ struct SystemStatus { }; static int sceKernelReferSystemStatus(u32 statusPtr) { - DEBUG_LOG(SCEKERNEL, "sceKernelReferSystemStatus(%08x)", statusPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelReferSystemStatus(%08x)", statusPtr); auto status = PSPPointer::Create(statusPtr); if (status.IsValid()) { memset((SystemStatus *)status, 0, sizeof(SystemStatus)); @@ -689,13 +694,13 @@ static u32 sceKernelReferThreadProfiler() { // This seems to simply has no parameter: // https://pspdev.github.io/pspsdk/group__ThreadMan.html#ga8fd30da51b9dc0507ac4dae04a7e4a17 // In testing it just returns null in around 140-150 cycles. See issue #17623. - DEBUG_LOG(SCEKERNEL, "0=sceKernelReferThreadProfiler()"); + DEBUG_LOG(Log::sceKernel, "0=sceKernelReferThreadProfiler()"); hleEatCycles(140); return 0; } static int sceKernelReferGlobalProfiler() { - DEBUG_LOG(SCEKERNEL, "0=sceKernelReferGlobalProfiler()"); + DEBUG_LOG(Log::sceKernel, "0=sceKernelReferGlobalProfiler()"); // See sceKernelReferThreadProfiler(), similar. hleEatCycles(140); return 0; diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index 722f89d37d..6094781909 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -459,7 +459,7 @@ public: if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset]) { // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP if (handle != 0 && (u32)handle != 0x80020001) { - WARN_LOG(SCEKERNEL, "Kernel: Bad %s handle %d (%08x)", T::GetStaticTypeName(), handle, handle); + WARN_LOG(Log::sceKernel, "Kernel: Bad %s handle %d (%08x)", T::GetStaticTypeName(), handle, handle); } outError = T::GetMissingErrorCode(); return 0; @@ -469,7 +469,7 @@ public: // see the Wrong type object error below, but we'll just have to live with that danger. T* t = static_cast(pool[handle - handleOffset]); if (t == nullptr || t->GetIDType() != T::GetStaticIDType()) { - WARN_LOG(SCEKERNEL, "Kernel: Wrong object type for %d (%08x), was %s, should have been %s", handle, handle, t ? t->GetTypeName() : "null", T::GetStaticTypeName()); + WARN_LOG(Log::sceKernel, "Kernel: Wrong object type for %d (%08x), was %s, should have been %s", handle, handle, t ? t->GetTypeName() : "null", T::GetStaticTypeName()); outError = T::GetMissingErrorCode(); return 0; } @@ -518,7 +518,7 @@ public: bool GetIDType(SceUID handle, int *type) const { if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset]) { - ERROR_LOG(SCEKERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); + ERROR_LOG(Log::sceKernel, "Kernel: Bad object handle %i (%08x)", handle, handle); return false; } KernelObject *t = pool[handle - handleOffset]; @@ -569,6 +569,9 @@ struct KernelStats { extern KernelStats kernelStats; extern u32 registeredExitCbId; +extern u32 g_GPOBits; +extern u32 g_GPIBits; + void Register_ThreadManForUser(); void Register_ThreadManForKernel(); void Register_LoadExecForUser(); diff --git a/Core/HLE/sceKernelAlarm.cpp b/Core/HLE/sceKernelAlarm.cpp index d6b12703df..edfe19b223 100644 --- a/Core/HLE/sceKernelAlarm.cpp +++ b/Core/HLE/sceKernelAlarm.cpp @@ -73,13 +73,13 @@ public: PSPAlarm *alarm = kernelObjects.Get(alarmID, error); if (error) { - WARN_LOG(SCEKERNEL, "Ignoring deleted alarm %08x", alarmID); + WARN_LOG(Log::sceKernel, "Ignoring deleted alarm %08x", alarmID); return false; } currentMIPS->pc = alarm->alm.handlerPtr; currentMIPS->r[MIPS_REG_A0] = alarm->alm.commonPtr; - DEBUG_LOG(SCEKERNEL, "Entering alarm %08x handler: %08x", alarmID, currentMIPS->pc); + DEBUG_LOG(Log::sceKernel, "Entering alarm %08x handler: %08x", alarmID, currentMIPS->pc); return true; } @@ -94,7 +94,7 @@ public: // A non-zero result means to reschedule. if (result > 0) { - DEBUG_LOG(SCEKERNEL, "Rescheduling alarm %08x for +%dms", alarmID, result); + DEBUG_LOG(Log::sceKernel, "Rescheduling alarm %08x for +%dms", alarmID, result); u32 error; PSPAlarm *alarm = kernelObjects.Get(alarmID, error); __KernelScheduleAlarm(alarm, result); @@ -102,9 +102,9 @@ public: else { if (result < 0) - WARN_LOG(SCEKERNEL, "Alarm requested reschedule for negative value %u, ignoring", (unsigned) result); + WARN_LOG(Log::sceKernel, "Alarm requested reschedule for negative value %u, ignoring", (unsigned) result); - DEBUG_LOG(SCEKERNEL, "Finished alarm %08x", alarmID); + DEBUG_LOG(Log::sceKernel, "Finished alarm %08x", alarmID); // Delete the alarm if it's not rescheduled. kernelObjects.Destroy(alarmID); @@ -171,7 +171,7 @@ static SceUID __KernelSetAlarm(u64 micro, u32 handlerPtr, u32 commonPtr) SceUID sceKernelSetAlarm(SceUInt micro, u32 handlerPtr, u32 commonPtr) { - DEBUG_LOG(SCEKERNEL, "sceKernelSetAlarm(%d, %08x, %08x)", micro, handlerPtr, commonPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelSetAlarm(%d, %08x, %08x)", micro, handlerPtr, commonPtr); return __KernelSetAlarm((u64) micro, handlerPtr, commonPtr); } @@ -184,13 +184,13 @@ SceUID sceKernelSetSysClockAlarm(u32 microPtr, u32 handlerPtr, u32 commonPtr) else return -1; - DEBUG_LOG(SCEKERNEL, "sceKernelSetSysClockAlarm(%lld, %08x, %08x)", micro, handlerPtr, commonPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelSetSysClockAlarm(%lld, %08x, %08x)", micro, handlerPtr, commonPtr); return __KernelSetAlarm(micro, handlerPtr, commonPtr); } int sceKernelCancelAlarm(SceUID uid) { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelAlarm(%08x)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelAlarm(%08x)", uid); CoreTiming::UnscheduleEvent(alarmTimer, uid); @@ -203,11 +203,11 @@ int sceKernelReferAlarmStatus(SceUID uid, u32 infoPtr) PSPAlarm *alarm = kernelObjects.Get(uid, error); if (!alarm) { - ERROR_LOG(SCEKERNEL, "sceKernelReferAlarmStatus(%08x, %08x): invalid alarm", uid, infoPtr); + ERROR_LOG(Log::sceKernel, "sceKernelReferAlarmStatus(%08x, %08x): invalid alarm", uid, infoPtr); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelReferAlarmStatus(%08x, %08x)", uid, infoPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelReferAlarmStatus(%08x, %08x)", uid, infoPtr); if (!Memory::IsValidAddress(infoPtr)) return -1; diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index b903f950d3..101b592cf4 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -195,28 +195,28 @@ static bool __KernelClearEventFlagThreads(EventFlag *e, int reason) { void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, eventFlagWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB: Suspending lock wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelWaitEventFlagCB: Suspending lock wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelWaitEventFlagCB: wait not found to pause for callback"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelWaitEventFlagCB: wait not found to pause for callback"); else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelWaitEventFlagCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelWaitEventFlagCB: beginning callback with bad wait id?"); } void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, eventFlagWaitTimer, __KernelUnlockEventFlagForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) - DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB: Resuming lock wait from callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelWaitEventFlagCB: Resuming lock wait from callback"); } //SceUID sceKernelCreateEventFlag(const char *name, int attr, int bits, SceKernelEventFlagOptParam *opt); int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr) { if (!name) { - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name"); } // These attributes aren't valid. if ((flag_attr & 0x100) != 0 || flag_attr >= 0x300) { - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", flag_attr); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", flag_attr); } EventFlag *e = new EventFlag(); @@ -233,12 +233,12 @@ int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPatte if (optPtr != 0) { u32 size = Memory::Read_U32(optPtr); if (size > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateEventFlag(%s) unsupported options parameter, size = %d", name, size); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateEventFlag(%s) unsupported options parameter, size = %d", name, size); } if ((flag_attr & ~PSP_EVENT_WAITMULTIPLE) != 0) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateEventFlag(%s) unsupported attr parameter: %08x", name, flag_attr); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateEventFlag(%s) unsupported attr parameter: %08x", name, flag_attr); - return hleLogSuccessI(SCEKERNEL, id); + return hleLogSuccessI(Log::sceKernel, id); } u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr) { @@ -255,9 +255,9 @@ u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr) { hleReSchedule("event flag canceled"); hleEatCycles(580); - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogDebug(SCEKERNEL, error, "invalid event flag"); + return hleLogDebug(Log::sceKernel, error, "invalid event flag"); } } @@ -268,9 +268,9 @@ u32 sceKernelClearEventFlag(SceUID id, u32 bits) { e->nef.currentPattern &= bits; // Note that it's not possible for threads to get woken up by this action. hleEatCycles(430); - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogDebug(SCEKERNEL, error, "invalid event flag"); + return hleLogDebug(Log::sceKernel, error, "invalid event flag"); } } @@ -282,9 +282,9 @@ u32 sceKernelDeleteEventFlag(SceUID uid) { if (wokeThreads) hleReSchedule("event flag deleted"); - return hleLogSuccessI(SCEKERNEL, kernelObjects.Destroy(uid)); + return hleLogSuccessI(Log::sceKernel, kernelObjects.Destroy(uid)); } else { - return hleLogDebug(SCEKERNEL, error, "invalid event flag"); + return hleLogDebug(Log::sceKernel, error, "invalid event flag"); } } @@ -309,9 +309,9 @@ u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet) { hleReSchedule("event flag set"); hleEatCycles(430); - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogDebug(SCEKERNEL, error, "invalid event flag"); + return hleLogDebug(Log::sceKernel, error, "invalid event flag"); } } @@ -361,15 +361,15 @@ static void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr) { int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) { if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); } // Can't wait on 0, that's guaranteed to wait forever. if (bits == 0) { - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern"); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern"); } if (!__KernelIsDispatchEnabled()) { - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } u32 error; @@ -387,10 +387,10 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti // Do we allow more than one thread to wait? if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) { - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_MULTI); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_EVF_MULTI); } - (void)hleLogSuccessI(SCEKERNEL, 0, "waiting"); + (void)hleLogSuccessI(Log::sceKernel, 0, "waiting"); // No match - must wait. th.threadID = __KernelGetCurThread(); @@ -403,27 +403,27 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti __KernelSetEventFlagTimeout(e, timeoutPtr); __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false, "event flag waited"); } else { - (void)hleLogSuccessI(SCEKERNEL, 0); + (void)hleLogSuccessI(Log::sceKernel, 0); } hleEatCycles(500); return 0; } else { - return hleLogDebug(SCEKERNEL, error, "invalid event flag"); + return hleLogDebug(Log::sceKernel, error, "invalid event flag"); } } int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) { if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); } // Can't wait on 0, that's guaranteed to wait forever. if (bits == 0) { - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern"); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern"); } if (!__KernelIsDispatchEnabled()) { - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } u32 error; @@ -450,10 +450,10 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 // Do we allow more than one thread to wait? if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) { - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_MULTI); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_EVF_MULTI); } - (void)hleLogSuccessI(SCEKERNEL, 0, "waiting"); + (void)hleLogSuccessI(Log::sceKernel, 0, "waiting"); // No match - must wait. th.threadID = __KernelGetCurThread(); @@ -469,7 +469,7 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 else __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true, "event flag waited"); } else { - (void)hleLogSuccessI(SCEKERNEL, 0); + (void)hleLogSuccessI(Log::sceKernel, 0); __KernelApplyEventFlagMatch(&e->nef.currentPattern, bits, wait, outBitsPtr); hleCheckCurrentCallbacks(); } @@ -477,21 +477,21 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 hleEatCycles(500); return 0; } else { - return hleLogDebug(SCEKERNEL, error, "invalid event flag"); + return hleLogDebug(Log::sceKernel, error, "invalid event flag"); } } int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr) { if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); } // Poll seems to also fail when CLEAR and CLEARALL are used together, but not wait. if ((wait & PSP_EVENT_WAITCLEAR) != 0 && (wait & PSP_EVENT_WAITCLEARALL) != 0) { - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait); } // Can't wait on 0, it never matches. if (bits == 0) { - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern"); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern"); } hleEatCycles(360); @@ -504,16 +504,16 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr) { Memory::Write_U32(e->nef.currentPattern, outBitsPtr); if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) { - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_MULTI); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_EVF_MULTI); } // No match - return that, this is polling, not waiting. - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_COND); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_EVF_COND); } else { - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } } else { - return hleLogDebug(SCEKERNEL, error, "invalid event flag"); + return hleLogDebug(Log::sceKernel, error, "invalid event flag"); } } @@ -524,7 +524,7 @@ u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr) { if (e) { auto status = PSPPointer::Create(statusPtr); if (!status.IsValid()) - return hleLogWarning(SCEKERNEL, -1, "invalid ptr"); + return hleLogWarning(Log::sceKernel, -1, "invalid ptr"); HLEKernel::CleanupWaitingThreads(WAITTYPE_EVENTFLAG, id, e->waitingThreads); @@ -533,8 +533,8 @@ u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr) { *status = e->nef; status.NotifyWrite("EventFlagStatus"); } - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogDebug(SCEKERNEL, error, "invalid event flag"); + return hleLogDebug(Log::sceKernel, error, "invalid event flag"); } } diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index 1663c81eec..a781a2ec0b 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -50,13 +50,13 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char BlockAllocator *allocator = BlockAllocatorFromAddr(partitionId); // TODO: Validate error code. if (!allocator) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); // TODO: This should probably actually use flags? Name? u32 addr = allocator->Alloc(allocSize, g_fromBottom, StringFromFormat("KernelHeap/%s", Name).c_str()); if (addr == (u32)-1) { // TODO: Validate error code. - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "fFailed to allocate %d bytes of memory", size); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "fFailed to allocate %d bytes of memory", size); } KernelHeap *heap = new KernelHeap(); @@ -69,54 +69,54 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char heap->address = addr; heap->alloc.Init(heap->address + 128, heap->size - 128, true); heap->uid = uid; - return hleLogSuccessInfoX(SCEKERNEL, uid); + return hleLogSuccessInfoX(Log::sceKernel, uid); } static int sceKernelAllocHeapMemory(int heapId, int size) { u32 error; KernelHeap *heap = kernelObjects.Get(heapId, error); if (!heap) - return hleLogError(SCEKERNEL, error, "sceKernelAllocHeapMemory(%d): invalid heapId", heapId); + return hleLogError(Log::sceKernel, error, "sceKernelAllocHeapMemory(%d): invalid heapId", heapId); // There's 8 bytes at the end of every block, reserved. u32 memSize = KERNEL_HEAP_BLOCK_HEADER_SIZE + size; u32 addr = heap->alloc.Alloc(memSize, true); - return hleLogSuccessInfoX(SCEKERNEL, addr); + return hleLogSuccessInfoX(Log::sceKernel, addr); } static int sceKernelDeleteHeap(int heapId) { u32 error; KernelHeap *heap = kernelObjects.Get(heapId, error); if (!heap) - return hleLogError(SCEKERNEL, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId); + return hleLogError(Log::sceKernel, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId); // Not using heap->partitionId here for backwards compatibility with old save states. BlockAllocator *allocator = BlockAllocatorFromAddr(heap->address); if (allocator) allocator->Free(heap->address); kernelObjects.Destroy(heap->uid); - return hleLogSuccessInfoX(SCEKERNEL, 0); + return hleLogSuccessInfoX(Log::sceKernel, 0); } static u32 sceKernelPartitionTotalFreeMemSize(int partitionId) { BlockAllocator *allocator = BlockAllocatorFromID(partitionId); // TODO: Validate error code. if (!allocator) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); - return hleLogWarning(SCEKERNEL, allocator->GetTotalFreeBytes()); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + return hleLogWarning(Log::sceKernel, allocator->GetTotalFreeBytes()); } static u32 sceKernelPartitionMaxFreeMemSize(int partitionId) { BlockAllocator *allocator = BlockAllocatorFromID(partitionId); // TODO: Validate error code. if (!allocator) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); - return hleLogWarning(SCEKERNEL, allocator->GetLargestFreeBlockSize()); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition"); + return hleLogWarning(Log::sceKernel, allocator->GetLargestFreeBlockSize()); } static u32 sceKernelGetUidmanCB() { - ERROR_LOG_REPORT(SCEKERNEL, "UNIMP sceKernelGetUidmanCB"); + ERROR_LOG_REPORT(Log::sceKernel, "UNIMP sceKernelGetUidmanCB"); return 0; } @@ -124,14 +124,14 @@ static int sceKernelFreeHeapMemory(int heapId, u32 block) { u32 error; KernelHeap* heap = kernelObjects.Get(heapId, error); if (!heap) - return hleLogError(SCEKERNEL, error, "sceKernelFreeHeapMemory(%d): invalid heapId", heapId); + return hleLogError(Log::sceKernel, error, "sceKernelFreeHeapMemory(%d): invalid heapId", heapId); if (block == 0) { - return hleLogSuccessInfoI(SCEKERNEL, 0, "sceKernelFreeHeapMemory(%d): heapId,0: block", heapId); + return hleLogSuccessInfoI(Log::sceKernel, 0, "sceKernelFreeHeapMemory(%d): heapId,0: block", heapId); } if (!heap->alloc.FreeExact(block)) { - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid pointer %08x", block); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid pointer %08x", block); } - return hleLogSuccessInfoI(SCEKERNEL, 0, "sceKernelFreeHeapMemory(%d): heapId, block", heapId, block); + return hleLogSuccessInfoI(Log::sceKernel, 0, "sceKernelFreeHeapMemory(%d): heapId, block", heapId, block); } @@ -139,18 +139,18 @@ static int sceKernelAllocHeapMemoryWithOption(int heapId, u32 memSize, u32 param u32 error; KernelHeap* heap = kernelObjects.Get(heapId, error); if (!heap) - return hleLogError(SCEKERNEL, error, "sceKernelFreeHeapMemory(%d): invalid heapId", heapId); + return hleLogError(Log::sceKernel, error, "sceKernelFreeHeapMemory(%d): invalid heapId", heapId); u32 grain = 4; // 0 is ignored. if (paramsPtr != 0) { u32 size = Memory::Read_U32(paramsPtr); if (size < 8) - return hleLogError(SCEKERNEL, 0, "invalid param size"); + return hleLogError(Log::sceKernel, 0, "invalid param size"); if (size > 8) - WARN_LOG(HLE, "sceKernelAllocHeapMemoryWithOption(): unexpected param size %d", size); + WARN_LOG(Log::HLE, "sceKernelAllocHeapMemoryWithOption(): unexpected param size %d", size); grain = Memory::Read_U32(paramsPtr + 4); } - INFO_LOG(HLE, "sceKernelAllocHeapMemoryWithOption(%08x, %08x, %08x)", heapId, memSize, paramsPtr); + INFO_LOG(Log::HLE, "sceKernelAllocHeapMemoryWithOption(%08x, %08x, %08x)", heapId, memSize, paramsPtr); // There's 8 bytes at the end of every block, reserved. memSize += 8; u32 addr = heap->alloc.AllocAligned(memSize, grain, grain, true); diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 76e1788e39..5794150250 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -79,7 +79,7 @@ static SceUID threadBeforeInterrupt; static int sceKernelCpuSuspendIntr() { - VERBOSE_LOG(SCEINTC, "sceKernelCpuSuspendIntr"); + VERBOSE_LOG(Log::sceIntc, "sceKernelCpuSuspendIntr"); int returnValue; if (__InterruptsEnabled()) { @@ -96,7 +96,7 @@ static int sceKernelCpuSuspendIntr() static void sceKernelCpuResumeIntr(u32 enable) { - VERBOSE_LOG(SCEINTC, "sceKernelCpuResumeIntr(%i)", enable); + VERBOSE_LOG(Log::sceIntc, "sceKernelCpuResumeIntr(%i)", enable); if (enable) { __EnableInterrupts(); @@ -113,14 +113,14 @@ static void sceKernelCpuResumeIntr(u32 enable) static int sceKernelIsCpuIntrEnable() { u32 retVal = __InterruptsEnabled(); - DEBUG_LOG(SCEINTC, "%i=sceKernelIsCpuIntrEnable()", retVal); + DEBUG_LOG(Log::sceIntc, "%i=sceKernelIsCpuIntrEnable()", retVal); return retVal; } static int sceKernelIsCpuIntrSuspended(int flag) { int retVal = flag == 0 ? 1 : 0; - DEBUG_LOG(SCEINTC, "%i=sceKernelIsCpuIntrSuspended(%d)", retVal, flag); + DEBUG_LOG(Log::sceIntc, "%i=sceKernelIsCpuIntrSuspended(%d)", retVal, flag); return retVal; } @@ -134,7 +134,7 @@ bool IntrHandler::run(PendingInterrupt& pend) SubIntrHandler *handler = get(pend.subintr); if (handler == NULL) { - WARN_LOG(SCEINTC, "Ignoring interrupt, already been released."); + WARN_LOG(Log::sceIntc, "Ignoring interrupt, already been released."); return false; } @@ -146,7 +146,7 @@ bool IntrHandler::run(PendingInterrupt& pend) void IntrHandler::copyArgsToCPU(PendingInterrupt& pend) { SubIntrHandler* handler = get(pend.subintr); - DEBUG_LOG(CPU, "Entering interrupt handler %08x", handler->handlerAddress); + DEBUG_LOG(Log::CPU, "Entering interrupt handler %08x", handler->handlerAddress); currentMIPS->pc = handler->handlerAddress; currentMIPS->r[MIPS_REG_A0] = handler->subIntrNumber; currentMIPS->r[MIPS_REG_A1] = handler->handlerArg; @@ -248,7 +248,7 @@ void __InterruptsDoState(PointerWrap &p) if (numInterrupts != PSP_NUMBER_INTERRUPTS) { p.SetError(p.ERROR_FAILURE); - ERROR_LOG(SCEINTC, "Savestate failure: wrong number of interrupts, can't load."); + ERROR_LOG(Log::sceIntc, "Savestate failure: wrong number of interrupts, can't load."); return; } @@ -339,7 +339,7 @@ retry: IntrHandler* handler = intrHandlers[pend.intr]; if (handler == NULL) { - WARN_LOG(SCEINTC, "Ignoring interrupt"); + WARN_LOG(Log::sceIntc, "Ignoring interrupt"); pendingInterrupts.pop_front(); goto retry; } @@ -366,7 +366,7 @@ retry: } else { if (needsThreadReturn) __KernelSwitchToThread(threadBeforeInterrupt, "left interrupt"); - // DEBUG_LOG(SCEINTC, "No more interrupts!"); + // DEBUG_LOG(Log::sceIntc, "No more interrupts!"); return false; } } @@ -398,14 +398,14 @@ void __TriggerInterrupt(int type, PSPInterrupt intno, int subintr) if (interruptsEnabled || (type & PSP_INTR_ONLY_IF_ENABLED) == 0) { intrHandlers[intno]->queueUp(subintr); - VERBOSE_LOG(SCEINTC, "Triggering subinterrupts for interrupt %i sub %i (%i in queue)", intno, subintr, (u32)pendingInterrupts.size()); + VERBOSE_LOG(Log::sceIntc, "Triggering subinterrupts for interrupt %i sub %i (%i in queue)", intno, subintr, (u32)pendingInterrupts.size()); __TriggerRunInterrupts(type); } } void __KernelReturnFromInterrupt() { - VERBOSE_LOG(SCEINTC, "Left interrupt handler at %08x", currentMIPS->pc); + VERBOSE_LOG(Log::sceIntc, "Left interrupt handler at %08x", currentMIPS->pc); hleSkipDeadbeef(); @@ -493,11 +493,11 @@ int __ReleaseSubIntrHandler(int intrNumber, int subIntrNumber) { u32 sceKernelRegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handler, u32 handlerArg) { if (intrNumber >= PSP_NUMBER_INTERRUPTS) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid interrupt", intrNumber, subIntrNumber, handler, handlerArg); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid interrupt", intrNumber, subIntrNumber, handler, handlerArg); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid subinterrupt", intrNumber, subIntrNumber, handler, handlerArg); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid subinterrupt", intrNumber, subIntrNumber, handler, handlerArg); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } @@ -505,46 +505,46 @@ u32 sceKernelRegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handl SubIntrHandler *subIntrHandler = __RegisterSubIntrHandler(intrNumber, subIntrNumber, handler, handlerArg, error); if (subIntrHandler) { if (handler == 0) { - WARN_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): ignored NULL handler", intrNumber, subIntrNumber, handler, handlerArg); + WARN_LOG_REPORT(Log::sceIntc, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): ignored NULL handler", intrNumber, subIntrNumber, handler, handlerArg); } else { - DEBUG_LOG(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x)", intrNumber, subIntrNumber, handler, handlerArg); + DEBUG_LOG(Log::sceIntc, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x)", intrNumber, subIntrNumber, handler, handlerArg); } } else if (error == SCE_KERNEL_ERROR_FOUND_HANDLER) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): duplicate handler", intrNumber, subIntrNumber, handler, handlerArg); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): duplicate handler", intrNumber, subIntrNumber, handler, handlerArg); } else { - ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): error %08x", intrNumber, subIntrNumber, handler, handlerArg, error); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): error %08x", intrNumber, subIntrNumber, handler, handlerArg, error); } return error; } u32 sceKernelReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber) { if (intrNumber >= PSP_NUMBER_INTERRUPTS) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): invalid interrupt", intrNumber, subIntrNumber); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelReleaseSubIntrHandler(%i, %i): invalid interrupt", intrNumber, subIntrNumber); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelReleaseSubIntrHandler(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } u32 error = __ReleaseSubIntrHandler(intrNumber, subIntrNumber); if (error != SCE_KERNEL_ERROR_OK) { - ERROR_LOG(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): error %08x", intrNumber, subIntrNumber, error); + ERROR_LOG(Log::sceIntc, "sceKernelReleaseSubIntrHandler(%i, %i): error %08x", intrNumber, subIntrNumber, error); } return error; } u32 sceKernelEnableSubIntr(u32 intrNumber, u32 subIntrNumber) { if (intrNumber >= PSP_NUMBER_INTERRUPTS) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelEnableSubIntr(%i, %i): invalid interrupt", intrNumber, subIntrNumber); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelEnableSubIntr(%i, %i): invalid interrupt", intrNumber, subIntrNumber); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelEnableSubIntr(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelEnableSubIntr(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } - DEBUG_LOG(SCEINTC, "sceKernelEnableSubIntr(%i, %i)", intrNumber, subIntrNumber); + DEBUG_LOG(Log::sceIntc, "sceKernelEnableSubIntr(%i, %i)", intrNumber, subIntrNumber); u32 error; if (!intrHandlers[intrNumber]->has(subIntrNumber)) { // Enableing a handler before registering it works fine. @@ -557,15 +557,15 @@ u32 sceKernelEnableSubIntr(u32 intrNumber, u32 subIntrNumber) { static u32 sceKernelDisableSubIntr(u32 intrNumber, u32 subIntrNumber) { if (intrNumber >= PSP_NUMBER_INTERRUPTS) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelDisableSubIntr(%i, %i): invalid interrupt", intrNumber, subIntrNumber); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelDisableSubIntr(%i, %i): invalid interrupt", intrNumber, subIntrNumber); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) { - ERROR_LOG_REPORT(SCEINTC, "sceKernelDisableSubIntr(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber); + ERROR_LOG_REPORT(Log::sceIntc, "sceKernelDisableSubIntr(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber); return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE; } - DEBUG_LOG(SCEINTC, "sceKernelDisableSubIntr(%i, %i)", intrNumber, subIntrNumber); + DEBUG_LOG(Log::sceIntc, "sceKernelDisableSubIntr(%i, %i)", intrNumber, subIntrNumber); if (!intrHandlers[intrNumber]->has(subIntrNumber)) { // Disabling when not registered is not an error. @@ -598,14 +598,14 @@ struct PspIntrHandlerOptionParam { static int QueryIntrHandlerInfo() { - ERROR_LOG_REPORT(SCEINTC, "QueryIntrHandlerInfo()"); + ERROR_LOG_REPORT(Log::sceIntc, "QueryIntrHandlerInfo()"); return 0; } static u32 sceKernelMemset(u32 addr, u32 fillc, u32 n) { u8 c = fillc & 0xff; - DEBUG_LOG(SCEINTC, "sceKernelMemset(ptr = %08x, c = %02x, n = %08x)", addr, c, n); + DEBUG_LOG(Log::sceIntc, "sceKernelMemset(ptr = %08x, c = %02x, n = %08x)", addr, c, n); bool skip = false; if (n != 0) { if (Memory::IsVRAMAddress(addr)) { @@ -621,7 +621,7 @@ static u32 sceKernelMemset(u32 addr, u32 fillc, u32 n) static u32 sceKernelMemcpy(u32 dst, u32 src, u32 size) { - DEBUG_LOG(SCEKERNEL, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); + DEBUG_LOG(Log::sceKernel, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); // Some games copy from executable code. We need to flush emuhack ops. if (size != 0) @@ -696,16 +696,16 @@ static u32 sysclib_memcpy(u32 dst, u32 src, u32 size) { } static u32 sysclib_strcat(u32 dst, u32 src) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_strcat(dest=%08x, src=%08x)", dst, src); - if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src)) { + ERROR_LOG(Log::sceKernel, "Untested sysclib_strcat(dest=%08x, src=%08x)", dst, src); + if (Memory::IsValidNullTerminatedString(dst) && Memory::IsValidNullTerminatedString(src)) { strcat((char *)Memory::GetPointerWriteUnchecked(dst), (const char *)Memory::GetPointerUnchecked(src)); } return dst; } static int sysclib_strcmp(u32 dst, u32 src) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_strcmp(dest=%08x, src=%08x)", dst, src); - if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src)) { + ERROR_LOG(Log::sceKernel, "Untested sysclib_strcmp(dest=%08x, src=%08x)", dst, src); + if (Memory::IsValidNullTerminatedString(dst) && Memory::IsValidNullTerminatedString(src)) { return strcmp((const char *)Memory::GetPointerUnchecked(dst), (const char *)Memory::GetPointerUnchecked(src)); } else { // What to do? Crash, probably. @@ -714,16 +714,16 @@ static int sysclib_strcmp(u32 dst, u32 src) { } static u32 sysclib_strcpy(u32 dst, u32 src) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_strcpy(dest=%08x, src=%08x)", dst, src); - if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src)) { + ERROR_LOG(Log::sceKernel, "Untested sysclib_strcpy(dest=%08x, src=%08x)", dst, src); + if (Memory::IsValidAddress(dst) && Memory::IsValidNullTerminatedString(src)) { strcpy((char *)Memory::GetPointerWriteUnchecked(dst), (const char *)Memory::GetPointerUnchecked(src)); } return dst; } static u32 sysclib_strlen(u32 src) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_strlen(src=%08x)", src); - if (Memory::IsValidAddress(src)) { + ERROR_LOG(Log::sceKernel, "Untested sysclib_strlen(src=%08x)", src); + if (Memory::IsValidNullTerminatedString(src)) { // TODO: This computes the length, could reuse it maybe. return (u32)strlen(Memory::GetCharPointerUnchecked(src)); } else { // What to do? Crash, probably. @@ -732,7 +732,7 @@ static u32 sysclib_strlen(u32 src) { } static int sysclib_memcmp(u32 dst, u32 src, u32 size) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_memcmp(dest=%08x, src=%08x, size=%i)", dst, src, size); + ERROR_LOG(Log::sceKernel, "Untested sysclib_memcmp(dest=%08x, src=%08x, size=%i)", dst, src, size); if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) { return memcmp(Memory::GetCharPointerUnchecked(dst), Memory::GetCharPointerUnchecked(src), size); } else { @@ -742,18 +742,158 @@ static int sysclib_memcmp(u32 dst, u32 src, u32 size) { } static int sysclib_sprintf(u32 dst, u32 fmt) { - ERROR_LOG(SCEKERNEL, "Unimpl sysclib_sprintf(dest=%08x, src=%08x)", dst, fmt); - if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(fmt)) { - // TODO: Properly use the format string with more parameters. - return sprintf((char *)Memory::GetPointerUnchecked(dst), "%s", Memory::GetCharPointerUnchecked(fmt)); - } else { - // What to do? Crash, probably. + ERROR_LOG(Log::sceKernel, "Untested sysclib_sprintf(dst=%08x, fmt=%08x)", dst, fmt); + + if (!Memory::IsValidNullTerminatedString(fmt)) { + ERROR_LOG(Log::sceKernel, "sysclib_sprintf bad fmt"); return 0; } + + DEBUG_LOG(Log::sceKernel, "sysclib_sprintf fmt: %s", Memory::GetCharPointerUnchecked(fmt)); + DEBUG_LOG(Log::sceKernel, "sysclib_sprintf a0-a4, t0-t4: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", + currentMIPS->r[MIPS_REG_A0], + currentMIPS->r[MIPS_REG_A1], + currentMIPS->r[MIPS_REG_A2], + currentMIPS->r[MIPS_REG_A3], + currentMIPS->r[MIPS_REG_T0], + currentMIPS->r[MIPS_REG_T1], + currentMIPS->r[MIPS_REG_T2], + currentMIPS->r[MIPS_REG_T3] + ); + + bool processing_specifier = false; + std::string specifier = ""; + int bytes_to_read = 0; + int arg_idx = 0; + std::string result = ""; + for (const char *c = Memory::GetCharPointerUnchecked(fmt); *c != '\0'; c++) { + if (!processing_specifier) { + if (*c == '%') { + specifier = "%"; + processing_specifier = true; + bytes_to_read = 0; + } else { + result.append(1, *c); + } + } else { + specifier.append(1, *c); + + // going by https://cplusplus.com/reference/cstdio/printf/#compatibility + // no idea what the kernel module really supports as of writing this + switch (*c) { + case '%': + { + result.append(specifier); + processing_specifier = false; + break; + } + case 's': + { + // consume 4 bytes from arguments + u32 val = 0; + if (arg_idx <= 1) { + val = currentMIPS->r[MIPS_REG_A2 + arg_idx]; + } else if(arg_idx <= 5) { + val = currentMIPS->r[MIPS_REG_T0 + arg_idx - 2]; + } else { + int stack_idx = arg_idx - 6; + u32 stack_cur = currentMIPS->r[MIPS_REG_SP] + stack_idx * 4; + + if (!Memory::IsValidAddress(stack_cur)) { + ERROR_LOG(Log::sceKernel, "sysclib_sprintf bad stack pointer %08x", stack_cur); + return 0; + } + val = Memory::Read_U32(stack_cur); + DEBUG_LOG(Log::sceKernel, "sysclib_sprintf fetching %08x from sp + %u", val, stack_idx * 4); + } + arg_idx++; + + if (!Memory::IsValidNullTerminatedString(val)) { + ERROR_LOG(Log::sceKernel, "sysclib_sprintf bad string reference at %08x", val); + return 0; + } + result.append(Memory::GetCharPointerUnchecked(val)); + processing_specifier = false; + break; + } + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + case 'c': + case 'p': + case 'n': + { + u64 val = 0; + if (bytes_to_read == 0) { + bytes_to_read = 4; + } + int read_cnt = 0; + while (bytes_to_read != 0) { + u32 val_from_arg = 0; + if (arg_idx <= 1) { + val_from_arg = currentMIPS->r[MIPS_REG_A2 + arg_idx]; + } else if (arg_idx <= 5) { + val_from_arg = currentMIPS->r[MIPS_REG_T0 + arg_idx - 2]; + } else { + int stack_idx = arg_idx - 6; + u32 stack_cur = currentMIPS->r[MIPS_REG_SP] + stack_idx * 4; + + if (!Memory::IsValidAddress(stack_cur)) { + ERROR_LOG(Log::sceKernel, "sysclib_sprintf bad stack pointer %08x", stack_cur); + return 0; + } + val_from_arg = Memory::Read_U32(stack_cur); + DEBUG_LOG(Log::sceKernel, "sysclib_sprintf fetching %08x from sp + %u", val_from_arg, stack_idx * 4); + } + arg_idx++; + + val = val | ((u64)val_from_arg << (read_cnt * 32)); + + bytes_to_read = bytes_to_read - 4; + read_cnt++; + } + char buf[128] = {0}; + snprintf(buf, sizeof(buf), specifier.c_str(), val); + buf[sizeof(buf) - 1] = '\0'; + result.append(buf); + processing_specifier = false; + break; + } + case 'h': + { + // allegrex calling convention is 4 bytes aligned + bytes_to_read = 4; + break; + } + case 'l': + { + bytes_to_read = bytes_to_read + 4; + break; + } + } + } + } + + DEBUG_LOG(Log::sceKernel, "sysclib_sprintf result string has length %d, content:", (int)result.length()); + DEBUG_LOG(Log::sceKernel, "%s", result.c_str()); + if (!Memory::IsValidRange(dst, (u32)result.length() + 1)) { + ERROR_LOG(Log::sceKernel, "sysclib_sprintf result string is too long or dst is invalid"); + return 0; + } + memcpy((char *)Memory::GetPointerUnchecked(dst), result.c_str(), (int)result.length() + 1); + return (int)result.length(); } static u32 sysclib_memset(u32 destAddr, int data, int size) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_memset(dest=%08x, data=%d ,size=%d)", destAddr, data, size); + DEBUG_LOG(Log::sceKernel, "Untested sysclib_memset(dest=%08x, data=%d ,size=%d)", destAddr, data, size); if (Memory::IsValidRange(destAddr, size)) { memset(Memory::GetPointerWriteUnchecked(destAddr), data, size); } @@ -762,8 +902,8 @@ static u32 sysclib_memset(u32 destAddr, int data, int size) { } static int sysclib_strstr(u32 s1, u32 s2) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_strstr(%08x, %08x)", s1, s2); - if (Memory::IsValidAddress(s1) && Memory::IsValidAddress(s2)) { + DEBUG_LOG(Log::sceKernel, "Untested sysclib_strstr(%08x, %08x)", s1, s2); + if (Memory::IsValidNullTerminatedString(s1) && Memory::IsValidNullTerminatedString(s2)) { std::string str1 = Memory::GetCharPointerUnchecked(s1); std::string str2 = Memory::GetCharPointerUnchecked(s2); size_t index = str1.find(str2); @@ -776,8 +916,8 @@ static int sysclib_strstr(u32 s1, u32 s2) { } static int sysclib_strncmp(u32 s1, u32 s2, u32 size) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_strncmp(%08x, %08x, %08x)", s1, s2, size); - if (Memory::IsValidAddress(s1) && Memory::IsValidAddress(s2)) { + DEBUG_LOG(Log::sceKernel, "Untested sysclib_strncmp(%08x, %08x, %08x)", s1, s2, size); + if (Memory::IsValidRange(s1, size) && Memory::IsValidRange(s2, size)) { const char * str1 = Memory::GetCharPointerUnchecked(s1); const char * str2 = Memory::GetCharPointerUnchecked(s2); return strncmp(str1, str2, size); @@ -786,7 +926,7 @@ static int sysclib_strncmp(u32 s1, u32 s2, u32 size) { } static u32 sysclib_memmove(u32 dst, u32 src, u32 size) { - ERROR_LOG(SCEKERNEL, "Untested sysclib_memmove(%08x, %08x, %08x)", dst, src, size); + DEBUG_LOG(Log::sceKernel, "Untested sysclib_memmove(%08x, %08x, %08x)", dst, src, size); if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) { memmove(Memory::GetPointerWriteUnchecked(dst), Memory::GetPointerUnchecked(src), size); } @@ -797,8 +937,8 @@ static u32 sysclib_memmove(u32 dst, u32 src, u32 size) { } static u32 sysclib_strncpy(u32 dest, u32 src, u32 size) { - if (!Memory::IsValidAddress(dest) || Memory::IsValidAddress(src)) { - return hleLogError(SCEKERNEL, 0, "invalid address"); + if (!Memory::IsValidAddress(dest) || !Memory::IsValidAddress(src)) { + return hleLogError(Log::sceKernel, 0, "invalid address"); } // This is just regular strncpy, but being explicit to avoid warnings/safety fixes on missing null. @@ -818,12 +958,12 @@ static u32 sysclib_strncpy(u32 dest, u32 src, u32 size) { *destp++ = 0; } - return hleLogSuccessX(SCEKERNEL, dest); + return hleLogSuccessX(Log::sceKernel, dest); } static u32 sysclib_strtol(u32 strPtr, u32 endPtrPtr, int base) { - if (!Memory::IsValidAddress(strPtr)) { - return hleLogError(SCEKERNEL, 0, "invalid address"); + if (!Memory::IsValidNullTerminatedString(strPtr)) { + return hleLogError(Log::sceKernel, 0, "invalid address"); } const char* str = Memory::GetCharPointer(strPtr); char* end = nullptr; @@ -834,8 +974,8 @@ static u32 sysclib_strtol(u32 strPtr, u32 endPtrPtr, int base) { } static u32 sysclib_strchr(u32 src, int c) { - if (!Memory::IsValidAddress(src)) { - return hleLogError(SCEKERNEL, 0, "invalid address"); + if (!Memory::IsValidNullTerminatedString(src)) { + return hleLogError(Log::sceKernel, 0, "invalid address"); } const std::string str = Memory::GetCharPointer(src); size_t cpos = str.find(str, c); @@ -846,8 +986,8 @@ static u32 sysclib_strchr(u32 src, int c) { } static u32 sysclib_strrchr(u32 src, int c) { - if (!Memory::IsValidAddress(src)) { - return hleLogError(SCEKERNEL, 0, "invalid address"); + if (!Memory::IsValidNullTerminatedString(src)) { + return hleLogError(Log::sceKernel, 0, "invalid address"); } const std::string str = Memory::GetCharPointer(src); size_t cpos = str.rfind(str, c); diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 0a5f132f01..543b57d97b 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -237,18 +237,18 @@ void __KernelMbxBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, mbxWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Suspending mbx wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB: Suspending mbx wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelReceiveMbxCB: wait not found to pause for callback"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelReceiveMbxCB: wait not found to pause for callback"); else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelReceiveMbxCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelReceiveMbxCB: beginning callback with bad wait id?"); } void __KernelMbxEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, mbxWaitTimer, __KernelUnlockMbxForThreadCheck); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Resuming mbx wait from callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB: Resuming mbx wait from callback"); } void __KernelMbxTimeout(u64 userdata, int cyclesLate) @@ -298,13 +298,13 @@ SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr) { if (!name) { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateMbx(): invalid name", SCE_KERNEL_ERROR_ERROR); + WARN_LOG_REPORT(Log::sceKernel, "%08x=sceKernelCreateMbx(): invalid name", SCE_KERNEL_ERROR_ERROR); return SCE_KERNEL_ERROR_ERROR; } // Accepts 0x000 - 0x0FF, 0x100 - 0x1FF, and 0x400 - 0x4FF. if (((attr & ~SCE_KERNEL_MBA_ATTR_KNOWN) & ~0xFF) != 0) { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateMbx(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); + WARN_LOG_REPORT(Log::sceKernel, "%08x=sceKernelCreateMbx(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); return SCE_KERNEL_ERROR_ILLEGAL_ATTR; } @@ -319,16 +319,16 @@ SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr) m->nmb.numMessages = 0; m->nmb.packetListHead = 0; - DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateMbx(%s, %08x, %08x)", id, name, attr, optAddr); + DEBUG_LOG(Log::sceKernel, "%i=sceKernelCreateMbx(%s, %08x, %08x)", id, name, attr, optAddr); if (optAddr != 0) { u32 size = Memory::Read_U32(optAddr); if (size > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMbx(%s) unsupported options parameter, size = %d", name, size); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMbx(%s) unsupported options parameter, size = %d", name, size); } if ((attr & ~SCE_KERNEL_MBA_ATTR_KNOWN) != 0) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMbx(%s) unsupported attr parameter: %08x", name, attr); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMbx(%s) unsupported attr parameter: %08x", name, attr); return id; } @@ -339,7 +339,7 @@ int sceKernelDeleteMbx(SceUID id) Mbx *m = kernelObjects.Get(id, error); if (m) { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteMbx(%i)", id); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteMbx(%i)", id); bool wokeThreads = false; for (size_t i = 0; i < m->waitingThreads.size(); i++) @@ -351,7 +351,7 @@ int sceKernelDeleteMbx(SceUID id) } else { - ERROR_LOG(SCEKERNEL, "sceKernelDeleteMbx(%i): invalid mbx id", id); + ERROR_LOG(Log::sceKernel, "sceKernelDeleteMbx(%i): invalid mbx id", id); } return kernelObjects.Destroy(id); } @@ -362,14 +362,14 @@ int sceKernelSendMbx(SceUID id, u32 packetAddr) Mbx *m = kernelObjects.Get(id, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelSendMbx(%i, %08x): invalid mbx id", id, packetAddr); + ERROR_LOG(Log::sceKernel, "sceKernelSendMbx(%i, %08x): invalid mbx id", id, packetAddr); return error; } NativeMbxPacket *addPacket = (NativeMbxPacket*)Memory::GetPointer(packetAddr); if (addPacket == 0) { - ERROR_LOG(SCEKERNEL, "sceKernelSendMbx(%i, %08x): invalid packet address", id, packetAddr); + ERROR_LOG(Log::sceKernel, "sceKernelSendMbx(%i, %08x): invalid packet address", id, packetAddr); return -1; } @@ -392,7 +392,7 @@ int sceKernelSendMbx(SceUID id, u32 packetAddr) if (wokeThreads) { - DEBUG_LOG(SCEKERNEL, "sceKernelSendMbx(%i, %08x): threads waiting, resuming %d", id, packetAddr, t.threadID); + DEBUG_LOG(Log::sceKernel, "sceKernelSendMbx(%i, %08x): threads waiting, resuming %d", id, packetAddr, t.threadID); Memory::Write_U32(packetAddr, t.packetAddr); hleReSchedule("mbx sent"); @@ -402,7 +402,7 @@ int sceKernelSendMbx(SceUID id, u32 packetAddr) } } - DEBUG_LOG(SCEKERNEL, "sceKernelSendMbx(%i, %08x): no threads currently waiting, adding message to queue", id, packetAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelSendMbx(%i, %08x): no threads currently waiting, adding message to queue", id, packetAddr); if (m->nmb.numMessages == 0) m->AddInitialMessage(packetAddr); @@ -454,18 +454,18 @@ int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelReceiveMbx(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr); + ERROR_LOG(Log::sceKernel, "sceKernelReceiveMbx(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr); return error; } if (m->nmb.numMessages > 0) { - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbx(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbx(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr); return m->ReceiveMessage(packetAddrPtr); } else { - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbx(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbx(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); HLEKernel::RemoveWaitingThread(m->waitingThreads, __KernelGetCurThread()); m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); __KernelWaitMbx(m, timeoutPtr); @@ -481,19 +481,19 @@ int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelReceiveMbxCB(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr); + ERROR_LOG(Log::sceKernel, "sceKernelReceiveMbxCB(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr); return error; } if (m->nmb.numMessages > 0) { - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr); hleCheckCurrentCallbacks(); return m->ReceiveMessage(packetAddrPtr); } else { - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMbxCB(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); HLEKernel::RemoveWaitingThread(m->waitingThreads, __KernelGetCurThread()); m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); __KernelWaitMbx(m, timeoutPtr); @@ -509,18 +509,18 @@ int sceKernelPollMbx(SceUID id, u32 packetAddrPtr) if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelPollMbx(%i, %08x): invalid mbx id", id, packetAddrPtr); + ERROR_LOG(Log::sceKernel, "sceKernelPollMbx(%i, %08x): invalid mbx id", id, packetAddrPtr); return error; } if (m->nmb.numMessages > 0) { - DEBUG_LOG(SCEKERNEL, "sceKernelPollMbx(%i, %08x): sending first queue message", id, packetAddrPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelPollMbx(%i, %08x): sending first queue message", id, packetAddrPtr); return m->ReceiveMessage(packetAddrPtr); } else { - DEBUG_LOG(SCEKERNEL, "SCE_KERNEL_ERROR_MBOX_NOMSG=sceKernelPollMbx(%i, %08x): no message in queue", id, packetAddrPtr); + DEBUG_LOG(Log::sceKernel, "SCE_KERNEL_ERROR_MBOX_NOMSG=sceKernelPollMbx(%i, %08x): no message in queue", id, packetAddrPtr); return SCE_KERNEL_ERROR_MBOX_NOMSG; } } @@ -532,12 +532,12 @@ int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr) if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelCancelReceiveMbx(%i, %08x): invalid mbx id", id, numWaitingThreadsAddr); + ERROR_LOG(Log::sceKernel, "sceKernelCancelReceiveMbx(%i, %08x): invalid mbx id", id, numWaitingThreadsAddr); return error; } u32 count = (u32) m->waitingThreads.size(); - DEBUG_LOG(SCEKERNEL, "sceKernelCancelReceiveMbx(%i, %08x): cancelling %d threads", id, numWaitingThreadsAddr, count); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelReceiveMbx(%i, %08x): cancelling %d threads", id, numWaitingThreadsAddr, count); bool wokeThreads = false; for (size_t i = 0; i < m->waitingThreads.size(); i++) @@ -556,13 +556,13 @@ int sceKernelReferMbxStatus(SceUID id, u32 infoAddr) { u32 error; Mbx *m = kernelObjects.Get(id, error); if (!m) { - return hleLogError(SCEKERNEL, error, "invalid mbx id"); + return hleLogError(Log::sceKernel, error, "invalid mbx id"); } // Should we crash the thread somehow? auto info = PSPPointer::Create(infoAddr); if (!info.IsValid()) - return hleLogError(SCEKERNEL, -1, "invalid pointer"); + return hleLogError(Log::sceKernel, -1, "invalid pointer"); for (int i = 0, n = m->nmb.numMessages; i < n; ++i) m->nmb.packetListHead = Memory::Read_U32(m->nmb.packetListHead); diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 72b1a3faa9..98992800f4 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -346,15 +346,15 @@ struct SceKernelVplHeader { while (b.ptr < lastBlock.ptr) { bool isFree = b->next.ptr != SentinelPtr(); if (nextFreeBlock_ == b && isFree) { - NOTICE_LOG(SCEKERNEL, "NEXT: %x -> %x (size %x)", b.ptr - startPtr_, b->next.ptr - startPtr_, b->sizeInBlocks * 8); + NOTICE_LOG(Log::sceKernel, "NEXT: %x -> %x (size %x)", b.ptr - startPtr_, b->next.ptr - startPtr_, b->sizeInBlocks * 8); } else if (isFree) { - NOTICE_LOG(SCEKERNEL, "FREE: %x -> %x (size %x)", b.ptr - startPtr_, b->next.ptr - startPtr_, b->sizeInBlocks * 8); + NOTICE_LOG(Log::sceKernel, "FREE: %x -> %x (size %x)", b.ptr - startPtr_, b->next.ptr - startPtr_, b->sizeInBlocks * 8); } else { - NOTICE_LOG(SCEKERNEL, "BLOCK: %x (size %x)", b.ptr - startPtr_, b->sizeInBlocks * 8); + NOTICE_LOG(Log::sceKernel, "BLOCK: %x (size %x)", b.ptr - startPtr_, b->sizeInBlocks * 8); } b += b->sizeInBlocks; } - NOTICE_LOG(SCEKERNEL, "LAST: %x -> %x (size %x)", lastBlock.ptr - startPtr_, lastBlock->next.ptr - startPtr_, lastBlock->sizeInBlocks * 8); + NOTICE_LOG(Log::sceKernel, "LAST: %x -> %x (size %x)", lastBlock.ptr - startPtr_, lastBlock->next.ptr - startPtr_, lastBlock->sizeInBlocks * 8); } PSPPointer MergeBlocks(PSPPointer first, PSPPointer second) { @@ -437,7 +437,7 @@ void __KernelMemoryInit() volatileMemory.Init(PSP_GetVolatileMemoryStart(), PSP_GetVolatileMemoryEnd() - PSP_GetVolatileMemoryStart(), false); ParallelMemset(&g_threadManager, Memory::GetPointerWrite(PSP_GetKernelMemoryBase()), 0, PSP_GetUserMemoryEnd() - PSP_GetKernelMemoryBase(), TaskPriority::HIGH); NotifyMemInfo(MemBlockFlags::WRITE, PSP_GetKernelMemoryBase(), PSP_GetUserMemoryEnd() - PSP_GetKernelMemoryBase(), "MemInit"); - INFO_LOG(SCEKERNEL, "Kernel and user memory pools initialized"); + INFO_LOG(Log::sceKernel, "Kernel and user memory pools initialized"); vplWaitTimer = CoreTiming::RegisterEvent("VplTimeout", __KernelVplTimeout); fplWaitTimer = CoreTiming::RegisterEvent("FplTimeout", __KernelFplTimeout); @@ -487,17 +487,17 @@ void __KernelMemoryDoState(PointerWrap &p) void __KernelMemoryShutdown() { #ifdef _DEBUG - INFO_LOG(SCEKERNEL, "Shutting down volatile memory pool: "); + INFO_LOG(Log::sceKernel, "Shutting down volatile memory pool: "); volatileMemory.ListBlocks(); #endif volatileMemory.Shutdown(); #ifdef _DEBUG - INFO_LOG(SCEKERNEL,"Shutting down user memory pool: "); + INFO_LOG(Log::sceKernel,"Shutting down user memory pool: "); userMemory.ListBlocks(); #endif userMemory.Shutdown(); #ifdef _DEBUG - INFO_LOG(SCEKERNEL,"Shutting down \"kernel\" memory pool: "); + INFO_LOG(Log::sceKernel,"Shutting down \"kernel\" memory pool: "); kernelMemory.ListBlocks(); #endif kernelMemory.Shutdown(); @@ -600,18 +600,18 @@ void __KernelFplBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, fplWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFplCB: Suspending fpl wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB: Suspending fpl wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelAllocateFplCB: wait not found to pause for callback"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelAllocateFplCB: wait not found to pause for callback"); else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelAllocateFplCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelAllocateFplCB: beginning callback with bad wait id?"); } void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, fplWaitTimer, __KernelUnlockFplForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) - DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFplCB: Resuming mbx wait from callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB: Resuming mbx wait from callback"); } static bool __FplThreadSortPriority(FplWaitingThread thread1, FplWaitingThread thread2) @@ -642,15 +642,15 @@ static void __KernelSortFplThreads(FPL *fpl) int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 numBlocks, u32 optPtr) { if (!name) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "invalid name"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "invalid name"); if (mpid < 1 || mpid > 9 || mpid == 7) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", mpid); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", mpid); BlockAllocator *allocator = BlockAllocatorFromID(mpid); if (allocator == nullptr) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_PERM, "invalid partition %d", mpid); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_PERM, "invalid partition %d", mpid); if (((attr & ~PSP_FPL_ATTR_KNOWN) & ~0xFF) != 0) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", attr); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", attr); // There's probably a simpler way to get this same basic formula... // This is based on results from a PSP. @@ -660,7 +660,7 @@ int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 if (!illegalMemSize && (u64) numBlocks >= 0x100000000ULL / (((u64) blockSize + 3ULL) & ~3ULL)) illegalMemSize = true; if (illegalMemSize) - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid blockSize/count"); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid blockSize/count"); int alignment = 4; if (Memory::IsValidRange(optPtr, 4)) { @@ -669,7 +669,7 @@ int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 alignment = Memory::Read_U32(optPtr + 4); // Must be a power of 2 to be valid. if ((alignment & (alignment - 1)) != 0) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid alignment %d", alignment); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid alignment %d", alignment); } if (alignment < 4) @@ -680,7 +680,7 @@ int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 bool atEnd = (attr & PSP_FPL_ATTR_HIGHMEM) != 0; u32 address = allocator->Alloc(totalSize, atEnd, StringFromFormat("FPL/%s", name).c_str()); if (address == (u32)-1) { - DEBUG_LOG(SCEKERNEL, "sceKernelCreateFpl(\"%s\", partition=%i, attr=%08x, bsize=%i, nb=%i) FAILED - out of ram", + DEBUG_LOG(Log::sceKernel, "sceKernelCreateFpl(\"%s\", partition=%i, attr=%08x, bsize=%i, nb=%i) FAILED - out of ram", name, mpid, attr, blockSize, numBlocks); return SCE_KERNEL_ERROR_NO_MEMORY; } @@ -702,7 +702,7 @@ int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 fpl->address = address; fpl->alignedSize = alignedSize; - DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateFpl(\"%s\", partition=%i, attr=%08x, bsize=%i, nb=%i)", + DEBUG_LOG(Log::sceKernel, "%i=sceKernelCreateFpl(\"%s\", partition=%i, attr=%08x, bsize=%i, nb=%i)", id, name, mpid, attr, blockSize, numBlocks); return id; @@ -715,7 +715,7 @@ int sceKernelDeleteFpl(SceUID uid) FPL *fpl = kernelObjects.Get(uid, error); if (fpl) { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteFpl(%i)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteFpl(%i)", uid); bool wokeThreads = __KernelClearFplThreads(fpl, SCE_KERNEL_ERROR_WAIT_DELETE); if (wokeThreads) @@ -729,7 +729,7 @@ int sceKernelDeleteFpl(SceUID uid) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteFpl(%i): invalid fpl", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteFpl(%i): invalid fpl", uid); return error; } } @@ -766,7 +766,7 @@ int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) FPL *fpl = kernelObjects.Get(uid, error); if (fpl) { - DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFpl(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFpl(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr); int blockNum = fpl->allocateBlock(); if (blockNum >= 0) { @@ -787,7 +787,7 @@ int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFpl(%i, %08x, %08x): invalid fpl", uid, blockPtrAddr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFpl(%i, %08x, %08x): invalid fpl", uid, blockPtrAddr, timeoutPtr); return error; } } @@ -798,7 +798,7 @@ int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) FPL *fpl = kernelObjects.Get(uid, error); if (fpl) { - DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFplCB(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr); int blockNum = fpl->allocateBlock(); if (blockNum >= 0) { @@ -819,7 +819,7 @@ int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelAllocateFplCB(%i, %08x, %08x): invalid fpl", uid, blockPtrAddr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB(%i, %08x, %08x): invalid fpl", uid, blockPtrAddr, timeoutPtr); return error; } } @@ -830,7 +830,7 @@ int sceKernelTryAllocateFpl(SceUID uid, u32 blockPtrAddr) FPL *fpl = kernelObjects.Get(uid, error); if (fpl) { - DEBUG_LOG(SCEKERNEL, "sceKernelTryAllocateFpl(%i, %08x)", uid, blockPtrAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelTryAllocateFpl(%i, %08x)", uid, blockPtrAddr); int blockNum = fpl->allocateBlock(); if (blockNum >= 0) { @@ -844,7 +844,7 @@ int sceKernelTryAllocateFpl(SceUID uid, u32 blockPtrAddr) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelTryAllocateFpl(%i, %08x): invalid fpl", uid, blockPtrAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelTryAllocateFpl(%i, %08x): invalid fpl", uid, blockPtrAddr); return error; } } @@ -852,7 +852,7 @@ int sceKernelTryAllocateFpl(SceUID uid, u32 blockPtrAddr) int sceKernelFreeFpl(SceUID uid, u32 blockPtr) { if (blockPtr > PSP_GetUserMemoryEnd()) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelFreeFpl(%i, %08x): invalid address", SCE_KERNEL_ERROR_ILLEGAL_ADDR, uid, blockPtr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelFreeFpl(%i, %08x): invalid address", SCE_KERNEL_ERROR_ILLEGAL_ADDR, uid, blockPtr); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } @@ -861,14 +861,14 @@ int sceKernelFreeFpl(SceUID uid, u32 blockPtr) if (fpl) { int blockNum = (blockPtr - fpl->address) / fpl->alignedSize; if (blockNum < 0 || blockNum >= fpl->nf.numBlocks) { - DEBUG_LOG(SCEKERNEL, "sceKernelFreeFpl(%i, %08x): bad block ptr", uid, blockPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelFreeFpl(%i, %08x): bad block ptr", uid, blockPtr); return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK; } else { if (fpl->freeBlock(blockNum)) { u32 blockPtr = fpl->address + fpl->alignedSize * blockNum; NotifyMemInfo(MemBlockFlags::SUB_FREE, blockPtr, fpl->alignedSize, "FplFree"); - DEBUG_LOG(SCEKERNEL, "sceKernelFreeFpl(%i, %08x)", uid, blockPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelFreeFpl(%i, %08x)", uid, blockPtr); __KernelSortFplThreads(fpl); bool wokeThreads = false; @@ -886,14 +886,14 @@ retry: hleReSchedule("fpl freed"); return 0; } else { - DEBUG_LOG(SCEKERNEL, "sceKernelFreeFpl(%i, %08x): already free", uid, blockPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelFreeFpl(%i, %08x): already free", uid, blockPtr); return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK; } } } else { - DEBUG_LOG(SCEKERNEL, "sceKernelFreeFpl(%i, %08x): invalid fpl", uid, blockPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelFreeFpl(%i, %08x): invalid fpl", uid, blockPtr); return error; } } @@ -906,7 +906,7 @@ int sceKernelCancelFpl(SceUID uid, u32 numWaitThreadsPtr) FPL *fpl = kernelObjects.Get(uid, error); if (fpl) { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelFpl(%i, %08x)", uid, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelFpl(%i, %08x)", uid, numWaitThreadsPtr); fpl->nf.numWaitThreads = (int) fpl->waitingThreads.size(); if (Memory::IsValidAddress(numWaitThreadsPtr)) Memory::Write_U32(fpl->nf.numWaitThreads, numWaitThreadsPtr); @@ -918,7 +918,7 @@ int sceKernelCancelFpl(SceUID uid, u32 numWaitThreadsPtr) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelFpl(%i, %08x): invalid fpl", uid, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelFpl(%i, %08x): invalid fpl", uid, numWaitThreadsPtr); return error; } } @@ -940,9 +940,9 @@ int sceKernelReferFplStatus(SceUID uid, u32 statusPtr) { *status = fpl->nf; status.NotifyWrite("FplStatus"); } - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error, "invalid fpl"); + return hleLogError(Log::sceKernel, error, "invalid fpl"); } } @@ -1022,46 +1022,46 @@ public: static u32 sceKernelMaxFreeMemSize() { u32 retVal = userMemory.GetLargestFreeBlockSize(); - DEBUG_LOG(SCEKERNEL, "%08x (dec %i)=sceKernelMaxFreeMemSize()", retVal, retVal); + DEBUG_LOG(Log::sceKernel, "%08x (dec %i)=sceKernelMaxFreeMemSize()", retVal, retVal); return retVal; } static u32 sceKernelTotalFreeMemSize() { u32 retVal = userMemory.GetTotalFreeBytes(); - DEBUG_LOG(SCEKERNEL, "%08x (dec %i)=sceKernelTotalFreeMemSize()", retVal, retVal); + DEBUG_LOG(Log::sceKernel, "%08x (dec %i)=sceKernelTotalFreeMemSize()", retVal, retVal); return retVal; } int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32 size, u32 addr) { if (type < PSP_SMEM_Low || type > PSP_SMEM_HighAligned) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE, "invalid type %x", type); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE, "invalid type %x", type); // Alignment is only allowed for powers of 2. if (type == PSP_SMEM_LowAligned || type == PSP_SMEM_HighAligned) { if ((addr & (addr - 1)) != 0 || addr == 0) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE, "invalid alignment %x", addr); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE, "invalid alignment %x", addr); } if (partition < 1 || partition > 9 || partition == 7) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %x", partition); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %x", partition); BlockAllocator *allocator = BlockAllocatorFromID(partition); if (allocator == nullptr) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_PARTITION, "invalid partition %x", partition); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_PARTITION, "invalid partition %x", partition); if (name == nullptr) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (size == 0) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED, "invalid size %x", size); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED, "invalid size %x", size); PartitionMemoryBlock *block = new PartitionMemoryBlock(allocator, name, size, (MemblockType)type, addr); if (!block->IsValid()) { delete block; - ERROR_LOG(SCEKERNEL, "sceKernelAllocPartitionMemory(partition = %i, %s, type= %i, size= %i, addr= %08x): allocation failed", partition, name, type, size, addr); + ERROR_LOG(Log::sceKernel, "sceKernelAllocPartitionMemory(partition = %i, %s, type= %i, size= %i, addr= %08x): allocation failed", partition, name, type, size, addr); return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; } SceUID uid = kernelObjects.Create(block); - DEBUG_LOG(SCEKERNEL,"%i = sceKernelAllocPartitionMemory(partition = %i, %s, type= %i, size= %i, addr= %08x)", + DEBUG_LOG(Log::sceKernel,"%i = sceKernelAllocPartitionMemory(partition = %i, %s, type= %i, size= %i, addr= %08x)", uid, partition, name, type, size, addr); return uid; @@ -1069,7 +1069,7 @@ int sceKernelAllocPartitionMemory(int partition, const char *name, int type, u32 int sceKernelFreePartitionMemory(SceUID id) { - DEBUG_LOG(SCEKERNEL,"sceKernelFreePartitionMemory(%d)",id); + DEBUG_LOG(Log::sceKernel,"sceKernelFreePartitionMemory(%d)",id); return kernelObjects.Destroy(id); } @@ -1080,12 +1080,12 @@ u32 sceKernelGetBlockHeadAddr(SceUID id) PartitionMemoryBlock *block = kernelObjects.Get(id, error); if (block) { - DEBUG_LOG(SCEKERNEL,"%08x = sceKernelGetBlockHeadAddr(%i)", block->address, id); + DEBUG_LOG(Log::sceKernel,"%08x = sceKernelGetBlockHeadAddr(%i)", block->address, id); return block->address; } else { - ERROR_LOG(SCEKERNEL,"sceKernelGetBlockHeadAddr failed(%i)", id); + ERROR_LOG(Log::sceKernel,"sceKernelGetBlockHeadAddr failed(%i)", id); return 0; } } @@ -1211,9 +1211,9 @@ static int sceKernelPrintf(const char *formatString) result.resize(result.size() - 1); if (supported) - INFO_LOG(PRINTF, "sceKernelPrintf: %s", result.c_str()); + INFO_LOG(Log::Printf, "sceKernelPrintf: %s", result.c_str()); else - ERROR_LOG(PRINTF, "UNIMPL sceKernelPrintf(%s, %08x, %08x, %08x)", format.c_str(), PARAM(1), PARAM(2), PARAM(3)); + ERROR_LOG(Log::Printf, "UNIMPL sceKernelPrintf(%s, %08x, %08x, %08x)", format.c_str(), PARAM(1), PARAM(2), PARAM(3)); return 0; } @@ -1242,10 +1242,10 @@ static int sceKernelSetCompiledSdkVersion(int sdkVersion) { } if (!validSDK) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion unknown SDK: %x", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1254,10 +1254,10 @@ static int sceKernelSetCompiledSdkVersion(int sdkVersion) { static int sceKernelSetCompiledSdkVersion370(int sdkVersion) { int sdkMainVersion = sdkVersion & 0xFFFF0000; if (sdkMainVersion != 0x03070000) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion370 unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion370 unknown SDK: %x", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion370(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion370(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1266,12 +1266,12 @@ static int sceKernelSetCompiledSdkVersion370(int sdkVersion) { static int sceKernelSetCompiledSdkVersion380_390(int sdkVersion) { int sdkMainVersion = sdkVersion & 0xFFFF0000; if (sdkMainVersion != 0x03080000 && sdkMainVersion != 0x03090000) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion380_390 unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion380_390 unknown SDK: %x", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion380_390(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion380_390(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1284,10 +1284,10 @@ static int sceKernelSetCompiledSdkVersion395(int sdkVersion) { && sdkMainVersion != 0x04000500 && sdkMainVersion != 0x03090500 && sdkMainVersion != 0x03090600) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion395 unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion395 unknown SDK: %x", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion395(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion395(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1298,10 +1298,10 @@ static int sceKernelSetCompiledSdkVersion600_602(int sdkVersion) { if (sdkMainVersion != 0x06010000 && sdkMainVersion != 0x06000000 && sdkMainVersion != 0x06020000) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion600_602 unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion600_602 unknown SDK: %x", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion600_602(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion600_602(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1312,10 +1312,10 @@ static int sceKernelSetCompiledSdkVersion500_505(int sdkVersion) int sdkMainVersion = sdkVersion & 0xFFFF0000; if (sdkMainVersion != 0x05000000 && sdkMainVersion != 0x05050000) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion500_505 unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion500_505 unknown SDK: %x", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion500_505(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion500_505(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1325,10 +1325,10 @@ static int sceKernelSetCompiledSdkVersion401_402(int sdkVersion) { int sdkMainVersion = sdkVersion & 0xFFFF0000; if (sdkMainVersion != 0x04010000 && sdkMainVersion != 0x04020000) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion401_402 unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion401_402 unknown SDK: %x", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion401_402(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion401_402(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1337,10 +1337,10 @@ static int sceKernelSetCompiledSdkVersion401_402(int sdkVersion) { static int sceKernelSetCompiledSdkVersion507(int sdkVersion) { int sdkMainVersion = sdkVersion & 0xFFFF0000; if (sdkMainVersion != 0x05070000) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion507 unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion507 unknown SDK: %x", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion507(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion507(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1351,10 +1351,10 @@ static int sceKernelSetCompiledSdkVersion603_605(int sdkVersion) { if (sdkMainVersion != 0x06040000 && sdkMainVersion != 0x06030000 && sdkMainVersion != 0x06050000) { - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion603_605 unknown SDK: %x", sdkVersion); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion603_605 unknown SDK: %x", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion603_605(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion603_605(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1363,10 +1363,10 @@ static int sceKernelSetCompiledSdkVersion603_605(int sdkVersion) { static int sceKernelSetCompiledSdkVersion606(int sdkVersion) { int sdkMainVersion = sdkVersion & 0xFFFF0000; if (sdkMainVersion != 0x06060000) { - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelSetCompiledSdkVersion606 unknown SDK: %x (would crash)", sdkVersion); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelSetCompiledSdkVersion606 unknown SDK: %x (would crash)", sdkVersion); } - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompiledSdkVersion606(%08x)", sdkVersion); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompiledSdkVersion606(%08x)", sdkVersion); sdkVersion_ = sdkVersion; flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; return 0; @@ -1379,7 +1379,7 @@ int sceKernelGetCompiledSdkVersion() { } static int sceKernelSetCompilerVersion(int version) { - DEBUG_LOG(SCEKERNEL, "sceKernelSetCompilerVersion(%08x)", version); + DEBUG_LOG(Log::sceKernel, "sceKernelSetCompilerVersion(%08x)", version); compilerVersion_ = version; flags_ |= SCE_KERNEL_HASCOMPILERVERSION; return 0; @@ -1456,18 +1456,18 @@ void __KernelVplBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, vplWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelAllocateVplCB: Suspending vpl wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelAllocateVplCB: Suspending vpl wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelAllocateVplCB: wait not found to pause for callback"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelAllocateVplCB: wait not found to pause for callback"); else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelAllocateVplCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelAllocateVplCB: beginning callback with bad wait id?"); } void __KernelVplEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, vplWaitTimer, __KernelUnlockVplForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) - DEBUG_LOG(SCEKERNEL, "sceKernelAllocateVplCB: Resuming mbx wait from callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelAllocateVplCB: Resuming mbx wait from callback"); } static bool __VplThreadSortPriority(VplWaitingThread thread1, VplWaitingThread thread2) @@ -1498,21 +1498,21 @@ static void __KernelSortVplThreads(VPL *vpl) SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize, u32 optPtr) { if (!name) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (partition < 1 || partition > 9 || partition == 7) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", partition); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", partition); BlockAllocator *allocator = BlockAllocatorFromID(partition); if (allocator == nullptr) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_PERM, "invalid partition %d", partition); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_PERM, "invalid partition %d", partition); if (((attr & ~PSP_VPL_ATTR_KNOWN) & ~0xFF) != 0) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", attr); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", attr); if (vplSize == 0) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid size"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid size"); // Block Allocator seems to A-OK this, let's stop it here. if (vplSize >= 0x80000000) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "way too big size"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "way too big size"); // Can't have that little space in a Vpl, sorry. if (vplSize <= 0x30) @@ -1523,7 +1523,7 @@ SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize u32 allocSize = vplSize; u32 memBlockPtr = allocator->Alloc(allocSize, (attr & PSP_VPL_ATTR_HIGHMEM) != 0, StringFromFormat("VPL/%s", name).c_str()); if (memBlockPtr == (u32)-1) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "failed to allocate %i bytes of pool data", vplSize); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "failed to allocate %i bytes of pool data", vplSize); VPL *vpl = new VPL; SceUID id = kernelObjects.Create(vpl); @@ -1543,14 +1543,14 @@ SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize vpl->header = PSPPointer::Create(memBlockPtr); vpl->header->Init(memBlockPtr, vplSize); - DEBUG_LOG(SCEKERNEL, "%x=sceKernelCreateVpl(\"%s\", block=%i, attr=%i, size=%i)", + DEBUG_LOG(Log::sceKernel, "%x=sceKernelCreateVpl(\"%s\", block=%i, attr=%i, size=%i)", id, name, partition, vpl->nv.attr, vpl->nv.poolSize); if (optPtr != 0) { u32 size = Memory::Read_U32(optPtr); if (size > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateVpl(): unsupported options parameter, size = %d", size); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateVpl(): unsupported options parameter, size = %d", size); } return id; @@ -1558,7 +1558,7 @@ SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize int sceKernelDeleteVpl(SceUID uid) { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteVpl(%i)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteVpl(%i)", uid); u32 error; VPL *vpl = kernelObjects.Get(uid, error); if (vpl) @@ -1584,12 +1584,12 @@ static bool __KernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 &error, b VPL *vpl = kernelObjects.Get(uid, error); if (vpl) { if (size == 0 || size > (u32) vpl->nv.poolSize) { - WARN_LOG(SCEKERNEL, "%s(vpl=%i, size=%i, ptrout=%08x): invalid size", funcname, uid, size, addrPtr); + WARN_LOG(Log::sceKernel, "%s(vpl=%i, size=%i, ptrout=%08x): invalid size", funcname, uid, size, addrPtr); error = SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE; return false; } - VERBOSE_LOG(SCEKERNEL, "%s(vpl=%i, size=%i, ptrout=%08x)", funcname, uid, size, addrPtr); + VERBOSE_LOG(Log::sceKernel, "%s(vpl=%i, size=%i, ptrout=%08x)", funcname, uid, size, addrPtr); // For some reason, try doesn't follow the same rules... if (!trying && (vpl->nv.attr & PSP_VPL_ATTR_MASK_ORDER) == PSP_VPL_ATTR_FIFO) @@ -1733,11 +1733,11 @@ int sceKernelTryAllocateVpl(SceUID uid, u32 size, u32 addrPtr) int sceKernelFreeVpl(SceUID uid, u32 addr) { if (addr && !Memory::IsValidAddress(addr)) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelFreeVpl(%i, %08x): Invalid address", SCE_KERNEL_ERROR_ILLEGAL_ADDR, uid, addr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelFreeVpl(%i, %08x): Invalid address", SCE_KERNEL_ERROR_ILLEGAL_ADDR, uid, addr); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } - VERBOSE_LOG(SCEKERNEL, "sceKernelFreeVpl(%i, %08x)", uid, addr); + VERBOSE_LOG(Log::sceKernel, "sceKernelFreeVpl(%i, %08x)", uid, addr); u32 error; VPL *vpl = kernelObjects.Get(uid, error); if (vpl) { @@ -1770,7 +1770,7 @@ retry: return 0; } else { - WARN_LOG(SCEKERNEL, "%08x=sceKernelFreeVpl(%i, %08x): Unable to free", SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK, uid, addr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelFreeVpl(%i, %08x): Unable to free", SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK, uid, addr); return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK; } } else { @@ -1784,7 +1784,7 @@ int sceKernelCancelVpl(SceUID uid, u32 numWaitThreadsPtr) VPL *vpl = kernelObjects.Get(uid, error); if (vpl) { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelVpl(%i, %08x)", uid, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelVpl(%i, %08x)", uid, numWaitThreadsPtr); vpl->nv.numWaitThreads = (int) vpl->waitingThreads.size(); if (Memory::IsValidAddress(numWaitThreadsPtr)) Memory::Write_U32(vpl->nv.numWaitThreads, numWaitThreadsPtr); @@ -1797,7 +1797,7 @@ int sceKernelCancelVpl(SceUID uid, u32 numWaitThreadsPtr) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelVpl(%i, %08x): invalid vpl", uid, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelVpl(%i, %08x): invalid vpl", uid, numWaitThreadsPtr); return error; } } @@ -1818,27 +1818,27 @@ int sceKernelReferVplStatus(SceUID uid, u32 infoPtr) { *info = vpl->nv; info.NotifyWrite("VplStatus"); } - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error, "invalid vpl"); + return hleLogError(Log::sceKernel, error, "invalid vpl"); } } static u32 AllocMemoryBlock(const char *pname, u32 type, u32 size, u32 paramsAddr) { if (Memory::IsValidAddress(paramsAddr) && Memory::Read_U32(paramsAddr) != 4) { - ERROR_LOG_REPORT(SCEKERNEL, "AllocMemoryBlock(%s): unsupported params size %d", pname, Memory::Read_U32(paramsAddr)); + ERROR_LOG_REPORT(Log::sceKernel, "AllocMemoryBlock(%s): unsupported params size %d", pname, Memory::Read_U32(paramsAddr)); return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; } if (type != PSP_SMEM_High && type != PSP_SMEM_Low) { - ERROR_LOG_REPORT(SCEKERNEL, "AllocMemoryBlock(%s): unsupported type %d", pname, type); + ERROR_LOG_REPORT(Log::sceKernel, "AllocMemoryBlock(%s): unsupported type %d", pname, type); return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE; } if (size == 0) { - WARN_LOG_REPORT(SCEKERNEL, "AllocMemoryBlock(%s): invalid size %x", pname, size); + WARN_LOG_REPORT(Log::sceKernel, "AllocMemoryBlock(%s): invalid size %x", pname, size); return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; } if (pname == NULL) { - ERROR_LOG_REPORT(SCEKERNEL, "AllocMemoryBlock(): NULL name"); + ERROR_LOG_REPORT(Log::sceKernel, "AllocMemoryBlock(): NULL name"); return SCE_KERNEL_ERROR_ERROR; } @@ -1846,17 +1846,17 @@ static u32 AllocMemoryBlock(const char *pname, u32 type, u32 size, u32 paramsAdd if (!block->IsValid()) { delete block; - ERROR_LOG(SCEKERNEL, "AllocMemoryBlock(%s, %i, %08x, %08x): allocation failed", pname, type, size, paramsAddr); + ERROR_LOG(Log::sceKernel, "AllocMemoryBlock(%s, %i, %08x, %08x): allocation failed", pname, type, size, paramsAddr); return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; } SceUID uid = kernelObjects.Create(block); - INFO_LOG(SCEKERNEL,"%08x=AllocMemoryBlock(SysMemUserForUser_FE707FDF)(%s, %i, %08x, %08x)", uid, pname, type, size, paramsAddr); + INFO_LOG(Log::sceKernel,"%08x=AllocMemoryBlock(SysMemUserForUser_FE707FDF)(%s, %i, %08x, %08x)", uid, pname, type, size, paramsAddr); return uid; } static u32 FreeMemoryBlock(u32 uid) { - INFO_LOG(SCEKERNEL, "FreeMemoryBlock(%08x)", uid); + INFO_LOG(Log::sceKernel, "FreeMemoryBlock(%08x)", uid); return kernelObjects.Destroy(uid); } @@ -1865,31 +1865,31 @@ static u32 GetMemoryBlockPtr(u32 uid, u32 addr) { PartitionMemoryBlock *block = kernelObjects.Get(uid, error); if (block) { - INFO_LOG(SCEKERNEL, "GetMemoryBlockPtr(%08x, %08x) = %08x", uid, addr, block->address); + INFO_LOG(Log::sceKernel, "GetMemoryBlockPtr(%08x, %08x) = %08x", uid, addr, block->address); Memory::Write_U32(block->address, addr); return 0; } else { - ERROR_LOG(SCEKERNEL, "GetMemoryBlockPtr(%08x, %08x) failed", uid, addr); + ERROR_LOG(Log::sceKernel, "GetMemoryBlockPtr(%08x, %08x) failed", uid, addr); return 0; } } static u32 SysMemUserForUser_D8DE5C1E() { // Called by Evangelion Jo and return 0 here to go in-game. - ERROR_LOG(SCEKERNEL,"UNIMPL SysMemUserForUser_D8DE5C1E()"); + ERROR_LOG(Log::sceKernel,"UNIMPL SysMemUserForUser_D8DE5C1E()"); return 0; } static u32 SysMemUserForUser_ACBD88CA() { - ERROR_LOG_REPORT_ONCE(SysMemUserForUser_ACBD88CA, SCEKERNEL, "UNIMPL SysMemUserForUser_ACBD88CA()"); + ERROR_LOG_REPORT_ONCE(SysMemUserForUser_ACBD88CA, Log::sceKernel, "UNIMPL SysMemUserForUser_ACBD88CA()"); return 0; } static u32 SysMemUserForUser_945E45DA() { // Called by Evangelion Jo and expected return 0 here. - ERROR_LOG_REPORT_ONCE(SysMemUserForUser945E45DA, SCEKERNEL, "UNIMPL SysMemUserForUser_945E45DA()"); + ERROR_LOG_REPORT_ONCE(SysMemUserForUser945E45DA, Log::sceKernel, "UNIMPL SysMemUserForUser_945E45DA()"); return 0; } @@ -2074,15 +2074,15 @@ void __KernelTlsplThreadEnd(SceUID threadID) SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 blockSize, u32 count, u32 optionsPtr) { if (!name) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "invalid name"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "invalid name"); if ((attr & ~PSP_TLSPL_ATTR_KNOWN) >= 0x100) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", attr); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", attr); if (partition < 1 || partition > 9 || partition == 7) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", partition); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", partition); BlockAllocator *allocator = BlockAllocatorFromID(partition); if (allocator == nullptr) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_PERM, "invalid partition %x", partition); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_PERM, "invalid partition %x", partition); // There's probably a simpler way to get this same basic formula... // This is based on results from a PSP. @@ -2092,7 +2092,7 @@ SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 block if (!illegalMemSize && (u64) count >= 0x100000000ULL / (((u64) blockSize + 3ULL) & ~3ULL)) illegalMemSize = true; if (illegalMemSize) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid blockSize/count"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid blockSize/count"); int index = -1; for (int i = 0; i < TLSPL_NUM_INDEXES; ++i) { @@ -2103,7 +2103,7 @@ SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 block } if (index == -1) - return hleLogWarning(SCEKERNEL, PSP_ERROR_TOO_MANY_TLSPL, "ran out of indexes for TLS pools"); + return hleLogWarning(Log::sceKernel, PSP_ERROR_TOO_MANY_TLSPL, "ran out of indexes for TLS pools"); // Unless otherwise specified, we align to 4 bytes (a mips word.) u32 alignment = 4; @@ -2114,7 +2114,7 @@ SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 block // Note that 0 intentionally is allowed. if ((alignment & (alignment - 1)) != 0) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "alignment is not a power of 2: %d", alignment); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "alignment is not a power of 2: %d", alignment); // This goes for 0, 1, and 2. Can't have less than 4 byte alignment. if (alignment < 4) alignment = 4; @@ -2130,7 +2130,7 @@ SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 block #endif if (blockPtr == (u32)-1) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "failed to allocate memory"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "failed to allocate memory"); TLSPL *tls = new TLSPL(); SceUID id = kernelObjects.Create(tls); @@ -2149,7 +2149,7 @@ SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 block tls->alignment = alignment; tls->usage.resize(count, 0); - return hleLogSuccessInfoI(SCEKERNEL, id); + return hleLogSuccessInfoI(Log::sceKernel, id); } int sceKernelDeleteTlspl(SceUID uid) @@ -2167,11 +2167,11 @@ int sceKernelDeleteTlspl(SceUID uid) if (inUse) { error = PSP_ERROR_TLSPL_IN_USE; - WARN_LOG(SCEKERNEL, "%08x=sceKernelDeleteTlspl(%08x): in use", error, uid); + WARN_LOG(Log::sceKernel, "%08x=sceKernelDeleteTlspl(%08x): in use", error, uid); return error; } - WARN_LOG(SCEKERNEL, "sceKernelDeleteTlspl(%08x)", uid); + WARN_LOG(Log::sceKernel, "sceKernelDeleteTlspl(%08x)", uid); for (SceUID threadID : tls->waitingThreads) HLEKernel::ResumeFromWait(threadID, WAITTYPE_TLSPL, uid, 0); @@ -2185,7 +2185,7 @@ int sceKernelDeleteTlspl(SceUID uid) kernelObjects.Destroy(uid); } else - ERROR_LOG(SCEKERNEL, "%08x=sceKernelDeleteTlspl(%08x): bad tlspl", error, uid); + ERROR_LOG(Log::sceKernel, "%08x=sceKernelDeleteTlspl(%08x): bad tlspl", error, uid); return error; } @@ -2204,23 +2204,23 @@ static bool FindTLSByIndex(TLSPL *possible, FindTLSByIndexArg *state) { int sceKernelGetTlsAddr(SceUID uid) { if (!__KernelIsDispatchEnabled() || __IsInInterrupt()) - return hleLogWarning(SCEKERNEL, 0, "dispatch disabled"); + return hleLogWarning(Log::sceKernel, 0, "dispatch disabled"); u32 error; TLSPL *tls = kernelObjects.Get(uid, error); if (!tls) { if (uid < 0) - return hleLogError(SCEKERNEL, 0, "tlspl not found"); + return hleLogError(Log::sceKernel, 0, "tlspl not found"); // There's this weird behavior where it looks up by index. Maybe we shouldn't use uids... if (!tlsplUsedIndexes[(uid >> 3) & 15]) - return hleLogError(SCEKERNEL, 0, "tlspl not found"); + return hleLogError(Log::sceKernel, 0, "tlspl not found"); FindTLSByIndexArg state; state.index = (uid >> 3) & 15; kernelObjects.Iterate(&FindTLSByIndex, &state); if (!state.result) - return hleLogError(SCEKERNEL, 0, "tlspl not found"); + return hleLogError(Log::sceKernel, 0, "tlspl not found"); tls = state.result; } @@ -2259,7 +2259,7 @@ int sceKernelGetTlsAddr(SceUID uid) { { tls->waitingThreads.push_back(threadID); __KernelWaitCurThread(WAITTYPE_TLSPL, uid, 1, 0, false, "allocate tls"); - return hleLogDebug(SCEKERNEL, 0, "waiting for tls alloc"); + return hleLogDebug(Log::sceKernel, 0, "waiting for tls alloc"); } u32 alignedSize = (tls->ntls.blockSize + tls->alignment - 1) & ~(tls->alignment - 1); @@ -2271,13 +2271,13 @@ int sceKernelGetTlsAddr(SceUID uid) { Memory::Memset(allocAddress, 0, tls->ntls.blockSize, "TlsAddr"); } - return hleLogDebug(SCEKERNEL, allocAddress); + return hleLogDebug(Log::sceKernel, allocAddress); } // Parameters are an educated guess. int sceKernelFreeTlspl(SceUID uid) { - WARN_LOG(SCEKERNEL, "UNIMPL sceKernelFreeTlspl(%08x)", uid); + WARN_LOG(Log::sceKernel, "UNIMPL sceKernelFreeTlspl(%08x)", uid); u32 error; TLSPL *tls = kernelObjects.Get(uid, error); if (tls) @@ -2302,9 +2302,9 @@ int sceKernelReferTlsplStatus(SceUID uid, u32 infoPtr) { *info = tls->ntls; info.NotifyWrite("TlsplStatus"); } - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error, "invalid tlspl"); + return hleLogError(Log::sceKernel, error, "invalid tlspl"); } } diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index bd61e25b75..dd0b7e0e0b 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -28,6 +28,8 @@ #include "Common/StringUtils.h" #include "Common/System/Request.h" #include "Common/System/System.h" +#include "Common/System/OSD.h" +#include "Common/Data/Text/I18n.h" #include "Core/Config.h" #include "Core/Core.h" @@ -363,7 +365,7 @@ public: } if (foundBroken) { - ERROR_LOG(LOADER, "Broken stub import data while loading state"); + ERROR_LOG(Log::Loader, "Broken stub import data while loading state"); } } @@ -384,11 +386,11 @@ public: void ImportFunc(const FuncSymbolImport &func, bool reimporting) { if (!Memory::IsValidAddress(func.stubAddr)) { - WARN_LOG_REPORT(LOADER, "Invalid address for syscall stub %s %08x", func.moduleName, func.nid); + WARN_LOG_REPORT(Log::Loader, "Invalid address for syscall stub %s %08x", func.moduleName, func.nid); return; } - DEBUG_LOG(LOADER, "Importing %s : %08x", GetFuncName(func.moduleName, func.nid), func.stubAddr); + DEBUG_LOG(Log::Loader, "Importing %s : %08x", GetFuncName(func.moduleName, func.nid), func.stubAddr); // Add the symbol to the symbol map for debugging. char temp[256]; @@ -560,7 +562,7 @@ void __KernelModuleDoState(PointerWrap &p) PSPModule *module = kernelObjects.Get(moduleId, error); if (module && module->libstub != 0) { if (!KernelImportModuleFuncs(module, nullptr, true)) { - ERROR_LOG(LOADER, "Something went wrong loading imports on load state"); + ERROR_LOG(Log::Loader, "Something went wrong loading imports on load state"); } } } @@ -598,7 +600,7 @@ static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 re switch (type) { case R_MIPS_NONE: - WARN_LOG_REPORT(LOADER, "Var relocation type NONE - %08x => %08x", exportAddress, relocAddress); + WARN_LOG_REPORT(Log::Loader, "Var relocation type NONE - %08x => %08x", exportAddress, relocAddress); break; case R_MIPS_32: @@ -613,7 +615,7 @@ static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 re /* case R_MIPS_26: if (exportAddress % 4 || (exportAddress >> 28) != ((relocAddress + 4) >> 28)) { - WARN_LOG_REPORT(LOADER, "Bad var relocation addresses for type 26 - %08x => %08x", exportAddress, relocAddress) + WARN_LOG_REPORT(Log::Loader, "Bad var relocation addresses for type 26 - %08x => %08x", exportAddress, relocAddress) } else { if (!reverse) { relocData = (relocData & ~0x03ffffff) | ((relocData + (exportAddress >> 2)) & 0x03ffffff); @@ -627,7 +629,7 @@ static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 re case R_MIPS_HI16: if (state.lastHI16ExportAddress != exportAddress) { if (!state.lastHI16Processed && !state.lastHI16Relocs.empty()) { - WARN_LOG_REPORT(LOADER, "Unsafe unpaired HI16 variable relocation @ %08x / %08x", state.lastHI16Relocs[state.lastHI16Relocs.size() - 1].addr, relocAddress); + WARN_LOG_REPORT(Log::Loader, "Unsafe unpaired HI16 variable relocation @ %08x / %08x", state.lastHI16Relocs[state.lastHI16Relocs.size() - 1].addr, relocAddress); } state.lastHI16ExportAddress = exportAddress; @@ -657,10 +659,10 @@ static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 re // The ABI requires that these come in pairs, at least. if (state.lastHI16Relocs.empty()) { - ERROR_LOG_REPORT(LOADER, "LO16 without any HI16 variable import at %08x for %08x", relocAddress, exportAddress); + ERROR_LOG_REPORT(Log::Loader, "LO16 without any HI16 variable import at %08x for %08x", relocAddress, exportAddress); // Try to process at least the low relocation... } else if (state.lastHI16ExportAddress != exportAddress) { - ERROR_LOG_REPORT(LOADER, "HI16 and LO16 imports do not match at %08x for %08x (should be %08x)", relocAddress, state.lastHI16ExportAddress, exportAddress); + ERROR_LOG_REPORT(Log::Loader, "HI16 and LO16 imports do not match at %08x for %08x (should be %08x)", relocAddress, state.lastHI16ExportAddress, exportAddress); } else { // Process each of the HI16. Usually there's only one. for (auto &reloc : state.lastHI16Relocs) { @@ -684,7 +686,7 @@ static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 re break; default: - WARN_LOG_REPORT(LOADER, "Unsupported var relocation type %d - %08x => %08x", type, exportAddress, relocAddress); + WARN_LOG_REPORT(Log::Loader, "Unsupported var relocation type %d - %08x => %08x", type, exportAddress, relocAddress); } Memory::Write_U32(relocData, relocAddress); @@ -694,12 +696,12 @@ static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 re void ImportVarSymbol(WriteVarSymbolState &state, const VarSymbolImport &var) { if (var.nid == 0) { // TODO: What's the right thing for this? - ERROR_LOG_REPORT(LOADER, "Var import with nid = 0, type = %d", var.type); + ERROR_LOG_REPORT(Log::Loader, "Var import with nid = 0, type = %d", var.type); return; } if (!Memory::IsValidAddress(var.stubAddr)) { - ERROR_LOG_REPORT(LOADER, "Invalid address for var import nid = %08x, type = %d, addr = %08x", var.nid, var.type, var.stubAddr); + ERROR_LOG_REPORT(Log::Loader, "Invalid address for var import nid = %08x, type = %d, addr = %08x", var.nid, var.type, var.stubAddr); return; } @@ -720,7 +722,7 @@ void ImportVarSymbol(WriteVarSymbolState &state, const VarSymbolImport &var) { } // It hasn't been exported yet, but hopefully it will later. - INFO_LOG(LOADER, "Variable (%s,%08x) unresolved, storing for later resolving", var.moduleName, var.nid); + INFO_LOG(Log::Loader, "Variable (%s,%08x) unresolved, storing for later resolving", var.moduleName, var.nid); } void ExportVarSymbol(const VarSymbolExport &var) { @@ -735,7 +737,7 @@ void ExportVarSymbol(const VarSymbolExport &var) { WriteVarSymbolState state; for (auto &imported : module->importedVars) { if (var.Matches(imported)) { - INFO_LOG(LOADER, "Resolving var %s/%08x", var.moduleName, var.nid); + INFO_LOG(Log::Loader, "Resolving var %s/%08x", var.moduleName, var.nid); WriteVarSymbol(state, var.symAddr, imported.stubAddr, imported.type); } } @@ -754,7 +756,7 @@ void UnexportVarSymbol(const VarSymbolExport &var) { WriteVarSymbolState state; for (auto &imported : module->importedVars) { if (var.Matches(imported)) { - INFO_LOG(LOADER, "Unresolving var %s/%08x", var.moduleName, var.nid); + INFO_LOG(Log::Loader, "Unresolving var %s/%08x", var.moduleName, var.nid); WriteVarSymbol(state, var.symAddr, imported.stubAddr, imported.type, true); } } @@ -766,11 +768,13 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting, const char // TODO: Or not? if (FuncImportIsSyscall(func.moduleName, func.nid)) { if (reimporting && Memory::Read_Instruction(func.stubAddr + 4) != GetSyscallOp(func.moduleName, func.nid)) { - WARN_LOG(LOADER, "Reimporting updated syscall %s", GetFuncName(func.moduleName, func.nid)); + WARN_LOG(Log::Loader, "Reimporting updated syscall %s", GetFuncName(func.moduleName, func.nid)); } WriteSyscall(func.moduleName, func.nid, func.stubAddr); currentMIPS->InvalidateICache(func.stubAddr, 8); - MIPSAnalyst::PrecompileFunction(func.stubAddr, 8); + if (g_Config.bPreloadFunctions) { + MIPSAnalyst::PrecompileFunction(func.stubAddr, 8); + } return; } @@ -785,11 +789,13 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting, const char for (auto it = module->exportedFuncs.begin(), end = module->exportedFuncs.end(); it != end; ++it) { if (it->Matches(func)) { if (reimporting && Memory::Read_Instruction(func.stubAddr) != MIPS_MAKE_J(it->symAddr)) { - WARN_LOG_REPORT(LOADER, "Reimporting: func import %s/%08x changed", func.moduleName, func.nid); + WARN_LOG_REPORT(Log::Loader, "Reimporting: func import %s/%08x changed", func.moduleName, func.nid); } WriteFuncStub(func.stubAddr, it->symAddr); currentMIPS->InvalidateICache(func.stubAddr, 8); - MIPSAnalyst::PrecompileFunction(func.stubAddr, 8); + if (g_Config.bPreloadFunctions) { + MIPSAnalyst::PrecompileFunction(func.stubAddr, 8); + } return; } } @@ -799,9 +805,9 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting, const char bool isKnownModule = GetModuleIndex(func.moduleName) != -1; if (isKnownModule) { // We used to report this, but I don't think it's very interesting anymore. - WARN_LOG(LOADER, "Unknown syscall from known module '%s': 0x%08x (import for '%s')", func.moduleName, func.nid, importingModule); + WARN_LOG(Log::Loader, "Unknown syscall from known module '%s': 0x%08x (import for '%s')", func.moduleName, func.nid, importingModule); } else { - INFO_LOG(LOADER, "Function (%s,%08x) unresolved in '%s', storing for later resolving", func.moduleName, func.nid, importingModule); + INFO_LOG(Log::Loader, "Function (%s,%08x) unresolved in '%s', storing for later resolving", func.moduleName, func.nid, importingModule); } if (isKnownModule || !reimporting) { WriteFuncMissingStub(func.stubAddr, func.nid); @@ -812,7 +818,7 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting, const char void ExportFuncSymbol(const FuncSymbolExport &func) { if (FuncImportIsSyscall(func.moduleName, func.nid)) { // HLE covers this already - let's ignore the function. - WARN_LOG(LOADER, "Ignoring func export %s/%08x, already implemented in HLE.", func.moduleName, func.nid); + WARN_LOG(Log::Loader, "Ignoring func export %s/%08x, already implemented in HLE.", func.moduleName, func.nid); return; } @@ -826,10 +832,12 @@ void ExportFuncSymbol(const FuncSymbolExport &func) { // Look for imports currently loaded modules already have, hook it up right away. for (auto it = module->importedFuncs.begin(), end = module->importedFuncs.end(); it != end; ++it) { if (func.Matches(*it)) { - INFO_LOG(LOADER, "Resolving function %s/%08x", func.moduleName, func.nid); + INFO_LOG(Log::Loader, "Resolving function %s/%08x", func.moduleName, func.nid); WriteFuncStub(it->stubAddr, func.symAddr); currentMIPS->InvalidateICache(it->stubAddr, 8); - MIPSAnalyst::PrecompileFunction(it->stubAddr, 8); + if (g_Config.bPreloadFunctions) { + MIPSAnalyst::PrecompileFunction(it->stubAddr, 8); + } } } } @@ -851,7 +859,7 @@ void UnexportFuncSymbol(const FuncSymbolExport &func) { // Look for imports modules that are *still* loaded have, and write back stubs. for (auto it = module->importedFuncs.begin(), end = module->importedFuncs.end(); it != end; ++it) { if (func.Matches(*it)) { - INFO_LOG(LOADER, "Unresolving function %s/%08x", func.moduleName, func.nid); + INFO_LOG(Log::Loader, "Unresolving function %s/%08x", func.moduleName, func.nid); WriteFuncMissingStub(it->stubAddr, it->nid); currentMIPS->InvalidateICache(it->stubAddr, 8); } @@ -872,7 +880,7 @@ void PSPModule::Cleanup() { } if (memoryBlockAddr != 0 && nm.text_addr != 0 && memoryBlockSize >= nm.data_size + nm.bss_size + nm.text_size) { - DEBUG_LOG(LOADER, "Zeroing out module %s memory: %08x - %08x", nm.name, memoryBlockAddr, memoryBlockAddr + memoryBlockSize); + DEBUG_LOG(Log::Loader, "Zeroing out module %s memory: %08x - %08x", nm.name, memoryBlockAddr, memoryBlockAddr + memoryBlockSize); u32 clearSize = Memory::ValidSize(nm.text_addr, (u32)nm.text_size + 3); for (u32 i = 0; i < clearSize; i += 4) { Memory::WriteUnchecked_U32(MIPS_MAKE_BREAK(1), nm.text_addr + i); @@ -887,12 +895,12 @@ void PSPModule::Cleanup() { static void SaveDecryptedEbootToStorageMedia(const u8 *decryptedEbootDataPtr, const u32 length, const char *name) { if (!decryptedEbootDataPtr) { - ERROR_LOG(SCEMODULE, "Error saving decrypted EBOOT.BIN: invalid pointer"); + ERROR_LOG(Log::sceModule, "Error saving decrypted EBOOT.BIN: invalid pointer"); return; } if (length == 0) { - ERROR_LOG(SCEMODULE, "Error saving decrypted EBOOT.BIN: invalid length"); + ERROR_LOG(Log::sceModule, "Error saving decrypted EBOOT.BIN: invalid length"); return; } @@ -900,23 +908,40 @@ static void SaveDecryptedEbootToStorageMedia(const u8 *decryptedEbootDataPtr, co const Path dumpDirectory = GetSysDirectory(DIRECTORY_DUMP); const Path fullPath = dumpDirectory / filenameToDumpTo; + auto s = GetI18NCategory(I18NCat::SYSTEM); + // If the file already exists, don't dump it again. if (File::Exists(fullPath)) { - INFO_LOG(SCEMODULE, "Decrypted EBOOT.BIN already exists for this game, skipping dump."); + INFO_LOG(Log::sceModule, "Decrypted EBOOT.BIN already exists for this game, skipping dump."); + + char *path = new char[strlen(fullPath.c_str()) + 1]; + strcpy(path, fullPath.c_str()); + + g_OSD.Show(OSDType::MESSAGE_INFO, s->T("Dump Decrypted Eboot"), fullPath.ToVisualString(), 5.0f, "decr"); + if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) { + g_OSD.SetClickCallback("decr", [](bool clicked, void *userdata) { + char *path = (char *)userdata; + if (clicked) { + System_ShowFileInFolder(Path(path)); + } else { + delete[] path; + } + }, path); + } return; } // Make sure the dump directory exists before continuing. if (!File::Exists(dumpDirectory)) { if (!File::CreateDir(dumpDirectory)) { - ERROR_LOG(SCEMODULE, "Unable to create directory for EBOOT dumping, aborting."); + ERROR_LOG(Log::sceModule, "Unable to create directory for EBOOT dumping, aborting."); return; } } FILE *decryptedEbootFile = File::OpenCFile(fullPath, "wb"); if (!decryptedEbootFile) { - ERROR_LOG(SCEMODULE, "Unable to write decrypted EBOOT."); + ERROR_LOG(Log::sceModule, "Unable to write decrypted EBOOT."); return; } @@ -924,7 +949,23 @@ static void SaveDecryptedEbootToStorageMedia(const u8 *decryptedEbootDataPtr, co fwrite(decryptedEbootDataPtr, sizeof(u8), lengthToWrite, decryptedEbootFile); fclose(decryptedEbootFile); - INFO_LOG(SCEMODULE, "Successfully wrote decrypted EBOOT to %s", fullPath.c_str()); + INFO_LOG(Log::sceModule, "Successfully wrote decrypted EBOOT to %s", fullPath.c_str()); + + char *path = new char[strlen(fullPath.c_str()) + 1]; + strcpy(path, fullPath.c_str()); + + // Re-suing the translation string here. + g_OSD.Show(OSDType::MESSAGE_SUCCESS, s->T("Dump Decrypted Eboot"), fullPath.ToVisualString(), 5.0f, "decr"); + if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) { + g_OSD.SetClickCallback("decr", [](bool clicked, void *userdata) { + char *path = (char *)userdata; + if (clicked) { + System_ShowFileInFolder(Path(path)); + } else { + delete[] path; + } + }, path); + } } static bool IsHLEVersionedModule(const char *name) { @@ -998,7 +1039,7 @@ static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, return false; } if (!Memory::IsValidRange(module->libstub, module->libstubend - module->libstub)) { - ERROR_LOG_REPORT(LOADER, "Garbage libstub address %08x or end %08x", module->libstub, module->libstubend); + ERROR_LOG_REPORT(Log::Loader, "Garbage libstub address %08x or end %08x", module->libstub, module->libstubend); return false; } @@ -1018,13 +1059,13 @@ static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, needReport = true; } - DEBUG_LOG(LOADER, "Importing Module %s, stubs at %08x", modulename, entry->firstSymAddr); + DEBUG_LOG(Log::Loader, "Importing Module %s, stubs at %08x", modulename, entry->firstSymAddr); if (entry->size != 5 && entry->size != 6) { if (entry->size != 7) { - WARN_LOG_REPORT(LOADER, "Unexpected module entry size %d", entry->size); + WARN_LOG_REPORT(Log::Loader, "Unexpected module entry size %d", entry->size); needReport = true; } else if (entry->extra != 0) { - WARN_LOG_REPORT(LOADER, "Unexpected module entry with non-zero 7th value %08x", entry->extra); + WARN_LOG_REPORT(Log::Loader, "Unexpected module entry with non-zero 7th value %08x", entry->extra); needReport = true; } } @@ -1036,7 +1077,7 @@ static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, // If nidData is 0, only variables are being imported. if (entry->numFuncs > 0 && entry->nidData != 0) { if (!Memory::IsValidAddress(entry->nidData)) { - ERROR_LOG_REPORT(LOADER, "Crazy nidData address %08x, skipping entire module", entry->nidData); + ERROR_LOG_REPORT(Log::Loader, "Crazy nidData address %08x, skipping entire module", entry->nidData); needReport = true; continue; } @@ -1057,7 +1098,7 @@ static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, if (firstImportStubAddr && (!*firstImportStubAddr || *firstImportStubAddr > (u32)entry->firstSymAddr)) *firstImportStubAddr = entry->firstSymAddr; } else if (entry->numFuncs > 0) { - WARN_LOG_REPORT(LOADER, "Module entry with %d imports but no valid address", entry->numFuncs); + WARN_LOG_REPORT(Log::Loader, "Module entry with %d imports but no valid address", entry->numFuncs); needReport = true; } @@ -1065,7 +1106,7 @@ static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, // We only reimport funcs, which can't be double-offset. if (entry->numVars > 0 && entry->varData != 0 && !reimporting) { if (!Memory::IsValidAddress(entry->varData)) { - ERROR_LOG_REPORT(LOADER, "Crazy varData address %08x, skipping rest of module", entry->varData); + ERROR_LOG_REPORT(Log::Loader, "Crazy varData address %08x, skipping rest of module", entry->varData); needReport = true; continue; } @@ -1078,7 +1119,7 @@ static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, u32 varRefsPtr = Memory::Read_U32(entry->varData + i * 8); u32 nid = Memory::Read_U32(entry->varData + i * 8 + 4); if (!Memory::IsValidAddress(varRefsPtr)) { - WARN_LOG_REPORT(LOADER, "Bad relocation list address for nid %08x in %s", nid, modulename); + WARN_LOG_REPORT(Log::Loader, "Bad relocation list address for nid %08x in %s", nid, modulename); continue; } @@ -1092,11 +1133,11 @@ static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, } } } else if (entry->numVars > 0 && !reimporting) { - WARN_LOG_REPORT(LOADER, "Module entry with %d var imports but no valid address", entry->numVars); + WARN_LOG_REPORT(Log::Loader, "Module entry with %d var imports but no valid address", entry->numVars); needReport = true; } - DEBUG_LOG(LOADER, "-------------------------------------------------------------"); + DEBUG_LOG(Log::Loader, "-------------------------------------------------------------"); } if (needReport) { @@ -1150,6 +1191,64 @@ static int gzipDecompress(u8 *OutBuffer, int OutBufferLength, u8 *InBuffer) { return stream.total_out; } +static void parsePrxLibInfo(const u8* ptr, u32 headerSize) { + // 0x0 - ~SCE + // 0x4 - the header's size + // At some offset (starting from 0x8) - the lib info + const u8 start = 0x8; + const u8 lib_info_size = 8 + 12 + 4; // The prefix, libname and version + + if (headerSize - start < lib_info_size) { + // That's very wrong! + WARN_LOG(Log::sceModule, "~SCE module, header too small (0x%x bytes) to fit a lib info", headerSize); + return; + } + + auto end = ptr + headerSize; + ptr += start; + while (*ptr == 0x0 && ptr < end) { + ++ptr; + } + + // Now that we have found the start, let's do one more check + if (end - ptr < lib_info_size) { + // That's very wrong! + WARN_LOG(Log::sceModule, "~SCE module, unexpected header (not an error)"); + return; + } + + // The lib info prefix looks like {'\', 'y', 'r', '=', '`', 'c', '`', '0'} (Big Endian) + const u64_le lib_info_prefix = 0x306063603D72795C; + + // 'ptr' can potentially be misaligned here so let's use a memcmp instead of dereferencing 8 bytes at 'ptr' + if (memcmp(ptr, &lib_info_prefix, 8) != 0) { + // That's very wrong! + WARN_LOG(Log::sceModule, "~SCE module, unexpected header (not an error)"); + return; + } + ptr += sizeof(lib_info_prefix); + + // Decipher the Caesar cipher with sanity checks (isprint) + + u8 nameBuffer[12 + 1]; + for (int i = 0; i < 12; ++i, ++ptr) { + u8 symbol = *ptr - 0x12u; + nameBuffer[i] = isprint(symbol) ? symbol : '?'; + } + nameBuffer[12] = '\0'; + + u8 versionBuffer[7 + 1] = "?.?.?.?"; + for (int i = 0; i < 4; ++i, ++ptr) { + u8 symbol = *ptr - 0x14u; + if (isprint(symbol)) { + versionBuffer[2 * i] = symbol; + } + } + // The null byte is already in its place, no need to assign it manually + + INFO_LOG(Log::sceModule, "~SCE module: Lib-PSP %s (SDK %s)", nameBuffer, versionBuffer); +} + static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAddress, bool fromTop, std::string *error_string, u32 *magic, u32 &error) { PSPModule *module = new PSPModule(); kernelObjects.Create(module); @@ -1164,23 +1263,30 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load u8 *newptr = 0; u32_le *magicPtr = (u32_le *) ptr; if (*magicPtr == 0x4543537e) { // "~SCE" - INFO_LOG(SCEMODULE, "~SCE module, skipping header"); + u32 headerSize = *(u32_le*)(ptr + 4); if (headerSize < elfSize) { + // Parse and print the lib info + parsePrxLibInfo(ptr, headerSize); + + // Advance the pointer to the relevant data ptr += headerSize; elfSize -= headerSize; magicPtr = (u32_le *)ptr; } + else { + ERROR_LOG(Log::sceModule, "~SCE module: bad data"); + } } *magic = *magicPtr; if (*magic == 0x5053507e && elfSize > sizeof(PSP_Header)) { // "~PSP" - DEBUG_LOG(SCEMODULE, "Decrypting ~PSP file"); + DEBUG_LOG(Log::sceModule, "Decrypting ~PSP file"); PSP_Header *head = (PSP_Header*)ptr; devkitVersion = head->devkitversion; if (IsHLEVersionedModule(head->modname)) { int ver = (head->module_ver_hi << 8) | head->module_ver_lo; - INFO_LOG(SCEMODULE, "Loading module %s with version %04x, devkit %08x, crc %x", head->modname, ver, head->devkitversion, module->crc); + INFO_LOG(Log::sceModule, "Loading module %s with version %04x, devkit %08x, crc %x", head->modname, ver, head->devkitversion, module->crc); reportedModule = true; if (!strcmp(head->modname, "sceMpeg_library")) { @@ -1251,7 +1357,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load return module; } else if (ret <= 0) { - ERROR_LOG(SCEMODULE, "Failed decrypting PRX! That's not normal! ret = %i\n", ret); + ERROR_LOG(Log::sceModule, "Failed decrypting PRX! That's not normal! ret = %i\n", ret); Reporting::ReportMessage("Failed decrypting the PRX (ret = %i, size = %i, psp_size = %i)!", ret, head->elf_size, head->psp_size); // Fall through to safe exit in the next check. } else { @@ -1279,7 +1385,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load // DO NOT change to else if, see above. if (*magicPtr != 0x464c457f) { - ERROR_LOG(SCEMODULE, "Wrong magic number %08x", *magicPtr); + ERROR_LOG(Log::sceModule, "Wrong magic number %08x", *magicPtr); *error_string = "File corrupt"; if (newptr) delete [] newptr; @@ -1294,7 +1400,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load int result = reader.LoadInto(loadAddress, fromTop); if (result != SCE_KERNEL_ERROR_OK) { - ERROR_LOG(SCEMODULE, "LoadInto failed with error %08x",result); + ERROR_LOG(Log::sceModule, "LoadInto failed with error %08x",result); if (newptr) delete [] newptr; module->Cleanup(); @@ -1319,7 +1425,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load if (!Memory::IsValidAddress(modinfoaddr)) { *error_string = StringFromFormat("Bad module info address %08x", modinfoaddr); - ERROR_LOG(SCEMODULE, "Bad module info address %08x", modinfoaddr); + ERROR_LOG(Log::sceModule, "Bad module info address %08x", modinfoaddr); if (newptr) delete[] newptr; module->Cleanup(); @@ -1386,8 +1492,8 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load module->libstub = modinfo->libstub; module->libstubend = modinfo->libstubend; - INFO_LOG(LOADER, "Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent, modinfo->libstub); - DEBUG_LOG(LOADER,"==================================================="); + INFO_LOG(Log::Loader, "Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent, modinfo->libstub); + DEBUG_LOG(Log::Loader,"==================================================="); u32 firstImportStubAddr = 0; KernelImportModuleFuncs(module, &firstImportStubAddr); @@ -1418,7 +1524,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load continue; } if (!Memory::IsValidRange(start, len)) { - ERROR_LOG(LOADER, "Bad section %08x (len %08x) of section %d", start, len, id); + ERROR_LOG(Log::Loader, "Bad section %08x (len %08x) of section %d", start, len, id); continue; } @@ -1449,7 +1555,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load } insertSymbols = MIPSAnalyst::ScanForFunctions(scanStart, scanEnd, insertSymbols); } else { - ERROR_LOG(LOADER, "Bad text scan range %08x-%08x", scanStart, scanEnd); + ERROR_LOG(Log::Loader, "Bad text scan range %08x-%08x", scanStart, scanEnd); } } @@ -1486,7 +1592,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load const PspLibEntEntry *ent = (const PspLibEntEntry *)entPos; entPos += ent->size; if (ent->size == 0) { - WARN_LOG_REPORT(LOADER, "Invalid export entry size %d", ent->size); + WARN_LOG_REPORT(Log::Loader, "Invalid export entry size %d", ent->size); entPos += 4; continue; } @@ -1501,11 +1607,11 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load name = "invalid?"; } - INFO_LOG(LOADER, "Exporting ent %d named %s, %d funcs, %d vars, resident %08x", m, name, ent->fcount, ent->vcount, ent->resident); + INFO_LOG(Log::Loader, "Exporting ent %d named %s, %d funcs, %d vars, resident %08x", m, name, ent->fcount, ent->vcount, ent->resident); if (!Memory::IsValidAddress(ent->resident)) { if (ent->fcount + variableCount > 0) { - WARN_LOG_REPORT(LOADER, "Invalid export resident address %08x", ent->resident); + WARN_LOG_REPORT(Log::Loader, "Invalid export resident address %08x", ent->resident); } continue; } @@ -1514,7 +1620,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load u32_le *exportPtr = residentPtr + ent->fcount + variableCount; if (ent->size != 4 && ent->unknown1 != 0 && ent->unknown2 != 0) { - WARN_LOG_REPORT(LOADER, "Unexpected export module entry size %d, vcountNew=%08x, unknown1=%08x, unknown2=%08x", ent->size, ent->vcountNew, ent->unknown1, ent->unknown2); + WARN_LOG_REPORT(Log::Loader, "Unexpected export module entry size %d, vcountNew=%08x, unknown1=%08x, unknown2=%08x", ent->size, ent->vcountNew, ent->unknown1, ent->unknown2); } FuncSymbolExport func; @@ -1545,7 +1651,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load func.nid = nid; func.symAddr = exportAddr; if (ent->name == 0) { - WARN_LOG_REPORT(HLE, "Exporting func from syslib export: %08x", nid); + WARN_LOG_REPORT(Log::HLE, "Exporting func from syslib export: %08x", nid); } module->ExportFunc(func); } @@ -1569,7 +1675,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load if (size == 0) break; else if (size != 3) - WARN_LOG_REPORT(LOADER, "Strange value at module_start_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); + WARN_LOG_REPORT(Log::Loader, "Strange value at module_start_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); module->nm.module_start_thread_priority = Memory::Read_U32(exportAddr + 4); module->nm.module_start_thread_stacksize = Memory::Read_U32(exportAddr + 8); module->nm.module_start_thread_attr = Memory::Read_U32(exportAddr + 12); @@ -1579,7 +1685,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load if (size == 0) break; else if (size != 3) - WARN_LOG_REPORT(LOADER, "Strange value at module_stop_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); + WARN_LOG_REPORT(Log::Loader, "Strange value at module_stop_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); module->nm.module_stop_thread_priority = Memory::Read_U32(exportAddr + 4); module->nm.module_stop_thread_stacksize = Memory::Read_U32(exportAddr + 8); module->nm.module_stop_thread_attr = Memory::Read_U32(exportAddr + 12); @@ -1589,20 +1695,20 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load if (size == 0) break; else if (size != 3) - WARN_LOG_REPORT(LOADER, "Strange value at module_reboot_before_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); + WARN_LOG_REPORT(Log::Loader, "Strange value at module_reboot_before_thread_parameter export: %08x", Memory::Read_U32(exportAddr)); module->nm.module_reboot_before_thread_priority = Memory::Read_U32(exportAddr + 4); module->nm.module_reboot_before_thread_stacksize = Memory::Read_U32(exportAddr + 8); module->nm.module_reboot_before_thread_attr = Memory::Read_U32(exportAddr + 12); break; case NID_MODULE_SDK_VERSION: - DEBUG_LOG(LOADER, "Module SDK: %08x", Memory::Read_U32(exportAddr)); + DEBUG_LOG(Log::Loader, "Module SDK: %08x", Memory::Read_U32(exportAddr)); devkitVersion = Memory::Read_U32(exportAddr); break; default: var.nid = nid; var.symAddr = exportAddr; if (ent->name == 0) { - WARN_LOG_REPORT(HLE, "Exporting var from syslib export: %08x", nid); + WARN_LOG_REPORT(Log::HLE, "Exporting var from syslib export: %08x", nid); } module->ExportVar(var); break; @@ -1627,7 +1733,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load delete [] newptr; if (!reportedModule && IsHLEVersionedModule(modinfo->name)) { - INFO_LOG(SCEMODULE, "Loading module %s with version %04x, devkit %08x", modinfo->name, modinfo->moduleVersion, devkitVersion); + INFO_LOG(Log::sceModule, "Loading module %s with version %04x, devkit %08x", modinfo->name, modinfo->moduleVersion, devkitVersion); if (!strcmp(modinfo->name, "sceMpeg_library")) { __MpegLoadModule(modinfo->moduleVersion, module->crc); @@ -1705,7 +1811,7 @@ static PSPModule *__KernelLoadModule(u8 *fileptr, size_t fileSize, SceKernelLMOp temp = new u8[elfSize]; memcpy(temp, fileptr + offsets[5], elfSize); - INFO_LOG(LOADER, "PBP: ELF unaligned (%d: %d), aligning!", offsets[5], offsets[5] & 3); + INFO_LOG(Log::Loader, "PBP: ELF unaligned (%d: %d), aligning!", offsets[5], offsets[5] & 3); } u32 error; @@ -1731,7 +1837,7 @@ static void __KernelStartModule(PSPModule *m, int args, const char *argp, SceKer if (m->nm.module_start_func != 0 && m->nm.module_start_func != (u32)-1) { if (m->nm.module_start_func != m->nm.entry_addr) - WARN_LOG_REPORT(LOADER, "Main module has start func (%08x) different from entry (%08x)?", m->nm.module_start_func, m->nm.entry_addr); + WARN_LOG_REPORT(Log::Loader, "Main module has start func (%08x) different from entry (%08x)?", m->nm.module_start_func, m->nm.entry_addr); // TODO: Should we try to run both? currentMIPS->pc = m->nm.module_start_func; } @@ -1777,7 +1883,7 @@ void __KernelLoadReset() { module->Cleanup(); } else { // An invalid module. We need to remove it or we'll loop forever. - WARN_LOG(LOADER, "Invalid module still marked as loaded on loadexec"); + WARN_LOG(Log::Loader, "Invalid module still marked as loaded on loadexec"); loadedModules.erase(moduleID); } } @@ -1814,7 +1920,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str } if (param.keyp != 0) { u32 keyAddr = param.keyp; - size_t keylen = strlen(Memory::GetCharPointer(keyAddr))+1; + size_t keylen = strlen(Memory::GetCharPointer(keyAddr)) + 1; param_key = new u8[keylen]; Memory::Memcpy(param_key, keyAddr, (u32)keylen, "KernelLoadParam"); } @@ -1823,7 +1929,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str std::vector fileData; if (pspFileSystem.ReadEntireFile(filename, fileData) < 0) { - ERROR_LOG(LOADER, "Failed to load executable %s - file doesn't exist", filename); + ERROR_LOG(Log::Loader, "Failed to load executable %s - file doesn't exist", filename); *error_string = StringFromFormat("Could not find executable %s", filename); delete[] param_argp; delete[] param_key; @@ -1840,7 +1946,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str module->Cleanup(); kernelObjects.Destroy(module->GetUID()); } - ERROR_LOG(LOADER, "Failed to load module %s", filename); + ERROR_LOG(Log::Loader, "Failed to load module %s", filename); *error_string = "Failed to load executable: " + *error_string; delete[] param_argp; delete[] param_key; @@ -1854,7 +1960,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str mipsr4k.pc = module->nm.entry_addr; - INFO_LOG(LOADER, "Module entry: %08x (%s %04x)", mipsr4k.pc, moduleName, moduleVersion); + INFO_LOG(Log::Loader, "Module entry: %08x (%s %04x)", mipsr4k.pc, moduleName, moduleVersion); SceKernelSMOption option; option.size = sizeof(SceKernelSMOption); @@ -1934,7 +2040,7 @@ void __KernelGPUReplay() { // Special ABI: s0 and s1 are the "args". Not null terminated. const char *filenamep = Memory::GetCharPointer(currentMIPS->r[MIPS_REG_S1]); if (!filenamep) { - ERROR_LOG(G3D, "Failed to load dump filename"); + ERROR_LOG(Log::G3D, "Failed to load dump filename"); Core_Stop(); return; } @@ -1970,20 +2076,20 @@ int sceKernelLoadExec(const char *filename, u32 paramPtr) } if (!info.exists) { - ERROR_LOG(LOADER, "sceKernelLoadExec(%s, ...): File does not exist", filename); + ERROR_LOG(Log::Loader, "sceKernelLoadExec(%s, ...): File does not exist", filename); return SCE_KERNEL_ERROR_NOFILE; } s64 size = (s64)info.size; if (!size) { - ERROR_LOG(LOADER, "sceKernelLoadExec(%s, ...): File is size 0", filename); + ERROR_LOG(Log::Loader, "sceKernelLoadExec(%s, ...): File is size 0", filename); return SCE_KERNEL_ERROR_ILLEGAL_OBJECT; } - DEBUG_LOG(SCEMODULE, "sceKernelLoadExec(name=%s,...): loading %s", filename, exec_filename.c_str()); + DEBUG_LOG(Log::sceModule, "sceKernelLoadExec(name=%s,...): loading %s", filename, exec_filename.c_str()); std::string error_string; if (!__KernelLoadExec(exec_filename.c_str(), paramPtr, &error_string)) { - ERROR_LOG(SCEMODULE, "sceKernelLoadExec failed: %s", error_string.c_str()); + ERROR_LOG(Log::sceModule, "sceKernelLoadExec failed: %s", error_string.c_str()); Core_UpdateState(CORE_RUNTIME_ERROR); return -1; } @@ -1995,7 +2101,7 @@ int sceKernelLoadExec(const char *filename, u32 paramPtr) u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { if (!name) { - return hleLogError(LOADER, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad filename"); + return hleLogError(Log::Loader, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad filename"); } for (size_t i = 0; i < ARRAY_SIZE(lieAboutSuccessModules); i++) { @@ -2021,42 +2127,42 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { // TODO: It would be more ideal to allocate memory for this module. - return hleLogSuccessInfoI(LOADER, module->GetUID(), "created fake module"); + return hleLogSuccessInfoI(Log::Loader, module->GetUID(), "created fake module"); } } std::vector fileData; if (pspFileSystem.ReadEntireFile(name, fileData) < 0) { - const u32 error = hleLogError(LOADER, SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "file does not exist"); + const u32 error = hleLogError(Log::Loader, SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND, "file does not exist"); return hleDelayResult(error, "module loaded", 500); } if (fileData.empty()) { - const u32 error = hleLogError(LOADER, SCE_KERNEL_ERROR_FILEERR, "module file size is 0"); + const u32 error = hleLogError(Log::Loader, SCE_KERNEL_ERROR_FILEERR, "module file size is 0"); return hleDelayResult(error, "module loaded", 500); } // We log before hand because ELF loading logs a bunch. - DEBUG_LOG(LOADER, "sceKernelLoadModule(%s, %08x)", name, flags); + DEBUG_LOG(Log::Loader, "sceKernelLoadModule(%s, %08x)", name, flags); if (flags != 0) { - WARN_LOG_REPORT(LOADER, "sceKernelLoadModule: unsupported flags: %08x", flags); + WARN_LOG_REPORT(Log::Loader, "sceKernelLoadModule: unsupported flags: %08x", flags); } SceKernelLMOption *lmoption = 0; if (optionAddr) { lmoption = (SceKernelLMOption *)Memory::GetPointer(optionAddr); if (lmoption->position < PSP_SMEM_Low || lmoption->position > PSP_SMEM_HighAligned) { - ERROR_LOG_REPORT(LOADER, "sceKernelLoadModule(%s): invalid position (%i)", name, (int)lmoption->position); + ERROR_LOG_REPORT(Log::Loader, "sceKernelLoadModule(%s): invalid position (%i)", name, (int)lmoption->position); return hleDelayResult(SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE, "module loaded", 500); } if (lmoption->position == PSP_SMEM_LowAligned || lmoption->position == PSP_SMEM_HighAligned) { - ERROR_LOG_REPORT(LOADER, "sceKernelLoadModule(%s): invalid position (aligned)", name); + ERROR_LOG_REPORT(Log::Loader, "sceKernelLoadModule(%s): invalid position (aligned)", name); return hleDelayResult(SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT_SIZE, "module loaded", 500); } if (lmoption->position == PSP_SMEM_Addr) { - ERROR_LOG_REPORT(LOADER, "sceKernelLoadModule(%s): invalid position (fixed)", name); + ERROR_LOG_REPORT(Log::Loader, "sceKernelLoadModule(%s): invalid position (fixed)", name); return hleDelayResult(SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED, "module loaded", 500); } - WARN_LOG_REPORT(LOADER, "sceKernelLoadModule: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d", lmoption->size, lmoption->flags, lmoption->position, lmoption->access, lmoption->mpiddata, lmoption->mpidtext); + WARN_LOG_REPORT(Log::Loader, "sceKernelLoadModule: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d", lmoption->size, lmoption->flags, lmoption->position, lmoption->access, lmoption->mpiddata, lmoption->mpidtext); } PSPModule *module = nullptr; @@ -2067,7 +2173,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { if (!module) { if (magic == 0x46535000) { - ERROR_LOG(LOADER, "Game tried to load an SFO as a module. Go figure? Magic = %08x", magic); + ERROR_LOG(Log::Loader, "Game tried to load an SFO as a module. Go figure? Magic = %08x", magic); // TODO: What's actually going on here? error = -1; return hleDelayResult(error, "module loaded", 500); @@ -2075,7 +2181,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { PSPFileInfo info = pspFileSystem.GetFileInfo(name); if (info.name == "BOOT.BIN") { - NOTICE_LOG_REPORT(LOADER, "Module %s is blacklisted or undecryptable - we try __KernelLoadExec", name); + NOTICE_LOG_REPORT(Log::Loader, "Module %s is blacklisted or undecryptable - we try __KernelLoadExec", name); // Name might get deleted. const std::string safeName = name; if (gpu) { @@ -2083,17 +2189,17 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { } return __KernelLoadExec(safeName.c_str(), 0, &error_string); } else { - hleLogError(LOADER, error, "failed to load"); + hleLogError(Log::Loader, error, "failed to load"); return hleDelayResult(error, "module loaded", 500); } } if (lmoption) { - INFO_LOG(SCEMODULE,"%i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,position = %08x)", + INFO_LOG(Log::sceModule,"%i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,position = %08x)", module->GetUID(),name,flags, lmoption->size,lmoption->mpidtext,lmoption->mpiddata,lmoption->position); } else { - INFO_LOG(SCEMODULE,"%i=sceKernelLoadModule(name=%s,flag=%08x,(...))", module->GetUID(), name, flags); + INFO_LOG(Log::sceModule,"%i=sceKernelLoadModule(name=%s,flag=%08x,(...))", module->GetUID(), name, flags); } // TODO: This is not the right timing and probably not the right wait type, just an approximation. @@ -2102,7 +2208,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { static u32 sceKernelLoadModuleNpDrm(const char *name, u32 flags, u32 optionAddr) { - DEBUG_LOG(LOADER, "sceKernelLoadModuleNpDrm(%s, %08x)", name, flags); + DEBUG_LOG(Log::Loader, "sceKernelLoadModuleNpDrm(%s, %08x)", name, flags); return sceKernelLoadModule(name, flags, optionAddr); } @@ -2152,10 +2258,10 @@ int KernelStartModule(SceUID moduleId, u32 argsize, u32 argAddr, u32 returnValue *needsWait = true; } } else if (entryAddr == 0 || entryAddr == (u32)-1) { - INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x): no entry address", moduleId, argsize, argAddr, returnValueAddr); + INFO_LOG(Log::sceModule, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x): no entry address", moduleId, argsize, argAddr, returnValueAddr); module->nm.status = MODULE_STATUS_STARTED; } else { - ERROR_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x): invalid entry address", moduleId, argsize, argAddr, returnValueAddr); + ERROR_LOG(Log::sceModule, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x): invalid entry address", moduleId, argsize, argAddr, returnValueAddr); return -1; } @@ -2167,25 +2273,25 @@ static void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 ret u32 error; PSPModule *module = kernelObjects.Get(moduleId, error); if (!module) { - INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): error %08x", moduleId, argsize, argAddr, returnValueAddr, optionAddr, error); + INFO_LOG(Log::sceModule, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): error %08x", moduleId, argsize, argAddr, returnValueAddr, optionAddr, error); RETURN(error); return; } else if (module->isFake) { - INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): faked (undecryptable module)", + INFO_LOG(Log::sceModule, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): faked (undecryptable module)", moduleId,argsize,argAddr,returnValueAddr,optionAddr); if (returnValueAddr) Memory::Write_U32(0, returnValueAddr); RETURN(moduleId); return; } else if (module->nm.status == MODULE_STATUS_STARTED) { - ERROR_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x) : already started", + ERROR_LOG(Log::sceModule, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x) : already started", moduleId,argsize,argAddr,returnValueAddr,optionAddr); // TODO: Maybe should be SCE_KERNEL_ERROR_ALREADY_STARTED, but I get SCE_KERNEL_ERROR_ERROR. // But I also get crashes... RETURN(SCE_KERNEL_ERROR_ERROR); return; } else { - INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)", + INFO_LOG(Log::sceModule, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)", moduleId,argsize,argAddr,returnValueAddr,optionAddr); bool needsWait; @@ -2216,20 +2322,20 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur PSPModule *module = kernelObjects.Get(moduleId, error); if (!module) { - ERROR_LOG(SCEMODULE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): invalid module id", moduleId, argSize, argAddr, returnValueAddr, optionAddr); + ERROR_LOG(Log::sceModule, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): invalid module id", moduleId, argSize, argAddr, returnValueAddr, optionAddr); return error; } if (module->isFake) { - INFO_LOG(SCEMODULE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x) - faking", moduleId, argSize, argAddr, returnValueAddr, optionAddr); + INFO_LOG(Log::sceModule, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x) - faking", moduleId, argSize, argAddr, returnValueAddr, optionAddr); if (returnValueAddr) Memory::Write_U32(0, returnValueAddr); return 0; } if (module->nm.status != MODULE_STATUS_STARTED) { - ERROR_LOG(SCEMODULE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): already stopped", moduleId, argSize, argAddr, returnValueAddr, optionAddr); + ERROR_LOG(Log::sceModule, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): already stopped", moduleId, argSize, argAddr, returnValueAddr, optionAddr); return SCE_KERNEL_ERROR_ALREADY_STOPPED; } @@ -2254,7 +2360,7 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur attr = options->attribute; // TODO: Maybe based on size? else if (attr != 0) - WARN_LOG_REPORT(SCEMODULE, "Stopping module with attr=%x, but options specify 0", attr); + WARN_LOG_REPORT(Log::sceModule, "Stopping module with attr=%x, but options specify 0", attr); } if (Memory::IsValidAddress(stopFunc)) @@ -2270,12 +2376,12 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur } else if (stopFunc == 0) { - INFO_LOG(SCEMODULE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): no stop func, skipping", moduleId, argSize, argAddr, returnValueAddr, optionAddr); + INFO_LOG(Log::sceModule, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): no stop func, skipping", moduleId, argSize, argAddr, returnValueAddr, optionAddr); module->nm.status = MODULE_STATUS_STOPPED; } else { - ERROR_LOG_REPORT(SCEMODULE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): bad stop func address", moduleId, argSize, argAddr, returnValueAddr, optionAddr); + ERROR_LOG_REPORT(Log::sceModule, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): bad stop func address", moduleId, argSize, argAddr, returnValueAddr, optionAddr); module->nm.status = MODULE_STATUS_STOPPED; } @@ -2284,7 +2390,7 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur static u32 sceKernelUnloadModule(u32 moduleId) { - INFO_LOG(SCEMODULE,"sceKernelUnloadModule(%i)", moduleId); + INFO_LOG(Log::sceModule,"sceKernelUnloadModule(%i)", moduleId); u32 error; PSPModule *module = kernelObjects.Get(moduleId, error); if (!module) @@ -2297,10 +2403,13 @@ static u32 sceKernelUnloadModule(u32 moduleId) u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, u32 argp, u32 statusAddr, u32 optionAddr, bool WithStatus) { if (loadedModules.size() > 1) { - if (WithStatus) - ERROR_LOG_REPORT(SCEMODULE, "UNIMPL sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): game may have crashed", exitCode, argSize, argp, statusAddr, optionAddr); - else - ERROR_LOG_REPORT(SCEMODULE, "UNIMPL sceKernelSelfStopUnloadModule(%08x, %08x, %08x): game may have crashed", exitCode, argSize, argp); + if (WithStatus) { + ERROR_LOG_REPORT(Log::sceModule, "UNIMPL sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): game may have crashed", exitCode, argSize, argp, statusAddr, optionAddr); + } else { + // NOTE: The previous "may have crashed" message is not accurate, Splinter Cell Essentials uses this normally when leaving/entering in-game. + // We should not report this. + WARN_LOG(Log::sceModule, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x)", exitCode, argSize, argp); + } SceUID moduleID = __KernelGetCurThreadModuleId(); u32 priority = 0x20; u32 stacksize = 0x40000; @@ -2311,10 +2420,9 @@ u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, PSPModule *module = kernelObjects.Get(moduleID, error); if (!module) { if (WithStatus) - ERROR_LOG(SCEMODULE, "sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): invalid module id", exitCode, argSize, argp, statusAddr, optionAddr); + ERROR_LOG(Log::sceModule, "sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): invalid module id", exitCode, argSize, argp, statusAddr, optionAddr); else - ERROR_LOG(SCEMODULE, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x): invalid module id", exitCode, argSize, argp); - + ERROR_LOG(Log::sceModule, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x): invalid module id", exitCode, argSize, argp); return error; } @@ -2338,7 +2446,7 @@ u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, attr = options->attribute; // TODO: Maybe based on size? else if (attr != 0) - WARN_LOG_REPORT(SCEMODULE, "Stopping module with attr=%x, but options specify 0", attr); + WARN_LOG_REPORT(Log::sceModule, "Stopping module with attr=%x, but options specify 0", attr); } if (Memory::IsValidAddress(stopFunc)) { @@ -2352,26 +2460,26 @@ u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, module->waitingThreads.push_back(mwt); } else if (stopFunc == 0) { if (WithStatus) - INFO_LOG(SCEMODULE, "sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): no stop func", exitCode, argSize, argp, statusAddr, optionAddr); + INFO_LOG(Log::sceModule, "sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): no stop func", exitCode, argSize, argp, statusAddr, optionAddr); else - INFO_LOG(SCEMODULE, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x): no stop func", exitCode, argSize, argp); + INFO_LOG(Log::sceModule, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x): no stop func", exitCode, argSize, argp); sceKernelExitDeleteThread(exitCode); module->Cleanup(); kernelObjects.Destroy(moduleID); } else { if (WithStatus) - ERROR_LOG_REPORT(SCEMODULE, "sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): bad stop func address", exitCode, argSize, argp, statusAddr, optionAddr); + ERROR_LOG_REPORT(Log::sceModule, "sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): bad stop func address", exitCode, argSize, argp, statusAddr, optionAddr); else - ERROR_LOG_REPORT(SCEMODULE, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x): bad stop func address", exitCode, argSize, argp); + ERROR_LOG_REPORT(Log::sceModule, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x): bad stop func address", exitCode, argSize, argp); sceKernelExitDeleteThread(exitCode); module->Cleanup(); kernelObjects.Destroy(moduleID); } } else { if (WithStatus) - ERROR_LOG_REPORT(SCEMODULE, "UNIMPL sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): game has likely crashed", exitCode, argSize, argp, statusAddr, optionAddr); + ERROR_LOG_REPORT(Log::sceModule, "UNIMPL sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): game has likely crashed", exitCode, argSize, argp, statusAddr, optionAddr); else - ERROR_LOG_REPORT(SCEMODULE, "UNIMPL sceKernelSelfStopUnloadModule(%08x, %08x, %08x): game has likely crashed", exitCode, argSize, argp); + ERROR_LOG_REPORT(Log::sceModule, "UNIMPL sceKernelSelfStopUnloadModule(%08x, %08x, %08x): game has likely crashed", exitCode, argSize, argp); } return 0; @@ -2403,7 +2511,7 @@ void __KernelReturnFromModuleFunc() u32 error; PSPModule *module = kernelObjects.Get(leftModuleID, error); if (!module) { - ERROR_LOG_REPORT(SCEMODULE, "Returned from deleted module start/stop func"); + ERROR_LOG_REPORT(Log::sceModule, "Returned from deleted module start/stop func"); return; } @@ -2458,16 +2566,15 @@ static u32 sceKernelGetModuleIdByAddress(u32 moduleAddr) kernelObjects.Iterate(&__GetModuleIdByAddressIterator, &state); if (state.result == (SceUID)SCE_KERNEL_ERROR_UNKNOWN_MODULE) - ERROR_LOG(SCEMODULE, "sceKernelGetModuleIdByAddress(%08x): module not found", moduleAddr); + ERROR_LOG(Log::sceModule, "sceKernelGetModuleIdByAddress(%08x): module not found", moduleAddr); else - DEBUG_LOG(SCEMODULE, "%x=sceKernelGetModuleIdByAddress(%08x)", state.result, moduleAddr); + DEBUG_LOG(Log::sceModule, "%x=sceKernelGetModuleIdByAddress(%08x)", state.result, moduleAddr); return state.result; } static u32 sceKernelGetModuleId() { - INFO_LOG(SCEMODULE,"sceKernelGetModuleId()"); - return __KernelGetCurThreadModuleId(); + return hleLogSuccessI(Log::sceModule, __KernelGetCurThreadModuleId()); } u32 sceKernelFindModuleByUID(u32 uid) @@ -2475,11 +2582,10 @@ u32 sceKernelFindModuleByUID(u32 uid) u32 error; PSPModule *module = kernelObjects.Get(uid, error); if (!module || module->isFake) { - ERROR_LOG(SCEMODULE, "0 = sceKernelFindModuleByUID(%d): Module Not Found or Fake", uid); + ERROR_LOG(Log::sceModule, "0 = sceKernelFindModuleByUID(%d): Module Not Found or Fake", uid); return 0; } - INFO_LOG(SCEMODULE, "%d = sceKernelFindModuleByUID(%d)", module->modulePtr.ptr, uid); - return module->modulePtr.ptr; + return hleLogSuccessInfoI(Log::sceModule, module->modulePtr.ptr); } u32 sceKernelFindModuleByName(const char *name) @@ -2491,16 +2597,16 @@ u32 sceKernelFindModuleByName(const char *name) continue; if (strcmp(name, module->nm.name) == 0) { if (!module->isFake) { - INFO_LOG(SCEMODULE, "%d = sceKernelFindModuleByName(%s)", module->modulePtr.ptr, name); + INFO_LOG(Log::sceModule, "%d = sceKernelFindModuleByName(%s)", module->modulePtr.ptr, name); return module->modulePtr.ptr; } else { - WARN_LOG(SCEMODULE, "0 = sceKernelFindModuleByName(%s): Module Fake", name); + WARN_LOG(Log::sceModule, "0 = sceKernelFindModuleByName(%s): Module Fake", name); return hleDelayResult(0, "Module Fake", 1000 * 1000); } } } - WARN_LOG(SCEMODULE, "0 = sceKernelFindModuleByName(%s): Module Not Found", name); + WARN_LOG(Log::sceModule, "0 = sceKernelFindModuleByName(%s): Module Not Found", name); return 0; } @@ -2509,16 +2615,16 @@ static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) u32 error; u32 handle = __IoGetFileHandleFromId(id, error); if (handle == (u32)-1) { - ERROR_LOG(SCEMODULE,"sceKernelLoadModuleByID(%08x, %08x, %08x): could not open file id",id,flags,lmoptionPtr); + ERROR_LOG(Log::sceModule,"sceKernelLoadModuleByID(%08x, %08x, %08x): could not open file id",id,flags,lmoptionPtr); return error; } if (flags != 0) { - WARN_LOG_REPORT(LOADER, "sceKernelLoadModuleByID: unsupported flags: %08x", flags); + WARN_LOG_REPORT(Log::Loader, "sceKernelLoadModuleByID: unsupported flags: %08x", flags); } SceKernelLMOption *lmoption = 0; if (lmoptionPtr) { lmoption = (SceKernelLMOption *)Memory::GetPointer(lmoptionPtr); - WARN_LOG_REPORT(LOADER, "sceKernelLoadModuleByID: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d", lmoption->size, lmoption->flags, lmoption->position, lmoption->access, lmoption->mpiddata, lmoption->mpidtext); + WARN_LOG_REPORT(Log::Loader, "sceKernelLoadModuleByID: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d", lmoption->size, lmoption->flags, lmoption->position, lmoption->access, lmoption->mpiddata, lmoption->mpidtext); } u32 pos = (u32) pspFileSystem.SeekFile(handle, 0, FILEMOVE_CURRENT); size_t size = pspFileSystem.SeekFile(handle, 0, FILEMOVE_END); @@ -2535,7 +2641,7 @@ static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) // Some games try to load strange stuff as PARAM.SFO as modules and expect it to fail. // This checks for the SFO magic number. if (magic == 0x46535000) { - ERROR_LOG(LOADER, "Game tried to load an SFO as a module. Go figure? Magic = %08x", magic); + ERROR_LOG(Log::Loader, "Game tried to load an SFO as a module. Go figure? Magic = %08x", magic); return error; } @@ -2543,22 +2649,22 @@ static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) { // Module was blacklisted or couldn't be decrypted, which means it's a kernel module we don't want to run.. // Let's just act as if it worked. - NOTICE_LOG(LOADER, "Module %d is blacklisted or undecryptable - we lie about success", id); + NOTICE_LOG(Log::Loader, "Module %d is blacklisted or undecryptable - we lie about success", id); return 1; } else { - NOTICE_LOG(LOADER, "Module %d failed to load: %08x", id, error); + NOTICE_LOG(Log::Loader, "Module %d failed to load: %08x", id, error); return error; } } if (lmoption) { - INFO_LOG(SCEMODULE,"%i=sceKernelLoadModuleByID(%d,flag=%08x,%08x,%08x,%08x,position = %08x)", + INFO_LOG(Log::sceModule,"%i=sceKernelLoadModuleByID(%d,flag=%08x,%08x,%08x,%08x,position = %08x)", module->GetUID(),id,flags, lmoption->size,lmoption->mpidtext,lmoption->mpiddata,lmoption->position); } else { - INFO_LOG(SCEMODULE,"%i=sceKernelLoadModuleByID(%d,flag=%08x,(...))", module->GetUID(), id, flags); + INFO_LOG(Log::sceModule,"%i=sceKernelLoadModuleByID(%d,flag=%08x,(...))", module->GetUID(), id, flags); } return module->GetUID(); @@ -2566,7 +2672,7 @@ static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) static u32 sceKernelLoadModuleDNAS(const char *name, u32 flags) { - ERROR_LOG_REPORT(SCEMODULE, "UNIMPL 0=sceKernelLoadModuleDNAS()"); + ERROR_LOG_REPORT(Log::sceModule, "UNIMPL 0=sceKernelLoadModuleDNAS()"); return 0; } @@ -2574,12 +2680,12 @@ static u32 sceKernelLoadModuleDNAS(const char *name, u32 flags) static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, u32 lmoptionPtr) { if (flags != 0) { - WARN_LOG_REPORT(LOADER, "sceKernelLoadModuleBufferUsbWlan: unsupported flags: %08x", flags); + WARN_LOG_REPORT(Log::Loader, "sceKernelLoadModuleBufferUsbWlan: unsupported flags: %08x", flags); } SceKernelLMOption *lmoption = 0; if (lmoptionPtr) { lmoption = (SceKernelLMOption *)Memory::GetPointer(lmoptionPtr); - WARN_LOG_REPORT(LOADER, "sceKernelLoadModuleBufferUsbWlan: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d", lmoption->size, lmoption->flags, lmoption->position, lmoption->access, lmoption->mpiddata, lmoption->mpidtext); + WARN_LOG_REPORT(Log::Loader, "sceKernelLoadModuleBufferUsbWlan: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d", lmoption->size, lmoption->flags, lmoption->position, lmoption->access, lmoption->mpiddata, lmoption->mpidtext); } std::string error_string; PSPModule *module = nullptr; @@ -2591,7 +2697,7 @@ static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, // Some games try to load strange stuff as PARAM.SFO as modules and expect it to fail. // This checks for the SFO magic number. if (magic == 0x46535000) { - ERROR_LOG(LOADER, "Game tried to load an SFO as a module. Go figure? Magic = %08x", magic); + ERROR_LOG(Log::Loader, "Game tried to load an SFO as a module. Go figure? Magic = %08x", magic); return error; } @@ -2599,22 +2705,22 @@ static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, { // Module was blacklisted or couldn't be decrypted, which means it's a kernel module we don't want to run.. // Let's just act as if it worked. - NOTICE_LOG(LOADER, "Module is blacklisted or undecryptable - we lie about success"); + NOTICE_LOG(Log::Loader, "Module is blacklisted or undecryptable - we lie about success"); return 1; } else { - NOTICE_LOG(LOADER, "Module failed to load: %08x", error); + NOTICE_LOG(Log::Loader, "Module failed to load: %08x", error); return error; } } if (lmoption) { - INFO_LOG(SCEMODULE,"%i=sceKernelLoadModuleBufferUsbWlan(%x,%08x,flag=%08x,%08x,%08x,%08x,position = %08x)", + INFO_LOG(Log::sceModule,"%i=sceKernelLoadModuleBufferUsbWlan(%x,%08x,flag=%08x,%08x,%08x,%08x,position = %08x)", module->GetUID(),size,bufPtr,flags, lmoption->size,lmoption->mpidtext,lmoption->mpiddata,lmoption->position); } else { - INFO_LOG(SCEMODULE,"%i=sceKernelLoadModuleBufferUsbWlan(%x,%08x,flag=%08x,(...))", module->GetUID(), size,bufPtr, flags); + INFO_LOG(Log::sceModule,"%i=sceKernelLoadModuleBufferUsbWlan(%x,%08x,flag=%08x,(...))", module->GetUID(), size,bufPtr, flags); } return module->GetUID(); @@ -2622,13 +2728,13 @@ static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, static u32 sceKernelQueryModuleInfo(u32 uid, u32 infoAddr) { - DEBUG_LOG(SCEMODULE, "sceKernelQueryModuleInfo(%i, %08x)", uid, infoAddr); + DEBUG_LOG(Log::sceModule, "sceKernelQueryModuleInfo(%i, %08x)", uid, infoAddr); u32 error; PSPModule *module = kernelObjects.Get(uid, error); if (!module) return error; if (!Memory::IsValidAddress(infoAddr)) { - ERROR_LOG(SCEMODULE, "sceKernelQueryModuleInfo(%i, %08x) - bad infoAddr", uid, infoAddr); + ERROR_LOG(Log::sceModule, "sceKernelQueryModuleInfo(%i, %08x) - bad infoAddr", uid, infoAddr); return -1; } @@ -2658,7 +2764,7 @@ static u32 sceKernelQueryModuleInfo(u32 uid, u32 infoAddr) static u32 sceKernelGetModuleIdList(u32 resultBuffer, u32 resultBufferSize, u32 idCountAddr) { - ERROR_LOG(SCEMODULE, "UNTESTED sceKernelGetModuleIdList(%08x, %i, %08x)", resultBuffer, resultBufferSize, idCountAddr); + ERROR_LOG(Log::sceModule, "UNTESTED sceKernelGetModuleIdList(%08x, %i, %08x)", resultBuffer, resultBufferSize, idCountAddr); int idCount = 0; u32 resultBufferOffset = 0; diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index 5292d90c10..63244b2a0b 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -385,7 +385,7 @@ static int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int wa { if (sendSize > (u32) m->nmp.bufSize) { - ERROR_LOG(SCEKERNEL, "__KernelSendMsgPipe(%d): size %d too large for buffer", uid, sendSize); + ERROR_LOG(Log::sceKernel, "__KernelSendMsgPipe(%d): size %d too large for buffer", uid, sendSize); return SCE_KERNEL_ERROR_ILLEGAL_SIZE; } @@ -486,7 +486,7 @@ static int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSiz { if (receiveSize > (u32) m->nmp.bufSize) { - ERROR_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): size %d too large for buffer", uid, receiveSize); + ERROR_LOG(Log::sceKernel, "__KernelReceiveMsgPipe(%d): size %d too large for buffer", uid, receiveSize); return SCE_KERNEL_ERROR_ILLEGAL_SIZE; } @@ -541,12 +541,12 @@ static void __KernelMsgPipeBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, waitTimer, ko->sendWaitingThreads, ko->pausedSendWaits, timeoutPtr != 0); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelSendMsgPipeCB: Suspending wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelSendMsgPipeCB: Suspending wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelSendMsgPipeCB: wait not found to pause for callback"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelSendMsgPipeCB: wait not found to pause for callback"); } else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSendMsgPipeCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSendMsgPipeCB: beginning callback with bad wait id?"); break; case MSGPIPE_WAIT_VALUE_RECV: @@ -554,16 +554,16 @@ static void __KernelMsgPipeBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, waitTimer, ko->receiveWaitingThreads, ko->pausedReceiveWaits, timeoutPtr != 0); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMsgPipeCB: Suspending wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMsgPipeCB: Suspending wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelReceiveMsgPipeCB: wait not found to pause for callback"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelReceiveMsgPipeCB: wait not found to pause for callback"); } else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelReceiveMsgPipeCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelReceiveMsgPipeCB: beginning callback with bad wait id?"); break; default: - ERROR_LOG_REPORT(SCEKERNEL, "__KernelMsgPipeBeginCallback: Unexpected wait value"); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelMsgPipeBeginCallback: Unexpected wait value"); } } @@ -617,7 +617,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) { MsgPipe *ko = uid == 0 ? NULL : kernelObjects.Get(uid, error); if (ko == NULL) { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelMsgPipeEndCallback: Invalid object"); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelMsgPipeEndCallback: Invalid object"); return; } @@ -627,7 +627,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) { MsgPipeWaitingThread dummy; auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, waitTimer, __KernelCheckResumeMsgPipeSend, dummy, ko->sendWaitingThreads, ko->pausedSendWaits); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) { - DEBUG_LOG(SCEKERNEL, "sceKernelSendMsgPipeCB: Resuming wait from callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelSendMsgPipeCB: Resuming wait from callback"); } else if (result == HLEKernel::WAIT_CB_TIMED_OUT) { // It was re-added to the the waiting threads list, but it timed out. Let's remove it. ko->RemoveSendWaitingThread(threadID); @@ -640,7 +640,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) { MsgPipeWaitingThread dummy; auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, waitTimer, __KernelCheckResumeMsgPipeReceive, dummy, ko->receiveWaitingThreads, ko->pausedReceiveWaits); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) { - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMsgPipeCB: Resuming wait from callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMsgPipeCB: Resuming wait from callback"); } else if (result == HLEKernel::WAIT_CB_TIMED_OUT) { // It was re-added to the the waiting threads list, but it timed out. Let's remove it. ko->RemoveReceiveWaitingThread(threadID); @@ -649,7 +649,7 @@ static void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) { break; default: - ERROR_LOG_REPORT(SCEKERNEL, "__KernelMsgPipeEndCallback: Unexpected wait value"); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelMsgPipeEndCallback: Unexpected wait value"); } } @@ -672,16 +672,16 @@ void __KernelMsgPipeDoState(PointerWrap &p) int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, u32 optionsPtr) { if (!name) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "invalid name"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "invalid name"); if (partition < 1 || partition > 9 || partition == 7) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", partition); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "invalid partition %d", partition); BlockAllocator *allocator = BlockAllocatorFromID(partition); if (allocator == nullptr) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_PERM, "invalid partition %d", partition); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_PERM, "invalid partition %d", partition); if ((attr & ~SCE_KERNEL_MPA_KNOWN) >= 0x100) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", attr); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", attr); u32 memBlockPtr = 0; if (size != 0) { @@ -689,7 +689,7 @@ int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, u32 allocSize = size; memBlockPtr = allocator->Alloc(allocSize, (attr & SCE_KERNEL_MPA_HIGHMEM) != 0, StringFromFormat("MsgPipe/%s", name).c_str()); if (memBlockPtr == (u32)-1) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "failed to allocate %i bytes for buffer", size); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "failed to allocate %i bytes for buffer", size); } MsgPipe *m = new MsgPipe(); @@ -706,13 +706,13 @@ int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, m->buffer = memBlockPtr; - DEBUG_LOG(SCEKERNEL, "%d=sceKernelCreateMsgPipe(%s, part=%d, attr=%08x, size=%d, opt=%08x)", id, name, partition, attr, size, optionsPtr); + DEBUG_LOG(Log::sceKernel, "%d=sceKernelCreateMsgPipe(%s, part=%d, attr=%08x, size=%d, opt=%08x)", id, name, partition, attr, size, optionsPtr); if (optionsPtr != 0) { u32 optionsSize = Memory::Read_U32(optionsPtr); if (optionsSize > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMsgPipe(%s) unsupported options parameter, size = %d", name, optionsSize); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMsgPipe(%s) unsupported options parameter, size = %d", name, optionsSize); } return id; @@ -726,7 +726,7 @@ int sceKernelDeleteMsgPipe(SceUID uid) MsgPipe *m = kernelObjects.Get(uid, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelDeleteMsgPipe(%i) - ERROR %08x", uid, error); + ERROR_LOG(Log::sceKernel, "sceKernelDeleteMsgPipe(%i) - ERROR %08x", uid, error); return error; } @@ -739,7 +739,7 @@ int sceKernelDeleteMsgPipe(SceUID uid) for (size_t i = 0; i < m->receiveWaitingThreads.size(); i++) m->receiveWaitingThreads[i].Cancel(uid, SCE_KERNEL_ERROR_WAIT_DELETE); - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteMsgPipe(%i)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteMsgPipe(%i)", uid); return kernelObjects.Destroy(uid); } @@ -747,19 +747,19 @@ static int __KernelValidateSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize { if (sendSize & 0x80000000) { - ERROR_LOG(SCEKERNEL, "__KernelSendMsgPipe(%d): illegal size %d", uid, sendSize); + ERROR_LOG(Log::sceKernel, "__KernelSendMsgPipe(%d): illegal size %d", uid, sendSize); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } if (sendSize != 0 && !Memory::IsValidAddress(sendBufAddr)) { - ERROR_LOG(SCEKERNEL, "__KernelSendMsgPipe(%d): bad buffer address %08x (should crash?)", uid, sendBufAddr); + ERROR_LOG(Log::sceKernel, "__KernelSendMsgPipe(%d): bad buffer address %08x (should crash?)", uid, sendBufAddr); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } if (waitMode != SCE_KERNEL_MPW_ASAP && waitMode != SCE_KERNEL_MPW_FULL) { - ERROR_LOG(SCEKERNEL, "__KernelSendMsgPipe(%d): invalid wait mode %d", uid, waitMode); + ERROR_LOG(Log::sceKernel, "__KernelSendMsgPipe(%d): invalid wait mode %d", uid, waitMode); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } @@ -767,12 +767,12 @@ static int __KernelValidateSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize { if (!__KernelIsDispatchEnabled()) { - WARN_LOG(SCEKERNEL, "__KernelSendMsgPipe(%d): dispatch disabled", uid); + WARN_LOG(Log::sceKernel, "__KernelSendMsgPipe(%d): dispatch disabled", uid); return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } if (__IsInInterrupt()) { - WARN_LOG(SCEKERNEL, "__KernelSendMsgPipe(%d): in interrupt", uid); + WARN_LOG(Log::sceKernel, "__KernelSendMsgPipe(%d): in interrupt", uid); return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; } } @@ -810,11 +810,11 @@ int sceKernelSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode } MsgPipe *m = kernelObjects.Get(uid, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error); + ERROR_LOG(Log::sceKernel, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelSendMsgPipe(id=%i, addr=%08x, size=%i, mode=%i, result=%08x, timeout=%08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelSendMsgPipe(id=%i, addr=%08x, size=%i, mode=%i, result=%08x, timeout=%08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr); return __KernelSendMsgPipe(m, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr, false, false); } @@ -826,11 +826,11 @@ int sceKernelSendMsgPipeCB(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMo } MsgPipe *m = kernelObjects.Get(uid, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelSendMsgPipeCB(%i) - ERROR %08x", uid, error); + ERROR_LOG(Log::sceKernel, "sceKernelSendMsgPipeCB(%i) - ERROR %08x", uid, error); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelSendMsgPipeCB(id=%i, addr=%08x, size=%i, mode=%i, result=%08x, timeout=%08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelSendMsgPipeCB(id=%i, addr=%08x, size=%i, mode=%i, result=%08x, timeout=%08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr); // TODO: Verify callback behavior. hleCheckCurrentCallbacks(); return __KernelSendMsgPipe(m, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr, true, false); @@ -844,11 +844,11 @@ int sceKernelTrySendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitM } MsgPipe *m = kernelObjects.Get(uid, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelTrySendMsgPipe(%i) - ERROR %08x", uid, error); + ERROR_LOG(Log::sceKernel, "sceKernelTrySendMsgPipe(%i) - ERROR %08x", uid, error); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelTrySendMsgPipe(id=%i, addr=%08x, size=%i, mode=%i, result=%08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelTrySendMsgPipe(id=%i, addr=%08x, size=%i, mode=%i, result=%08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr); return __KernelSendMsgPipe(m, sendBufAddr, sendSize, waitMode, resultAddr, 0, false, true); } @@ -856,19 +856,19 @@ static int __KernelValidateReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 re { if (receiveSize & 0x80000000) { - ERROR_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): illegal size %d", uid, receiveSize); + ERROR_LOG(Log::sceKernel, "__KernelReceiveMsgPipe(%d): illegal size %d", uid, receiveSize); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } if (receiveSize != 0 && !Memory::IsValidAddress(receiveBufAddr)) { - ERROR_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): bad buffer address %08x (should crash?)", uid, receiveBufAddr); + ERROR_LOG(Log::sceKernel, "__KernelReceiveMsgPipe(%d): bad buffer address %08x (should crash?)", uid, receiveBufAddr); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } if (waitMode != SCE_KERNEL_MPW_ASAP && waitMode != SCE_KERNEL_MPW_FULL) { - ERROR_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): invalid wait mode %d", uid, waitMode); + ERROR_LOG(Log::sceKernel, "__KernelReceiveMsgPipe(%d): invalid wait mode %d", uid, waitMode); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } @@ -876,12 +876,12 @@ static int __KernelValidateReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 re { if (!__KernelIsDispatchEnabled()) { - WARN_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): dispatch disabled", uid); + WARN_LOG(Log::sceKernel, "__KernelReceiveMsgPipe(%d): dispatch disabled", uid); return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } if (__IsInInterrupt()) { - WARN_LOG(SCEKERNEL, "__KernelReceiveMsgPipe(%d): in interrupt", uid); + WARN_LOG(Log::sceKernel, "__KernelReceiveMsgPipe(%d): in interrupt", uid); return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; } } @@ -917,11 +917,11 @@ int sceKernelReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u32 } MsgPipe *m = kernelObjects.Get(uid, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelReceiveMsgPipe(%i) - ERROR %08x", uid, error); + ERROR_LOG(Log::sceKernel, "sceKernelReceiveMsgPipe(%i) - ERROR %08x", uid, error); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr); return __KernelReceiveMsgPipe(m, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr, false, false); } @@ -933,11 +933,11 @@ int sceKernelReceiveMsgPipeCB(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u } MsgPipe *m = kernelObjects.Get(uid, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelReceiveMsgPipeCB(%i) - ERROR %08x", uid, error); + ERROR_LOG(Log::sceKernel, "sceKernelReceiveMsgPipeCB(%i) - ERROR %08x", uid, error); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMsgPipeCB(%i, %08x, %i, %i, %08x, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelReceiveMsgPipeCB(%i, %08x, %i, %i, %08x, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr); // TODO: Verify callback behavior. hleCheckCurrentCallbacks(); return __KernelReceiveMsgPipe(m, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr, true, false); @@ -951,11 +951,11 @@ int sceKernelTryReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, } MsgPipe *m = kernelObjects.Get(uid, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelTryReceiveMsgPipe(%i) - ERROR %08x", uid, error); + ERROR_LOG(Log::sceKernel, "sceKernelTryReceiveMsgPipe(%i) - ERROR %08x", uid, error); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelTryReceiveMsgPipe(%i, %08x, %i, %i, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelTryReceiveMsgPipe(%i, %08x, %i, %i, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr); return __KernelReceiveMsgPipe(m, receiveBufAddr, receiveSize, waitMode, resultAddr, 0, false, true); } @@ -967,7 +967,7 @@ int sceKernelCancelMsgPipe(SceUID uid, u32 numSendThreadsAddr, u32 numReceiveThr MsgPipe *m = kernelObjects.Get(uid, error); if (!m) { - ERROR_LOG(SCEKERNEL, "sceKernelCancelMsgPipe(%i) - ERROR %08x", uid, error); + ERROR_LOG(Log::sceKernel, "sceKernelCancelMsgPipe(%i) - ERROR %08x", uid, error); return error; } @@ -990,7 +990,7 @@ int sceKernelCancelMsgPipe(SceUID uid, u32 numSendThreadsAddr, u32 numReceiveThr // And now the entire buffer is free. m->nmp.freeSize = m->nmp.bufSize; - DEBUG_LOG(SCEKERNEL, "sceKernelCancelMsgPipe(%i, %i, %i)", uid, numSendThreadsAddr, numReceiveThreadsAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelMsgPipe(%i, %i, %i)", uid, numSendThreadsAddr, numReceiveThreadsAddr); return 0; } @@ -1000,7 +1000,7 @@ int sceKernelReferMsgPipeStatus(SceUID uid, u32 statusPtr) { if (m) { auto status = PSPPointer::Create(statusPtr); if (!status.IsValid()) { - return hleLogError(SCEKERNEL, -1, "invalid address"); + return hleLogError(Log::sceKernel, -1, "invalid address"); } // Clean up any that have timed out. @@ -1013,8 +1013,8 @@ int sceKernelReferMsgPipeStatus(SceUID uid, u32 statusPtr) { *status = m->nmp; status.NotifyWrite("MsgPipeStatus"); } - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error, "bad message pipe"); + return hleLogError(Log::sceKernel, error, "bad message pipe"); } } diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 1885552ce1..45f0a9fb4e 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -293,28 +293,28 @@ void __KernelMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, mutexWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelLockMutexCB: Suspending lock wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelLockMutexCB: Suspending lock wait for callback"); else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelLockMutexCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelLockMutexCB: beginning callback with bad wait id?"); } void __KernelMutexEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, mutexWaitTimer, __KernelUnlockMutexForThreadCheck); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) - DEBUG_LOG(SCEKERNEL, "sceKernelLockMutexCB: Resuming lock wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelLockMutexCB: Resuming lock wait for callback"); } int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!name) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (attr & ~0xBFF) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr); if (initialCount < 0) - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_COUNT, "illegal initial count"); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_COUNT, "illegal initial count"); if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1) - return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_COUNT, "illegal non-recursive count"); + return hleLogDebug(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_COUNT, "illegal non-recursive count"); PSPMutex *mutex = new PSPMutex(); SceUID id = kernelObjects.Create(mutex); @@ -334,12 +334,12 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio if (optionsPtr != 0) { u32 size = Memory::Read_U32(optionsPtr); if (size > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMutex(%s) unsupported options parameter, size = %d", name, size); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMutex(%s) unsupported options parameter, size = %d", name, size); } if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateMutex(%s) unsupported attr parameter: %08x", name, attr); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateMutex(%s) unsupported attr parameter: %08x", name, attr); - return hleLogSuccessX(SCEKERNEL, id); + return hleLogSuccessX(Log::sceKernel, id); } int sceKernelDeleteMutex(SceUID id) @@ -348,7 +348,7 @@ int sceKernelDeleteMutex(SceUID id) PSPMutex *mutex = kernelObjects.Get(id, error); if (mutex) { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteMutex(%i)", id); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteMutex(%i)", id); bool wokeThreads = false; std::vector::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) @@ -365,7 +365,7 @@ int sceKernelDeleteMutex(SceUID id) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteMutex(%i): invalid mutex", id); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteMutex(%i): invalid mutex", id); return error; } } @@ -504,12 +504,12 @@ int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) // May still be okay. As long as the count/etc. are valid. if (error != 0 && error != PSP_MUTEX_ERROR_LOCK_OVERFLOW && error != PSP_MUTEX_ERROR_ALREADY_LOCKED) { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelMutex(%i, %d, %08x): invalid count", uid, count, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelMutex(%i, %d, %08x): invalid count", uid, count, numWaitThreadsPtr); return error; } } - DEBUG_LOG(SCEKERNEL, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr); // Remove threads no longer waiting on this first (so the numWaitThreads value is correct.) HLEKernel::CleanupWaitingThreads(WAITTYPE_MUTEX, uid, mutex->waitingThreads); @@ -540,7 +540,7 @@ int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr); return error; } } @@ -548,7 +548,7 @@ int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) // int sceKernelLockMutex(SceUID id, int count, int *timeout) int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) { - DEBUG_LOG(SCEKERNEL, "sceKernelLockMutex(%i, %i, %08x)", id, count, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelLockMutex(%i, %i, %08x)", id, count, timeoutPtr); u32 error; PSPMutex *mutex = kernelObjects.Get(id, error); @@ -573,7 +573,7 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) // int sceKernelLockMutexCB(SceUID id, int count, int *timeout) int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) { - DEBUG_LOG(SCEKERNEL, "sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr); u32 error; PSPMutex *mutex = kernelObjects.Get(id, error); @@ -612,7 +612,7 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) // int sceKernelTryLockMutex(SceUID id, int count) int sceKernelTryLockMutex(SceUID id, int count) { - DEBUG_LOG(SCEKERNEL, "sceKernelTryLockMutex(%i, %i)", id, count); + DEBUG_LOG(Log::sceKernel, "sceKernelTryLockMutex(%i, %i)", id, count); u32 error; PSPMutex *mutex = kernelObjects.Get(id, error); @@ -627,7 +627,7 @@ int sceKernelTryLockMutex(SceUID id, int count) // int sceKernelUnlockMutex(SceUID id, int count) int sceKernelUnlockMutex(SceUID id, int count) { - DEBUG_LOG(SCEKERNEL, "sceKernelUnlockMutex(%i, %i)", id, count); + DEBUG_LOG(Log::sceKernel, "sceKernelUnlockMutex(%i, %i)", id, count); u32 error; PSPMutex *mutex = kernelObjects.Get(id, error); @@ -657,13 +657,13 @@ int sceKernelReferMutexStatus(SceUID id, u32 infoAddr) { u32 error; PSPMutex *m = kernelObjects.Get(id, error); if (!m) { - return hleLogError(SCEKERNEL, error, "invalid mutex id"); + return hleLogError(Log::sceKernel, error, "invalid mutex id"); } // Should we crash the thread somehow? auto info = PSPPointer::Create(infoAddr); if (!info.IsValid()) - return hleLogError(SCEKERNEL, -1, "invalid pointer"); + return hleLogError(Log::sceKernel, -1, "invalid pointer"); // Don't write if the size is 0. Anything else is A-OK, though, apparently. if (info->size != 0) { @@ -673,19 +673,19 @@ int sceKernelReferMutexStatus(SceUID id, u32 infoAddr) { *info = m->nm; info.NotifyWrite("MutexStatus"); } - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!name) { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateLwMutex(): invalid name", SCE_KERNEL_ERROR_ERROR); + WARN_LOG_REPORT(Log::sceKernel, "%08x=sceKernelCreateLwMutex(): invalid name", SCE_KERNEL_ERROR_ERROR); return SCE_KERNEL_ERROR_ERROR; } if (attr >= 0x400) { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateLwMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); + WARN_LOG_REPORT(Log::sceKernel, "%08x=sceKernelCreateLwMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr); return SCE_KERNEL_ERROR_ILLEGAL_ATTR; } @@ -713,16 +713,16 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init workarea->attr = attr; workarea->uid = id; - DEBUG_LOG(SCEKERNEL, "sceKernelCreateLwMutex(%08x, %s, %08x, %d, %08x)", workareaPtr, name, attr, initialCount, optionsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCreateLwMutex(%08x, %s, %08x, %d, %08x)", workareaPtr, name, attr, initialCount, optionsPtr); if (optionsPtr != 0) { u32 size = Memory::Read_U32(optionsPtr); if (size > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateLwMutex(%s) unsupported options parameter, size = %d", name, size); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateLwMutex(%s) unsupported options parameter, size = %d", name, size); } if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateLwMutex(%s) unsupported attr parameter: %08x", name, attr); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateLwMutex(%s) unsupported attr parameter: %08x", name, attr); return 0; } @@ -754,7 +754,7 @@ bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID, int sceKernelDeleteLwMutex(u32 workareaPtr) { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteLwMutex(%08x)", workareaPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteLwMutex(%08x)", workareaPtr); if (!workareaPtr || !Memory::IsValidAddress(workareaPtr)) return SCE_KERNEL_ERROR_ILLEGAL_ADDR; @@ -896,24 +896,24 @@ void __KernelLwMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, lwMutexWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelLockLwMutexCB: Suspending lock wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelLockLwMutexCB: Suspending lock wait for callback"); else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelLockLwMutexCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelLockLwMutexCB: beginning callback with bad wait id?"); } void __KernelLwMutexEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, lwMutexWaitTimer, __KernelUnlockLwMutexForThreadCheck); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) - DEBUG_LOG(SCEKERNEL, "sceKernelLockLwMutexCB: Resuming lock wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelLockLwMutexCB: Resuming lock wait for callback"); } int sceKernelTryLockLwMutex(u32 workareaPtr, int count) { - DEBUG_LOG(SCEKERNEL, "sceKernelTryLockLwMutex(%08x, %i)", workareaPtr, count); + DEBUG_LOG(Log::sceKernel, "sceKernelTryLockLwMutex(%08x, %i)", workareaPtr, count); if (!Memory::IsValidAddress(workareaPtr)) { - ERROR_LOG(SCEKERNEL, "Bad workarea pointer for LwMutex"); + ERROR_LOG(Log::sceKernel, "Bad workarea pointer for LwMutex"); return SCE_KERNEL_ERROR_ACCESS_ERROR; } @@ -932,10 +932,10 @@ int sceKernelTryLockLwMutex(u32 workareaPtr, int count) int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) { - DEBUG_LOG(SCEKERNEL, "sceKernelTryLockLwMutex_600(%08x, %i)", workareaPtr, count); + DEBUG_LOG(Log::sceKernel, "sceKernelTryLockLwMutex_600(%08x, %i)", workareaPtr, count); if (!Memory::IsValidAddress(workareaPtr)) { - ERROR_LOG(SCEKERNEL, "Bad workarea pointer for LwMutex"); + ERROR_LOG(Log::sceKernel, "Bad workarea pointer for LwMutex"); return SCE_KERNEL_ERROR_ACCESS_ERROR; } @@ -953,10 +953,10 @@ int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) { - VERBOSE_LOG(SCEKERNEL, "sceKernelLockLwMutex(%08x, %i, %08x)", workareaPtr, count, timeoutPtr); + VERBOSE_LOG(Log::sceKernel, "sceKernelLockLwMutex(%08x, %i, %08x)", workareaPtr, count, timeoutPtr); if (!Memory::IsValidAddress(workareaPtr)) { - ERROR_LOG(SCEKERNEL, "Bad workarea pointer for LwMutex"); + ERROR_LOG(Log::sceKernel, "Bad workarea pointer for LwMutex"); return SCE_KERNEL_ERROR_ACCESS_ERROR; } @@ -990,10 +990,10 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) { - VERBOSE_LOG(SCEKERNEL, "sceKernelLockLwMutexCB(%08x, %i, %08x)", workareaPtr, count, timeoutPtr); + VERBOSE_LOG(Log::sceKernel, "sceKernelLockLwMutexCB(%08x, %i, %08x)", workareaPtr, count, timeoutPtr); if (!Memory::IsValidAddress(workareaPtr)) { - ERROR_LOG(SCEKERNEL, "Bad workarea pointer for LwMutex"); + ERROR_LOG(Log::sceKernel, "Bad workarea pointer for LwMutex"); return SCE_KERNEL_ERROR_ACCESS_ERROR; } @@ -1027,10 +1027,10 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) int sceKernelUnlockLwMutex(u32 workareaPtr, int count) { - VERBOSE_LOG(SCEKERNEL, "sceKernelUnlockLwMutex(%08x, %i)", workareaPtr, count); + VERBOSE_LOG(Log::sceKernel, "sceKernelUnlockLwMutex(%08x, %i)", workareaPtr, count); if (!Memory::IsValidAddress(workareaPtr)) { - ERROR_LOG(SCEKERNEL, "Bad workarea pointer for LwMutex"); + ERROR_LOG(Log::sceKernel, "Bad workarea pointer for LwMutex"); return SCE_KERNEL_ERROR_ACCESS_ERROR; } @@ -1064,12 +1064,12 @@ static int __KernelReferLwMutexStatus(SceUID uid, u32 infoPtr) { u32 error; LwMutex *m = kernelObjects.Get(uid, error); if (!m) - return hleLogError(SCEKERNEL, error, "invalid id"); + return hleLogError(Log::sceKernel, error, "invalid id"); // Should we crash the thread somehow? auto info = PSPPointer::Create(infoPtr); if (!info.IsValid()) - return hleLogError(SCEKERNEL, -1, "invalid pointer"); + return hleLogError(Log::sceKernel, -1, "invalid pointer"); if (info->size != 0) { @@ -1084,7 +1084,7 @@ static int __KernelReferLwMutexStatus(SceUID uid, u32 infoPtr) { *info = m->nm; info.NotifyWrite("LwMutexStatus"); } - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } int sceKernelReferLwMutexStatusByID(SceUID uid, u32 infoPtr) { @@ -1094,7 +1094,7 @@ int sceKernelReferLwMutexStatusByID(SceUID uid, u32 infoPtr) { int sceKernelReferLwMutexStatus(u32 workareaPtr, u32 infoPtr) { auto workarea = PSPPointer::Create(workareaPtr); if (!workarea.IsValid()) { - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ACCESS_ERROR, "bad workarea pointer for LwMutex"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "bad workarea pointer for LwMutex"); } return __KernelReferLwMutexStatus(workarea->uid, infoPtr); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index b6a759cb76..4597a024c9 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -143,16 +143,16 @@ void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, semaWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelWaitSemaCB: Suspending sema wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelWaitSemaCB: Suspending sema wait for callback"); else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelWaitSemaCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelWaitSemaCB: beginning callback with bad wait id?"); } void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, semaWaitTimer, __KernelUnlockSemaForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) - DEBUG_LOG(SCEKERNEL, "sceKernelWaitSemaCB: Resuming sema wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelWaitSemaCB: Resuming sema wait for callback"); } // Resume all waiting threads (for delete / cancel.) @@ -176,11 +176,11 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) { if (newCount > s->ns.maxCount) { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelSema(%i, %i, %08x): invalid count", id, newCount, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelSema(%i, %i, %08x): invalid count", id, newCount, numWaitThreadsPtr); return SCE_KERNEL_ERROR_ILLEGAL_COUNT; } - DEBUG_LOG(SCEKERNEL, "sceKernelCancelSema(%i, %i, %08x)", id, newCount, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelSema(%i, %i, %08x)", id, newCount, numWaitThreadsPtr); s->ns.numWaitThreads = (int) s->waitingThreads.size(); if (Memory::IsValidAddress(numWaitThreadsPtr)) @@ -198,16 +198,16 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelCancelSema(%i, %i, %08x): invalid semaphore", id, newCount, numWaitThreadsPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelSema(%i, %i, %08x): invalid semaphore", id, newCount, numWaitThreadsPtr); return error; } } int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) { if (!name) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (attr >= 0x200) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter %08x", attr); PSPSemaphore *s = new PSPSemaphore(); SceUID id = kernelObjects.Create(s); @@ -224,14 +224,14 @@ int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 // Many games pass garbage into optionPtr, it doesn't have any options. if (optionPtr != 0) { if (!Memory::IsValidRange(optionPtr, 4)) - hleLogWarning(SCEKERNEL, id, "invalid options parameter"); + hleLogWarning(Log::sceKernel, id, "invalid options parameter"); else if (Memory::Read_U32(optionPtr) > 4) - hleLogDebug(SCEKERNEL, id, "invalid options parameter size"); + hleLogDebug(Log::sceKernel, id, "invalid options parameter size"); } if ((attr & ~PSP_SEMA_ATTR_PRIORITY) != 0) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateSema(%s) unsupported attr parameter: %08x", name, attr); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateSema(%s) unsupported attr parameter: %08x", name, attr); - return hleLogSuccessX(SCEKERNEL, id); + return hleLogSuccessX(Log::sceKernel, id); } int sceKernelDeleteSema(SceUID id) @@ -240,7 +240,7 @@ int sceKernelDeleteSema(SceUID id) PSPSemaphore *s = kernelObjects.Get(id, error); if (s) { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteSema(%i)", id); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteSema(%i)", id); bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE); if (wokeThreads) @@ -250,7 +250,7 @@ int sceKernelDeleteSema(SceUID id) } else { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteSema(%i): invalid semaphore", id); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteSema(%i): invalid semaphore", id); return error; } } @@ -261,7 +261,7 @@ int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) { if (s) { auto info = PSPPointer::Create(infoPtr); if (!info.IsValid()) - return hleLogWarning(SCEKERNEL, -1, "invalid pointer"); + return hleLogWarning(Log::sceKernel, -1, "invalid pointer"); HLEKernel::CleanupWaitingThreads(WAITTYPE_SEMA, id, s->waitingThreads); @@ -270,9 +270,9 @@ int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) { *info = s->ns; info.NotifyWrite("SemaStatus"); } - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error); + return hleLogError(Log::sceKernel, error); } } @@ -284,13 +284,13 @@ int sceKernelSignalSema(SceUID id, int signal) { if (s->ns.currentCount + signal - (int) s->waitingThreads.size() > s->ns.maxCount) { - VERBOSE_LOG(SCEKERNEL, "sceKernelSignalSema(%i, %i): overflow (at %i)", id, signal, s->ns.currentCount); + VERBOSE_LOG(Log::sceKernel, "sceKernelSignalSema(%i, %i): overflow (at %i)", id, signal, s->ns.currentCount); return SCE_KERNEL_ERROR_SEMA_OVF; } int oldval = s->ns.currentCount; s->ns.currentCount += signal; - DEBUG_LOG(SCEKERNEL, "sceKernelSignalSema(%i, %i) (count: %i -> %i)", id, signal, oldval, s->ns.currentCount); + DEBUG_LOG(Log::sceKernel, "sceKernelSignalSema(%i, %i) (count: %i -> %i)", id, signal, oldval, s->ns.currentCount); if ((s->ns.attr & PSP_SEMA_ATTR_PRIORITY) != 0) std::stable_sort(s->waitingThreads.begin(), s->waitingThreads.end(), __KernelThreadSortPriority); @@ -314,7 +314,7 @@ retry: } else { - DEBUG_LOG(SCEKERNEL, "sceKernelSignalSema(%i, %i): invalid semaphore", id, signal); + DEBUG_LOG(Log::sceKernel, "sceKernelSignalSema(%i, %i): invalid semaphore", id, signal); return error; } } @@ -396,11 +396,11 @@ int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) { int result = __KernelWaitSema(id, wantedCount, timeoutPtr, false); if (result == (int)SCE_KERNEL_ERROR_ILLEGAL_COUNT) - DEBUG_LOG(SCEKERNEL, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); else if (result == 0) - DEBUG_LOG(SCEKERNEL, "0=sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "0=sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); else - DEBUG_LOG(SCEKERNEL, "%08x=sceKernelWaitSema(%i, %i, %i)", result, id, wantedCount, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "%08x=sceKernelWaitSema(%i, %i, %i)", result, id, wantedCount, timeoutPtr); return result; } @@ -408,11 +408,11 @@ int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) { int result = __KernelWaitSema(id, wantedCount, timeoutPtr, true); if (result == (int)SCE_KERNEL_ERROR_ILLEGAL_COUNT) - DEBUG_LOG(SCEKERNEL, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); else if (result == 0) - DEBUG_LOG(SCEKERNEL, "0=sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "0=sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); else - DEBUG_LOG(SCEKERNEL, "%08x=sceKernelWaitSemaCB(%i, %i, %i)", result, id, wantedCount, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "%08x=sceKernelWaitSemaCB(%i, %i, %i)", result, id, wantedCount, timeoutPtr); return result; } @@ -421,7 +421,7 @@ int sceKernelPollSema(SceUID id, int wantedCount) { if (wantedCount <= 0) { - DEBUG_LOG(SCEKERNEL, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelPollSema(%i, %i)", id, wantedCount); + DEBUG_LOG(Log::sceKernel, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelPollSema(%i, %i)", id, wantedCount); return (int)SCE_KERNEL_ERROR_ILLEGAL_COUNT; } @@ -431,19 +431,19 @@ int sceKernelPollSema(SceUID id, int wantedCount) { if (s->ns.currentCount >= wantedCount && s->waitingThreads.size() == 0) { - DEBUG_LOG(SCEKERNEL, "0=sceKernelPollSema(%i, %i)", id, wantedCount); + DEBUG_LOG(Log::sceKernel, "0=sceKernelPollSema(%i, %i)", id, wantedCount); s->ns.currentCount -= wantedCount; return 0; } else { - DEBUG_LOG(SCEKERNEL, "SCE_KERNEL_ERROR_SEMA_ZERO=sceKernelPollSema(%i, %i)", id, wantedCount); + DEBUG_LOG(Log::sceKernel, "SCE_KERNEL_ERROR_SEMA_ZERO=sceKernelPollSema(%i, %i)", id, wantedCount); return SCE_KERNEL_ERROR_SEMA_ZERO; } } else { - DEBUG_LOG(SCEKERNEL, "sceKernelPollSema(%i, %i): invalid semaphore", id, wantedCount); + DEBUG_LOG(Log::sceKernel, "sceKernelPollSema(%i, %i): invalid semaphore", id, wantedCount); return error; } } @@ -458,7 +458,7 @@ static u32 sceUtilsBufferCopyWithRange(u32 outAddr, int outSize, u32 inAddr, int const u8 *inAddress = Memory::IsValidRange(inAddr, inSize) ? Memory::GetPointerUnchecked(inAddr) : nullptr; int temp = kirk_sceUtilsBufferCopyWithRange(outAddress, outSize, inAddress, inSize, cmd); if (temp != 0) { - ERROR_LOG(SCEKERNEL, "hleUtilsBufferCopyWithRange: Failed with %d", temp); + ERROR_LOG(Log::sceKernel, "hleUtilsBufferCopyWithRange: Failed with %d", temp); } return 0; } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 40a575da74..91066511c1 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -22,7 +22,7 @@ #include #include "Common/CommonTypes.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Common/StringUtils.h" #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" @@ -406,7 +406,7 @@ public: { currentStack.start = 0; nt.initialStack = 0; - ERROR_LOG(SCEKERNEL, "Failed to allocate stack for thread"); + ERROR_LOG(Log::sceKernel, "Failed to allocate stack for thread"); return false; } @@ -439,7 +439,7 @@ public: void FreeStack() { if (currentStack.start != 0) { - DEBUG_LOG(SCEKERNEL, "Freeing thread stack %s", nt.name); + DEBUG_LOG(Log::sceKernel, "Freeing thread stack %s", nt.name); if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) { Memory::Memset(nt.initialStack, 0, nt.stackSize, "ThreadFreeStack"); @@ -490,7 +490,7 @@ public: if (pushedStacks.size() != 0) { - WARN_LOG_REPORT(SCEKERNEL, "Thread ended within an extended stack"); + WARN_LOG_REPORT(Log::sceKernel, "Thread ended within an extended stack"); for (size_t i = 0; i < pushedStacks.size(); ++i) userMemory.Free(pushedStacks[i].start); } @@ -752,10 +752,10 @@ static void __KernelDelayBeginCallback(SceUID threadID, SceUID prevCallbackId) { // Most waits need to keep track of waiting threads, delays don't. Use a fake list. std::vector dummy; HLEKernel::WaitBeginCallback(threadID, prevCallbackId, eventScheduledWakeup, dummy, pausedDelays, true); - DEBUG_LOG(SCEKERNEL, "sceKernelDelayThreadCB: Suspending delay for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelDelayThreadCB: Suspending delay for callback"); } else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelDelayThreadCB: beginning callback with bad wait?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelDelayThreadCB: beginning callback with bad wait?"); } static void __KernelDelayEndCallback(SceUID threadID, SceUID prevCallbackId) { @@ -764,7 +764,7 @@ static void __KernelDelayEndCallback(SceUID threadID, SceUID prevCallbackId) { if (pausedDelays.find(pauseKey) == pausedDelays.end()) { // This probably should not happen. - WARN_LOG_REPORT(SCEKERNEL, "sceKernelDelayThreadCB: cannot find delay deadline"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelDelayThreadCB: cannot find delay deadline"); __KernelResumeThreadFromWait(threadID, 0); return; } @@ -780,12 +780,12 @@ static void __KernelDelayEndCallback(SceUID threadID, SceUID prevCallbackId) { else { CoreTiming::ScheduleEvent(cyclesLeft, eventScheduledWakeup, __KernelGetCurThread()); - DEBUG_LOG(SCEKERNEL, "sceKernelDelayThreadCB: Resuming delay after callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelDelayThreadCB: Resuming delay after callback"); } } static void __KernelSleepBeginCallback(SceUID threadID, SceUID prevCallbackId) { - DEBUG_LOG(SCEKERNEL, "sceKernelSleepThreadCB: Suspending sleep for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelSleepThreadCB: Suspending sleep for callback"); } static void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId) { @@ -793,7 +793,7 @@ static void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId) { PSPThread *thread = kernelObjects.Get(threadID, error); if (!thread) { // This probably should not happen. - WARN_LOG_REPORT(SCEKERNEL, "sceKernelSleepThreadCB: thread deleted?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelSleepThreadCB: thread deleted?"); return; } @@ -801,10 +801,10 @@ static void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId) { if (thread->nt.wakeupCount > 0) { thread->nt.wakeupCount--; - DEBUG_LOG(SCEKERNEL, "sceKernelSleepThreadCB: resume from callback, wakeupCount decremented to %i", thread->nt.wakeupCount); + DEBUG_LOG(Log::sceKernel, "sceKernelSleepThreadCB: resume from callback, wakeupCount decremented to %i", thread->nt.wakeupCount); __KernelResumeThreadFromWait(threadID, 0); } else { - DEBUG_LOG(SCEKERNEL, "sceKernelSleepThreadCB: Resuming sleep after callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelSleepThreadCB: Resuming sleep after callback"); } } @@ -812,11 +812,11 @@ static void __KernelThreadEndBeginCallback(SceUID threadID, SceUID prevCallbackI { auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, eventThreadEndTimeout); if (result == HLEKernel::WAIT_CB_SUCCESS) - DEBUG_LOG(SCEKERNEL, "sceKernelWaitThreadEndCB: Suspending wait for callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB: Suspending wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelWaitThreadEndCB: wait not found to pause for callback"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelWaitThreadEndCB: wait not found to pause for callback"); else - WARN_LOG_REPORT(SCEKERNEL, "sceKernelWaitThreadEndCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelWaitThreadEndCB: beginning callback with bad wait id?"); } static bool __KernelCheckResumeThreadEnd(PSPThread *t, SceUID waitingThreadID, u32 &error, int result, bool &wokeThreads) { @@ -840,7 +840,7 @@ static void __KernelThreadEndEndCallback(SceUID threadID, SceUID prevCallbackId) { auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, eventThreadEndTimeout, __KernelCheckResumeThreadEnd); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) - DEBUG_LOG(SCEKERNEL, "sceKernelWaitThreadEndCB: Resuming wait from callback"); + DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB: Resuming wait from callback"); } u32 __KernelSetThreadRA(SceUID threadID, u32 nid) @@ -852,7 +852,7 @@ u32 __KernelSetThreadRA(SceUID threadID, u32 nid) newRA = moduleReturnHackAddr; break; default: - ERROR_LOG_REPORT(SCEKERNEL, "__KernelSetThreadRA(): invalid RA address"); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelSetThreadRA(): invalid RA address"); return -1; } @@ -1064,7 +1064,7 @@ static void __KernelChangeReadyState(SceUID threadID, bool ready) if (thread) __KernelChangeReadyState(thread, threadID, ready); else - WARN_LOG(SCEKERNEL, "Trying to change the ready state of an unknown thread?"); + WARN_LOG(Log::sceKernel, "Trying to change the ready state of an unknown thread?"); } void __KernelStartIdleThreads(SceUID moduleId) @@ -1109,7 +1109,7 @@ bool __KernelSwitchOffThread(const char *reason) return true; } else - ERROR_LOG(SCEKERNEL, "Unable to switch to idle thread."); + ERROR_LOG(Log::sceKernel, "Unable to switch to idle thread."); } return false; @@ -1122,7 +1122,7 @@ bool __KernelSwitchToThread(SceUID threadID, const char *reason) if (currentThread != threadIdleID[0] && currentThread != threadIdleID[1]) { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelSwitchToThread used when already on a thread."); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelSwitchToThread used when already on a thread."); return false; } @@ -1133,7 +1133,7 @@ bool __KernelSwitchToThread(SceUID threadID, const char *reason) PSPThread *t = kernelObjects.Get(threadID, error); if (!t) { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelSwitchToThread: %x doesn't exist", threadID); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelSwitchToThread: %x doesn't exist", threadID); hleReSchedule("switch to deleted thread"); } else if (t->isReady() || t->isRunning()) @@ -1219,7 +1219,7 @@ u32 __KernelGetWaitValue(SceUID threadID, u32 &error) { if (t) { return t->getWaitInfo().waitValue; } else { - ERROR_LOG(SCEKERNEL, "__KernelGetWaitValue ERROR: thread %i", threadID); + ERROR_LOG(Log::sceKernel, "__KernelGetWaitValue ERROR: thread %i", threadID); return 0; } } @@ -1229,7 +1229,7 @@ u32 __KernelGetWaitTimeoutPtr(SceUID threadID, u32 &error) { if (t) { return t->getWaitInfo().timeoutPtr; } else { - ERROR_LOG(SCEKERNEL, "__KernelGetWaitTimeoutPtr ERROR: thread %i", threadID); + ERROR_LOG(Log::sceKernel, "__KernelGetWaitTimeoutPtr ERROR: thread %i", threadID); return 0; } } @@ -1239,7 +1239,7 @@ SceUID __KernelGetWaitID(SceUID threadID, WaitType type, u32 &error) { if (t) { return t->getWaitID(type); } else { - ERROR_LOG(SCEKERNEL, "__KernelGetWaitID ERROR: thread %i", threadID); + ERROR_LOG(Log::sceKernel, "__KernelGetWaitID ERROR: thread %i", threadID); return -1; } } @@ -1249,7 +1249,7 @@ SceUID __KernelGetCurrentCallbackID(SceUID threadID, u32 &error) { if (t) { return t->currentCallbackId; } else { - ERROR_LOG(SCEKERNEL, "__KernelGetCurrentCallbackID ERROR: thread %i", threadID); + ERROR_LOG(Log::sceKernel, "__KernelGetCurrentCallbackID ERROR: thread %i", threadID); return 0; } } @@ -1267,7 +1267,7 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr) if (!t) { hleEatCycles(700); hleReSchedule("refer thread status"); - return hleLogError(SCEKERNEL, error, "bad thread"); + return hleLogError(Log::sceKernel, error, "bad thread"); } u32 wantedSize = Memory::Read_U32(statusPtr); @@ -1276,7 +1276,7 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr) if (wantedSize > THREADINFO_SIZE_AFTER_260) { hleEatCycles(1200); hleReSchedule("refer thread status"); - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_SIZE, "bad size %d", wantedSize); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_SIZE, "bad size %d", wantedSize); } t->nt.nativeSize = THREADINFO_SIZE_AFTER_260; @@ -1294,7 +1294,7 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr) hleEatCycles(1400); hleReSchedule("refer thread status"); - return hleLogSuccessVerboseI(SCEKERNEL, 0); + return hleLogSuccessVerboseI(Log::sceKernel, 0); } // Thanks JPCSP @@ -1307,11 +1307,11 @@ u32 sceKernelReferThreadRunStatus(u32 threadID, u32 statusPtr) PSPThread *t = kernelObjects.Get(threadID, error); if (!t) { - ERROR_LOG(SCEKERNEL,"sceKernelReferThreadRunStatus Error %08x", error); + ERROR_LOG(Log::sceKernel,"sceKernelReferThreadRunStatus Error %08x", error); return error; } - DEBUG_LOG(SCEKERNEL,"sceKernelReferThreadRunStatus(%i, %08x)", threadID, statusPtr); + DEBUG_LOG(Log::sceKernel,"sceKernelReferThreadRunStatus(%i, %08x)", threadID, statusPtr); if (!Memory::IsValidAddress(statusPtr)) return -1; @@ -1336,14 +1336,14 @@ int __KernelGetThreadExitStatus(SceUID threadID) { u32 error; PSPThread *t = kernelObjects.Get(threadID, error); if (!t) { - return hleLogError(SCEKERNEL, error); + return hleLogError(Log::sceKernel, error); } // __KernelResetThread and __KernelCreateThread set exitStatus in case it's DORMANT. if (t->nt.status == THREADSTATUS_DORMANT) { - return hleLogSuccessI(SCEKERNEL, t->nt.exitStatus); + return hleLogSuccessI(Log::sceKernel, t->nt.exitStatus); } - return hleLogVerbose(SCEKERNEL, SCE_KERNEL_ERROR_NOT_DORMANT, "not dormant"); + return hleLogVerbose(Log::sceKernel, SCE_KERNEL_ERROR_NOT_DORMANT, "not dormant"); } int sceKernelGetThreadExitStatus(SceUID threadID) { @@ -1357,15 +1357,15 @@ u32 sceKernelGetThreadmanIdType(u32 uid) { int type; if (kernelObjects.GetIDType(uid, &type)) { if (type < 0x1000) { - DEBUG_LOG(SCEKERNEL, "%i=sceKernelGetThreadmanIdType(%i)", type, uid); + DEBUG_LOG(Log::sceKernel, "%i=sceKernelGetThreadmanIdType(%i)", type, uid); return type; } else { // This means a partition memory block or module, etc. - ERROR_LOG(SCEKERNEL, "sceKernelGetThreadmanIdType(%i): invalid object type %i", uid, type); + ERROR_LOG(Log::sceKernel, "sceKernelGetThreadmanIdType(%i): invalid object type %i", uid, type); return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; } } else { - ERROR_LOG(SCEKERNEL, "sceKernelGetThreadmanIdType(%i) - FAILED", uid); + ERROR_LOG(Log::sceKernel, "sceKernelGetThreadmanIdType(%i) - FAILED", uid); return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; } } @@ -1389,12 +1389,12 @@ static bool __ThreadmanIdListIsDormant(const PSPThread *t) { u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr) { if (readBufSize >= 0x8000000) { // Not exact, it's probably if the sum ends up negative or something. - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid size", type, readBufPtr, readBufSize, idCountPtr); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid size", type, readBufPtr, readBufSize, idCountPtr); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } if (!Memory::IsValidAddress(readBufPtr) && readBufSize > 0) { // Crashes on a PSP. - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid pointer", type, readBufPtr, readBufSize, idCountPtr); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid pointer", type, readBufPtr, readBufSize, idCountPtr); return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; } @@ -1402,7 +1402,7 @@ u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 i auto uids = PSPPointer::Create(readBufPtr); u32 error; if (type > 0 && type <= SCE_KERNEL_TMID_Tlspl) { - DEBUG_LOG(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x)", type, readBufPtr, readBufSize, idCountPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x)", type, readBufPtr, readBufSize, idCountPtr); total = kernelObjects.ListIDType(type, uids, readBufSize); } else if (type >= SCE_KERNEL_TMID_SleepThread && type <= SCE_KERNEL_TMID_DormantThread) { bool (*checkFunc)(const PSPThread *t) = nullptr; @@ -1437,7 +1437,7 @@ u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 i } } } else { - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid type", type, readBufPtr, readBufSize, idCountPtr); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid type", type, readBufPtr, readBufSize, idCountPtr); return SCE_KERNEL_ERROR_ILLEGAL_TYPE; } @@ -1495,7 +1495,7 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, u32 retval) } else { - ERROR_LOG(SCEKERNEL, "__KernelResumeThreadFromWait(%d): bad thread: %08x", threadID, error); + ERROR_LOG(Log::sceKernel, "__KernelResumeThreadFromWait(%d): bad thread: %08x", threadID, error); return error; } } @@ -1512,7 +1512,7 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval) } else { - ERROR_LOG(SCEKERNEL, "__KernelResumeThreadFromWait(%d): bad thread: %08x", threadID, error); + ERROR_LOG(Log::sceKernel, "__KernelResumeThreadFromWait(%d): bad thread: %08x", threadID, error); return error; } } @@ -1520,14 +1520,14 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval) // makes the current thread wait for an event void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr, bool processCallbacks, const char *reason) { if (!dispatchEnabled) { - WARN_LOG_REPORT(SCEKERNEL, "Ignoring wait, dispatching disabled... right thing to do?"); + WARN_LOG_REPORT(Log::sceKernel, "Ignoring wait, dispatching disabled... right thing to do?"); return; } PSPThread *thread = __GetCurrentThread(); _assert_(thread != nullptr); if ((thread->nt.status & THREADSTATUS_WAIT) != 0) - WARN_LOG_REPORT(SCEKERNEL, "Waiting thread for %d that was already waiting for %d", type, thread->nt.waitType); + WARN_LOG_REPORT(Log::sceKernel, "Waiting thread for %d that was already waiting for %d", type, thread->nt.waitType); thread->nt.waitID = waitID; thread->nt.waitType = type; __KernelChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->nt.status & THREADSTATUS_SUSPEND))); @@ -1543,13 +1543,13 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 time void __KernelWaitCallbacksCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr) { if (!dispatchEnabled) { - WARN_LOG_REPORT(SCEKERNEL, "Ignoring wait, dispatching disabled... right thing to do?"); + WARN_LOG_REPORT(Log::sceKernel, "Ignoring wait, dispatching disabled... right thing to do?"); return; } PSPThread *thread = __GetCurrentThread(); if ((thread->nt.status & THREADSTATUS_WAIT) != 0) - WARN_LOG_REPORT(SCEKERNEL, "Waiting thread for %d that was already waiting for %d", type, thread->nt.waitType); + WARN_LOG_REPORT(Log::sceKernel, "Waiting thread for %d that was already waiting for %d", type, thread->nt.waitType); thread->nt.waitID = waitID; thread->nt.waitType = type; __KernelChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->nt.status & THREADSTATUS_SUSPEND))); @@ -1639,7 +1639,7 @@ void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason) t->nt.waitType = WAITTYPE_NONE; t->nt.waitID = 0; } else { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelStopThread: thread %d does not exist (%s)", threadID, reason ? reason : "?"); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelStopThread: thread %d does not exist (%s)", threadID, reason ? reason : "?"); } } @@ -1711,9 +1711,9 @@ static void __ReportThreadQueueEmpty() { sprintf(idleDescription1, "DELETED"); } - ERROR_LOG_REPORT_ONCE(threadqueueempty, SCEKERNEL, "Failed to reschedule: out of threads on queue (%d, %d)", idleStatus0, idleStatus1); - WARN_LOG(SCEKERNEL, "Failed to reschedule: idle0 -> %s", idleDescription0); - WARN_LOG(SCEKERNEL, "Failed to reschedule: idle1 -> %s", idleDescription1); + ERROR_LOG_REPORT_ONCE(threadqueueempty, Log::sceKernel, "Failed to reschedule: out of threads on queue (%d, %d)", idleStatus0, idleStatus1); + WARN_LOG(Log::sceKernel, "Failed to reschedule: idle0 -> %s", idleDescription0); + WARN_LOG(Log::sceKernel, "Failed to reschedule: idle1 -> %s", idleDescription1); } // Returns NULL if the current thread is fine. @@ -1788,10 +1788,10 @@ int sceKernelCheckThreadStack() PSPThread *t = kernelObjects.Get(__KernelGetCurThread(), error); if (t) { u32 diff = labs((long)((s64)currentMIPS->r[MIPS_REG_SP] - (s64)t->currentStack.start)); - DEBUG_LOG(SCEKERNEL, "%i=sceKernelCheckThreadStack()", diff); + DEBUG_LOG(Log::sceKernel, "%i=sceKernelCheckThreadStack()", diff); return diff; } else { - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelCheckThreadStack() - not on thread"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelCheckThreadStack() - not on thread"); return -1; } } @@ -1855,7 +1855,7 @@ void __KernelResetThread(PSPThread *t, int lowestPriority) { t->FillStack(); if (!t->waitingThreads.empty()) - ERROR_LOG_REPORT(SCEKERNEL, "Resetting thread with threads waiting on end?"); + ERROR_LOG_REPORT(Log::sceKernel, "Resetting thread with threads waiting on end?"); } PSPThread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr) { @@ -1910,7 +1910,7 @@ SceUID __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int SceUID id; PSPThread *thread = __KernelCreateThread(id, moduleID, "root", currentMIPS->pc, prio, stacksize, attr); if (thread->currentStack.start == 0) - ERROR_LOG_REPORT(SCEKERNEL, "Unable to allocate stack for root thread."); + ERROR_LOG_REPORT(Log::sceKernel, "Unable to allocate stack for root thread."); __KernelResetThread(thread, 0); PSPThread *prevThread = __GetCurrentThread(); @@ -1948,23 +1948,23 @@ SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr, bool allowKernel) { if (threadName == nullptr) - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "NULL thread name"); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "NULL thread name"); if ((u32)stacksize < 0x200) - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE, "bogus thread stack size %08x", stacksize); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE, "bogus thread stack size %08x", stacksize); if (prio < 0x08 || prio > 0x77) { - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "bogus thread priority %08x", prio); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "bogus thread priority %08x", prio); } if (!Memory::IsValidAddress(entry)) { // The PSP firmware seems to allow NULL...? if (entry != 0) - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid thread entry %08x", entry); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid thread entry %08x", entry); } if ((attr & ~PSP_THREAD_ATTR_USER_MASK) != 0 && !allowKernel) - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "illegal thread attributes %08x", attr); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "illegal thread attributes %08x", attr); if ((attr & ~PSP_THREAD_ATTR_SUPPORTED) != 0) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateThread(name=%s): unsupported attributes %08x", threadName, attr); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateThread(name=%s): unsupported attributes %08x", threadName, attr); // TODO: Not sure what these values are, but they are removed from the attr silently. // Some are USB/VSH specific, probably removes when they are from the wrong module? @@ -1980,10 +1980,10 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 SceUID id = __KernelCreateThreadInternal(threadName, moduleID, entry, prio, stacksize, attr); if ((u32)id == SCE_KERNEL_ERROR_NO_MEMORY) - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "out of memory, %08x stack requested", stacksize); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "out of memory, %08x stack requested", stacksize); if (optionAddr != 0) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateThread(name=%s): unsupported options parameter %08x", threadName, optionAddr); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateThread(name=%s): unsupported options parameter %08x", threadName, optionAddr); // Creating a thread resumes dispatch automatically. Probably can't create without it. dispatchEnabled = true; @@ -1996,7 +1996,7 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 // Before triggering, set v0, since we restore on return. RETURN(id); __KernelThreadTriggerEvent((attr & PSP_THREAD_ATTR_KERNEL) != 0, id, THREADEVENT_CREATE); - return hleLogSuccessInfoI(SCEKERNEL, id); + return hleLogSuccessInfoI(Log::sceKernel, id); } int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr) { @@ -2075,17 +2075,17 @@ int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bo int __KernelStartThreadValidate(SceUID threadToStartID, int argSize, u32 argBlockPtr, bool forceArgs) { if (threadToStartID == 0) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_THID, "thread id is 0"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_THID, "thread id is 0"); if (argSize < 0 || argBlockPtr & 0x80000000) - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad thread argument pointer/length %08x / %08x", argSize, argBlockPtr); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad thread argument pointer/length %08x / %08x", argSize, argBlockPtr); u32 error = 0; PSPThread *startThread = kernelObjects.Get(threadToStartID, error); if (startThread == 0) - return hleLogError(SCEKERNEL, error, "thread does not exist"); + return hleLogError(Log::sceKernel, error, "thread does not exist"); if (startThread->nt.status != THREADSTATUS_DORMANT) - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_NOT_DORMANT, "thread already running"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_NOT_DORMANT, "thread already running"); hleEatCycles(3400); return __KernelStartThread(threadToStartID, argSize, argBlockPtr, forceArgs); @@ -2093,12 +2093,12 @@ int __KernelStartThreadValidate(SceUID threadToStartID, int argSize, u32 argBloc // int sceKernelStartThread(SceUID threadToStartID, SceSize argSize, void *argBlock) int sceKernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr) { - return hleLogSuccessInfoI(SCEKERNEL, __KernelStartThreadValidate(threadToStartID, argSize, argBlockPtr)); + return hleLogSuccessInfoI(Log::sceKernel, __KernelStartThreadValidate(threadToStartID, argSize, argBlockPtr)); } int sceKernelGetThreadStackFreeSize(SceUID threadID) { - DEBUG_LOG(SCEKERNEL, "sceKernelGetThreadStackFreeSize(%i)", threadID); + DEBUG_LOG(Log::sceKernel, "sceKernelGetThreadStackFreeSize(%i)", threadID); if (threadID == 0) threadID = __KernelGetCurThread(); @@ -2106,7 +2106,7 @@ int sceKernelGetThreadStackFreeSize(SceUID threadID) u32 error; PSPThread *thread = kernelObjects.Get(threadID, error); if (thread == nullptr) { - ERROR_LOG(SCEKERNEL, "sceKernelGetThreadStackFreeSize: invalid thread id %i", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelGetThreadStackFreeSize: invalid thread id %i", threadID); return error; } @@ -2131,7 +2131,7 @@ void __KernelReturnFromThread() PSPThread *thread = __GetCurrentThread(); _dbg_assert_msg_(thread != NULL, "Returned from a NULL thread."); - DEBUG_LOG(SCEKERNEL, "__KernelReturnFromThread: %d", exitStatus); + DEBUG_LOG(Log::sceKernel, "__KernelReturnFromThread: %d", exitStatus); __KernelStopThread(currentThread, exitStatus, "thread returned"); hleReSchedule("thread returned"); @@ -2144,11 +2144,11 @@ void __KernelReturnFromThread() int sceKernelExitThread(int exitStatus) { if (!__KernelIsDispatchEnabled() && sceKernelGetCompiledSdkVersion() >= 0x03080000) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_CAN_NOT_WAIT); PSPThread *thread = __GetCurrentThread(); _dbg_assert_msg_(thread != NULL, "Exited from a NULL thread."); - INFO_LOG(SCEKERNEL, "sceKernelExitThread(%d)", exitStatus); + INFO_LOG(Log::sceKernel, "sceKernelExitThread(%d)", exitStatus); if (exitStatus < 0) { exitStatus = SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; } @@ -2167,7 +2167,7 @@ void _sceKernelExitThread(int exitStatus) { PSPThread *thread = __GetCurrentThread(); _dbg_assert_msg_(thread != NULL, "_Exited from a NULL thread."); - ERROR_LOG_REPORT(SCEKERNEL, "_sceKernelExitThread(%d): should not be called directly", exitStatus); + ERROR_LOG_REPORT(Log::sceKernel, "_sceKernelExitThread(%d): should not be called directly", exitStatus); __KernelStopThread(currentThread, exitStatus, "thread _exited"); hleReSchedule("thread _exited"); @@ -2180,11 +2180,11 @@ void _sceKernelExitThread(int exitStatus) { int sceKernelExitDeleteThread(int exitStatus) { if (!__KernelIsDispatchEnabled() && sceKernelGetCompiledSdkVersion() >= 0x03080000) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_CAN_NOT_WAIT); PSPThread *thread = __GetCurrentThread(); if (thread) { - INFO_LOG(SCEKERNEL,"sceKernelExitDeleteThread(%d)", exitStatus); + INFO_LOG(Log::sceKernel,"sceKernelExitDeleteThread(%d)", exitStatus); uint32_t thread_attr = thread->nt.attr; uint32_t uid = thread->GetUID(); __KernelDeleteThread(currentThread, exitStatus, "thread exited with delete"); @@ -2197,7 +2197,7 @@ int sceKernelExitDeleteThread(int exitStatus) { __KernelThreadTriggerEvent((thread_attr & PSP_THREAD_ATTR_KERNEL) != 0, uid, THREADEVENT_EXIT); } else - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelExitDeleteThread(%d) ERROR - could not find myself!", exitStatus); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelExitDeleteThread(%d) ERROR - could not find myself!", exitStatus); return 0; } @@ -2205,13 +2205,13 @@ u32 sceKernelSuspendDispatchThread() { if (!__InterruptsEnabled()) { - DEBUG_LOG(SCEKERNEL, "sceKernelSuspendDispatchThread(): interrupts disabled"); + DEBUG_LOG(Log::sceKernel, "sceKernelSuspendDispatchThread(): interrupts disabled"); return SCE_KERNEL_ERROR_CPUDI; } u32 oldDispatchEnabled = dispatchEnabled; dispatchEnabled = false; - DEBUG_LOG(SCEKERNEL, "%i=sceKernelSuspendDispatchThread()", oldDispatchEnabled); + DEBUG_LOG(Log::sceKernel, "%i=sceKernelSuspendDispatchThread()", oldDispatchEnabled); hleEatCycles(940); return oldDispatchEnabled; } @@ -2220,13 +2220,13 @@ u32 sceKernelResumeDispatchThread(u32 enabled) { if (!__InterruptsEnabled()) { - DEBUG_LOG(SCEKERNEL, "sceKernelResumeDispatchThread(%i): interrupts disabled", enabled); + DEBUG_LOG(Log::sceKernel, "sceKernelResumeDispatchThread(%i): interrupts disabled", enabled); return SCE_KERNEL_ERROR_CPUDI; } u32 oldDispatchEnabled = dispatchEnabled; dispatchEnabled = enabled != 0; - DEBUG_LOG(SCEKERNEL, "sceKernelResumeDispatchThread(%i) - from %i", enabled, oldDispatchEnabled); + DEBUG_LOG(Log::sceKernel, "sceKernelResumeDispatchThread(%i) - from %i", enabled, oldDispatchEnabled); hleReSchedule("dispatch resumed"); hleEatCycles(940); return 0; @@ -2268,12 +2268,12 @@ int sceKernelRotateThreadReadyQueue(int priority) { hleReSchedule("rotatethreadreadyqueue"); hleEatCycles(250); } - return hleLogSuccessVerboseI(SCEKERNEL, result); + return hleLogSuccessVerboseI(Log::sceKernel, result); } int sceKernelDeleteThread(int threadID) { if (threadID == 0 || threadID == currentThread) { - ERROR_LOG(SCEKERNEL, "sceKernelDeleteThread(%i): cannot delete current thread", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelDeleteThread(%i): cannot delete current thread", threadID); return SCE_KERNEL_ERROR_NOT_DORMANT; } @@ -2281,14 +2281,14 @@ int sceKernelDeleteThread(int threadID) { PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (!t->isStopped()) { - ERROR_LOG(SCEKERNEL, "sceKernelDeleteThread(%i): thread not dormant", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelDeleteThread(%i): thread not dormant", threadID); return SCE_KERNEL_ERROR_NOT_DORMANT; } - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteThread(%i)", threadID); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteThread(%i)", threadID); return __KernelDeleteThread(threadID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "thread deleted"); } else { - ERROR_LOG(SCEKERNEL, "sceKernelDeleteThread(%i): thread doesn't exist", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelDeleteThread(%i): thread doesn't exist", threadID); return error; } } @@ -2297,11 +2297,11 @@ int sceKernelTerminateDeleteThread(int threadID) { if (threadID == 0 || threadID == currentThread) { - ERROR_LOG(SCEKERNEL, "sceKernelTerminateDeleteThread(%i): cannot terminate current thread", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelTerminateDeleteThread(%i): cannot terminate current thread", threadID); return SCE_KERNEL_ERROR_ILLEGAL_THID; } if (!__KernelIsDispatchEnabled() && sceKernelGetCompiledSdkVersion() >= 0x03080000) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_CAN_NOT_WAIT); u32 error; PSPThread *t = kernelObjects.Get(threadID, error); @@ -2311,7 +2311,7 @@ int sceKernelTerminateDeleteThread(int threadID) uint32_t attr = t->nt.attr; uint32_t uid = t->GetUID(); - INFO_LOG(SCEKERNEL, "sceKernelTerminateDeleteThread(%i)", threadID); + INFO_LOG(Log::sceKernel, "sceKernelTerminateDeleteThread(%i)", threadID); error = __KernelDeleteThread(threadID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "thread terminated with delete"); if (!wasStopped) { @@ -2324,26 +2324,26 @@ int sceKernelTerminateDeleteThread(int threadID) } else { - ERROR_LOG(SCEKERNEL, "sceKernelTerminateDeleteThread(%i): thread doesn't exist", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelTerminateDeleteThread(%i): thread doesn't exist", threadID); return error; } } int sceKernelTerminateThread(SceUID threadID) { if (__IsInInterrupt() && sceKernelGetCompiledSdkVersion() >= 0x03080000) { - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "in interrupt"); } if (!__KernelIsDispatchEnabled() && sceKernelGetCompiledSdkVersion() >= 0x03080000) - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_CAN_NOT_WAIT); if (threadID == 0 || threadID == currentThread) { - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_THID, "cannot terminate current thread"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_THID, "cannot terminate current thread"); } u32 error; PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (t->isStopped()) { - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_DORMANT, "already stopped"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_DORMANT, "already stopped"); } // TODO: Should this reschedule? Seems like not. @@ -2356,9 +2356,9 @@ int sceKernelTerminateThread(SceUID threadID) { RETURN(0); __KernelThreadTriggerEvent((t->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0, t->GetUID(), THREADEVENT_EXIT); - return hleLogSuccessInfoI(SCEKERNEL, 0); + return hleLogSuccessInfoI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error, "thread doesn't exist"); + return hleLogError(Log::sceKernel, error, "thread doesn't exist"); } } @@ -2397,28 +2397,28 @@ u32 __KernelGetCurThreadStackStart() { SceUID sceKernelGetThreadId() { - VERBOSE_LOG(SCEKERNEL, "%i = sceKernelGetThreadId()", currentThread); + VERBOSE_LOG(Log::sceKernel, "%i = sceKernelGetThreadId()", currentThread); hleEatCycles(180); return currentThread; } int sceKernelGetThreadCurrentPriority() { u32 retVal = __GetCurrentThread()->nt.currentPriority; - return hleLogSuccessI(SCEKERNEL, retVal); + return hleLogSuccessI(Log::sceKernel, retVal); } int sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr) { // Seems like this is the only allowed attribute? if ((clearAttr & ~PSP_THREAD_ATTR_VFPU) != 0 || (setAttr & ~PSP_THREAD_ATTR_VFPU) != 0) { - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr"); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr"); } PSPThread *t = __GetCurrentThread(); if (!t) - return hleReportError(SCEKERNEL, -1, "no current thread"); + return hleReportError(Log::sceKernel, -1, "no current thread"); t->nt.attr = (t->nt.attr & ~clearAttr) | setAttr; - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } // Assumes validated parameters. @@ -2452,7 +2452,7 @@ int sceKernelChangeThreadPriority(SceUID threadID, int priority) { if (priority == 0) { PSPThread *cur = __GetCurrentThread(); if (!cur) { - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelChangeThreadPriority(%i, %i): no current thread?", threadID, priority); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelChangeThreadPriority(%i, %i): no current thread?", threadID, priority); } else { priority = cur->nt.currentPriority; } @@ -2462,11 +2462,11 @@ int sceKernelChangeThreadPriority(SceUID threadID, int priority) { PSPThread *thread = kernelObjects.Get(threadID, error); if (thread) { if (thread->isStopped()) { - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_DORMANT, "thread is dormant"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_DORMANT, "thread is dormant"); } if (priority < 0x08 || priority > 0x77) { - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "bogus priority"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "bogus priority"); } KernelChangeThreadPriority(threadID, priority); @@ -2474,9 +2474,9 @@ int sceKernelChangeThreadPriority(SceUID threadID, int priority) { hleEatCycles(450); hleReSchedule("change thread priority"); - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error, "thread not found"); + return hleLogError(Log::sceKernel, error, "thread not found"); } } @@ -2507,7 +2507,7 @@ int sceKernelDelayThreadCB(u32 usec) { s64 delayUs = __KernelDelayThreadUs(usec); __KernelScheduleWakeup(curThread, delayUs); __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true, "thread delayed"); - return hleLogSuccessI(SCEKERNEL, 0, "delaying %lld usecs", delayUs); + return hleLogSuccessI(Log::sceKernel, 0, "delaying %lld usecs", delayUs); } int sceKernelDelayThread(u32 usec) { @@ -2518,14 +2518,14 @@ int sceKernelDelayThread(u32 usec) { s64 delayUs = __KernelDelayThreadUs(usec); __KernelScheduleWakeup(curThread, delayUs); __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, false, "thread delayed"); - return hleLogSuccessI(SCEKERNEL, 0, "delaying %lld usecs", delayUs); + return hleLogSuccessI(Log::sceKernel, 0, "delaying %lld usecs", delayUs); } int sceKernelDelaySysClockThreadCB(u32 sysclockAddr) { auto sysclock = PSPPointer::Create(sysclockAddr); if (!sysclock.IsValid()) { // Note: crashes on real firmware. - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointer"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointer"); } // This is just a u64 of usecs. All bits are respected, but overflow can happen for very large values. @@ -2535,14 +2535,14 @@ int sceKernelDelaySysClockThreadCB(u32 sysclockAddr) { s64 delayUs = __KernelDelayThreadUs(usec); __KernelScheduleWakeup(curThread, delayUs); __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true, "thread delayed"); - return hleLogSuccessI(SCEKERNEL, 0, "delaying %lld usecs", delayUs); + return hleLogSuccessI(Log::sceKernel, 0, "delaying %lld usecs", delayUs); } int sceKernelDelaySysClockThread(u32 sysclockAddr) { auto sysclock = PSPPointer::Create(sysclockAddr); if (!sysclock.IsValid()) { // Note: crashes on real firmware. - return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointer"); + return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointer"); } // This is just a u64 of usecs. All bits are respected, but overflow can happen for very large values. @@ -2552,7 +2552,7 @@ int sceKernelDelaySysClockThread(u32 sysclockAddr) { s64 delayUs = __KernelDelayThreadUs(usec); __KernelScheduleWakeup(curThread, delayUs); __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, false, "thread delayed"); - return hleLogSuccessI(SCEKERNEL, 0, "delaying %lld usecs", delayUs); + return hleLogSuccessI(Log::sceKernel, 0, "delaying %lld usecs", delayUs); } u32 __KernelGetThreadPrio(SceUID id) { @@ -2573,7 +2573,7 @@ bool __KernelThreadSortPriority(SceUID thread1, SceUID thread2) ////////////////////////////////////////////////////////////////////////// int sceKernelWakeupThread(SceUID uid) { if (uid == currentThread) { - return hleLogWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_THID, "unable to wakeup current thread"); + return hleLogWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_THID, "unable to wakeup current thread"); } u32 error; @@ -2581,14 +2581,14 @@ int sceKernelWakeupThread(SceUID uid) { if (t) { if (!t->isWaitingFor(WAITTYPE_SLEEP, 0)) { t->nt.wakeupCount++; - return hleLogSuccessI(SCEKERNEL, 0, "wakeupCount incremented to %i", t->nt.wakeupCount); + return hleLogSuccessI(Log::sceKernel, 0, "wakeupCount incremented to %i", t->nt.wakeupCount); } else { __KernelResumeThreadFromWait(uid, 0); hleReSchedule("thread woken up"); - return hleLogSuccessVerboseI(SCEKERNEL, 0, "woke thread at %i", t->nt.wakeupCount); + return hleLogSuccessVerboseI(Log::sceKernel, 0, "woke thread at %i", t->nt.wakeupCount); } } else { - return hleLogError(SCEKERNEL, error, "bad thread id"); + return hleLogError(Log::sceKernel, error, "bad thread id"); } } @@ -2602,25 +2602,25 @@ int sceKernelCancelWakeupThread(SceUID uid) { if (t) { int wCount = t->nt.wakeupCount; t->nt.wakeupCount = 0; - return hleLogSuccessI(SCEKERNEL, wCount, "wakeupCount reset to 0"); + return hleLogSuccessI(Log::sceKernel, wCount, "wakeupCount reset to 0"); } else { - return hleLogError(SCEKERNEL, error, "bad thread id"); + return hleLogError(Log::sceKernel, error, "bad thread id"); } } static int __KernelSleepThread(bool doCallbacks) { PSPThread *thread = __GetCurrentThread(); if (!thread) { - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelSleepThread*(): bad current thread"); + ERROR_LOG_REPORT(Log::sceKernel, "sceKernelSleepThread*(): bad current thread"); return -1; } if (thread->nt.wakeupCount > 0) { thread->nt.wakeupCount--; - return hleLogSuccessI(SCEKERNEL, 0, "wakeupCount decremented to %i", thread->nt.wakeupCount); + return hleLogSuccessI(Log::sceKernel, 0, "wakeupCount decremented to %i", thread->nt.wakeupCount); } else { __KernelWaitCurThread(WAITTYPE_SLEEP, 0, 0, 0, doCallbacks, "thread slept"); - return hleLogSuccessVerboseI(SCEKERNEL, 0, "sleeping"); + return hleLogSuccessVerboseI(Log::sceKernel, 0, "sleeping"); } return 0; } @@ -2636,7 +2636,7 @@ int sceKernelSleepThreadCB() { int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr) { - DEBUG_LOG(SCEKERNEL, "sceKernelWaitThreadEnd(%i, %08x)", threadID, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEnd(%i, %08x)", threadID, timeoutPtr); if (threadID == 0 || threadID == currentThread) return SCE_KERNEL_ERROR_ILLEGAL_THID; @@ -2662,14 +2662,14 @@ int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr) } else { - ERROR_LOG(SCEKERNEL, "sceKernelWaitThreadEnd - bad thread %i", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelWaitThreadEnd - bad thread %i", threadID); return error; } } int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr) { - DEBUG_LOG(SCEKERNEL, "sceKernelWaitThreadEndCB(%i, 0x%X)", threadID, timeoutPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB(%i, 0x%X)", threadID, timeoutPtr); if (threadID == 0 || threadID == currentThread) return SCE_KERNEL_ERROR_ILLEGAL_THID; @@ -2697,16 +2697,16 @@ int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr) } else { - ERROR_LOG(SCEKERNEL, "sceKernelWaitThreadEndCB - bad thread %i", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelWaitThreadEndCB - bad thread %i", threadID); return error; } } int sceKernelReleaseWaitThread(SceUID threadID) { - DEBUG_LOG(SCEKERNEL, "sceKernelReleaseWaitThread(%i)", threadID); + DEBUG_LOG(Log::sceKernel, "sceKernelReleaseWaitThread(%i)", threadID); if (__KernelInCallback()) - WARN_LOG_REPORT(SCEKERNEL, "UNTESTED sceKernelReleaseWaitThread() might not do the right thing in a callback"); + WARN_LOG_REPORT(Log::sceKernel, "UNTESTED sceKernelReleaseWaitThread() might not do the right thing in a callback"); if (threadID == 0 || threadID == currentThread) return SCE_KERNEL_ERROR_ILLEGAL_THID; @@ -2719,12 +2719,12 @@ int sceKernelReleaseWaitThread(SceUID threadID) return SCE_KERNEL_ERROR_NOT_WAIT; if (t->nt.waitType == WAITTYPE_HLEDELAY) { - WARN_LOG_REPORT_ONCE(rwt_delay, SCEKERNEL, "sceKernelReleaseWaitThread(): Refusing to wake HLE-delayed thread, right thing to do?"); + WARN_LOG_REPORT_ONCE(rwt_delay, Log::sceKernel, "sceKernelReleaseWaitThread(): Refusing to wake HLE-delayed thread, right thing to do?"); return SCE_KERNEL_ERROR_NOT_WAIT; } if (t->nt.waitType == WAITTYPE_MODULE) { - WARN_LOG_REPORT_ONCE(rwt_sm, SCEKERNEL, "sceKernelReleaseWaitThread(): Refusing to wake start_module thread, right thing to do?"); + WARN_LOG_REPORT_ONCE(rwt_sm, Log::sceKernel, "sceKernelReleaseWaitThread(): Refusing to wake start_module thread, right thing to do?"); return SCE_KERNEL_ERROR_NOT_WAIT; } @@ -2734,7 +2734,7 @@ int sceKernelReleaseWaitThread(SceUID threadID) } else { - ERROR_LOG(SCEKERNEL, "sceKernelReleaseWaitThread - bad thread %i", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelReleaseWaitThread - bad thread %i", threadID); return error; } } @@ -2744,7 +2744,7 @@ int sceKernelSuspendThread(SceUID threadID) // TODO: What about interrupts/callbacks? if (threadID == 0 || threadID == currentThread) { - ERROR_LOG(SCEKERNEL, "sceKernelSuspendThread(%d): cannot suspend current thread", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelSuspendThread(%d): cannot suspend current thread", threadID); return SCE_KERNEL_ERROR_ILLEGAL_THID; } @@ -2754,16 +2754,16 @@ int sceKernelSuspendThread(SceUID threadID) { if (t->isStopped()) { - ERROR_LOG(SCEKERNEL, "sceKernelSuspendThread(%d): thread not running", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelSuspendThread(%d): thread not running", threadID); return SCE_KERNEL_ERROR_DORMANT; } if (t->isSuspended()) { - ERROR_LOG(SCEKERNEL, "sceKernelSuspendThread(%d): thread already suspended", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelSuspendThread(%d): thread already suspended", threadID); return SCE_KERNEL_ERROR_SUSPEND; } - DEBUG_LOG(SCEKERNEL, "sceKernelSuspendThread(%d)", threadID); + DEBUG_LOG(Log::sceKernel, "sceKernelSuspendThread(%d)", threadID); if (t->isReady()) __KernelChangeReadyState(t, threadID, false); t->nt.status = (t->nt.status & ~THREADSTATUS_READY) | THREADSTATUS_SUSPEND; @@ -2771,7 +2771,7 @@ int sceKernelSuspendThread(SceUID threadID) } else { - ERROR_LOG(SCEKERNEL, "sceKernelSuspendThread(%d): bad thread", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelSuspendThread(%d): bad thread", threadID); return error; } } @@ -2781,7 +2781,7 @@ int sceKernelResumeThread(SceUID threadID) // TODO: What about interrupts/callbacks? if (threadID == 0 || threadID == currentThread) { - ERROR_LOG(SCEKERNEL, "sceKernelResumeThread(%d): cannot suspend current thread", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelResumeThread(%d): cannot suspend current thread", threadID); return SCE_KERNEL_ERROR_ILLEGAL_THID; } @@ -2791,10 +2791,10 @@ int sceKernelResumeThread(SceUID threadID) { if (!t->isSuspended()) { - ERROR_LOG(SCEKERNEL, "sceKernelResumeThread(%d): thread not suspended", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelResumeThread(%d): thread not suspended", threadID); return SCE_KERNEL_ERROR_NOT_SUSPEND; } - DEBUG_LOG(SCEKERNEL, "sceKernelResumeThread(%d)", threadID); + DEBUG_LOG(Log::sceKernel, "sceKernelResumeThread(%d)", threadID); t->nt.status &= ~THREADSTATUS_SUSPEND; // If it was dormant, waiting, etc. before we don't flip its ready state. @@ -2805,7 +2805,7 @@ int sceKernelResumeThread(SceUID threadID) } else { - ERROR_LOG(SCEKERNEL, "sceKernelResumeThread(%d): bad thread", threadID); + ERROR_LOG(Log::sceKernel, "sceKernelResumeThread(%d): bad thread", threadID); return error; } } @@ -2819,9 +2819,9 @@ int sceKernelResumeThread(SceUID threadID) SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg) { if (!name) - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name"); if (entrypoint & 0xF0000000) - return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid func"); + return hleReportWarning(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid func"); PSPCallback *cb = new PSPCallback(); SceUID id = kernelObjects.Create(cb); @@ -2839,7 +2839,7 @@ SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg) if (thread) thread->callbacks.push_back(id); - return hleLogSuccessI(SCEKERNEL, id); + return hleLogSuccessI(Log::sceKernel, id); } int sceKernelDeleteCallback(SceUID cbId) @@ -2854,9 +2854,9 @@ int sceKernelDeleteCallback(SceUID cbId) if (cb->nc.notifyCount != 0) readyCallbacksCount--; - return hleLogSuccessI(SCEKERNEL, kernelObjects.Destroy(cbId)); + return hleLogSuccessI(Log::sceKernel, kernelObjects.Destroy(cbId)); } else { - return hleLogError(SCEKERNEL, error, "bad cbId"); + return hleLogError(Log::sceKernel, error, "bad cbId"); } } @@ -2867,9 +2867,9 @@ int sceKernelNotifyCallback(SceUID cbId, int notifyArg) PSPCallback *cb = kernelObjects.Get(cbId, error); if (cb) { __KernelNotifyCallback(cbId, notifyArg); - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error, "bad cbId"); + return hleLogError(Log::sceKernel, error, "bad cbId"); } } @@ -2880,9 +2880,9 @@ int sceKernelCancelCallback(SceUID cbId) if (cb) { // This just resets the notify count. cb->nc.notifyArg = 0; - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogError(SCEKERNEL, error, "bad cbId"); + return hleLogError(Log::sceKernel, error, "bad cbId"); } } @@ -2891,9 +2891,9 @@ int sceKernelGetCallbackCount(SceUID cbId) u32 error; PSPCallback *cb = kernelObjects.Get(cbId, error); if (cb) { - return hleLogSuccessVerboseI(SCEKERNEL, cb->nc.notifyCount); + return hleLogSuccessVerboseI(Log::sceKernel, cb->nc.notifyCount); } else { - return hleLogError(SCEKERNEL, error, "bad cbId"); + return hleLogError(Log::sceKernel, error, "bad cbId"); } } @@ -2905,26 +2905,26 @@ int sceKernelReferCallbackStatus(SceUID cbId, u32 statusAddr) { if (status.IsValid() && status->size != 0) { *status = c->nc; status.NotifyWrite("CallbackStatus"); - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogDebug(SCEKERNEL, 0, "struct size was 0"); + return hleLogDebug(Log::sceKernel, 0, "struct size was 0"); } } else { - return hleLogError(SCEKERNEL, error, "bad cbId"); + return hleLogError(Log::sceKernel, error, "bad cbId"); } } u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter) { if (size < 512) - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE, "xxx", "stack size too small"); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE, "xxx", "stack size too small"); PSPThread *thread = __GetCurrentThread(); if (!thread) - return hleReportError(SCEKERNEL, -1, "xxx", "not on a thread?"); + return hleReportError(Log::sceKernel, -1, "xxx", "not on a thread?"); if (!thread->PushExtendedStack(size)) - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_NO_MEMORY, "xxx", "could not allocate new stack"); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_NO_MEMORY, "xxx", "could not allocate new stack"); // The stack has been changed now, so it's do or die time. @@ -2942,7 +2942,7 @@ u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter) currentMIPS->r[MIPS_REG_SP] = thread->currentStack.end - 0x10; hleSkipDeadbeef(); - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } void __KernelReturnFromExtendStack() @@ -2952,7 +2952,7 @@ void __KernelReturnFromExtendStack() PSPThread *thread = __GetCurrentThread(); if (!thread) { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelReturnFromExtendStack() - not on a thread?"); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelReturnFromExtendStack() - not on a thread?"); return; } @@ -2963,13 +2963,13 @@ void __KernelReturnFromExtendStack() if (!thread->PopExtendedStack()) { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelReturnFromExtendStack() - no stack to restore?"); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelReturnFromExtendStack() - no stack to restore?"); return; } KernelValidateThreadTarget(restorePC); - DEBUG_LOG(SCEKERNEL, "__KernelReturnFromExtendStack()"); + DEBUG_LOG(Log::sceKernel, "__KernelReturnFromExtendStack()"); currentMIPS->r[MIPS_REG_RA] = restoreRA; currentMIPS->r[MIPS_REG_SP] = restoreSP; currentMIPS->pc = restorePC; @@ -3079,7 +3079,7 @@ void __KernelSwitchContext(PSPThread *target, const char *reason) { s64 consumedCycles = nowCycles - lastSwitchCycles; lastSwitchCycles = nowCycles; - DEBUG_LOG(SCEKERNEL, "Context switch: %s -> %s (%i->%i, pc: %08x->%08x, %s) +%lldus", + DEBUG_LOG(Log::sceKernel, "Context switch: %s -> %s (%i->%i, pc: %08x->%08x, %s) +%lldus", oldName, hleCurrentThreadName, oldUID, currentThread, oldPC, currentMIPS->pc, @@ -3112,7 +3112,7 @@ void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus) { return; if (!dispatchEnabled && thread == __GetCurrentThread() && newStatus != THREADSTATUS_RUNNING) { - ERROR_LOG(SCEKERNEL, "Dispatching suspended, not changing thread state"); + ERROR_LOG(Log::sceKernel, "Dispatching suspended, not changing thread state"); return; } @@ -3124,7 +3124,7 @@ void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus) { if (newStatus == THREADSTATUS_WAIT) { if (thread->nt.waitType == WAITTYPE_NONE) { - ERROR_LOG(SCEKERNEL, "Waittype none not allowed here"); + ERROR_LOG(Log::sceKernel, "Waittype none not allowed here"); } // Schedule deletion of stopped threads here. if (thread->isStopped()) @@ -3140,7 +3140,7 @@ static bool __CanExecuteCallbackNow(PSPThread *thread) { // Takes ownership of afterAction. void __KernelCallAddress(PSPThread *thread, u32 entryPoint, PSPAction *afterAction, const u32 args[], int numargs, bool reschedAfter, SceUID cbId) { if (!thread || thread->isStopped()) { - WARN_LOG_REPORT(SCEKERNEL, "Running mipscall on dormant thread"); + WARN_LOG_REPORT(Log::sceKernel, "Running mipscall on dormant thread"); } _dbg_assert_msg_(numargs <= 6, "MipsCalls can only take 6 args."); @@ -3164,7 +3164,7 @@ void __KernelCallAddress(PSPThread *thread, u32 entryPoint, PSPAction *afterActi if (waitTypeFuncs[thread->nt.waitType].beginFunc != NULL) { waitTypeFuncs[thread->nt.waitType].beginFunc(after->threadID, thread->currentCallbackId); } else { - ERROR_LOG_REPORT(HLE, "Missing begin/restore funcs for wait type %d", thread->nt.waitType); + ERROR_LOG_REPORT(Log::HLE, "Missing begin/restore funcs for wait type %d", thread->nt.waitType); } } @@ -3198,10 +3198,10 @@ void __KernelCallAddress(PSPThread *thread, u32 entryPoint, PSPAction *afterActi if (!called) { if (thread) { - DEBUG_LOG(SCEKERNEL, "Making mipscall pending on thread"); + DEBUG_LOG(Log::sceKernel, "Making mipscall pending on thread"); thread->pendingMipsCalls.push_back(callId); } else { - WARN_LOG(SCEKERNEL, "Ignoring mispcall on NULL/deleted thread"); + WARN_LOG(Log::sceKernel, "Ignoring mispcall on NULL/deleted thread"); } } } @@ -3216,20 +3216,20 @@ bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter) PSPThread *cur = __GetCurrentThread(); if (cur == nullptr) { - ERROR_LOG(SCEKERNEL, "__KernelExecuteMipsCallOnCurrentThread(): Bad current thread"); + ERROR_LOG(Log::sceKernel, "__KernelExecuteMipsCallOnCurrentThread(): Bad current thread"); return false; } if (g_inCbCount > 0) { - WARN_LOG_REPORT(SCEKERNEL, "__KernelExecuteMipsCallOnCurrentThread(): Already in a callback!"); + WARN_LOG_REPORT(Log::sceKernel, "__KernelExecuteMipsCallOnCurrentThread(): Already in a callback!"); } - DEBUG_LOG(SCEKERNEL, "Executing mipscall %i", callId); + DEBUG_LOG(Log::sceKernel, "Executing mipscall %i", callId); MipsCall *call = mipsCalls.get(callId); // Grab some MIPS stack space. u32 &sp = currentMIPS->r[MIPS_REG_SP]; if (!Memory::IsValidAddress(sp - 32 * 4)) { - ERROR_LOG_REPORT(SCEKERNEL, "__KernelExecuteMipsCallOnCurrentThread(): Not enough free stack"); + ERROR_LOG_REPORT(Log::sceKernel, "__KernelExecuteMipsCallOnCurrentThread(): Not enough free stack"); return false; } @@ -3273,7 +3273,7 @@ void __KernelReturnFromMipsCall() PSPThread *cur = __GetCurrentThread(); if (cur == NULL) { - ERROR_LOG(SCEKERNEL, "__KernelReturnFromMipsCall(): Bad current thread"); + ERROR_LOG(Log::sceKernel, "__KernelReturnFromMipsCall(): Bad current thread"); return; } @@ -3282,7 +3282,7 @@ void __KernelReturnFromMipsCall() // Value returned by the callback function u32 retVal = currentMIPS->r[MIPS_REG_V0]; - DEBUG_LOG(SCEKERNEL, "__KernelReturnFromMipsCall(), returned %08x", retVal); + DEBUG_LOG(Log::sceKernel, "__KernelReturnFromMipsCall(), returned %08x", retVal); // TODO: Should also save/restore wait state here? if (call->doAfter) { @@ -3321,7 +3321,7 @@ void __KernelReturnFromMipsCall() if (waitTypeFuncs[cur->nt.waitType].endFunc != NULL) waitTypeFuncs[cur->nt.waitType].endFunc(cur->GetUID(), cur->currentCallbackId); else - ERROR_LOG_REPORT(HLE, "Missing begin/restore funcs for wait type %d", cur->nt.waitType); + ERROR_LOG_REPORT(Log::HLE, "Missing begin/restore funcs for wait type %d", cur->nt.waitType); } } @@ -3368,11 +3368,11 @@ static void __KernelRunCallbackOnThread(SceUID cbId, PSPThread *thread, bool res u32 error; PSPCallback *cb = kernelObjects.Get(cbId, error); if (!cb) { - ERROR_LOG(SCEKERNEL, "__KernelRunCallbackOnThread: Bad cbId %i", cbId); + ERROR_LOG(Log::sceKernel, "__KernelRunCallbackOnThread: Bad cbId %i", cbId); return; } - DEBUG_LOG(SCEKERNEL, "__KernelRunCallbackOnThread: Turning callback %i into pending mipscall", cbId); + DEBUG_LOG(Log::sceKernel, "__KernelRunCallbackOnThread: Turning callback %i into pending mipscall", cbId); // Alright, we're on the right thread // Should save/restore wait state? @@ -3387,7 +3387,7 @@ static void __KernelRunCallbackOnThread(SceUID cbId, PSPThread *thread, bool res if (action != NULL) action->setCallback(cbId); else - ERROR_LOG(SCEKERNEL, "Something went wrong creating a restore action for a callback."); + ERROR_LOG(Log::sceKernel, "Something went wrong creating a restore action for a callback."); __KernelCallAddress(thread, cb->nc.entrypoint, action, args, 3, reschedAfter, cbId); } @@ -3403,10 +3403,10 @@ void ActionAfterCallback::run(MipsCall &call) { __KernelCheckThreadCallbacks(t, true); } - DEBUG_LOG(SCEKERNEL, "Left callback %i - %s", cbId, cb->nc.name); + DEBUG_LOG(Log::sceKernel, "Left callback %i - %s", cbId, cb->nc.name); // Callbacks that don't return 0 are deleted. But should this be done here? if (currentMIPS->r[MIPS_REG_V0] != 0) { - DEBUG_LOG(SCEKERNEL, "ActionAfterCallback::run(): Callback returned non-zero, gets deleted!"); + DEBUG_LOG(Log::sceKernel, "ActionAfterCallback::run(): Callback returned non-zero, gets deleted!"); kernelObjects.Destroy(cbId); } } @@ -3457,7 +3457,7 @@ bool __KernelCheckCallbacks() { return false; } if (readyCallbacksCount < 0) { - ERROR_LOG_REPORT(SCEKERNEL, "readyCallbacksCount became negative: %i", readyCallbacksCount); + ERROR_LOG_REPORT(Log::sceKernel, "readyCallbacksCount became negative: %i", readyCallbacksCount); } if (__IsInInterrupt() || !__KernelIsDispatchEnabled() || __KernelInCallback()) { // TODO: Technically, other callbacks can run when a thread within a callback is waiting. @@ -3489,7 +3489,7 @@ bool __KernelForceCallbacks() return false; } if (readyCallbacksCount < 0) { - ERROR_LOG_REPORT(SCEKERNEL, "readyCallbacksCount became negative: %i", readyCallbacksCount); + ERROR_LOG_REPORT(Log::sceKernel, "readyCallbacksCount became negative: %i", readyCallbacksCount); } PSPThread *curThread = __GetCurrentThread(); @@ -3510,7 +3510,7 @@ void sceKernelCheckCallback() bool callbacksProcessed = __KernelForceCallbacks(); if (callbacksProcessed) { - DEBUG_LOG(SCEKERNEL, "sceKernelCheckCallback() - processed a callback."); + DEBUG_LOG(Log::sceKernel, "sceKernelCheckCallback() - processed a callback."); // The RETURN(1) above is still active here, unless __KernelForceCallbacks changed it. } else { RETURN(0); @@ -3530,7 +3530,7 @@ void __KernelNotifyCallback(SceUID cbId, int notifyArg) PSPCallback *cb = kernelObjects.Get(cbId, error); if (!cb) { // Yeah, we're screwed, this shouldn't happen. - ERROR_LOG(SCEKERNEL, "__KernelNotifyCallback - invalid callback %08x", cbId); + ERROR_LOG(Log::sceKernel, "__KernelNotifyCallback - invalid callback %08x", cbId); return; } if (cb->nc.notifyCount == 0) { @@ -3606,45 +3606,45 @@ int sceKernelRegisterExitCallback(SceUID cbId) PSPCallback *cb = kernelObjects.Get(cbId, error); if (!cb) { - WARN_LOG(SCEKERNEL, "sceKernelRegisterExitCallback(%i): invalid callback id", cbId); + WARN_LOG(Log::sceKernel, "sceKernelRegisterExitCallback(%i): invalid callback id", cbId); if (sceKernelGetCompiledSdkVersion() >= 0x3090500) return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; return 0; } - DEBUG_LOG(SCEKERNEL, "sceKernelRegisterExitCallback(%i)", cbId); + DEBUG_LOG(Log::sceKernel, "sceKernelRegisterExitCallback(%i)", cbId); registeredExitCbId = cbId; return 0; } int LoadExecForUser_362A956B() { - WARN_LOG_REPORT(SCEKERNEL, "LoadExecForUser_362A956B()"); + WARN_LOG_REPORT(Log::sceKernel, "LoadExecForUser_362A956B()"); u32 error; PSPCallback *cb = kernelObjects.Get(registeredExitCbId, error); if (!cb) { - WARN_LOG(SCEKERNEL, "LoadExecForUser_362A956B() : registeredExitCbId not found 0x%x", registeredExitCbId); + WARN_LOG(Log::sceKernel, "LoadExecForUser_362A956B() : registeredExitCbId not found 0x%x", registeredExitCbId); return SCE_KERNEL_ERROR_UNKNOWN_CBID; } int cbArg = cb->nc.commonArgument; if (!Memory::IsValidAddress(cbArg)) { - WARN_LOG(SCEKERNEL, "LoadExecForUser_362A956B() : invalid address for cbArg (0x%08X)", cbArg); + WARN_LOG(Log::sceKernel, "LoadExecForUser_362A956B() : invalid address for cbArg (0x%08X)", cbArg); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } u32 unknown1 = Memory::Read_U32(cbArg - 8); if (unknown1 >= 4) { - WARN_LOG(SCEKERNEL, "LoadExecForUser_362A956B() : invalid value unknown1 (0x%08X)", unknown1); + WARN_LOG(Log::sceKernel, "LoadExecForUser_362A956B() : invalid value unknown1 (0x%08X)", unknown1); return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; } u32 parameterArea = Memory::Read_U32(cbArg - 4); if (!Memory::IsValidAddress(parameterArea)) { - WARN_LOG(SCEKERNEL, "LoadExecForUser_362A956B() : invalid address for parameterArea on userMemory (0x%08X)", parameterArea); + WARN_LOG(Log::sceKernel, "LoadExecForUser_362A956B() : invalid address for parameterArea on userMemory (0x%08X)", parameterArea); return SCE_KERNEL_ERROR_ILLEGAL_ADDR; } u32 size = Memory::Read_U32(parameterArea); if (size < 12) { - WARN_LOG(SCEKERNEL, "LoadExecForUser_362A956B() : invalid parameterArea size %d", size); + WARN_LOG(Log::sceKernel, "LoadExecForUser_362A956B() : invalid parameterArea size %d", size); return SCE_KERNEL_ERROR_ILLEGAL_SIZE; } Memory::Write_U32(0, parameterArea + 4); @@ -3735,20 +3735,20 @@ bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u32 mask, u32 handlerPtr, u32 commonArg) { if (!name) { - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name"); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ERROR, "invalid name"); } if (threadID == 0) { // "atexit"? if (mask != THREADEVENT_EXIT) { - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid thread id"); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid thread id"); } } u32 error; if (kernelObjects.Get(threadID, error) == NULL && threadID != SCE_TE_THREADID_ALL_USER) { - return hleReportError(SCEKERNEL, error, "bad thread id"); + return hleReportError(Log::sceKernel, error, "bad thread id"); } if ((mask & ~THREADEVENT_SUPPORTED) != 0) { - return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MASK, "invalid event mask"); + return hleReportError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_MASK, "invalid event mask"); } auto teh = new ThreadEventHandler; @@ -3763,34 +3763,34 @@ SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u3 SceUID uid = kernelObjects.Create(teh); threadEventHandlers[threadID].push_back(uid); - return hleLogSuccessI(SCEKERNEL, uid); + return hleLogSuccessI(Log::sceKernel, uid); } int sceKernelReleaseThreadEventHandler(SceUID uid) { u32 error; auto teh = kernelObjects.Get(uid, error); if (!teh) { - return hleReportError(SCEKERNEL, error, "bad handler id"); + return hleReportError(Log::sceKernel, error, "bad handler id"); } auto &handlers = threadEventHandlers[teh->nteh.threadID]; handlers.erase(std::remove(handlers.begin(), handlers.end(), uid), handlers.end()); - return hleLogSuccessI(SCEKERNEL, kernelObjects.Destroy(uid)); + return hleLogSuccessI(Log::sceKernel, kernelObjects.Destroy(uid)); } int sceKernelReferThreadEventHandlerStatus(SceUID uid, u32 infoPtr) { u32 error; auto teh = kernelObjects.Get(uid, error); if (!teh) { - return hleReportError(SCEKERNEL, error, "bad handler id"); + return hleReportError(Log::sceKernel, error, "bad handler id"); } auto info = PSPPointer::Create(infoPtr); if (info.IsValid() && info->size != 0) { *info = teh->nteh; info.NotifyWrite("ThreadEventHandlerStatus"); - return hleLogSuccessI(SCEKERNEL, 0); + return hleLogSuccessI(Log::sceKernel, 0); } else { - return hleLogDebug(SCEKERNEL, 0, "struct size was 0"); + return hleLogDebug(Log::sceKernel, 0, "struct size was 0"); } } diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 67fe49189f..5c300283ac 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -71,7 +71,7 @@ int sceKernelGetSystemTime(u32 sysclockPtr) u64 t = CoreTiming::GetGlobalTimeUs(); if (Memory::IsValidAddress(sysclockPtr)) Memory::Write_U64(t, sysclockPtr); - VERBOSE_LOG(SCEKERNEL, "sceKernelGetSystemTime(out:%16llx)", t); + VERBOSE_LOG(Log::sceKernel, "sceKernelGetSystemTime(out:%16llx)", t); hleEatCycles(265); hleReSchedule("system time"); return 0; @@ -81,7 +81,7 @@ u32 sceKernelGetSystemTimeLow() { // This clock should tick at 1 Mhz. u64 t = CoreTiming::GetGlobalTimeUs(); - VERBOSE_LOG(SCEKERNEL,"%08x=sceKernelGetSystemTimeLow()",(u32)t); + VERBOSE_LOG(Log::sceKernel,"%08x=sceKernelGetSystemTimeLow()",(u32)t); hleEatCycles(165); hleReSchedule("system time"); return (u32)t; @@ -90,7 +90,7 @@ u32 sceKernelGetSystemTimeLow() u64 sceKernelGetSystemTimeWide() { u64 t = CoreTiming::GetGlobalTimeUsScaled(); - VERBOSE_LOG(SCEKERNEL,"%i=sceKernelGetSystemTimeWide()",(u32)t); + VERBOSE_LOG(Log::sceKernel,"%i=sceKernelGetSystemTimeWide()",(u32)t); hleEatCycles(250); hleReSchedule("system time"); return t; @@ -98,7 +98,7 @@ u64 sceKernelGetSystemTimeWide() int sceKernelUSec2SysClock(u32 usec, u32 clockPtr) { - VERBOSE_LOG(SCEKERNEL, "sceKernelUSec2SysClock(%i, %08x)", usec, clockPtr); + VERBOSE_LOG(Log::sceKernel, "sceKernelUSec2SysClock(%i, %08x)", usec, clockPtr); if (Memory::IsValidAddress(clockPtr)) Memory::Write_U64((usec & 0xFFFFFFFFL), clockPtr); hleEatCycles(165); @@ -107,14 +107,14 @@ int sceKernelUSec2SysClock(u32 usec, u32 clockPtr) u64 sceKernelUSec2SysClockWide(u32 usec) { - VERBOSE_LOG(SCEKERNEL, "sceKernelUSec2SysClockWide(%i)", usec); + VERBOSE_LOG(Log::sceKernel, "sceKernelUSec2SysClockWide(%i)", usec); hleEatCycles(150); return usec; } int sceKernelSysClock2USec(u32 sysclockPtr, u32 highPtr, u32 lowPtr) { - DEBUG_LOG(SCEKERNEL, "sceKernelSysClock2USec(clock = %08x, lo = %08x, hi = %08x)", sysclockPtr, highPtr, lowPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelSysClock2USec(clock = %08x, lo = %08x, hi = %08x)", sysclockPtr, highPtr, lowPtr); u64 time = Memory::Read_U64(sysclockPtr); u32 highResult = (u32)(time / 1000000); u32 lowResult = (u32)(time % 1000000); @@ -129,7 +129,7 @@ int sceKernelSysClock2USec(u32 sysclockPtr, u32 highPtr, u32 lowPtr) int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 highPtr) { u64 sysClock = lowClock | ((u64)highClock << 32); - DEBUG_LOG(SCEKERNEL, "sceKernelSysClock2USecWide(clock = %llu, lo = %08x, hi = %08x)", sysClock, lowPtr, highPtr); + DEBUG_LOG(Log::sceKernel, "sceKernelSysClock2USecWide(clock = %llu, lo = %08x, hi = %08x)", sysClock, lowPtr, highPtr); if (Memory::IsValidAddress(lowPtr)) { Memory::Write_U32((u32)(sysClock / 1000000), lowPtr); if (Memory::IsValidAddress(highPtr)) @@ -144,7 +144,7 @@ int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 high u32 sceKernelLibcClock() { u32 retVal = (u32) CoreTiming::GetGlobalTimeUs(); - DEBUG_LOG(SCEKERNEL, "%i = sceKernelLibcClock", retVal); + DEBUG_LOG(Log::sceKernel, "%i = sceKernelLibcClock", retVal); hleEatCycles(330); hleReSchedule("libc clock"); return retVal; @@ -154,7 +154,7 @@ u32 sceKernelLibcTime(u32 outPtr) { u32 t = (u32) start_time + (u32) (CoreTiming::GetGlobalTimeUs() / 1000000ULL); - DEBUG_LOG(SCEKERNEL, "%i = sceKernelLibcTime(%08X)", t, outPtr); + DEBUG_LOG(Log::sceKernel, "%i = sceKernelLibcTime(%08X)", t, outPtr); // The PSP sure takes its sweet time on this function. hleEatCycles(3385); @@ -176,7 +176,7 @@ u32 sceKernelLibcGettimeofday(u32 timeAddr, u32 tzAddr) __RtcTimeOfDay(tv); } - DEBUG_LOG(SCEKERNEL,"sceKernelLibcGettimeofday(%08x, %08x)", timeAddr, tzAddr); + DEBUG_LOG(Log::sceKernel,"sceKernelLibcGettimeofday(%08x, %08x)", timeAddr, tzAddr); hleEatCycles(1885); hleReSchedule("libc timeofday"); diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index ce26b208ac..f9e836e8ee 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -216,10 +216,10 @@ void __KernelVTimerInit() { u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) { if (!name) { - WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateVTimer(): invalid name", SCE_KERNEL_ERROR_ERROR); + WARN_LOG_REPORT(Log::sceKernel, "%08x=sceKernelCreateVTimer(): invalid name", SCE_KERNEL_ERROR_ERROR); return SCE_KERNEL_ERROR_ERROR; } - DEBUG_LOG(SCEKERNEL, "sceKernelCreateVTimer(%s, %08x)", name, optParamAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelCreateVTimer(%s, %08x)", name, optParamAddr); VTimer *vtimer = new VTimer; SceUID id = kernelObjects.Create(vtimer); @@ -232,20 +232,20 @@ u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) { if (optParamAddr != 0) { u32 size = Memory::Read_U32(optParamAddr); if (size > 4) - WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateVTimer(%s) unsupported options parameter, size = %d", name, size); + WARN_LOG_REPORT(Log::sceKernel, "sceKernelCreateVTimer(%s) unsupported options parameter, size = %d", name, size); } return id; } u32 sceKernelDeleteVTimer(SceUID uid) { - DEBUG_LOG(SCEKERNEL, "sceKernelDeleteVTimer(%08x)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelDeleteVTimer(%08x)", uid); u32 error; VTimer* vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelDeleteVTimer(%08x)", error, uid); + WARN_LOG(Log::sceKernel, "%08x=sceKernelDeleteVTimer(%08x)", error, uid); return error; } @@ -260,13 +260,13 @@ u32 sceKernelDeleteVTimer(SceUID uid) { } u32 sceKernelGetVTimerBase(SceUID uid, u32 baseClockAddr) { - DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerBase(%08x, %08x)", uid, baseClockAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelGetVTimerBase(%08x, %08x)", uid, baseClockAddr); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerBase(%08x, %08x)", error, uid, baseClockAddr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelGetVTimerBase(%08x, %08x)", error, uid, baseClockAddr); return error; } @@ -277,13 +277,13 @@ u32 sceKernelGetVTimerBase(SceUID uid, u32 baseClockAddr) { } u64 sceKernelGetVTimerBaseWide(SceUID uid) { - DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerBaseWide(%08x)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelGetVTimerBaseWide(%08x)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerBaseWide(%08x)", error, uid); + WARN_LOG(Log::sceKernel, "%08x=sceKernelGetVTimerBaseWide(%08x)", error, uid); return -1; } @@ -291,13 +291,13 @@ u64 sceKernelGetVTimerBaseWide(SceUID uid) { } u32 sceKernelGetVTimerTime(SceUID uid, u32 timeClockAddr) { - DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerTime(%08x, %08x)", uid, timeClockAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelGetVTimerTime(%08x, %08x)", uid, timeClockAddr); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerTime(%08x, %08x)", error, uid, timeClockAddr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelGetVTimerTime(%08x, %08x)", error, uid, timeClockAddr); return error; } @@ -309,13 +309,13 @@ u32 sceKernelGetVTimerTime(SceUID uid, u32 timeClockAddr) { } u64 sceKernelGetVTimerTimeWide(SceUID uid) { - DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerTimeWide(%08x)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelGetVTimerTimeWide(%08x)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerTimeWide(%08x)", error, uid); + WARN_LOG(Log::sceKernel, "%08x=sceKernelGetVTimerTimeWide(%08x)", error, uid); return -1; } @@ -334,13 +334,13 @@ static u64 __KernelSetVTimer(VTimer *vt, u64 time) { } u32 sceKernelSetVTimerTime(SceUID uid, u32 timeClockAddr) { - DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTime(%08x, %08x)", uid, timeClockAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelSetVTimerTime(%08x, %08x)", uid, timeClockAddr); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerTime(%08x, %08x)", error, uid, timeClockAddr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelSetVTimerTime(%08x, %08x)", error, uid, timeClockAddr); return error; } @@ -353,16 +353,16 @@ u32 sceKernelSetVTimerTime(SceUID uid, u32 timeClockAddr) { u64 sceKernelSetVTimerTimeWide(SceUID uid, u64 timeClock) { if (__IsInInterrupt()) { - WARN_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu): in interrupt", uid, timeClock); + WARN_LOG(Log::sceKernel, "sceKernelSetVTimerTimeWide(%08x, %llu): in interrupt", uid, timeClock); return -1; } - DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu)", uid, timeClock); + DEBUG_LOG(Log::sceKernel, "sceKernelSetVTimerTimeWide(%08x, %llu)", uid, timeClock); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (error || vt == NULL) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerTimeWide(%08x, %llu)", error, uid, timeClock); + WARN_LOG(Log::sceKernel, "%08x=sceKernelSetVTimerTimeWide(%08x, %llu)", error, uid, timeClock); return -1; } @@ -381,11 +381,11 @@ u32 sceKernelStartVTimer(SceUID uid) { hleEatCycles(12200); if (uid == runningVTimer) { - WARN_LOG(SCEKERNEL, "sceKernelStartVTimer(%08x): invalid vtimer", uid); + WARN_LOG(Log::sceKernel, "sceKernelStartVTimer(%08x): invalid vtimer", uid); return SCE_KERNEL_ERROR_ILLEGAL_VTID; } - DEBUG_LOG(SCEKERNEL, "sceKernelStartVTimer(%08x)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelStartVTimer(%08x)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); @@ -410,10 +410,10 @@ static void __stopVTimer(VTimer *vt) { u32 sceKernelStopVTimer(SceUID uid) { if (uid == runningVTimer) { - WARN_LOG(SCEKERNEL, "sceKernelStopVTimer(%08x): invalid vtimer", uid); + WARN_LOG(Log::sceKernel, "sceKernelStopVTimer(%08x): invalid vtimer", uid); return SCE_KERNEL_ERROR_ILLEGAL_VTID; } - DEBUG_LOG(SCEKERNEL, "sceKernelStopVTimer(%08x)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelStopVTimer(%08x)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); @@ -432,7 +432,7 @@ u32 sceKernelStopVTimer(SceUID uid) { u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) { hleEatCycles(900); if (uid == runningVTimer) { - WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x): invalid vtimer", uid, scheduleAddr, handlerFuncAddr, commonAddr); + WARN_LOG(Log::sceKernel, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x): invalid vtimer", uid, scheduleAddr, handlerFuncAddr, commonAddr); return SCE_KERNEL_ERROR_ILLEGAL_VTID; } @@ -440,11 +440,11 @@ u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, VTimer *vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x)", error, uid, scheduleAddr, handlerFuncAddr, commonAddr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x)", error, uid, scheduleAddr, handlerFuncAddr, commonAddr); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x)", uid, scheduleAddr, handlerFuncAddr, commonAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x)", uid, scheduleAddr, handlerFuncAddr, commonAddr); hleEatCycles(2000); u64 schedule = Memory::Read_U64(scheduleAddr); @@ -462,7 +462,7 @@ u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 sceKernelSetVTimerHandlerWide(SceUID uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) { hleEatCycles(900); if (uid == runningVTimer) { - WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x): invalid vtimer", uid, schedule, handlerFuncAddr, commonAddr); + WARN_LOG(Log::sceKernel, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x): invalid vtimer", uid, schedule, handlerFuncAddr, commonAddr); return SCE_KERNEL_ERROR_ILLEGAL_VTID; } @@ -470,11 +470,11 @@ u32 sceKernelSetVTimerHandlerWide(SceUID uid, u64 schedule, u32 handlerFuncAddr, VTimer *vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x)", error, uid, schedule, handlerFuncAddr, commonAddr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x)", error, uid, schedule, handlerFuncAddr, commonAddr); return error; } - DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x)", uid, schedule, handlerFuncAddr, commonAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x)", uid, schedule, handlerFuncAddr, commonAddr); vt->nvt.handlerAddr = handlerFuncAddr; if (handlerFuncAddr) { @@ -489,24 +489,24 @@ u32 sceKernelSetVTimerHandlerWide(SceUID uid, u64 schedule, u32 handlerFuncAddr, u32 sceKernelCancelVTimerHandler(SceUID uid) { if (uid == runningVTimer) { - WARN_LOG(SCEKERNEL, "sceKernelCancelVTimerHandler(%08x): invalid vtimer", uid); + WARN_LOG(Log::sceKernel, "sceKernelCancelVTimerHandler(%08x): invalid vtimer", uid); return SCE_KERNEL_ERROR_ILLEGAL_VTID; } - DEBUG_LOG(SCEKERNEL, "sceKernelCancelVTimerHandler(%08x)", uid); + DEBUG_LOG(Log::sceKernel, "sceKernelCancelVTimerHandler(%08x)", uid); //__cancelVTimer checks if uid is valid return __KernelCancelVTimer(uid); } u32 sceKernelReferVTimerStatus(SceUID uid, u32 statusAddr) { - DEBUG_LOG(SCEKERNEL, "sceKernelReferVTimerStatus(%08x, %08x)", uid, statusAddr); + DEBUG_LOG(Log::sceKernel, "sceKernelReferVTimerStatus(%08x, %08x)", uid, statusAddr); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (error) { - WARN_LOG(SCEKERNEL, "%08x=sceKernelReferVTimerStatus(%08x, %08x)", error, uid, statusAddr); + WARN_LOG(Log::sceKernel, "%08x=sceKernelReferVTimerStatus(%08x, %08x)", error, uid, statusAddr); return error; } @@ -522,5 +522,5 @@ u32 sceKernelReferVTimerStatus(SceUID uid, u32 statusAddr) { // Not sure why this is exposed... void _sceKernelReturnFromTimerHandler() { - ERROR_LOG_REPORT(SCEKERNEL,"_sceKernelReturnFromTimerHandler - should not be called!"); + ERROR_LOG_REPORT(Log::sceKernel,"_sceKernelReturnFromTimerHandler - should not be called!"); } diff --git a/Core/HLE/sceMd5.cpp b/Core/HLE/sceMd5.cpp index 532428bfe4..7a279d5bcb 100644 --- a/Core/HLE/sceMd5.cpp +++ b/Core/HLE/sceMd5.cpp @@ -30,7 +30,7 @@ // Not really sure where these belong - is it worth giving them their own file? u32 sceKernelUtilsMt19937Init(u32 ctx, u32 seed) { - DEBUG_LOG(HLE, "sceKernelUtilsMt19937Init(%08x, %08x)", ctx, seed); + DEBUG_LOG(Log::HLE, "sceKernelUtilsMt19937Init(%08x, %08x)", ctx, seed); if (!Memory::IsValidAddress(ctx)) return -1; void *ptr = Memory::GetPointerWrite(ctx); @@ -41,7 +41,7 @@ u32 sceKernelUtilsMt19937Init(u32 ctx, u32 seed) { } u32 sceKernelUtilsMt19937UInt(u32 ctx) { - VERBOSE_LOG(HLE, "sceKernelUtilsMt19937UInt(%08x)", ctx); + VERBOSE_LOG(Log::HLE, "sceKernelUtilsMt19937UInt(%08x)", ctx); if (!Memory::IsValidAddress(ctx)) return -1; MersenneTwister *mt = (MersenneTwister *)Memory::GetPointerUnchecked(ctx); @@ -53,7 +53,7 @@ u32 sceKernelUtilsMt19937UInt(u32 ctx) { static md5_context md5_ctx; static int sceMd5Digest(u32 dataAddr, u32 len, u32 digestAddr) { - DEBUG_LOG(HLE, "sceMd5Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); + DEBUG_LOG(Log::HLE, "sceMd5Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); if (!Memory::IsValidAddress(dataAddr) || !Memory::IsValidAddress(digestAddr)) return -1; @@ -63,7 +63,7 @@ static int sceMd5Digest(u32 dataAddr, u32 len, u32 digestAddr) { } static int sceMd5BlockInit(u32 ctxAddr) { - DEBUG_LOG(HLE, "sceMd5BlockInit(%08x)", ctxAddr); + DEBUG_LOG(Log::HLE, "sceMd5BlockInit(%08x)", ctxAddr); if (!Memory::IsValidAddress(ctxAddr)) return -1; @@ -75,7 +75,7 @@ static int sceMd5BlockInit(u32 ctxAddr) { } static int sceMd5BlockUpdate(u32 ctxAddr, u32 dataPtr, u32 len) { - DEBUG_LOG(HLE, "sceMd5BlockUpdate(%08x, %08x, %d)", ctxAddr, dataPtr, len); + DEBUG_LOG(Log::HLE, "sceMd5BlockUpdate(%08x, %08x, %d)", ctxAddr, dataPtr, len); if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataPtr)) return -1; @@ -84,7 +84,7 @@ static int sceMd5BlockUpdate(u32 ctxAddr, u32 dataPtr, u32 len) { } static int sceMd5BlockResult(u32 ctxAddr, u32 digestAddr) { - DEBUG_LOG(HLE, "sceMd5BlockResult(%08x, %08x)", ctxAddr, digestAddr); + DEBUG_LOG(Log::HLE, "sceMd5BlockResult(%08x, %08x)", ctxAddr, digestAddr); if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; @@ -93,7 +93,7 @@ static int sceMd5BlockResult(u32 ctxAddr, u32 digestAddr) { } int sceKernelUtilsMd5Digest(u32 dataAddr, int len, u32 digestAddr) { - DEBUG_LOG(HLE, "sceKernelUtilsMd5Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); + DEBUG_LOG(Log::HLE, "sceKernelUtilsMd5Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); if (!Memory::IsValidAddress(dataAddr) || !Memory::IsValidAddress(digestAddr)) return -1; @@ -103,7 +103,7 @@ int sceKernelUtilsMd5Digest(u32 dataAddr, int len, u32 digestAddr) { } int sceKernelUtilsMd5BlockInit(u32 ctxAddr) { - DEBUG_LOG(HLE, "sceKernelUtilsMd5BlockInit(%08x)", ctxAddr); + DEBUG_LOG(Log::HLE, "sceKernelUtilsMd5BlockInit(%08x)", ctxAddr); if (!Memory::IsValidAddress(ctxAddr)) return -1; @@ -115,7 +115,7 @@ int sceKernelUtilsMd5BlockInit(u32 ctxAddr) { } int sceKernelUtilsMd5BlockUpdate(u32 ctxAddr, u32 dataPtr, int len) { - DEBUG_LOG(HLE, "sceKernelUtilsMd5BlockUpdate(%08x, %08x, %d)", ctxAddr, dataPtr, len); + DEBUG_LOG(Log::HLE, "sceKernelUtilsMd5BlockUpdate(%08x, %08x, %d)", ctxAddr, dataPtr, len); if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataPtr)) return -1; @@ -124,7 +124,7 @@ int sceKernelUtilsMd5BlockUpdate(u32 ctxAddr, u32 dataPtr, int len) { } int sceKernelUtilsMd5BlockResult(u32 ctxAddr, u32 digestAddr) { - DEBUG_LOG(HLE, "sceKernelUtilsMd5BlockResult(%08x, %08x)", ctxAddr, digestAddr); + DEBUG_LOG(Log::HLE, "sceKernelUtilsMd5BlockResult(%08x, %08x)", ctxAddr, digestAddr); if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; @@ -136,7 +136,7 @@ int sceKernelUtilsMd5BlockResult(u32 ctxAddr, u32 digestAddr) { static sha1_context sha1_ctx; int sceKernelUtilsSha1Digest(u32 dataAddr, int len, u32 digestAddr) { - DEBUG_LOG(HLE, "sceKernelUtilsSha1Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); + DEBUG_LOG(Log::HLE, "sceKernelUtilsSha1Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); if (!Memory::IsValidAddress(dataAddr) || !Memory::IsValidAddress(digestAddr)) return -1; @@ -146,7 +146,7 @@ int sceKernelUtilsSha1Digest(u32 dataAddr, int len, u32 digestAddr) { } int sceKernelUtilsSha1BlockInit(u32 ctxAddr) { - DEBUG_LOG(HLE, "sceKernelUtilsSha1BlockInit(%08x)", ctxAddr); + DEBUG_LOG(Log::HLE, "sceKernelUtilsSha1BlockInit(%08x)", ctxAddr); if (!Memory::IsValidAddress(ctxAddr)) return -1; @@ -159,7 +159,7 @@ int sceKernelUtilsSha1BlockInit(u32 ctxAddr) { } int sceKernelUtilsSha1BlockUpdate(u32 ctxAddr, u32 dataAddr, int len) { - DEBUG_LOG(HLE, "sceKernelUtilsSha1BlockUpdate(%08x, %08x, %d)", ctxAddr, dataAddr, len); + DEBUG_LOG(Log::HLE, "sceKernelUtilsSha1BlockUpdate(%08x, %08x, %d)", ctxAddr, dataAddr, len); if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataAddr)) return -1; @@ -168,7 +168,7 @@ int sceKernelUtilsSha1BlockUpdate(u32 ctxAddr, u32 dataAddr, int len) { } int sceKernelUtilsSha1BlockResult(u32 ctxAddr, u32 digestAddr) { - DEBUG_LOG(HLE, "sceKernelUtilsSha1BlockResult(%08x, %08x)", ctxAddr, digestAddr); + DEBUG_LOG(Log::HLE, "sceKernelUtilsSha1BlockResult(%08x, %08x)", ctxAddr, digestAddr); if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index aa070b4ff8..48c3ede269 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -15,6 +15,57 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +// Games known to support custom music and almost certainly use sceMp3: +// +// * ATV Offroad Fury: Blazin' Trails +// * Beats (/PSP/MUSIC) +// * Crazy Taxi : Fare Wars (/MUSIC) +// * Dead or Alive Paradise +// * Gran Turismo - You must first clear all driving challenges up to C to unlock this feature, then it will be available through the options menu. +// * Grand Theft Auto : Liberty City Stories +// * Grand Theft Auto : Vice City Stories +// * Heroes' VS (#5866 ?) +// * MLB 08 : The Show +// * MotorStorm : Artic Edge +// * NBA Live 09 +// * Need for Speed Carbon +// * Need for Speed Pro Street +// * Pro Evolution Soccer 2014 +// * SD Gundam G Generation Overworld +// * TOCA Race Driver 2 +// * Untold Legends II +// * Wipeout Pulse (/MUSIC/WIPEOUT) +// +// Games known to use LowLevelDecode: +// +// * Gundam G (custom BGM) +// * Heroes' VS (custom BGM) +// +// Games that use sceMp3 internally +// +// * Kirameki School Life SP +// * Breakquest (mini) +// * Orbit (mini) +// * SWAT Target Liberty ULES00927 +// * Geometry Wars (homebrew) +// * Hanayaka Nari Wa ga Ichizoku +// * Velocity (mini) +// * N+ (mini) (#9379) +// * Mighty Flip Champs DX (mini) +// * EDGE (mini) +// * Stellar Attack (mini) +// * Hungry Giraffe (mini) +// * OMG - Z (mini) +// ...probably lots more minis... +// +// BUGS +// +// Custom music plays but starts stuttering: +// * Beats +// +// Custom music just repeats a small section: +// * Crazy Taxi + #include #include @@ -44,9 +95,9 @@ static const int AU_BUF_MIN_SIZE = 8192; static const int PCM_BUF_MIN_SIZE = 9216; static const size_t MP3_MAX_HANDLES = 2; -struct Mp3Context { +// This one is only used for save state upgrading. +struct Mp3ContextOld { public: - int mp3StreamStart; int mp3StreamEnd; u32 mp3Buf; @@ -106,6 +157,10 @@ static AuCtx *getMp3Ctx(u32 mp3) { return mp3Map[mp3]; } +void __Mp3Init() { + resourceInited = false; +} + void __Mp3Shutdown() { for (auto it = mp3Map.begin(), end = mp3Map.end(); it != end; ++it) { delete it->second; @@ -121,7 +176,7 @@ void __Mp3DoState(PointerWrap &p) { if (s >= 2) { Do(p, mp3Map); } else { - std::map mp3Map_old; + std::map mp3Map_old; Do(p, mp3Map_old); // read old map for (auto it = mp3Map_old.begin(), end = mp3Map_old.end(); it != end; ++it) { auto mp3 = new AuCtx; @@ -143,8 +198,7 @@ void __Mp3DoState(PointerWrap &p) { mp3->MaxOutputSample = mp3_old->mp3MaxSamples; mp3->SetReadPos(mp3_old->readPosition); - mp3->audioType = PSP_CODEC_MP3; - mp3->decoder = new SimpleAudio(mp3->audioType); + mp3->decoder = CreateAudioDecoder(PSP_CODEC_MP3); mp3Map[id] = mp3; } } @@ -161,18 +215,18 @@ static int sceMp3Decode(u32 mp3, u32 outPcmPtr) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); } else if (ctx->Version < 0 || ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); } int pcmBytes = ctx->AuDecode(outPcmPtr); if (pcmBytes > 0) { // decode data successfully, delay thread - return hleDelayResult(hleLogSuccessI(ME, pcmBytes), "mp3 decode", mp3DecodeDelay); + return hleDelayResult(hleLogSuccessI(Log::ME, pcmBytes), "mp3 decode", mp3DecodeDelay); } else if (pcmBytes == 0) { - return hleLogSuccessI(ME, pcmBytes); + return hleLogSuccessI(Log::ME, pcmBytes); } // Should already have logged. return pcmBytes; @@ -182,44 +236,44 @@ static int sceMp3ResetPlayPosition(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); } else if (ctx->Version < 0 || ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); } - return hleLogSuccessI(ME, ctx->AuResetPlayPosition()); + return hleLogSuccessI(Log::ME, ctx->AuResetPlayPosition()); } static int sceMp3CheckStreamDataNeeded(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); } else if (ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); } - return hleLogSuccessI(ME, ctx->AuCheckStreamDataNeeded()); + return hleLogSuccessI(Log::ME, ctx->AuCheckStreamDataNeeded()); } static u32 sceMp3ReserveMp3Handle(u32 mp3Addr) { if (!resourceInited) { - return hleLogError(ME, ERROR_MP3_NO_RESOURCE_AVAIL, "sceMp3InitResource must be called first"); + return hleLogError(Log::ME, ERROR_MP3_NO_RESOURCE_AVAIL, "sceMp3InitResource must be called first"); } if (mp3Map.size() >= MP3_MAX_HANDLES) { - return hleLogError(ME, ERROR_MP3_NO_RESOURCE_AVAIL, "no free handles"); + return hleLogError(Log::ME, ERROR_MP3_NO_RESOURCE_AVAIL, "no free handles"); } if (mp3Addr != 0 && !Memory::IsValidRange(mp3Addr, 32)) { // The PSP would crash, but might as well return a proper error. - return hleLogError(ME, SCE_KERNEL_ERROR_INVALID_POINTER, "bad mp3 pointer"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_INVALID_POINTER, "bad mp3 pointer"); } AuCtx *Au = new AuCtx; if (mp3Addr) { - Au->startPos = Memory::Read_U64(mp3Addr); // Audio stream start position. - Au->endPos = Memory::Read_U64(mp3Addr + 8); // Audio stream end position. + Au->startPos = Memory::Read_U64(mp3Addr); // AUDIO stream start position. + Au->endPos = Memory::Read_U64(mp3Addr + 8); // AUDIO stream end position. Au->AuBuf = Memory::Read_U32(mp3Addr + 16); // Input Au data buffer. Au->AuBufSize = Memory::Read_U32(mp3Addr + 20); // Input Au data buffer size. Au->PCMBuf = Memory::Read_U32(mp3Addr + 24); // Output PCM data buffer. @@ -227,18 +281,18 @@ static u32 sceMp3ReserveMp3Handle(u32 mp3Addr) { if (Au->startPos >= Au->endPos) { delete Au; - return hleLogError(ME, ERROR_MP3_BAD_SIZE, "start must be before end"); + return hleLogError(Log::ME, ERROR_MP3_BAD_SIZE, "start must be before end"); } if (!Au->AuBuf || !Au->PCMBuf) { delete Au; - return hleLogError(ME, ERROR_MP3_BAD_ADDR, "invalid buffer addresses"); + return hleLogError(Log::ME, ERROR_MP3_BAD_ADDR, "invalid buffer addresses"); } if ((int)Au->AuBufSize < AU_BUF_MIN_SIZE || (int)Au->PCMBufSize < PCM_BUF_MIN_SIZE) { delete Au; - return hleLogError(ME, ERROR_MP3_BAD_SIZE, "buffers too small"); + return hleLogError(Log::ME, ERROR_MP3_BAD_SIZE, "buffers too small"); } - DEBUG_LOG(ME, "startPos %llx endPos %llx mp3buf %08x mp3bufSize %08x PCMbuf %08x PCMbufSize %08x", + DEBUG_LOG(Log::ME, "startPos %llx endPos %llx mp3buf %08x mp3bufSize %08x PCMbuf %08x PCMbufSize %08x", Au->startPos, Au->endPos, Au->AuBuf, Au->AuBufSize, Au->PCMBuf, Au->PCMBufSize); } else { Au->startPos = 0; @@ -249,28 +303,27 @@ static u32 sceMp3ReserveMp3Handle(u32 mp3Addr) { Au->PCMBufSize = 0; } - Au->audioType = PSP_CODEC_MP3; Au->SetReadPos(Au->startPos); - Au->decoder = new SimpleAudio(Au->audioType); + Au->decoder = CreateAudioDecoder(PSP_CODEC_MP3); int handle = (int)mp3Map.size(); mp3Map[handle] = Au; - return hleLogSuccessI(ME, handle); + return hleLogSuccessI(Log::ME, handle); } static int sceMp3InitResource() { // TODO: Could validate the utility modules have been loaded? if (resourceInited) { - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } resourceInited = true; - return hleLogSuccessI(ME, hleDelayResult(0, "mp3 resource init", 200)); + return hleLogSuccessI(Log::ME, hleDelayResult(0, "mp3 resource init", 200)); } static int sceMp3TermResource() { if (!resourceInited) { - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } // Free any handles that are still open. @@ -280,7 +333,7 @@ static int sceMp3TermResource() { mp3Map.clear(); resourceInited = false; - return hleLogSuccessI(ME, hleDelayResult(0, "mp3 resource term", 100)); + return hleLogSuccessI(Log::ME, hleDelayResult(0, "mp3 resource term", 100)); } static int __CalculateMp3Channels(int bitval) { @@ -382,10 +435,10 @@ static int sceMp3Init(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); } else if (ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); } static const int PARSE_DELAY_MS = 500; @@ -394,7 +447,7 @@ static int sceMp3Init(u32 mp3) { // If we have an ID3 tag, we'll get past it based on frame sync. Don't modify startPos. int header = 0; if (FindMp3Header(ctx, header, 1440) < 0) - return hleDelayResult(hleLogWarning(ME, ERROR_AVCODEC_INVALID_DATA, "no header found"), "mp3 init", PARSE_DELAY_MS); + return hleDelayResult(hleLogWarning(Log::ME, ERROR_AVCODEC_INVALID_DATA, "no header found"), "mp3 init", PARSE_DELAY_MS); // Parse the Mp3 header int layerBits = (header >> 17) & 0x3; @@ -403,23 +456,23 @@ static int sceMp3Init(u32 mp3) { int samplerate = __CalculateMp3SampleRates((header >> 10) & 0x3, versionBits);; int channels = __CalculateMp3Channels((header >> 6) & 0x3); - DEBUG_LOG(ME, "sceMp3Init(): channels=%i, samplerate=%iHz, bitrate=%ikbps, layerBits=%d ,versionBits=%d,HEADER: %08x", channels, samplerate, bitrate, layerBits, versionBits, header); + DEBUG_LOG(Log::ME, "sceMp3Init(): channels=%i, samplerate=%iHz, bitrate=%ikbps, layerBits=%d ,versionBits=%d,HEADER: %08x", channels, samplerate, bitrate, layerBits, versionBits, header); if (layerBits != 1) { // TODO: Should return ERROR_AVCODEC_INVALID_DATA. - WARN_LOG_REPORT(ME, "sceMp3Init: invalid data: not layer 3"); + WARN_LOG_REPORT(Log::ME, "sceMp3Init: invalid data: not layer 3"); } if (bitrate == 0 || bitrate == -1) { - return hleDelayResult(hleReportError(ME, ERROR_AVCODEC_INVALID_DATA, "invalid bitrate v%d l%d rate %04x", versionBits, layerBits, (header >> 12) & 0xF), "mp3 init", PARSE_DELAY_MS); + return hleDelayResult(hleReportError(Log::ME, ERROR_AVCODEC_INVALID_DATA, "invalid bitrate v%d l%d rate %04x", versionBits, layerBits, (header >> 12) & 0xF), "mp3 init", PARSE_DELAY_MS); } if (samplerate == -1) { - return hleDelayResult(hleReportError(ME, ERROR_AVCODEC_INVALID_DATA, "invalid sample rate v%d l%d rate %02x", versionBits, layerBits, (header >> 10) & 0x3), "mp3 init", PARSE_DELAY_MS); + return hleDelayResult(hleReportError(Log::ME, ERROR_AVCODEC_INVALID_DATA, "invalid sample rate v%d l%d rate %02x", versionBits, layerBits, (header >> 10) & 0x3), "mp3 init", PARSE_DELAY_MS); } // Before we allow init, newer SDK versions next require at least 156 bytes. // That happens to be the size of the first frame header for VBR. if (sdkver >= 0x06000000 && ctx->ReadPos() < 156) { - return hleDelayResult(hleLogError(ME, SCE_KERNEL_ERROR_INVALID_VALUE, "insufficient mp3 data for init"), "mp3 init", PARSE_DELAY_MS); + return hleDelayResult(hleLogError(Log::ME, SCE_KERNEL_ERROR_INVALID_VALUE, "insufficient mp3 data for init"), "mp3 init", PARSE_DELAY_MS); } ctx->SamplingRate = samplerate; @@ -430,10 +483,10 @@ static int sceMp3Init(u32 mp3) { if (versionBits != 3) { // TODO: Should return 0x80671301 (unsupported version?) - WARN_LOG_REPORT(ME, "sceMp3Init: invalid data: not MPEG v1"); + WARN_LOG_REPORT(Log::ME, "sceMp3Init: invalid data: not MPEG v1"); } if (samplerate != 44100 && sdkver < 3090500) { - return hleDelayResult(hleLogError(ME, ERROR_MP3_BAD_SAMPLE_RATE, "invalid data: not 44.1kHz"), "mp3 init", PARSE_DELAY_MS); + return hleDelayResult(hleLogError(Log::ME, ERROR_MP3_BAD_SAMPLE_RATE, "invalid data: not 44.1kHz"), "mp3 init", PARSE_DELAY_MS); } // Based on bitrate, we can calculate the frame size in bytes. @@ -445,138 +498,136 @@ static int sceMp3Init(u32 mp3) { ctx->Version = versionBits; - // This tells us to resample to the same frequency it decodes to. - ctx->decoder->SetResampleFrequency(ctx->freq); - - return hleDelayResult(hleLogSuccessI(ME, 0), "mp3 init", PARSE_DELAY_MS); + return hleDelayResult(hleLogSuccessI(Log::ME, 0), "mp3 init", PARSE_DELAY_MS); } static int sceMp3GetLoopNum(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); } else if (ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); } - return hleLogSuccessI(ME, ctx->AuGetLoopNum()); + return hleLogSuccessI(Log::ME, ctx->LoopNum); } static int sceMp3GetMaxOutputSample(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); } else if (ctx->Version < 0) { - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); } else if (ctx->AuBuf == 0) { - return hleLogWarning(ME, 0, "no channel available for low level"); + return hleLogWarning(Log::ME, 0, "no channel available for low level"); } - return hleLogSuccessI(ME, ctx->AuGetMaxOutputSample()); + return hleLogSuccessI(Log::ME, ctx->MaxOutputSample); } static int sceMp3GetSumDecodedSample(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); } else if (ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); } - return hleLogSuccessI(ME, ctx->AuGetSumDecodedSample()); + return hleLogSuccessI(Log::ME, ctx->SumDecodedSamples); } static int sceMp3SetLoopNum(u32 mp3, int loop) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); } else if (ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); } if (loop < 0) loop = -1; - return hleLogSuccessI(ME, ctx->AuSetLoopNum(loop)); + ctx->LoopNum = loop; + return hleLogSuccessI(Log::ME, 0); } static int sceMp3GetMp3ChannelNum(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); } else if (ctx->Version < 0) { - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); } else if (ctx->AuBuf == 0) { - return hleLogWarning(ME, 0, "no channel available for low level"); + return hleLogWarning(Log::ME, 0, "no channel available for low level"); } - return hleLogSuccessI(ME, ctx->AuGetChannelNum()); + return hleLogSuccessI(Log::ME, ctx->Channels); } static int sceMp3GetBitRate(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); } else if (ctx->Version < 0) { - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); } else if (ctx->AuBuf == 0) { - return hleLogWarning(ME, 0, "no bitrate available for low level"); + return hleLogWarning(Log::ME, 0, "no bitrate available for low level"); } - return hleLogSuccessI(ME, ctx->AuGetBitRate()); + return hleLogSuccessI(Log::ME, ctx->BitRate); } static int sceMp3GetSamplingRate(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); } else if (ctx->Version < 0) { - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); } else if (ctx->AuBuf == 0) { - return hleLogWarning(ME, 0, "no sample rate available for low level"); + return hleLogWarning(Log::ME, 0, "no sample rate available for low level"); } - return hleLogSuccessI(ME, ctx->AuGetSamplingRate()); + return hleLogSuccessI(Log::ME, ctx->SamplingRate); } static int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcposPtr) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); } else if (ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); } - return hleLogSuccessI(ME, ctx->AuGetInfoToAddStreamData(dstPtr, towritePtr, srcposPtr)); + return hleLogSuccessI(Log::ME, ctx->AuGetInfoToAddStreamData(dstPtr, towritePtr, srcposPtr)); } static int sceMp3NotifyAddStreamData(u32 mp3, int size) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); } else if (ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type"); } - return hleLogSuccessI(ME, ctx->AuNotifyAddStreamData(size)); + return hleLogSuccessI(Log::ME, ctx->AuNotifyAddStreamData(size)); } static int sceMp3ReleaseMp3Handle(u32 mp3) { @@ -584,22 +635,22 @@ static int sceMp3ReleaseMp3Handle(u32 mp3) { if (ctx) { delete ctx; mp3Map.erase(mp3); - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } else if (mp3 >= MP3_MAX_HANDLES) { - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); } // Intentionally a zero result. - return hleLogDebug(ME, 0, "double free ignored"); + return hleLogDebug(Log::ME, 0, "double free ignored"); } static u32 sceMp3EndEntry() { - ERROR_LOG_REPORT(ME, "UNIMPL sceMp3EndEntry(...)"); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMp3EndEntry(...)"); return 0; } static u32 sceMp3StartEntry() { - ERROR_LOG_REPORT(ME, "UNIMPL sceMp3StartEntry(...)"); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMp3StartEntry(...)"); return 0; } @@ -607,55 +658,54 @@ static u32 sceMp3GetFrameNum(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); } else if (ctx->Version < 0 || ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); } - return hleLogSuccessI(ME, ctx->AuGetFrameNum()); + return hleLogSuccessI(Log::ME, ctx->FrameNum); } static u32 sceMp3GetMPEGVersion(u32 mp3) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle"); } else if (ctx->Version < 0) { // Seems to be the wrong error code. - return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_UNRESERVED_HANDLE, "not yet init"); } else if (ctx->AuBuf == 0) { - return hleLogWarning(ME, 0, "no MPEG version available for low level"); + return hleLogWarning(Log::ME, 0, "no MPEG version available for low level"); } // Tests have not revealed how to expose more than "3" here as a result. - return hleReportDebug(ME, ctx->AuGetVersion()); + return hleReportDebug(Log::ME, ctx->Version); } static u32 sceMp3ResetPlayPositionByFrame(u32 mp3, u32 frame) { AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { if (mp3 >= MP3_MAX_HANDLES) - return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); + return hleLogError(Log::ME, ERROR_MP3_INVALID_HANDLE, "invalid handle"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle"); } else if (ctx->Version < 0 || ctx->AuBuf == 0) { - return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); + return hleLogError(Log::ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init"); } - if (frame >= (u32)ctx->AuGetFrameNum()) { - return hleLogError(ME, ERROR_MP3_BAD_RESET_FRAME, "bad frame position"); + if (frame >= (u32)ctx->FrameNum) { + return hleLogError(Log::ME, ERROR_MP3_BAD_RESET_FRAME, "bad frame position"); } - return hleLogSuccessI(ME, ctx->AuResetPlayPositionByFrame(frame)); + return hleLogSuccessI(Log::ME, ctx->AuResetPlayPositionByFrame(frame)); } static u32 sceMp3LowLevelInit(u32 mp3, u32 unk) { - auto ctx = new AuCtx; + auto ctx = new AuCtx(); - ctx->audioType = PSP_CODEC_MP3; // create mp3 decoder - ctx->decoder = new SimpleAudio(ctx->audioType); + ctx->decoder = CreateAudioDecoder(PSP_CODEC_MP3); // close the audio if mp3 already exists. if (mp3Map.find(mp3) != mp3Map.end()) { @@ -667,7 +717,7 @@ static u32 sceMp3LowLevelInit(u32 mp3, u32 unk) { // Indicate that we've run low level init by setting version to 1. ctx->Version = 1; - return hleLogSuccessInfoI(ME, hleDelayResult(0, "mp3 low level", 600)); + return hleLogSuccessInfoI(Log::ME, hleDelayResult(0, "mp3 low level", 600)); } static u32 sceMp3LowLevelDecode(u32 mp3, u32 sourceAddr, u32 sourceBytesConsumedAddr, u32 samplesAddr, u32 sampleBytesAddr) { @@ -675,29 +725,31 @@ static u32 sceMp3LowLevelDecode(u32 mp3, u32 sourceAddr, u32 sourceBytesConsumed // sourceBytesConsumedAddr: consumed bytes decoded in source // samplesAddr: output pcm buffer // sampleBytesAddr: output pcm size - DEBUG_LOG(ME, "sceMp3LowLevelDecode(%08x, %08x, %08x, %08x, %08x)", mp3, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); + DEBUG_LOG(Log::ME, "sceMp3LowLevelDecode(%08x, %08x, %08x, %08x, %08x)", mp3, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); AuCtx *ctx = getMp3Ctx(mp3); if (!ctx) { - ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); + ERROR_LOG(Log::ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } if (!Memory::IsValidAddress(sourceAddr) || !Memory::IsValidAddress(sourceBytesConsumedAddr) || !Memory::IsValidAddress(samplesAddr) || !Memory::IsValidAddress(sampleBytesAddr)) { - ERROR_LOG(ME, "sceMp3LowLevelDecode(%08x, %08x, %08x, %08x, %08x) : invalid address in args", mp3, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); + ERROR_LOG(Log::ME, "sceMp3LowLevelDecode(%08x, %08x, %08x, %08x, %08x) : invalid address in args", mp3, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); return -1; } - auto inbuff = Memory::GetPointerWriteUnchecked(sourceAddr); - auto outbuff = Memory::GetPointerWriteUnchecked(samplesAddr); + const u8 *inbuff = Memory::GetPointerWriteUnchecked(sourceAddr); + int16_t *outbuf = (int16_t *)Memory::GetPointerWriteUnchecked(samplesAddr); - int outpcmbytes = 0; - ctx->decoder->Decode(inbuff, 4096, outbuff, &outpcmbytes); - NotifyMemInfo(MemBlockFlags::WRITE, samplesAddr, outpcmbytes, "Mp3LowLevelDecode"); + int outSamples = 0; + int inbytesConsumed = 0; + ctx->decoder->Decode(inbuff, 4096, &inbytesConsumed, 2, outbuf, &outSamples); + int outBytes = outSamples * sizeof(int16_t) * 2; + NotifyMemInfo(MemBlockFlags::WRITE, samplesAddr, outBytes, "Mp3LowLevelDecode"); - Memory::Write_U32(ctx->decoder->GetSourcePos(), sourceBytesConsumedAddr); - Memory::Write_U32(outpcmbytes, sampleBytesAddr); + Memory::Write_U32(inbytesConsumed, sourceBytesConsumedAddr); + Memory::Write_U32(outBytes, sampleBytesAddr); return 0; } diff --git a/Core/HLE/sceMp3.h b/Core/HLE/sceMp3.h index 84ff082dfb..d1aa4fa3b5 100644 --- a/Core/HLE/sceMp3.h +++ b/Core/HLE/sceMp3.h @@ -21,5 +21,6 @@ class PointerWrap; void Register_sceMp3(); +void __Mp3Init(); void __Mp3Shutdown(); -void __Mp3DoState(PointerWrap &p); \ No newline at end of file +void __Mp3DoState(PointerWrap &p); diff --git a/Core/HLE/sceMp4.cpp b/Core/HLE/sceMp4.cpp index 38c288e950..bd6cdf2f11 100644 --- a/Core/HLE/sceMp4.cpp +++ b/Core/HLE/sceMp4.cpp @@ -50,80 +50,80 @@ void __AACDoState(PointerWrap &p) { static u32 sceMp4Init() { - INFO_LOG(ME, "sceMp4Init()"); + INFO_LOG(Log::ME, "sceMp4Init()"); return 0; } static u32 sceMp4Finish() { - ERROR_LOG(ME, "UNIMPL sceMp4Finish()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4Finish()"); return 0; } static u32 sceMp4Create(u32 mp4, u32 callbacks, u32 readBufferAddr, u32 readBufferSize) { - ERROR_LOG_REPORT(ME, "UNIMPL sceMp4Create(mp4 %i,callbacks %08x,readBufferAddr %08x,readBufferSize %i)", mp4, callbacks, readBufferAddr, readBufferSize); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMp4Create(mp4 %i,callbacks %08x,readBufferAddr %08x,readBufferSize %i)", mp4, callbacks, readBufferAddr, readBufferSize); return 0; } static u32 sceMp4GetNumberOfSpecificTrack() { - ERROR_LOG(ME, "UNIMPL sceMp4GetNumberOfSpecificTrack()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4GetNumberOfSpecificTrack()"); return 1; } static u32 sceMp4GetMovieInfo(u32 mp4, u32 unknown2) { - ERROR_LOG(ME, "UNIMPL sceMp4GetMovieInfo(mp4 %i, unknown2 %08x)",mp4, unknown2); + ERROR_LOG(Log::ME, "UNIMPL sceMp4GetMovieInfo(mp4 %i, unknown2 %08x)",mp4, unknown2); return 0; } static u32 sceMp4TrackSampleBufAvailableSize(u32 mp4, u32 trackAddr, u32 writableSamplesAddr, u32 writableBytesAddr) { - return hleLogError(ME, 0, "unimplemented"); + return hleLogError(Log::ME, 0, "unimplemented"); } static u32 sceMp4Delete(u32 mp4) { - return hleLogError(ME, 0, "unimplemented"); + return hleLogError(Log::ME, 0, "unimplemented"); } static u32 sceMp4AacDecodeInitResource(int unknown) { - ERROR_LOG(ME, "UNIMPL sceMp4AacDecodeInitResource(%i)",unknown); + ERROR_LOG(Log::ME, "UNIMPL sceMp4AacDecodeInitResource(%i)",unknown); return 0; } static u32 sceMp4InitAu(u32 mp4, u32 unknown2, u32 auAddr) { // unknown2 = return value of sceMpegAvcResourceGetAvcEsBuf() - ERROR_LOG(ME, "UNIMPL sceMp4InitAu(mp4 %i,unknown2 %08x,auAddr %08x)", mp4, unknown2, auAddr); + ERROR_LOG(Log::ME, "UNIMPL sceMp4InitAu(mp4 %i,unknown2 %08x,auAddr %08x)", mp4, unknown2, auAddr); return 0; } static u32 sceMp4GetAvcAu(u32 mp4, u32 unknown2, u32 auAddr, u32 unknown4) { // unknown2 = return value of sceMpegAvcResourceGetAvcEsBuf() - ERROR_LOG(ME, "UNIMPL sceMp4InitAu(mp4 %i,unknown2 %08x,auAddr %08x,unknown4 %08x)", mp4, unknown2, auAddr, unknown4); + ERROR_LOG(Log::ME, "UNIMPL sceMp4InitAu(mp4 %i,unknown2 %08x,auAddr %08x,unknown4 %08x)", mp4, unknown2, auAddr, unknown4); return 0; } static u32 sceMp4GetAvcTrackInfoData() { - ERROR_LOG(ME, "UNIMPL sceMp4GetAvcTrackInfoData()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4GetAvcTrackInfoData()"); return 0; } static u32 sceMp4TrackSampleBufConstruct(u32 mp4, u32 unknown2, u32 unknown3, u32 unknown4, u32 unknown5, u32 unknown6, u32 unknown7) { // unknown4 == value returned by sceMp4_BCA9389C - ERROR_LOG(ME, "UNIMPL sceMp4TrackSampleBufConstruct(mp4 %i,unknown2 %08x,unknown3 %08x, unknown4 %08x, unknown5 %08x, unknown6 %08x, unknown7 %08x)", mp4, unknown2, unknown3, unknown4, unknown5, unknown6, unknown7); + ERROR_LOG(Log::ME, "UNIMPL sceMp4TrackSampleBufConstruct(mp4 %i,unknown2 %08x,unknown3 %08x, unknown4 %08x, unknown5 %08x, unknown6 %08x, unknown7 %08x)", mp4, unknown2, unknown3, unknown4, unknown5, unknown6, unknown7); return 0; } static u32 sceMp4TrackSampleBufQueryMemSize(u32 unknown1, u32 unknown2, u32 unknown3, u32 unknown4, u32 unknown5) { u32 value = std::max(unknown2 * unknown3, unknown4 << 1) + (unknown2 << 6) + unknown5 + 256; - ERROR_LOG(ME, "sceMp4TrackSampleBufQueryMemSize return %i",value); + ERROR_LOG(Log::ME, "sceMp4TrackSampleBufQueryMemSize return %i",value); return value; } @@ -132,7 +132,7 @@ static u32 sceMp4AacDecode(u32 mp4, u32 auAddr, u32 bufferAddr, u32 init, u32 fr // Decode audio: // - init: 1 at first call, 0 afterwards // - frequency: 44100 - ERROR_LOG(ME, "sceMp4AacDecode(mp4 %i,auAddr %08x,bufferAddr %08x,init %i,frequency %i ", mp4, auAddr, bufferAddr, init, frequency); + ERROR_LOG(Log::ME, "sceMp4AacDecode(mp4 %i,auAddr %08x,bufferAddr %08x,init %i,frequency %i ", mp4, auAddr, bufferAddr, init, frequency); return 0; //This is hack //return -1; @@ -141,55 +141,55 @@ static u32 sceMp4AacDecode(u32 mp4, u32 auAddr, u32 bufferAddr, u32 init, u32 fr static u32 sceMp4GetAacAu(u32 mp4, u32 unknown2, u32 auAddr, u32 unknown4) { // unknown4: pointer to a 40-bytes structure - ERROR_LOG(ME, "sceMp4GetAacAu(mp4 %i,unknown2 %08x,auAddr %08x,unknown4 %i ", mp4, unknown2, auAddr, unknown4); + ERROR_LOG(Log::ME, "sceMp4GetAacAu(mp4 %i,unknown2 %08x,auAddr %08x,unknown4 %i ", mp4, unknown2, auAddr, unknown4); return 0; } static u32 sceMp4GetSampleInfo() { - ERROR_LOG(ME, "UNIMPL sceMp4GetSampleInfo()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4GetSampleInfo()"); return 0; } static u32 sceMp4GetSampleNumWithTimeStamp() { - ERROR_LOG(ME, "UNIMPL sceMp4GetSampleNumWithTimeStamp()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4GetSampleNumWithTimeStamp()"); return 0; } static u32 sceMp4TrackSampleBufFlush() { - ERROR_LOG(ME, "UNIMPL sceMp4TrackSampleBufFlush()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4TrackSampleBufFlush()"); return 0; } static u32 sceMp4AacDecodeInit(int unknown) { - ERROR_LOG(ME, "UNIMPL sceMp4AacDecodeInit(%i)",unknown); + ERROR_LOG(Log::ME, "UNIMPL sceMp4AacDecodeInit(%i)",unknown); return 0; } static u32 sceMp4GetAacTrackInfoData() { - ERROR_LOG(ME, "UNIMPL sceMp4GetAacTrackInfoData()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4GetAacTrackInfoData()"); return 0; } static u32 sceMp4GetNumberOfMetaData() { - ERROR_LOG(ME, "UNIMPL sceMp4GetNumberOfMetaData()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4GetNumberOfMetaData()"); return 0; } static u32 sceMp4RegistTrack(u32 mp4, u32 unknown2, u32 unknown3, u32 callbacks, u32 unknown5) { - ERROR_LOG(ME, "UNIMPL sceMp4RegistTrack(mp4 %i,unknown2 %i,unknown3 %i,callbacks %i unknown5 %i)",mp4,unknown2,unknown3,callbacks,unknown5); + ERROR_LOG(Log::ME, "UNIMPL sceMp4RegistTrack(mp4 %i,unknown2 %i,unknown3 %i,callbacks %i unknown5 %i)",mp4,unknown2,unknown3,callbacks,unknown5); return 0; } static u32 sceMp4SearchSyncSampleNum() { - ERROR_LOG(ME, "UNIMPL sceMp4SearchSyncSampleNum()"); + ERROR_LOG(Log::ME, "UNIMPL sceMp4SearchSyncSampleNum()"); return 0; } @@ -198,13 +198,13 @@ static u32 sceMp4SearchSyncSampleNum() static u32 sceAacExit(u32 id) { - INFO_LOG(ME, "sceAacExit(id %i)", id); + INFO_LOG(Log::ME, "sceAacExit(id %i)", id); if (aacMap.find(id) != aacMap.end()) { delete aacMap[id]; aacMap.erase(id); } else{ - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } return 0; @@ -212,51 +212,50 @@ static u32 sceAacExit(u32 id) static u32 sceAacInit(u32 id) { - INFO_LOG(ME, "UNIMPL sceAacInit(%08x)", id); + INFO_LOG(Log::ME, "UNIMPL sceAacInit(%08x)", id); if (!Memory::IsValidAddress(id)){ - ERROR_LOG(ME, "sceAacInit() AAC Invalid id address %08x", id); + ERROR_LOG(Log::ME, "sceAacInit() AAC Invalid id address %08x", id); return ERROR_AAC_INVALID_ADDRESS; } AuCtx *aac = new AuCtx(); - aac->startPos = Memory::Read_U64(id); // Audio stream start position. - aac->endPos = Memory::Read_U32(id + 8); // Audio stream end position. + aac->startPos = Memory::Read_U64(id); // AUDIO stream start position. + aac->endPos = Memory::Read_U32(id + 8); // AUDIO stream end position. aac->AuBuf = Memory::Read_U32(id + 16); // Input AAC data buffer. aac->AuBufSize = Memory::Read_U32(id + 20); // Input AAC data buffer size. aac->PCMBuf = Memory::Read_U32(id + 24); // Output PCM data buffer. aac->PCMBufSize = Memory::Read_U32(id + 28); // Output PCM data buffer size. aac->freq = Memory::Read_U32(id + 32); // Frequency. if (aac->AuBuf == 0 || aac->PCMBuf == 0) { - ERROR_LOG(ME, "sceAacInit() AAC INVALID ADDRESS AuBuf %08x PCMBuf %08x", aac->AuBuf, aac->PCMBuf); + ERROR_LOG(Log::ME, "sceAacInit() AAC INVALID ADDRESS AuBuf %08x PCMBuf %08x", aac->AuBuf, aac->PCMBuf); delete aac; return ERROR_AAC_INVALID_ADDRESS; } if (aac->startPos > aac->endPos) { - ERROR_LOG(ME, "sceAacInit() AAC INVALID startPos %lli endPos %lli", aac->startPos, aac->endPos); + ERROR_LOG(Log::ME, "sceAacInit() AAC INVALID startPos %lli endPos %lli", aac->startPos, aac->endPos); delete aac; return ERROR_AAC_INVALID_PARAMETER; } if (aac->AuBufSize < 8192 || aac->PCMBufSize < 8192) { - ERROR_LOG(ME, "sceAacInit() AAC INVALID PARAMETER, bufferSize %i outputSize %i", aac->AuBufSize, aac->PCMBufSize); + ERROR_LOG(Log::ME, "sceAacInit() AAC INVALID PARAMETER, bufferSize %i outputSize %i", aac->AuBufSize, aac->PCMBufSize); delete aac; return ERROR_AAC_INVALID_PARAMETER; } if (aac->freq != 24000 && aac->freq != 32000 && aac->freq != 44100 && aac->freq != 48000) { - ERROR_LOG(ME, "sceAacInit() AAC INVALID freq %i", aac->freq); + ERROR_LOG(Log::ME, "sceAacInit() AAC INVALID freq %i", aac->freq); delete aac; return ERROR_AAC_INVALID_PARAMETER; } - DEBUG_LOG(ME, "startPos %llx endPos %llx AuBuf %08x AuBufSize %08x PCMbuf %08x PCMbufSize %08x freq %d", + DEBUG_LOG(Log::ME, "startPos %llx endPos %llx AuBuf %08x AuBufSize %08x PCMbuf %08x PCMbufSize %08x freq %d", aac->startPos, aac->endPos, aac->AuBuf, aac->AuBufSize, aac->PCMBuf, aac->PCMBufSize, aac->freq); aac->Channels = 2; aac->MaxOutputSample = aac->PCMBufSize / 4; aac->SetReadPos((int)aac->startPos); - aac->audioType = PSP_CODEC_AAC; // create aac decoder - aac->decoder = new SimpleAudio(aac->audioType); + aac->decoder = CreateAudioDecoder(PSP_CODEC_AAC); // close the audio if id already exist. if (aacMap.find(id) != aacMap.end()) { @@ -271,23 +270,23 @@ static u32 sceAacInit(u32 id) static u32 sceAacInitResource(u32 numberIds) { // Do nothing here - INFO_LOG_REPORT(ME, "sceAacInitResource(%i)", numberIds); + INFO_LOG_REPORT(Log::ME, "sceAacInitResource(%i)", numberIds); return 0; } static u32 sceAacTermResource() { - ERROR_LOG(ME, "UNIMPL sceAacTermResource()"); + ERROR_LOG(Log::ME, "UNIMPL sceAacTermResource()"); return 0; } static u32 sceAacDecode(u32 id, u32 pcmAddr) { // return the size of output pcm, <0 error - DEBUG_LOG(ME, "sceAacDecode(id %i, bufferAddress %08x)", id, pcmAddr); + DEBUG_LOG(Log::ME, "sceAacDecode(id %i, bufferAddress %08x)", id, pcmAddr); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } @@ -296,35 +295,36 @@ static u32 sceAacDecode(u32 id, u32 pcmAddr) static u32 sceAacGetLoopNum(u32 id) { - INFO_LOG(ME, "sceAacGetLoopNum(id %i)", id); + INFO_LOG(Log::ME, "sceAacGetLoopNum(id %i)", id); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } - return ctx->AuGetLoopNum(); + return ctx->LoopNum; } static u32 sceAacSetLoopNum(u32 id, int loop) { - INFO_LOG(ME, "sceAacSetLoopNum(id %i,loop %d)", id, loop); + INFO_LOG(Log::ME, "sceAacSetLoopNum(id %i,loop %d)", id, loop); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } - return ctx->AuSetLoopNum(loop); + ctx->LoopNum = loop; + return 0; } static int sceAacCheckStreamDataNeeded(u32 id) { // return 1 to read more data stream, 0 don't read, <0 error - DEBUG_LOG(ME, "sceAacCheckStreamDataNeeded(%i)", id); + DEBUG_LOG(Log::ME, "sceAacCheckStreamDataNeeded(%i)", id); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } @@ -334,11 +334,11 @@ static int sceAacCheckStreamDataNeeded(u32 id) static u32 sceAacNotifyAddStreamData(u32 id, int size) { // check how many bytes we have read from source file - DEBUG_LOG(ME, "sceAacNotifyAddStreamData(%i, %08x)", id, size); + DEBUG_LOG(Log::ME, "sceAacNotifyAddStreamData(%i, %08x)", id, size); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } @@ -348,11 +348,11 @@ static u32 sceAacNotifyAddStreamData(u32 id, int size) static u32 sceAacGetInfoToAddStreamData(u32 id, u32 buff, u32 size, u32 srcPos) { // read from stream position srcPos of size bytes into buff - DEBUG_LOG(ME, "sceAacGetInfoToAddStreamData(%08X, %08X, %08X, %08X)", id, buff, size, srcPos); + DEBUG_LOG(Log::ME, "sceAacGetInfoToAddStreamData(%08X, %08X, %08X, %08X)", id, buff, size, srcPos); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac handle %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac handle %08x", __FUNCTION__, id); return -1; } @@ -361,34 +361,34 @@ static u32 sceAacGetInfoToAddStreamData(u32 id, u32 buff, u32 size, u32 srcPos) static u32 sceAacGetMaxOutputSample(u32 id) { - DEBUG_LOG(ME, "sceAacGetMaxOutputSample(id %i)", id); + DEBUG_LOG(Log::ME, "sceAacGetMaxOutputSample(id %i)", id); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } - return ctx->AuGetMaxOutputSample(); + return ctx->MaxOutputSample; } static u32 sceAacGetSumDecodedSample(u32 id) { - DEBUG_LOG(ME, "sceAacGetSumDecodedSample(id %i)", id); + DEBUG_LOG(Log::ME, "sceAacGetSumDecodedSample(id %i)", id); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } - return ctx->AuGetSumDecodedSample(); + return ctx->SumDecodedSamples; } static u32 sceAacResetPlayPosition(u32 id) { - INFO_LOG(ME, "sceAacResetPlayPosition(id %i)", id); + INFO_LOG(Log::ME, "sceAacResetPlayPosition(id %i)", id); auto ctx = getAacCtx(id); if (!ctx) { - ERROR_LOG(ME, "%s: bad aac id %08x", __FUNCTION__, id); + ERROR_LOG(Log::ME, "%s: bad aac id %08x", __FUNCTION__, id); return -1; } @@ -396,12 +396,12 @@ static u32 sceAacResetPlayPosition(u32 id) } static u32 mp4msv_3C2183C7(u32 unknown1, u32 unknown2) { - ERROR_LOG(ME, "UNIMPL mp4msv_3C2183C7(%d, %x)", unknown1, unknown2); + ERROR_LOG(Log::ME, "UNIMPL mp4msv_3C2183C7(%d, %x)", unknown1, unknown2); return 0; } static u32 mp4msv_9CA13D1A(u32 unknown1, u32 unknown2) { - ERROR_LOG(ME, "UNIMPL mp4msv_9CA13D1A(%d, %x)", unknown1, unknown2); + ERROR_LOG(Log::ME, "UNIMPL mp4msv_9CA13D1A(%d, %x)", unknown1, unknown2); return 0; } diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 8be78c73e0..ed8bf37833 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -29,7 +29,6 @@ #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HW/MediaEngine.h" -#include "Core/Config.h" #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" #include "GPU/GPUInterface.h" @@ -97,7 +96,9 @@ static const int MPEG_HEADER_BUFFER_MINIMUM_SIZE = 2048; // For PMP media static u32 pmp_videoSource = 0; //pointer to the video source (SceMpegLLi structure) static int pmp_nBlocks = 0; //number of blocks received in the last sceMpegBasePESpacketCopy call +#ifdef USE_FFMPEG static std::list pmp_queue; //list of pmp video frames have been decoded and will be played +#endif static std::list pmp_ContextList; //list of pmp media contexts static bool pmp_oldStateLoaded = false; // for dostate @@ -338,7 +339,7 @@ static void AnalyzeMpeg(const u8 *buffer, u32 validSize, MpegContext *ctx) { // Sanity Check ctx->mpegFirstTimestamp if (ctx->mpegFirstTimestamp != 90000) { - WARN_LOG_REPORT(ME, "Unexpected mpeg first timestamp: %llx / %lld", ctx->mpegFirstTimestamp, ctx->mpegFirstTimestamp); + WARN_LOG_REPORT(Log::ME, "Unexpected mpeg first timestamp: %llx / %lld", ctx->mpegFirstTimestamp, ctx->mpegFirstTimestamp); } if (ctx->mpegMagic != PSMF_MAGIC || ctx->mpegVersion < 0 || @@ -368,8 +369,8 @@ static void AnalyzeMpeg(const u8 *buffer, u32 validSize, MpegContext *ctx) { memcpy(ctx->mpegheader, buffer, validSize >= 2048 ? 2048 : validSize); *(u32_le*)(ctx->mpegheader + PSMF_STREAM_OFFSET_OFFSET) = 0x80000; - INFO_LOG(ME, "Stream offset: %d, Stream size: 0x%X", ctx->mpegOffset, ctx->mpegStreamSize); - INFO_LOG(ME, "First timestamp: %lld, Last timestamp: %lld", ctx->mpegFirstTimestamp, ctx->mpegLastTimestamp); + INFO_LOG(Log::ME, "Stream offset: %d, Stream size: 0x%X", ctx->mpegOffset, ctx->mpegStreamSize); + INFO_LOG(Log::ME, "First timestamp: %lld, Last timestamp: %lld", ctx->mpegFirstTimestamp, ctx->mpegLastTimestamp); } class PostPutAction : public PSPAction { @@ -457,11 +458,11 @@ void __MpegLoadModule(int version,u32 crc) { static u32 sceMpegInit() { if (isMpegInit) { - WARN_LOG(ME, "sceMpegInit(): already initialized"); + WARN_LOG(Log::ME, "sceMpegInit(): already initialized"); // TODO: Need to properly hook module load/unload for this to work right. //return ERROR_MPEG_ALREADY_INIT; } else { - INFO_LOG(ME, "sceMpegInit(), mpegLibVersion 0x%0x, mpegLibcrc %x", mpegLibVersion, mpegLibCrc); + INFO_LOG(Log::ME, "sceMpegInit(), mpegLibVersion 0x%0x, mpegLibcrc %x", mpegLibVersion, mpegLibCrc); } isMpegInit = true; return hleDelayResult(0, "mpeg init", 750); @@ -473,33 +474,33 @@ static u32 __MpegRingbufferQueryMemSize(int packets) { static u32 sceMpegRingbufferQueryMemSize(int packets) { u32 size = __MpegRingbufferQueryMemSize(packets); - DEBUG_LOG(ME, "%i = sceMpegRingbufferQueryMemSize(%i)", size, packets); + DEBUG_LOG(Log::ME, "%i = sceMpegRingbufferQueryMemSize(%i)", size, packets); return size; } static u32 sceMpegRingbufferConstruct(u32 ringbufferAddr, u32 numPackets, u32 data, u32 size, u32 callbackAddr, u32 callbackArg) { if (!Memory::IsValidAddress(ringbufferAddr)) { - ERROR_LOG_REPORT(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): bad ringbuffer, should crash", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); + ERROR_LOG_REPORT(Log::ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): bad ringbuffer, should crash", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS; } if ((int)size < 0) { - ERROR_LOG_REPORT(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): invalid size", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); + ERROR_LOG_REPORT(Log::ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): invalid size", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); return ERROR_MPEG_NO_MEMORY; } if (__MpegRingbufferQueryMemSize(numPackets) > size) { if (numPackets < 0x00100000) { - ERROR_LOG_REPORT(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): too many packets for buffer", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); + ERROR_LOG_REPORT(Log::ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): too many packets for buffer", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); return ERROR_MPEG_NO_MEMORY; } else { // The PSP's firmware allows some cases here, due to a bug in its validation. - ERROR_LOG_REPORT(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): too many packets for buffer, bogus size", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); + ERROR_LOG_REPORT(Log::ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): too many packets for buffer, bogus size", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); } } - DEBUG_LOG(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x)", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); + DEBUG_LOG(Log::ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x)", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg); auto ring = PSPPointer::Create(ringbufferAddr); InitRingbuffer(ring, numPackets, data, size, callbackAddr, callbackArg); return 0; @@ -515,12 +516,12 @@ static u32 MpegRequiredMem() { static u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 frameWidth, u32 mode, u32 ddrTop) { if (!Memory::IsValidAddress(mpegAddr)) { - WARN_LOG(ME, "sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i): invalid addresses", mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop); + WARN_LOG(Log::ME, "sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i): invalid addresses", mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop); return -1; } if (size < MpegRequiredMem()) { - WARN_LOG(ME, "ERROR_MPEG_NO_MEMORY=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i)", mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop); + WARN_LOG(Log::ME, "ERROR_MPEG_NO_MEMORY=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i)", mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop); return ERROR_MPEG_NO_MEMORY; } @@ -548,7 +549,7 @@ static u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr } MpegContext *ctx = new MpegContext(); if (mpegMap.find(mpegHandle) != mpegMap.end()) { - WARN_LOG_REPORT(HLE, "Replacing existing mpeg context at %08x", mpegAddr); + WARN_LOG_REPORT(Log::HLE, "Replacing existing mpeg context at %08x", mpegAddr); // Otherwise, it would leak. delete mpegMap[mpegHandle]; } @@ -577,7 +578,7 @@ static u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr ctx->isAnalyzed = false; ctx->mediaengine = new MediaEngine(); - INFO_LOG(ME, "%08x=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i)", mpegHandle, mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop); + INFO_LOG(Log::ME, "%08x=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i)", mpegHandle, mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop); return hleDelayResult(0, "mpeg create", 29000); } @@ -585,11 +586,11 @@ static int sceMpegDelete(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegDelete(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "sceMpegDelete(%08x): bad mpeg handle", mpeg); return -1; } - DEBUG_LOG(ME, "sceMpegDelete(%08x)", mpeg); + DEBUG_LOG(Log::ME, "sceMpegDelete(%08x)", mpeg); delete ctx; mpegMap.erase(Memory::Read_U32(mpeg)); @@ -601,24 +602,24 @@ static int sceMpegDelete(u32 mpeg) static int sceMpegAvcDecodeMode(u32 mpeg, u32 modeAddr) { if (!Memory::IsValidAddress(modeAddr)) { - WARN_LOG(ME, "sceMpegAvcDecodeMode(%08x, %08x): invalid addresses", mpeg, modeAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecodeMode(%08x, %08x): invalid addresses", mpeg, modeAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegAvcDecodeMode(%08x, %08x): bad mpeg handle", mpeg, modeAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecodeMode(%08x, %08x): bad mpeg handle", mpeg, modeAddr); return -1; } - DEBUG_LOG(ME, "sceMpegAvcDecodeMode(%08x, %08x)", mpeg, modeAddr); + DEBUG_LOG(Log::ME, "sceMpegAvcDecodeMode(%08x, %08x)", mpeg, modeAddr); int mode = Memory::Read_U32(modeAddr); int pixelMode = Memory::Read_U32(modeAddr + 4); if (pixelMode >= GE_CMODE_16BIT_BGR5650 && pixelMode <= GE_CMODE_32BIT_ABGR8888) { ctx->videoPixelMode = pixelMode; } else { - ERROR_LOG(ME, "sceMpegAvcDecodeMode(%i, %i): unknown pixelMode ", mode, pixelMode); + ERROR_LOG(Log::ME, "sceMpegAvcDecodeMode(%i, %i): unknown pixelMode ", mode, pixelMode); } return 0; } @@ -626,31 +627,31 @@ static int sceMpegAvcDecodeMode(u32 mpeg, u32 modeAddr) static int sceMpegQueryStreamOffset(u32 mpeg, u32 bufferAddr, u32 offsetAddr) { if (!Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(offsetAddr)) { - ERROR_LOG(ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x): invalid addresses", mpeg, bufferAddr, offsetAddr); + ERROR_LOG(Log::ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x): invalid addresses", mpeg, bufferAddr, offsetAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x): bad mpeg handle", mpeg, bufferAddr, offsetAddr); + WARN_LOG(Log::ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x): bad mpeg handle", mpeg, bufferAddr, offsetAddr); return -1; } - DEBUG_LOG(ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x)", mpeg, bufferAddr, offsetAddr); + DEBUG_LOG(Log::ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x)", mpeg, bufferAddr, offsetAddr); // Kinda destructive, no? Shouldn't this just do what sceMpegQueryStreamSize does? AnalyzeMpeg(Memory::GetPointerWriteUnchecked(bufferAddr), Memory::ValidSize(bufferAddr, 32768), ctx); if (ctx->mpegMagic != PSMF_MAGIC) { - ERROR_LOG(ME, "sceMpegQueryStreamOffset: Bad PSMF magic"); + ERROR_LOG(Log::ME, "sceMpegQueryStreamOffset: Bad PSMF magic"); Memory::Write_U32(0, offsetAddr); return ERROR_MPEG_INVALID_VALUE; } else if (ctx->mpegVersion < 0) { - ERROR_LOG(ME, "sceMpegQueryStreamOffset: Bad version"); + ERROR_LOG(Log::ME, "sceMpegQueryStreamOffset: Bad version"); Memory::Write_U32(0, offsetAddr); return ERROR_MPEG_BAD_VERSION; } else if ((ctx->mpegOffset & 2047) != 0 || ctx->mpegOffset == 0) { - ERROR_LOG(ME, "sceMpegQueryStreamOffset: Bad offset"); + ERROR_LOG(Log::ME, "sceMpegQueryStreamOffset: Bad offset"); Memory::Write_U32(0, offsetAddr); return ERROR_MPEG_INVALID_VALUE; } @@ -662,11 +663,11 @@ static int sceMpegQueryStreamOffset(u32 mpeg, u32 bufferAddr, u32 offsetAddr) static u32 sceMpegQueryStreamSize(u32 bufferAddr, u32 sizeAddr) { if (!Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(sizeAddr)) { - ERROR_LOG(ME, "sceMpegQueryStreamSize(%08x, %08x): invalid addresses", bufferAddr, sizeAddr); + ERROR_LOG(Log::ME, "sceMpegQueryStreamSize(%08x, %08x): invalid addresses", bufferAddr, sizeAddr); return -1; } - DEBUG_LOG(ME, "sceMpegQueryStreamSize(%08x, %08x)", bufferAddr, sizeAddr); + DEBUG_LOG(Log::ME, "sceMpegQueryStreamSize(%08x, %08x)", bufferAddr, sizeAddr); MpegContext ctx; ctx.mediaengine = nullptr; // makes sure we don't actually load the stream. @@ -675,11 +676,11 @@ static u32 sceMpegQueryStreamSize(u32 bufferAddr, u32 sizeAddr) AnalyzeMpeg(Memory::GetPointerWriteUnchecked(bufferAddr), Memory::ValidSize(bufferAddr, 32768), &ctx); if (ctx.mpegMagic != PSMF_MAGIC) { - ERROR_LOG(ME, "sceMpegQueryStreamSize: Bad PSMF magic"); + ERROR_LOG(Log::ME, "sceMpegQueryStreamSize: Bad PSMF magic"); Memory::Write_U32(0, sizeAddr); return ERROR_MPEG_INVALID_VALUE; } else if ((ctx.mpegOffset & 2047) != 0 ) { - ERROR_LOG(ME, "sceMpegQueryStreamSize: Bad offset"); + ERROR_LOG(Log::ME, "sceMpegQueryStreamSize: Bad offset"); Memory::Write_U32(0, sizeAddr); return ERROR_MPEG_INVALID_VALUE; } @@ -692,11 +693,11 @@ static int sceMpegRegistStream(u32 mpeg, u32 streamType, u32 streamNum) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegRegistStream(%08x, %i, %i): bad mpeg handle", mpeg, streamType, streamNum); + WARN_LOG(Log::ME, "sceMpegRegistStream(%08x, %i, %i): bad mpeg handle", mpeg, streamType, streamNum); return -1; } - INFO_LOG(ME, "sceMpegRegistStream(%08x, %i, %i)", mpeg, streamType, streamNum); + INFO_LOG(Log::ME, "sceMpegRegistStream(%08x, %i, %i)", mpeg, streamType, streamNum); switch (streamType) { case MPEG_AVC_STREAM: @@ -718,7 +719,7 @@ static int sceMpegRegistStream(u32 mpeg, u32 streamType, u32 streamNum) ctx->dataRegistered = true; break; default : - DEBUG_LOG(ME, "sceMpegRegistStream(%i) : unknown stream type", streamType); + DEBUG_LOG(Log::ME, "sceMpegRegistStream(%i) : unknown stream type", streamType); break; } // ... @@ -736,11 +737,11 @@ static int sceMpegMallocAvcEsBuf(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegMallocAvcEsBuf(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "sceMpegMallocAvcEsBuf(%08x): bad mpeg handle", mpeg); return -1; } - DEBUG_LOG(ME, "sceMpegMallocAvcEsBuf(%08x)", mpeg); + DEBUG_LOG(Log::ME, "sceMpegMallocAvcEsBuf(%08x)", mpeg); // Doesn't actually malloc, just keeps track of a couple of flags for (int i = 0; i < MPEG_DATA_ES_BUFFERS; i++) { @@ -757,11 +758,11 @@ static int sceMpegFreeAvcEsBuf(u32 mpeg, int esBuf) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegFreeAvcEsBuf(%08x, %i): bad mpeg handle", mpeg, esBuf); + WARN_LOG(Log::ME, "sceMpegFreeAvcEsBuf(%08x, %i): bad mpeg handle", mpeg, esBuf); return -1; } - DEBUG_LOG(ME, "sceMpegFreeAvcEsBuf(%08x, %i)", mpeg, esBuf); + DEBUG_LOG(Log::ME, "sceMpegFreeAvcEsBuf(%08x, %i)", mpeg, esBuf); if (esBuf == 0) { return ERROR_MPEG_INVALID_VALUE; @@ -806,14 +807,14 @@ static bool InitPmp(MpegContext * ctx){ // Create H264 video codec AVCodec * pmp_Codec = avcodec_find_decoder(AV_CODEC_ID_H264); if (pmp_Codec == NULL){ - ERROR_LOG(ME, "Can not find H264 codec, please update ffmpeg"); + ERROR_LOG(Log::ME, "Can not find H264 codec, please update ffmpeg"); return false; } // Create CodecContext AVCodecContext * pmp_CodecCtx = avcodec_alloc_context3(pmp_Codec); if (pmp_CodecCtx == NULL){ - ERROR_LOG(ME, "Can not allocate pmp Codec Context"); + ERROR_LOG(Log::ME, "Can not allocate pmp Codec Context"); return false; } @@ -831,7 +832,7 @@ static bool InitPmp(MpegContext * ctx){ // Open pmp video codec if (avcodec_open2(pmp_CodecCtx, pmp_Codec, NULL) < 0){ - ERROR_LOG(ME, "Can not open pmp video codec"); + ERROR_LOG(Log::ME, "Can not open pmp video codec"); return false; } @@ -955,7 +956,7 @@ static bool decodePmpVideo(PSPPointer ringbuffer, u32 pmpctxA if (isContextExist(pmpctxAddr) == false){ bool ret = InitPmp(ctx); if (!ret){ - ERROR_LOG(ME, "Pmp video initialization failed"); + ERROR_LOG(Log::ME, "Pmp video initialization failed"); return false; } // add the initialized context into ContextList @@ -1024,7 +1025,7 @@ static bool decodePmpVideo(PSPPointer ringbuffer, u32 pmpctxA #else int len = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet); #endif - DEBUG_LOG(ME, "got_picture %d", got_picture); + DEBUG_LOG(Log::ME, "got_picture %d", got_picture); if (got_picture){ SwsContext *img_convert_ctx = NULL; img_convert_ctx = sws_getContext( @@ -1038,7 +1039,7 @@ static bool decodePmpVideo(PSPPointer ringbuffer, u32 pmpctxA NULL, NULL, NULL); if (!img_convert_ctx) { - ERROR_LOG(ME, "Cannot initialize sws conversion context"); + ERROR_LOG(Log::ME, "Cannot initialize sws conversion context"); return false; } @@ -1046,7 +1047,7 @@ static bool decodePmpVideo(PSPPointer ringbuffer, u32 pmpctxA int swsRet = sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); if (swsRet < 0){ - ERROR_LOG(ME, "sws_scale: Error while converting %d", swsRet); + ERROR_LOG(Log::ME, "sws_scale: Error while converting %d", swsRet); return false; } // free sws context @@ -1128,7 +1129,7 @@ static u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): bad mpeg handle", mpeg, auAddr, frameWidth, bufferAddr, initAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): bad mpeg handle", mpeg, auAddr, frameWidth, bufferAddr, initAddr); return -1; } @@ -1145,23 +1146,23 @@ static u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr auto ringbuffer = PSPPointer::Create(ctx->mpegRingbufferAddr); if (!ringbuffer.IsValid()) { - ERROR_LOG(ME, "Bogus mpegringbufferaddr"); + ERROR_LOG(Log::ME, "Bogus mpegringbufferaddr"); return -1; } u32 buffer = Memory::Read_U32(bufferAddr); u32 init = Memory::Read_U32(initAddr); - DEBUG_LOG(ME, "video: bufferAddr = %08x, *buffer = %08x, *init = %08x", bufferAddr, buffer, init); + DEBUG_LOG(Log::ME, "video: bufferAddr = %08x, *buffer = %08x, *init = %08x", bufferAddr, buffer, init); // check and decode pmp video bool ispmp = false; if (decodePmpVideo(ringbuffer, mpeg)){ - DEBUG_LOG(ME, "Using ffmpeg to decode pmp video"); + DEBUG_LOG(Log::ME, "Using ffmpeg to decode pmp video"); ispmp = true; } if (ringbuffer->packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) { - WARN_LOG(ME, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): mpeg buffer empty", mpeg, auAddr, frameWidth, bufferAddr, initAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): mpeg buffer empty", mpeg, auAddr, frameWidth, bufferAddr, initAddr); return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs); } @@ -1218,7 +1219,7 @@ static u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr } ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS; - DEBUG_LOG(ME, "sceMpegAvcDecode(%08x, %08x, %i, %08x, %08x)", mpeg, auAddr, frameWidth, bufferAddr, initAddr); + DEBUG_LOG(Log::ME, "sceMpegAvcDecode(%08x, %08x, %i, %08x, %08x)", mpeg, auAddr, frameWidth, bufferAddr, initAddr); if (ctx->videoFrameCount <= 1) return hleDelayResult(0, "mpeg decode", avcFirstDelayMs); @@ -1231,17 +1232,17 @@ static u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr static u32 sceMpegAvcDecodeStop(u32 mpeg, u32 frameWidth, u32 bufferAddr, u32 statusAddr) { if (!Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(statusAddr)){ - ERROR_LOG(ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x): invalid addresses", mpeg, frameWidth, bufferAddr, statusAddr); + ERROR_LOG(Log::ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x): invalid addresses", mpeg, frameWidth, bufferAddr, statusAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, frameWidth, bufferAddr, statusAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, frameWidth, bufferAddr, statusAddr); return -1; } - DEBUG_LOG(ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x)", mpeg, frameWidth, bufferAddr, statusAddr); + DEBUG_LOG(Log::ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x)", mpeg, frameWidth, bufferAddr, statusAddr); // No last frame generated Memory::Write_U32(0, statusAddr); @@ -1252,7 +1253,7 @@ static u32 sceMpegUnRegistStream(u32 mpeg, int streamUid) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegUnRegistStream(%08x, %i): bad mpeg handle", mpeg, streamUid); + WARN_LOG(Log::ME, "sceMpegUnRegistStream(%08x, %i): bad mpeg handle", mpeg, streamUid); return -1; } @@ -1273,7 +1274,7 @@ static u32 sceMpegUnRegistStream(u32 mpeg, int streamUid) ctx->dataRegistered = false; break; default : - DEBUG_LOG(ME, "sceMpegUnRegistStream(%i) : unknown streamID ", streamUid); + DEBUG_LOG(Log::ME, "sceMpegUnRegistStream(%i) : unknown streamID ", streamUid); break; } ctx->streamMap[streamUid] = info; @@ -1287,17 +1288,17 @@ static u32 sceMpegUnRegistStream(u32 mpeg, int streamUid) static int sceMpegAvcDecodeDetail(u32 mpeg, u32 detailAddr) { if (!Memory::IsValidAddress(detailAddr)){ - WARN_LOG(ME, "sceMpegAvcDecodeDetail(%08x, %08x): invalid addresses", mpeg, detailAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecodeDetail(%08x, %08x): invalid addresses", mpeg, detailAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegAvcDecodeDetail(%08x, %08x): bad mpeg handle", mpeg, detailAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecodeDetail(%08x, %08x): bad mpeg handle", mpeg, detailAddr); return -1; } - DEBUG_LOG(ME, "sceMpegAvcDecodeDetail(%08x, %08x)", mpeg, detailAddr); + DEBUG_LOG(Log::ME, "sceMpegAvcDecodeDetail(%08x, %08x)", mpeg, detailAddr); Memory::Write_U32(ctx->avc.avcDecodeResult, detailAddr + 0); Memory::Write_U32(ctx->videoFrameCount, detailAddr + 4); @@ -1314,17 +1315,17 @@ static int sceMpegAvcDecodeDetail(u32 mpeg, u32 detailAddr) static u32 sceMpegAvcDecodeStopYCbCr(u32 mpeg, u32 bufferAddr, u32 statusAddr) { if (!Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(statusAddr)) { - ERROR_LOG(ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x): invalid addresses", mpeg, bufferAddr, statusAddr); + ERROR_LOG(Log::ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x): invalid addresses", mpeg, bufferAddr, statusAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x): bad mpeg handle", mpeg, bufferAddr, statusAddr); + WARN_LOG(Log::ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x): bad mpeg handle", mpeg, bufferAddr, statusAddr); return -1; } - ERROR_LOG(ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x)", mpeg, bufferAddr, statusAddr); + ERROR_LOG(Log::ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x)", mpeg, bufferAddr, statusAddr); Memory::Write_U32(0, statusAddr); return 0; } @@ -1333,7 +1334,7 @@ static int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initA { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, auAddr, bufferAddr, initAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, auAddr, bufferAddr, initAddr); return -1; } @@ -1342,12 +1343,12 @@ static int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initA auto ringbuffer = PSPPointer::Create(ctx->mpegRingbufferAddr); if (!ringbuffer.IsValid()) { - ERROR_LOG(ME, "Bogus mpegringbufferaddr"); + ERROR_LOG(Log::ME, "Bogus mpegringbufferaddr"); return -1; } if (ringbuffer->packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) { - WARN_LOG(ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): mpeg buffer empty", mpeg, auAddr, bufferAddr, initAddr); + WARN_LOG(Log::ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): mpeg buffer empty", mpeg, auAddr, bufferAddr, initAddr); return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs); } @@ -1358,7 +1359,7 @@ static int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initA u32 buffer = Memory::Read_U32(bufferAddr); u32 init = Memory::Read_U32(initAddr); - DEBUG_LOG(ME, "*buffer = %08x, *init = %08x", buffer, init); + DEBUG_LOG(Log::ME, "*buffer = %08x, *init = %08x", buffer, init); if (ctx->mediaengine->stepVideo(ctx->videoPixelMode)) { // Don't draw here, we'll draw in the Csc func. @@ -1391,7 +1392,7 @@ static int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initA } ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS; - DEBUG_LOG(ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x)", mpeg, auAddr, bufferAddr, initAddr); + DEBUG_LOG(Log::ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x)", mpeg, auAddr, bufferAddr, initAddr); if (ctx->videoFrameCount <= 1) return hleDelayResult(0, "mpeg decode", avcFirstDelayMs); @@ -1405,11 +1406,11 @@ static u32 sceMpegAvcDecodeFlush(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegAvcDecodeFlush(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegAvcDecodeFlush(%08x): bad mpeg handle", mpeg); return -1; } - ERROR_LOG(ME, "UNIMPL sceMpegAvcDecodeFlush(%08x)", mpeg); + ERROR_LOG(Log::ME, "UNIMPL sceMpegAvcDecodeFlush(%08x)", mpeg); if ( ctx->videoFrameCount > 0 || ctx->audioFrameCount > 0) { //__MpegFinish(); } @@ -1420,11 +1421,11 @@ static int sceMpegInitAu(u32 mpeg, u32 bufferAddr, u32 auPointer) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegInitAu(%08x, %i, %08x): bad mpeg handle", mpeg, bufferAddr, auPointer); + WARN_LOG(Log::ME, "sceMpegInitAu(%08x, %i, %08x): bad mpeg handle", mpeg, bufferAddr, auPointer); return -1; } - DEBUG_LOG(ME, "sceMpegInitAu(%08x, %i, %08x)", mpeg, bufferAddr, auPointer); + DEBUG_LOG(Log::ME, "sceMpegInitAu(%08x, %i, %08x)", mpeg, bufferAddr, auPointer); SceMpegAu sceAu; sceAu.read(auPointer); @@ -1456,17 +1457,17 @@ static int sceMpegInitAu(u32 mpeg, u32 bufferAddr, u32 auPointer) static int sceMpegQueryAtracEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr) { if (!Memory::IsValidAddress(esSizeAddr) || !Memory::IsValidAddress(outSizeAddr)) { - ERROR_LOG(ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr); + ERROR_LOG(Log::ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr); + WARN_LOG(Log::ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr); return -1; } - DEBUG_LOG(ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr); + DEBUG_LOG(Log::ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr); Memory::Write_U32(MPEG_ATRAC_ES_SIZE, esSizeAddr); Memory::Write_U32(MPEG_ATRAC_ES_OUTPUT_SIZE, outSizeAddr); @@ -1478,13 +1479,13 @@ static int sceMpegRingbufferAvailableSize(u32 ringbufferAddr) auto ringbuffer = PSPPointer::Create(ringbufferAddr); if (!ringbuffer.IsValid()) { - ERROR_LOG(ME, "sceMpegRingbufferAvailableSize(%08x): invalid ringbuffer, should crash", ringbufferAddr); + ERROR_LOG(Log::ME, "sceMpegRingbufferAvailableSize(%08x): invalid ringbuffer, should crash", ringbufferAddr); return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS; } MpegContext *ctx = getMpegCtx(ringbuffer->mpeg); if (!ctx) { - ERROR_LOG(ME, "sceMpegRingbufferAvailableSize(%08x): bad mpeg handle", ringbufferAddr); + ERROR_LOG(Log::ME, "sceMpegRingbufferAvailableSize(%08x): bad mpeg handle", ringbufferAddr); return ERROR_MPEG_NOT_YET_INIT; } @@ -1494,10 +1495,10 @@ static int sceMpegRingbufferAvailableSize(u32 ringbufferAddr) static int lastAvail = 0; if (lastAvail != ringbuffer->packetsAvail) { - DEBUG_LOG(ME, "%i=sceMpegRingbufferAvailableSize(%08x)", ringbuffer->packets - ringbuffer->packetsAvail, ringbufferAddr); + DEBUG_LOG(Log::ME, "%i=sceMpegRingbufferAvailableSize(%08x)", ringbuffer->packets - ringbuffer->packetsAvail, ringbufferAddr); lastAvail = ringbuffer->packetsAvail; } else { - VERBOSE_LOG(ME, "%i=sceMpegRingbufferAvailableSize(%08x)", ringbuffer->packets - ringbuffer->packetsAvail, ringbufferAddr); + VERBOSE_LOG(Log::ME, "%i=sceMpegRingbufferAvailableSize(%08x)", ringbuffer->packets - ringbuffer->packetsAvail, ringbufferAddr); } return ringbuffer->packets - ringbuffer->packetsAvail; } @@ -1531,7 +1532,7 @@ void PostPutAction::run(MipsCall &call) { } if (invalid) { // Bail out early - don't accept any of the packets, even the good ones. - ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut(): invalid mpeg data"); + ERROR_LOG_REPORT(Log::ME, "sceMpegRingbufferPut(): invalid mpeg data"); call.setReturnValue(ERROR_MPEG_INVALID_VALUE); if (mpegLibVersion <= 0x0103) { @@ -1550,20 +1551,20 @@ void PostPutAction::run(MipsCall &call) { } if (packetsAddedThisRound > 0) { if (packetsAddedThisRound > ringbuffer->packets - ringbuffer->packetsAvail) { - WARN_LOG(ME, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAddedThisRound, ringbuffer->packets - ringbuffer->packetsAvail); + WARN_LOG(Log::ME, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAddedThisRound, ringbuffer->packets - ringbuffer->packetsAvail); packetsAddedThisRound = ringbuffer->packets - ringbuffer->packetsAvail; } const u8 *data = Memory::GetPointer(ringbuffer->data + writeOffset * 2048); uint32_t dataSize = Memory::ValidSize(ringbuffer->data + writeOffset * 2048, packetsAddedThisRound * 2048); int actuallyAdded = ctx->mediaengine == NULL ? 8 : ctx->mediaengine->addStreamData(data, dataSize) / 2048; if (actuallyAdded != packetsAddedThisRound) { - WARN_LOG_REPORT(ME, "sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames."); + WARN_LOG_REPORT(Log::ME, "sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames."); } ringbuffer->packetsRead += packetsAddedThisRound; ringbuffer->packetsWritePos += packetsAddedThisRound; ringbuffer->packetsAvail += packetsAddedThisRound; } - DEBUG_LOG(ME, "packetAdded: %i packetsRead: %i packetsTotal: %i", packetsAddedThisRound, ringbuffer->packetsRead, ringbuffer->packets); + DEBUG_LOG(Log::ME, "packetAdded: %i packetsRead: %i packetsTotal: %i", packetsAddedThisRound, ringbuffer->packetsRead, ringbuffer->packets); if (packetsAddedThisRound < 0 && ringbufferPutPacketsAdded == 0) { // Return an error. @@ -1580,7 +1581,7 @@ static u32 sceMpegRingbufferPut(u32 ringbufferAddr, int numPackets, int availabl auto ringbuffer = PSPPointer::Create(ringbufferAddr); if (!ringbuffer.IsValid()) { // Would have crashed before, TODO test behavior. - ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut(%08x, %i, %i): invalid ringbuffer address", ringbufferAddr, numPackets, available); + ERROR_LOG_REPORT(Log::ME, "sceMpegRingbufferPut(%08x, %i, %i): invalid ringbuffer address", ringbufferAddr, numPackets, available); return -1; } @@ -1589,19 +1590,19 @@ static u32 sceMpegRingbufferPut(u32 ringbufferAddr, int numPackets, int availabl // Seems still need to check actual available, Patapon 3 for example. numPackets = std::min(numPackets, ringbuffer->packets - ringbuffer->packetsAvail); if (numPackets <= 0) { - DEBUG_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i): no packets to enqueue", ringbufferAddr, numPackets, available); + DEBUG_LOG(Log::ME, "sceMpegRingbufferPut(%08x, %i, %i): no packets to enqueue", ringbufferAddr, numPackets, available); return 0; } MpegContext *ctx = getMpegCtx(ringbuffer->mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i): bad mpeg handle %08x", ringbufferAddr, numPackets, available, ringbuffer->mpeg); + WARN_LOG(Log::ME, "sceMpegRingbufferPut(%08x, %i, %i): bad mpeg handle %08x", ringbufferAddr, numPackets, available, ringbuffer->mpeg); return -1; } ringbufferPutPacketsAdded = 0; // Execute callback function as a direct MipsCall, no blocking here so no messing around with wait states etc if (ringbuffer->callback_addr != 0) { - DEBUG_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i)", ringbufferAddr, numPackets, available); + DEBUG_LOG(Log::ME, "sceMpegRingbufferPut(%08x, %i, %i)", ringbufferAddr, numPackets, available); // Call this multiple times until we get numPackets. // Normally this would be if it did not read enough, but also if available > packets. @@ -1622,7 +1623,7 @@ static u32 sceMpegRingbufferPut(u32 ringbufferAddr, int numPackets, int availabl break; } } else { - ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut: callback_addr zero"); + ERROR_LOG_REPORT(Log::ME, "sceMpegRingbufferPut: callback_addr zero"); } return 0; } @@ -1631,20 +1632,20 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamId, auAddr, attrAddr); + WARN_LOG(Log::ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamId, auAddr, attrAddr); return -1; } auto ringbuffer = PSPPointer::Create(ctx->mpegRingbufferAddr); if (!ringbuffer.IsValid()) { // Would have crashed before, TODO test behavior. - ERROR_LOG_REPORT(ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamId, auAddr, attrAddr); + ERROR_LOG_REPORT(Log::ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamId, auAddr, attrAddr); return -1; } if (PSP_CoreParameter().compat.flags().MpegAvcWarmUp) { if (ctx->mpegwarmUp == 0) { - DEBUG_LOG(ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): warming up", mpeg, streamId, auAddr, attrAddr); + DEBUG_LOG(Log::ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): warming up", mpeg, streamId, auAddr, attrAddr); ctx->mpegwarmUp++; return ERROR_MPEG_NO_DATA; } @@ -1654,7 +1655,7 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) avcAu.read(auAddr); if (ringbuffer->packetsRead == 0 || ringbuffer->packetsAvail == 0) { - DEBUG_LOG(ME, "ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr); + DEBUG_LOG(Log::ME, "ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr); avcAu.pts = -1; avcAu.dts = -1; avcAu.write(auAddr); @@ -1664,7 +1665,7 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) auto streamInfo = ctx->streamMap.find(streamId); if (streamInfo == ctx->streamMap.end()) { - WARN_LOG_REPORT(ME, "sceMpegGetAvcAu: invalid video stream %08x", streamId); + WARN_LOG_REPORT(Log::ME, "sceMpegGetAvcAu: invalid video stream %08x", streamId); return -1; } @@ -1680,7 +1681,7 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) /*// Wait for audio if too much ahead if (ctx->atracRegistered && (ctx->mediaengine->getVideoTimeStamp() > ctx->mediaengine->getAudioTimeStamp() + getMaxAheadTimestamp(mpegRingbuffer))) { - ERROR_LOG(ME, "sceMpegGetAvcAu - video too much ahead"); + ERROR_LOG(Log::ME, "sceMpegGetAvcAu - video too much ahead"); // TODO: Does this really reschedule? return hleDelayResult(ERROR_MPEG_NO_DATA, "mpeg get avc", mpegDecodeErrorDelayMs); }*/ @@ -1691,7 +1692,7 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) avcAu.dts = avcAu.pts - videoTimestampStep; if (ctx->mediaengine->IsVideoEnd()) { - INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)avcAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); + INFO_LOG(Log::ME, "video end reach. pts: %i dts: %i", (int)avcAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); ringbuffer->packetsAvail = 0; result = ERROR_MPEG_NO_DATA; @@ -1705,7 +1706,7 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) Memory::Write_U32(1, attrAddr); } - DEBUG_LOG(ME, "%x=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr); + DEBUG_LOG(Log::ME, "%x=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr); // TODO: sceMpegGetAvcAu seems to modify esSize, and delay when it's > 1000 or something. // There's definitely more to it, but ultimately it seems games should expect it to delay randomly. return hleDelayResult(result, "mpeg get avc", 100); @@ -1714,11 +1715,11 @@ static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) static u32 sceMpegFinish() { if (!isMpegInit) { - WARN_LOG(ME, "sceMpegFinish(...): not initialized"); + WARN_LOG(Log::ME, "sceMpegFinish(...): not initialized"); // TODO: Need to properly hook module load/unload for this to work right. //return ERROR_MPEG_NOT_YET_INIT; } else { - INFO_LOG(ME, "sceMpegFinish(...)"); + INFO_LOG(Log::ME, "sceMpegFinish(...)"); __VideoPmpShutdown(); } isMpegInit = false; @@ -1727,21 +1728,21 @@ static u32 sceMpegFinish() } static u32 sceMpegQueryMemSize() { - return hleLogSuccessX(ME, MpegRequiredMem()); + return hleLogSuccessX(Log::ME, MpegRequiredMem()); } static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegGetAtracAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamId, auAddr, attrAddr); + WARN_LOG(Log::ME, "sceMpegGetAtracAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamId, auAddr, attrAddr); return -1; } auto ringbuffer = PSPPointer::Create(ctx->mpegRingbufferAddr); if (!ringbuffer.IsValid()) { // Would have crashed before, TODO test behavior. - WARN_LOG(ME, "sceMpegGetAtracAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamId, auAddr, attrAddr); + WARN_LOG(Log::ME, "sceMpegGetAtracAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamId, auAddr, attrAddr); return -1; } @@ -1754,13 +1755,13 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) streamInfo->second.needsReset = false; } if (streamInfo == ctx->streamMap.end()) { - WARN_LOG_REPORT(ME, "sceMpegGetAtracAu: invalid audio stream %08x", streamId); + WARN_LOG_REPORT(Log::ME, "sceMpegGetAtracAu: invalid audio stream %08x", streamId); // TODO: Why was this changed to not return an error? } // The audio can end earlier than the video does. if (ringbuffer->packetsAvail == 0) { - DEBUG_LOG(ME, "ERROR_MPEG_NO_DATA=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr); + DEBUG_LOG(Log::ME, "ERROR_MPEG_NO_DATA=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr); // TODO: Does this really delay? return hleDelayResult(ERROR_MPEG_NO_DATA, "mpeg get atrac", mpegDecodeErrorDelayMs); } @@ -1776,17 +1777,17 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) atracAu.pts = ctx->mediaengine->getAudioTimeStamp() + ctx->mpegFirstTimestamp; if (ctx->mediaengine->IsVideoEnd()) { - INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)atracAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); + INFO_LOG(Log::ME, "video end reach. pts: %i dts: %i", (int)atracAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); ringbuffer->packetsAvail = 0; // TODO: Is this correct? if (!ctx->mediaengine->IsNoAudioData()) { - WARN_LOG_REPORT(ME, "Video end without audio end, potentially skipping some audio?"); + WARN_LOG_REPORT(Log::ME, "Video end without audio end, potentially skipping some audio?"); } result = ERROR_MPEG_NO_DATA; } if (ctx->atracRegistered && ctx->mediaengine->IsNoAudioData() && !ctx->endOfAudioReached) { - WARN_LOG(ME, "Audio end reach. pts: %i dts: %i", (int)atracAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); + WARN_LOG(Log::ME, "Audio end reach. pts: %i dts: %i", (int)atracAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); ctx->endOfAudioReached = true; } if (ctx->mediaengine->IsNoAudioData()) { @@ -1800,7 +1801,7 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) Memory::Write_U32(0, attrAddr); } - DEBUG_LOG(ME, "%x=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr); + DEBUG_LOG(Log::ME, "%x=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr); // TODO: Not clear on exactly when this delays. return hleDelayResult(result, "mpeg get atrac", 100); } @@ -1808,17 +1809,17 @@ static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) static int sceMpegQueryPcmEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr) { if (!Memory::IsValidAddress(esSizeAddr) || !Memory::IsValidAddress(outSizeAddr)) { - ERROR_LOG(ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr); + ERROR_LOG(Log::ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr); + WARN_LOG(Log::ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr); return -1; } - ERROR_LOG(ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr); + ERROR_LOG(Log::ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr); Memory::Write_U32(MPEG_PCM_ES_SIZE, esSizeAddr); Memory::Write_U32(MPEG_PCM_ES_OUTPUT_SIZE, outSizeAddr); @@ -1830,21 +1831,21 @@ static u32 sceMpegChangeGetAuMode(u32 mpeg, int streamUid, int mode) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegChangeGetAuMode(%08x, %i, %i): bad mpeg handle", mpeg, streamUid, mode); + WARN_LOG(Log::ME, "sceMpegChangeGetAuMode(%08x, %i, %i): bad mpeg handle", mpeg, streamUid, mode); return ERROR_MPEG_INVALID_VALUE; } if (mode != MPEG_AU_MODE_DECODE && mode != MPEG_AU_MODE_SKIP) { - ERROR_LOG(ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): bad mode", mpeg, streamUid, mode); + ERROR_LOG(Log::ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): bad mode", mpeg, streamUid, mode); return ERROR_MPEG_INVALID_VALUE; } auto stream = ctx->streamMap.find(streamUid); if (stream == ctx->streamMap.end()) { - ERROR_LOG(ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): unknown streamID", mpeg, streamUid, mode); + ERROR_LOG(Log::ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): unknown streamID", mpeg, streamUid, mode); return ERROR_MPEG_INVALID_VALUE; } else { StreamInfo &info = stream->second; - DEBUG_LOG(ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): changing type=%d", mpeg, streamUid, mode, info.type); + DEBUG_LOG(Log::ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): changing type=%d", mpeg, streamUid, mode, info.type); switch (info.type) { case MPEG_AVC_STREAM: if (mode == MPEG_AU_MODE_DECODE) { @@ -1869,7 +1870,7 @@ static u32 sceMpegChangeGetAuMode(u32 mpeg, int streamUid, int mode) } break; default: - ERROR_LOG(ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): unknown streamID", mpeg, streamUid, mode); + ERROR_LOG(Log::ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): unknown streamID", mpeg, streamUid, mode); break; } } @@ -1879,17 +1880,17 @@ static u32 sceMpegChangeGetAuMode(u32 mpeg, int streamUid, int mode) static u32 sceMpegChangeGetAvcAuMode(u32 mpeg, u32 stream_addr, int mode) { if (!Memory::IsValidAddress(stream_addr)) { - ERROR_LOG(ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i): invalid addresses", mpeg, stream_addr, mode); + ERROR_LOG(Log::ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i): invalid addresses", mpeg, stream_addr, mode); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i): bad mpeg handle", mpeg, stream_addr, mode); + WARN_LOG(Log::ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i): bad mpeg handle", mpeg, stream_addr, mode); return -1; } - ERROR_LOG_REPORT_ONCE(mpegChangeAvcAu, ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i)", mpeg, stream_addr, mode); + ERROR_LOG_REPORT_ONCE(mpegChangeAvcAu, Log::ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i)", mpeg, stream_addr, mode); return 0; } @@ -1897,24 +1898,24 @@ static u32 sceMpegGetPcmAu(u32 mpeg, int streamUid, u32 auAddr, u32 attrAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x): bad mpeg handle", mpeg, streamUid, auAddr, attrAddr); + WARN_LOG(Log::ME, "UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x): bad mpeg handle", mpeg, streamUid, auAddr, attrAddr); return -1; } auto ringbuffer = PSPPointer::Create(ctx->mpegRingbufferAddr); if (!ringbuffer.IsValid()) { // Would have crashed before, TODO test behavior - WARN_LOG(ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamUid, auAddr, attrAddr); + WARN_LOG(Log::ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamUid, auAddr, attrAddr); return -1; } if (!Memory::IsValidAddress(streamUid)) { - WARN_LOG(ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): didn't get a fake stream", mpeg, streamUid, auAddr, attrAddr); + WARN_LOG(Log::ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): didn't get a fake stream", mpeg, streamUid, auAddr, attrAddr); return ERROR_MPEG_INVALID_ADDR; } SceMpegAu atracAu; atracAu.read(auAddr); auto streamInfo = ctx->streamMap.find(streamUid); if (streamInfo == ctx->streamMap.end()) { - WARN_LOG(ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): bad streamUid ", mpeg, streamUid, auAddr, attrAddr); + WARN_LOG(Log::ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): bad streamUid ", mpeg, streamUid, auAddr, attrAddr); return -1; } @@ -1924,7 +1925,7 @@ static u32 sceMpegGetPcmAu(u32 mpeg, int streamUid, u32 auAddr, u32 attrAddr) if (Memory::IsValidAddress(attrAddr)) Memory::Write_U32(attr, attrAddr); - ERROR_LOG_REPORT_ONCE(mpegPcmAu, ME, "UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x)", mpeg, streamUid, auAddr, attrAddr); + ERROR_LOG_REPORT_ONCE(mpegPcmAu, Log::ME, "UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x)", mpeg, streamUid, auAddr, attrAddr); return 0; } @@ -1933,7 +1934,7 @@ static int __MpegRingbufferQueryPackNum(u32 memorySize) { } static int sceMpegRingbufferQueryPackNum(u32 memorySize) { - DEBUG_LOG(ME, "sceMpegRingbufferQueryPackNum(%i)", memorySize); + DEBUG_LOG(Log::ME, "sceMpegRingbufferQueryPackNum(%i)", memorySize); return __MpegRingbufferQueryPackNum(memorySize); } @@ -1941,11 +1942,11 @@ static u32 sceMpegFlushAllStream(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegFlushAllStream(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "sceMpegFlushAllStream(%08x): bad mpeg handle", mpeg); return -1; } - WARN_LOG(ME, "UNIMPL sceMpegFlushAllStream(%08x)", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegFlushAllStream(%08x)", mpeg); ctx->isAnalyzed = false; @@ -1962,17 +1963,17 @@ static u32 sceMpegFlushAllStream(u32 mpeg) static u32 sceMpegFlushStream(u32 mpeg, int stream_addr) { if (!Memory::IsValidAddress(stream_addr)) { - ERROR_LOG(ME, "UNIMPL sceMpegFlushStream(%08x, %i): invalid addresses", mpeg , stream_addr); + ERROR_LOG(Log::ME, "UNIMPL sceMpegFlushStream(%08x, %i): invalid addresses", mpeg , stream_addr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegFlushStream(%08x, %i): bad mpeg handle", mpeg , stream_addr); + WARN_LOG(Log::ME, "UNIMPL sceMpegFlushStream(%08x, %i): bad mpeg handle", mpeg , stream_addr); return -1; } - ERROR_LOG(ME, "UNIMPL sceMpegFlushStream(%08x, %i)", mpeg , stream_addr); + ERROR_LOG(Log::ME, "UNIMPL sceMpegFlushStream(%08x, %i)", mpeg , stream_addr); //__MpegFinish(); return 0; } @@ -1980,18 +1981,18 @@ static u32 sceMpegFlushStream(u32 mpeg, int stream_addr) static u32 sceMpegAvcCopyYCbCr(u32 mpeg, u32 sourceAddr, u32 YCbCrAddr) { if (!Memory::IsValidAddress(sourceAddr) || !Memory::IsValidAddress(YCbCrAddr)) { - ERROR_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): invalid addresses", mpeg, sourceAddr, YCbCrAddr); + ERROR_LOG(Log::ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): invalid addresses", mpeg, sourceAddr, YCbCrAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - ERROR_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): bad mpeg handle", mpeg, sourceAddr, YCbCrAddr); + ERROR_LOG(Log::ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): bad mpeg handle", mpeg, sourceAddr, YCbCrAddr); return -1; } // This is very common. - DEBUG_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x)", mpeg, sourceAddr, YCbCrAddr); + DEBUG_LOG(Log::ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x)", mpeg, sourceAddr, YCbCrAddr); return 0; } @@ -1999,16 +2000,16 @@ static u32 sceMpegAtracDecode(u32 mpeg, u32 auAddr, u32 bufferAddr, int init) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i): bad mpeg handle", mpeg, auAddr, bufferAddr, init); + WARN_LOG(Log::ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i): bad mpeg handle", mpeg, auAddr, bufferAddr, init); return -1; } if (!Memory::IsValidAddress(bufferAddr)) { - WARN_LOG(ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i): invalid addresses", mpeg, auAddr, bufferAddr, init); + WARN_LOG(Log::ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i): invalid addresses", mpeg, auAddr, bufferAddr, init); return -1; } - DEBUG_LOG(ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i)", mpeg, auAddr, bufferAddr, init); + DEBUG_LOG(Log::ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i)", mpeg, auAddr, bufferAddr, init); SceMpegAu atracAu; atracAu.read(auAddr); @@ -2032,17 +2033,17 @@ static u32 sceMpegAtracDecode(u32 mpeg, u32 auAddr, u32 bufferAddr, int init) static u32 sceMpegAvcCsc(u32 mpeg, u32 sourceAddr, u32 rangeAddr, int frameWidth, u32 destAddr) { if (!Memory::IsValidAddress(sourceAddr) || !Memory::IsValidAddress(rangeAddr) || !Memory::IsValidAddress(destAddr)) { - ERROR_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x): invalid addresses", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); + ERROR_LOG(Log::ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x): invalid addresses", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x): bad mpeg handle", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); + WARN_LOG(Log::ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x): bad mpeg handle", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); return -1; } - DEBUG_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x)", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); + DEBUG_LOG(Log::ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x)", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); if (frameWidth == 0) { if (!ctx->defaultFrameWidth) { @@ -2058,7 +2059,7 @@ static u32 sceMpegAvcCsc(u32 mpeg, u32 sourceAddr, u32 rangeAddr, int frameWidth int height = Memory::Read_U32(rangeAddr + 12); if (x < 0 || y < 0 || width < 0 || height < 0) { - WARN_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x) returning ERROR_INVALID_VALUE", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); + WARN_LOG(Log::ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x) returning ERROR_INVALID_VALUE", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr); return SCE_KERNEL_ERROR_INVALID_VALUE; } @@ -2076,7 +2077,7 @@ static u32 sceMpegAvcCsc(u32 mpeg, u32 sourceAddr, u32 rangeAddr, int frameWidth static u32 sceMpegRingbufferDestruct(u32 ringbufferAddr) { - DEBUG_LOG(ME, "sceMpegRingbufferDestruct(%08x)", ringbufferAddr); + DEBUG_LOG(Log::ME, "sceMpegRingbufferDestruct(%08x)", ringbufferAddr); // Apparently, does nothing. return 0; } @@ -2084,28 +2085,28 @@ static u32 sceMpegRingbufferDestruct(u32 ringbufferAddr) static u32 sceMpegAvcInitYCbCr(u32 mpeg, int mode, int width, int height, u32 ycbcr_addr) { if (!Memory::IsValidAddress(ycbcr_addr)) { - ERROR_LOG(ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x): invalid addresses", mpeg, mode, width, height, ycbcr_addr); + ERROR_LOG(Log::ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x): invalid addresses", mpeg, mode, width, height, ycbcr_addr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x): bad mpeg handle", mpeg, mode, width, height, ycbcr_addr); + WARN_LOG(Log::ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x): bad mpeg handle", mpeg, mode, width, height, ycbcr_addr); return -1; } - WARN_LOG_ONCE(sceMpegAvcInitYCbCr, ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x)", mpeg, mode, width, height, ycbcr_addr); + WARN_LOG_ONCE(sceMpegAvcInitYCbCr, Log::ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x)", mpeg, mode, width, height, ycbcr_addr); return 0; } static int sceMpegAvcQueryYCbCrSize(u32 mpeg, u32 mode, u32 width, u32 height, u32 resultAddr) { if ((width & 15) != 0 || (height & 15) != 0 || height > 272 || width > 480) { - ERROR_LOG(ME, "sceMpegAvcQueryYCbCrSize: bad w/h %i x %i", width, height); + ERROR_LOG(Log::ME, "sceMpegAvcQueryYCbCrSize: bad w/h %i x %i", width, height); return ERROR_MPEG_INVALID_VALUE; } - DEBUG_LOG(ME, "sceMpegAvcQueryYCbCrSize(%08x, %i, %i, %i, %08x)", mpeg, mode, width, height, resultAddr); + DEBUG_LOG(Log::ME, "sceMpegAvcQueryYCbCrSize(%08x, %i, %i, %i, %08x)", mpeg, mode, width, height, resultAddr); int size = (width / 2) * (height / 2) * 6 + 128; Memory::Write_U32(size, resultAddr); @@ -2115,17 +2116,17 @@ static int sceMpegAvcQueryYCbCrSize(u32 mpeg, u32 mode, u32 width, u32 height, u static u32 sceMpegQueryUserdataEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr) { if (!Memory::IsValidAddress(esSizeAddr) || !Memory::IsValidAddress(outSizeAddr)) { - ERROR_LOG(ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr); + ERROR_LOG(Log::ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr); + WARN_LOG(Log::ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr); return -1; } - DEBUG_LOG(ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr); + DEBUG_LOG(Log::ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr); Memory::Write_U32(MPEG_DATA_ES_SIZE, esSizeAddr); Memory::Write_U32(MPEG_DATA_ES_OUTPUT_SIZE, outSizeAddr); @@ -2134,20 +2135,20 @@ static u32 sceMpegQueryUserdataEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr) static u32 sceMpegAvcResourceGetAvcDecTopAddr(u32 mpeg) { - ERROR_LOG(ME, "UNIMPL sceMpegAvcResourceGetAvcDecTopAddr(%08x)", mpeg); + ERROR_LOG(Log::ME, "UNIMPL sceMpegAvcResourceGetAvcDecTopAddr(%08x)", mpeg); // it's just a random address return 0x12345678; } static u32 sceMpegAvcResourceFinish(u32 mpeg) { - DEBUG_LOG(ME,"UNIMPL sceMpegAvcResourceFinish(%08x)", mpeg); + DEBUG_LOG(Log::ME,"UNIMPL sceMpegAvcResourceFinish(%08x)", mpeg); return 0; } static u32 sceMpegAvcResourceGetAvcEsBuf(u32 mpeg) { - ERROR_LOG_REPORT_ONCE(mpegResourceEsBuf, ME, "UNIMPL sceMpegAvcResourceGetAvcEsBuf(%08x)", mpeg); + ERROR_LOG_REPORT_ONCE(mpegResourceEsBuf, Log::ME, "UNIMPL sceMpegAvcResourceGetAvcEsBuf(%08x)", mpeg); return 0; } @@ -2157,7 +2158,7 @@ static u32 sceMpegAvcResourceInit(u32 mpeg) return ERROR_MPEG_INVALID_VALUE; } - ERROR_LOG(ME, "UNIMPL sceMpegAvcResourceInit(%08x)", mpeg); + ERROR_LOG(Log::ME, "UNIMPL sceMpegAvcResourceInit(%08x)", mpeg); return 0; } @@ -2188,7 +2189,7 @@ static int __MpegAvcConvertToYuv420(const void *data, u32 bufferOutputAddr, int u8 *Cr = Cb + sizeCb; if (!Y) - return hleLogError(ME, 0, "Bad output buffer pointer for yuv conv: %08x", bufferOutputAddr); + return hleLogError(Log::ME, 0, "Bad output buffer pointer for yuv conv: %08x", bufferOutputAddr); for (int y = 0; y < height; y += 2) { for (int x = 0; x < width; x += 2) { @@ -2216,14 +2217,14 @@ static int __MpegAvcConvertToYuv420(const void *data, u32 bufferOutputAddr, int static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 bufferAddr, int unknown2) { if (!Memory::IsValidAddress(bufferOutputAddr)) - return hleLogError(ME, ERROR_MPEG_INVALID_VALUE, "invalid addresses"); + return hleLogError(Log::ME, ERROR_MPEG_INVALID_VALUE, "invalid addresses"); MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) - return hleLogWarning(ME, -1, "bad mpeg handle"); + return hleLogWarning(Log::ME, -1, "bad mpeg handle"); if (ctx->mediaengine->m_buffer == 0) - return hleLogWarning(ME, ERROR_MPEG_AVC_INVALID_VALUE, "m_buffer is zero"); + return hleLogWarning(Log::ME, ERROR_MPEG_AVC_INVALID_VALUE, "m_buffer is zero"); const u8 *data = ctx->mediaengine->getFrameImage(); int width = ctx->mediaengine->m_desWidth; @@ -2232,18 +2233,18 @@ static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 bufferA if (data) { __MpegAvcConvertToYuv420(data, bufferOutputAddr, width, height); } - return hleLogSuccessX(ME, (width << 16) | height); + return hleLogSuccessX(Log::ME, (width << 16) | height); } static int sceMpegGetUserdataAu(u32 mpeg, u32 streamUid, u32 auAddr, u32 resultAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "sceMpegGetUserdataAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamUid, auAddr, resultAddr); + WARN_LOG(Log::ME, "sceMpegGetUserdataAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamUid, auAddr, resultAddr); return -1; } - DEBUG_LOG(ME, "sceMpegGetUserdataAu(%08x, %08x, %08x, %08x)", mpeg, streamUid, auAddr, resultAddr); + DEBUG_LOG(Log::ME, "sceMpegGetUserdataAu(%08x, %08x, %08x, %08x)", mpeg, streamUid, auAddr, resultAddr); // TODO: Are these at all right? Seen in Phantasy Star Portable 2. Memory::Write_U32(0, resultAddr); @@ -2258,11 +2259,11 @@ static u32 sceMpegNextAvcRpAu(u32 mpeg, u32 streamUid) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegNextAvcRpAu(%08x, %08x): bad mpeg handle", mpeg, streamUid); + WARN_LOG(Log::ME, "UNIMPL sceMpegNextAvcRpAu(%08x, %08x): bad mpeg handle", mpeg, streamUid); return -1; } - ERROR_LOG_REPORT(ME, "UNIMPL sceMpegNextAvcRpAu(%08x, %08x)", mpeg, streamUid); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMpegNextAvcRpAu(%08x, %08x)", mpeg, streamUid); return 0; } @@ -2271,11 +2272,11 @@ static u32 sceMpegGetAvcNalAu(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegGetAvcNalAu(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegGetAvcNalAu(%08x): bad mpeg handle", mpeg); return -1; } - ERROR_LOG_REPORT(ME, "UNIMPL sceMpegGetAvcNalAu(%08x)", mpeg); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMpegGetAvcNalAu(%08x)", mpeg); return 0; } @@ -2284,11 +2285,11 @@ static u32 sceMpegAvcDecodeDetailIndex(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegAvcDecodeDetailIndex(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegAvcDecodeDetailIndex(%08x): bad mpeg handle", mpeg); return -1; } - ERROR_LOG_REPORT(ME, "UNIMPL sceMpegAvcDecodeDetailIndex(%08x)", mpeg); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMpegAvcDecodeDetailIndex(%08x)", mpeg); return 0; } @@ -2297,11 +2298,11 @@ static u32 sceMpegAvcDecodeDetail2(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegAvcDecodeDetail2(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegAvcDecodeDetail2(%08x): bad mpeg handle", mpeg); return -1; } - ERROR_LOG_REPORT(ME, "UNIMPL sceMpegAvcDecodeDetail2(%08x)", mpeg); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMpegAvcDecodeDetail2(%08x)", mpeg); return 0; } @@ -2310,11 +2311,11 @@ static u32 sceMpegGetAvcEsAu(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegGetAvcEsAu(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegGetAvcEsAu(%08x): bad mpeg handle", mpeg); return -1; } - ERROR_LOG_REPORT(ME, "UNIMPL sceMpegGetAvcEsAu(%08x)", mpeg); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMpegGetAvcEsAu(%08x)", mpeg); return 0; } @@ -2323,11 +2324,11 @@ static u32 sceMpegAvcCscInfo(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegAvcCscInfo(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegAvcCscInfo(%08x): bad mpeg handle", mpeg); return -1; } - ERROR_LOG_REPORT(ME, "UNIMPL sceMpegAvcCscInfo(%08x)", mpeg); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMpegAvcCscInfo(%08x)", mpeg); return 0; } @@ -2336,11 +2337,11 @@ static u32 sceMpegAvcCscMode(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegAvcCscMode(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegAvcCscMode(%08x): bad mpeg handle", mpeg); return -1; } - ERROR_LOG_REPORT(ME, "UNIMPL sceMpegAvcCscMode(%08x)", mpeg); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMpegAvcCscMode(%08x)", mpeg); return 0; } @@ -2349,11 +2350,11 @@ static u32 sceMpegFlushAu(u32 mpeg) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { - WARN_LOG(ME, "UNIMPL sceMpegFlushAu(%08x): bad mpeg handle", mpeg); + WARN_LOG(Log::ME, "UNIMPL sceMpegFlushAu(%08x): bad mpeg handle", mpeg); return -1; } - ERROR_LOG_REPORT(ME, "UNIMPL sceMpegFlushAu(%08x)", mpeg); + ERROR_LOG_REPORT(Log::ME, "UNIMPL sceMpegFlushAu(%08x)", mpeg); return 0; } @@ -2443,7 +2444,7 @@ static u32 sceMpegBasePESpacketCopy(u32 p) ++lli; } - DEBUG_LOG(ME, "sceMpegBasePESpacketCopy(%08x), received %d block(s)", pmp_videoSource, pmp_nBlocks); + DEBUG_LOG(Log::ME, "sceMpegBasePESpacketCopy(%08x), received %d block(s)", pmp_videoSource, pmp_nBlocks); return 0; } diff --git a/Core/HLE/sceMt19937.cpp b/Core/HLE/sceMt19937.cpp index 64adebcf81..e29996fc37 100644 --- a/Core/HLE/sceMt19937.cpp +++ b/Core/HLE/sceMt19937.cpp @@ -15,12 +15,14 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include // for some reason required for the 'new'. + #include "Common/Data/Random/Rng.h" +#include "Common/CommonTypes.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceMt19937.h" #include "Core/MemMap.h" -#include "Core/Reporting.h" #ifdef USE_CRT_DBG #undef new @@ -30,20 +32,20 @@ static u32 sceMt19937Init(u32 mt19937Addr, u32 seed) { if (!Memory::IsValidAddress(mt19937Addr)) - return hleLogError(HLE, -1); + return hleLogError(Log::HLE, -1); void *ptr = Memory::GetPointerWriteUnchecked(mt19937Addr); // This is made to match the memory layout of a PSP MT structure exactly. // Let's just construct it in place with placement new. Elite C++ hackery FTW. new (ptr) MersenneTwister(seed); - return hleLogSuccessInfoI(HLE, 0); + return hleLogSuccessInfoI(Log::HLE, 0); } static u32 sceMt19937UInt(u32 mt19937Addr) { if (!Memory::IsValidAddress(mt19937Addr)) - return hleLogError(HLE, -1); + return hleLogError(Log::HLE, -1); MersenneTwister *mt = (MersenneTwister *)Memory::GetPointer(mt19937Addr); - return hleLogSuccessVerboseX(HLE, mt->R32()); + return hleLogSuccessVerboseX(Log::HLE, mt->R32()); } const HLEFunction sceMt19937[] = diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 2e256fffbb..be5c8d795f 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -22,7 +22,6 @@ #include #endif -#include "Common/Net/Resolve.h" #include "Common/Data/Text/Parsers.h" #include "Common/Serialize/Serializer.h" @@ -34,18 +33,18 @@ #include "Core/MIPS/MIPS.h" #include "Core/Config.h" #include "Core/MemMapHelpers.h" +#include "Core/Reporting.h" #include "Core/Util/PortManager.h" #include "sceKernel.h" #include "sceKernelThread.h" -#include "sceKernelMutex.h" #include "sceUtility.h" #include "Core/HLE/proAdhoc.h" #include "Core/HLE/sceNetAdhoc.h" #include "Core/HLE/sceNet.h" #include "Core/HLE/sceNp.h" -#include "Core/Reporting.h" +#include "Core/CoreTiming.h" #include "Core/Instance.h" #if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) @@ -106,7 +105,7 @@ void AfterApctlMipsCall::DoState(PointerWrap & p) { void AfterApctlMipsCall::run(MipsCall& call) { u32 v0 = currentMIPS->r[MIPS_REG_V0]; - DEBUG_LOG(SCENET, "AfterApctlMipsCall::run [ID=%i][OldState=%d][NewState=%d][Event=%d][Error=%d][ArgsPtr=%08x] [cbId: %u][retV0: %08x]", handlerID, oldState, newState, event, error, argsAddr, call.cbId, v0); + DEBUG_LOG(Log::sceNet, "AfterApctlMipsCall::run [ID=%i][OldState=%d][NewState=%d][Event=%d][Error=%d][ArgsPtr=%08x] [cbId: %u][retV0: %08x]", handlerID, oldState, newState, event, error, argsAddr, call.cbId, v0); //call.setReturnValue(v0); } @@ -141,7 +140,7 @@ static void __ApctlState(u64 userdata, int cyclesLate) { SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error); if (waitID == 0 || error != 0) { - WARN_LOG(SCENET, "sceNetApctl State WaitID(%i) on Thread(%i) already woken up? (error: %08x)", uid, threadID, error); + WARN_LOG(Log::sceNet, "sceNetApctl State WaitID(%i) on Thread(%i) already woken up? (error: %08x)", uid, threadID, error); return; } @@ -151,7 +150,7 @@ static void __ApctlState(u64 userdata, int cyclesLate) { } __KernelResumeThreadFromWait(threadID, result); - DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %08x) Result (%08x) of sceNetApctl - Event: %d, State: %d", waitID, error, (int)result, event, netApctlState); + DEBUG_LOG(Log::sceNet, "Returning (WaitID: %d, error: %08x) Result (%08x) of sceNetApctl - Event: %d, State: %d", waitID, error, (int)result, event, netApctlState); } // Used to change Apctl State after a delay and before executing callback mipscall (since we don't have beforeAction) @@ -210,7 +209,7 @@ void __NetInit() { SceNetEtherAddr mac; getLocalMac(&mac); - INFO_LOG(SCENET, "LocalHost IP will be %s [%s]", ip2str(g_localhostIP.in.sin_addr).c_str(), mac2str(&mac).c_str()); + INFO_LOG(Log::sceNet, "LocalHost IP will be %s [%s]", ip2str(g_localhostIP.in.sin_addr).c_str(), mac2str(&mac).c_str()); // TODO: May be we should initialize & cleanup somewhere else than here for PortManager to be used as general purpose for whatever port forwarding PPSSPP needed __UPnPInit(); @@ -440,7 +439,7 @@ void __NetApctlCallbacks() int handlerID = id - 1; for (std::map::iterator it = npAuthHandlers.begin(); it != npAuthHandlers.end(); ++it) { if (it->first == handlerID) { - DEBUG_LOG(SCENET, "NpAuthCallback [HandlerID=%i][RequestID=%d][Result=%d][ArgsPtr=%08x]", it->first, id, result, it->second.argument); + DEBUG_LOG(Log::sceNet, "NpAuthCallback [HandlerID=%i][RequestID=%d][Result=%d][ArgsPtr=%08x]", it->first, id, result, it->second.argument); // TODO: Update result / args.data[1] with the actual ticket length (or error code?) hleEnqueueCall(it->second.entryPoint, 3, args.data); } @@ -537,7 +536,7 @@ void __NetApctlCallbacks() // Run mipscall. Should we skipped executing the mipscall if oldState == newState? for (std::map::iterator it = apctlHandlers.begin(); it != apctlHandlers.end(); ++it) { - DEBUG_LOG(SCENET, "ApctlCallback [ID=%i][OldState=%d][NewState=%d][Event=%d][Error=%08x][ArgsPtr=%08x]", it->first, oldState, newState, event, error, it->second.argument); + DEBUG_LOG(Log::sceNet, "ApctlCallback [ID=%i][OldState=%d][NewState=%d][Event=%d][Error=%08x][ArgsPtr=%08x]", it->first, oldState, newState, event, error, it->second.argument); args.data[4] = it->second.argument; AfterApctlMipsCall* after = (AfterApctlMipsCall*)__KernelCreateAction(actionAfterApctlMipsCall); after->SetData(it->first, oldState, newState, event, error, it->second.argument); @@ -599,7 +598,7 @@ u32 Net_Term() { } static u32 sceNetTerm() { - WARN_LOG(SCENET, "sceNetTerm() at %08x", currentMIPS->pc); + WARN_LOG(Log::sceNet, "sceNetTerm() at %08x", currentMIPS->pc); int retval = Net_Term(); // Give time to make sure everything are cleaned up @@ -623,11 +622,11 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini Net_Term(); // This cleanup attempt might not worked when SaveState were loaded in the middle of multiplayer game and re-entering multiplayer, thus causing memory leaks & wasting binded ports. May be we shouldn't save/load "Inited" vars on SaveState? if (poolSize == 0) { - return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid pool size"); + return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid pool size"); } else if (calloutPri < 0x08 || calloutPri > 0x77) { - return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "invalid callout thread priority"); + return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "invalid callout thread priority"); } else if (netinitPri < 0x08 || netinitPri > 0x77) { - return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "invalid init thread priority"); + return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "invalid init thread priority"); } // TODO: Should also start the threads, probably? For now, let's just allocate. @@ -635,22 +634,22 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini u32 stackSize = 4096; netThread1Addr = AllocUser(stackSize, true, "netstack1"); if (netThread1Addr == 0) { - return hleLogError(SCENET, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate thread"); + return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate thread"); } netThread2Addr = AllocUser(stackSize, true, "netstack2"); if (netThread2Addr == 0) { FreeUser(netThread1Addr); - return hleLogError(SCENET, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate thread"); + return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate thread"); } netPoolAddr = AllocUser(poolSize, false, "netpool"); if (netPoolAddr == 0) { FreeUser(netThread1Addr); FreeUser(netThread2Addr); - return hleLogError(SCENET, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate pool"); + return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate pool"); } - WARN_LOG(SCENET, "sceNetInit(poolsize=%d, calloutpri=%i, calloutstack=%d, netintrpri=%i, netintrstack=%d) at %08x", poolSize, calloutPri, calloutStack, netinitPri, netinitStack, currentMIPS->pc); + WARN_LOG(Log::sceNet, "sceNetInit(poolsize=%d, calloutpri=%i, calloutstack=%d, netintrpri=%i, netintrstack=%d) at %08x", poolSize, calloutPri, calloutStack, netinitPri, netinitStack, currentMIPS->pc); netMallocStat.pool = poolSize - 0x20; // On Vantage Master Portable this is slightly (32 bytes) smaller than the poolSize arg when tested with JPCSP + prx files netMallocStat.maximum = 0x4050; // Dummy maximum foot print @@ -660,20 +659,20 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini memset(&adhocSockets, 0, sizeof(adhocSockets)); netInited = true; - return hleLogSuccessI(SCENET, 0); + return hleLogSuccessI(Log::sceNet, 0); } // Free(delete) thread info / data. // Normal usage: sceKernelDeleteThread followed by sceNetFreeThreadInfo with the same threadID as argument static int sceNetFreeThreadinfo(SceUID thid) { - ERROR_LOG(SCENET, "UNIMPL sceNetFreeThreadinfo(%i)", thid); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetFreeThreadinfo(%i)", thid); return 0; } // Abort a thread. static int sceNetThreadAbort(SceUID thid) { - ERROR_LOG(SCENET, "UNIMPL sceNetThreadAbort(%i)", thid); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetThreadAbort(%i)", thid); return 0; } @@ -681,7 +680,7 @@ static int sceNetThreadAbort(SceUID thid) { static u32 sceWlanGetEtherAddr(u32 addrAddr) { if (!Memory::IsValidRange(addrAddr, 6)) { // More correctly, it should crash. - return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "illegal address"); + return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "illegal address"); } u8 *addr = Memory::GetPointerWriteUnchecked(addrAddr); @@ -692,34 +691,34 @@ static u32 sceWlanGetEtherAddr(u32 addrAddr) { } else { // Read MAC Address from config if (!ParseMacAddress(g_Config.sMACAddress, addr)) { - ERROR_LOG(SCENET, "Error parsing mac address %s", g_Config.sMACAddress.c_str()); + ERROR_LOG(Log::sceNet, "Error parsing mac address %s", g_Config.sMACAddress.c_str()); Memory::Memset(addrAddr, 0, 6); } } NotifyMemInfo(MemBlockFlags::WRITE, addrAddr, 6, "WlanEtherAddr"); - return hleLogSuccessI(SCENET, hleDelayResult(0, "get ether mac", 200)); + return hleLogSuccessI(Log::sceNet, hleDelayResult(0, "get ether mac", 200)); } static u32 sceNetGetLocalEtherAddr(u32 addrAddr) { // FIXME: Return 0x80410180 (pspnet[_core] error code?) before successful attempt to Create/Connect/Join a Group? (ie. adhocctlCurrentMode == ADHOCCTL_MODE_NONE) if (adhocctlCurrentMode == ADHOCCTL_MODE_NONE) - return hleLogDebug(SCENET, 0x80410180, "address not available?"); + return hleLogDebug(Log::sceNet, 0x80410180, "address not available?"); return sceWlanGetEtherAddr(addrAddr); } static u32 sceWlanDevIsPowerOn() { - return hleLogSuccessVerboseI(SCENET, g_Config.bEnableWlan ? 1 : 0); + return hleLogSuccessVerboseI(Log::sceNet, g_Config.bEnableWlan ? 1 : 0); } static u32 sceWlanGetSwitchState() { - return hleLogSuccessVerboseI(SCENET, g_Config.bEnableWlan ? 1 : 0); + return hleLogSuccessVerboseI(Log::sceNet, g_Config.bEnableWlan ? 1 : 0); } // Probably a void function, but often returns a useful value. static void sceNetEtherNtostr(u32 macPtr, u32 bufferPtr) { - DEBUG_LOG(SCENET, "sceNetEtherNtostr(%08x, %08x) at %08x", macPtr, bufferPtr, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "sceNetEtherNtostr(%08x, %08x) at %08x", macPtr, bufferPtr, currentMIPS->pc); if (Memory::IsValidAddress(bufferPtr) && Memory::IsValidAddress(macPtr)) { char *buffer = (char *)Memory::GetPointerWriteUnchecked(bufferPtr); @@ -729,7 +728,7 @@ static void sceNetEtherNtostr(u32 macPtr, u32 bufferPtr) { sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - VERBOSE_LOG(SCENET, "sceNetEtherNtostr - [%s]", buffer); + VERBOSE_LOG(Log::sceNet, "sceNetEtherNtostr - [%s]", buffer); } } @@ -745,7 +744,7 @@ static int hex_to_digit(int c) { // Probably a void function, but sometimes returns a useful-ish value. static void sceNetEtherStrton(u32 bufferPtr, u32 macPtr) { - DEBUG_LOG(SCENET, "sceNetEtherStrton(%08x, %08x)", bufferPtr, macPtr); + DEBUG_LOG(Log::sceNet, "sceNetEtherStrton(%08x, %08x)", bufferPtr, macPtr); if (Memory::IsValidAddress(bufferPtr) && Memory::IsValidAddress(macPtr)) { const char *buffer = (const char *)Memory::GetPointerUnchecked(bufferPtr); @@ -775,7 +774,7 @@ static void sceNetEtherStrton(u32 bufferPtr, u32 macPtr) { } } - VERBOSE_LOG(SCENET, "sceNetEtherStrton - [%s]", mac2str((SceNetEtherAddr*)Memory::GetPointer(macPtr)).c_str()); + VERBOSE_LOG(Log::sceNet, "sceNetEtherStrton - [%s]", mac2str((SceNetEtherAddr*)Memory::GetPointer(macPtr)).c_str()); // Seems to maybe kinda return the last value. Probably returns void. //return value; } @@ -784,10 +783,10 @@ static void sceNetEtherStrton(u32 bufferPtr, u32 macPtr) { // Write static data since we don't actually manage any memory for sceNet* yet. static int sceNetGetMallocStat(u32 statPtr) { - VERBOSE_LOG(SCENET, "UNTESTED sceNetGetMallocStat(%x) at %08x", statPtr, currentMIPS->pc); + VERBOSE_LOG(Log::sceNet, "UNTESTED sceNetGetMallocStat(%x) at %08x", statPtr, currentMIPS->pc); auto stat = PSPPointer::Create(statPtr); if (!stat.IsValid()) - return hleLogError(SCENET, 0, "invalid address"); + return hleLogError(Log::sceNet, 0, "invalid address"); *stat = netMallocStat; stat.NotifyWrite("sceNetGetMallocStat"); @@ -795,7 +794,7 @@ static int sceNetGetMallocStat(u32 statPtr) { } static int sceNetInetInit() { - ERROR_LOG(SCENET, "UNIMPL sceNetInetInit()"); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetInit()"); if (netInetInited) return ERROR_NET_INET_ALREADY_INITIALIZED; netInetInited = true; @@ -803,7 +802,7 @@ static int sceNetInetInit() { } int sceNetInetTerm() { - ERROR_LOG(SCENET, "UNIMPL sceNetInetTerm()"); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetTerm()"); netInetInited = false; return 0; @@ -836,7 +835,7 @@ void NetApctl_InitInfo() { } static int sceNetApctlInit(int stackSize, int initPriority) { - WARN_LOG(SCENET, "UNTESTED %s(%i, %i)", __FUNCTION__, stackSize, initPriority); + WARN_LOG(Log::sceNet, "UNTESTED %s(%i, %i)", __FUNCTION__, stackSize, initPriority); if (netApctlInited) return ERROR_NET_APCTL_ALREADY_INITIALIZED; @@ -884,144 +883,144 @@ int NetApctl_Term() { } int sceNetApctlTerm() { - WARN_LOG(SCENET, "UNTESTED %s()", __FUNCTION__); + WARN_LOG(Log::sceNet, "UNTESTED %s()", __FUNCTION__); return NetApctl_Term(); } static int sceNetApctlGetInfo(int code, u32 pInfoAddr) { - WARN_LOG(SCENET, "UNTESTED %s(%i, %08x)", __FUNCTION__, code, pInfoAddr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%i, %08x)", __FUNCTION__, code, pInfoAddr); if (!netApctlInited) - return hleLogError(SCENET, ERROR_NET_APCTL_NOT_IN_BSS, "apctl not in bss"); // Only have valid info after joining an AP and got an IP, right? + return hleLogError(Log::sceNet, ERROR_NET_APCTL_NOT_IN_BSS, "apctl not in bss"); // Only have valid info after joining an AP and got an IP, right? switch (code) { case PSP_NET_APCTL_INFO_PROFILE_NAME: if (!Memory::IsValidRange(pInfoAddr, APCTL_PROFILENAME_MAXLEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.name, APCTL_PROFILENAME_MAXLEN); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, APCTL_PROFILENAME_MAXLEN, "NetApctlGetInfo"); - DEBUG_LOG(SCENET, "ApctlInfo - ProfileName: %s", netApctlInfo.name); + DEBUG_LOG(Log::sceNet, "ApctlInfo - ProfileName: %s", netApctlInfo.name); break; case PSP_NET_APCTL_INFO_BSSID: if (!Memory::IsValidRange(pInfoAddr, ETHER_ADDR_LEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.bssid, ETHER_ADDR_LEN); - DEBUG_LOG(SCENET, "ApctlInfo - BSSID: %s", mac2str((SceNetEtherAddr*)&netApctlInfo.bssid).c_str()); + DEBUG_LOG(Log::sceNet, "ApctlInfo - BSSID: %s", mac2str((SceNetEtherAddr*)&netApctlInfo.bssid).c_str()); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, ETHER_ADDR_LEN, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_SSID: if (!Memory::IsValidRange(pInfoAddr, APCTL_SSID_MAXLEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.ssid, APCTL_SSID_MAXLEN); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, APCTL_SSID_MAXLEN, "NetApctlGetInfo"); - DEBUG_LOG(SCENET, "ApctlInfo - SSID: %s", netApctlInfo.ssid); + DEBUG_LOG(Log::sceNet, "ApctlInfo - SSID: %s", netApctlInfo.ssid); break; case PSP_NET_APCTL_INFO_SSID_LENGTH: if (!Memory::IsValidRange(pInfoAddr, 4)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U32(netApctlInfo.ssidLength, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 4, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_SECURITY_TYPE: if (!Memory::IsValidRange(pInfoAddr, 4)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U32(netApctlInfo.securityType, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 4, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_STRENGTH: if (!Memory::IsValidRange(pInfoAddr, 1)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U8(netApctlInfo.strength, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 1, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_CHANNEL: if (!Memory::IsValidRange(pInfoAddr, 1)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U8(netApctlInfo.channel, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 1, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_POWER_SAVE: if (!Memory::IsValidRange(pInfoAddr, 1)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U8(netApctlInfo.powerSave, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 1, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_IP: if (!Memory::IsValidRange(pInfoAddr, APCTL_IPADDR_MAXLEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.ip, APCTL_IPADDR_MAXLEN); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, APCTL_IPADDR_MAXLEN, "NetApctlGetInfo"); - DEBUG_LOG(SCENET, "ApctlInfo - IP: %s", netApctlInfo.ip); + DEBUG_LOG(Log::sceNet, "ApctlInfo - IP: %s", netApctlInfo.ip); break; case PSP_NET_APCTL_INFO_SUBNETMASK: if (!Memory::IsValidRange(pInfoAddr, APCTL_IPADDR_MAXLEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.subNetMask, APCTL_IPADDR_MAXLEN); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, APCTL_IPADDR_MAXLEN, "NetApctlGetInfo"); - DEBUG_LOG(SCENET, "ApctlInfo - SubNet Mask: %s", netApctlInfo.subNetMask); + DEBUG_LOG(Log::sceNet, "ApctlInfo - SubNet Mask: %s", netApctlInfo.subNetMask); break; case PSP_NET_APCTL_INFO_GATEWAY: if (!Memory::IsValidRange(pInfoAddr, APCTL_IPADDR_MAXLEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.gateway, APCTL_IPADDR_MAXLEN); - DEBUG_LOG(SCENET, "ApctlInfo - Gateway IP: %s", netApctlInfo.gateway); + DEBUG_LOG(Log::sceNet, "ApctlInfo - Gateway IP: %s", netApctlInfo.gateway); break; case PSP_NET_APCTL_INFO_PRIMDNS: if (!Memory::IsValidRange(pInfoAddr, APCTL_IPADDR_MAXLEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.primaryDns, APCTL_IPADDR_MAXLEN); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, APCTL_IPADDR_MAXLEN, "NetApctlGetInfo"); - DEBUG_LOG(SCENET, "ApctlInfo - Primary DNS: %s", netApctlInfo.primaryDns); + DEBUG_LOG(Log::sceNet, "ApctlInfo - Primary DNS: %s", netApctlInfo.primaryDns); break; case PSP_NET_APCTL_INFO_SECDNS: if (!Memory::IsValidRange(pInfoAddr, APCTL_IPADDR_MAXLEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.secondaryDns, APCTL_IPADDR_MAXLEN); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, APCTL_IPADDR_MAXLEN, "NetApctlGetInfo"); - DEBUG_LOG(SCENET, "ApctlInfo - Secondary DNS: %s", netApctlInfo.secondaryDns); + DEBUG_LOG(Log::sceNet, "ApctlInfo - Secondary DNS: %s", netApctlInfo.secondaryDns); break; case PSP_NET_APCTL_INFO_USE_PROXY: if (!Memory::IsValidRange(pInfoAddr, 4)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U32(netApctlInfo.useProxy, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 4, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_PROXY_URL: if (!Memory::IsValidRange(pInfoAddr, APCTL_URL_MAXLEN)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::MemcpyUnchecked(pInfoAddr, netApctlInfo.proxyUrl, APCTL_URL_MAXLEN); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, APCTL_URL_MAXLEN, "NetApctlGetInfo"); - DEBUG_LOG(SCENET, "ApctlInfo - Proxy URL: %s", netApctlInfo.proxyUrl); + DEBUG_LOG(Log::sceNet, "ApctlInfo - Proxy URL: %s", netApctlInfo.proxyUrl); break; case PSP_NET_APCTL_INFO_PROXY_PORT: if (!Memory::IsValidRange(pInfoAddr, 2)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U16(netApctlInfo.proxyPort, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 2, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_8021_EAP_TYPE: if (!Memory::IsValidRange(pInfoAddr, 4)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U32(netApctlInfo.eapType, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 4, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_START_BROWSER: if (!Memory::IsValidRange(pInfoAddr, 4)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U32(netApctlInfo.startBrowser, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 4, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_WIFISP: if (!Memory::IsValidRange(pInfoAddr, 4)) - return hleLogError(SCENET, -1, "apctl invalid arg"); + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U32(netApctlInfo.wifisp, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 4, "NetApctlGetInfo"); break; default: - return hleLogError(SCENET, ERROR_NET_APCTL_INVALID_CODE, "apctl invalid code"); + return hleLogError(Log::sceNet, ERROR_NET_APCTL_INVALID_CODE, "apctl invalid code"); } - return hleLogSuccessI(SCENET, 0); + return hleLogSuccessI(Log::sceNet, 0); } int NetApctl_AddHandler(u32 handlerPtr, u32 handlerArg) { @@ -1045,15 +1044,15 @@ int NetApctl_AddHandler(u32 handlerPtr, u32 handlerArg) { if (!foundHandler && Memory::IsValidAddress(handlerPtr)) { if (apctlHandlers.size() >= MAX_APCTL_HANDLERS) { - ERROR_LOG(SCENET, "Failed to Add handler(%x, %x): Too many handlers", handlerPtr, handlerArg); + ERROR_LOG(Log::sceNet, "Failed to Add handler(%x, %x): Too many handlers", handlerPtr, handlerArg); retval = ERROR_NET_ADHOCCTL_TOO_MANY_HANDLERS; // TODO: What's the proper error code for Apctl's TOO_MANY_HANDLERS? return retval; } apctlHandlers[retval] = handler; - WARN_LOG(SCENET, "Added Apctl handler(%x, %x): %d", handlerPtr, handlerArg, retval); + WARN_LOG(Log::sceNet, "Added Apctl handler(%x, %x): %d", handlerPtr, handlerArg, retval); } else { - ERROR_LOG(SCENET, "Existing Apctl handler(%x, %x)", handlerPtr, handlerArg); + ERROR_LOG(Log::sceNet, "Existing Apctl handler(%x, %x)", handlerPtr, handlerArg); } // The id to return is the number of handlers currently registered @@ -1063,33 +1062,33 @@ int NetApctl_AddHandler(u32 handlerPtr, u32 handlerArg) { // TODO: How many handlers can the PSP actually have for Apctl? // TODO: Should we allow the same handler to be added more than once? static u32 sceNetApctlAddHandler(u32 handlerPtr, u32 handlerArg) { - INFO_LOG(SCENET, "%s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); + INFO_LOG(Log::sceNet, "%s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); return NetApctl_AddHandler(handlerPtr, handlerArg); } int NetApctl_DelHandler(u32 handlerID) { if (apctlHandlers.find(handlerID) != apctlHandlers.end()) { apctlHandlers.erase(handlerID); - WARN_LOG(SCENET, "Deleted Apctl handler: %d", handlerID); + WARN_LOG(Log::sceNet, "Deleted Apctl handler: %d", handlerID); } else { - ERROR_LOG(SCENET, "Invalid Apctl handler: %d", handlerID); + ERROR_LOG(Log::sceNet, "Invalid Apctl handler: %d", handlerID); } return 0; } static int sceNetApctlDelHandler(u32 handlerID) { - INFO_LOG(SCENET, "%s(%d)", __FUNCTION__, handlerID); + INFO_LOG(Log::sceNet, "%s(%d)", __FUNCTION__, handlerID); return NetApctl_DelHandler(handlerID); } static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { - ERROR_LOG(SCENET, "UNIMPL sceNetInetInetAton(%s, %08x)", hostname, addrPtr); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetInetAton(%s, %08x)", hostname, addrPtr); return -1; } int sceNetInetPoll(void *fds, u32 nfds, int timeout) { // timeout in miliseconds - DEBUG_LOG(SCENET, "UNTESTED sceNetInetPoll(%p, %d, %i) at %08x", fds, nfds, timeout, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNTESTED sceNetInetPoll(%p, %d, %i) at %08x", fds, nfds, timeout, currentMIPS->pc); int retval = -1; SceNetInetPollfd *fdarray = (SceNetInetPollfd *)fds; // SceNetInetPollfd/pollfd, sceNetInetPoll() have similarity to BSD poll() but pollfd have different size on 64bit //#ifdef _WIN32 @@ -1144,17 +1143,17 @@ int sceNetInetPoll(void *fds, u32 nfds, int timeout) { // timeout in miliseconds } static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, u32 flags) { - ERROR_LOG(SCENET, "UNIMPL sceNetInetRecv(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetRecv(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); return -1; } static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, u32 flags) { - ERROR_LOG(SCENET, "UNIMPL sceNetInetSend(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetSend(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); return -1; } static int sceNetInetGetErrno() { - ERROR_LOG(SCENET, "UNTESTED sceNetInetGetErrno()"); + ERROR_LOG(Log::sceNet, "UNTESTED sceNetInetGetErrno()"); int error = errno; switch (error) { case ETIMEDOUT: @@ -1170,22 +1169,22 @@ static int sceNetInetGetErrno() { } static int sceNetInetSocket(int domain, int type, int protocol) { - ERROR_LOG(SCENET, "UNIMPL sceNetInetSocket(%i, %i, %i)", domain, type, protocol); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetSocket(%i, %i, %i)", domain, type, protocol); return -1; } static int sceNetInetSetsockopt(int socket, int level, int optname, u32 optvalPtr, int optlen) { - ERROR_LOG(SCENET, "UNIMPL sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, level, optname, optvalPtr, optlen); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, level, optname, optvalPtr, optlen); return -1; } static int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLength) { - ERROR_LOG(SCENET, "UNIMPL sceNetInetConnect(%i, %08x, %i)", socket, sockAddrInternetPtr, addressLength); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetConnect(%i, %08x, %i)", socket, sockAddrInternetPtr, addressLength); return -1; } int sceNetApctlConnect(int connIndex) { - WARN_LOG(SCENET, "UNTESTED %s(%i)", __FUNCTION__, connIndex); + WARN_LOG(Log::sceNet, "UNTESTED %s(%i)", __FUNCTION__, connIndex); // Is this connIndex is the index to the scanning's result data or sceNetApctlGetBSSDescIDListUser result? __UpdateApctlHandlers(0, 0, PSP_NET_APCTL_EVENT_CONNECT_REQUEST, 0); //hleDelayResult(0, "give time to init/cleanup", adhocEventDelayMS * 1000); @@ -1193,7 +1192,7 @@ int sceNetApctlConnect(int connIndex) { } static int sceNetApctlDisconnect() { - ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); // Like its 'sister' function sceNetAdhocctlDisconnect, we need to alert Apctl handlers that a disconnect took place // or else games like Phantasy Star Portable 2 will hang at certain points (e.g. returning to the main menu after trying to connect to PSN). @@ -1206,30 +1205,30 @@ int NetApctl_GetState() { } static int sceNetApctlGetState(u32 pStateAddr) { - //if (!netApctlInited) return hleLogError(SCENET, ERROR_NET_APCTL_NOT_IN_BSS, "apctl not in bss"); + //if (!netApctlInited) return hleLogError(Log::sceNet, ERROR_NET_APCTL_NOT_IN_BSS, "apctl not in bss"); // Valid Arguments if (Memory::IsValidAddress(pStateAddr)) { // Return Thread Status Memory::Write_U32(NetApctl_GetState(), pStateAddr); // Return Success - return hleLogSuccessI(SCENET, 0); + return hleLogSuccessI(Log::sceNet, 0); } - return hleLogError(SCENET, -1, "apctl invalid arg"); // 0x8002013A or ERROR_NET_WLAN_INVALID_ARG ? + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); // 0x8002013A or ERROR_NET_WLAN_INVALID_ARG ? } int NetApctl_ScanUser() { // Scan probably only works when not in connected state, right? if (netApctlState != PSP_NET_APCTL_STATE_DISCONNECTED) - return hleLogError(SCENET, ERROR_NET_APCTL_NOT_DISCONNECTED, "apctl not disconnected"); + return hleLogError(Log::sceNet, ERROR_NET_APCTL_NOT_DISCONNECTED, "apctl not disconnected"); __UpdateApctlHandlers(0, 0, PSP_NET_APCTL_EVENT_SCAN_REQUEST, 0); return 0; } static int sceNetApctlScanUser() { - ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); return NetApctl_ScanUser(); } @@ -1238,7 +1237,7 @@ int NetApctl_GetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) { // Faking 4 entries, games like MGS:PW Recruit will need to have a different AP for each entry int entries = 4; if (!Memory::IsValidAddress(sizeAddr) || !Memory::IsValidAddress(bufAddr)) - return hleLogError(SCENET, -1, "apctl invalid arg"); // 0x8002013A or ERROR_NET_WLAN_INVALID_ARG ? + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); // 0x8002013A or ERROR_NET_WLAN_INVALID_ARG ? int size = Memory::Read_U32(sizeAddr); // Return size required @@ -1252,7 +1251,7 @@ int NetApctl_GetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) { break; } - DEBUG_LOG(SCENET, "%s writing ID#%d to %08x", __FUNCTION__, i, bufAddr + offset); + DEBUG_LOG(Log::sceNet, "%s writing ID#%d to %08x", __FUNCTION__, i, bufAddr + offset); // Pointer to next Network structure in list Memory::Write_U32((i + 1) * userInfoSize + bufAddr, bufAddr + offset); @@ -1271,13 +1270,13 @@ int NetApctl_GetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) { } static int sceNetApctlGetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x, %08x)", __FUNCTION__, sizeAddr, bufAddr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x, %08x)", __FUNCTION__, sizeAddr, bufAddr); return NetApctl_GetBSSDescIDListUser(sizeAddr, bufAddr); } int NetApctl_GetBSSDescEntryUser(int entryId, int infoId, u32 resultAddr) { if (!Memory::IsValidAddress(resultAddr)) - return hleLogError(SCENET, -1, "apctl invalid arg"); // 0x8002013A or ERROR_NET_WLAN_INVALID_ARG ? + return hleLogError(Log::sceNet, -1, "apctl invalid arg"); // 0x8002013A or ERROR_NET_WLAN_INVALID_ARG ? // Generate an SSID name char dummySSID[APCTL_SSID_MAXLEN] = "WifiAP0"; @@ -1336,19 +1335,19 @@ int NetApctl_GetBSSDescEntryUser(int entryId, int infoId, u32 resultAddr) { Memory::Write_U32(netApctlInfo.securityType, resultAddr); break; default: - return hleLogError(SCENET, ERROR_NET_APCTL_INVALID_CODE, "unknown info id"); + return hleLogError(Log::sceNet, ERROR_NET_APCTL_INVALID_CODE, "unknown info id"); } return 0; } static int sceNetApctlGetBSSDescEntryUser(int entryId, int infoId, u32 resultAddr) { - WARN_LOG(SCENET, "UNTESTED %s(%i, %i, %08x)", __FUNCTION__, entryId, infoId, resultAddr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%i, %i, %08x)", __FUNCTION__, entryId, infoId, resultAddr); return NetApctl_GetBSSDescEntryUser(entryId, infoId, resultAddr); } static int sceNetApctlScanSSID2() { - WARN_LOG(SCENET, "UNTESTED %s() at %08x", __FUNCTION__, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED %s() at %08x", __FUNCTION__, currentMIPS->pc); return NetApctl_ScanUser(); } @@ -1359,7 +1358,7 @@ static int sceNetApctlScanSSID2() { * Arg4 = input flag? (initially 0/1 ?) ***************/ static int sceNetApctlGetBSSDescIDList2(u32 Arg1, u32 Arg2, u32 Arg3, u32 Arg4) { - WARN_LOG(SCENET, "UNTESTED %s(%08x, %08x, %08x, %08x) at %08x", __FUNCTION__, Arg1, Arg2, Arg3, Arg4, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x, %08x, %08x, %08x) at %08x", __FUNCTION__, Arg1, Arg2, Arg3, Arg4, currentMIPS->pc); return NetApctl_GetBSSDescIDListUser(Arg1, Arg2); } @@ -1369,97 +1368,97 @@ static int sceNetApctlGetBSSDescIDList2(u32 Arg1, u32 Arg2, u32 Arg3, u32 Arg4) * Arg3 = output buffer for retrieved entry data? (max size = 32 bytes? ie. APCTL_SSID_MAXLEN ? or similar to SceNetApctlInfoInternal union ?) ***************/ static int sceNetApctlGetBSSDescEntry2(int entryId, int infoId, u32 resultAddr) { - WARN_LOG(SCENET, "UNTESTED %s(%i, %i, %08x) at %08x", __FUNCTION__, entryId, infoId, resultAddr, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED %s(%i, %i, %08x) at %08x", __FUNCTION__, entryId, infoId, resultAddr, currentMIPS->pc); return NetApctl_GetBSSDescEntryUser(entryId, infoId, resultAddr); } static int sceNetResolverInit() { - ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); return 0; } static int sceNetApctlAddInternalHandler(u32 handlerPtr, u32 handlerArg) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); // This seems to be a 2nd kind of handler return NetApctl_AddHandler(handlerPtr, handlerArg); } static int sceNetApctlDelInternalHandler(u32 handlerID) { - ERROR_LOG(SCENET, "UNIMPL %s(%i)", __FUNCTION__, handlerID); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%i)", __FUNCTION__, handlerID); // This seems to be a 2nd kind of handler return NetApctl_DelHandler(handlerID); } static int sceNetApctl_A7BB73DF(u32 handlerPtr, u32 handlerArg) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); // This seems to be a 3rd kind of handler return sceNetApctlAddHandler(handlerPtr, handlerArg); } static int sceNetApctl_6F5D2981(u32 handlerID) { - ERROR_LOG(SCENET, "UNIMPL %s(%i)", __FUNCTION__, handlerID); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%i)", __FUNCTION__, handlerID); // This seems to be a 3rd kind of handler return sceNetApctlDelHandler(handlerID); } static int sceNetApctl_lib2_69745F0A(int handlerId) { - return hleLogError(SCENET, 0, "unimplemented"); + return hleLogError(Log::sceNet, 0, "unimplemented"); } static int sceNetApctl_lib2_4C19731F(int code, u32 pInfoAddr) { - ERROR_LOG(SCENET, "UNIMPL %s(%i, %08x)", __FUNCTION__, code, pInfoAddr); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%i, %08x)", __FUNCTION__, code, pInfoAddr); return sceNetApctlGetInfo(code, pInfoAddr); } static int sceNetApctlScan() { - ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); return NetApctl_ScanUser(); } static int sceNetApctlGetBSSDescIDList(u32 sizeAddr, u32 bufAddr) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x, %08x)", __FUNCTION__, sizeAddr, bufAddr); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x, %08x)", __FUNCTION__, sizeAddr, bufAddr); return sceNetApctlGetBSSDescIDListUser(sizeAddr, bufAddr); } static int sceNetApctlGetBSSDescEntry(int entryId, int infoId, u32 resultAddr) { - ERROR_LOG(SCENET, "UNIMPL %s(%i, %i, %08x)", __FUNCTION__, entryId, infoId, resultAddr); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%i, %i, %08x)", __FUNCTION__, entryId, infoId, resultAddr); return sceNetApctlGetBSSDescEntryUser(entryId, infoId, resultAddr); } static int sceNetApctl_lib2_C20A144C(int connIndex, u32 ps3MacAddressPtr) { - ERROR_LOG(SCENET, "UNIMPL %s(%i, %08x)", __FUNCTION__, connIndex, ps3MacAddressPtr); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%i, %08x)", __FUNCTION__, connIndex, ps3MacAddressPtr); return sceNetApctlConnect(connIndex); } static int sceNetUpnpInit(int unknown1,int unknown2) { - ERROR_LOG_REPORT_ONCE(sceNetUpnpInit, SCENET, "UNIMPLsceNetUpnpInit %d,%d",unknown1,unknown2); + ERROR_LOG_REPORT_ONCE(sceNetUpnpInit, Log::sceNet, "UNIMPLsceNetUpnpInit %d,%d",unknown1,unknown2); return 0; } static int sceNetUpnpStart() { - ERROR_LOG(SCENET, "UNIMPLsceNetUpnpStart"); + ERROR_LOG(Log::sceNet, "UNIMPLsceNetUpnpStart"); return 0; } static int sceNetUpnpStop() { - ERROR_LOG(SCENET, "UNIMPLsceNetUpnpStop"); + ERROR_LOG(Log::sceNet, "UNIMPLsceNetUpnpStop"); return 0; } static int sceNetUpnpTerm() { - ERROR_LOG(SCENET, "UNIMPLsceNetUpnpTerm"); + ERROR_LOG(Log::sceNet, "UNIMPLsceNetUpnpTerm"); return 0; } static int sceNetUpnpGetNatInfo() { - ERROR_LOG(SCENET, "UNIMPLsceNetUpnpGetNatInfo"); + ERROR_LOG(Log::sceNet, "UNIMPLsceNetUpnpGetNatInfo"); return 0; } @@ -1467,14 +1466,14 @@ static int sceNetGetDropRate(u32 dropRateAddr, u32 dropDurationAddr) { Memory::Write_U32(netDropRate, dropRateAddr); Memory::Write_U32(netDropDuration, dropDurationAddr); - return hleLogSuccessInfoI(SCENET, 0); + return hleLogSuccessInfoI(Log::sceNet, 0); } static int sceNetSetDropRate(u32 dropRate, u32 dropDuration) { netDropRate = dropRate; netDropDuration = dropDuration; - return hleLogSuccessInfoI(SCENET, 0); + return hleLogSuccessInfoI(Log::sceNet, 0); } const HLEFunction sceNet[] = { diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 0441b6f372..9e6d45900a 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -46,6 +46,7 @@ #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/Util/PortManager.h" #include "Core/Config.h" +#include "Core/CoreTiming.h" #include "Core/Core.h" #include "Core/Reporting.h" #include "Core/MemMapHelpers.h" @@ -175,12 +176,12 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) { gameModeBuffer = buf; if ((gameModeSocket = sceNetAdhocPdpCreate((const char*)&masterGameModeArea.mac, ADHOC_GAMEMODE_PORT, gameModeBuffSize, 0)) < 0) { - ERROR_LOG(SCENET, "GameMode: Failed to create socket (Error %08x)", gameModeSocket); + ERROR_LOG(Log::sceNet, "GameMode: Failed to create socket (Error %08x)", gameModeSocket); __KernelResumeThreadFromWait(threadID, gameModeSocket); return; } else - INFO_LOG(SCENET, "GameMode: Synchronizer (%d, %d) has started", gameModeSocket, gameModeBuffSize); + INFO_LOG(Log::sceNet, "GameMode: Synchronizer (%d, %d) has started", gameModeSocket, gameModeBuffSize); } if (gameModeSocket < 0) { // ReSchedule @@ -189,7 +190,7 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) { } auto sock = adhocSockets[gameModeSocket - 1]; if (!sock) { - WARN_LOG(SCENET, "GameMode: Socket (%d) got deleted", gameModeSocket); + WARN_LOG(Log::sceNet, "GameMode: Socket (%d) got deleted", gameModeSocket); u32 waitVal = __KernelGetWaitValue(threadID, error); if (error == 0) { __KernelResumeThreadFromWait(threadID, waitVal); @@ -210,7 +211,7 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) { int sent = sceNetAdhocPdpSend(gameModeSocket, (const char*)&gma.mac, port, masterGameModeArea.data, masterGameModeArea.size, 0, ADHOC_F_NONBLOCK); if (sent != ERROR_NET_ADHOC_WOULD_BLOCK) { gma.dataSent = 1; - DEBUG_LOG(SCENET, "GameMode: Master data Sent %d bytes to Area #%d [%s]", masterGameModeArea.size, gma.id, mac2str(&gma.mac).c_str()); + DEBUG_LOG(Log::sceNet, "GameMode: Master data Sent %d bytes to Area #%d [%s]", masterGameModeArea.size, gma.id, mac2str(&gma.mac).c_str()); sentcount++; } } @@ -245,15 +246,15 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) { if (recvd == replicaGameModeAreas.size()) { u32 waitVal = __KernelGetWaitValue(threadID, error); if (error == 0) { - DEBUG_LOG(SCENET, "GameMode: Resuming Thread %d after Master data Synced (Result = %08x)", threadID, waitVal); + DEBUG_LOG(Log::sceNet, "GameMode: Resuming Thread %d after Master data Synced (Result = %08x)", threadID, waitVal); __KernelResumeThreadFromWait(threadID, waitVal); } else - ERROR_LOG(SCENET, "GameMode: Error (%08x) on WaitValue %d ThreadID %d", error, waitVal, threadID); + ERROR_LOG(Log::sceNet, "GameMode: Error (%08x) on WaitValue %d ThreadID %d", error, waitVal, threadID); } // Attempt to Re-Send initial Master data (in case previous packets were lost) else if (static_cast(now - masterGameModeArea.updateTimestamp) > GAMEMODE_SYNC_TIMEOUT) { - DEBUG_LOG(SCENET, "GameMode: Attempt to Re-Send Master data after Sync Timeout (%d us)", GAMEMODE_SYNC_TIMEOUT); + DEBUG_LOG(Log::sceNet, "GameMode: Attempt to Re-Send Master data after Sync Timeout (%d us)", GAMEMODE_SYNC_TIMEOUT); // Reset Sent marker on players who haven't replied yet (except disconnected players) for (auto& gma : replicaGameModeAreas) if (!gma.dataUpdated && gma.updateTimestamp != 0) @@ -279,7 +280,7 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) { SceNetAdhocctlPeerInfo* peer = findFriend(&sendermac); if (peer != NULL) truncate_cpy(name, sizeof(name), (const char*)peer->nickname.data); - WARN_LOG(SCENET, "GameMode: Unknown Source Port from [%s][%s:%u -> %u] (Result=%i, Size=%i)", name, mac2str(&sendermac).c_str(), senderport, ADHOC_GAMEMODE_PORT, ret, bufsz); + WARN_LOG(Log::sceNet, "GameMode: Unknown Source Port from [%s][%s:%u -> %u] (Result=%i, Size=%i)", name, mac2str(&sendermac).c_str(), senderport, ADHOC_GAMEMODE_PORT, ret, bufsz); g_OSD.Show(OSDType::MESSAGE_WARNING, std::string(n->T("GM: Data from Unknown Port")) + std::string(" [") + std::string(name) + std::string("]:") + std::to_string(senderport) + std::string(" -> ") + std::to_string(ADHOC_GAMEMODE_PORT) + std::string(" (") + std::to_string(portOffset) + std::string(")")); peerlock.unlock(); } @@ -288,7 +289,7 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) { for (auto& gma : replicaGameModeAreas) { if (IsMatch(gma.mac, sendermac)) { - DEBUG_LOG(SCENET, "GameMode: Replica data Received %d bytes for Area #%d [%s]", bufsz, gma.id, mac2str(&sendermac).c_str()); + DEBUG_LOG(Log::sceNet, "GameMode: Replica data Received %d bytes for Area #%d [%s]", bufsz, gma.id, mac2str(&sendermac).c_str()); memcpy(gma.data, gameModeBuffer, std::min(gma.size, bufsz)); gma.dataUpdated = 1; gma.updateTimestamp = CoreTiming::GetGlobalTimeUsScaled(); @@ -303,10 +304,10 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) { CoreTiming::ScheduleEvent(usToCycles(GAMEMODE_UPDATE_INTERVAL) - cyclesLate, gameModeNotifyEvent, userdata); return; } - INFO_LOG(SCENET, "GameMode Scheduler (%d, %d) has ended", gameModeSocket, gameModeBuffSize); + INFO_LOG(Log::sceNet, "GameMode Scheduler (%d, %d) has ended", gameModeSocket, gameModeBuffSize); u32 waitVal = __KernelGetWaitValue(threadID, error); if (error == 0) { - DEBUG_LOG(SCENET, "GameMode: Resuming Thread %d after Master Deleted (Result = %08x)", threadID, waitVal); + DEBUG_LOG(Log::sceNet, "GameMode: Resuming Thread %d after Master Deleted (Result = %08x)", threadID, waitVal); __KernelResumeThreadFromWait(threadID, waitVal); } } @@ -320,13 +321,13 @@ static void __AdhocctlNotify(u64 userdata, int cyclesLate) { SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error); if (waitID == 0 || error != 0) { - WARN_LOG(SCENET, "sceNetAdhocctl Socket WaitID(%i) on Thread(%i) already woken up? (error: %08x)", uid, threadID, error); + WARN_LOG(Log::sceNet, "sceNetAdhocctl Socket WaitID(%i) on Thread(%i) already woken up? (error: %08x)", uid, threadID, error); return; } // Socket not found?! Should never happen! But if it ever happened (ie. loaded from SaveState where adhocctlRequests got cleared) return BUSY and let the game try again. if (adhocctlRequests.find(uid) == adhocctlRequests.end()) { - WARN_LOG(SCENET, "sceNetAdhocctl Socket WaitID(%i) not found!", uid); + WARN_LOG(Log::sceNet, "sceNetAdhocctl Socket WaitID(%i) not found!", uid); __KernelResumeThreadFromWait(threadID, ERROR_NET_ADHOCCTL_BUSY); return; } @@ -367,7 +368,7 @@ static void __AdhocctlNotify(u64 userdata, int cyclesLate) { // Prevent from sending again req.opcode = 0; if (ret == SOCKET_ERROR) - DEBUG_LOG(SCENET, "sceNetAdhocctl[%i]: Socket Error (%i)", uid, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctl[%i]: Socket Error (%i)", uid, sockerr); } } } @@ -389,7 +390,7 @@ static void __AdhocctlNotify(u64 userdata, int cyclesLate) { u32 waitVal = __KernelGetWaitValue(threadID, error); __KernelResumeThreadFromWait(threadID, result); - DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %08x) Result (%08x) of sceNetAdhocctl - Opcode: %d, State: %d", waitID, error, (int)result, waitVal, adhocctlState); + DEBUG_LOG(Log::sceNet, "Returning (WaitID: %d, error: %08x) Result (%08x) of sceNetAdhocctl - Opcode: %d, State: %d", waitID, error, (int)result, waitVal, adhocctlState); // We are done with this request adhocctlRequests.erase(uid); @@ -405,7 +406,7 @@ static void __AdhocctlState(u64 userdata, int cyclesLate) { SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error); if (waitID == 0 || error != 0) { - WARN_LOG(SCENET, "sceNetAdhocctl State WaitID(%i) on Thread(%i) already woken up? (error: %08x)", uid, threadID, error); + WARN_LOG(Log::sceNet, "sceNetAdhocctl State WaitID(%i) on Thread(%i) already woken up? (error: %08x)", uid, threadID, error); return; } @@ -421,7 +422,7 @@ static void __AdhocctlState(u64 userdata, int cyclesLate) { } __KernelResumeThreadFromWait(threadID, result); - DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %08x) Result (%08x) of sceNetAdhocctl - Event: %d, State: %d", waitID, error, (int)result, event, adhocctlState); + DEBUG_LOG(Log::sceNet, "Returning (WaitID: %d, error: %08x) Result (%08x) of sceNetAdhocctl - Event: %d, State: %d", waitID, error, (int)result, event, adhocctlState); } // Used to simulate blocking on metasocket when send OP code to AdhocServer @@ -429,7 +430,7 @@ int WaitBlockingAdhocctlSocket(AdhocctlRequest request, int usec, const char* re int uid = (metasocket <= 0) ? 1 : (int)metasocket; if (adhocctlRequests.find(uid) != adhocctlRequests.end()) { - WARN_LOG(SCENET, "sceNetAdhocctl - WaitID[%d] already existed, Socket is busy!", uid); + WARN_LOG(Log::sceNet, "sceNetAdhocctl - WaitID[%d] already existed, Socket is busy!", uid); return ERROR_NET_ADHOCCTL_BUSY; } @@ -455,9 +456,9 @@ int ScheduleAdhocctlState(int event, int newState, int usec, const char* reason) } int StartGameModeScheduler() { - INFO_LOG(SCENET, "Initiating GameMode Scheduler"); + INFO_LOG(Log::sceNet, "Initiating GameMode Scheduler"); if (CoreTiming::IsScheduled(gameModeNotifyEvent)) { - WARN_LOG(SCENET, "GameMode Scheduler is already running!"); + WARN_LOG(Log::sceNet, "GameMode Scheduler is already running!"); return -1; } u64 param = ((u64)__KernelGetCurThread()) << 32; @@ -505,7 +506,7 @@ int DoBlockingPdpRecv(AdhocSocketRequest& req, s64& result) { u64 now = (u64)(time_now_d() * 1000000.0); if (req.timeout != 0 && now - req.startTime > req.timeout) { result = ERROR_NET_ADHOC_TIMEOUT; - DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i]: Discard Timeout", req.id); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i]: Discard Timeout", req.id); return 0; } else @@ -524,7 +525,7 @@ int DoBlockingPdpRecv(AdhocSocketRequest& req, s64& result) { // UDP can also receives 0 data, while on TCP receiving 0 data = connection gracefully closed, but not sure whether PDP can send/recv 0 data or not tho *req.length = 0; if (ret >= 0) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %u bytes from %s:%u\n", req.id, getLocalPort(pdpsocket.id), ret, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i:%u]: Received %u bytes from %s:%u\n", req.id, getLocalPort(pdpsocket.id), ret, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); // Find Peer MAC if (resolveIP(sin.sin_addr.s_addr, &mac)) { @@ -546,7 +547,7 @@ int DoBlockingPdpRecv(AdhocSocketRequest& req, s64& result) { *req.length = ret; *req.remotePort = ntohs(sin.sin_port) - portOffset; - WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %i bytes from Unknown Peer %s:%u", req.id, getLocalPort(pdpsocket.id), ret, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); + WARN_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i:%u]: Received %i bytes from Unknown Peer %s:%u", req.id, getLocalPort(pdpsocket.id), ret, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); } } result = 0; @@ -563,7 +564,7 @@ int DoBlockingPdpRecv(AdhocSocketRequest& req, s64& result) { } // Returning required buffer size when available data in recv buffer is larger than provided buffer size else if (ret > *req.length) { - WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", req.id, getLocalPort(pdpsocket.id), ret, *req.length, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); + WARN_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", req.id, getLocalPort(pdpsocket.id), ret, *req.length, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); *req.length = ret; // Find Peer MAC @@ -585,7 +586,7 @@ int DoBlockingPdpRecv(AdhocSocketRequest& req, s64& result) { result = ERROR_NET_ADHOC_TIMEOUT; // ERROR_NET_ADHOC_INVALID_ARG; // ERROR_NET_ADHOC_DISCONNECTED if (ret == SOCKET_ERROR) - DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i]: Socket Error (%i)", req.id, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i]: Socket Error (%i)", req.id, sockerr); return 0; } @@ -616,7 +617,7 @@ int DoBlockingPdpSend(AdhocSocketRequest& req, s64& result, AdhocSendTargets& ta int sockerr = errno; if (ret >= 0) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u](B): Sent %u bytes to %s:%u\n", req.id, getLocalPort(pdpsocket.id), ret, ip2str(target.sin_addr).c_str(), ntohs(target.sin_port)); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpSend[%i:%u](B): Sent %u bytes to %s:%u\n", req.id, getLocalPort(pdpsocket.id), ret, ip2str(target.sin_addr).c_str(), ntohs(target.sin_port)); // Remove successfully sent to peer to prevent sending the same data again during a retry peer = targetPeers.peers.erase(peer); } @@ -634,7 +635,7 @@ int DoBlockingPdpSend(AdhocSocketRequest& req, s64& result, AdhocSendTargets& ta } if (ret == SOCKET_ERROR) - DEBUG_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u](B) [size=%i]", sockerr, req.id, getLocalPort(pdpsocket.id), ntohs(target.sin_port), targetPeers.length); + DEBUG_LOG(Log::sceNet, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u](B) [size=%i]", sockerr, req.id, getLocalPort(pdpsocket.id), ntohs(target.sin_port), targetPeers.length); } if (retry) @@ -665,7 +666,7 @@ int DoBlockingPtpSend(AdhocSocketRequest& req, s64& result) { // Save Length *req.length = ret; - DEBUG_LOG(SCENET, "sceNetAdhocPtpSend[%i:%u]: Sent %u bytes to %s:%u\n", req.id, ptpsocket.lport, ret, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpSend[%i:%u]: Sent %u bytes to %s:%u\n", req.id, ptpsocket.lport, ret, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); // Set to Established on successful Send when an attempt to Connect was initiated if (ptpsocket.state == ADHOC_PTP_STATE_SYN_SENT) @@ -691,7 +692,7 @@ int DoBlockingPtpSend(AdhocSocketRequest& req, s64& result) { } if (ret == SOCKET_ERROR) - DEBUG_LOG(SCENET, "sceNetAdhocPtpSend[%i]: Socket Error (%i)", req.id, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpSend[%i]: Socket Error (%i)", req.id, sockerr); return 0; } @@ -714,7 +715,7 @@ int DoBlockingPtpRecv(AdhocSocketRequest& req, s64& result) { // Received Data. POSIX: May received 0 bytes when the remote peer already closed the connection. if (ret > 0) { - DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv[%i:%u]: Received %u bytes from %s:%u\n", req.id, ptpsocket.lport, ret, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpRecv[%i:%u]: Received %u bytes from %s:%u\n", req.id, ptpsocket.lport, ret, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); // Save Length *req.length = ret; @@ -747,7 +748,7 @@ int DoBlockingPtpRecv(AdhocSocketRequest& req, s64& result) { } if (ret == SOCKET_ERROR) - DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv[%i]: Socket Error (%i)", req.id, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpRecv[%i]: Socket Error (%i)", req.id, sockerr); return 0; } @@ -797,7 +798,7 @@ int DoBlockingPtpAccept(AdhocSocketRequest& req, s64& result) { result = ERROR_NET_ADHOC_INVALID_ARG; //ERROR_NET_ADHOC_TIMEOUT if (ret == SOCKET_ERROR) - DEBUG_LOG(SCENET, "sceNetAdhocPtpAccept[%i]: Socket Error (%i)", req.id, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpAccept[%i]: Socket Error (%i)", req.id, sockerr); return 0; } @@ -827,7 +828,7 @@ int DoBlockingPtpConnect(AdhocSocketRequest& req, s64& result, AdhocSendTargets& ret = connect(ptpsocket.id, (struct sockaddr*)&sin, sizeof(sin)); sockerr = errno; if (sockerr != 0) - DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: connect(%i) error = %i", req.id, ptpsocket.lport, ptpsocket.id, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: connect(%i) error = %i", req.id, ptpsocket.lport, ptpsocket.id, sockerr); else ret = 1; // Ensure returned success value from connect to be compatible with returned success value from select (ie. positive value) } @@ -835,9 +836,9 @@ int DoBlockingPtpConnect(AdhocSocketRequest& req, s64& result, AdhocSendTargets& // Note: On Linux "select" can return > 0 (with SO_ERROR = 0) even when the connection is not accepted yet, thus need "getpeername" to ensure else { ret = IsSocketReady(ptpsocket.id, false, true, &sockerr); - DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Select(%i) = %i, error = %i", req.id, ptpsocket.lport, ptpsocket.id, ret, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: Select(%i) = %i, error = %i", req.id, ptpsocket.lport, ptpsocket.id, ret, sockerr); if (sockerr != 0) { - DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: SelectError(%i) = %i", req.id, ptpsocket.lport, ptpsocket.id, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: SelectError(%i) = %i", req.id, ptpsocket.lport, ptpsocket.id, sockerr); ret = SOCKET_ERROR; // Ensure returned value from select to be negative when the socket has error (the socket may need to be recreated again) } @@ -856,7 +857,7 @@ int DoBlockingPtpConnect(AdhocSocketRequest& req, s64& result, AdhocSendTargets& ret = getpeername(ptpsocket.id, (struct sockaddr*)&sin, &sinlen); if (ret == SOCKET_ERROR) { int err = errno; - VERBOSE_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: getpeername(%i) error %i, sockerr = %i", req.id, ptpsocket.lport, ptpsocket.id, err, sockerr); + VERBOSE_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: getpeername(%i) error %i, sockerr = %i", req.id, ptpsocket.lport, ptpsocket.id, err, sockerr); sockerr = err; } } @@ -864,7 +865,7 @@ int DoBlockingPtpConnect(AdhocSocketRequest& req, s64& result, AdhocSendTargets& // Update Adhoc Socket state if (ret != SOCKET_ERROR || sockerr == EISCONN) { ptpsocket.state = ADHOC_PTP_STATE_ESTABLISHED; - INFO_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Established (%s:%u)", req.id, ptpsocket.lport, ip2str(sin.sin_addr).c_str(), ptpsocket.pport); + INFO_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: Established (%s:%u)", req.id, ptpsocket.lport, ip2str(sin.sin_addr).c_str(), ptpsocket.pport); // Done result = 0; @@ -876,9 +877,9 @@ int DoBlockingPtpConnect(AdhocSocketRequest& req, s64& result, AdhocSendTargets& else { // Only recreate the socket once per frame (just like most adhoc games that tried to PtpConnect once per frame when using non-blocking mode) if (/*sockerr == ECONNREFUSED ||*/ static_cast(CoreTiming::GetGlobalTimeUsScaled() - sock->internalLastAttempt) > 16666) { - DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Recreating Socket %i, errno = %i, state = %i, attempt = %i", req.id, ptpsocket.lport, ptpsocket.id, sockerr, ptpsocket.state, sock->attemptCount); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: Recreating Socket %i, errno = %i, state = %i, attempt = %i", req.id, ptpsocket.lport, ptpsocket.id, sockerr, ptpsocket.state, sock->attemptCount); if (RecreatePtpSocket(req.id) < 0) { - WARN_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: RecreatePtpSocket error %i", req.id, ptpsocket.lport, errno); + WARN_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: RecreatePtpSocket error %i", req.id, ptpsocket.lport, errno); } ptpsocket.state = ADHOC_PTP_STATE_CLOSED; sock->internalLastAttempt = CoreTiming::GetGlobalTimeUsScaled(); @@ -905,7 +906,7 @@ int DoBlockingPtpConnect(AdhocSocketRequest& req, s64& result, AdhocSendTargets& } if (ret == SOCKET_ERROR) - DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i]: Socket Error (%i)", req.id, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i]: Socket Error (%i)", req.id, sockerr); return 0; } @@ -937,7 +938,7 @@ int DoBlockingPtpFlush(AdhocSocketRequest& req, s64& result) { } if (sockerr != 0) { - DEBUG_LOG(SCENET, "sceNetAdhocPtpFlush[%i]: Socket Error (%i)", req.id, sockerr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpFlush[%i]: Socket Error (%i)", req.id, sockerr); } return 0; @@ -965,9 +966,9 @@ int DoBlockingAdhocPollSocket(AdhocSocketRequest& req, s64& result) { if (sds[i].id > 0 && sds[i].id <= MAX_SOCKET && adhocSockets[sds[i].id - 1] != NULL) { auto sock = adhocSockets[sds[i].id - 1]; if (sock->type == SOCK_PTP) - VERBOSE_LOG(SCENET, "Poll PTP Socket Id: %d (%d), events: %08x, revents: %08x - state: %d", sds[i].id, sock->data.ptp.id, sds[i].events, sds[i].revents, sock->data.ptp.state); + VERBOSE_LOG(Log::sceNet, "Poll PTP Socket Id: %d (%d), events: %08x, revents: %08x - state: %d", sds[i].id, sock->data.ptp.id, sds[i].events, sds[i].revents, sock->data.ptp.state); else - VERBOSE_LOG(SCENET, "Poll PDP Socket Id: %d (%d), events: %08x, revents: %08x", sds[i].id, sock->data.pdp.id, sds[i].events, sds[i].revents); + VERBOSE_LOG(Log::sceNet, "Poll PDP Socket Id: %d (%d), events: %08x, revents: %08x", sds[i].id, sock->data.pdp.id, sds[i].events, sds[i].revents); } } } @@ -985,13 +986,13 @@ static void __AdhocSocketNotify(u64 userdata, int cyclesLate) { SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error); if (waitID == 0 || error != 0) { - WARN_LOG(SCENET, "sceNetAdhoc Socket WaitID(%i) on Thread(%i) already woken up? (error: %08x)", uid, threadID, error); + WARN_LOG(Log::sceNet, "sceNetAdhoc Socket WaitID(%i) on Thread(%i) already woken up? (error: %08x)", uid, threadID, error); return; } // Socket not found?! Should never happened! But if it ever happened (ie. loaded from SaveState where adhocSocketRequests got cleared) return TIMEOUT and let the game try again. if (adhocSocketRequests.find(userdata) == adhocSocketRequests.end()) { - WARN_LOG(SCENET, "sceNetAdhoc Socket WaitID(%i) on Thread(%i) not found!", uid, threadID); + WARN_LOG(Log::sceNet, "sceNetAdhoc Socket WaitID(%i) on Thread(%i) not found!", uid, threadID); __KernelResumeThreadFromWait(threadID, ERROR_NET_ADHOC_TIMEOUT); return; } @@ -1071,7 +1072,7 @@ static void __AdhocSocketNotify(u64 userdata, int cyclesLate) { } __KernelResumeThreadFromWait(threadID, result); - DEBUG_LOG(SCENET, "Returning (ThreadId: %d, WaitID: %d, error: %08x) Result (%08x) of sceNetAdhoc[%d] - SocketID: %d", threadID, waitID, error, (int)result, req.type, req.id); + DEBUG_LOG(Log::sceNet, "Returning (ThreadId: %d, WaitID: %d, error: %08x) Result (%08x) of sceNetAdhoc[%d] - SocketID: %d", threadID, waitID, error, (int)result, req.type, req.id); // We are done with this socket adhocSocketRequests.erase(userdata); @@ -1081,7 +1082,7 @@ static void __AdhocSocketNotify(u64 userdata, int cyclesLate) { int WaitBlockingAdhocSocket(u64 threadSocketId, int type, int pspSocketId, void* buffer, s32_le* len, u32 timeoutUS, SceNetEtherAddr* remoteMAC, u16_le* remotePort, const char* reason) { int uid = (int)(threadSocketId & 0xFFFFFFFF); if (adhocSocketRequests.find(threadSocketId) != adhocSocketRequests.end()) { - WARN_LOG(SCENET, "sceNetAdhoc[%d] - ThreadID[%d] WaitID[%d] already existed, Socket[%d] is busy!", type, static_cast(threadSocketId >> 32), uid, pspSocketId); + WARN_LOG(Log::sceNet, "sceNetAdhoc[%d] - ThreadID[%d] WaitID[%d] already existed, Socket[%d] is busy!", type, static_cast(threadSocketId >> 32), uid, pspSocketId); // FIXME: Not sure if Adhoc Socket can return ADHOC_BUSY or not (assuming it's similar to EINPROGRESS for Adhoc Socket), or may be we should return TIMEOUT instead? return ERROR_NET_ADHOC_BUSY; // ERROR_NET_ADHOC_TIMEOUT } @@ -1293,14 +1294,14 @@ u32 sceNetAdhocInit() { deleteAllGMB(); // Return Success - return hleLogSuccessInfoI(SCENET, 0, "at %08x", currentMIPS->pc); + return hleLogSuccessInfoI(Log::sceNet, 0, "at %08x", currentMIPS->pc); } // Already initialized - return hleLogWarning(SCENET, ERROR_NET_ADHOC_ALREADY_INITIALIZED, "already initialized"); + return hleLogWarning(Log::sceNet, ERROR_NET_ADHOC_ALREADY_INITIALIZED, "already initialized"); } static u32 sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) { - INFO_LOG(SCENET, "sceNetAdhocctlInit(%i, %i, %08x) at %08x", stackSize, prio, productAddr, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlInit(%i, %i, %08x) at %08x", stackSize, prio, productAddr, currentMIPS->pc); // FIXME: Returning 0x8002013a (SCE_KERNEL_ERROR_LIBRARY_NOT_YET_LINKED) without adhoc module loaded first? // FIXME: Sometimes returning 0x80410601 (ERROR_NET_ADHOC_AUTH_ALREADY_INITIALIZED / Library module is already initialized ?) when AdhocctlTerm is not fully done? @@ -1361,7 +1362,7 @@ int sceNetAdhocctlGetState(u32 ptrToStatus) { Memory::Write_U32(state, ptrToStatus); // Return Success - return hleLogSuccessVerboseI(SCENET, 0, "state = %d", state); + return hleLogSuccessVerboseI(Log::sceNet, 0, "state = %d", state); } /** @@ -1374,7 +1375,7 @@ int sceNetAdhocctlGetState(u32 ptrToStatus) { */ // When choosing AdHoc menu in Wipeout Pulse sometimes it's saying that "WLAN is turned off" on game screen and getting "kUnityCommandCode_MediaDisconnected" error in the Log Console when calling sceNetAdhocPdpCreate, probably it needed to wait something from the thread before calling this (ie. need to receives 7 bytes from adhoc server 1st?) static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 flag) { - INFO_LOG(SCENET, "sceNetAdhocPdpCreate(%s, %u, %u, %u) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), port, bufferSize, flag, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocPdpCreate(%s, %u, %u, %u) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), port, bufferSize, flag, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -1391,7 +1392,7 @@ static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 f // Port is in use by another PDP Socket. if (isPDPPortInUse(port)) { // FIXME: When PORT_IN_USE error occured it seems the index to the socket id also increased, which means it tries to create & bind the socket first and then closes it due to failed to bind - return hleLogDebug(SCENET, ERROR_NET_ADHOC_PORT_IN_USE, "port in use"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_PORT_IN_USE, "port in use"); } //sport 0 should be shifted back to 0 when using offset Phantasy Star Portable 2 use this @@ -1437,7 +1438,7 @@ static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 f requestedport = 65535; // Hopefully it will be safe to default it to 65535 since there can't be more than one port that can bumped into 65536 // Show a warning about privileged ports if (requestedport != 0 && requestedport < 1024) { - WARN_LOG(SCENET, "sceNetAdhocPdpCreate - Ports below 1024(ie. %hu) may require Admin Privileges", requestedport); + WARN_LOG(Log::sceNet, "sceNetAdhocPdpCreate - Ports below 1024(ie. %hu) may require Admin Privileges", requestedport); } addr.sin_port = htons(requestedport); @@ -1454,7 +1455,7 @@ static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 f if (getsockname(usocket, (struct sockaddr*)&addr, &len) == 0) { uint16_t boundport = ntohs(addr.sin_port); if (port + static_cast(portOffset) >= 65536 || static_cast(boundport) - static_cast(portOffset) <= 0) - WARN_LOG(SCENET, "sceNetAdhocPdpCreate - Wrapped Port Detected: Original(%d) -> Requested(%d), Bound(%d) -> BoundOriginal(%d)", port, requestedport, boundport, boundport - portOffset); + WARN_LOG(Log::sceNet, "sceNetAdhocPdpCreate - Wrapped Port Detected: Original(%d) -> Requested(%d), Bound(%d) -> BoundOriginal(%d)", port, requestedport, boundport, boundport - portOffset); port = boundport - portOffset; } @@ -1495,7 +1496,7 @@ static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 f changeBlockingMode(usocket, 1); // Success - INFO_LOG(SCENET, "sceNetAdhocPdpCreate - PSP Socket id: %i, Host Socket id: %i", i + 1, usocket); + INFO_LOG(Log::sceNet, "sceNetAdhocPdpCreate - PSP Socket id: %i, Host Socket id: %i", i + 1, usocket); return i + 1; } @@ -1509,27 +1510,27 @@ static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 f // Port not available (exclusively in use?) if (iResult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port)); + ERROR_LOG(Log::sceNet, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port)); auto n = GetI18NCategory(I18NCat::NETWORKING); g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to Bind Port")) + " " + std::to_string(port + portOffset) + "\n" + std::string(n->T("Please change your Port Offset"))); - return hleLogDebug(SCENET, ERROR_NET_ADHOC_PORT_NOT_AVAIL, "port not available"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_PORT_NOT_AVAIL, "port not available"); } } // Default to No-Space Error - return hleLogDebug(SCENET, ERROR_NET_NO_SPACE, "net no space"); + return hleLogDebug(Log::sceNet, ERROR_NET_NO_SPACE, "net no space"); } // Invalid MAC supplied - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); } // Invalid Arguments were supplied - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); } // Library is uninitialized - return hleLogDebug(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); } /** @@ -1541,19 +1542,19 @@ static int sceNetAdhocctlGetParameter(u32 paramAddr) { char grpName[9] = { 0 }; memcpy(grpName, parameter.group_name.data, ADHOCCTL_GROUPNAME_LEN); parameter.nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0; - DEBUG_LOG(SCENET, "sceNetAdhocctlGetParameter(%08x) [Ch=%i][Group=%s][BSSID=%s][name=%s]", paramAddr, parameter.channel, grpName, mac2str(¶meter.bssid.mac_addr).c_str(), parameter.nickname.data); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctlGetParameter(%08x) [Ch=%i][Group=%s][BSSID=%s][name=%s]", paramAddr, parameter.channel, grpName, mac2str(¶meter.bssid.mac_addr).c_str(), parameter.nickname.data); if (!g_Config.bEnableWlan) { return ERROR_NET_ADHOCCTL_DISCONNECTED; } // Library initialized if (!netAdhocctlInited) { - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED); } auto ptr = PSPPointer::Create(paramAddr); if (!ptr.IsValid()) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_INVALID_ARG); *ptr = parameter; ptr.NotifyWrite("NetAdhocctlGetParameter"); @@ -1573,9 +1574,9 @@ static int sceNetAdhocctlGetParameter(u32 paramAddr) { */ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, int timeout, int flag) { if (flag == 0) { // Prevent spamming Debug Log with retries of non-bocking socket - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i) at %08x", id, mac2str((SceNetEtherAddr*)mac).c_str(), port, data, len, timeout, flag, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i) at %08x", id, mac2str((SceNetEtherAddr*)mac).c_str(), port, data, len, timeout, flag, currentMIPS->pc); } else { - VERBOSE_LOG(SCENET, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i) at %08x", id, mac2str((SceNetEtherAddr*)mac).c_str(), port, data, len, timeout, flag, currentMIPS->pc); + VERBOSE_LOG(Log::sceNet, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i) at %08x", id, mac2str((SceNetEtherAddr*)mac).c_str(), port, data, len, timeout, flag, currentMIPS->pc); } if (!g_Config.bEnableWlan) { return -1; @@ -1615,7 +1616,7 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int if (socket->flags & ADHOC_F_ALERTSEND) { socket->alerted_flags |= ADHOC_F_ALERTSEND; - return hleLogError(SCENET, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); } // Single Target @@ -1643,8 +1644,8 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int if (!flag && (error == EAGAIN || error == EWOULDBLOCK)) { u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | pdpsocket.id; if (sendTargetPeers.find(threadSocketId) != sendTargetPeers.end()) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Socket(%d) is Busy!", id, getLocalPort(pdpsocket.id), pdpsocket.id); - return hleLogError(SCENET, ERROR_NET_ADHOC_BUSY, "busy?"); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpSend[%i:%u]: Socket(%d) is Busy!", id, getLocalPort(pdpsocket.id), pdpsocket.id); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_BUSY, "busy?"); } AdhocSendTargets dest = { len, {}, false }; @@ -1653,7 +1654,7 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int return WaitBlockingAdhocSocket(threadSocketId, PDP_SEND, id, data, nullptr, timeout, nullptr, nullptr, "pdp send"); } - DEBUG_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u] (size=%i)", error, id, getLocalPort(pdpsocket.id), ntohs(target.sin_port), len); + DEBUG_LOG(Log::sceNet, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u] (size=%i)", error, id, getLocalPort(pdpsocket.id), ntohs(target.sin_port), len); } //changeBlockingMode(socket->id, 0); @@ -1663,7 +1664,7 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int hleEatMicro(50); // Can be longer than 1ms tho // Sent Data if (sent >= 0) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Sent %u bytes to %s:%u\n", id, getLocalPort(pdpsocket.id), sent, ip2str(target.sin_addr).c_str(), ntohs(target.sin_port)); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpSend[%i:%u]: Sent %u bytes to %s:%u\n", id, getLocalPort(pdpsocket.id), sent, ip2str(target.sin_addr).c_str(), ntohs(target.sin_port)); // Success return 0; // sent; // MotorStorm will try to resend if return value is not 0 @@ -1671,12 +1672,12 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int // Non-Blocking if (flag) - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); // Does PDP can Timeout? There is no concept of Timeout when sending UDP due to no ACK, but might happen if the socket buffer is full, not sure about PDP since some games did use the timeout arg - return hleLogDebug(SCENET, ERROR_NET_ADHOC_TIMEOUT, "timeout?"); // ERROR_NET_ADHOC_INVALID_ADDR; + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_TIMEOUT, "timeout?"); // ERROR_NET_ADHOC_INVALID_ADDR; } - VERBOSE_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Unknown Target Peer %s:%u (faking success)\n", id, getLocalPort(pdpsocket.id), mac2str(daddr).c_str(), ntohs(target.sin_port)); + VERBOSE_LOG(Log::sceNet, "sceNetAdhocPdpSend[%i:%u]: Unknown Target Peer %s:%u (faking success)\n", id, getLocalPort(pdpsocket.id), mac2str(daddr).c_str(), ntohs(target.sin_port)); return 0; // faking success } @@ -1719,8 +1720,8 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int if (!flag) { u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | pdpsocket.id; if (sendTargetPeers.find(threadSocketId) != sendTargetPeers.end()) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u](BC): Socket(%d) is Busy!", id, getLocalPort(pdpsocket.id), pdpsocket.id); - return hleLogError(SCENET, ERROR_NET_ADHOC_BUSY, "busy?"); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpSend[%i:%u](BC): Socket(%d) is Busy!", id, getLocalPort(pdpsocket.id), pdpsocket.id); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_BUSY, "busy?"); } sendTargetPeers[threadSocketId] = dest; @@ -1739,11 +1740,11 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int int sent = sendto(pdpsocket.id, (const char*)data, len, MSG_NOSIGNAL, (struct sockaddr*)&target, sizeof(target)); int error = errno; if (sent == SOCKET_ERROR) { - DEBUG_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u](BC) [size=%i]", error, id, getLocalPort(pdpsocket.id), ntohs(target.sin_port), len); + DEBUG_LOG(Log::sceNet, "Socket Error (%i) on sceNetAdhocPdpSend[%i:%u->%u](BC) [size=%i]", error, id, getLocalPort(pdpsocket.id), ntohs(target.sin_port), len); } if (sent >= 0) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u](BC): Sent %u bytes to %s:%u\n", id, getLocalPort(pdpsocket.id), sent, ip2str(target.sin_addr).c_str(), ntohs(target.sin_port)); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpSend[%i:%u](BC): Sent %u bytes to %s:%u\n", id, getLocalPort(pdpsocket.id), sent, ip2str(target.sin_addr).c_str(), ntohs(target.sin_port)); } } } @@ -1760,27 +1761,27 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int } // Invalid Destination Address - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); } // Invalid Argument - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); } // Invalid Socket ID - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Invalid Data Length - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_DATALEN, "invalid data length"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_DATALEN, "invalid data length"); } // Invalid Destination Port - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_PORT, "invalid port"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_PORT, "invalid port"); } // Library is uninitialized - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); } /** @@ -1796,9 +1797,9 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int */ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *dataLength, u32 timeout, int flag) { if (flag == 0) { // Prevent spamming Debug Log with retries of non-bocking socket - DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i) at %08x", id, addr, port, buf, dataLength, timeout, flag, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i) at %08x", id, addr, port, buf, dataLength, timeout, flag, currentMIPS->pc); } else { - VERBOSE_LOG(SCENET, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i) at %08x", id, addr, port, buf, dataLength, timeout, flag, currentMIPS->pc); + VERBOSE_LOG(Log::sceNet, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i) at %08x", id, addr, port, buf, dataLength, timeout, flag, currentMIPS->pc); } if (!g_Config.bEnableWlan) { @@ -1848,7 +1849,7 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * if (socket->flags & ADHOC_F_ALERTRECV) { socket->alerted_flags |= ADHOC_F_ALERTRECV; - return hleLogError(SCENET, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); } // Sender Address @@ -1884,8 +1885,8 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * memset(&sin, 0, sinlen); recvfrom(pdpsocket.id, dummyPeekBuf64k, dummyPeekBuf64kSize, MSG_NOSIGNAL, (struct sockaddr*)&sin, &sinlen); if (flag) { - VERBOSE_LOG(SCENET, "%08x=sceNetAdhocPdpRecv: would block (disc)", ERROR_NET_ADHOC_WOULD_BLOCK); // Temporary fix to avoid a crash on the Logs due to trying to Logs syscall's argument from another thread (ie. AdhocMatchingInput thread) - return ERROR_NET_ADHOC_WOULD_BLOCK; // hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block (disc)"); + VERBOSE_LOG(Log::sceNet, "%08x=sceNetAdhocPdpRecv: would block (disc)", ERROR_NET_ADHOC_WOULD_BLOCK); // Temporary fix to avoid a crash on the Logs due to trying to Logs syscall's argument from another thread (ie. AdhocMatchingInput thread) + return ERROR_NET_ADHOC_WOULD_BLOCK; // hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block (disc)"); } else { // Simulate blocking behaviour with non-blocking socket, and discard more unresolvable packets until timeout reached @@ -1899,7 +1900,7 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * // At this point we assumed that the packet is a valid PPSSPP packet if (received != SOCKET_ERROR && *len < received) { - INFO_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", id, getLocalPort(pdpsocket.id), received, *len, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); + INFO_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", id, getLocalPort(pdpsocket.id), received, *len, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); if (received > 0 && *len > 0) memcpy(buf, dummyPeekBuf64k, std::min(received, *len)); @@ -1917,7 +1918,7 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * if (peer != NULL) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); peerlock.unlock(); - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_NOT_ENOUGH_SPACE, "not enough space"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_NOT_ENOUGH_SPACE, "not enough space"); } sinlen = sizeof(sin); @@ -1934,14 +1935,14 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * return WaitBlockingAdhocSocket(threadSocketId, PDP_RECV, id, buf, len, timeout, saddr, sport, "pdp recv"); } - VERBOSE_LOG(SCENET, "%08x=sceNetAdhocPdpRecv: would block", ERROR_NET_ADHOC_WOULD_BLOCK); // Temporary fix to avoid a crash on the Logs due to trying to Logs syscall's argument from another thread (ie. AdhocMatchingInput thread) - return ERROR_NET_ADHOC_WOULD_BLOCK; // hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); + VERBOSE_LOG(Log::sceNet, "%08x=sceNetAdhocPdpRecv: would block", ERROR_NET_ADHOC_WOULD_BLOCK); // Temporary fix to avoid a crash on the Logs due to trying to Logs syscall's argument from another thread (ie. AdhocMatchingInput thread) + return ERROR_NET_ADHOC_WOULD_BLOCK; // hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); } hleEatMicro(50); // Received Data. UDP can also receives 0 data, while on TCP 0 data = connection gracefully closed, but not sure about PDP tho if (received >= 0) { - DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %u bytes from %s:%u\n", id, getLocalPort(pdpsocket.id), received, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i:%u]: Received %u bytes from %s:%u\n", id, getLocalPort(pdpsocket.id), received, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); // Find Peer MAC if (resolveIP(sin.sin_addr.s_addr, &mac)) { @@ -1971,10 +1972,10 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * //free(tmpbuf); // Receiving data from unknown peer? Should never reached here! Unless the Peeked's packet was different than the Recved one (which mean there is a problem) - WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %i bytes from Unknown Peer %s:%u", id, getLocalPort(pdpsocket.id), received, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); + WARN_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i:%u]: Received %i bytes from Unknown Peer %s:%u", id, getLocalPort(pdpsocket.id), received, ip2str(sin.sin_addr).c_str(), ntohs(sin.sin_port)); if (flag) { - VERBOSE_LOG(SCENET, "%08x=sceNetAdhocPdpRecv: would block (problem)", ERROR_NET_ADHOC_WOULD_BLOCK); // Temporary fix to avoid a crash on the Logs due to trying to Logs syscall's argument from another thread (ie. AdhocMatchingInput thread) - return ERROR_NET_ADHOC_WOULD_BLOCK; // hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block (problem)"); + VERBOSE_LOG(Log::sceNet, "%08x=sceNetAdhocPdpRecv: would block (problem)", ERROR_NET_ADHOC_WOULD_BLOCK); // Temporary fix to avoid a crash on the Logs due to trying to Logs syscall's argument from another thread (ie. AdhocMatchingInput thread) + return ERROR_NET_ADHOC_WOULD_BLOCK; // hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block (problem)"); } } @@ -1986,22 +1987,22 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void * if (wouldblock) flag = 1; #endif - DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Result:%i (Error:%i)", id, pdpsocket.lport, received, error); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPdpRecv[%i:%u]: Result:%i (Error:%i)", id, pdpsocket.lport, received, error); // Unexpected error (other than EAGAIN/EWOULDBLOCK/ECONNRESET) or in case the Peeked's packet was different than Recved one, treated as Timeout? - return hleLogError(SCENET, ERROR_NET_ADHOC_TIMEOUT, "timeout?"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_TIMEOUT, "timeout?"); } // Invalid Argument - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); } // Invalid Socket ID - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Library is uninitialized - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); } int NetAdhoc_SetSocketAlert(int id, s32_le flag) { @@ -2019,11 +2020,11 @@ int NetAdhoc_SetSocketAlert(int id, s32_le flag) { // Flags seems to be bitmasks of ADHOC_F_ALERT... (need more games to test this) int sceNetAdhocSetSocketAlert(int id, int flag) { - WARN_LOG_REPORT_ONCE(sceNetAdhocSetSocketAlert, SCENET, "UNTESTED sceNetAdhocSetSocketAlert(%d, %08x) at %08x", id, flag, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocSetSocketAlert, Log::sceNet, "UNTESTED sceNetAdhocSetSocketAlert(%d, %08x) at %08x", id, flag, currentMIPS->pc); int retval = NetAdhoc_SetSocketAlert(id, flag); hleDelayResult(retval, "set socket alert delay", 1000); - return hleLogDebug(SCENET, retval, ""); + return hleLogDebug(Log::sceNet, retval, ""); } int PollAdhocSocket(SceNetAdhocPollSd* sds, int count, int timeout, int nonblock) { @@ -2122,7 +2123,7 @@ int PollAdhocSocket(SceNetAdhocPollSd* sds, int count, int timeout, int nonblock } int sceNetAdhocPollSocket(u32 socketStructAddr, int count, int timeout, int nonblock) { // timeout in microseconds - DEBUG_LOG_REPORT_ONCE(sceNetAdhocPollSocket, SCENET, "UNTESTED sceNetAdhocPollSocket(%08x, %i, %i, %i) at %08x", socketStructAddr, count, timeout, nonblock, currentMIPS->pc); + DEBUG_LOG_REPORT_ONCE(sceNetAdhocPollSocket, Log::sceNet, "UNTESTED sceNetAdhocPollSocket(%08x, %i, %i, %i) at %08x", socketStructAddr, count, timeout, nonblock, currentMIPS->pc); // Library is initialized if (netAdhocInited) { @@ -2136,7 +2137,7 @@ int sceNetAdhocPollSocket(u32 socketStructAddr, int count, int timeout, int nonb for (int i = 0; i < count; i++) { // Invalid Socket if (sds[i].id < 1 || sds[i].id > MAX_SOCKET || adhocSockets[sds[i].id - 1] == NULL) - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Nonblocking Mode @@ -2173,28 +2174,28 @@ int sceNetAdhocPollSocket(u32 socketStructAddr, int count, int timeout, int nonb if (sds[i].id > 0 && sds[i].id <= MAX_SOCKET && adhocSockets[sds[i].id - 1] != NULL) { auto sock = adhocSockets[sds[i].id - 1]; if (sock->type == SOCK_PTP) - VERBOSE_LOG(SCENET, "Poll PTP Socket Id: %d (%d), events: %08x, revents: %08x - state: %d", sds[i].id, sock->data.ptp.id, sds[i].events, sds[i].revents, sock->data.ptp.state); + VERBOSE_LOG(Log::sceNet, "Poll PTP Socket Id: %d (%d), events: %08x, revents: %08x - state: %d", sds[i].id, sock->data.ptp.id, sds[i].events, sds[i].revents, sock->data.ptp.state); else - VERBOSE_LOG(SCENET, "Poll PDP Socket Id: %d (%d), events: %08x, revents: %08x", sds[i].id, sock->data.pdp.id, sds[i].events, sds[i].revents); + VERBOSE_LOG(Log::sceNet, "Poll PDP Socket Id: %d (%d), events: %08x, revents: %08x", sds[i].id, sock->data.pdp.id, sds[i].events, sds[i].revents); } } } // Workaround to get 30 FPS instead of the too fast 60 FPS on Fate Unlimited Codes, it's abit absurd for a non-blocking call to have this much delay tho, and hleDelayResult doesn't works as good as hleEatMicro for this workaround. hleEatMicro(50); // hleEatMicro(7500); // normally 1ms, but using 7.5ms here seems to show better result for Bleach Heat the Soul 7 and other games with too high FPS, but may have a risk of slowing down games that already runs at normal FPS? (need more games to test this) - return hleLogDebug(SCENET, affectedsockets, "success"); + return hleLogDebug(Log::sceNet, affectedsockets, "success"); } //else if (nonblock && affectedsockets < 0) - // return hleLogDebug(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); // Is this error code valid for PollSocket? as it always returns 0 even when nonblock flag is set + // return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); // Is this error code valid for PollSocket? as it always returns 0 even when nonblock flag is set - return hleLogDebug(SCENET, ERROR_NET_ADHOC_EXCEPTION_EVENT, "exception event"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_EXCEPTION_EVENT, "exception event"); } // Invalid Argument - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); } // Library is uninitialized - return hleLogDebug(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); } int NetAdhocPdp_Delete(int id, int unknown) { @@ -2212,7 +2213,7 @@ int NetAdhocPdp_Delete(int id, int unknown) { sl.l_onoff = 1; // non-zero value enables linger option in kernel sl.l_linger = 0; // timeout interval in seconds setsockopt(sock->data.pdp.id, SOL_SOCKET, SO_LINGER, (const char*)&sl, sizeof(sl)); - shutdown(sock->data.pdp.id, SD_BOTH); + shutdown(sock->data.pdp.id, SD_RECEIVE); closesocket(sock->data.pdp.id); // Remove Port Forward from Router @@ -2249,7 +2250,7 @@ int NetAdhocPdp_Delete(int id, int unknown) { */ static int sceNetAdhocPdpDelete(int id, int unknown) { // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right? - INFO_LOG(SCENET, "sceNetAdhocPdpDelete(%d, %d) at %08x", id, unknown, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocPdpDelete(%d, %d) at %08x", id, unknown, currentMIPS->pc); /* if (!g_Config.bEnableWlan) { return 0; @@ -2260,24 +2261,24 @@ static int sceNetAdhocPdpDelete(int id, int unknown) { } static int sceNetAdhocctlGetAdhocId(u32 productStructAddr) { - INFO_LOG(SCENET, "sceNetAdhocctlGetAdhocId(%08x) at %08x", productStructAddr, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlGetAdhocId(%08x) at %08x", productStructAddr, currentMIPS->pc); if (!netAdhocctlInited) - return hleLogDebug(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); auto productStruct = PSPPointer::Create(productStructAddr); if (!productStruct.IsValid()) - return hleLogDebug(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); *productStruct = product_code; productStruct.NotifyWrite("NetAdhocctlGetAdhocId"); - return hleLogDebug(SCENET, 0, "type = %d, code = %s", product_code.type, product_code.data); + return hleLogDebug(Log::sceNet, 0, "type = %d, code = %s", product_code.type, product_code.data); } // FIXME: Scan probably not a blocking function since there is ADHOCCTL_STATE_SCANNING state that can be polled by the game, right? But apparently it need to be delayed for Naruto Shippuden Ultimate Ninja Heroes 3 int sceNetAdhocctlScan() { - INFO_LOG(SCENET, "sceNetAdhocctlScan() at %08x", currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlScan() at %08x", currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -2322,11 +2323,11 @@ int sceNetAdhocctlScan() { } // FIXME: Returning BUSY when previous adhocctl handler's callback is not fully executed yet, But returning success and notifying handler's callback with error (ie. ALREADY_CONNECTED) when previous adhocctl handler's callback is fully executed? Is there a case where error = BUSY sent through handler's callback? - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_BUSY, "busy"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_BUSY, "busy"); } // Library uninitialized - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); } int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { @@ -2335,7 +2336,7 @@ int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { SceNetAdhocctlScanInfoEmu *buf = NULL; if (Memory::IsValidAddress(bufAddr)) buf = (SceNetAdhocctlScanInfoEmu *)Memory::GetPointer(bufAddr); - INFO_LOG(SCENET, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x) at %08x", sizeAddr, Memory::Read_U32(sizeAddr), bufAddr, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x) at %08x", sizeAddr, Memory::Read_U32(sizeAddr), bufAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return 0; } @@ -2356,13 +2357,13 @@ int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { // FIXME: When already connected to a group GetScanInfo will return size = 0 ? or may be only hides the group created by it's self? if (adhocctlState == ADHOCCTL_STATE_CONNECTED || adhocctlState == ADHOCCTL_STATE_GAMEMODE) { *buflen = 0; - DEBUG_LOG(SCENET, "NetworkList [Available: 0] Already in a Group"); + DEBUG_LOG(Log::sceNet, "NetworkList [Available: 0] Already in a Group"); } // Length Returner Mode else if (buf == NULL) { int availNetworks = countAvailableNetworks(excludeSelf); *buflen = availNetworks * sizeof(SceNetAdhocctlScanInfoEmu); - DEBUG_LOG(SCENET, "NetworkList [Available: %i]", availNetworks); + DEBUG_LOG(Log::sceNet, "NetworkList [Available: %i]", availNetworks); } // Normal Information Mode else { @@ -2410,7 +2411,7 @@ int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr) { // Fix Size *buflen = discovered * sizeof(SceNetAdhocctlScanInfoEmu); - DEBUG_LOG(SCENET, "NetworkList [Requested: %i][Discovered: %i]", requestcount, discovered); + DEBUG_LOG(Log::sceNet, "NetworkList [Requested: %i][Discovered: %i]", requestcount, discovered); } // Multithreading Unlock @@ -2453,17 +2454,17 @@ static u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) { if (!foundHandler && Memory::IsValidAddress(handlerPtr)) { if (adhocctlHandlers.size() >= MAX_ADHOCCTL_HANDLERS) { - ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Too many handlers", handlerPtr, handlerArg); + ERROR_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Too many handlers", handlerPtr, handlerArg); retval = ERROR_NET_ADHOCCTL_TOO_MANY_HANDLERS; return retval; } adhocctlHandlers[retval] = handler; - WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): added handler %d", handlerPtr, handlerArg, retval); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): added handler %d", handlerPtr, handlerArg, retval); } else if(foundHandler) { - ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Same handler already exists", handlerPtr, handlerArg); + ERROR_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Same handler already exists", handlerPtr, handlerArg); retval = 0; //Faking success } else { - ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Invalid handler", handlerPtr, handlerArg); + ERROR_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Invalid handler", handlerPtr, handlerArg); retval = ERROR_NET_ADHOCCTL_INVALID_ARG; } @@ -2505,7 +2506,7 @@ u32 NetAdhocctl_Disconnect() { // Sending may get socket error 10053 if the AdhocServer is already shutted down if (iResult == SOCKET_ERROR) { if (error != EAGAIN && error != EWOULDBLOCK) { - ERROR_LOG(SCENET, "Socket error (%i) when sending", error); + ERROR_LOG(Log::sceNet, "Socket error (%i) when sending", error); // Set Disconnected State adhocctlState = ADHOCCTL_STATE_DISCONNECTED; } @@ -2529,7 +2530,7 @@ u32 NetAdhocctl_Disconnect() { // Clear Peer List, since games are moving to a different a group when the mission started may be we shouldn't free all peers yet int32_t peercount = 0; timeoutFriendsRecursive(friends, &peercount); - INFO_LOG(SCENET, "Marked for Timedout Peer List (%i)", peercount); + INFO_LOG(Log::sceNet, "Marked for Timedout Peer List (%i)", peercount); // Delete Peer Reference //friends = NULL; @@ -2561,20 +2562,20 @@ static u32 sceNetAdhocctlDisconnect() { char grpName[9] = { 0 }; memcpy(grpName, parameter.group_name.data, ADHOCCTL_GROUPNAME_LEN); // Copied to null-terminated var to prevent unexpected behaviour on Logs int ret = NetAdhocctl_Disconnect(); - INFO_LOG(SCENET, "%08x=sceNetAdhocctlDisconnect() at %08x [group=%s]", ret, currentMIPS->pc, grpName); + INFO_LOG(Log::sceNet, "%08x=sceNetAdhocctlDisconnect() at %08x [group=%s]", ret, currentMIPS->pc, grpName); return ret; } static u32 sceNetAdhocctlDelHandler(u32 handlerID) { if (!netAdhocctlInited) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "adhocctl not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "adhocctl not initialized"); if (adhocctlHandlers.find(handlerID) != adhocctlHandlers.end()) { adhocctlHandlers.erase(handlerID); - INFO_LOG(SCENET, "sceNetAdhocctlDelHandler(%d) at %08x", handlerID, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlDelHandler(%d) at %08x", handlerID, currentMIPS->pc); } else { - WARN_LOG(SCENET, "sceNetAdhocctlDelHandler(%d): Invalid Handler ID", handlerID); + WARN_LOG(Log::sceNet, "sceNetAdhocctlDelHandler(%d): Invalid Handler ID", handlerID); } return 0; @@ -2605,7 +2606,7 @@ int NetAdhocctl_Term() { // Clear Peer List int32_t peercount = 0; freeFriendsRecursive(friends, &peercount); - INFO_LOG(SCENET, "Cleared Peer List (%i)", peercount); + INFO_LOG(Log::sceNet, "Cleared Peer List (%i)", peercount); // Delete Peer Reference friends = NULL; //May also need to clear Handlers @@ -2632,7 +2633,7 @@ int NetAdhocctl_Term() { int sceNetAdhocctlTerm() { // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right? - INFO_LOG(SCENET, "sceNetAdhocctlTerm() at %08x", currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlTerm() at %08x", currentMIPS->pc); //if (netAdhocMatchingInited) NetAdhocMatching_Term(); int retval = NetAdhocctl_Term(); @@ -2642,7 +2643,7 @@ int sceNetAdhocctlTerm() { } static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { - DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocctlGetNameByAddr(%s, %08x) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), nameAddr, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlGetNameByAddr(%s, %08x) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), nameAddr, currentMIPS->pc); // Library initialized if (netAdhocctlInited) @@ -2661,7 +2662,7 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { // Write Data *nickname = parameter.nickname; - DEBUG_LOG(SCENET, "sceNetAdhocctlGetNameByAddr - [PlayerName:%s]", (char*)nickname); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctlGetNameByAddr - [PlayerName:%s]", (char*)nickname); // Return Success return 0; @@ -2685,7 +2686,7 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { // Multithreading Unlock peerlock.unlock(); - DEBUG_LOG(SCENET, "sceNetAdhocctlGetNameByAddr - [PeerName:%s]", (char*)nickname); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctlGetNameByAddr - [PeerName:%s]", (char*)nickname); // Return Success return 0; @@ -2695,7 +2696,7 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { // Multithreading Unlock peerlock.unlock(); - DEBUG_LOG(SCENET, "sceNetAdhocctlGetNameByAddr - PlayerName not found"); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctlGetNameByAddr - PlayerName not found"); // Player not found return ERROR_NET_ADHOC_NO_ENTRY; } @@ -2709,7 +2710,7 @@ static int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) { } int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) { - VERBOSE_LOG(SCENET, "sceNetAdhocctlGetPeerInfo(%s, %i, %08x) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), size, peerInfoAddr, currentMIPS->pc); + VERBOSE_LOG(Log::sceNet, "sceNetAdhocctlGetPeerInfo(%s, %i, %08x) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), size, peerInfoAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -2852,32 +2853,32 @@ int sceNetAdhocctlCreate(const char *groupName) { char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; if (groupName) memcpy(grpName, groupName, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated - INFO_LOG(SCENET, "sceNetAdhocctlCreate(%s) at %08x", grpName, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlCreate(%s) at %08x", grpName, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } adhocctlCurrentMode = ADHOCCTL_MODE_NORMAL; adhocConnectionType = ADHOC_CREATE; - return hleLogDebug(SCENET, NetAdhocctl_Create(groupName), ""); + return hleLogDebug(Log::sceNet, NetAdhocctl_Create(groupName), ""); } int sceNetAdhocctlConnect(const char* groupName) { char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; if (groupName) memcpy(grpName, groupName, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated - INFO_LOG(SCENET, "sceNetAdhocctlConnect(%s) at %08x", grpName, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlConnect(%s) at %08x", grpName, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } adhocctlCurrentMode = ADHOCCTL_MODE_NORMAL; adhocConnectionType = ADHOC_CONNECT; - return hleLogDebug(SCENET, NetAdhocctl_Create(groupName), ""); + return hleLogDebug(Log::sceNet, NetAdhocctl_Create(groupName), ""); } int sceNetAdhocctlJoin(u32 scanInfoAddr) { - INFO_LOG(SCENET, "sceNetAdhocctlJoin(%08x) at %08x", scanInfoAddr, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocctlJoin(%08x) at %08x", scanInfoAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -2891,13 +2892,13 @@ int sceNetAdhocctlJoin(u32 scanInfoAddr) { SceNetAdhocctlScanInfoEmu* sinfo = (SceNetAdhocctlScanInfoEmu*)Memory::GetPointer(scanInfoAddr); char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; memcpy(grpName, sinfo->group_name.data, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated - DEBUG_LOG(SCENET, "sceNetAdhocctlJoin - Group: %s", grpName); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctlJoin - Group: %s", grpName); // We can ignore minor connection process differences here // TODO: Adhoc Server may need to be changed to differentiate between Host/Create and Join, otherwise it can't support multiple Host using the same Group name, thus causing one of the Host to be confused being treated as Join. adhocctlCurrentMode = ADHOCCTL_MODE_NORMAL; adhocConnectionType = ADHOC_JOIN; - return hleLogDebug(SCENET, NetAdhocctl_Create(grpName), ""); + return hleLogDebug(Log::sceNet, NetAdhocctl_Create(grpName), ""); } // Invalid Argument @@ -2924,7 +2925,7 @@ int NetAdhocctl_CreateEnterGameMode(const char* group_name, int game_type, int n SceNetEtherAddr* addrs = PSPPointer::Create(membersAddr); // List of participating MAC addresses (started from host) for (int i = 0; i < num_members; i++) { requiredGameModeMacs.push_back(*addrs); - DEBUG_LOG(SCENET, "GameMode macAddress#%d=%s", i, mac2str(addrs).c_str()); + DEBUG_LOG(Log::sceNet, "GameMode macAddress#%d=%s", i, mac2str(addrs).c_str()); addrs++; } // Add local MAC (Host) first @@ -2964,9 +2965,9 @@ static int sceNetAdhocctlCreateEnterGameMode(const char * group_name, int game_t char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; if (group_name) memcpy(grpName, group_name, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated - WARN_LOG_REPORT_ONCE(sceNetAdhocctlCreateEnterGameMode, SCENET, "UNTESTED sceNetAdhocctlCreateEnterGameMode(%s, %i, %i, %08x, %i, %i) at %08x", grpName, game_type, num_members, membersAddr, timeout, flag, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocctlCreateEnterGameMode, Log::sceNet, "UNTESTED sceNetAdhocctlCreateEnterGameMode(%s, %i, %i, %08x, %i, %i) at %08x", grpName, game_type, num_members, membersAddr, timeout, flag, currentMIPS->pc); - return hleLogDebug(SCENET, NetAdhocctl_CreateEnterGameMode(group_name, game_type, num_members, membersAddr, timeout, flag), ""); + return hleLogDebug(Log::sceNet, NetAdhocctl_CreateEnterGameMode(group_name, game_type, num_members, membersAddr, timeout, flag), ""); } /** @@ -2983,13 +2984,13 @@ static int sceNetAdhocctlJoinEnterGameMode(const char * group_name, const char * char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; if (group_name) memcpy(grpName, group_name, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated - WARN_LOG_REPORT_ONCE(sceNetAdhocctlJoinEnterGameMode, SCENET, "UNTESTED sceNetAdhocctlJoinEnterGameMode(%s, %s, %i, %i) at %08x", grpName, mac2str((SceNetEtherAddr*)hostMac).c_str(), timeout, flag, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocctlJoinEnterGameMode, Log::sceNet, "UNTESTED sceNetAdhocctlJoinEnterGameMode(%s, %s, %i, %i) at %08x", grpName, mac2str((SceNetEtherAddr*)hostMac).c_str(), timeout, flag, currentMIPS->pc); if (!netAdhocctlInited) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); if (!hostMac) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); deleteAllGMB(); @@ -3007,7 +3008,7 @@ static int sceNetAdhocctlJoinEnterGameMode(const char * group_name, const char * adhocConnectionType = ADHOC_JOIN; netAdhocGameModeEntered = true; netAdhocEnterGameModeTimeout = timeout; - return hleLogDebug(SCENET, NetAdhocctl_Create(group_name), ""); + return hleLogDebug(Log::sceNet, NetAdhocctl_Create(group_name), ""); } /** @@ -3025,9 +3026,9 @@ int sceNetAdhocctlCreateEnterGameModeMin(const char *group_name, int game_type, char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; if (group_name) memcpy(grpName, group_name, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated - WARN_LOG_REPORT_ONCE(sceNetAdhocctlCreateEnterGameModeMin, SCENET, "UNTESTED sceNetAdhocctlCreateEnterGameModeMin(%s, %i, %i, %i, %08x, %d, %i) at %08x", grpName, game_type, min_members, num_members, membersAddr, timeout, flag, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocctlCreateEnterGameModeMin, Log::sceNet, "UNTESTED sceNetAdhocctlCreateEnterGameModeMin(%s, %i, %i, %i, %08x, %d, %i) at %08x", grpName, game_type, min_members, num_members, membersAddr, timeout, flag, currentMIPS->pc); // We don't really need the Minimum User Check - return hleLogDebug(SCENET, NetAdhocctl_CreateEnterGameMode(group_name, game_type, num_members, membersAddr, timeout, flag), ""); + return hleLogDebug(Log::sceNet, NetAdhocctl_CreateEnterGameMode(group_name, game_type, num_members, membersAddr, timeout, flag), ""); } int NetAdhoc_Term() { @@ -3053,12 +3054,12 @@ int NetAdhoc_Term() { // Library shutdown netAdhocInited = false; - //return hleLogSuccessInfoI(SCENET, 0); + //return hleLogSuccessInfoI(Log::sceNet, 0); } /*else { // TODO: Reportedly returns SCE_KERNEL_ERROR_LWMUTEX_NOT_FOUND in some cases? // Only seen returning 0 in tests. - return hleLogWarning(SCENET, 0, "already uninitialized"); + return hleLogWarning(Log::sceNet, 0, "already uninitialized"); }*/ return 0; @@ -3069,11 +3070,11 @@ int sceNetAdhocTerm() { int retval = NetAdhoc_Term(); hleEatMicro(adhocDefaultDelay); - return hleLogSuccessInfoI(SCENET, retval); + return hleLogSuccessInfoI(Log::sceNet, retval); } static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { - VERBOSE_LOG(SCENET, "sceNetAdhocGetPdpStat(%08x, %08x) at %08x", structSize, structAddr, currentMIPS->pc); + VERBOSE_LOG(Log::sceNet, "sceNetAdhocGetPdpStat(%08x, %08x) at %08x", structSize, structAddr, currentMIPS->pc); // Library is initialized if (netAdhocInited) @@ -3091,7 +3092,7 @@ static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { { // Return Required Size *buflen = sizeof(SceNetAdhocPdpStat) * socketcount; - VERBOSE_LOG(SCENET, "Stat PDP Socket Count: %d", socketcount); + VERBOSE_LOG(Log::sceNet, "Stat PDP Socket Count: %d", socketcount); // Success return 0; @@ -3143,7 +3144,7 @@ static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { if (i > 0) buf[i - 1].next = structAddr + (i * sizeof(SceNetAdhocPdpStat)); - VERBOSE_LOG(SCENET, "Stat PDP Socket Id: %d (%d), LPort: %d, RecvSbCC: %d", buf[i].id, sock->data.pdp.id, buf[i].lport, buf[i].rcv_sb_cc); + VERBOSE_LOG(Log::sceNet, "Stat PDP Socket Id: %d (%d), LPort: %d, RecvSbCC: %d", buf[i].id, sock->data.pdp.id, buf[i].lport, buf[i].rcv_sb_cc); // Increment Counter i++; @@ -3159,11 +3160,11 @@ static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { } // Invalid Arguments - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg, at %08x", currentMIPS->pc); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg, at %08x", currentMIPS->pc); } // Library is uninitialized - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized, at %08x", currentMIPS->pc); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized, at %08x", currentMIPS->pc); } @@ -3175,7 +3176,7 @@ static int sceNetAdhocGetPdpStat(u32 structSize, u32 structAddr) { */ static int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) { // Spams a lot - VERBOSE_LOG(SCENET,"sceNetAdhocGetPtpStat(%08x, %08x) at %08x",structSize,structAddr,currentMIPS->pc); + VERBOSE_LOG(Log::sceNet,"sceNetAdhocGetPtpStat(%08x, %08x) at %08x",structSize,structAddr,currentMIPS->pc); s32_le *buflen = NULL; if (Memory::IsValidAddress(structSize)) buflen = (s32_le *)Memory::GetPointer(structSize); @@ -3191,7 +3192,7 @@ static int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) { if (buflen != NULL && buf == NULL) { // Return Required Size *buflen = sizeof(SceNetAdhocPtpStat) * socketcount; - VERBOSE_LOG(SCENET, "Stat PTP Socket Count: %d", socketcount); + VERBOSE_LOG(Log::sceNet, "Stat PTP Socket Count: %d", socketcount); // Success return 0; @@ -3251,7 +3252,7 @@ static int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) { if (i > 0) buf[i - 1].next = structAddr + (i * sizeof(SceNetAdhocPtpStat)); - VERBOSE_LOG(SCENET, "Stat PTP Socket Id: %d (%d), LPort: %d, RecvSbCC: %d, State: %d", buf[i].id, sock->data.ptp.id, buf[i].lport, buf[i].rcv_sb_cc, buf[i].state); + VERBOSE_LOG(Log::sceNet, "Stat PTP Socket Id: %d (%d), LPort: %d, RecvSbCC: %d, State: %d", buf[i].id, sock->data.ptp.id, buf[i].lport, buf[i].rcv_sb_cc, buf[i].state); // Increment Counter i++; @@ -3267,11 +3268,11 @@ static int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) { } // Invalid Arguments - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg, at %08x", currentMIPS->pc); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg, at %08x", currentMIPS->pc); } // Library is uninitialized - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized, at %08x", currentMIPS->pc); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized, at %08x", currentMIPS->pc); } @@ -3336,7 +3337,7 @@ int RecreatePtpSocket(int ptpId) { // Bound Socket to local Port if (bind(tcpsocket, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { - ERROR_LOG(SCENET, "RecreatePtpSocket(%i) - Socket error (%i) when binding port %u", ptpId, errno, ntohs(addr.sin_port)); + ERROR_LOG(Log::sceNet, "RecreatePtpSocket(%i) - Socket error (%i) when binding port %u", ptpId, errno, ntohs(addr.sin_port)); } else { // Update sport with the port assigned internal->lport = ntohs(local.sin_port) @@ -3344,17 +3345,17 @@ int RecreatePtpSocket(int ptpId) { if (getsockname(tcpsocket, (struct sockaddr*)&addr, &len) == 0) { uint16_t boundport = ntohs(addr.sin_port); if (sock->data.ptp.lport + static_cast(portOffset) >= 65536 || static_cast(boundport) - static_cast(portOffset) <= 0) - WARN_LOG(SCENET, "RecreatePtpSocket(%i) - Wrapped Port Detected: Original(%d) -> Requested(%d), Bound(%d) -> BoundOriginal(%d)", ptpId, sock->data.ptp.lport, requestedport, boundport, boundport - portOffset); + WARN_LOG(Log::sceNet, "RecreatePtpSocket(%i) - Wrapped Port Detected: Original(%d) -> Requested(%d), Bound(%d) -> BoundOriginal(%d)", ptpId, sock->data.ptp.lport, requestedport, boundport, boundport - portOffset); u16 newlport = boundport - portOffset; if (newlport != sock->data.ptp.lport) { - WARN_LOG(SCENET, "RecreatePtpSocket(%i) - Old and New LPort is different! The port may need to be reforwarded", ptpId); + WARN_LOG(Log::sceNet, "RecreatePtpSocket(%i) - Old and New LPort is different! The port may need to be reforwarded", ptpId); if (!sock->isClient) UPnP_Add(IP_PROTOCOL_TCP, isOriPort ? newlport : newlport + portOffset, newlport + portOffset); } sock->data.ptp.lport = newlport; } else { - WARN_LOG(SCENET, "RecreatePtpSocket(%i): getsockname error %i", ptpId, errno); + WARN_LOG(Log::sceNet, "RecreatePtpSocket(%i): getsockname error %i", ptpId, errno); } } @@ -3377,7 +3378,7 @@ int RecreatePtpSocket(int ptpId) { * @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT */ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, int dport, int bufsize, int rexmt_int, int rexmt_cnt, int flag) { - INFO_LOG(SCENET, "sceNetAdhocPtpOpen(%s, %d, %s, %d, %d, %d, %d, %d) at %08x", mac2str((SceNetEtherAddr*)srcmac).c_str(), sport, mac2str((SceNetEtherAddr*)dstmac).c_str(),dport,bufsize, rexmt_int, rexmt_cnt, flag, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocPtpOpen(%s, %d, %s, %d, %d, %d, %d, %d) at %08x", mac2str((SceNetEtherAddr*)srcmac).c_str(), sport, mac2str((SceNetEtherAddr*)dstmac).c_str(),dport,bufsize, rexmt_int, rexmt_cnt, flag, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -3395,7 +3396,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, // Dissidia 012 will try to reOpen the port without Closing the old one first when PtpConnect failed to try again. if (isPTPPortInUse(sport, false, daddr, dport)) { // FIXME: When PORT_IN_USE error occured it seems the index to the socket id also increased, which means it tries to create & bind the socket first and then closes it due to failed to bind - return hleLogDebug(SCENET, ERROR_NET_ADHOC_PORT_IN_USE, "port in use"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_PORT_IN_USE, "port in use"); } // Random Port required @@ -3448,7 +3449,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, requestedport = 65535; // Hopefully it will be safe to default it to 65535 since there can't be more than one port that can bumped into 65536 // Show a warning about privileged ports if (requestedport != 0 && requestedport < 1024) { - WARN_LOG(SCENET, "sceNetAdhocPtpOpen - Ports below 1024(ie. %hu) may require Admin Privileges", requestedport); + WARN_LOG(Log::sceNet, "sceNetAdhocPtpOpen - Ports below 1024(ie. %hu) may require Admin Privileges", requestedport); } addr.sin_port = htons(requestedport); @@ -3459,7 +3460,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, if (getsockname(tcpsocket, (struct sockaddr*)&addr, &len) == 0) { uint16_t boundport = ntohs(addr.sin_port); if (sport + static_cast(portOffset) >= 65536 || static_cast(boundport) - static_cast(portOffset) <= 0) - WARN_LOG(SCENET, "sceNetAdhocPtpOpen - Wrapped Port Detected: Original(%d) -> Requested(%d), Bound(%d) -> BoundOriginal(%d)", sport, requestedport, boundport, boundport - portOffset); + WARN_LOG(Log::sceNet, "sceNetAdhocPtpOpen - Wrapped Port Detected: Original(%d) -> Requested(%d), Bound(%d) -> BoundOriginal(%d)", sport, requestedport, boundport, boundport - portOffset); sport = boundport - portOffset; } @@ -3515,7 +3516,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, hleDelayResult(i + 1, "delayed ptpopen", rexmt_int); // Return PTP Socket id - INFO_LOG(SCENET, "sceNetAdhocPtpOpen - PSP Socket id: %i, Host Socket id: %i", i + 1, tcpsocket); + INFO_LOG(Log::sceNet, "sceNetAdhocPtpOpen - PSP Socket id: %i, Host Socket id: %i", i + 1, tcpsocket); return i + 1; } @@ -3524,7 +3525,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, } } else { - ERROR_LOG(SCENET, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port)); + ERROR_LOG(Log::sceNet, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port)); auto n = GetI18NCategory(I18NCat::NETWORKING); g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to Bind Port")) + " " + std::to_string(sport + portOffset) + "\n" + std::string(n->T("Please change your Port Offset"))); } @@ -3533,20 +3534,20 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, closesocket(tcpsocket); // Port not available (exclusively in use?) - return hleLogDebug(SCENET, ERROR_NET_ADHOC_PORT_NOT_AVAIL, "port not available"); // ERROR_NET_ADHOC_PORT_IN_USE; // ERROR_NET_ADHOC_INVALID_PORT; + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_PORT_NOT_AVAIL, "port not available"); // ERROR_NET_ADHOC_PORT_IN_USE; // ERROR_NET_ADHOC_INVALID_PORT; } } // Invalid Arguments - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); } // Invalid Addresses - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); // ERROR_NET_ADHOC_INVALID_ARG; + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); // ERROR_NET_ADHOC_INVALID_ARG; } // Library is uninitialized - return hleLogDebug(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); } // On a POSIX accept, returned socket may inherits properties from the listening socket, does PtpAccept also have similar behavior? @@ -3641,7 +3642,7 @@ int AcceptPtpSocket(int ptpId, int newsocket, sockaddr_in& peeraddr, SceNetEther // Switch to non-blocking for futher usage changeBlockingMode(newsocket, 1); - INFO_LOG(SCENET, "sceNetAdhocPtpAccept[%i->%i(%i):%u]: Established (%s:%u) - state: %d", ptpId, i + 1, newsocket, internal->data.ptp.lport, ip2str(peeraddr.sin_addr).c_str(), internal->data.ptp.pport, internal->data.ptp.state); + INFO_LOG(Log::sceNet, "sceNetAdhocPtpAccept[%i->%i(%i):%u]: Established (%s:%u) - state: %d", ptpId, i + 1, newsocket, internal->data.ptp.lport, ip2str(peeraddr.sin_addr).c_str(), internal->data.ptp.pport, internal->data.ptp.state); // Return Socket return i + 1; @@ -3656,7 +3657,7 @@ int AcceptPtpSocket(int ptpId, int newsocket, sockaddr_in& peeraddr, SceNetEther // Close Socket closesocket(newsocket); - ERROR_LOG(SCENET, "sceNetAdhocPtpAccept[%i]: Failed (Socket Closed)", ptpId); + ERROR_LOG(Log::sceNet, "sceNetAdhocPtpAccept[%i]: Failed (Socket Closed)", ptpId); return -1; } @@ -3680,9 +3681,9 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int port = (uint16_t *)Memory::GetPointer(peerPortPtr); } if (flag == 0) { // Prevent spamming Debug Log with retries of non-bocking socket - DEBUG_LOG(SCENET, "sceNetAdhocPtpAccept(%d, [%08x]=%s, [%08x]=%u, %d, %u) at %08x", id, peerMacAddrPtr, mac2str(addr).c_str(), peerPortPtr, port ? *port : -1, timeout, flag, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpAccept(%d, [%08x]=%s, [%08x]=%u, %d, %u) at %08x", id, peerMacAddrPtr, mac2str(addr).c_str(), peerPortPtr, port ? *port : -1, timeout, flag, currentMIPS->pc); } else { - VERBOSE_LOG(SCENET, "sceNetAdhocPtpAccept(%d, [%08x]=%s, [%08x]=%u, %d, %u) at %08x", id, peerMacAddrPtr, mac2str(addr).c_str(), peerPortPtr, port ? *port : -1, timeout, flag, currentMIPS->pc); + VERBOSE_LOG(Log::sceNet, "sceNetAdhocPtpAccept(%d, [%08x]=%s, [%08x]=%u, %d, %u) at %08x", id, peerMacAddrPtr, mac2str(addr).c_str(), peerPortPtr, port ? *port : -1, timeout, flag, currentMIPS->pc); } if (!g_Config.bEnableWlan) { return -1; @@ -3702,7 +3703,7 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int if (socket->flags & ADHOC_F_ALERTACCEPT) { socket->alerted_flags |= ADHOC_F_ALERTACCEPT; - return hleLogError(SCENET, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); } // Listener Socket @@ -3730,7 +3731,7 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int } // Prevent spamming Debug Log with retries of non-bocking socket else { - VERBOSE_LOG(SCENET, "sceNetAdhocPtpAccept[%i]: Socket Error (%i)", id, error); + VERBOSE_LOG(Log::sceNet, "sceNetAdhocPtpAccept[%i]: Socket Error (%i)", id, error); } } @@ -3743,26 +3744,26 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int // Action would block if (flag) - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); // Timeout - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_TIMEOUT, "timeout"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_TIMEOUT, "timeout"); } // Client Socket - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_NOT_LISTENED, "not listened"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_NOT_LISTENED, "not listened"); } // Invalid Socket - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Invalid Arguments - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); } // Library is uninitialized - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); } int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) { @@ -3779,7 +3780,7 @@ int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) if (socket->flags & ADHOC_F_ALERTCONNECT) { socket->alerted_flags |= ADHOC_F_ALERTCONNECT; - return hleLogError(SCENET, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); } // Phantasy Star Portable 2 will try to reconnect even when previous connect already success, so we should return success too if it's already connected @@ -3813,9 +3814,9 @@ int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) if (connectresult == SOCKET_ERROR) { if (errorcode == EAGAIN || errorcode == EWOULDBLOCK || errorcode == EALREADY || errorcode == EISCONN) - DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i]: Socket Error (%i) to %s:%u", id, errorcode, ip2str(sin.sin_addr).c_str(), ptpsocket.pport); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i]: Socket Error (%i) to %s:%u", id, errorcode, ip2str(sin.sin_addr).c_str(), ptpsocket.pport); else - ERROR_LOG(SCENET, "sceNetAdhocPtpConnect[%i]: Socket Error (%i) to %s:%u", id, errorcode, ip2str(sin.sin_addr).c_str(), ptpsocket.pport); + ERROR_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i]: Socket Error (%i) to %s:%u", id, errorcode, ip2str(sin.sin_addr).c_str(), ptpsocket.pport); } // Instant Connection (Lucky!) @@ -3826,7 +3827,7 @@ int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) // Set Connected State ptpsocket.state = ADHOC_PTP_STATE_ESTABLISHED; - INFO_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Already Connected to %s:%u", id, ptpsocket.lport, ip2str(sin.sin_addr).c_str(), ptpsocket.pport); + INFO_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: Already Connected to %s:%u", id, ptpsocket.lport, ip2str(sin.sin_addr).c_str(), ptpsocket.pport); // Success return 0; } @@ -3842,9 +3843,9 @@ int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) } // On Windows you can call connect again using the same socket after ECONNREFUSED/ETIMEDOUT/ENETUNREACH error, but on non-Windows you'll need to recreate the socket first else { - DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Recreating Socket %i, errno = %i, state = %i, attempt = %i", id, ptpsocket.lport, ptpsocket.id, errorcode, ptpsocket.state, socket->attemptCount); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: Recreating Socket %i, errno = %i, state = %i, attempt = %i", id, ptpsocket.lport, ptpsocket.id, errorcode, ptpsocket.state, socket->attemptCount); if (RecreatePtpSocket(id) < 0) { - WARN_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Failed to Recreate Socket", id, ptpsocket.lport); + WARN_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: Failed to Recreate Socket", id, ptpsocket.lport); } ptpsocket.state = ADHOC_PTP_STATE_CLOSED; } @@ -3857,8 +3858,8 @@ int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) // Simulate blocking behaviour with non-blocking socket u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id; if (sendTargetPeers.find(threadSocketId) != sendTargetPeers.end()) { - DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect[%i:%u]: Socket(%d) is Busy!", id, ptpsocket.lport, ptpsocket.id); - return hleLogError(SCENET, ERROR_NET_ADHOC_BUSY, "busy?"); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpConnect[%i:%u]: Socket(%d) is Busy!", id, ptpsocket.lport, ptpsocket.id); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_BUSY, "busy?"); } AdhocSendTargets dest = { 0, {}, false }; @@ -3869,26 +3870,26 @@ int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) // NonBlocking Mode else { // Returning WOULD_BLOCK as Workaround for ERROR_NET_ADHOC_CONNECTION_REFUSED to be more cross-platform, since there is no way to simulate ERROR_NET_ADHOC_CONNECTION_REFUSED properly on Windows - return hleLogDebug(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); } } } } // Peer not found - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); // ERROR_NET_ADHOC_WOULD_BLOCK / ERROR_NET_ADHOC_TIMEOUT + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); // ERROR_NET_ADHOC_WOULD_BLOCK / ERROR_NET_ADHOC_TIMEOUT } // Not a valid Client Socket - return hleLogDebug(SCENET, ERROR_NET_ADHOC_NOT_OPENED, "not opened"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_NOT_OPENED, "not opened"); } // Invalid Socket - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Library is uninitialized - return hleLogDebug(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); } /** @@ -3899,7 +3900,7 @@ int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) * @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_CONNECTION_REFUSED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_OPENED, ADHOC_THREAD_ABORTED, NET_INTERNAL */ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) { - INFO_LOG(SCENET, "sceNetAdhocPtpConnect(%i, %i, %i) at %08x", id, timeout, flag, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocPtpConnect(%i, %i, %i) at %08x", id, timeout, flag, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -3922,7 +3923,7 @@ int NetAdhocPtp_Close(int id, int unknown) { sl.l_onoff = 1; // non-zero value enables linger option in kernel sl.l_linger = 0; // timeout interval in seconds setsockopt(socket->data.ptp.id, SOL_SOCKET, SO_LINGER, (const char*)&sl, sizeof(sl)); - shutdown(socket->data.ptp.id, SD_BOTH); + shutdown(socket->data.ptp.id, SD_RECEIVE); closesocket(socket->data.ptp.id); // Remove Port Forward from Router @@ -3957,7 +3958,7 @@ int NetAdhocPtp_Close(int id, int unknown) { * @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED */ static int sceNetAdhocPtpClose(int id, int unknown) { - INFO_LOG(SCENET,"sceNetAdhocPtpClose(%d,%d) at %08x",id,unknown,currentMIPS->pc); + INFO_LOG(Log::sceNet,"sceNetAdhocPtpClose(%d,%d) at %08x",id,unknown,currentMIPS->pc); /*if (!g_Config.bEnableWlan) { return 0; }*/ @@ -3978,7 +3979,7 @@ static int sceNetAdhocPtpClose(int id, int unknown) { * @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT, ADHOC_SOCKET_ID_NOT_AVAIL, ADHOC_PORT_NOT_AVAIL, ADHOC_PORT_IN_USE, NET_NO_SPACE */ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int rexmt_int, int rexmt_cnt, int backlog, int flag) { - INFO_LOG(SCENET, "sceNetAdhocPtpListen(%s, %d, %d, %d, %d, %d, %d) at %08x", mac2str((SceNetEtherAddr*)srcmac).c_str(), sport,bufsize,rexmt_int,rexmt_cnt,backlog,flag, currentMIPS->pc); + INFO_LOG(Log::sceNet, "sceNetAdhocPtpListen(%s, %d, %d, %d, %d, %d, %d) at %08x", mac2str((SceNetEtherAddr*)srcmac).c_str(), sport,bufsize,rexmt_int,rexmt_cnt,backlog,flag, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -3995,7 +3996,7 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int // It's allowed to Listen and Open the same PTP port, But it's not allowed to Listen or Open the same PTP port twice. if (isPTPPortInUse(sport, true)) { // FIXME: When PORT_IN_USE error occured it seems the index to the socket id also increased, which means it tries to create & bind the socket first and then closes it due to failed to bind - return hleLogDebug(SCENET, ERROR_NET_ADHOC_PORT_IN_USE, "port in use"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_PORT_IN_USE, "port in use"); } // Random Port required @@ -4048,7 +4049,7 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int requestedport = 65535; // Hopefully it will be safe to default it to 65535 since there can't be more than one port that can bumped into 65536 // Show a warning about privileged ports if (requestedport != 0 && requestedport < 1024) { - WARN_LOG(SCENET, "sceNetAdhocPtpListen - Ports below 1024(ie. %hu) may require Admin Privileges", requestedport); + WARN_LOG(Log::sceNet, "sceNetAdhocPtpListen - Ports below 1024(ie. %hu) may require Admin Privileges", requestedport); } addr.sin_port = htons(requestedport); @@ -4060,7 +4061,7 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int if (getsockname(tcpsocket, (struct sockaddr*)&addr, &len) == 0) { uint16_t boundport = ntohs(addr.sin_port); if (sport + static_cast(portOffset) >= 65536 || static_cast(boundport) - static_cast(portOffset) <= 0) - WARN_LOG(SCENET, "sceNetAdhocPtpListen - Wrapped Port Detected: Original(%d) -> Requested(%d), Bound(%d) -> BoundOriginal(%d)", sport, requestedport, boundport, boundport - portOffset); + WARN_LOG(Log::sceNet, "sceNetAdhocPtpListen - Wrapped Port Detected: Original(%d) -> Requested(%d), Bound(%d) -> BoundOriginal(%d)", sport, requestedport, boundport, boundport - portOffset); sport = boundport - portOffset; } // Switch into Listening Mode @@ -4109,7 +4110,7 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int changeBlockingMode(tcpsocket, 1); // Return PTP Socket id - INFO_LOG(SCENET, "sceNetAdhocPtpListen - PSP Socket id: %i, Host Socket id: %i", i + 1, tcpsocket); + INFO_LOG(Log::sceNet, "sceNetAdhocPtpListen - PSP Socket id: %i, Host Socket id: %i", i + 1, tcpsocket); return i + 1; } @@ -4125,30 +4126,30 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int if (iResult == SOCKET_ERROR) { int error = errno; - ERROR_LOG(SCENET, "sceNetAdhocPtpListen[%i]: Socket Error (%i)", sport, error); + ERROR_LOG(Log::sceNet, "sceNetAdhocPtpListen[%i]: Socket Error (%i)", sport, error); } // Close Socket closesocket(tcpsocket); // Port not available (exclusively in use?) - return hleLogDebug(SCENET, ERROR_NET_ADHOC_PORT_NOT_AVAIL, "port not available"); //ERROR_NET_ADHOC_PORT_IN_USE; // ERROR_NET_ADHOC_INVALID_PORT; + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_PORT_NOT_AVAIL, "port not available"); //ERROR_NET_ADHOC_PORT_IN_USE; // ERROR_NET_ADHOC_INVALID_PORT; } // Socket not available - return hleLogDebug(SCENET, ERROR_NET_ADHOC_SOCKET_ID_NOT_AVAIL, "socket id not available"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_SOCKET_ID_NOT_AVAIL, "socket id not available"); } // Invalid Arguments - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); } // Invalid Addresses - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ADDR, "invalid address"); } // Library is uninitialized - return hleLogDebug(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "adhoc not initialized"); } /** @@ -4161,7 +4162,7 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int * @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_CONNECTED, ADHOC_THREAD_ABORTED, ADHOC_INVALID_DATALEN, ADHOC_DISCONNECTED, NET_INTERNAL, NET_NO_SPACE */ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeout, int flag) { - DEBUG_LOG(SCENET, "sceNetAdhocPtpSend(%d,%08x,%08x,%d,%d) at %08x", id, dataAddr, dataSizeAddr, timeout, flag, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpSend(%d,%08x,%08x,%d,%d) at %08x", id, dataAddr, dataSizeAddr, timeout, flag, currentMIPS->pc); int * len = (int *)Memory::GetPointer(dataSizeAddr); const char * data = Memory::GetCharPointer(dataAddr); @@ -4188,7 +4189,7 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou if (socket->flags & ADHOC_F_ALERTSEND) { socket->alerted_flags |= ADHOC_F_ALERTSEND; - return hleLogError(SCENET, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); } // Acquire Network Lock @@ -4207,7 +4208,7 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou // Save Length *len = sent; - DEBUG_LOG(SCENET, "sceNetAdhocPtpSend[%i:%u]: Sent %u bytes to %s:%u\n", id, ptpsocket.lport, sent, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpSend[%i:%u]: Sent %u bytes to %s:%u\n", id, ptpsocket.lport, sent, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); // Set to Established on successful Send when an attempt to Connect was initiated if (ptpsocket.state == ADHOC_PTP_STATE_SYN_SENT) @@ -4221,36 +4222,36 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou else if (sent == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK || (ptpsocket.state == ADHOC_PTP_STATE_SYN_SENT && (error == ENOTCONN || connectInProgress(error))))) { // Non-Blocking if (flag) - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); // Simulate blocking behaviour with non-blocking socket u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id; return WaitBlockingAdhocSocket(threadSocketId, PTP_SEND, id, (void*)data, len, timeout, nullptr, nullptr, "ptp send"); } - DEBUG_LOG(SCENET, "sceNetAdhocPtpSend[%i:%u -> %s:%u]: Result:%i (Error:%i)", id, ptpsocket.lport, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport, sent, error); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpSend[%i:%u -> %s:%u]: Result:%i (Error:%i)", id, ptpsocket.lport, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport, sent, error); // Change Socket State ptpsocket.state = ADHOC_PTP_STATE_CLOSED; // Disconnected - return hleLogError(SCENET, ERROR_NET_ADHOC_DISCONNECTED, "disconnected"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_DISCONNECTED, "disconnected"); } // Invalid Arguments - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); } // Not Connected - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CONNECTED, "not connected"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_CONNECTED, "not connected"); } // Invalid Socket - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Library is uninitialized - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); } /** @@ -4263,7 +4264,7 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou * @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_DISCONNECTED, NET_INTERNAL */ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeout, int flag) { - DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv(%d,%08x,%08x,%d,%d) at %08x", id, dataAddr, dataSizeAddr, timeout, flag, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpRecv(%d,%08x,%08x,%d,%d) at %08x", id, dataAddr, dataSizeAddr, timeout, flag, currentMIPS->pc); void * buf = (void *)Memory::GetPointer(dataAddr); int * len = (int *)Memory::GetPointer(dataSizeAddr); @@ -4289,7 +4290,7 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou if (socket->flags & ADHOC_F_ALERTRECV) { socket->alerted_flags |= ADHOC_F_ALERTRECV; - return hleLogError(SCENET, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); } // Acquire Network Lock @@ -4310,7 +4311,7 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou return WaitBlockingAdhocSocket(threadSocketId, PTP_RECV, id, buf, len, timeout, nullptr, nullptr, "ptp recv"); } - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); } // Free Network Lock @@ -4329,7 +4330,7 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou if (peer != NULL) peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); peerlock.unlock(); - DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv[%i:%u]: Received %u bytes from %s:%u\n", id, ptpsocket.lport, received, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpRecv[%i:%u]: Received %u bytes from %s:%u\n", id, ptpsocket.lport, received, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport); // Set to Established on successful Recv when an attempt to Connect was initiated if (ptpsocket.state == ADHOC_PTP_STATE_SYN_SENT) @@ -4339,7 +4340,7 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou return 0; } - DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv[%i:%u]: Result:%i (Error:%i)", id, ptpsocket.lport, received, error); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpRecv[%i:%u]: Result:%i (Error:%i)", id, ptpsocket.lport, received, error); if (*len == 0) return 0; @@ -4348,23 +4349,23 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou ptpsocket.state = ADHOC_PTP_STATE_CLOSED; // Disconnected - return hleLogError(SCENET, ERROR_NET_ADHOC_DISCONNECTED, "disconnected"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_DISCONNECTED, "disconnected"); } // Not Connected - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CONNECTED, "not connected"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_CONNECTED, "not connected"); } // Invalid Socket - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Invalid Arguments - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid socket arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid socket arg"); } // Library is uninitialized - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); } int FlushPtpSocket(int socketId) { @@ -4394,7 +4395,7 @@ int FlushPtpSocket(int socketId) { * @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_DISCONNECTED, ADHOC_NOT_CONNECTED, NET_INTERNAL */ static int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) { - DEBUG_LOG(SCENET,"sceNetAdhocPtpFlush(%d,%d,%d) at %08x", id, timeout, nonblock, currentMIPS->pc); + DEBUG_LOG(Log::sceNet,"sceNetAdhocPtpFlush(%d,%d,%d) at %08x", id, timeout, nonblock, currentMIPS->pc); // Library initialized if (netAdhocInited) { @@ -4408,7 +4409,7 @@ static int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) { if (socket->flags & ADHOC_F_ALERTFLUSH) { socket->alerted_flags |= ADHOC_F_ALERTFLUSH; - return hleLogError(SCENET, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_SOCKET_ALERTED, "socket alerted"); } // Connected Socket @@ -4423,7 +4424,7 @@ static int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) { if (error == EAGAIN || error == EWOULDBLOCK) { // Non-Blocking if (nonblock) - return hleLogSuccessVerboseX(SCENET, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); + return hleLogSuccessVerboseX(Log::sceNet, ERROR_NET_ADHOC_WOULD_BLOCK, "would block"); // Simulate blocking behaviour with non-blocking socket u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id; @@ -4431,7 +4432,7 @@ static int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) { } if (error != 0) - DEBUG_LOG(SCENET, "sceNetAdhocPtpFlush[%i:%u -> %s:%u]: Error:%i", id, ptpsocket.lport, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport, error); + DEBUG_LOG(Log::sceNet, "sceNetAdhocPtpFlush[%i:%u -> %s:%u]: Error:%i", id, ptpsocket.lport, mac2str(&ptpsocket.paddr).c_str(), ptpsocket.pport, error); } // Dummy Result, Always success? @@ -4439,10 +4440,10 @@ static int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) { } // Invalid Socket - return hleLogError(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); } // Library uninitialized - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_INITIALIZED, "not initialized"); } /** @@ -4454,21 +4455,21 @@ static int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) { * @return 0 on success, < 0 on error. */ static int sceNetAdhocGameModeCreateMaster(u32 dataAddr, int size) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocGameModeCreateMaster(%08x, %i) at %08x", dataAddr, size, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocGameModeCreateMaster(%08x, %i) at %08x", dataAddr, size, currentMIPS->pc); if (!netAdhocctlInited) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); if (adhocctlCurrentMode != ADHOCCTL_MODE_GAMEMODE) - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); if (!netAdhocGameModeEntered) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); if (size < 0 || !Memory::IsValidAddress(dataAddr)) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); if (masterGameModeArea.data) - return hleLogError(SCENET, ERROR_NET_ADHOC_ALREADY_CREATED, "already created"); // FIXME: Should we return a success instead? (need to test this on a homebrew) + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_ALREADY_CREATED, "already created"); // FIXME: Should we return a success instead? (need to test this on a homebrew) hleEatMicro(1000); SceNetEtherAddr localMac; @@ -4488,13 +4489,13 @@ static int sceNetAdhocGameModeCreateMaster(u32 dataAddr, int size) { if (replicaGameModeAreas.size() == (gameModeMacs.size() - 1)) { if (CoreTiming::IsScheduled(gameModeNotifyEvent)) { __KernelWaitCurThread(WAITTYPE_NET, GAMEMODE_WAITID, 0, 0, false, "syncing master data"); - DEBUG_LOG(SCENET, "GameMode: Blocking Thread %d to Sync initial Master data", __KernelGetCurThread()); + DEBUG_LOG(Log::sceNet, "GameMode: Blocking Thread %d to Sync initial Master data", __KernelGetCurThread()); } } - return hleLogDebug(SCENET, 0, "success"); // returned an id just like CreateReplica? always return 0? + return hleLogDebug(Log::sceNet, 0, "success"); // returned an id just like CreateReplica? always return 0? } - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CREATED, "not created"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_CREATED, "not created"); } /** @@ -4507,18 +4508,18 @@ static int sceNetAdhocGameModeCreateMaster(u32 dataAddr, int size) { * @return The id of the replica on success, < 0 on error. */ static int sceNetAdhocGameModeCreateReplica(const char *mac, u32 dataAddr, int size) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocGameModeCreateReplica(%s, %08x, %i) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), dataAddr, size, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocGameModeCreateReplica(%s, %08x, %i) at %08x", mac2str((SceNetEtherAddr*)mac).c_str(), dataAddr, size, currentMIPS->pc); if (!netAdhocctlInited) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); if (adhocctlCurrentMode != ADHOCCTL_MODE_GAMEMODE) - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); if (!netAdhocGameModeEntered) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); if (mac == nullptr || size < 0 || !Memory::IsValidAddress(dataAddr)) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); hleEatMicro(1000); int maxid = 0; @@ -4529,7 +4530,7 @@ static int sceNetAdhocGameModeCreateReplica(const char *mac, u32 dataAddr, int s }); // MAC address already existed! if (it != replicaGameModeAreas.end()) { - WARN_LOG(SCENET, "sceNetAdhocGameModeCreateReplica - [%s] is already existed (id: %d)", mac2str((SceNetEtherAddr*)mac).c_str(), it->id); + WARN_LOG(Log::sceNet, "sceNetAdhocGameModeCreateReplica - [%s] is already existed (id: %d)", mac2str((SceNetEtherAddr*)mac).c_str(), it->id); return it->id; // ERROR_NET_ADHOC_ALREADY_CREATED } @@ -4551,25 +4552,25 @@ static int sceNetAdhocGameModeCreateReplica(const char *mac, u32 dataAddr, int s if (masterGameModeArea.data != NULL && replicaGameModeAreas.size() == (gameModeMacs.size() - 1)) { if (CoreTiming::IsScheduled(gameModeNotifyEvent)) { __KernelWaitCurThread(WAITTYPE_NET, GAMEMODE_WAITID, ret, 0, false, "syncing master data"); - DEBUG_LOG(SCENET, "GameMode: Blocking Thread %d to Sync initial Master data", __KernelGetCurThread()); + DEBUG_LOG(Log::sceNet, "GameMode: Blocking Thread %d to Sync initial Master data", __KernelGetCurThread()); } } - return hleLogSuccessInfoI(SCENET, ret, "success"); + return hleLogSuccessInfoI(Log::sceNet, ret, "success"); } - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CREATED, "not created"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_CREATED, "not created"); } static int sceNetAdhocGameModeUpdateMaster() { - DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocGameModeUpdateMaster() at %08x", currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNTESTED sceNetAdhocGameModeUpdateMaster() at %08x", currentMIPS->pc); if (!netAdhocctlInited) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); if (adhocctlCurrentMode != ADHOCCTL_MODE_GAMEMODE) - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); if (!netAdhocGameModeEntered) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); if (masterGameModeArea.data) { Memory::Memcpy(masterGameModeArea.data, masterGameModeArea.addr, masterGameModeArea.size); @@ -4587,7 +4588,7 @@ static int sceNetAdhocGameModeUpdateMaster() { int NetAdhocGameMode_DeleteMaster() { if (CoreTiming::IsScheduled(gameModeNotifyEvent)) { __KernelWaitCurThread(WAITTYPE_NET, GAMEMODE_WAITID, 0, 0, false, "deleting master data"); - DEBUG_LOG(SCENET, "GameMode: Blocking Thread %d to End GameMode Scheduler", __KernelGetCurThread()); + DEBUG_LOG(Log::sceNet, "GameMode: Blocking Thread %d to End GameMode Scheduler", __KernelGetCurThread()); } if (masterGameModeArea.data) { @@ -4607,23 +4608,23 @@ int NetAdhocGameMode_DeleteMaster() { } static int sceNetAdhocGameModeDeleteMaster() { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocGameModeDeleteMaster() at %08x", currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocGameModeDeleteMaster() at %08x", currentMIPS->pc); if (isZeroMAC(&masterGameModeArea.mac)) - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CREATED, "not created"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_CREATED, "not created"); return NetAdhocGameMode_DeleteMaster(); } static int sceNetAdhocGameModeUpdateReplica(int id, u32 infoAddr) { - DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocGameModeUpdateReplica(%i, %08x) at %08x", id, infoAddr, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNTESTED sceNetAdhocGameModeUpdateReplica(%i, %08x) at %08x", id, infoAddr, currentMIPS->pc); if (!netAdhocctlInited) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); if (adhocctlCurrentMode != ADHOCCTL_MODE_GAMEMODE) - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_IN_GAMEMODE, "not in gamemode"); if (!netAdhocGameModeEntered) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_ENTER_GAMEMODE, "not enter gamemode"); auto it = std::find_if(replicaGameModeAreas.begin(), replicaGameModeAreas.end(), [id](GameModeArea const& e) { @@ -4631,7 +4632,7 @@ static int sceNetAdhocGameModeUpdateReplica(int id, u32 infoAddr) { }); if (it == replicaGameModeAreas.end()) - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CREATED, "not created"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_CREATED, "not created"); // Bomberman Panic Bomber is using 0/null on infoAddr, so i guess it's optional. GameModeUpdateInfo* gmuinfo = NULL; @@ -4664,14 +4665,14 @@ static int sceNetAdhocGameModeUpdateReplica(int id, u32 infoAddr) { } static int sceNetAdhocGameModeDeleteReplica(int id) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocGameModeDeleteReplica(%i) at %08x", id, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocGameModeDeleteReplica(%i) at %08x", id, currentMIPS->pc); auto it = std::find_if(replicaGameModeAreas.begin(), replicaGameModeAreas.end(), [id](GameModeArea const& e) { return e.id == id; }); if (it == replicaGameModeAreas.end()) - return hleLogError(SCENET, ERROR_NET_ADHOC_NOT_CREATED, "not created"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_NOT_CREATED, "not created"); if (it->data) { free(it->data); @@ -4690,17 +4691,17 @@ static int sceNetAdhocGameModeDeleteReplica(int id) { } int sceNetAdhocGetSocketAlert(int id, u32 flagPtr) { - WARN_LOG_REPORT_ONCE(sceNetAdhocGetSocketAlert, SCENET, "UNTESTED sceNetAdhocGetSocketAlert(%i, %08x) at %08x", id, flagPtr, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocGetSocketAlert, Log::sceNet, "UNTESTED sceNetAdhocGetSocketAlert(%i, %08x) at %08x", id, flagPtr, currentMIPS->pc); if (!Memory::IsValidAddress(flagPtr)) - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_ARG, "invalid arg"); if (id < 1 || id > MAX_SOCKET || adhocSockets[id - 1] == NULL) - return hleLogDebug(SCENET, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_INVALID_SOCKET_ID, "invalid socket id"); s32_le flg = adhocSockets[id - 1]->flags; Memory::Write_U32(flg, flagPtr); - return hleLogDebug(SCENET, 0, "flags = %08x", flg); + return hleLogDebug(Log::sceNet, 0, "flags = %08x", flg); } int NetAdhocMatching_Stop(int matchingId) { @@ -4752,7 +4753,7 @@ int NetAdhocMatching_Stop(int matchingId) { } int sceNetAdhocMatchingStop(int matchingId) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStop(%i) at %08x", matchingId, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingStop(%i) at %08x", matchingId, currentMIPS->pc); return NetAdhocMatching_Stop(matchingId); } @@ -4827,7 +4828,7 @@ int sceNetAdhocMatchingDelete(int matchingId) { NetAdhocMatching_Delete(matchingId); - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingDelete(%i) at %08x", matchingId, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingDelete(%i) at %08x", matchingId, currentMIPS->pc); // Give a little time to make sure everything are cleaned up before the following AdhocMatchingCreate, Not too long tho, otherwise Naruto Ultimate Ninja Heroes 3 will have an issue //hleDelayResult(0, "give time to init/cleanup", adhocExtraPollDelayMS * 1000); @@ -4835,7 +4836,7 @@ int sceNetAdhocMatchingDelete(int matchingId) { } int sceNetAdhocMatchingInit(u32 memsize) { - WARN_LOG_REPORT_ONCE(sceNetAdhocMatchingInit, SCENET, "sceNetAdhocMatchingInit(%d) at %08x", memsize, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocMatchingInit, Log::sceNet, "sceNetAdhocMatchingInit(%d) at %08x", memsize, currentMIPS->pc); // Uninitialized Library if (netAdhocMatchingInited) @@ -4871,7 +4872,7 @@ int NetAdhocMatching_Term() { } int sceNetAdhocMatchingTerm() { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingTerm() at %08x", currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingTerm() at %08x", currentMIPS->pc); // Should we cleanup all created matching contexts first? just in case there are games that doesn't delete them before calling this NetAdhocMatching_Term(); @@ -4882,7 +4883,7 @@ int sceNetAdhocMatchingTerm() { // Presumably returns a "matchingId". static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbuflen, int hello_int, int keepalive_int, int init_count, int rexmt_int, u32 callbackAddr) { - WARN_LOG(SCENET, "sceNetAdhocMatchingCreate(mode=%i, maxnum=%i, port=%i, rxbuflen=%i, hello=%i, keepalive=%i, initcount=%i, rexmt=%i, callbackAddr=%08x) at %08x", mode, maxnum, port, rxbuflen, hello_int, keepalive_int, init_count, rexmt_int, callbackAddr, currentMIPS->pc); + WARN_LOG(Log::sceNet, "sceNetAdhocMatchingCreate(mode=%i, maxnum=%i, port=%i, rxbuflen=%i, hello=%i, keepalive=%i, initcount=%i, rexmt=%i, callbackAddr=%08x) at %08x", mode, maxnum, port, rxbuflen, hello_int, keepalive_int, init_count, rexmt_int, callbackAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -4904,7 +4905,7 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle for (; item != NULL; item = item->next) { // Port Match found if (item->port == port) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_PORT_IN_USE, "adhoc matching port in use"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_PORT_IN_USE, "adhoc matching port in use"); } // Allocate Context Memory @@ -4971,7 +4972,7 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle //hleDelayResult(context->id, "give time to init/cleanup", adhocEventDelayMS * 1000); // Return Matching ID - return hleLogDebug(SCENET, context->id, "success"); + return hleLogDebug(Log::sceNet, context->id, "success"); } // Free Memory @@ -4979,22 +4980,22 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle } // Out of Memory - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NO_SPACE, "adhoc matching no space"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NO_SPACE, "adhoc matching no space"); } // InvalidERROR_NET_Arguments - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhoc matching invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhoc matching invalid arg"); } // Invalid Receive Buffer Size - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_RXBUF_TOO_SHORT, "adhoc matching rxbuf too short"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_RXBUF_TOO_SHORT, "adhoc matching rxbuf too short"); } // Invalid Member Limit - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_MAXNUM, "adhoc matching invalid maxnum"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_MAXNUM, "adhoc matching invalid maxnum"); } // Uninitialized Library - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhoc matching not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhoc matching not initialized"); } int NetAdhocMatching_Start(int matchingId, int evthPri, int evthPartitionId, int evthStack, int inthPri, int inthPartitionId, int inthStack, int optLen, u32 optDataAddr) { @@ -5023,7 +5024,7 @@ int NetAdhocMatching_Start(int matchingId, int evthPri, int evthPartitionId, int item->socket = sock; if (sock < 1) { peerlock.unlock(); - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_PORT_IN_USE, "adhoc matching port in use"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_PORT_IN_USE, "adhoc matching port in use"); } // Create & Start the Fake PSP Thread ("matching_ev%d" and "matching_io%d") @@ -5062,7 +5063,7 @@ int NetAdhocMatching_Start(int matchingId, int evthPri, int evthPartitionId, int #define VSHELL_PARTITION_ID 5 // This should be similar with sceNetAdhocMatchingStart2 but using USER_PARTITION_ID (2) for PartitionId params static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, int inthPri, int inthStack, int optLen, u32 optDataAddr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart(%i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthStack, inthPri, inthStack, optLen, optDataAddr, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingStart(%i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthStack, inthPri, inthStack, optLen, optDataAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; @@ -5074,7 +5075,7 @@ static int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, // With params for Partition ID for the event & input handler stack static int sceNetAdhocMatchingStart2(int matchingId, int evthPri, int evthPartitionId, int evthStack, int inthPri, int inthPartitionId, int inthStack, int optLen, u32 optDataAddr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingStart2(%i, %i, %i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthPartitionId, evthStack, inthPri, inthPartitionId, inthStack, optLen, optDataAddr, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingStart2(%i, %i, %i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthPartitionId, evthStack, inthPri, inthPartitionId, inthStack, optLen, optDataAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; @@ -5086,7 +5087,7 @@ static int sceNetAdhocMatchingStart2(int matchingId, int evthPri, int evthPartit static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddress, int optLen, u32 optDataPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSelectTarget(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str(), optLen, optDataPtr, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingSelectTarget(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str(), optLen, optDataPtr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; @@ -5122,10 +5123,10 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) { // Already Connected - if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); + if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); // Not enough space - if (countChildren(context) == (context->maxpeers - 1)) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_EXCEED_MAXNUM, "adhocmatching exceed maxnum"); + if (countChildren(context) == (context->maxpeers - 1)) return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_EXCEED_MAXNUM, "adhocmatching exceed maxnum"); // Requesting Peer if (peer->state == PSP_ADHOC_MATCHING_PEER_INCOMING_REQUEST) @@ -5153,10 +5154,10 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres else if (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD) { // Already connected - if (findParent(context) != NULL) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); + if (findParent(context) != NULL) return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); // Outgoing Request in Progress - if (findOutgoingRequest(context) != NULL) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS, "adhocmatching request in progress"); + if (findOutgoingRequest(context) != NULL) return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS, "adhocmatching request in progress"); // Valid Offer if (peer->state == PSP_ADHOC_MATCHING_PEER_OFFER) @@ -5176,10 +5177,10 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres else { // Already connected - if (findP2P(context) != NULL) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); + if (findP2P(context) != NULL) return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED, "adhocmatching already established"); // Outgoing Request in Progress - if (findOutgoingRequest(context) != NULL) return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS, "adhocmatching request in progress"); + if (findOutgoingRequest(context) != NULL) return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS, "adhocmatching request in progress"); // Join Request Mode if (peer->state == PSP_ADHOC_MATCHING_PEER_OFFER) @@ -5211,31 +5212,31 @@ static int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddres } // How did this happen?! It shouldn't! - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_TARGET_NOT_READY, "adhocmatching target not ready"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_TARGET_NOT_READY, "adhocmatching target not ready"); } // Invalid Optional Data Length - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN, "adhocmatching invalid optlen"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN, "adhocmatching invalid optlen"); } // Peer not found - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); } // Idle Context - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); } // Invalid Matching ID - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); } // Invalid Arguments - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); } // Uninitialized Library - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); } int NetAdhocMatching_CancelTargetWithOpt(int matchingId, const char* macAddress, int optLen, u32 optDataPtr) { @@ -5295,43 +5296,43 @@ int NetAdhocMatching_CancelTargetWithOpt(int matchingId, const char* macAddress, } // Peer not found - //return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); + //return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); // Faking success to prevent the game (ie. Soul Calibur) to repeatedly calling this function when the other player is disconnected return 0; } // Context not running - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); } // Invalid Matching ID - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); } // Invalid Arguments - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); } // Uninitialized Library - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); } int sceNetAdhocMatchingCancelTargetWithOpt(int matchingId, const char *macAddress, int optLen, u32 optDataPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingCancelTargetWithOpt(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str(), optLen, optDataPtr, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingCancelTargetWithOpt(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str(), optLen, optDataPtr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; return NetAdhocMatching_CancelTargetWithOpt(matchingId, macAddress, optLen, optDataPtr); } int sceNetAdhocMatchingCancelTarget(int matchingId, const char *macAddress) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingCancelTarget(%i, %s)", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str()); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingCancelTarget(%i, %s)", matchingId, mac2str((SceNetEtherAddr*)macAddress).c_str()); if (!g_Config.bEnableWlan) return -1; return NetAdhocMatching_CancelTargetWithOpt(matchingId, macAddress, 0, 0); } int sceNetAdhocMatchingGetHelloOpt(int matchingId, u32 optLenAddr, u32 optDataAddr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingGetHelloOpt(%i, %08x, %08x)", matchingId, optLenAddr, optDataAddr); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingGetHelloOpt(%i, %08x, %08x)", matchingId, optLenAddr, optDataAddr); if (!g_Config.bEnableWlan) return -1; @@ -5362,12 +5363,12 @@ int sceNetAdhocMatchingGetHelloOpt(int matchingId, u32 optLenAddr, u32 optDataAd } int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAddr) { - VERBOSE_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSetHelloOpt(%i, %i, %08x) at %08x", matchingId, optLenAddr, optDataAddr, currentMIPS->pc); + VERBOSE_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingSetHelloOpt(%i, %i, %08x) at %08x", matchingId, optLenAddr, optDataAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; if (!netAdhocMatchingInited) - return hleLogDebug(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); // Multithreading Lock peerlock.lock(); @@ -5379,19 +5380,19 @@ int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAd // Context not found if (context == NULL) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); // Invalid Matching Mode (Child) if (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD) - return hleLogDebug(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_MODE, "adhocmatching invalid mode"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_MODE, "adhocmatching invalid mode"); // Context not running if (!context->running) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); // Invalid Optional Data Length if ((optLenAddr != 0) && (optDataAddr == 0)) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN, "adhocmatching invalid optlen"); //ERROR_NET_ADHOC_MATCHING_INVALID_ARG + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN, "adhocmatching invalid optlen"); //ERROR_NET_ADHOC_MATCHING_INVALID_ARG // Grab Existing Hello Data void* hello = context->hello; @@ -5435,16 +5436,16 @@ int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAd } static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) { - DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocMatchingGetMembers(%i, [%08x]=%i, %08x) at %08x", matchingId, sizeAddr, Memory::Read_U32(sizeAddr), buf, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingGetMembers(%i, [%08x]=%i, %08x) at %08x", matchingId, sizeAddr, Memory::Read_U32(sizeAddr), buf, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; if (!netAdhocMatchingInited) - return hleLogDebug(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); // Minimum Argument if (!Memory::IsValidAddress(sizeAddr)) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); // Multithreading Lock peerlock.lock(); @@ -5455,15 +5456,15 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Context not found if (context == NULL) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); // Context not running if (!context->running) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); // Buffer Length not available if (!Memory::IsValidAddress(sizeAddr)) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); int* buflen = (int*)Memory::GetPointer(sizeAddr); SceNetAdhocMatchingMemberInfoEmu* buf2 = NULL; @@ -5483,7 +5484,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) { // Get Connected Peer Count *buflen = available; - DEBUG_LOG(SCENET, "MemberList [Connected: %i]", peercount); + DEBUG_LOG(Log::sceNet, "MemberList [Connected: %i]", peercount); } // Normal Mode @@ -5511,7 +5512,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Add Local MAC buf2[filledpeers++].mac_addr = context->mac; - DEBUG_LOG(SCENET, "MemberSelf [%s]", mac2str(&context->mac).c_str()); + DEBUG_LOG(Log::sceNet, "MemberSelf [%s]", mac2str(&context->mac).c_str()); } // Room for more than local peer @@ -5536,7 +5537,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Add P2P Brother MAC buf2[filledpeers++].mac_addr = p2p->mac; - DEBUG_LOG(SCENET, "MemberP2P [%s]", mac2str(&p2p->mac).c_str()); + DEBUG_LOG(Log::sceNet, "MemberP2P [%s]", mac2str(&p2p->mac).c_str()); } } @@ -5556,7 +5557,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Add Parent MAC buf2[filledpeers++].mac_addr = parentpeer->mac; - DEBUG_LOG(SCENET, "MemberParent [%s]", mac2str(&parentpeer->mac).c_str()); + DEBUG_LOG(Log::sceNet, "MemberParent [%s]", mac2str(&parentpeer->mac).c_str()); } // We may need to rearrange children where last joined player placed last @@ -5589,7 +5590,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Add Child MAC buf2[filledpeers++].mac_addr = peer->mac; - DEBUG_LOG(SCENET, "MemberChild [%s]", mac2str(&peer->mac).c_str()); + DEBUG_LOG(Log::sceNet, "MemberChild [%s]", mac2str(&peer->mac).c_str()); } } @@ -5600,14 +5601,14 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Add Peer MAC buf2[filledpeers++].mac_addr = peer->mac; - DEBUG_LOG(SCENET, "MemberSibling [%s]", mac2str(&peer->mac).c_str()); + DEBUG_LOG(Log::sceNet, "MemberSibling [%s]", mac2str(&peer->mac).c_str()); } // Self Peer else if (peer->state == 0) { // Add Local MAC buf2[filledpeers++].mac_addr = peer->mac; - DEBUG_LOG(SCENET, "MemberSelf [%s]", mac2str(&peer->mac).c_str()); + DEBUG_LOG(Log::sceNet, "MemberSelf [%s]", mac2str(&peer->mac).c_str()); } } @@ -5629,7 +5630,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Fix Buffer Size *buflen = sizeof(SceNetAdhocMatchingMemberInfoEmu) * filledpeers; - DEBUG_LOG(SCENET, "MemberList [Requested: %i][Discovered: %i]", requestedpeers, filledpeers); + DEBUG_LOG(Log::sceNet, "MemberList [Requested: %i][Discovered: %i]", requestedpeers, filledpeers); } // Return Success @@ -5638,7 +5639,7 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Gran Turismo may replace the 1st bit of the 1st byte of MAC address's OUI with 0 (unicast bit), or replace the whole 6-bytes of MAC address with all 00 (invalid mac) for unknown reason int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u32 dataAddr) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSendData(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)mac).c_str(), dataLen, dataAddr, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingSendData(%i, %s, %i, %08x) at %08x", matchingId, mac2str((SceNetEtherAddr*)mac).c_str(), dataLen, dataAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; @@ -5660,7 +5661,7 @@ int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u3 // Invalid Data Length if (dataLen <=0 || dataAddr == 0) // Invalid Data Length - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_DATALEN, "invalid datalen"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_DATALEN, "invalid datalen"); void* data = NULL; if (Memory::IsValidAddress(dataAddr)) data = Memory::GetPointerWriteUnchecked(dataAddr); @@ -5679,7 +5680,7 @@ int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u3 { // Send in Progress if (peer->sending) - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_DATA_BUSY, "data busy"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_DATA_BUSY, "data busy"); // Mark Peer as Sending peer->sending = 1; @@ -5692,31 +5693,31 @@ int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u3 } // Not connected / accepted - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_ESTABLISHED, "not established"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_ESTABLISHED, "not established"); } // Peer not found - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "unknown target"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "unknown target"); } // Context not running - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "not running"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "not running"); } // Invalid Matching ID - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "invalid id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "invalid id"); } // Invalid Arguments - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "invalid arg"); } // Uninitialized Library - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "not initialized"); } int sceNetAdhocMatchingAbortSendData(int matchingId, const char *mac) { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingAbortSendData(%i, %s)", matchingId, mac2str((SceNetEtherAddr*)mac).c_str()); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingAbortSendData(%i, %s)", matchingId, mac2str((SceNetEtherAddr*)mac).c_str()); if (!g_Config.bEnableWlan) return -1; @@ -5756,37 +5757,37 @@ int sceNetAdhocMatchingAbortSendData(int matchingId, const char *mac) { } // Peer not found - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET, "adhocmatching unknown target"); } // Context not running - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_RUNNING, "adhocmatching not running"); } // Invalid Matching ID - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ID, "adhocmatching invalid id"); } // Invalid Arguments - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); } // Uninitialized Library - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); } // Get the maximum memory usage by the matching library static int sceNetAdhocMatchingGetPoolMaxAlloc() { - ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetPoolMaxAlloc() at %08x", currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL sceNetAdhocMatchingGetPoolMaxAlloc() at %08x", currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; // Lazy way out - hardcoded return value - return hleLogDebug(SCENET, fakePoolSize/2, "faked value"); + return hleLogDebug(Log::sceNet, fakePoolSize/2, "faked value"); } int sceNetAdhocMatchingGetPoolStat(u32 poolstatPtr) { - DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocMatchingGetPoolStat(%08x) at %08x", poolstatPtr, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNTESTED sceNetAdhocMatchingGetPoolStat(%08x) at %08x", poolstatPtr, currentMIPS->pc); if (!g_Config.bEnableWlan) return -1; @@ -5809,11 +5810,11 @@ int sceNetAdhocMatchingGetPoolStat(u32 poolstatPtr) { } // Invalid Argument - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_INVALID_ARG, "adhocmatching invalid arg"); } // Uninitialized Library - return hleLogError(SCENET, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED, "adhocmatching not initialized"); } void __NetTriggerCallbacks() @@ -5867,10 +5868,10 @@ void __NetTriggerCallbacks() if (adhocConnectionType == ADHOC_JOIN) delayus += adhocExtraDelay * 3; // Shows player list - INFO_LOG(SCENET, "GameMode - All players have joined:"); + INFO_LOG(Log::sceNet, "GameMode - All players have joined:"); int i = 0; for (auto& mac : gameModeMacs) { - INFO_LOG(SCENET, "GameMode macAddress#%d=%s", i++, mac2str(&mac).c_str()); + INFO_LOG(Log::sceNet, "GameMode macAddress#%d=%s", i++, mac2str(&mac).c_str()); if (i >= ADHOCCTL_GAMEMODE_MAX_MEMBERS) break; } @@ -5888,7 +5889,7 @@ void __NetTriggerCallbacks() } for (std::map::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); ++it) { - DEBUG_LOG(SCENET, "AdhocctlCallback: [ID=%i][EVENT=%i][Error=%08x]", it->first, flags, error); + DEBUG_LOG(Log::sceNet, "AdhocctlCallback: [ID=%i][EVENT=%i][Error=%08x]", it->first, flags, error); args[2] = it->second.argument; AfterAdhocMipsCall* after = (AfterAdhocMipsCall*)__KernelCreateAction(actionAfterAdhocMipsCall); after->SetData(it->first, flags, args[2]); @@ -5923,11 +5924,11 @@ void __NetMatchingCallbacks() //(int matchingId) if (actionAfterMatchingMipsCall < 0) { actionAfterMatchingMipsCall = __KernelRegisterActionType(AfterMatchingMipsCall::Create); } - DEBUG_LOG(SCENET, "AdhocMatching - Remaining Events: %zu", matchingEvents.size()); + DEBUG_LOG(Log::sceNet, "AdhocMatching - Remaining Events: %zu", matchingEvents.size()); auto peer = findPeer(context, (SceNetEtherAddr*)Memory::GetPointer(args[2])); // Discard HELLO Events when in the middle of joining, as some games (ie. Super Pocket Tennis) might tried to join again (TODO: Need to confirm whether sceNetAdhocMatchingSelectTarget supposed to be blocking the current thread or not) if (peer == NULL || (args[1] != PSP_ADHOC_MATCHING_EVENT_HELLO || (peer->state != PSP_ADHOC_MATCHING_PEER_OUTGOING_REQUEST && peer->state != PSP_ADHOC_MATCHING_PEER_INCOMING_REQUEST))) { - DEBUG_LOG(SCENET, "AdhocMatchingCallback: [ID=%i][EVENT=%i][%s]", args[0], args[1], mac2str((SceNetEtherAddr *)Memory::GetPointer(args[2])).c_str()); + DEBUG_LOG(Log::sceNet, "AdhocMatchingCallback: [ID=%i][EVENT=%i][%s]", args[0], args[1], mac2str((SceNetEtherAddr *)Memory::GetPointer(args[2])).c_str()); AfterMatchingMipsCall* after = (AfterMatchingMipsCall*)__KernelCreateAction(actionAfterMatchingMipsCall); after->SetData(args[0], args[1], args[2]); @@ -5935,7 +5936,7 @@ void __NetMatchingCallbacks() //(int matchingId) matchingEvents.pop_front(); } else { - DEBUG_LOG(SCENET, "AdhocMatching - Discarding Callback: [ID=%i][EVENT=%i][%s]", args[0], args[1], mac2str((SceNetEtherAddr*)Memory::GetPointer(args[2])).c_str()); + DEBUG_LOG(Log::sceNet, "AdhocMatching - Discarding Callback: [ID=%i][EVENT=%i][%s]", args[0], args[1], mac2str((SceNetEtherAddr*)Memory::GetPointer(args[2])).c_str()); matchingEvents.pop_front(); } } @@ -6012,25 +6013,25 @@ int NetAdhocctl_ExitGameMode() { } static int sceNetAdhocctlExitGameMode() { - WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlExitGameMode() at %08x", currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlExitGameMode() at %08x", currentMIPS->pc); return NetAdhocctl_ExitGameMode(); } static int sceNetAdhocctlGetGameModeInfo(u32 infoAddr) { - DEBUG_LOG(SCENET, "sceNetAdhocctlGetGameModeInfo(%08x)", infoAddr); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctlGetGameModeInfo(%08x)", infoAddr); if (!netAdhocctlInited) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); if (!Memory::IsValidAddress(infoAddr)) - return hleLogError(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + return hleLogError(Log::sceNet, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); SceNetAdhocctlGameModeInfo* gmInfo = (SceNetAdhocctlGameModeInfo*)Memory::GetPointer(infoAddr); // Writes number of participants and each participating MAC address into infoAddr/gmInfo gmInfo->num = static_cast(gameModeMacs.size()); int i = 0; for (auto& mac : gameModeMacs) { - VERBOSE_LOG(SCENET, "GameMode macAddress#%d=%s", i, mac2str(&mac).c_str()); + VERBOSE_LOG(Log::sceNet, "GameMode macAddress#%d=%s", i, mac2str(&mac).c_str()); gmInfo->members[i++] = mac; if (i >= ADHOCCTL_GAMEMODE_MAX_MEMBERS) break; @@ -6046,7 +6047,7 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { SceNetAdhocctlPeerInfoEmu *buf = NULL; if (Memory::IsValidAddress(bufAddr)) buf = (SceNetAdhocctlPeerInfoEmu *)Memory::GetPointer(bufAddr); - DEBUG_LOG(SCENET, "sceNetAdhocctlGetPeerList([%08x]=%i, %08x) at %08x", sizeAddr, /*buflen ? *buflen : -1*/Memory::Read_U32(sizeAddr), bufAddr, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "sceNetAdhocctlGetPeerList([%08x]=%i, %08x) at %08x", sizeAddr, /*buflen ? *buflen : -1*/Memory::Read_U32(sizeAddr), bufAddr, currentMIPS->pc); if (!g_Config.bEnableWlan) { return -1; } @@ -6065,7 +6066,7 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { if (buf == NULL) { int activePeers = getActivePeerCount(excludeTimedout); *buflen = activePeers * sizeof(SceNetAdhocctlPeerInfoEmu); - DEBUG_LOG(SCENET, "PeerList [Active: %i]", activePeers); + DEBUG_LOG(Log::sceNet, "PeerList [Active: %i]", activePeers); } // Normal Mode else { @@ -6101,7 +6102,7 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { discovered++; u32_le ipaddr = peer->ip_addr; - DEBUG_LOG(SCENET, "Peer [%s][%s][%s][%llu]", mac2str(&peer->mac_addr).c_str(), ip2str(*(in_addr*)&ipaddr).c_str(), (const char*)&peer->nickname.data, peer->last_recv); + DEBUG_LOG(Log::sceNet, "Peer [%s][%s][%s][%llu]", mac2str(&peer->mac_addr).c_str(), ip2str(*(in_addr*)&ipaddr).c_str(), (const char*)&peer->nickname.data, peer->last_recv); } } @@ -6116,7 +6117,7 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { // Fix Size *buflen = discovered * sizeof(SceNetAdhocctlPeerInfoEmu); - DEBUG_LOG(SCENET, "PeerList [Requested: %i][Discovered: %i]", requestcount, discovered); + DEBUG_LOG(Log::sceNet, "PeerList [Requested: %i][Discovered: %i]", requestcount, discovered); } // Multithreading Unlock @@ -6127,11 +6128,11 @@ static int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) { } // Invalid Arguments - return hleLogDebug(SCENET, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOCCTL_INVALID_ARG, "invalid arg"); } // Uninitialized Library - return hleLogDebug(SCENET, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); + return hleLogDebug(Log::sceNet, ERROR_NET_ADHOCCTL_NOT_INITIALIZED, "not initialized"); } static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 bufAddr) { @@ -6142,7 +6143,7 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b memcpy(nckName, nickName, ADHOCCTL_NICKNAME_LEN); // Copied to null-terminated var to prevent unexpected behaviour on Logs nckName[ADHOCCTL_NICKNAME_LEN - 1] = 0; - WARN_LOG_REPORT_ONCE(sceNetAdhocctlGetAddrByName, SCENET, "UNTESTED sceNetAdhocctlGetAddrByName(%s, [%08x]=%d/%zu, %08x) at %08x", nckName, sizeAddr, buflen ? *buflen : -1, sizeof(SceNetAdhocctlPeerInfoEmu), bufAddr, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocctlGetAddrByName, Log::sceNet, "UNTESTED sceNetAdhocctlGetAddrByName(%s, [%08x]=%d/%zu, %08x) at %08x", nckName, sizeAddr, buflen ? *buflen : -1, sizeof(SceNetAdhocctlPeerInfoEmu), bufAddr, currentMIPS->pc); // Library initialized if (netAdhocctlInited) @@ -6160,7 +6161,7 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b if (buf == NULL) { int foundName = getNicknameCount(nickName); *buflen = foundName * sizeof(SceNetAdhocctlPeerInfoEmu); - DEBUG_LOG(SCENET, "PeerNameList [%s: %i]", nickName, foundName); + DEBUG_LOG(Log::sceNet, "PeerNameList [%s: %i]", nickName, foundName); } // Normal Information Mode else @@ -6193,7 +6194,7 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b u64 lastrecv = std::max(0LL, static_cast(CoreTiming::GetGlobalTimeUsScaled() - defaultLastRecvDelta)); buf[discovered++].last_recv = lastrecv; - DEBUG_LOG(SCENET, "Peer [%s][%s][%s][%llu]", mac2str(&mac).c_str(), ip2str(addr.sin_addr).c_str(), nickName, lastrecv); + DEBUG_LOG(Log::sceNet, "Peer [%s][%s][%s][%llu]", mac2str(&mac).c_str(), ip2str(addr.sin_addr).c_str(), nickName, lastrecv); } // Peer Reference @@ -6216,7 +6217,7 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b buf[discovered++].last_recv = peer->last_recv; u32_le ipaddr = peer->ip_addr; - DEBUG_LOG(SCENET, "Peer [%s][%s][%s][%llu]", mac2str(&peer->mac_addr).c_str(), ip2str(*(in_addr*)&ipaddr).c_str(), (const char*)&peer->nickname.data, peer->last_recv); + DEBUG_LOG(Log::sceNet, "Peer [%s][%s][%s][%llu]", mac2str(&peer->mac_addr).c_str(), ip2str(*(in_addr*)&ipaddr).c_str(), (const char*)&peer->nickname.data, peer->last_recv); } } @@ -6233,14 +6234,14 @@ static int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 b // Fix Buffer Size *buflen = discovered * sizeof(SceNetAdhocctlPeerInfoEmu); - DEBUG_LOG(SCENET, "PeerNameList [%s][Requested: %i][Discovered: %i]", nickName, requestcount, discovered); + DEBUG_LOG(Log::sceNet, "PeerNameList [%s][Requested: %i][Discovered: %i]", nickName, requestcount, discovered); } // Multithreading Unlock peerlock.unlock(); // Return Success - return hleLogDebug(SCENET, hleDelayResult(0, "delay 100 ~ 1000us", 100), "success"); // FIXME: Might have similar delay with GetPeerList? need to know which games using this tho + return hleLogDebug(Log::sceNet, hleDelayResult(0, "delay 100 ~ 1000us", 100), "success"); // FIXME: Might have similar delay with GetPeerList? need to know which games using this tho } // Invalid Arguments @@ -6278,7 +6279,7 @@ const HLEFunction sceNetAdhocctl[] = { // Return value: 0/0x80410005/0x80411301/error returned from sceNetAdhocctl_lib_F8BABD85[/error returned from sceUtilityGetSystemParamInt?] int sceNetAdhocDiscoverInitStart(u32 paramAddr) { - WARN_LOG_REPORT_ONCE(sceNetAdhocDiscoverInitStart, SCENET, "UNIMPL sceNetAdhocDiscoverInitStart(%08x) at %08x", paramAddr, currentMIPS->pc); + WARN_LOG_REPORT_ONCE(sceNetAdhocDiscoverInitStart, Log::sceNet, "UNIMPL sceNetAdhocDiscoverInitStart(%08x) at %08x", paramAddr, currentMIPS->pc); // FIXME: Most AdhocDiscover syscalls will return 0x80410005 if (sceKernelCheckThreadStack_user() < 0x00000FE0), AdhocDiscover seems to be storing some data in the stack, while we use global variables for these if (sceKernelCheckThreadStack() < 0x00000FE0) return 0x80410005; @@ -6296,7 +6297,7 @@ int sceNetAdhocDiscoverInitStart(u32 paramAddr) { // TODO: Need to findout whether using invalid params or param address will return an error code or not netAdhocDiscoverParam = (SceNetAdhocDiscoverParam*)Memory::GetPointer(paramAddr); if (!netAdhocDiscoverParam) - return hleLogError(SCENET, -1, "invalid param?"); + return hleLogError(Log::sceNet, -1, "invalid param?"); // FIXME: paramAddr seems to be stored at 0x000010D8 without validating the value first //*((int*)Memory::GetPointer(0x000010D8)) = paramAddr; @@ -6328,23 +6329,23 @@ int sceNetAdhocDiscoverInitStart(u32 paramAddr) { char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; memcpy(grpName, netAdhocDiscoverParam->groupName, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated - DEBUG_LOG(SCENET, "sceNetAdhocDiscoverInitStart - Param.Unknown1 : %08x", netAdhocDiscoverParam->unknown1); - DEBUG_LOG(SCENET, "sceNetAdhocDiscoverInitStart - Param.GroupName: [%s]", grpName); - DEBUG_LOG(SCENET, "sceNetAdhocDiscoverInitStart - Param.Unknown2 : %08x", netAdhocDiscoverParam->unknown2); - DEBUG_LOG(SCENET, "sceNetAdhocDiscoverInitStart - Param.Result : %08x", netAdhocDiscoverParam->result); + DEBUG_LOG(Log::sceNet, "sceNetAdhocDiscoverInitStart - Param.Unknown1 : %08x", netAdhocDiscoverParam->unknown1); + DEBUG_LOG(Log::sceNet, "sceNetAdhocDiscoverInitStart - Param.GroupName: [%s]", grpName); + DEBUG_LOG(Log::sceNet, "sceNetAdhocDiscoverInitStart - Param.Unknown2 : %08x", netAdhocDiscoverParam->unknown2); + DEBUG_LOG(Log::sceNet, "sceNetAdhocDiscoverInitStart - Param.Result : %08x", netAdhocDiscoverParam->result); // TODO: Check whether we're already in the correct group and change the status and result accordingly netAdhocDiscoverIsStopping = false; netAdhocDiscoverStatus = NET_ADHOC_DISCOVER_STATUS_IN_PROGRESS; netAdhocDiscoverParam->result = NET_ADHOC_DISCOVER_RESULT_NO_PEER_FOUND; netAdhocDiscoverStartTime = CoreTiming::GetGlobalTimeUsScaled(); - return hleLogSuccessInfoX(SCENET, 0); + return hleLogSuccessInfoX(Log::sceNet, 0); } // Note1: When canceling the progress, Legend Of The Dragon will use DiscoverStop -> AdhocctlDisconnect -> DiscoverTerm (when status changed to 2) // Note2: When result = NO_PEER_FOUND or PEER_FOUND the progress can no longer be canceled on Legend Of The Dragon int sceNetAdhocDiscoverStop() { - WARN_LOG(SCENET, "UNIMPL sceNetAdhocDiscoverStop()"); + WARN_LOG(Log::sceNet, "UNIMPL sceNetAdhocDiscoverStop()"); if (sceKernelCheckThreadStack() < 0x00000FF0) return 0x80410005; @@ -6360,7 +6361,7 @@ int sceNetAdhocDiscoverStop() { } int sceNetAdhocDiscoverTerm() { - WARN_LOG(SCENET, "UNIMPL sceNetAdhocDiscoverTerm() at %08x", currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNIMPL sceNetAdhocDiscoverTerm() at %08x", currentMIPS->pc); /* if (sceKernelCheckThreadStack() < 0x00000FF0) return 0x80410005; @@ -6387,7 +6388,7 @@ int sceNetAdhocDiscoverTerm() { } int sceNetAdhocDiscoverGetStatus() { - DEBUG_LOG(SCENET, "UNIMPL sceNetAdhocDiscoverGetStatus() at %08x", currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNIMPL sceNetAdhocDiscoverGetStatus() at %08x", currentMIPS->pc); if (sceKernelCheckThreadStack() < 0x00000FF0) return 0x80410005; /* @@ -6398,12 +6399,12 @@ int sceNetAdhocDiscoverGetStatus() { if (Memory::Read_U32(netAdhocDiscoverBufAddr + 0x80) == 0x13) return 2; */ - return hleLogDebug(SCENET, netAdhocDiscoverStatus); // Returning 2 will trigger Legend Of The Dragon to call sceNetAdhocctlGetPeerList (only happened if it was the first sceNetAdhocDiscoverGetStatus after sceNetAdhocDiscoverInitStart) + return hleLogDebug(Log::sceNet, netAdhocDiscoverStatus); // Returning 2 will trigger Legend Of The Dragon to call sceNetAdhocctlGetPeerList (only happened if it was the first sceNetAdhocDiscoverGetStatus after sceNetAdhocDiscoverInitStart) } int sceNetAdhocDiscoverRequestSuspend() { - ERROR_LOG_REPORT_ONCE(sceNetAdhocDiscoverRequestSuspend, SCENET, "UNIMPL sceNetAdhocDiscoverRequestSuspend() at %08x", currentMIPS->pc); + ERROR_LOG_REPORT_ONCE(sceNetAdhocDiscoverRequestSuspend, Log::sceNet, "UNIMPL sceNetAdhocDiscoverRequestSuspend() at %08x", currentMIPS->pc); // FIXME: Not sure what is this syscall used for, may be related to Sleep Mode and can be triggered by using Power/Hold Switch? (based on what's written on Dissidia 012) if (sceKernelCheckThreadStack() < 0x00000FF0) return 0x80410005; @@ -6419,11 +6420,11 @@ int sceNetAdhocDiscoverRequestSuspend() */ // Since we don't know what this supposed to do, and we currently don't have a working AdhocDiscover yet, may be we should cancel the progress for now? netAdhocDiscoverIsStopping = true; - return hleLogError(SCENET, 0); + return hleLogError(Log::sceNet, 0); } int sceNetAdhocDiscoverUpdate() { - DEBUG_LOG(SCENET, "UNIMPL sceNetAdhocDiscoverUpdate() at %08x", currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNIMPL sceNetAdhocDiscoverUpdate() at %08x", currentMIPS->pc); if (sceKernelCheckThreadStack() < 0x00000FF0) return 0x80410005; @@ -6437,7 +6438,7 @@ int sceNetAdhocDiscoverUpdate() { netAdhocDiscoverParam->result = NET_ADHOC_DISCOVER_RESULT_CANCELED; // netAdhocDiscoverIsStopping ? NET_ADHOC_DISCOVER_RESULT_CANCELED : NET_ADHOC_DISCOVER_RESULT_PEER_FOUND; } } - return hleDelayResult(hleLogDebug(SCENET, 0/*netAdhocDiscoverBufAddr*/), "adhoc discover update", 300); // FIXME: Based on JPCSP+prx, it seems to be returning a pointer to the internal buffer/struct (only when status = 1 ?), But when i stepped the code it returns 0 (might be a bug on JPCSP LLE Logging?) + return hleDelayResult(hleLogDebug(Log::sceNet, 0/*netAdhocDiscoverBufAddr*/), "adhoc discover update", 300); // FIXME: Based on JPCSP+prx, it seems to be returning a pointer to the internal buffer/struct (only when status = 1 ?), But when i stepped the code it returns 0 (might be a bug on JPCSP LLE Logging?) } const HLEFunction sceNetAdhocDiscover[] = { @@ -6522,7 +6523,7 @@ void broadcastHelloMessage(SceNetAdhocMatchingContext * context) std::string hellohex; DataToHexString(10, 0, context->hello, context->hellolen, &hellohex); - DEBUG_LOG(SCENET, "HELLO Dump (%d bytes):\n%s", context->hellolen, hellohex.c_str()); + DEBUG_LOG(Log::sceNet, "HELLO Dump (%d bytes):\n%s", context->hellolen, hellohex.c_str()); // Send Broadcast, so everyone know we have a room here peerlock.lock(); @@ -6825,9 +6826,9 @@ void sendBirthPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac // Log Send Success if (sent >= 0) - INFO_LOG(SCENET, "InputLoop: Sending BIRTH [%s] to %s", mac2str(mac).c_str(), mac2str(&peer->mac).c_str()); + INFO_LOG(Log::sceNet, "InputLoop: Sending BIRTH [%s] to %s", mac2str(mac).c_str(), mac2str(&peer->mac).c_str()); else - WARN_LOG(SCENET, "InputLoop: Failed to Send BIRTH [%s] to %s", mac2str(mac).c_str(), mac2str(&peer->mac).c_str()); + WARN_LOG(Log::sceNet, "InputLoop: Failed to Send BIRTH [%s] to %s", mac2str(mac).c_str(), mac2str(&peer->mac).c_str()); } } } @@ -6996,7 +6997,7 @@ void actOnHelloPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * se { std::string hellohex; DataToHexString(10, 0, (u8*)opt, optlen, &hellohex); - DEBUG_LOG(SCENET, "HELLO Dump (%d bytes):\n%s", optlen, hellohex.c_str()); + DEBUG_LOG(Log::sceNet, "HELLO Dump (%d bytes):\n%s", optlen, hellohex.c_str()); // Spawn Hello Event. FIXME: HELLO event should not be triggered in the middle of joining? This will cause Bleach 7 to Cancel the join request spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_HELLO, sendermac, optlen, opt); @@ -7042,7 +7043,7 @@ void actOnJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sen // This is because the only way a parent can know of a child is via a join request... // If we thus know of a possible child, then we already had a previous join request thus no need for double tapping. if (peer != NULL && peer->lastping != 0 && context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) { - WARN_LOG(SCENET, "Join Event(2) Ignored"); + WARN_LOG(Log::sceNet, "Join Event(2) Ignored"); return; } @@ -7099,7 +7100,7 @@ void actOnJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sen } } } - WARN_LOG(SCENET, "Join Event(2) Rejected"); + WARN_LOG(Log::sceNet, "Join Event(2) Rejected"); // Auto-Reject Player sendCancelPacket(context, sendermac, 0, NULL); } @@ -7505,7 +7506,7 @@ int matchingEventThread(int matchingId) peerlock.unlock(); // Log Startup - INFO_LOG(SCENET, "EventLoop: Begin of EventLoop[%i] Thread", matchingId); + INFO_LOG(Log::sceNet, "EventLoop: Begin of EventLoop[%i] Thread", matchingId); // Run while needed... if (context != NULL) { @@ -7539,7 +7540,7 @@ int matchingEventThread(int matchingId) if (msg->optlen > 0) opt = ((u8*)msg) + sizeof(ThreadMessage); //&msg[1] // Log Matching Events - INFO_LOG(SCENET, "EventLoop[%d]: Matching Event [%d=%s][%s] OptSize=%d", matchingId, msg->opcode, getMatchingEventStr(msg->opcode), mac2str(&msg->mac).c_str(), msg->optlen); + INFO_LOG(Log::sceNet, "EventLoop[%d]: Matching Event [%d=%s][%s] OptSize=%d", matchingId, msg->opcode, getMatchingEventStr(msg->opcode), mac2str(&msg->mac).c_str(), msg->optlen); // Unlock to prevent race-condition with other threads due to recursive lock //context->eventlock->unlock(); @@ -7589,7 +7590,7 @@ int matchingEventThread(int matchingId) // Grab Optional Data if (msg->optlen > 0) opt = ((u8 *)msg) + sizeof(ThreadMessage); //&msg[1] - INFO_LOG(SCENET, "EventLoop[%d]: Matching Event [EVENT=%d]\n", matchingId, msg->opcode); + INFO_LOG(Log::sceNet, "EventLoop[%d]: Matching Event [EVENT=%d]\n", matchingId, msg->opcode); //context->eventlock->unlock(); // Original Call Event Handler @@ -7605,7 +7606,7 @@ int matchingEventThread(int matchingId) // Free Stack context->eventlock->unlock(); - INFO_LOG(SCENET, "EventLoop[%d]: Finished (%d msg)", matchingId, msg_count); + INFO_LOG(Log::sceNet, "EventLoop[%d]: Finished (%d msg)", matchingId, msg_count); } // Free memory @@ -7616,7 +7617,7 @@ int matchingEventThread(int matchingId) } // Log Shutdown - INFO_LOG(SCENET, "EventLoop: End of EventLoop[%i] Thread", matchingId); + INFO_LOG(Log::sceNet, "EventLoop: End of EventLoop[%i] Thread", matchingId); // Return Zero to shut up Compiler return 0; @@ -7652,7 +7653,7 @@ int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is usi static int rxbuflen; // Log Startup - INFO_LOG(SCENET, "InputLoop: Begin of InputLoop[%i] Thread", matchingId); + INFO_LOG(Log::sceNet, "InputLoop: Begin of InputLoop[%i] Thread", matchingId); // Run while needed... if (context != NULL) { @@ -7762,7 +7763,7 @@ int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is usi { // Log Receive Success if (context->rxbuf[0] > 1) { - INFO_LOG(SCENET, "InputLoop[%d]: Received %d Bytes (Opcode[%d]=%s)", matchingId, rxbuflen, context->rxbuf[0], getMatchingOpcodeStr(context->rxbuf[0])); + INFO_LOG(Log::sceNet, "InputLoop[%d]: Received %d Bytes (Opcode[%d]=%s)", matchingId, rxbuflen, context->rxbuf[0], getMatchingOpcodeStr(context->rxbuf[0])); } // Update Peer Timestamp @@ -7771,11 +7772,11 @@ int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is usi if (peer != NULL) { now = CoreTiming::GetGlobalTimeUsScaled(); s64 delta = now - peer->last_recv; - DEBUG_LOG(SCENET, "Timestamp LastRecv Delta: %lld (%llu - %llu) from %s", delta, now, peer->last_recv, mac2str(&sendermac).c_str()); + DEBUG_LOG(Log::sceNet, "Timestamp LastRecv Delta: %lld (%llu - %llu) from %s", delta, now, peer->last_recv, mac2str(&sendermac).c_str()); if (peer->last_recv != 0) peer->last_recv = std::max(peer->last_recv, now - defaultLastRecvDelta); } else { - WARN_LOG(SCENET, "InputLoop[%d]: Unknown Peer[%s:%u] (Recved=%i, Length=%i)", matchingId, mac2str(&sendermac).c_str(), senderport, recvresult, rxbuflen); + WARN_LOG(Log::sceNet, "InputLoop[%d]: Unknown Peer[%s:%u] (Recved=%i, Length=%i)", matchingId, mac2str(&sendermac).c_str(), senderport, recvresult, rxbuflen); } // Show a warning if other player is having their port being re-mapped, thus that other player may have issue with the communication. @@ -7784,7 +7785,7 @@ int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is usi char name[9] = {}; if (peer != NULL) truncate_cpy(name, sizeof(name), (const char*)peer->nickname.data); - WARN_LOG(SCENET, "InputLoop[%d]: Unknown Source Port from [%s][%s:%u -> %u] (Recved=%i, Length=%i)", matchingId, name, mac2str(&sendermac).c_str(), senderport, context->port, recvresult, rxbuflen); + WARN_LOG(Log::sceNet, "InputLoop[%d]: Unknown Source Port from [%s][%s:%u -> %u] (Recved=%i, Length=%i)", matchingId, name, mac2str(&sendermac).c_str(), senderport, context->port, recvresult, rxbuflen); g_OSD.Show(OSDType::MESSAGE_WARNING, std::string(n->T("AM: Data from Unknown Port")) + std::string(" [") + std::string(name) + std::string("]:") + std::to_string(senderport) + std::string(" -> ") + std::to_string(context->port) + std::string(" (") + std::to_string(portOffset) + std::string(")")); } // Keep tracks of re-mapped peer's ports for further communication. @@ -7883,7 +7884,7 @@ int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is usi // Free Stack context->inputlock->unlock(); - INFO_LOG(SCENET, "InputLoop[%d]: Finished (%d msg)", matchingId, msg_count); + INFO_LOG(Log::sceNet, "InputLoop[%d]: Finished (%d msg)", matchingId, msg_count); } // Clear IO Message Stack @@ -7901,7 +7902,7 @@ int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is usi } // Log Shutdown - INFO_LOG(SCENET, "InputLoop: End of InputLoop[%i] Thread", matchingId); + INFO_LOG(Log::sceNet, "InputLoop: End of InputLoop[%i] Thread", matchingId); // Terminate Thread //sceKernelExitDeleteThread(0); diff --git a/Core/HLE/sceNp.cpp b/Core/HLE/sceNp.cpp index c5ca4be4c6..1d8aa8154a 100644 --- a/Core/HLE/sceNp.cpp +++ b/Core/HLE/sceNp.cpp @@ -107,7 +107,7 @@ void notifyNpAuthHandlers(u32 id, u32 result, u32 argAddr) { static int sceNpInit() { - ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); npOnlineId = g_Config.sNickName; return 0; @@ -116,19 +116,19 @@ static int sceNpInit() static int sceNpTerm() { // No parameters - ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); return 0; } static int sceNpGetContentRatingFlag(u32 parentalControlAddr, u32 userAgeAddr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x, %08x)", __FUNCTION__, parentalControlAddr, userAgeAddr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x, %08x)", __FUNCTION__, parentalControlAddr, userAgeAddr); if (!Memory::IsValidAddress(parentalControlAddr) || !Memory::IsValidAddress(userAgeAddr)) - return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); - INFO_LOG(SCENET, "%s - Parental Control: %d", __FUNCTION__, npParentalControl); - INFO_LOG(SCENET, "%s - User Age: %d", __FUNCTION__, npUserAge); + INFO_LOG(Log::sceNet, "%s - Parental Control: %d", __FUNCTION__, npParentalControl); + INFO_LOG(Log::sceNet, "%s - User Age: %d", __FUNCTION__, npUserAge); Memory::Write_U32(npParentalControl, parentalControlAddr); Memory::Write_U32(npUserAge, userAgeAddr); @@ -138,12 +138,12 @@ static int sceNpGetContentRatingFlag(u32 parentalControlAddr, u32 userAgeAddr) static int sceNpGetChatRestrictionFlag(u32 flagAddr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, flagAddr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x)", __FUNCTION__, flagAddr); if (!Memory::IsValidAddress(flagAddr)) - return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); - INFO_LOG(SCENET, "%s - Chat Restriction: %d", __FUNCTION__, npChatRestriction); + INFO_LOG(Log::sceNet, "%s - Chat Restriction: %d", __FUNCTION__, npChatRestriction); Memory::Write_U32(npChatRestriction, flagAddr); @@ -152,17 +152,17 @@ static int sceNpGetChatRestrictionFlag(u32 flagAddr) static int sceNpGetOnlineId(u32 idPtr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, idPtr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x)", __FUNCTION__, idPtr); auto id = PSPPointer::Create(idPtr); if (!id.IsValid()) - return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); memset((SceNpOnlineId *)id, 0, sizeof(SceNpOnlineId)); truncate_cpy(id->data, sizeof(id->data), npOnlineId.c_str()); id.NotifyWrite("NpGetOnlineId"); - INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, id->data); + INFO_LOG(Log::sceNet, "%s - Online ID: %s", __FUNCTION__, id->data); return 0; } @@ -175,22 +175,22 @@ int NpGetNpId(SceNpId* npid) static int sceNpGetNpId(u32 idPtr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, idPtr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x)", __FUNCTION__, idPtr); auto id = PSPPointer::Create(idPtr); if (!id.IsValid()) - return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); SceNpId dummyNpId{}; memset((SceNpId *)id, 0, sizeof(SceNpId)); int retval = NpGetNpId(id); if (retval < 0) - return hleLogError(SCENET, retval); + return hleLogError(Log::sceNet, retval); - INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, id->handle.data); + INFO_LOG(Log::sceNet, "%s - Online ID: %s", __FUNCTION__, id->handle.data); std::string datahex; DataToHexString(id->opt, sizeof(id->opt), &datahex); - INFO_LOG(SCENET, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); + INFO_LOG(Log::sceNet, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); id.NotifyWrite("NpGetNpId"); return 0; @@ -198,20 +198,20 @@ static int sceNpGetNpId(u32 idPtr) static int sceNpGetAccountRegion(u32 countryCodePtr, u32 regionCodePtr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x, %08x)", __FUNCTION__, countryCodePtr, regionCodePtr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x, %08x)", __FUNCTION__, countryCodePtr, regionCodePtr); auto countryCode = PSPPointer::Create(countryCodePtr); auto regionCode = PSPPointer::Create(regionCodePtr); if (!countryCode.IsValid() || !regionCode.IsValid()) - return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); memset((SceNpCountryCode *)countryCode, 0, sizeof(SceNpCountryCode)); memcpy(countryCode->data, npCountryCode, sizeof(countryCode->data)); memset((SceNpCountryCode *)regionCode, 0, sizeof(SceNpCountryCode)); memcpy(regionCode->data, npRegionCode, sizeof(regionCode->data)); - INFO_LOG(SCENET, "%s - Country Code: %s", __FUNCTION__, countryCode->data); - INFO_LOG(SCENET, "%s - Region? Code: %s", __FUNCTION__, regionCode->data); + INFO_LOG(Log::sceNet, "%s - Country Code: %s", __FUNCTION__, countryCode->data); + INFO_LOG(Log::sceNet, "%s - Region? Code: %s", __FUNCTION__, regionCode->data); countryCode.NotifyWrite("NpGetAccountRegion"); regionCode.NotifyWrite("NpGetAccountRegion"); @@ -221,15 +221,15 @@ static int sceNpGetAccountRegion(u32 countryCodePtr, u32 regionCodePtr) static int sceNpGetMyLanguages(u32 langListPtr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, langListPtr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x)", __FUNCTION__, langListPtr); auto langList = PSPPointer::Create(langListPtr); if (!langList.IsValid()) - return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); - INFO_LOG(SCENET, "%s - Language1 Code: %d", __FUNCTION__, npMyLangList.language1); - INFO_LOG(SCENET, "%s - Language2 Code: %d", __FUNCTION__, npMyLangList.language2); - INFO_LOG(SCENET, "%s - Language3 Code: %d", __FUNCTION__, npMyLangList.language3); + INFO_LOG(Log::sceNet, "%s - Language1 Code: %d", __FUNCTION__, npMyLangList.language1); + INFO_LOG(Log::sceNet, "%s - Language2 Code: %d", __FUNCTION__, npMyLangList.language2); + INFO_LOG(Log::sceNet, "%s - Language3 Code: %d", __FUNCTION__, npMyLangList.language3); *langList = npMyLangList; langList.NotifyWrite("NpGetMyLanguages"); @@ -239,21 +239,21 @@ static int sceNpGetMyLanguages(u32 langListPtr) static int sceNpGetUserProfile(u32 profilePtr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, profilePtr); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x)", __FUNCTION__, profilePtr); auto profile = PSPPointer::Create(profilePtr); if (!Memory::IsValidAddress(profilePtr)) - return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); memset((SceNpUserInformation *)profile, 0, sizeof(SceNpUserInformation)); truncate_cpy(profile->userId.handle.data, sizeof(profile->userId.handle.data), npOnlineId.c_str()); truncate_cpy(profile->icon.data, sizeof(profile->icon.data), npAvatarUrl.c_str()); - INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, profile->userId.handle.data); + INFO_LOG(Log::sceNet, "%s - Online ID: %s", __FUNCTION__, profile->userId.handle.data); std::string datahex; DataToHexString(profile->userId.opt, sizeof(profile->userId.opt), &datahex); - INFO_LOG(SCENET, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); - INFO_LOG(SCENET, "%s - Avatar URL: %s", __FUNCTION__, profile->icon.data); + INFO_LOG(Log::sceNet, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); + INFO_LOG(Log::sceNet, "%s - Avatar URL: %s", __FUNCTION__, profile->icon.data); profile.NotifyWrite("NpGetUserProfile"); @@ -280,14 +280,14 @@ void Register_sceNp() static int sceNpAuthTerm() { // No parameters - ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); npAuthInited = false; return 0; } static int sceNpAuthInit(u32 poolSize, u32 stackSize, u32 threadPrio) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %d, %d)", __FUNCTION__, poolSize, stackSize, threadPrio); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %d, %d)", __FUNCTION__, poolSize, stackSize, threadPrio); npAuthMemStat.npMemSize = poolSize - 0x20; npAuthMemStat.npMaxMemSize = 0x4050; // Dummy maximum foot print npAuthMemStat.npFreeMemSize = npAuthMemStat.npMemSize; @@ -299,11 +299,11 @@ static int sceNpAuthInit(u32 poolSize, u32 stackSize, u32 threadPrio) int sceNpAuthGetMemoryStat(u32 memStatAddr) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x)", __FUNCTION__, memStatAddr); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x)", __FUNCTION__, memStatAddr); auto memStat = PSPPointer::Create(memStatAddr); if (!memStat.IsValid()) - return hleLogError(SCENET, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); *memStat = npAuthMemStat; memStat.NotifyWrite("NpAuthGetMemoryStat"); @@ -325,21 +325,21 @@ return value >= 0 and <0 seems to be stored at a different location by the game */ int sceNpAuthCreateStartRequest(u32 paramAddr) { - WARN_LOG(SCENET, "UNTESTED %s(%08x) at %08x", __FUNCTION__, paramAddr, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x) at %08x", __FUNCTION__, paramAddr, currentMIPS->pc); if (!Memory::IsValidAddress(paramAddr)) - return hleLogError(SCENET, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); SceNpAuthRequestParameter params = {}; int size = Memory::Read_U32(paramAddr); Memory::Memcpy(¶ms, paramAddr, size); npServiceId = Memory::GetCharPointer(params.serviceIdAddr); - INFO_LOG(SCENET, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor); - INFO_LOG(SCENET, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr)); - INFO_LOG(SCENET, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr)); - INFO_LOG(SCENET, "%s - Consumed Count: %d", __FUNCTION__, params.consumedCount); - INFO_LOG(SCENET, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr)); + INFO_LOG(Log::sceNet, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor); + INFO_LOG(Log::sceNet, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr)); + INFO_LOG(Log::sceNet, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr)); + INFO_LOG(Log::sceNet, "%s - Consumed Count: %d", __FUNCTION__, params.consumedCount); + INFO_LOG(Log::sceNet, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr)); u32 retval = 0; if (params.size >= 32 && params.ticketCbAddr != 0) { @@ -364,10 +364,10 @@ int sceNpAuthCreateStartRequest(u32 paramAddr) if (!foundHandler && Memory::IsValidAddress(handler.entryPoint)) { npAuthHandlers[retval] = handler; - WARN_LOG(SCENET, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, retval); + WARN_LOG(Log::sceNet, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, retval); } else { - ERROR_LOG(SCENET, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); + ERROR_LOG(Log::sceNet, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); } // Patapon 3 will only Abort & Destroy AuthRequest if the ID is larger than 0. Is 0 a valid request id? retval++; @@ -388,10 +388,10 @@ int sceNpAuthCreateStartRequest(u32 paramAddr) // JPCSP is using length = 248 for dummy ticket int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, requestId, bufferAddr, length, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, requestId, bufferAddr, length, currentMIPS->pc); if (!Memory::IsValidAddress(bufferAddr)) - return hleLogError(SCENET, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); int result = length; Memory::Memset(bufferAddr, 0, length, "NpAuthGetTicket"); @@ -441,8 +441,8 @@ int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) // Patapon 3 will loop (for each DLC?) through an array of 4+4 bytes, ID addr (pchar) + result (int). Each loop calls this function using the same ticket addr but use different ID addr (arg3) and store the return value in result field (default/initial = -1) int sceNpAuthGetEntitlementById(u32 ticketBufferAddr, u32 ticketLength, u32 entitlementIdAddr, u32 arg4) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x, %d, %08x, %d)", __FUNCTION__, ticketBufferAddr, ticketLength, entitlementIdAddr, arg4); - INFO_LOG(SCENET, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(entitlementIdAddr)); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x, %d, %08x, %d)", __FUNCTION__, ticketBufferAddr, ticketLength, entitlementIdAddr, arg4); + INFO_LOG(Log::sceNet, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(entitlementIdAddr)); // Do we return the entitlement through function result? or update the ticket content? or replace the arg3 data with SceNpEntitlement struct? return 1; // dummy value assuming it's a boolean/flag, since we don't know how to return the entitlement result yet @@ -450,7 +450,7 @@ int sceNpAuthGetEntitlementById(u32 ticketBufferAddr, u32 ticketLength, u32 enti int sceNpAuthAbortRequest(int requestId) { - WARN_LOG(SCENET, "UNTESTED %s(%i)", __FUNCTION__, requestId); + WARN_LOG(Log::sceNet, "UNTESTED %s(%i)", __FUNCTION__, requestId); // TODO: Disconnect HTTPS connection & cancel the callback event std::lock_guard npAuthGuard(npAuthEvtMtx); for (auto it = npAuthEvents.begin(); it != npAuthEvents.end(); ) { @@ -462,15 +462,15 @@ int sceNpAuthAbortRequest(int requestId) int sceNpAuthDestroyRequest(int requestId) { - WARN_LOG(SCENET, "UNTESTED %s(%i)", __FUNCTION__, requestId); + WARN_LOG(Log::sceNet, "UNTESTED %s(%i)", __FUNCTION__, requestId); // Remove callback handler int handlerID = requestId - 1; if (npAuthHandlers.find(handlerID) != npAuthHandlers.end()) { npAuthHandlers.erase(handlerID); - WARN_LOG(SCENET, "%s: Deleted handler %d", __FUNCTION__, handlerID); + WARN_LOG(Log::sceNet, "%s: Deleted handler %d", __FUNCTION__, handlerID); } else { - ERROR_LOG(SCENET, "%s: Invalid request ID %d", __FUNCTION__, requestId); + ERROR_LOG(Log::sceNet, "%s: Invalid request ID %d", __FUNCTION__, requestId); } // Patapon 3 is checking for error code 0x80550402 @@ -479,7 +479,7 @@ int sceNpAuthDestroyRequest(int requestId) int sceNpAuthGetTicketParam(u32 ticketBufPtr, int ticketLen, int paramNum, u32 bufferPtr) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x, %0d, %d, %08x) at %08x", __FUNCTION__, ticketBufPtr, ticketLen, paramNum, bufferPtr, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x, %0d, %d, %08x) at %08x", __FUNCTION__, ticketBufPtr, ticketLen, paramNum, bufferPtr, currentMIPS->pc); const u32 PARAM_BUFFER_MAX_SIZE = 256; Memory::Memset(bufferPtr, 0, PARAM_BUFFER_MAX_SIZE); // JPCSP: This clear is always done, even when an error is returned if (paramNum < 0 || paramNum >= NUMBER_PARAMETERS) { @@ -495,7 +495,7 @@ int sceNpAuthGetTicketParam(u32 ticketBufPtr, int ticketLen, int paramNum, u32 b SceNpTicketParamData* ticketParam = (SceNpTicketParamData*)Memory::GetPointer(inbuf); u32 sz = (u32)sizeof(SceNpTicketParamData) + ticketParam->length; Memory::Memcpy(outbuf, inbuf, sz); - DEBUG_LOG(SCENET, "%s - Param #%d: Type = %04x, Length = %u", __FUNCTION__, i, static_cast(ticketParam->type), static_cast(ticketParam->length)); + DEBUG_LOG(Log::sceNet, "%s - Param #%d: Type = %04x, Length = %u", __FUNCTION__, i, static_cast(ticketParam->type), static_cast(ticketParam->length)); outbuf += sz; inbuf += sz; if (outbuf - bufferPtr >= PARAM_BUFFER_MAX_SIZE || inbuf - ticketBufPtr >= (u32)ticketLen) @@ -526,21 +526,21 @@ void Register_sceNpAuth() static int sceNpServiceTerm() { // No parameters - ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); return 0; } static int sceNpServiceInit(u32 poolSize, u32 stackSize, u32 threadPrio) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x, %08x, %08x)", __FUNCTION__, poolSize, stackSize, threadPrio); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x, %08x, %08x)", __FUNCTION__, poolSize, stackSize, threadPrio); return 0; } // FIXME: On Patapon 3 the Arg is pointing to a String, but based on RPCS3 the Arg is an Id integer ? static int sceNpLookupCreateTransactionCtx(u32 lookupTitleCtxIdAddr) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x)", __FUNCTION__, lookupTitleCtxIdAddr); - INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, Memory::GetCharPointer(lookupTitleCtxIdAddr)); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x)", __FUNCTION__, lookupTitleCtxIdAddr); + INFO_LOG(Log::sceNet, "%s - Title ID: %s", __FUNCTION__, Memory::GetCharPointer(lookupTitleCtxIdAddr)); // Patapon 3 will only Destroy if returned Id > 0. Is 0 a valid id? return 1; // returning dummy transaction id } @@ -548,7 +548,7 @@ static int sceNpLookupCreateTransactionCtx(u32 lookupTitleCtxIdAddr) // transId: id returned from sceNpLookupCreateTransactionCtx static int sceNpLookupDestroyTransactionCtx(s32 transId) { - ERROR_LOG(SCENET, "UNIMPL %s(%d)", __FUNCTION__, transId); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d)", __FUNCTION__, transId); return 0; } @@ -558,7 +558,7 @@ static int sceNpLookupDestroyTransactionCtx(s32 transId) // FIXME: maxSize and contentLength are u64 based on https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp.cpp ? But on Patapon 3 optionAddr will be deadbeef if maxSize is u64 ? static int sceNpLookupTitleSmallStorage(s32 transId, u32 dataAddr, u32 maxSize, u32 contentLengthAddr, u32 optionAddr) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %d, %08x[%d], %08x) at %08x", __FUNCTION__, transId, dataAddr, maxSize, contentLengthAddr, (Memory::IsValidAddress(contentLengthAddr)? Memory::Read_U32(contentLengthAddr): 0), optionAddr, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %d, %08x[%d], %08x) at %08x", __FUNCTION__, transId, dataAddr, maxSize, contentLengthAddr, (Memory::IsValidAddress(contentLengthAddr)? Memory::Read_U32(contentLengthAddr): 0), optionAddr, currentMIPS->pc); return 0; } @@ -571,7 +571,7 @@ static int sceNpLookupTitleSmallStorage(s32 transId, u32 dataAddr, u32 maxSize, // There could be more data in the struct? (at least 48-bytes?) static int sceNpRosterCreateRequest(u32 unknownAddr) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x) at %08x", __FUNCTION__, unknownAddr, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x) at %08x", __FUNCTION__, unknownAddr, currentMIPS->pc); return 1; // returning dummy roster id } @@ -584,19 +584,19 @@ static int sceNpRosterCreateRequest(u32 unknownAddr) // unknown6 set to 0 static int sceNpRosterGetFriendListEntry(s32 rosterId, u32 unknown1, u32 unknown2, u32 unknown3Addr, u32 unknown4Addr, u32 unknown5Addr, u32 unknown6) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x, %08x, %08x, %08x) at %08x", __FUNCTION__, rosterId, unknown1, unknown2, unknown3Addr, unknown4Addr, unknown5Addr, unknown6, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x, %08x, %08x, %08x) at %08x", __FUNCTION__, rosterId, unknown1, unknown2, unknown3Addr, unknown4Addr, unknown5Addr, unknown6, currentMIPS->pc); return 0; } static int sceNpRosterAbort(s32 rosterId) { - ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, rosterId, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d) at %08x", __FUNCTION__, rosterId, currentMIPS->pc); return 0; } static int sceNpRosterDeleteRequest(s32 rosterId) { - ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, rosterId, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d) at %08x", __FUNCTION__, rosterId, currentMIPS->pc); return 0; } diff --git a/Core/HLE/sceNp2.cpp b/Core/HLE/sceNp2.cpp index 70b349145b..a03829a23c 100644 --- a/Core/HLE/sceNp2.cpp +++ b/Core/HLE/sceNp2.cpp @@ -54,9 +54,9 @@ void notifyNpMatching2Handlers(NpMatching2Args &args, u32 ctxId, u32 serverId, u static int sceNpMatching2Init(int poolSize, int threadPriority, int cpuAffinityMask, int threadStackSize) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %d, %d, %d) at %08x", __FUNCTION__, poolSize, threadPriority, cpuAffinityMask, threadStackSize, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %d, %d, %d) at %08x", __FUNCTION__, poolSize, threadPriority, cpuAffinityMask, threadStackSize, currentMIPS->pc); //if (npMatching2Inited) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED); + // return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED); npMatching2MemStat.npMemSize = poolSize - 0x20; npMatching2MemStat.npMaxMemSize = 0x4050; // Dummy maximum foot print @@ -70,7 +70,7 @@ static int sceNpMatching2Init(int poolSize, int threadPriority, int cpuAffinityM static int sceNpMatching2Term() { - ERROR_LOG(SCENET, "UNIMPL %s() at %08x", __FUNCTION__, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s() at %08x", __FUNCTION__, currentMIPS->pc); npMatching2Inited = false; npMatching2Handlers.clear(); npMatching2Events.clear(); @@ -80,12 +80,12 @@ static int sceNpMatching2Term() static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr, u32 ctxIdPtr, int unknown) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x[%s], %08x[%08x], %08x[%hu], %i) at %08x", __FUNCTION__, communicationIdPtr, safe_string(Memory::GetCharPointer(communicationIdPtr)), passPhrasePtr, Memory::Read_U32(passPhrasePtr), ctxIdPtr, Memory::Read_U16(ctxIdPtr), unknown, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x[%s], %08x[%08x], %08x[%hu], %i) at %08x", __FUNCTION__, communicationIdPtr, safe_string(Memory::GetCharPointer(communicationIdPtr)), passPhrasePtr, Memory::Read_U32(passPhrasePtr), ctxIdPtr, Memory::Read_U16(ctxIdPtr), unknown, currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); if (!Memory::IsValidAddress(communicationIdPtr) || !Memory::IsValidAddress(passPhrasePtr) || !Memory::IsValidAddress(ctxIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // FIXME: It seems Context are mapped to TitleID? may return 0x80550C05 or 0x80550C06 when finding an existing context SceNpCommunicationId* titleid = (SceNpCommunicationId*)Memory::GetCharPointer(communicationIdPtr); @@ -96,16 +96,16 @@ static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr SceNpId npid{}; int retval = NpGetNpId(&npid); if (retval < 0) - return hleLogError(SCENET, retval); + return hleLogError(Log::sceNet, retval); - INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, titleid->data); - INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, npid.handle.data); + INFO_LOG(Log::sceNet, "%s - Title ID: %s", __FUNCTION__, titleid->data); + INFO_LOG(Log::sceNet, "%s - Online ID: %s", __FUNCTION__, npid.handle.data); std::string datahex; DataToHexString(npid.opt, sizeof(npid.opt), &datahex); - INFO_LOG(SCENET, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); + INFO_LOG(Log::sceNet, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); datahex.clear(); DataToHexString(10, 0, passph->data, sizeof(passph->data), &datahex); - INFO_LOG(SCENET, "%s - Passphrase: \n%s", __FUNCTION__, datahex.c_str()); + INFO_LOG(Log::sceNet, "%s - Passphrase: \n%s", __FUNCTION__, datahex.c_str()); // TODO: Allocate & zeroed a memory of 68 bytes where npId (36 bytes) is copied to offset 8, offset 44 = 0x00026808, offset 48 = 0 @@ -117,15 +117,15 @@ static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr static int sceNpMatching2ContextStart(int ctxId) { - ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); //if (!npMatching2Ctx) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + // return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID //if (npMatching2Ctx.started) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED); + // return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED); // TODO: use sceNpGetUserProfile and check server availability using sceNpService_76867C01 //npMatching2Ctx.started = true; @@ -134,7 +134,7 @@ static int sceNpMatching2ContextStart(int ctxId) bool cancelled = false; net::RequestProgress progress(&cancelled); if (!client.Resolve(url.Host().c_str(), url.Port())) { - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP failed to resolve %s", url.Resource().c_str()); + return hleLogError(Log::sceNet, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP failed to resolve %s", url.Resource().c_str()); } client.SetDataTimeout(20.0); @@ -143,12 +143,12 @@ static int sceNpMatching2ContextStart(int ctxId) snprintf(requestHeaders, sizeof(requestHeaders), "User-Agent: PS3Community-agent/1.0.0 libhttp/1.0.0\r\n"); - DEBUG_LOG(SCENET, "GET URI: %s", url.ToString().c_str()); + DEBUG_LOG(Log::sceNet, "GET URI: %s", url.ToString().c_str()); http::RequestParams req(url.Resource(), "*/*"); int err = client.SendRequest("GET", req, requestHeaders, &progress); if (err < 0) { client.Disconnect(); - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP GET Error = %d", err); + return hleLogError(Log::sceNet, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP GET Error = %d", err); } net::Buffer readbuf; @@ -156,13 +156,13 @@ static int sceNpMatching2ContextStart(int ctxId) int code = client.ReadResponseHeaders(&readbuf, responseHeaders, &progress); if (code != 200) { client.Disconnect(); - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP Error Code = %d", code); + return hleLogError(Log::sceNet, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP Error Code = %d", code); } net::Buffer output; int res = client.ReadResponseEntity(&readbuf, responseHeaders, &output, &progress); if (res != 0) { - WARN_LOG(SCENET, "Unable to read HTTP response entity: %d", res); + WARN_LOG(Log::sceNet, "Unable to read HTTP response entity: %d", res); } client.Disconnect(); @@ -174,19 +174,19 @@ static int sceNpMatching2ContextStart(int ctxId) std::string text; size_t ofs = entity.find("titleid="); if (ofs == std::string::npos) - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "titleid not found"); + return hleLogError(Log::sceNet, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "titleid not found"); ofs += 9; size_t ofs2 = entity.find('"', ofs); text = entity.substr(ofs, ofs2-ofs); - INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, text.c_str()); + INFO_LOG(Log::sceNet, "%s - Title ID: %s", __FUNCTION__, text.c_str()); int i = 1; while (true) { ofs = entity.find("", ++ofs2); + ofs = entity.find('>', ++ofs2); if (ofs == std::string::npos) - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent host not found"); + return hleLogError(Log::sceNet, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent host not found"); ofs2 = entity.find("pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); //if (!npMatching2Ctx) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + // return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID //if (!npMatching2Ctx.started) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED); + // return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED); //TODO: Stop any in-progress HTTPClient communication used on sceNpMatching2ContextStart //npMatching2Ctx.started = false; @@ -255,21 +255,21 @@ static int sceNpMatching2ContextStop(int ctxId) static int sceNpMatching2DestroyContext(int ctxId) { - ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); //if (!npMatching2Ctx) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + // return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID // Remove callback handler int handlerID = ctxId - 1; if (npMatching2Handlers.find(handlerID) != npMatching2Handlers.end()) { npMatching2Handlers.erase(handlerID); - WARN_LOG(SCENET, "%s: Deleted handler %d", __FUNCTION__, handlerID); + WARN_LOG(Log::sceNet, "%s: Deleted handler %d", __FUNCTION__, handlerID); } else { - ERROR_LOG(SCENET, "%s: Invalid Context ID %d", __FUNCTION__, ctxId); + ERROR_LOG(Log::sceNet, "%s: Invalid Context ID %d", __FUNCTION__, ctxId); } return 0; @@ -277,13 +277,13 @@ static int sceNpMatching2DestroyContext(int ctxId) static int sceNpMatching2GetMemoryStat(u32 memStatPtr) { - ERROR_LOG(SCENET, "UNIMPL %s(%08x) at %08x", __FUNCTION__, memStatPtr, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x) at %08x", __FUNCTION__, memStatPtr, currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); auto memStat = PSPPointer::Create(memStatPtr); if (!memStat.IsValid()) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); *memStat = npMatching2MemStat; memStat.NotifyWrite("NpMatching2GetMemoryStat"); @@ -293,12 +293,12 @@ static int sceNpMatching2GetMemoryStat(u32 memStatPtr) static int sceNpMatching2RegisterSignalingCallback(int ctxId, u32 callbackFunctionAddr, u32 callbackArgument) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x) at %08x", __FUNCTION__, ctxId, callbackFunctionAddr, callbackArgument, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x) at %08x", __FUNCTION__, ctxId, callbackFunctionAddr, callbackArgument, currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); if (ctxId <= 0) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID); int id = ctxId - 1; if (callbackFunctionAddr != 0) { @@ -320,10 +320,10 @@ static int sceNpMatching2RegisterSignalingCallback(int ctxId, u32 callbackFuncti if (!foundHandler && Memory::IsValidAddress(handler.entryPoint)) { npMatching2Handlers[id] = handler; - WARN_LOG(SCENET, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, id); + WARN_LOG(Log::sceNet, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, id); } else { - ERROR_LOG(SCENET, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); + ERROR_LOG(Log::sceNet, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); } //u32 dataLength = 4097; @@ -337,12 +337,12 @@ static int sceNpMatching2RegisterSignalingCallback(int ctxId, u32 callbackFuncti static int sceNpMatching2GetServerIdListLocal(int ctxId, u32 serverIdsPtr, int maxServerIds) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, ctxId, serverIdsPtr, maxServerIds, currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, ctxId, serverIdsPtr, maxServerIds, currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); if (!Memory::IsValidAddress(serverIdsPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); // Returning dummy Id, a 16-bit variable according to JPCSP for (int i = 0; i < maxServerIds; i++) @@ -354,18 +354,18 @@ static int sceNpMatching2GetServerIdListLocal(int ctxId, u32 serverIdsPtr, int m // Unknown1 = optParam, unknown2 = assignedReqId according to https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.cpp ? static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1Ptr, u32 unknown2Ptr) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x[%d], %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, serverIdPtr, Memory::Read_U16(serverIdPtr), unknown1Ptr, unknown2Ptr, Memory::Read_U32(unknown2Ptr), currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x[%d], %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, serverIdPtr, Memory::Read_U16(serverIdPtr), unknown1Ptr, unknown2Ptr, Memory::Read_U32(unknown2Ptr), currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); if (!Memory::IsValidAddress(serverIdPtr) || !Memory::IsValidAddress(unknown2Ptr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? // Server ID is a 16-bit variable according to JPCSP int serverId = Memory::Read_U16(serverIdPtr); if (serverId == 0) - return hleLogError(SCENET, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? + return hleLogError(Log::sceNet, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? // Output to unknown1(infoBuffer)? and unknown2(infoLength or flags)? // Patapon 3 is using serverId at 09FFF2F4, unknown1 at 09FFF2E4, unknown2 at 09FFF2E0, which mean unknown1's can only fit upto 16-bytes @@ -416,12 +416,12 @@ static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1P static int sceNpMatching2LeaveRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? u32 cbFunc = Memory::Read_U32(reqParamPtr); u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); @@ -450,18 +450,18 @@ static int sceNpMatching2LeaveRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, static int sceNpMatching2JoinRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 unknown1, u32 unknown2, u32 assignedReqIdPtr) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? // Server ID is a 16-bit variable according to JPCSP int serverId = Memory::Read_U16(reqParamPtr + 0x06); if (serverId == 0) - return hleLogError(SCENET, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? + return hleLogError(Log::sceNet, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? u32 cbFunc = Memory::Read_U32(reqParamPtr); u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); @@ -493,12 +493,12 @@ static int sceNpMatching2JoinRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u static int sceNpMatching2SearchRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? u32 cbFunc = Memory::Read_U32(reqParamPtr); u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); @@ -517,12 +517,12 @@ static int sceNpMatching2SearchRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, static int sceNpMatching2SendRoomChatMessage(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) { - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + ERROR_LOG(Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? u32 cbFunc = Memory::Read_U32(reqParamPtr); u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); diff --git a/Core/HLE/sceOpenPSID.cpp b/Core/HLE/sceOpenPSID.cpp index f15b7bc142..62def434e6 100644 --- a/Core/HLE/sceOpenPSID.cpp +++ b/Core/HLE/sceOpenPSID.cpp @@ -37,7 +37,7 @@ void __OpenPSIDShutdown() { static int sceOpenPSIDGetOpenPSID(u32 OpenPSIDPtr) { - WARN_LOG(HLE, "UNTESTED %s(%08x)", __FUNCTION__, OpenPSIDPtr); + WARN_LOG(Log::HLE, "UNTESTED %s(%08x)", __FUNCTION__, OpenPSIDPtr); auto ptr = PSPPointer::Create(OpenPSIDPtr); if (ptr.IsValid()) { @@ -49,7 +49,7 @@ static int sceOpenPSIDGetOpenPSID(u32 OpenPSIDPtr) static int sceOpenPSIDGetPSID(u32 OpenPSIDPtr,u32 unknown) { - WARN_LOG(HLE, "UNTESTED %s(%08x, %08x)", __FUNCTION__, OpenPSIDPtr, unknown); + WARN_LOG(Log::HLE, "UNTESTED %s(%08x, %08x)", __FUNCTION__, OpenPSIDPtr, unknown); auto ptr = PSPPointer::Create(OpenPSIDPtr); if (ptr.IsValid()) { @@ -74,14 +74,14 @@ Returns: 0 on success, otherwise < 0. */ static s32 sceDdrdb_F013F8BF(u32 pDataPtr, u32 pSigPtr) { - ERROR_LOG(HLE, "UNIMPL %s(%08x, %08x)", __FUNCTION__, pDataPtr, pSigPtr); + ERROR_LOG(Log::HLE, "UNIMPL %s(%08x, %08x)", __FUNCTION__, pDataPtr, pSigPtr); return 0; } // unkPtr might be a pointer to OpenPSID static s32 sceOpenPSIDGetProductCode(u32 unkPtr) { - ERROR_LOG_REPORT(HLE, "UNIMPL %s(%08x)", __FUNCTION__, unkPtr); + ERROR_LOG_REPORT(Log::HLE, "UNIMPL %s(%08x)", __FUNCTION__, unkPtr); return 0; } diff --git a/Core/HLE/sceP3da.cpp b/Core/HLE/sceP3da.cpp index e9cd6aa1c4..706b891057 100644 --- a/Core/HLE/sceP3da.cpp +++ b/Core/HLE/sceP3da.cpp @@ -24,13 +24,13 @@ static u32 sceP3daBridgeInit(u32 channelsNum, u32 samplesNum) { - ERROR_LOG_REPORT(SCEAUDIO, "UNIMPL sceP3daBridgeInit(%08x, %08x)", channelsNum, samplesNum); + ERROR_LOG_REPORT(Log::sceAudio, "UNIMPL sceP3daBridgeInit(%08x, %08x)", channelsNum, samplesNum); return 0; } static u32 sceP3daBridgeExit() { - ERROR_LOG_REPORT(SCEAUDIO, "UNIMPL sceP3daBridgeExit()"); + ERROR_LOG_REPORT(Log::sceAudio, "UNIMPL sceP3daBridgeExit()"); return 0; } @@ -45,7 +45,7 @@ static inline int getScaleValue(u32 channelsNum) { static u32 sceP3daBridgeCore(u32 p3daCoreAddr, u32 channelsNum, u32 samplesNum, u32 inputAddr, u32 outputAddr) { - DEBUG_LOG(SCEAUDIO, "sceP3daBridgeCore(%08x, %08x, %08x, %08x, %08x)", p3daCoreAddr, channelsNum, samplesNum, inputAddr, outputAddr); + DEBUG_LOG(Log::sceAudio, "sceP3daBridgeCore(%08x, %08x, %08x, %08x, %08x)", p3daCoreAddr, channelsNum, samplesNum, inputAddr, outputAddr); if (Memory::IsValidAddress(inputAddr) && Memory::IsValidAddress(outputAddr)) { int scaleval = getScaleValue(channelsNum); s16_le *outbuf = (s16_le *)Memory::GetPointerWriteUnchecked(outputAddr); diff --git a/Core/HLE/scePauth.cpp b/Core/HLE/scePauth.cpp index 705f6aeeaf..a9915e9ebc 100644 --- a/Core/HLE/scePauth.cpp +++ b/Core/HLE/scePauth.cpp @@ -36,7 +36,7 @@ static int scePauth_F7AA47F6(u32 srcPtr, int srcLength, u32 destLengthPtr, u32 w if (decryptResult < 0) { - ERROR_LOG(HLE, "Pauth decryption failed 0x%08X", decryptResult); + ERROR_LOG(Log::HLE, "Pauth decryption failed 0x%08X", decryptResult); return decryptResult; } @@ -53,7 +53,7 @@ static int scePauth_98B83B5D(u32 srcPtr, int srcLength, u32 destLengthPtr, u32 w if (decryptResult < 0) { - ERROR_LOG(HLE, "Pauth decryption failed 0x%08X", decryptResult); + ERROR_LOG(Log::HLE, "Pauth decryption failed 0x%08X", decryptResult); return decryptResult; } diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index d6fc4fd0aa..95c9d19c6f 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -165,49 +165,49 @@ void __PowerDoState(PointerWrap &p) { } static int scePowerGetBatteryLifePercent() { - DEBUG_LOG(HLE, "100=scePowerGetBatteryLifePercent"); + DEBUG_LOG(Log::HLE, "100=scePowerGetBatteryLifePercent"); return 100; } static int scePowerGetBatteryLifeTime() { - DEBUG_LOG(HLE, "0=scePowerGetBatteryLifeTime()"); + DEBUG_LOG(Log::HLE, "0=scePowerGetBatteryLifeTime()"); // 0 means we're on AC power. return 0; } static int scePowerGetBatteryTemp() { - DEBUG_LOG(HLE, "0=scePowerGetBatteryTemp()"); + DEBUG_LOG(Log::HLE, "0=scePowerGetBatteryTemp()"); // 0 means celsius temperature of the battery return 0; } static int scePowerIsPowerOnline() { - DEBUG_LOG(HLE, "1=scePowerIsPowerOnline"); + DEBUG_LOG(Log::HLE, "1=scePowerIsPowerOnline"); return 1; } static int scePowerIsBatteryExist() { - DEBUG_LOG(HLE, "1=scePowerIsBatteryExist"); + DEBUG_LOG(Log::HLE, "1=scePowerIsBatteryExist"); return 1; } static int scePowerIsBatteryCharging() { - DEBUG_LOG(HLE, "0=scePowerIsBatteryCharging"); + DEBUG_LOG(Log::HLE, "0=scePowerIsBatteryCharging"); return 0; } static int scePowerGetBatteryChargingStatus() { - DEBUG_LOG(HLE, "0=scePowerGetBatteryChargingStatus"); + DEBUG_LOG(Log::HLE, "0=scePowerGetBatteryChargingStatus"); return 0; } static int scePowerIsLowBattery() { - DEBUG_LOG(HLE, "0=scePowerIsLowBattery"); + DEBUG_LOG(Log::HLE, "0=scePowerIsLowBattery"); return 0; } static int scePowerRegisterCallback(int slot, int cbId) { - DEBUG_LOG(HLE, "0=scePowerRegisterCallback(%i, %i)", slot, cbId); + DEBUG_LOG(Log::HLE, "0=scePowerRegisterCallback(%i, %i)", slot, cbId); if (slot < -1 || slot >= numberOfCBPowerSlotsPrivate) { return PSP_POWER_ERROR_INVALID_SLOT; @@ -248,7 +248,7 @@ static int scePowerRegisterCallback(int slot, int cbId) { } static int scePowerUnregisterCallback(int slotId) { - DEBUG_LOG(HLE, "0=scePowerUnregisterCallback(%i)", slotId); + DEBUG_LOG(Log::HLE, "0=scePowerUnregisterCallback(%i)", slotId); if (slotId < 0 || slotId >= numberOfCBPowerSlotsPrivate) { return PSP_POWER_ERROR_INVALID_SLOT; @@ -259,7 +259,7 @@ static int scePowerUnregisterCallback(int slotId) { if (powerCbSlots[slotId] != 0) { int cbId = powerCbSlots[slotId]; - DEBUG_LOG(HLE, "0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId); + DEBUG_LOG(Log::HLE, "0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId); powerCbSlots[slotId] = 0; } else { return PSP_POWER_ERROR_EMPTY_SLOT; @@ -269,7 +269,7 @@ static int scePowerUnregisterCallback(int slotId) { } static int sceKernelPowerLock(int lockType) { - DEBUG_LOG(HLE, "0=sceKernelPowerLock(%i)", lockType); + DEBUG_LOG(Log::HLE, "0=sceKernelPowerLock(%i)", lockType); if (lockType == 0) { return 0; } else { @@ -278,7 +278,7 @@ static int sceKernelPowerLock(int lockType) { } static int sceKernelPowerUnlock(int lockType) { - DEBUG_LOG(HLE, "0=sceKernelPowerUnlock(%i)", lockType); + DEBUG_LOG(Log::HLE, "0=sceKernelPowerUnlock(%i)", lockType); if (lockType == 0) { return 0; } else { @@ -287,7 +287,7 @@ static int sceKernelPowerUnlock(int lockType) { } static int sceKernelPowerTick(int flag) { - DEBUG_LOG(HLE, "UNIMPL 0=sceKernelPowerTick(%i)", flag); + DEBUG_LOG(Log::HLE, "UNIMPL 0=sceKernelPowerTick(%i)", flag); return 0; } @@ -323,15 +323,15 @@ static int sceKernelVolatileMemTryLock(int type, u32 paddr, u32 psize) { // and with that it's still broken. So it's not this, unfortunately. // Leaving it in for the 0.9.8 release anyway. hleEatCycles(500000); - DEBUG_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - success", type, paddr, psize); + DEBUG_LOG(Log::HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - success", type, paddr, psize); break; case SCE_KERNEL_ERROR_POWER_VMEM_IN_USE: - ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - already locked!", type, paddr, psize); + ERROR_LOG(Log::HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - already locked!", type, paddr, psize); break; default: - ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemTryLock(%i, %08x, %08x) - error", type, paddr, psize, error); + ERROR_LOG_REPORT(Log::HLE, "%08x=sceKernelVolatileMemTryLock(%i, %08x, %08x) - error", type, paddr, psize, error); break; } @@ -365,7 +365,7 @@ int KernelVolatileMemUnlock(int type) { } if (wokeThreads) { - INFO_LOG(HLE, "KernelVolatileMemUnlock(%i) handed over to another thread", type); + INFO_LOG(Log::HLE, "KernelVolatileMemUnlock(%i) handed over to another thread", type); hleReSchedule("volatile mem unlocked"); } return 0; @@ -374,14 +374,14 @@ int KernelVolatileMemUnlock(int type) { static int sceKernelVolatileMemUnlock(int type) { int error = KernelVolatileMemUnlock(type); if (error == SCE_KERNEL_ERROR_INVALID_MODE) { - ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) - invalid mode", type); + ERROR_LOG_REPORT(Log::HLE, "sceKernelVolatileMemUnlock(%i) - invalid mode", type); return error; } else if (error == SCE_KERNEL_ERROR_SEMA_OVF) { - ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type); + ERROR_LOG_REPORT(Log::HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type); return error; } - return hleLogSuccessI(HLE, 0); + return hleLogSuccessI(Log::HLE, 0); } static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) { @@ -401,12 +401,12 @@ static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) { case 0: // Should only wait 1200 cycles though according to Unknown's testing, hleEatCycles(1200); - DEBUG_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - success", type, paddr, psize); + DEBUG_LOG(Log::HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - success", type, paddr, psize); break; case SCE_KERNEL_ERROR_POWER_VMEM_IN_USE: { - WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - already locked, waiting", type, paddr, psize); + WARN_LOG(Log::HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - already locked, waiting", type, paddr, psize); const VolatileWaitingThread waitInfo = { __KernelGetCurThread(), paddr, psize }; volatileWaitingThreads.push_back(waitInfo); __KernelWaitCurThread(WAITTYPE_VMEM, 1, 0, 0, false, "volatile mem waited"); @@ -415,7 +415,7 @@ static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) { case SCE_KERNEL_ERROR_CAN_NOT_WAIT: { - WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): dispatch disabled", type, paddr, psize); + WARN_LOG(Log::HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): dispatch disabled", type, paddr, psize); Memory::Write_U32(0x08400000, paddr); Memory::Write_U32(0x00400000, psize); } @@ -423,14 +423,14 @@ static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) { case SCE_KERNEL_ERROR_ILLEGAL_CONTEXT: { - WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): in interrupt", type, paddr, psize); + WARN_LOG(Log::HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): in interrupt", type, paddr, psize); Memory::Write_U32(0x08400000, paddr); Memory::Write_U32(0x00400000, psize); } break; default: - ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemLock(%i, %08x, %08x) - error", type, paddr, psize, error); + ERROR_LOG_REPORT(Log::HLE, "%08x=sceKernelVolatileMemLock(%i, %08x, %08x) - error", type, paddr, psize, error); break; } @@ -441,19 +441,19 @@ static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) { static u32 scePowerSetClockFrequency(u32 pllfreq, u32 cpufreq, u32 busfreq) { // 190 might (probably) be a typo for 19, but it's what the actual PSP validates against. if (pllfreq < 19 || pllfreq < cpufreq || pllfreq > 333) { - return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid pll frequency"); + return hleLogWarning(Log::sceMisc, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid pll frequency"); } if (cpufreq == 0 || cpufreq > 333) { - return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid cpu frequency"); + return hleLogWarning(Log::sceMisc, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid cpu frequency"); } if (busfreq == 0 || busfreq > 166) { - return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid bus frequency"); + return hleLogWarning(Log::sceMisc, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid bus frequency"); } // TODO: More restrictions. if (GetLockedCPUSpeedMhz() > 0) { - INFO_LOG(HLE, "scePowerSetClockFrequency(%i,%i,%i): locked by user config at %i, %i, %i", pllfreq, cpufreq, busfreq, GetLockedCPUSpeedMhz(), GetLockedCPUSpeedMhz(), busFreq); + INFO_LOG(Log::HLE, "scePowerSetClockFrequency(%i,%i,%i): locked by user config at %i, %i, %i", pllfreq, cpufreq, busfreq, GetLockedCPUSpeedMhz(), GetLockedCPUSpeedMhz(), busFreq); } else { - INFO_LOG(HLE, "scePowerSetClockFrequency(%i,%i,%i)", pllfreq, cpufreq, busfreq); + INFO_LOG(Log::HLE, "scePowerSetClockFrequency(%i,%i,%i)", pllfreq, cpufreq, busfreq); } // Only reschedules when the stepped PLL frequency changes. // It seems like the busfreq parameter has no effect (but can cause errors.) @@ -485,21 +485,21 @@ static u32 scePowerSetClockFrequency(u32 pllfreq, u32 cpufreq, u32 busfreq) { static u32 scePowerSetCpuClockFrequency(u32 cpufreq) { if (cpufreq == 0 || cpufreq > 333) { - return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency"); + return hleLogWarning(Log::sceMisc, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency"); } if (GetLockedCPUSpeedMhz() > 0) { - return hleLogDebug(SCEMISC, 0, "locked by user config at %i", GetLockedCPUSpeedMhz()); + return hleLogDebug(Log::sceMisc, 0, "locked by user config at %i", GetLockedCPUSpeedMhz()); } CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq)); - return hleLogSuccessI(SCEMISC, 0); + return hleLogSuccessI(Log::sceMisc, 0); } static u32 scePowerSetBusClockFrequency(u32 busfreq) { if (busfreq == 0 || busfreq > 111) { - return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency"); + return hleLogWarning(Log::sceMisc, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency"); } if (GetLockedCPUSpeedMhz() > 0) { - return hleLogDebug(SCEMISC, 0, "locked by user config at %i", GetLockedCPUSpeedMhz() / 2); + return hleLogDebug(Log::sceMisc, 0, "locked by user config at %i", GetLockedCPUSpeedMhz() / 2); } // The value passed is validated, but then doesn't seem to matter for the result. @@ -516,47 +516,47 @@ static u32 scePowerSetBusClockFrequency(u32 busfreq) { else busFreq = pllFreq / 2; - return hleLogSuccessI(SCEMISC, 0); + return hleLogSuccessI(Log::sceMisc, 0); } static u32 scePowerGetCpuClockFrequencyInt() { int cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000; - return hleLogSuccessI(SCEMISC, cpuFreq); + return hleLogSuccessI(Log::sceMisc, cpuFreq); } static u32 scePowerGetPllClockFrequencyInt() { - return hleLogSuccessInfoI(SCEMISC, pllFreq / 1000000); + return hleLogSuccessInfoI(Log::sceMisc, pllFreq / 1000000); } static u32 scePowerGetBusClockFrequencyInt() { - return hleLogSuccessInfoI(SCEMISC, busFreq / 1000000); + return hleLogSuccessInfoI(Log::sceMisc, busFreq / 1000000); } static float scePowerGetCpuClockFrequencyFloat() { float cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000.0f; - DEBUG_LOG(SCEMISC, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq); + DEBUG_LOG(Log::sceMisc, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq); return cpuFreq; } static float scePowerGetPllClockFrequencyFloat() { - INFO_LOG(SCEMISC, "%f=scePowerGetPllClockFrequencyFloat()", (float)pllFreq / 1000000.0f); + INFO_LOG(Log::sceMisc, "%f=scePowerGetPllClockFrequencyFloat()", (float)pllFreq / 1000000.0f); return (float) pllFreq / 1000000.0f; } static float scePowerGetBusClockFrequencyFloat() { - INFO_LOG(SCEMISC, "%f=scePowerGetBusClockFrequencyFloat()", (float)busFreq / 1000000.0f); + INFO_LOG(Log::sceMisc, "%f=scePowerGetBusClockFrequencyFloat()", (float)busFreq / 1000000.0f); return (float) busFreq / 1000000.0f; } static int scePowerTick() { - DEBUG_LOG(SCEMISC, "scePowerTick()"); + DEBUG_LOG(Log::sceMisc, "scePowerTick()"); // Don't think we need to do anything. return 0; } static u32 IsPSPNonFat() { - DEBUG_LOG(SCEMISC, "%d=scePower_a85880d0_IsPSPNonFat()", g_Config.iPSPModel); + DEBUG_LOG(Log::sceMisc, "%d=scePower_a85880d0_IsPSPNonFat()", g_Config.iPSPModel); return g_Config.iPSPModel; } diff --git a/Core/HLE/scePsmf.cpp b/Core/HLE/scePsmf.cpp index 8f142bb456..19c0a481c9 100644 --- a/Core/HLE/scePsmf.cpp +++ b/Core/HLE/scePsmf.cpp @@ -306,7 +306,7 @@ public: const u32 EP_MAP_STRIDE = 1 + 1 + 4 + 4; if (psmf->headerOffset != 0 && !Memory::IsValidRange(psmf->headerOffset, psmf->EPMapOffset + EP_MAP_STRIDE * psmf->EPMapEntriesNum)) { - ERROR_LOG(ME, "Invalid PSMF EP map entry count: %d", psmf->EPMapEntriesNum); + ERROR_LOG(Log::ME, "Invalid PSMF EP map entry count: %d", psmf->EPMapEntriesNum); psmf->EPMapEntriesNum = Memory::ValidSize(psmf->headerOffset + psmf->EPMapOffset, EP_MAP_STRIDE * psmf->EPMapEntriesNum) / EP_MAP_STRIDE; } @@ -322,7 +322,7 @@ public: psmf->EPMap.push_back(entry); } - INFO_LOG(ME, "PSMF MPEG data found: id=%02x, privid=%02x, epmoff=%08x, epmnum=%08x, width=%i, height=%i", streamId, privateStreamId, psmf->EPMapOffset, psmf->EPMapEntriesNum, psmf->videoWidth, psmf->videoHeight); + INFO_LOG(Log::ME, "PSMF MPEG data found: id=%02x, privid=%02x, epmoff=%08x, epmnum=%08x, width=%i, height=%i", streamId, privateStreamId, psmf->EPMapOffset, psmf->EPMapEntriesNum, psmf->videoWidth, psmf->videoHeight); } void readPrivateAudioStreamParams(const u8 *addr, Psmf *psmf) { @@ -332,7 +332,7 @@ public: // Note: "frequency" is usually 2. But that's what scePsmfGetAudioInfo() writes too. audioFrequency_ = addr[15]; // two unknowns here - INFO_LOG(ME, "PSMF private audio found: id=%02x, privid=%02x, channels=%i, freq=%i", streamId, privateStreamId, psmf->audioChannels, psmf->audioFrequency); + INFO_LOG(Log::ME, "PSMF private audio found: id=%02x, privid=%02x, channels=%i, freq=%i", streamId, privateStreamId, psmf->audioChannels, psmf->audioFrequency); } bool matchesType(int ty) { @@ -386,7 +386,7 @@ Psmf::Psmf(const u8 *ptr, u32 data) { currentStreamChannel = -1; if (data != 0 && !Memory::IsValidRange(data, 0x82 + numStreams * 16)) { - ERROR_LOG(ME, "Invalid PSMF stream count: %d", numStreams); + ERROR_LOG(Log::ME, "Invalid PSMF stream count: %d", numStreams); numStreams = Memory::ValidSize(data + 0x82, numStreams * 16) / 16; } @@ -401,7 +401,7 @@ Psmf::Psmf(const u8 *ptr, u32 data) { int type = PSMF_ATRAC_STREAM; int privateStreamId = currentStreamAddr[1]; if ((privateStreamId & 0xF0) != 0) { - WARN_LOG_REPORT(ME, "Unknown private stream type, assuming PCM: %02x", privateStreamId); + WARN_LOG_REPORT(Log::ME, "Unknown private stream type, assuming PCM: %02x", privateStreamId); type = PSMF_PCM_STREAM; } stream = new PsmfStream(type, privateStreamId & 0x0F); @@ -758,22 +758,22 @@ static void DelayPsmfStateChange(u32 psmfPlayer, u32 newState, s64 delayUs) { static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) { if (!Memory::IsValidAddress(psmfStruct) || !Memory::IsValidAddress(psmfData)) { // Crashes on a PSP. - return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); + return hleReportError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); } Psmf *psmf = new Psmf(Memory::GetPointer(psmfData), psmfData); if (psmf->magic != PSMF_MAGIC) { delete psmf; - return hleLogError(ME, ERROR_PSMF_INVALID_PSMF, "invalid psmf data"); + return hleLogError(Log::ME, ERROR_PSMF_INVALID_PSMF, "invalid psmf data"); } // Note: devkit 00000000 supports only '0012'(0F), '0013'(1F), and '0014'(2F). 03000310+ supports '0015'(3F.) if (psmf->version == 0) { delete psmf; - return hleLogError(ME, ERROR_PSMF_BAD_VERSION, "invalid psmf version"); + return hleLogError(Log::ME, ERROR_PSMF_BAD_VERSION, "invalid psmf version"); } if (psmf->streamOffset == 0) { delete psmf; - return hleLogError(ME, ERROR_PSMF_INVALID_VALUE, "invalid psmf version"); + return hleLogError(Log::ME, ERROR_PSMF_INVALID_VALUE, "invalid psmf version"); } // Note: this structure changes between versions. @@ -794,21 +794,21 @@ static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) { delete iter->second; psmfMap[data->headerOffset] = psmf; - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfGetNumberOfStreams(u32 psmfStruct) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } - return hleLogSuccessI(ME, psmf->numStreams); + return hleLogSuccessI(Log::ME, psmf->numStreams); } static u32 scePsmfGetNumberOfSpecificStreams(u32 psmfStruct, int streamType) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } int streamNum = 0; @@ -818,113 +818,113 @@ static u32 scePsmfGetNumberOfSpecificStreams(u32 psmfStruct, int streamType) { } } - return hleLogSuccessI(ME, streamNum); + return hleLogSuccessI(Log::ME, streamNum); } static u32 scePsmfSpecifyStreamWithStreamType(u32 psmfStruct, u32 streamType, u32 channel) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } if (!psmf->setStreamWithType(psmfStruct, streamType, channel)) { // An invalid type seems to make the stream number invalid, but retain the old type/channel. psmf->setStreamNum(psmfStruct, ERROR_PSMF_INVALID_ID, false); // Also, returns 0 even when no stream found. - return hleLogWarning(ME, 0, "no stream found"); + return hleLogWarning(Log::ME, 0, "no stream found"); } - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfSpecifyStreamWithStreamTypeNumber(u32 psmfStruct, u32 streamType, u32 typeNum) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } if (!psmf->setStreamWithTypeNumber(psmfStruct, streamType, typeNum)) { // Don't update stream, just bail out. - return hleLogWarning(ME, ERROR_PSMF_INVALID_ID, "no stream found"); + return hleLogWarning(Log::ME, ERROR_PSMF_INVALID_ID, "no stream found"); } - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfSpecifyStream(u32 psmfStruct, int streamNum) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } if (!psmf->setStreamNum(psmfStruct, streamNum)) { psmf->setStreamNum(psmfStruct, ERROR_PSMF_NOT_INITIALIZED); - return hleLogWarning(ME, ERROR_PSMF_INVALID_ID, "bad stream id"); + return hleLogWarning(Log::ME, ERROR_PSMF_INVALID_ID, "bad stream id"); } - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfGetVideoInfo(u32 psmfStruct, u32 videoInfoAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } else if (!psmf->isValidCurrentStreamNumber()) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid stream selected"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid stream selected"); } else if (!Memory::IsValidRange(videoInfoAddr, 8)) { // Would crash. - return hleLogError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); } auto info = psmf->streamMap[psmf->currentStreamNum]; if (info->videoWidth_ == PsmfStream::INVALID) { - return hleLogError(ME, ERROR_PSMF_INVALID_ID, "not a video stream"); + return hleLogError(Log::ME, ERROR_PSMF_INVALID_ID, "not a video stream"); } Memory::Write_U32(info->videoWidth_ == PsmfStream::USE_PSMF ? psmf->videoWidth : info->videoWidth_, videoInfoAddr); Memory::Write_U32(info->videoHeight_ == PsmfStream::USE_PSMF ? psmf->videoHeight : info->videoHeight_, videoInfoAddr + 4); - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfGetAudioInfo(u32 psmfStruct, u32 audioInfoAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } else if (!psmf->isValidCurrentStreamNumber()) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid stream selected"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid stream selected"); } else if (!Memory::IsValidRange(audioInfoAddr, 8)) { // Would crash. - return hleLogError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); } auto info = psmf->streamMap[psmf->currentStreamNum]; if (info->audioChannels_ == PsmfStream::INVALID) { - return hleLogError(ME, ERROR_PSMF_INVALID_ID, "not an audio stream"); + return hleLogError(Log::ME, ERROR_PSMF_INVALID_ID, "not an audio stream"); } Memory::Write_U32(info->audioChannels_ == PsmfStream::USE_PSMF ? psmf->audioChannels : info->audioChannels_, audioInfoAddr); Memory::Write_U32(info->audioFrequency_ == PsmfStream::USE_PSMF ? psmf->audioFrequency : info->audioFrequency_, audioInfoAddr + 4); - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfGetCurrentStreamType(u32 psmfStruct, u32 typeAddr, u32 channelAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } if (psmf->currentStreamNum == (int)ERROR_PSMF_NOT_INITIALIZED) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "no stream set"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "no stream set"); } if (!Memory::IsValidAddress(typeAddr) || !Memory::IsValidAddress(channelAddr)) { - return hleLogError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointers"); + return hleLogError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointers"); } if (psmf->currentStreamType != -1) { Memory::Write_U32(psmf->currentStreamType, typeAddr); Memory::Write_U32(psmf->currentStreamChannel, channelAddr); } - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfGetStreamSize(u32 psmfStruct, u32 sizeAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - ERROR_LOG(ME, "scePsmfGetStreamSize(%08x, %08x): invalid psmf", psmfStruct, sizeAddr); + ERROR_LOG(Log::ME, "scePsmfGetStreamSize(%08x, %08x): invalid psmf", psmfStruct, sizeAddr); return ERROR_PSMF_NOT_FOUND; } - DEBUG_LOG(ME, "scePsmfGetStreamSize(%08x, %08x)", psmfStruct, sizeAddr); + DEBUG_LOG(Log::ME, "scePsmfGetStreamSize(%08x, %08x)", psmfStruct, sizeAddr); if (Memory::IsValidAddress(sizeAddr)) { Memory::Write_U32(psmf->streamSize, sizeAddr); } @@ -933,7 +933,7 @@ static u32 scePsmfGetStreamSize(u32 psmfStruct, u32 sizeAddr) static u32 scePsmfQueryStreamOffset(u32 bufferAddr, u32 offsetAddr) { - WARN_LOG(ME, "scePsmfQueryStreamOffset(%08x, %08x)", bufferAddr, offsetAddr); + WARN_LOG(Log::ME, "scePsmfQueryStreamOffset(%08x, %08x)", bufferAddr, offsetAddr); if (Memory::IsValidAddress(offsetAddr)) { Memory::Write_U32(bswap32(Memory::Read_U32(bufferAddr + PSMF_STREAM_OFFSET_OFFSET)), offsetAddr); } @@ -942,7 +942,7 @@ static u32 scePsmfQueryStreamOffset(u32 bufferAddr, u32 offsetAddr) static u32 scePsmfQueryStreamSize(u32 bufferAddr, u32 sizeAddr) { - WARN_LOG(ME, "scePsmfQueryStreamSize(%08x, %08x)", bufferAddr, sizeAddr); + WARN_LOG(Log::ME, "scePsmfQueryStreamSize(%08x, %08x)", bufferAddr, sizeAddr); if (Memory::IsValidAddress(sizeAddr)) { Memory::Write_U32(bswap32(Memory::Read_U32(bufferAddr + PSMF_STREAM_SIZE_OFFSET)), sizeAddr); } @@ -953,10 +953,10 @@ static u32 scePsmfGetHeaderSize(u32 psmfStruct, u32 sizeAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - ERROR_LOG(ME, "scePsmfGetHeaderSize(%08x, %08x): invalid psmf", psmfStruct, sizeAddr); + ERROR_LOG(Log::ME, "scePsmfGetHeaderSize(%08x, %08x): invalid psmf", psmfStruct, sizeAddr); return ERROR_PSMF_NOT_FOUND; } - DEBUG_LOG(ME, "scePsmfGetHeaderSize(%08x, %08x)", psmfStruct, sizeAddr); + DEBUG_LOG(Log::ME, "scePsmfGetHeaderSize(%08x, %08x)", psmfStruct, sizeAddr); if (Memory::IsValidAddress(sizeAddr)) { Memory::Write_U32(psmf->headerSize, sizeAddr); } @@ -967,10 +967,10 @@ static u32 scePsmfGetPsmfVersion(u32 psmfStruct) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - ERROR_LOG(ME, "scePsmfGetPsmfVersion(%08x): invalid psmf", psmfStruct); + ERROR_LOG(Log::ME, "scePsmfGetPsmfVersion(%08x): invalid psmf", psmfStruct); return ERROR_PSMF_NOT_FOUND; } - DEBUG_LOG(ME, "scePsmfGetPsmfVersion(%08x)", psmfStruct); + DEBUG_LOG(Log::ME, "scePsmfGetPsmfVersion(%08x)", psmfStruct); return psmf->version; } @@ -978,18 +978,18 @@ static u32 scePsmfVerifyPsmf(u32 psmfAddr) { u32 magic = Memory::Read_U32(psmfAddr); if (magic != PSMF_MAGIC) { - ERROR_LOG(ME, "scePsmfVerifyPsmf(%08x): bad magic %08x", psmfAddr, magic); + ERROR_LOG(Log::ME, "scePsmfVerifyPsmf(%08x): bad magic %08x", psmfAddr, magic); return ERROR_PSMF_NOT_FOUND; } int version = Memory::Read_U32(psmfAddr + PSMF_STREAM_VERSION_OFFSET); if (version < 0) { - ERROR_LOG(ME, "scePsmfVerifyPsmf(%08x): bad version %08x", psmfAddr, version); + ERROR_LOG(Log::ME, "scePsmfVerifyPsmf(%08x): bad version %08x", psmfAddr, version); return ERROR_PSMF_NOT_FOUND; } // Kurohyou 2 (at least the demo) uses an uninitialized value that happens to be zero on the PSP. // It appears to be written by scePsmfVerifyPsmf(), so we write some bytes into the stack here. Memory::Memset(currentMIPS->r[MIPS_REG_SP] - 0x20, 0, 0x20, "PsmfStack"); - DEBUG_LOG(ME, "scePsmfVerifyPsmf(%08x)", psmfAddr); + DEBUG_LOG(Log::ME, "scePsmfVerifyPsmf(%08x)", psmfAddr); return 0; } @@ -997,10 +997,10 @@ static u32 scePsmfGetNumberOfEPentries(u32 psmfStruct) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - ERROR_LOG(ME, "scePsmfGetNumberOfEPentries(%08x): invalid psmf", psmfStruct); + ERROR_LOG(Log::ME, "scePsmfGetNumberOfEPentries(%08x): invalid psmf", psmfStruct); return ERROR_PSMF_NOT_FOUND; } - DEBUG_LOG(ME, "scePsmfGetNumberOfEPentries(%08x)", psmfStruct); + DEBUG_LOG(Log::ME, "scePsmfGetNumberOfEPentries(%08x)", psmfStruct); return psmf->EPMapEntriesNum; } @@ -1008,10 +1008,10 @@ static u32 scePsmfGetPresentationStartTime(u32 psmfStruct, u32 startTimeAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - ERROR_LOG(ME, "scePsmfGetPresentationStartTime(%08x, %08x): invalid psmf", psmfStruct, startTimeAddr); + ERROR_LOG(Log::ME, "scePsmfGetPresentationStartTime(%08x, %08x): invalid psmf", psmfStruct, startTimeAddr); return ERROR_PSMF_NOT_FOUND; } - DEBUG_LOG(ME, "scePsmfGetPresentationStartTime(%08x, %08x)", psmfStruct, startTimeAddr); + DEBUG_LOG(Log::ME, "scePsmfGetPresentationStartTime(%08x, %08x)", psmfStruct, startTimeAddr); if (Memory::IsValidAddress(startTimeAddr)) { Memory::Write_U32(psmf->presentationStartTime, startTimeAddr); } @@ -1022,10 +1022,10 @@ static u32 scePsmfGetPresentationEndTime(u32 psmfStruct, u32 endTimeAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - ERROR_LOG(ME, "scePsmfGetPresentationEndTime(%08x, %08x): invalid psmf", psmfStruct, endTimeAddr); + ERROR_LOG(Log::ME, "scePsmfGetPresentationEndTime(%08x, %08x): invalid psmf", psmfStruct, endTimeAddr); return ERROR_PSMF_NOT_FOUND; } - DEBUG_LOG(ME, "scePsmfGetPresentationEndTime(%08x, %08x)", psmfStruct, endTimeAddr); + DEBUG_LOG(Log::ME, "scePsmfGetPresentationEndTime(%08x, %08x)", psmfStruct, endTimeAddr); if (Memory::IsValidAddress(endTimeAddr)) { Memory::Write_U32(psmf->presentationEndTime, endTimeAddr); } @@ -1035,23 +1035,23 @@ static u32 scePsmfGetPresentationEndTime(u32 psmfStruct, u32 endTimeAddr) static u32 scePsmfGetCurrentStreamNumber(u32 psmfStruct) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } if (psmf->currentStreamNum < 0) { - return hleLogError(ME, psmf->currentStreamNum, "invalid stream"); + return hleLogError(Log::ME, psmf->currentStreamNum, "invalid stream"); } - return hleLogSuccessI(ME, psmf->currentStreamNum); + return hleLogSuccessI(Log::ME, psmf->currentStreamNum); } static u32 scePsmfCheckEPMap(u32 psmfStruct) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - ERROR_LOG(ME, "scePsmfCheckEPMap(%08x): invalid psmf", psmfStruct); + ERROR_LOG(Log::ME, "scePsmfCheckEPMap(%08x): invalid psmf", psmfStruct); return ERROR_PSMF_NOT_FOUND; } - DEBUG_LOG(ME, "scePsmfCheckEPMap(%08x)", psmfStruct); + DEBUG_LOG(Log::ME, "scePsmfCheckEPMap(%08x)", psmfStruct); return psmf->EPMap.empty() ? ERROR_PSMF_NOT_FOUND : 0; } @@ -1059,11 +1059,11 @@ static u32 scePsmfGetEPWithId(u32 psmfStruct, int epid, u32 entryAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } if (epid < 0 || epid >= (int)psmf->EPMap.size()) { - return hleLogError(ME, ERROR_PSMF_NOT_FOUND, "invalid id"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_FOUND, "invalid id"); } auto entry = PSPPointer::Create(entryAddr); @@ -1071,23 +1071,23 @@ static u32 scePsmfGetEPWithId(u32 psmfStruct, int epid, u32 entryAddr) *entry = psmf->EPMap[epid]; entry.NotifyWrite("PsmfGetEPWithId"); } - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfGetEPWithTimestamp(u32 psmfStruct, u32 ts, u32 entryAddr) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf"); } if (ts < psmf->presentationStartTime) { - return hleLogError(ME, ERROR_PSMF_NOT_FOUND, "invalid timestamp"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_FOUND, "invalid timestamp"); } int epid = psmf->FindEPWithTimestamp(ts); if (epid < 0 || epid >= (int)psmf->EPMap.size()) { - return hleLogError(ME, ERROR_PSMF_NOT_FOUND, "invalid id"); + return hleLogError(Log::ME, ERROR_PSMF_NOT_FOUND, "invalid id"); } auto entry = PSPPointer::Create(entryAddr); @@ -1095,31 +1095,31 @@ static u32 scePsmfGetEPWithTimestamp(u32 psmfStruct, u32 ts, u32 entryAddr) *entry = psmf->EPMap[epid]; entry.NotifyWrite("PsmfGetEPWithTimestamp"); } - return hleLogSuccessI(ME, 0); + return hleLogSuccessI(Log::ME, 0); } static u32 scePsmfGetEPidWithTimestamp(u32 psmfStruct, u32 ts) { Psmf *psmf = getPsmf(psmfStruct); if (!psmf) { - ERROR_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid psmf", psmfStruct, ts); + ERROR_LOG(Log::ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid psmf", psmfStruct, ts); return ERROR_PSMF_NOT_FOUND; } - DEBUG_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x, %i)", psmfStruct, ts); + DEBUG_LOG(Log::ME, "scePsmfGetEPidWithTimestamp(%08x, %i)", psmfStruct, ts); if (psmf->EPMap.empty()) { - ERROR_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x): EPMap is empty", psmfStruct); + ERROR_LOG(Log::ME, "scePsmfGetEPidWithTimestamp(%08x): EPMap is empty", psmfStruct); return ERROR_PSMF_NOT_FOUND; } if (ts < psmf->presentationStartTime) { - ERROR_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid timestamp", psmfStruct, ts); + ERROR_LOG(Log::ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid timestamp", psmfStruct, ts); return ERROR_PSMF_INVALID_TIMESTAMP; } int epid = psmf->FindEPWithTimestamp(ts); if (epid < 0 || epid >= (int)psmf->EPMap.size()) { - ERROR_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid id", psmfStruct, epid); + ERROR_LOG(Log::ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid id", psmfStruct, epid); return ERROR_PSMF_INVALID_ID; } @@ -1132,24 +1132,24 @@ static int scePsmfPlayerCreate(u32 psmfPlayer, u32 dataPtr) { if (!player.IsValid() || !data.IsValid()) { // Crashes on a PSP. - return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointers"); + return hleReportError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointers"); } if (!data->buffer.IsValid()) { // Also crashes on a PSP. *player = 0; - return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "invalid buffer address %08x", data->buffer.ptr); + return hleReportError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "invalid buffer address %08x", data->buffer.ptr); } if (data->bufferSize < 0x00285800) { *player = 0; - return hleReportError(ME, ERROR_PSMFPLAYER_BUFFER_SIZE, "buffer too small %08x", data->bufferSize); + return hleReportError(Log::ME, ERROR_PSMFPLAYER_BUFFER_SIZE, "buffer too small %08x", data->bufferSize); } if (data->threadPriority < 0x10 || data->threadPriority >= 0x6E) { *player = 0; - return hleReportError(ME, ERROR_PSMFPLAYER_INVALID_PARAM, "bad thread priority %02x", data->threadPriority); + return hleReportError(Log::ME, ERROR_PSMFPLAYER_INVALID_PARAM, "bad thread priority %02x", data->threadPriority); } if (!psmfPlayerMap.empty()) { *player = 0; - return hleReportError(ME, ERROR_MPEG_ALREADY_INIT, "already have an active player"); + return hleReportError(Log::ME, ERROR_MPEG_ALREADY_INIT, "already have an active player"); } PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); @@ -1169,34 +1169,34 @@ static int scePsmfPlayerCreate(u32 psmfPlayer, u32 dataPtr) { int delayUs = 20000; DelayPsmfStateChange(psmfPlayer, PSMF_PLAYER_STATUS_INIT, delayUs); - INFO_LOG(ME, "psmfplayer create, psmfPlayerLibVersion 0x%0x, psmfPlayerLibcrc %x", psmfPlayerLibVersion, psmfPlayerLibcrc); + INFO_LOG(Log::ME, "psmfplayer create, psmfPlayerLibVersion 0x%0x, psmfPlayerLibcrc %x", psmfPlayerLibVersion, psmfPlayerLibcrc); return hleDelayResult(0, "player create", delayUs); } static int scePsmfPlayerStop(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player"); + return hleLogError(Log::ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player"); } if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) { - return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "not yet playing"); + return hleLogError(Log::ME, ERROR_PSMFPLAYER_INVALID_STATUS, "not yet playing"); } psmfplayer->AbortFinish(); int delayUs = 3000; DelayPsmfStateChange(psmfPlayer, PSMF_PLAYER_STATUS_STANDBY, delayUs); - return hleLogSuccessInfoI(ME, hleDelayResult(0, "psmfplayer stop", delayUs)); + return hleLogSuccessInfoI(Log::ME, hleDelayResult(0, "psmfplayer stop", delayUs)); } static int scePsmfPlayerBreak(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player", psmfPlayer); + return hleLogError(Log::ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player", psmfPlayer); } psmfplayer->AbortFinish(); - return hleLogWarning(ME, 0); + return hleLogWarning(Log::ME, 0); } static int _PsmfPlayerFillRingbuffer(PsmfPlayer *psmfplayer) { @@ -1235,17 +1235,17 @@ static int _PsmfPlayerFillRingbuffer(PsmfPlayer *psmfplayer) { static int _PsmfPlayerSetPsmfOffset(u32 psmfPlayer, const char *filename, int offset, bool docallback) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer || psmfplayer->status != PSMF_PLAYER_STATUS_INIT) { - return hleReportError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player or status"); + return hleReportError(Log::ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player or status"); } if (!filename) { - return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_PARAM, "invalid filename"); + return hleLogError(Log::ME, ERROR_PSMFPLAYER_INVALID_PARAM, "invalid filename"); } int delayUs = 1100; psmfplayer->filehandle = pspFileSystem.OpenFile(filename, (FileAccess) FILEACCESS_READ); if (psmfplayer->filehandle < 0) { - return hleLogError(ME, hleDelayResult(SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "psmfplayer set", delayUs), "invalid file data or does not exist"); + return hleLogError(Log::ME, hleDelayResult(SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "psmfplayer set", delayUs), "invalid file data or does not exist"); } if (offset != 0) @@ -1258,14 +1258,14 @@ static int _PsmfPlayerSetPsmfOffset(u32 psmfPlayer, const char *filename, int of const u32 magic = *(u32_le *)buf; if (magic != PSMF_MAGIC) { // TODO: Let's keep trying as we were before. - ERROR_LOG_REPORT(ME, "scePsmfPlayerSetPsmf*: incorrect PSMF magic (%08x), bad data", magic); - //return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "incorrect PSMF magic (%08x), bad data", magic); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSetPsmf*: incorrect PSMF magic (%08x), bad data", magic); + //return hleReportError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "incorrect PSMF magic (%08x), bad data", magic); } // TODO: Merge better with Psmf. u16 numStreams = *(u16_be *)(buf + 0x80); if (numStreams > 128) { - return hleReportError(ME, hleDelayResult(SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "psmfplayer set", delayUs), "too many streams in PSMF video, bogus data"); + return hleReportError(Log::ME, hleDelayResult(SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "psmfplayer set", delayUs), "too many streams in PSMF video, bogus data"); } psmfplayer->totalVideoStreams = 0; @@ -1289,7 +1289,7 @@ static int _PsmfPlayerSetPsmfOffset(u32 psmfPlayer, const char *filename, int of } else if ((streamId & PSMF_AUDIO_STREAM_ID) == PSMF_AUDIO_STREAM_ID) { ++psmfplayer->totalAudioStreams; } else { - WARN_LOG_REPORT(ME, "scePsmfPlayerSetPsmf*: unexpected streamID %x", streamId); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerSetPsmf*: unexpected streamID %x", streamId); } } // TODO: It seems like it's invalid if there's not at least 1 video stream. @@ -1309,7 +1309,7 @@ static int _PsmfPlayerSetPsmfOffset(u32 psmfPlayer, const char *filename, int of psmfplayer->totalDurationTimestamp = psmfplayer->mediaengine->getLastTimeStamp(); DelayPsmfStateChange(psmfPlayer, PSMF_PLAYER_STATUS_STANDBY, delayUs); - return hleLogSuccessInfoI(ME, hleDelayResult(0, "psmfplayer set", delayUs)); + return hleLogSuccessInfoI(Log::ME, hleDelayResult(0, "psmfplayer set", delayUs)); } static int scePsmfPlayerSetPsmf(u32 psmfPlayer, const char *filename) { @@ -1333,9 +1333,9 @@ static int scePsmfPlayerSetPsmfOffsetCB(u32 psmfPlayer, const char *filename, in static int scePsmfPlayerGetAudioOutSize(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player"); + return hleLogError(Log::ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player"); } - return hleLogWarning(ME, audioSamplesBytes); + return hleLogWarning(Log::ME, audioSamplesBytes); } static bool __PsmfPlayerContinueSeek(PsmfPlayer *psmfplayer, int tries = 50) { @@ -1362,45 +1362,45 @@ static int scePsmfPlayerStart(u32 psmfPlayer, u32 psmfPlayerData, int initPts) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid psmf player", psmfPlayer, psmfPlayerData, initPts); + ERROR_LOG(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid psmf player", psmfPlayer, psmfPlayerData, initPts); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status == PSMF_PLAYER_STATUS_INIT) { - ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): psmf not yet set", psmfPlayer, psmfPlayerData, initPts); + ERROR_LOG(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): psmf not yet set", psmfPlayer, psmfPlayerData, initPts); return ERROR_PSMFPLAYER_INVALID_STATUS; } auto playerData = PSPPointer::Create(psmfPlayerData); if (!playerData.IsValid()) { // Crashes on a PSP. - ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): bad data address", psmfPlayer, psmfPlayerData, initPts); + ERROR_LOG(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): bad data address", psmfPlayer, psmfPlayerData, initPts); return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS; } if (playerData->playMode < 0 || playerData->playMode > (int)PSMF_PLAYER_MODE_REWIND) { - ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid mode", psmfPlayer, psmfPlayerData, initPts); + ERROR_LOG(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid mode", psmfPlayer, psmfPlayerData, initPts); return ERROR_PSMFPLAYER_INVALID_PARAM; } if (initPts >= psmfplayer->mediaengine->getLastTimeStamp()) { - ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): pts is outside video", psmfPlayer, psmfPlayerData, initPts); + ERROR_LOG(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): pts is outside video", psmfPlayer, psmfPlayerData, initPts); return ERROR_PSMFPLAYER_INVALID_PARAM; } if (psmfplayer->totalAudioStreams > 0) { if (playerData->audioCodec != 0x0F && playerData->audioCodec != 0x01) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid audio codec %02x", psmfPlayer, psmfPlayerData, initPts, playerData->audioCodec); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid audio codec %02x", psmfPlayer, psmfPlayerData, initPts, playerData->audioCodec); return ERROR_PSMFPLAYER_INVALID_STREAM; } if (playerData->audioStreamNum >= psmfplayer->totalAudioStreams) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to change audio stream to %d", psmfPlayer, psmfPlayerData, initPts, playerData->audioStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to change audio stream to %d", psmfPlayer, psmfPlayerData, initPts, playerData->audioStreamNum); return ERROR_PSMFPLAYER_INVALID_CONFIG; } } if (playerData->videoCodec != 0x0E && playerData->videoCodec != 0x00) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid video codec %02x", psmfPlayer, psmfPlayerData, initPts, playerData->videoCodec); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid video codec %02x", psmfPlayer, psmfPlayerData, initPts, playerData->videoCodec); return ERROR_PSMFPLAYER_INVALID_STREAM; } if (playerData->videoStreamNum < 0 || playerData->videoStreamNum >= psmfplayer->totalVideoStreams) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to change video stream to %d", psmfPlayer, psmfPlayerData, initPts, playerData->videoStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to change video stream to %d", psmfPlayer, psmfPlayerData, initPts, playerData->videoStreamNum); return ERROR_PSMFPLAYER_INVALID_CONFIG; } @@ -1408,10 +1408,10 @@ static int scePsmfPlayerStart(u32 psmfPlayer, u32 psmfPlayerData, int initPts) case PSMF_PLAYER_MODE_FORWARD: case PSMF_PLAYER_MODE_REWIND: if (psmfplayer->playerVersion == PSMF_PLAYER_VERSION_BASIC) { - WARN_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): no EP data for FORWARD/REWIND", psmfPlayer, psmfPlayerData, initPts); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): no EP data for FORWARD/REWIND", psmfPlayer, psmfPlayerData, initPts); return ERROR_PSMFPLAYER_INVALID_PARAM; } - WARN_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unsupported playMode", psmfPlayer, psmfPlayerData, initPts); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): unsupported playMode", psmfPlayer, psmfPlayerData, initPts); break; case PSMF_PLAYER_MODE_PLAY: @@ -1419,12 +1419,12 @@ static int scePsmfPlayerStart(u32 psmfPlayer, u32 psmfPlayerData, int initPts) break; default: - WARN_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unsupported playMode", psmfPlayer, psmfPlayerData, initPts); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): unsupported playMode", psmfPlayer, psmfPlayerData, initPts); break; } if (psmfplayer->playerVersion == PSMF_PLAYER_VERSION_BASIC && initPts != 0) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to seek without EPmap", psmfPlayer, psmfPlayerData, initPts); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to seek without EPmap", psmfPlayer, psmfPlayerData, initPts); return ERROR_PSMFPLAYER_INVALID_PARAM; } @@ -1440,7 +1440,7 @@ static int scePsmfPlayerStart(u32 psmfPlayer, u32 psmfPlayerData, int initPts) psmfplayer->playMode = playerData->playMode; psmfplayer->playSpeed = playerData->playSpeed; - WARN_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d (mode %d, speed %d)", psmfPlayer, psmfPlayerData, initPts, playerData->playMode, playerData->playSpeed); + WARN_LOG(Log::ME, "scePsmfPlayerStart(%08x, %08x, %d (mode %d, speed %d)", psmfPlayer, psmfPlayerData, initPts, playerData->playMode, playerData->playSpeed); // Does not alter current pts, it just catches up when Update()/etc. get there. @@ -1491,11 +1491,11 @@ static int scePsmfPlayerDelete(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerDelete(%08x): invalid psmf player", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerDelete(%08x): invalid psmf player", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } - INFO_LOG(ME, "scePsmfPlayerDelete(%08x)", psmfPlayer); + INFO_LOG(Log::ME, "scePsmfPlayerDelete(%08x)", psmfPlayer); delete psmfplayer; psmfPlayerMap.erase(Memory::Read_U32(psmfPlayer)); Memory::Write_U32(0, psmfPlayer); @@ -1507,20 +1507,20 @@ static int scePsmfPlayerUpdate(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerUpdate(%08x): invalid psmf player", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerUpdate(%08x): invalid psmf player", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG(ME, "scePsmfPlayerUpdate(%08x): not playing yet", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerUpdate(%08x): not playing yet", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } - DEBUG_LOG(ME, "scePsmfPlayerUpdate(%08x)", psmfPlayer); + DEBUG_LOG(Log::ME, "scePsmfPlayerUpdate(%08x)", psmfPlayer); if (psmfplayer->HasReachedEnd()) { if (videoLoopStatus == PSMF_PLAYER_CONFIG_NO_LOOP && psmfplayer->videoStep >= 1) { if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING_FINISHED) { psmfplayer->ScheduleFinish(psmfPlayer); - INFO_LOG(ME, "scePsmfPlayerUpdate(%08x): video end scheduled", psmfPlayer); + INFO_LOG(Log::ME, "scePsmfPlayerUpdate(%08x): video end scheduled", psmfPlayer); } } } @@ -1533,15 +1533,15 @@ static int scePsmfPlayerReleasePsmf(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerReleasePsmf(%08x): invalid psmf player", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerReleasePsmf(%08x): invalid psmf player", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status < PSMF_PLAYER_STATUS_STANDBY) { - ERROR_LOG(ME, "scePsmfPlayerReleasePsmf(%08x): not set yet", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerReleasePsmf(%08x): not set yet", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } - WARN_LOG(ME, "scePsmfPlayerReleasePsmf(%08x)", psmfPlayer); + WARN_LOG(Log::ME, "scePsmfPlayerReleasePsmf(%08x)", psmfPlayer); psmfplayer->status = PSMF_PLAYER_STATUS_INIT; return 0; } @@ -1558,32 +1558,32 @@ static int scePsmfPlayerGetVideoData(u32 psmfPlayer, u32 videoDataAddr) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid psmf player", psmfPlayer, videoDataAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid psmf player", psmfPlayer, videoDataAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): psmf not playing", psmfPlayer, videoDataAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetVideoData(%08x, %08x): psmf not playing", psmfPlayer, videoDataAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } auto videoData = PSPPointer::Create(videoDataAddr); if (!videoData.IsValid()) { - ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid data pointer", psmfPlayer, videoDataAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid data pointer", psmfPlayer, videoDataAddr); // Technically just crashes if videoData is not valid. return SCE_KERNEL_ERROR_INVALID_POINTER; } if (videoData->frameWidth < 0) { - ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): illegal bufw %d", psmfPlayer, videoDataAddr, videoData->frameWidth); + ERROR_LOG(Log::ME, "scePsmfPlayerGetVideoData(%08x, %08x): illegal bufw %d", psmfPlayer, videoDataAddr, videoData->frameWidth); return SCE_KERNEL_ERROR_PRIV_REQUIRED; } if (videoData->frameWidth != 0 && videoData->frameWidth < psmfplayer->mediaengine->VideoWidth()) { - ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): bufw %d smaller than width %d", psmfPlayer, videoDataAddr, videoData->frameWidth, psmfplayer->mediaengine->VideoWidth()); + ERROR_LOG(Log::ME, "scePsmfPlayerGetVideoData(%08x, %08x): bufw %d smaller than width %d", psmfPlayer, videoDataAddr, videoData->frameWidth, psmfplayer->mediaengine->VideoWidth()); return SCE_KERNEL_ERROR_INVALID_VALUE; } hleEatCycles(20000); if (!__PsmfPlayerContinueSeek(psmfplayer)) { - DEBUG_LOG(HLE, "scePsmfPlayerGetVideoData(%08x, %08x): still seeking", psmfPlayer, videoDataAddr); + DEBUG_LOG(Log::HLE, "scePsmfPlayerGetVideoData(%08x, %08x): still seeking", psmfPlayer, videoDataAddr); return ERROR_PSMFPLAYER_NO_MORE_DATA; } @@ -1591,7 +1591,7 @@ static int scePsmfPlayerGetVideoData(u32 psmfPlayer, u32 videoDataAddr) // Normally a minimum of 3 without audio, 5 with. But if you don't delay sufficiently between, hundreds. // It should be okay if we start videos quicker, but some games expect the first couple to fail. if (psmfplayer->warmUp < PSMF_PLAYER_WARMUP_FRAMES) { - DEBUG_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): warming up", psmfPlayer, videoDataAddr); + DEBUG_LOG(Log::ME, "scePsmfPlayerGetVideoData(%08x, %08x): warming up", psmfPlayer, videoDataAddr); ++psmfplayer->warmUp; return ERROR_PSMFPLAYER_NO_MORE_DATA; } @@ -1600,7 +1600,7 @@ static int scePsmfPlayerGetVideoData(u32 psmfPlayer, u32 videoDataAddr) // It's fine to pass an invalid value here if it's still warming up, but after that it's not okay. if (!Memory::IsValidAddress(videoData->displaybuf)) { - ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid buffer pointer %08x", psmfPlayer, videoDataAddr, videoData->displaybuf); + ERROR_LOG(Log::ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid buffer pointer %08x", psmfPlayer, videoDataAddr, videoData->displaybuf); return SCE_KERNEL_ERROR_INVALID_POINTER; } @@ -1616,7 +1616,7 @@ static int scePsmfPlayerGetVideoData(u32 psmfPlayer, u32 videoDataAddr) doVideoStep = false; } else { // This is an approximation, it should allow a certain amount ahead before skipping frames. - while (deltapts <= -(VIDEO_FRAME_DURATION_TS * 5)) { + while (!psmfplayer->mediaengine->IsVideoEnd() && deltapts <= -(VIDEO_FRAME_DURATION_TS * 5)) { psmfplayer->mediaengine->stepVideo(videoPixelMode, true); deltapts = psmfplayer->mediaengine->getVideoTimeStamp() - psmfplayer->mediaengine->getAudioTimeStamp(); } @@ -1643,7 +1643,7 @@ static int scePsmfPlayerGetVideoData(u32 psmfPlayer, u32 videoDataAddr) _PsmfPlayerFillRingbuffer(psmfplayer); - DEBUG_LOG(ME, "%08x=scePsmfPlayerGetVideoData(%08x, %08x)", 0, psmfPlayer, videoDataAddr); + DEBUG_LOG(Log::ME, "%08x=scePsmfPlayerGetVideoData(%08x, %08x)", 0, psmfPlayer, videoDataAddr); return hleDelayResult(0, "psmfPlayer video decode", 3000); } @@ -1651,26 +1651,26 @@ static int scePsmfPlayerGetAudioData(u32 psmfPlayer, u32 audioDataAddr) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerGetAudioData(%08x, %08x): invalid psmf player", psmfPlayer, audioDataAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetAudioData(%08x, %08x): invalid psmf player", psmfPlayer, audioDataAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG(ME, "scePsmfPlayerGetAudioData(%08x, %08x): not yet playing", psmfPlayer, audioDataAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetAudioData(%08x, %08x): not yet playing", psmfPlayer, audioDataAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (!Memory::IsValidAddress(audioDataAddr)) { - ERROR_LOG(ME, "scePsmfPlayerGetAudioData(%08x, %08x): invalid audio pointer", psmfPlayer, audioDataAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetAudioData(%08x, %08x): invalid audio pointer", psmfPlayer, audioDataAddr); return SCE_KERNEL_ERROR_INVALID_POINTER; } // Don't return audio frames before we would return video frames. if (psmfplayer->warmUp < PSMF_PLAYER_WARMUP_FRAMES) { - DEBUG_LOG(ME, "scePsmfPlayerGetAudioData(%08x, %08x): warming up", psmfPlayer, audioDataAddr); + DEBUG_LOG(Log::ME, "scePsmfPlayerGetAudioData(%08x, %08x): warming up", psmfPlayer, audioDataAddr); return ERROR_PSMFPLAYER_NO_MORE_DATA; } if (psmfplayer->playMode == PSMF_PLAYER_MODE_PAUSE) { - INFO_LOG(HLE, "scePsmfPlayerGetAudioData(%08x): paused mode", psmfPlayer); + INFO_LOG(Log::HLE, "scePsmfPlayerGetAudioData(%08x): paused mode", psmfPlayer); return ERROR_PSMFPLAYER_NO_MORE_DATA; } @@ -1684,7 +1684,7 @@ static int scePsmfPlayerGetAudioData(u32 psmfPlayer, u32 audioDataAddr) } } - DEBUG_LOG(ME, "%08x=scePsmfPlayerGetAudioData(%08x, %08x)", ret, psmfPlayer, audioDataAddr); + DEBUG_LOG(Log::ME, "%08x=scePsmfPlayerGetAudioData(%08x, %08x)", ret, psmfPlayer, audioDataAddr); if (ret != 0) { hleEatCycles(10000); } else { @@ -1700,15 +1700,15 @@ static int scePsmfPlayerGetCurrentStatus(u32 psmfPlayer) if (!psmfplayer) { // Mana Khemia and other games call this even when not necessary. // It's annoying so the logging is verbose'd out. - VERBOSE_LOG(ME, "scePsmfPlayerGetCurrentStatus(%08x): invalid psmf player", psmfPlayer); + VERBOSE_LOG(Log::ME, "scePsmfPlayerGetCurrentStatus(%08x): invalid psmf player", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status == PSMF_PLAYER_STATUS_NONE) { - ERROR_LOG(ME, "scePsmfPlayerGetCurrentStatus(%08x): not initialized", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerGetCurrentStatus(%08x): not initialized", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } - DEBUG_LOG(ME, "%d=scePsmfPlayerGetCurrentStatus(%08x)", psmfplayer->status, psmfPlayer); + DEBUG_LOG(Log::ME, "%d=scePsmfPlayerGetCurrentStatus(%08x)", psmfplayer->status, psmfPlayer); return psmfplayer->status; } @@ -1716,19 +1716,19 @@ static u32 scePsmfPlayerGetCurrentPts(u32 psmfPlayer, u32 currentPtsAddr) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): invalid psmf player", psmfPlayer, currentPtsAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): invalid psmf player", psmfPlayer, currentPtsAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status < PSMF_PLAYER_STATUS_STANDBY) { - ERROR_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): not initialized", psmfPlayer, currentPtsAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): not initialized", psmfPlayer, currentPtsAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->psmfPlayerAvcAu.pts < 0) { - VERBOSE_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): no frame yet", psmfPlayer, currentPtsAddr); + VERBOSE_LOG(Log::ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): no frame yet", psmfPlayer, currentPtsAddr); return ERROR_PSMFPLAYER_NO_MORE_DATA; } - DEBUG_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x)", psmfPlayer, currentPtsAddr); + DEBUG_LOG(Log::ME, "scePsmfPlayerGetCurrentPts(%08x, %08x)", psmfPlayer, currentPtsAddr); if (Memory::IsValidAddress(currentPtsAddr)) { Memory::Write_U32(psmfplayer->psmfPlayerAvcAu.pts, currentPtsAddr); } @@ -1738,22 +1738,22 @@ static u32 scePsmfPlayerGetCurrentPts(u32 psmfPlayer, u32 currentPtsAddr) static u32 scePsmfPlayerGetPsmfInfo(u32 psmfPlayer, u32 psmfInfoAddr, u32 widthAddr, u32 heightAddr) { auto info = PSPPointer::Create(psmfInfoAddr); if (!Memory::IsValidAddress(psmfPlayer) || !info.IsValid()) { - ERROR_LOG(ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x): invalid addresses", psmfPlayer, psmfInfoAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x): invalid addresses", psmfPlayer, psmfInfoAddr); // PSP would crash. return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS; } PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x): invalid psmf player", psmfPlayer, psmfInfoAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x): invalid psmf player", psmfPlayer, psmfInfoAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status < PSMF_PLAYER_STATUS_STANDBY) { - ERROR_LOG(ME, "scePsmfPlayerGetPsmfInfo(%08x): psmf not set yet", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerGetPsmfInfo(%08x): psmf not set yet", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } - DEBUG_LOG(ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x)", psmfPlayer, psmfInfoAddr); + DEBUG_LOG(Log::ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x)", psmfPlayer, psmfInfoAddr); // The first frame is at 0, so subtract one frame's duration to get the last frame's timestamp. info->lastFrameTS = psmfplayer->totalDurationTimestamp - VIDEO_FRAME_DURATION_TS; info->numVideoStreams = psmfplayer->totalVideoStreams; @@ -1781,11 +1781,11 @@ static u32 scePsmfPlayerGetCurrentPlayMode(u32 psmfPlayer, u32 playModeAddr, u32 { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerGetCurrentPlayMode(%08x, %08x, %08x): invalid psmf player", psmfPlayer, playModeAddr, playSpeedAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetCurrentPlayMode(%08x, %08x, %08x): invalid psmf player", psmfPlayer, playModeAddr, playSpeedAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } - DEBUG_LOG(ME, "scePsmfPlayerGetCurrentPlayMode(%08x, %08x, %08x)", psmfPlayer, playModeAddr, playSpeedAddr); + DEBUG_LOG(Log::ME, "scePsmfPlayerGetCurrentPlayMode(%08x, %08x, %08x)", psmfPlayer, playModeAddr, playSpeedAddr); if (Memory::IsValidAddress(playModeAddr)) { Memory::Write_U32(psmfplayer->playMode, playModeAddr); } @@ -1799,15 +1799,15 @@ static u32 scePsmfPlayerGetCurrentVideoStream(u32 psmfPlayer, u32 videoCodecAddr { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerGetCurrentVideoStream(%08x, %08x, %08x): invalid psmf player", psmfPlayer, videoCodecAddr, videoStreamNumAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetCurrentVideoStream(%08x, %08x, %08x): invalid psmf player", psmfPlayer, videoCodecAddr, videoStreamNumAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status == PSMF_PLAYER_STATUS_INIT) { - ERROR_LOG(ME, "scePsmfPlayerGetCurrentVideoStream(%08x): psmf not yet set", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerGetCurrentVideoStream(%08x): psmf not yet set", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } - DEBUG_LOG(ME, "scePsmfPlayerGetCurrentVideoStream(%08x, %08x, %08x)", psmfPlayer, videoCodecAddr, videoStreamNumAddr); + DEBUG_LOG(Log::ME, "scePsmfPlayerGetCurrentVideoStream(%08x, %08x, %08x)", psmfPlayer, videoCodecAddr, videoStreamNumAddr); if (Memory::IsValidAddress(videoCodecAddr)) { Memory::Write_U32(psmfplayer->videoCodec == 0x0E ? 0 : psmfplayer->videoCodec, videoCodecAddr); } @@ -1821,15 +1821,15 @@ static u32 scePsmfPlayerGetCurrentAudioStream(u32 psmfPlayer, u32 audioCodecAddr { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerGetCurrentAudioStream(%08x, %08x, %08x): invalid psmf player", psmfPlayer, audioCodecAddr, audioStreamNumAddr); + ERROR_LOG(Log::ME, "scePsmfPlayerGetCurrentAudioStream(%08x, %08x, %08x): invalid psmf player", psmfPlayer, audioCodecAddr, audioStreamNumAddr); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status == PSMF_PLAYER_STATUS_INIT) { - ERROR_LOG(ME, "scePsmfPlayerGetCurrentVideoStream(%08x): psmf not yet set", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerGetCurrentVideoStream(%08x): psmf not yet set", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } - DEBUG_LOG(ME, "scePsmfPlayerGetCurrentAudioStream(%08x, %08x, %08x)", psmfPlayer, audioCodecAddr, audioStreamNumAddr); + DEBUG_LOG(Log::ME, "scePsmfPlayerGetCurrentAudioStream(%08x, %08x, %08x)", psmfPlayer, audioCodecAddr, audioStreamNumAddr); if (Memory::IsValidAddress(audioCodecAddr)) { Memory::Write_U32(psmfplayer->audioCodec == 0x0F ? 1 : psmfplayer->audioCodec, audioCodecAddr); } @@ -1843,19 +1843,19 @@ static int scePsmfPlayerSetTempBuf(u32 psmfPlayer, u32 tempBufAddr, u32 tempBufS { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): invalid psmf player", psmfPlayer, tempBufAddr, tempBufSize); + ERROR_LOG(Log::ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): invalid psmf player", psmfPlayer, tempBufAddr, tempBufSize); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status != PSMF_PLAYER_STATUS_INIT) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): invalid status %x", psmfPlayer, tempBufAddr, tempBufSize, psmfplayer->status); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): invalid status %x", psmfPlayer, tempBufAddr, tempBufSize, psmfplayer->status); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (tempBufSize < 0x00010000) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): buffer too small", psmfPlayer, tempBufAddr, tempBufSize); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): buffer too small", psmfPlayer, tempBufAddr, tempBufSize); return ERROR_PSMFPLAYER_INVALID_PARAM; } - INFO_LOG(ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x)", psmfPlayer, tempBufAddr, tempBufSize); + INFO_LOG(Log::ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x)", psmfPlayer, tempBufAddr, tempBufSize); // fake it right now, use tempbuf from memory directly //psmfplayer->tempbuf = tempBufAddr; //psmfplayer->tempbufSize = tempBufSize; @@ -1867,15 +1867,15 @@ static u32 scePsmfPlayerChangePlayMode(u32 psmfPlayer, int playMode, int playSpe { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): invalid psmf player", psmfPlayer, playMode, playSpeed); + ERROR_LOG(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): invalid psmf player", psmfPlayer, playMode, playSpeed); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): not playing yet", psmfPlayer, playMode, playSpeed); + ERROR_LOG(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): not playing yet", psmfPlayer, playMode, playSpeed); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (playMode < 0 || playMode > (int)PSMF_PLAYER_MODE_REWIND) { - ERROR_LOG(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): invalid mode", psmfPlayer, playMode, playSpeed); + ERROR_LOG(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): invalid mode", psmfPlayer, playMode, playSpeed); return ERROR_PSMFPLAYER_INVALID_CONFIG; } @@ -1883,27 +1883,27 @@ static u32 scePsmfPlayerChangePlayMode(u32 psmfPlayer, int playMode, int playSpe case PSMF_PLAYER_MODE_FORWARD: case PSMF_PLAYER_MODE_REWIND: if (psmfplayer->playerVersion == PSMF_PLAYER_VERSION_BASIC) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): no EP data for FORWARD/REWIND", psmfPlayer, playMode, playSpeed); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): no EP data for FORWARD/REWIND", psmfPlayer, playMode, playSpeed); return ERROR_PSMFPLAYER_INVALID_STREAM; } psmfplayer->playSpeed = playSpeed; - WARN_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): unsupported playMode", psmfPlayer, playMode, playSpeed); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): unsupported playMode", psmfPlayer, playMode, playSpeed); break; case PSMF_PLAYER_MODE_PLAY: case PSMF_PLAYER_MODE_PAUSE: if (psmfplayer->playSpeed != playSpeed) { - WARN_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): play speed not changed", psmfPlayer, playMode, playSpeed); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): play speed not changed", psmfPlayer, playMode, playSpeed); } else { - DEBUG_LOG(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i)", psmfPlayer, playMode, playSpeed); + DEBUG_LOG(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i)", psmfPlayer, playMode, playSpeed); } break; default: if (psmfplayer->playSpeed != playSpeed) { - WARN_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): play speed not changed", psmfPlayer, playMode, playSpeed); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): play speed not changed", psmfPlayer, playMode, playSpeed); } - WARN_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): unsupported playMode", psmfPlayer, playMode, playSpeed); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): unsupported playMode", psmfPlayer, playMode, playSpeed); break; } @@ -1915,11 +1915,11 @@ static u32 scePsmfPlayerSelectAudio(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerSelectAudio(%08x): invalid psmf player", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerSelectAudio(%08x): invalid psmf player", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG(ME, "scePsmfPlayerSelectAudio(%08x): not playing", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerSelectAudio(%08x): not playing", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } @@ -1928,11 +1928,11 @@ static u32 scePsmfPlayerSelectAudio(u32 psmfPlayer) next = 0; if (next == psmfplayer->audioStreamNum || !psmfplayer->mediaengine->setAudioStream(next)) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectAudio(%08x): no stream to switch to", psmfPlayer); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectAudio(%08x): no stream to switch to", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STREAM; } - WARN_LOG_REPORT(ME, "scePsmfPlayerSelectAudio(%08x)", psmfPlayer); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerSelectAudio(%08x)", psmfPlayer); psmfplayer->audioStreamNum = next; return 0; } @@ -1941,11 +1941,11 @@ static u32 scePsmfPlayerSelectVideo(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerSelectVideo(%08x): invalid psmf player", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerSelectVideo(%08x): invalid psmf player", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG(ME, "scePsmfPlayerSelectVideo(%08x): not playing", psmfPlayer); + ERROR_LOG(Log::ME, "scePsmfPlayerSelectVideo(%08x): not playing", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } @@ -1954,11 +1954,11 @@ static u32 scePsmfPlayerSelectVideo(u32 psmfPlayer) next = 0; if (next == psmfplayer->videoStreamNum || !psmfplayer->mediaengine->setVideoStream(next)) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectVideo(%08x): no stream to switch to", psmfPlayer); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectVideo(%08x): no stream to switch to", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STREAM; } - WARN_LOG_REPORT(ME, "scePsmfPlayerSelectVideo(%08x)", psmfPlayer); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerSelectVideo(%08x)", psmfPlayer); psmfplayer->videoStreamNum = next; return 0; } @@ -1967,31 +1967,31 @@ static u32 scePsmfPlayerSelectSpecificVideo(u32 psmfPlayer, int videoCodec, int { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): invalid psmf player", psmfPlayer, videoCodec, videoStreamNum); + ERROR_LOG(Log::ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): invalid psmf player", psmfPlayer, videoCodec, videoStreamNum); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): not playing", psmfPlayer, videoCodec, videoStreamNum); + ERROR_LOG(Log::ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): not playing", psmfPlayer, videoCodec, videoStreamNum); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->totalVideoStreams < 2) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): unable to change stream", psmfPlayer, videoCodec, videoStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): unable to change stream", psmfPlayer, videoCodec, videoStreamNum); return ERROR_PSMFPLAYER_INVALID_STREAM; } if (videoStreamNum < 0 || videoStreamNum >= psmfplayer->totalVideoStreams) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): bad stream num param", psmfPlayer, videoCodec, videoStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): bad stream num param", psmfPlayer, videoCodec, videoStreamNum); return ERROR_PSMFPLAYER_INVALID_CONFIG; } if (videoCodec != 0x0E && videoCodec != 0x00) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): invalid codec", psmfPlayer, videoCodec, videoStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): invalid codec", psmfPlayer, videoCodec, videoStreamNum); return ERROR_PSMFPLAYER_INVALID_STREAM; } if (psmfplayer->totalVideoStreams < 2 || !psmfplayer->mediaengine->setVideoStream(videoStreamNum)) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): unable to change stream", psmfPlayer, videoCodec, videoStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): unable to change stream", psmfPlayer, videoCodec, videoStreamNum); return ERROR_PSMFPLAYER_INVALID_STREAM; } - WARN_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i)", psmfPlayer, videoCodec, videoStreamNum); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i)", psmfPlayer, videoCodec, videoStreamNum); if (psmfplayer->videoStreamNum != videoStreamNum) { hleDelayResult(0, "psmf select video", 100); } @@ -2005,31 +2005,31 @@ static u32 scePsmfPlayerSelectSpecificAudio(u32 psmfPlayer, int audioCodec, int { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): invalid psmf player", psmfPlayer, audioCodec, audioStreamNum); + ERROR_LOG(Log::ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): invalid psmf player", psmfPlayer, audioCodec, audioStreamNum); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): not playing", psmfPlayer, audioCodec, audioStreamNum); + ERROR_LOG(Log::ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): not playing", psmfPlayer, audioCodec, audioStreamNum); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->totalAudioStreams < 2) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): unable to change stream", psmfPlayer, audioCodec, audioStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): unable to change stream", psmfPlayer, audioCodec, audioStreamNum); return ERROR_PSMFPLAYER_INVALID_STREAM; } if (audioStreamNum < 0 || audioStreamNum >= psmfplayer->totalAudioStreams) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): bad stream num param", psmfPlayer, audioCodec, audioStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): bad stream num param", psmfPlayer, audioCodec, audioStreamNum); return ERROR_PSMFPLAYER_INVALID_CONFIG; } if (audioCodec != 0x0F && audioCodec != 0x01) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): invalid codec", psmfPlayer, audioCodec, audioStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): invalid codec", psmfPlayer, audioCodec, audioStreamNum); return ERROR_PSMFPLAYER_INVALID_STREAM; } if (psmfplayer->totalAudioStreams < 2 || !psmfplayer->mediaengine->setAudioStream(audioStreamNum)) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): unable to change stream", psmfPlayer, audioCodec, audioStreamNum); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): unable to change stream", psmfPlayer, audioCodec, audioStreamNum); return ERROR_PSMFPLAYER_INVALID_STREAM; } - WARN_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i)", psmfPlayer, audioCodec, audioStreamNum); + WARN_LOG_REPORT(Log::ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i)", psmfPlayer, audioCodec, audioStreamNum); if (psmfplayer->audioStreamNum != audioStreamNum) { hleDelayResult(0, "psmf select audio", 100); } @@ -2042,7 +2042,7 @@ static u32 scePsmfPlayerConfigPlayer(u32 psmfPlayer, int configMode, int configA { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG(ME, "scePsmfPlayerConfigPlayer(%08x, %i, %i): invalid psmf player", psmfPlayer, configMode, configAttr); + ERROR_LOG(Log::ME, "scePsmfPlayerConfigPlayer(%08x, %i, %i): invalid psmf player", psmfPlayer, configMode, configAttr); return ERROR_PSMFPLAYER_INVALID_STATUS; } // This one works in any status as long as it's created. @@ -2050,18 +2050,18 @@ static u32 scePsmfPlayerConfigPlayer(u32 psmfPlayer, int configMode, int configA switch (configMode) { case PSMF_PLAYER_CONFIG_MODE_LOOP: if (configAttr != 0 && configAttr != 1) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerConfigPlayer(%08x, loop, %i): invalid value", psmfPlayer, configAttr); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerConfigPlayer(%08x, loop, %i): invalid value", psmfPlayer, configAttr); return ERROR_PSMFPLAYER_INVALID_PARAM; } - INFO_LOG(ME, "scePsmfPlayerConfigPlayer(%08x, loop, %i)", psmfPlayer, configAttr); + INFO_LOG(Log::ME, "scePsmfPlayerConfigPlayer(%08x, loop, %i)", psmfPlayer, configAttr); videoLoopStatus = configAttr; break; case PSMF_PLAYER_CONFIG_MODE_PIXEL_TYPE: if (configAttr < -1 || configAttr > 3) { - ERROR_LOG_REPORT(ME, "scePsmfPlayerConfigPlayer(%08x, pixelType, %i): invalid value", psmfPlayer, configAttr); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerConfigPlayer(%08x, pixelType, %i): invalid value", psmfPlayer, configAttr); return ERROR_PSMFPLAYER_INVALID_PARAM; } - INFO_LOG(ME, "scePsmfPlayerConfigPlayer(%08x, pixelType, %i)", psmfPlayer, configAttr); + INFO_LOG(Log::ME, "scePsmfPlayerConfigPlayer(%08x, pixelType, %i)", psmfPlayer, configAttr); // Does -1 mean default or something? if (configAttr != -1) { videoPixelMode = configAttr; @@ -2071,7 +2071,7 @@ static u32 scePsmfPlayerConfigPlayer(u32 psmfPlayer, int configMode, int configA } break; default: - ERROR_LOG_REPORT(ME, "scePsmfPlayerConfigPlayer(%08x, %i, %i): unknown parameter", psmfPlayer, configMode, configAttr); + ERROR_LOG_REPORT(Log::ME, "scePsmfPlayerConfigPlayer(%08x, %i, %i): unknown parameter", psmfPlayer, configMode, configAttr); return ERROR_PSMFPLAYER_INVALID_CONFIG; } @@ -2081,15 +2081,15 @@ static u32 scePsmfPlayerConfigPlayer(u32 psmfPlayer, int configMode, int configA static int __PsmfPlayerFinish(u32 psmfPlayer) { PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer); if (!psmfplayer) { - ERROR_LOG_REPORT(ME, "__PsmfPlayerFinish(%08x): invalid psmf player", psmfPlayer); + ERROR_LOG_REPORT(Log::ME, "__PsmfPlayerFinish(%08x): invalid psmf player", psmfPlayer); return ERROR_PSMFPLAYER_INVALID_STATUS; } if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) { - ERROR_LOG_REPORT(ME, "__PsmfPlayerFinish(%08x): unexpected status %d", psmfPlayer, psmfplayer->status); + ERROR_LOG_REPORT(Log::ME, "__PsmfPlayerFinish(%08x): unexpected status %d", psmfPlayer, psmfplayer->status); return ERROR_PSMFPLAYER_INVALID_STATUS; } - INFO_LOG(ME, "__PsmfPlayerFinish(%08x): video end reached", psmfPlayer); + INFO_LOG(Log::ME, "__PsmfPlayerFinish(%08x): video end reached", psmfPlayer); psmfplayer->status = PSMF_PLAYER_STATUS_PLAYING_FINISHED; return 0; } diff --git a/Core/HLE/scePspNpDrm_user.cpp b/Core/HLE/scePspNpDrm_user.cpp index f35f6b5239..b81d92a601 100644 --- a/Core/HLE/scePspNpDrm_user.cpp +++ b/Core/HLE/scePspNpDrm_user.cpp @@ -6,25 +6,25 @@ static int sceNpDrmSetLicenseeKey(u32 npDrmKeyAddr) { - INFO_LOG(HLE, "call sceNpDrmSetLicenseeKey(%08x)", npDrmKeyAddr); + INFO_LOG(Log::HLE, "call sceNpDrmSetLicenseeKey(%08x)", npDrmKeyAddr); return 0; } static int sceNpDrmClearLicenseeKey() { - INFO_LOG(HLE, "call sceNpDrmClearLicenseeKey()"); + INFO_LOG(Log::HLE, "call sceNpDrmClearLicenseeKey()"); return 0; } static int sceNpDrmRenameCheck(const char *filename) { - INFO_LOG(HLE, "call sceNpDrmRenameCheck(%s)", filename); + INFO_LOG(Log::HLE, "call sceNpDrmRenameCheck(%s)", filename); return 0; } static int sceNpDrmEdataSetupKey(u32 edataFd) { - INFO_LOG(HLE, "call sceNpDrmEdataSetupKey %x", edataFd); + INFO_LOG(Log::HLE, "call sceNpDrmEdataSetupKey %x", edataFd); int usec = 0; // set PGD offset int retval = __IoIoctl(edataFd, 0x04100002, 0x90, 0, 0, 0, usec); @@ -39,13 +39,13 @@ static int sceNpDrmEdataSetupKey(u32 edataFd) static int sceNpDrmEdataGetDataSize(u32 edataFd) { - INFO_LOG(HLE, "call sceNpDrmEdataGetDataSize %x", edataFd); + INFO_LOG(Log::HLE, "call sceNpDrmEdataGetDataSize %x", edataFd); return sceIoIoctl(edataFd, 0x04100010, 0, 0, 0, 0); } static int sceNpDrmOpen() { - ERROR_LOG(HLE, "UNIMPL sceNpDrmOpen"); + ERROR_LOG(Log::HLE, "UNIMPL sceNpDrmOpen"); return 0; } diff --git a/Core/HLE/sceRtc.cpp b/Core/HLE/sceRtc.cpp index 7ceca39ce5..ff0dd67620 100644 --- a/Core/HLE/sceRtc.cpp +++ b/Core/HLE/sceRtc.cpp @@ -279,13 +279,13 @@ static bool __RtcValidatePspTime(const ScePspDateTime &t) static u32 sceRtcGetTickResolution() { - DEBUG_LOG(SCERTC, "sceRtcGetTickResolution()"); + DEBUG_LOG(Log::sceRtc, "sceRtcGetTickResolution()"); return 1000000; } static u32 sceRtcGetCurrentTick(u32 tickPtr) { - VERBOSE_LOG(SCERTC, "sceRtcGetCurrentTick(%08x)", tickPtr); + VERBOSE_LOG(Log::sceRtc, "sceRtcGetCurrentTick(%08x)", tickPtr); u64 curTick = __RtcGetCurrentTick(); if (Memory::IsValidAddress(tickPtr)) @@ -297,7 +297,7 @@ static u32 sceRtcGetCurrentTick(u32 tickPtr) static u64 sceRtcGetAccumulativeTime() { - DEBUG_LOG(SCERTC, "sceRtcGetAccumulativeTime()"); + DEBUG_LOG(Log::sceRtc, "sceRtcGetAccumulativeTime()"); hleEatCycles(300); hleReSchedule("rtc accumulative time"); return __RtcGetCurrentTick(); @@ -312,7 +312,7 @@ static u32 sceRtcGetCurrentClock(u32 pspTimePtr, int tz) { time_t sec = (time_t)tv.tv_sec; tm *utc = gmtime(&sec); if (!utc) { - return hleLogError(SCERTC, 0, "Date is too high/low to handle, pretending to work"); + return hleLogError(Log::sceRtc, 0, "Date is too high/low to handle, pretending to work"); } utc->tm_isdst = -1; @@ -326,7 +326,7 @@ static u32 sceRtcGetCurrentClock(u32 pspTimePtr, int tz) { hleEatCycles(1900); hleReSchedule("rtc current clock"); - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static u32 sceRtcGetCurrentClockLocalTime(u32 pspTimePtr) { @@ -338,7 +338,7 @@ static u32 sceRtcGetCurrentClockLocalTime(u32 pspTimePtr) { time_t sec = (time_t)tv.tv_sec; const tm *local = localtime(&sec); if (!local) { - return hleLogError(SCERTC, 0, "Date is too high/low to handle, pretending to work"); + return hleLogError(Log::sceRtc, 0, "Date is too high/low to handle, pretending to work"); } if (pt.IsValid()) { @@ -348,7 +348,7 @@ static u32 sceRtcGetCurrentClockLocalTime(u32 pspTimePtr) { hleEatCycles(2000); hleReSchedule("rtc current clock local"); - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static u32 sceRtcSetTick(u32 pspTimePtr, u32 tickPtr) { @@ -356,10 +356,10 @@ static u32 sceRtcSetTick(u32 pspTimePtr, u32 tickPtr) { auto tick = PSPPointer::Create(tickPtr); if (!pt.IsValid() || !tick.IsValid()) - return hleLogError(SCERTC, 0, "bad address"); + return hleLogError(Log::sceRtc, 0, "bad address"); __RtcTicksToPspTime(*pt, *tick); - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static u32 sceRtcGetTick(u32 pspTimePtr, u32 tickPtr) { @@ -367,17 +367,17 @@ static u32 sceRtcGetTick(u32 pspTimePtr, u32 tickPtr) { auto tick = PSPPointer::Create(tickPtr); if (!pt.IsValid() || !tick.IsValid()) - return hleLogError(SCERTC, 0, "bad address"); + return hleLogError(Log::sceRtc, 0, "bad address"); if (!__RtcValidatePspTime(*pt)) - return hleLogWarning(SCERTC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid time"); + return hleLogWarning(Log::sceRtc, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid time"); *tick = __RtcPspTimeToTicks(*pt); - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static u32 sceRtcGetDayOfWeek(u32 year, u32 month, u32 day) { - DEBUG_LOG(SCERTC, "sceRtcGetDayOfWeek(%d, %d, %d)", year, month, day); + DEBUG_LOG(Log::sceRtc, "sceRtcGetDayOfWeek(%d, %d, %d)", year, month, day); if(month == 0) // Mark month 0 as august, don't know why, but works { @@ -426,7 +426,7 @@ static int __RtcDaysInMonth(u32 year, u32 month) static u32 sceRtcGetDaysInMonth(u32 year, u32 month) { - DEBUG_LOG(SCERTC, "sceRtcGetDaysInMonth(%d, %d)", year, month); + DEBUG_LOG(Log::sceRtc, "sceRtcGetDaysInMonth(%d, %d)", year, month); if (year == 0 || month == 0 || month > 12) return SCE_KERNEL_ERROR_INVALID_ARGUMENT; @@ -436,13 +436,13 @@ static u32 sceRtcGetDaysInMonth(u32 year, u32 month) static u32 sceRtcIsLeapYear(u32 year) { - DEBUG_LOG(SCERTC, "sceRtcIsLeapYear(%d)", year); + DEBUG_LOG(Log::sceRtc, "sceRtcIsLeapYear(%d)", year); return __RtcIsLeapYear(year) ? 1 : 0; } static int sceRtcConvertLocalTimeToUTC(u32 tickLocalPtr,u32 tickUTCPtr) { - DEBUG_LOG(SCERTC, "sceRtcConvertLocalTimeToUTC(%d, %d)", tickLocalPtr, tickUTCPtr); + DEBUG_LOG(Log::sceRtc, "sceRtcConvertLocalTimeToUTC(%d, %d)", tickLocalPtr, tickUTCPtr); if (Memory::IsValidAddress(tickLocalPtr) && Memory::IsValidAddress(tickUTCPtr)) { u64 srcTick = Memory::Read_U64(tickLocalPtr); @@ -467,7 +467,7 @@ static int sceRtcConvertLocalTimeToUTC(u32 tickLocalPtr,u32 tickUTCPtr) static int sceRtcConvertUtcToLocalTime(u32 tickUTCPtr,u32 tickLocalPtr) { - DEBUG_LOG(SCERTC, "sceRtcConvertLocalTimeToUTC(%d, %d)", tickLocalPtr, tickUTCPtr); + DEBUG_LOG(Log::sceRtc, "sceRtcConvertLocalTimeToUTC(%d, %d)", tickLocalPtr, tickUTCPtr); if (Memory::IsValidAddress(tickLocalPtr) && Memory::IsValidAddress(tickUTCPtr)) { u64 srcTick = Memory::Read_U64(tickUTCPtr); @@ -494,7 +494,7 @@ static int sceRtcCheckValid(u32 datePtr) { auto pt = PSPPointer::Create(datePtr); if (!pt.IsValid() ) - return hleLogError(SCERTC, -1, "bad address"); + return hleLogError(Log::sceRtc, -1, "bad address"); int result = 0; if (pt->year < 1 || pt->year > 9999) @@ -513,51 +513,51 @@ static int sceRtcCheckValid(u32 datePtr) { result = PSP_TIME_INVALID_SECONDS; else if (pt->microsecond >= 1000000UL) result = PSP_TIME_INVALID_MICROSECONDS; - return hleLogSuccessI(SCERTC, result); + return hleLogSuccessI(Log::sceRtc, result); } static int sceRtcSetTime_t(u32 datePtr, u32 time) { auto pt = PSPPointer::Create(datePtr); if (!pt.IsValid()) - return hleLogError(SCERTC, 1, "bad address"); + return hleLogError(Log::sceRtc, 1, "bad address"); __RtcTicksToPspTime(*pt, time * 1000000ULL + rtcMagicOffset); - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static int sceRtcSetTime64_t(u32 datePtr, u64 time) { auto pt = PSPPointer::Create(datePtr); if (!pt.IsValid()) - return hleLogError(SCERTC, 1, "bad address"); + return hleLogError(Log::sceRtc, 1, "bad address"); __RtcTicksToPspTime(*pt, time * 1000000ULL + rtcMagicOffset); - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static int sceRtcGetTime_t(u32 datePtr, u32 timePtr) { auto pt = PSPPointer::Create(datePtr); auto timep = PSPPointer::Create(timePtr); if (!pt.IsValid() || !timep.IsValid()) - return hleLogError(SCERTC, 1, "bad address"); + return hleLogError(Log::sceRtc, 1, "bad address"); *timep = (u32)((__RtcPspTimeToTicks(*pt) - rtcMagicOffset) / 1000000ULL); - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static int sceRtcGetTime64_t(u32 datePtr, u32 timePtr) { auto pt = PSPPointer::Create(datePtr); auto timep = PSPPointer::Create(timePtr); if (!pt.IsValid() || !timep.IsValid()) - return hleLogError(SCERTC, 1, "bad address"); + return hleLogError(Log::sceRtc, 1, "bad address"); *timep = (__RtcPspTimeToTicks(*pt) - rtcMagicOffset) / 1000000ULL; - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static int sceRtcSetDosTime(u32 datePtr, u32 dosTime) { auto pt = PSPPointer::Create(datePtr); if (!pt.IsValid()) - return hleLogError(SCERTC, 1, "bad address"); + return hleLogError(Log::sceRtc, 1, "bad address"); int hms = dosTime & 0xFFFF; int ymd = dosTime >> 16; @@ -570,21 +570,21 @@ static int sceRtcSetDosTime(u32 datePtr, u32 dosTime) { pt->second = (hms << 1) & 0x3E; pt->microsecond = 0; - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static int sceRtcGetDosTime(u32 datePtr, u32 dosTime) { auto datep = PSPPointer::Create(datePtr); auto dosp = PSPPointer::Create(dosTime); if (!datep.IsValid() || !dosp.IsValid()) - return hleLogError(SCERTC, -1, "bad address"); + return hleLogError(Log::sceRtc, -1, "bad address"); if (datep->year < 1980) { *dosp = 0; - return hleLogWarning(SCERTC, -1, "invalid year"); + return hleLogWarning(Log::sceRtc, -1, "invalid year"); } else if (datep->year >= 2108) { *dosp = 0xFF9FBF7D; - return hleLogWarning(SCERTC, -1, "invalid year"); + return hleLogWarning(Log::sceRtc, -1, "invalid year"); } int year = ((datep->year - 1980) & 0x7F) << 9; @@ -597,18 +597,18 @@ static int sceRtcGetDosTime(u32 datePtr, u32 dosTime) { int hms = hour | minute | second; *dosp = (ymd << 16) | hms; - return hleLogSuccessI(SCERTC, 0); + return hleLogSuccessI(Log::sceRtc, 0); } static int sceRtcSetWin32FileTime(u32 datePtr, u64 win32Time) { if (!Memory::IsValidAddress(datePtr)) { - ERROR_LOG_REPORT(SCERTC, "sceRtcSetWin32FileTime(%08x, %lld): invalid address", datePtr, win32Time); + ERROR_LOG_REPORT(Log::sceRtc, "sceRtcSetWin32FileTime(%08x, %lld): invalid address", datePtr, win32Time); return -1; } - DEBUG_LOG(SCERTC, "sceRtcSetWin32FileTime(%08x, %lld)", datePtr, win32Time); + DEBUG_LOG(Log::sceRtc, "sceRtcSetWin32FileTime(%08x, %lld)", datePtr, win32Time); u64 ticks = (win32Time / 10) + rtcFiletimeOffset; auto pspTime = PSPPointer::Create(datePtr); @@ -620,11 +620,11 @@ static int sceRtcGetWin32FileTime(u32 datePtr, u32 win32TimePtr) { if (!Memory::IsValidAddress(datePtr)) { - ERROR_LOG_REPORT(SCERTC, "sceRtcGetWin32FileTime(%08x, %08x): invalid address", datePtr, win32TimePtr); + ERROR_LOG_REPORT(Log::sceRtc, "sceRtcGetWin32FileTime(%08x, %08x): invalid address", datePtr, win32TimePtr); return -1; } - DEBUG_LOG(SCERTC, "sceRtcGetWin32FileTime(%08x, %08x)", datePtr, win32TimePtr); + DEBUG_LOG(Log::sceRtc, "sceRtcGetWin32FileTime(%08x, %08x)", datePtr, win32TimePtr); if (!Memory::IsValidAddress(win32TimePtr)) return SCE_KERNEL_ERROR_INVALID_VALUE; @@ -643,7 +643,7 @@ static int sceRtcGetWin32FileTime(u32 datePtr, u32 win32TimePtr) static int sceRtcCompareTick(u32 tick1Ptr, u32 tick2Ptr) { - DEBUG_LOG(SCERTC, "sceRtcCompareTick(%d,%d)", tick1Ptr, tick2Ptr); + DEBUG_LOG(Log::sceRtc, "sceRtcCompareTick(%d,%d)", tick1Ptr, tick2Ptr); if (Memory::IsValidAddress(tick1Ptr) && Memory::IsValidAddress(tick2Ptr)) { u64 tick1 = Memory::Read_U64(tick1Ptr); @@ -666,7 +666,7 @@ static int sceRtcTickAddTicks(u32 destTickPtr, u32 srcTickPtr, u64 numTicks) Memory::Write_U64(srcTick, destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddTicks(%x,%x,%llu)", destTickPtr, srcTickPtr, numTicks); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddTicks(%x,%x,%llu)", destTickPtr, srcTickPtr, numTicks); return 0; } @@ -680,7 +680,7 @@ static int sceRtcTickAddMicroseconds(u32 destTickPtr,u32 srcTickPtr, u64 numMS) Memory::Write_U64(srcTick, destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddMicroseconds(%x,%x,%llu)", destTickPtr, srcTickPtr, numMS); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddMicroseconds(%x,%x,%llu)", destTickPtr, srcTickPtr, numMS); return 0; } @@ -693,7 +693,7 @@ static int sceRtcTickAddSeconds(u32 destTickPtr, u32 srcTickPtr, u64 numSecs) srcTick += numSecs * 1000000UL; Memory::Write_U64(srcTick, destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddSeconds(%x,%x,%llu)", destTickPtr, srcTickPtr, numSecs); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddSeconds(%x,%x,%llu)", destTickPtr, srcTickPtr, numSecs); return 0; } @@ -706,7 +706,7 @@ static int sceRtcTickAddMinutes(u32 destTickPtr, u32 srcTickPtr, u64 numMins) srcTick += numMins*60000000UL; Memory::Write_U64(srcTick, destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddMinutes(%x,%x,%llu)", destTickPtr, srcTickPtr, numMins); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddMinutes(%x,%x,%llu)", destTickPtr, srcTickPtr, numMins); return 0; } @@ -718,7 +718,7 @@ static int sceRtcTickAddHours(u32 destTickPtr, u32 srcTickPtr, int numHours) srcTick += numHours * 3600ULL * 1000000ULL; Memory::Write_U64(srcTick, destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddMinutes(%d,%d,%d)", destTickPtr, srcTickPtr, numHours); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddMinutes(%d,%d,%d)", destTickPtr, srcTickPtr, numHours); return 0; } @@ -731,7 +731,7 @@ static int sceRtcTickAddDays(u32 destTickPtr, u32 srcTickPtr, int numDays) srcTick += numDays * 86400ULL * 1000000ULL; Memory::Write_U64(srcTick, destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddDays(%d,%d,%d)", destTickPtr, srcTickPtr, numDays); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddDays(%d,%d,%d)", destTickPtr, srcTickPtr, numDays); return 0; } @@ -744,7 +744,7 @@ static int sceRtcTickAddWeeks(u32 destTickPtr, u32 srcTickPtr, int numWeeks) srcTick += numWeeks * 7ULL * 86400ULL * 1000000ULL; Memory::Write_U64(srcTick, destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddWeeks(%d,%d,%d)", destTickPtr, srcTickPtr, numWeeks); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddWeeks(%d,%d,%d)", destTickPtr, srcTickPtr, numWeeks); return 0; } @@ -752,7 +752,7 @@ static int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths) { if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(srcTickPtr)) { - WARN_LOG(SCERTC, "sceRtcTickAddMonths(%08x, %08x, %d): invalid address", destTickPtr, srcTickPtr, numMonths); + WARN_LOG(Log::sceRtc, "sceRtcTickAddMonths(%08x, %08x, %d): invalid address", destTickPtr, srcTickPtr, numMonths); return -1; } @@ -784,7 +784,7 @@ static int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths) Memory::Write_U64(__RtcPspTimeToTicks(pt), destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddMonths(%08x, %08x = %lld, %d)", destTickPtr, srcTickPtr, srcTick, numMonths); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddMonths(%08x, %08x = %lld, %d)", destTickPtr, srcTickPtr, srcTick, numMonths); return 0; } @@ -792,7 +792,7 @@ static int sceRtcTickAddYears(u32 destTickPtr, u32 srcTickPtr, int numYears) { if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(srcTickPtr)) { - WARN_LOG(SCERTC, "sceRtcTickAddYears(%08x, %08x, %d): invalid address", destTickPtr, srcTickPtr, numYears); + WARN_LOG(Log::sceRtc, "sceRtcTickAddYears(%08x, %08x, %d): invalid address", destTickPtr, srcTickPtr, numYears); return -1; } @@ -812,13 +812,13 @@ static int sceRtcTickAddYears(u32 destTickPtr, u32 srcTickPtr, int numYears) Memory::Write_U64(__RtcPspTimeToTicks(pt), destTickPtr); } - DEBUG_LOG(SCERTC, "sceRtcTickAddYears(%08x, %08x = %lld, %d)", destTickPtr, srcTickPtr, srcTick, numYears); + DEBUG_LOG(Log::sceRtc, "sceRtcTickAddYears(%08x, %08x = %lld, %d)", destTickPtr, srcTickPtr, srcTick, numYears); return 0; } static int sceRtcParseDateTime(u32 destTickPtr, u32 dateStringPtr) { - ERROR_LOG_REPORT(SCERTC, "UNIMPL sceRtcParseDateTime(%d,%d)", destTickPtr, dateStringPtr); + ERROR_LOG_REPORT(Log::sceRtc, "UNIMPL sceRtcParseDateTime(%d,%d)", destTickPtr, dateStringPtr); return 0; } @@ -826,7 +826,7 @@ static int sceRtcGetLastAdjustedTime(u32 tickPtr) { if (Memory::IsValidAddress(tickPtr)) Memory::Write_U64(rtcLastAdjustedTicks, tickPtr); - DEBUG_LOG(SCERTC, "sceRtcGetLastAdjustedTime(%d)", tickPtr); + DEBUG_LOG(Log::sceRtc, "sceRtcGetLastAdjustedTime(%d)", tickPtr); return 0; } @@ -834,14 +834,14 @@ static int sceRtcGetLastReincarnatedTime(u32 tickPtr) { if (Memory::IsValidAddress(tickPtr)) Memory::Write_U64(rtcLastReincarnatedTicks, tickPtr); - DEBUG_LOG(SCERTC, "sceRtcGetLastReincarnatedTime(%d)", tickPtr); + DEBUG_LOG(Log::sceRtc, "sceRtcGetLastReincarnatedTime(%d)", tickPtr); return 0; } //Returns 0 on success, according to Project Diva 2nd jpcsptrace log static int sceRtcSetAlarmTick(u32 unknown1, u32 unknown2) { - ERROR_LOG_REPORT(SCERTC, "UNIMPL sceRtcSetAlarmTick(%x, %x)", unknown1, unknown2); + ERROR_LOG_REPORT(Log::sceRtc, "UNIMPL sceRtcSetAlarmTick(%x, %x)", unknown1, unknown2); return 0; } @@ -914,11 +914,11 @@ static int sceRtcFormatRFC2822(u32 outPtr, u32 srcTickPtr, int tz) if (!Memory::IsValidAddress(outPtr) || !Memory::IsValidAddress(srcTickPtr)) { // TODO: Not well tested. - ERROR_LOG(SCERTC, "sceRtcFormatRFC2822(%08x, %08x, %d): invalid address", outPtr, srcTickPtr, tz); + ERROR_LOG(Log::sceRtc, "sceRtcFormatRFC2822(%08x, %08x, %d): invalid address", outPtr, srcTickPtr, tz); return -1; } - DEBUG_LOG(SCERTC, "sceRtcFormatRFC2822(%08x, %08x, %d)", outPtr, srcTickPtr, tz); + DEBUG_LOG(Log::sceRtc, "sceRtcFormatRFC2822(%08x, %08x, %d)", outPtr, srcTickPtr, tz); return __RtcFormatRFC2822(outPtr, srcTickPtr, tz); } @@ -927,7 +927,7 @@ static int sceRtcFormatRFC2822LocalTime(u32 outPtr, u32 srcTickPtr) if (!Memory::IsValidAddress(outPtr) || !Memory::IsValidAddress(srcTickPtr)) { // TODO: Not well tested. - ERROR_LOG(SCERTC, "sceRtcFormatRFC2822LocalTime(%08x, %08x): invalid address", outPtr, srcTickPtr); + ERROR_LOG(Log::sceRtc, "sceRtcFormatRFC2822LocalTime(%08x, %08x): invalid address", outPtr, srcTickPtr); return -1; } @@ -942,7 +942,7 @@ static int sceRtcFormatRFC2822LocalTime(u32 outPtr, u32 srcTickPtr) tz_seconds = time->tm_gmtoff; #endif - DEBUG_LOG(SCERTC, "sceRtcFormatRFC2822LocalTime(%08x, %08x)", outPtr, srcTickPtr); + DEBUG_LOG(Log::sceRtc, "sceRtcFormatRFC2822LocalTime(%08x, %08x)", outPtr, srcTickPtr); return __RtcFormatRFC2822(outPtr, srcTickPtr, tz_seconds / 60); } @@ -951,11 +951,11 @@ static int sceRtcFormatRFC3339(u32 outPtr, u32 srcTickPtr, int tz) if (!Memory::IsValidAddress(outPtr) || !Memory::IsValidAddress(srcTickPtr)) { // TODO: Not well tested. - ERROR_LOG(SCERTC, "sceRtcFormatRFC3339(%08x, %08x, %d): invalid address", outPtr, srcTickPtr, tz); + ERROR_LOG(Log::sceRtc, "sceRtcFormatRFC3339(%08x, %08x, %d): invalid address", outPtr, srcTickPtr, tz); return -1; } - DEBUG_LOG(SCERTC, "sceRtcFormatRFC3339(%08x, %08x, %d)", outPtr, srcTickPtr, tz); + DEBUG_LOG(Log::sceRtc, "sceRtcFormatRFC3339(%08x, %08x, %d)", outPtr, srcTickPtr, tz); return __RtcFormatRFC3339(outPtr, srcTickPtr, tz); } @@ -964,7 +964,7 @@ static int sceRtcFormatRFC3339LocalTime(u32 outPtr, u32 srcTickPtr) if (!Memory::IsValidAddress(outPtr) || !Memory::IsValidAddress(srcTickPtr)) { // TODO: Not well tested. - ERROR_LOG(SCERTC, "sceRtcFormatRFC3339LocalTime(%08x, %08x): invalid address", outPtr, srcTickPtr); + ERROR_LOG(Log::sceRtc, "sceRtcFormatRFC3339LocalTime(%08x, %08x): invalid address", outPtr, srcTickPtr); return -1; } @@ -979,7 +979,7 @@ static int sceRtcFormatRFC3339LocalTime(u32 outPtr, u32 srcTickPtr) tz_seconds = time->tm_gmtoff; #endif - DEBUG_LOG(SCERTC, "sceRtcFormatRFC3339LocalTime(%08x, %08x)", outPtr, srcTickPtr); + DEBUG_LOG(Log::sceRtc, "sceRtcFormatRFC3339LocalTime(%08x, %08x)", outPtr, srcTickPtr); return __RtcFormatRFC3339(outPtr, srcTickPtr, tz_seconds / 60); } diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index d8a320ee55..19a73f168e 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -176,7 +176,7 @@ static void sasMixFinish(u64 userdata, int cycleslate) { __KernelResumeThreadFromWait(threadID, result); __KernelReSchedule("woke from sas mix"); } else { - WARN_LOG(HLE, "Someone else woke up SAS-blocked thread?"); + WARN_LOG(Log::HLE, "Someone else woke up SAS-blocked thread?"); } } @@ -225,26 +225,26 @@ void __SasShutdown() { static u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate) { if (!Memory::IsValidAddress(core) || (core & 0x3F) != 0) { - ERROR_LOG_REPORT(SCESAS, "sceSasInit(%08x, %i, %i, %i, %i): bad core address", core, grainSize, maxVoices, outputMode, sampleRate); + ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad core address", core, grainSize, maxVoices, outputMode, sampleRate); return ERROR_SAS_BAD_ADDRESS; } if (maxVoices == 0 || maxVoices > PSP_SAS_VOICES_MAX) { - ERROR_LOG_REPORT(SCESAS, "sceSasInit(%08x, %i, %i, %i, %i): bad max voices", core, grainSize, maxVoices, outputMode, sampleRate); + ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad max voices", core, grainSize, maxVoices, outputMode, sampleRate); return ERROR_SAS_INVALID_MAX_VOICES; } if (grainSize < 0x40 || grainSize > 0x800 || (grainSize & 0x1F) != 0) { - ERROR_LOG_REPORT(SCESAS, "sceSasInit(%08x, %i, %i, %i, %i): bad grain size", core, grainSize, maxVoices, outputMode, sampleRate); + ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad grain size", core, grainSize, maxVoices, outputMode, sampleRate); return ERROR_SAS_INVALID_GRAIN; } if (outputMode != 0 && outputMode != 1) { - ERROR_LOG_REPORT(SCESAS, "sceSasInit(%08x, %i, %i, %i, %i): bad output mode", core, grainSize, maxVoices, outputMode, sampleRate); + ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad output mode", core, grainSize, maxVoices, outputMode, sampleRate); return ERROR_SAS_INVALID_OUTPUT_MODE; } if (sampleRate != 44100) { - ERROR_LOG_REPORT(SCESAS, "sceSasInit(%08x, %i, %i, %i, %i): bad sample rate", core, grainSize, maxVoices, outputMode, sampleRate); + ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad sample rate", core, grainSize, maxVoices, outputMode, sampleRate); return ERROR_SAS_INVALID_SAMPLE_RATE; } - INFO_LOG(SCESAS, "sceSasInit(%08x, %i, %i, %i, %i)", core, grainSize, maxVoices, outputMode, sampleRate); + INFO_LOG(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i)", core, grainSize, maxVoices, outputMode, sampleRate); sas->SetGrainSize(grainSize); // Seems like maxVoices is actually ignored for all intents and purposes. @@ -266,7 +266,7 @@ static u32 sceSasGetEndFlag(u32 core) { endFlag |= (1 << i); } - VERBOSE_LOG(SCESAS, "%08x=sceSasGetEndFlag(%08x)", endFlag, core); + VERBOSE_LOG(Log::sceSas, "%08x=sceSasGetEndFlag(%08x)", endFlag, core); return endFlag; } @@ -288,15 +288,15 @@ static u32 _sceSasCore(u32 core, u32 outAddr) { PROFILE_THIS_SCOPE("mixer"); if (!Memory::IsValidAddress(outAddr)) { - return hleReportError(SCESAS, ERROR_SAS_INVALID_PARAMETER, "invalid address"); + return hleReportError(Log::sceSas, ERROR_SAS_INVALID_PARAMETER, "invalid address"); } if (!__KernelIsDispatchEnabled()) { - return hleLogError(SCESAS, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogError(Log::sceSas, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } __SasEnqueueMix(outAddr); - return hleLogSuccessVerboseI(SCESAS, delaySasResult(0)); + return hleLogSuccessVerboseI(Log::sceSas, delaySasResult(0)); } // Another way of running the mixer, the inoutAddr should be both input and output @@ -304,47 +304,47 @@ static u32 _sceSasCoreWithMix(u32 core, u32 inoutAddr, int leftVolume, int right PROFILE_THIS_SCOPE("mixer"); if (!Memory::IsValidAddress(inoutAddr)) { - return hleReportError(SCESAS, ERROR_SAS_INVALID_PARAMETER, "invalid address"); + return hleReportError(Log::sceSas, ERROR_SAS_INVALID_PARAMETER, "invalid address"); } if (sas->outputMode == PSP_SAS_OUTPUTMODE_RAW) { - return hleReportError(SCESAS, 0x80000004, "unsupported outputMode"); + return hleReportError(Log::sceSas, 0x80000004, "unsupported outputMode"); } if (!__KernelIsDispatchEnabled()) { - return hleLogError(SCESAS, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogError(Log::sceSas, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } __SasEnqueueMix(inoutAddr, inoutAddr, leftVolume, rightVolume); - return hleLogSuccessVerboseI(SCESAS, delaySasResult(0)); + return hleLogSuccessVerboseI(Log::sceSas, delaySasResult(0)); } static u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogVerbose(SCESAS, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogVerbose(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); } if (size == 0 || ((u32)size & 0xF) != 0) { if (size == 0) { - DEBUG_LOG(SCESAS, "%s: invalid size %d", __FUNCTION__, size); + DEBUG_LOG(Log::sceSas, "%s: invalid size %d", __FUNCTION__, size); } else { - WARN_LOG(SCESAS, "%s: invalid size %d", __FUNCTION__, size); + WARN_LOG(Log::sceSas, "%s: invalid size %d", __FUNCTION__, size); } return ERROR_SAS_INVALID_PARAMETER; } if (loop != 0 && loop != 1) { - WARN_LOG_REPORT(SCESAS, "%s: invalid loop mode %d", __FUNCTION__, loop); + WARN_LOG_REPORT(Log::sceSas, "%s: invalid loop mode %d", __FUNCTION__, loop); return ERROR_SAS_INVALID_LOOP_POS; } if (!Memory::IsValidAddress(vagAddr)) { - ERROR_LOG(SCESAS, "%s: Ignoring invalid VAG audio address %08x", __FUNCTION__, vagAddr); + ERROR_LOG(Log::sceSas, "%s: Ignoring invalid VAG audio address %08x", __FUNCTION__, vagAddr); return 0; } __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (v.type == VOICETYPE_ATRAC3) { - return hleLogError(SCESAS, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); + return hleLogError(Log::sceSas, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); } if (size < 0) { @@ -354,9 +354,9 @@ static u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loo // Needs more rigorous testing perhaps, but this fixes issue https://github.com/hrydgard/ppsspp/issues/5652 // while being fairly low risk to other games. size = 0; - DEBUG_LOG(SCESAS, "sceSasSetVoice(%08x, %i, %08x, %i, %i) : HACK: Negative size changed to 0", core, voiceNum, vagAddr, size, loop); + DEBUG_LOG(Log::sceSas, "sceSasSetVoice(%08x, %i, %08x, %i, %i) : HACK: Negative size changed to 0", core, voiceNum, vagAddr, size, loop); } else { - DEBUG_LOG(SCESAS, "sceSasSetVoice(%08x, %i, %08x, %i, %i)", core, voiceNum, vagAddr, size, loop); + DEBUG_LOG(Log::sceSas, "sceSasSetVoice(%08x, %i, %08x, %i, %i)", core, voiceNum, vagAddr, size, loop); } u32 prevVagAddr = v.vagAddr; @@ -373,28 +373,28 @@ static u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loo static u32 sceSasSetVoicePCM(u32 core, int voiceNum, u32 pcmAddr, int size, int loopPos) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(SCESAS, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); } if (size <= 0 || size > 0x10000) { - WARN_LOG(SCESAS, "%s: invalid size %d", __FUNCTION__, size); + WARN_LOG(Log::sceSas, "%s: invalid size %d", __FUNCTION__, size); return ERROR_SAS_INVALID_PCM_SIZE; } if (loopPos >= size) { - ERROR_LOG_REPORT(SCESAS, "sceSasSetVoicePCM(%08x, %i, %08x, %i, %i): bad loop pos", core, voiceNum, pcmAddr, size, loopPos); + ERROR_LOG_REPORT(Log::sceSas, "sceSasSetVoicePCM(%08x, %i, %08x, %i, %i): bad loop pos", core, voiceNum, pcmAddr, size, loopPos); return ERROR_SAS_INVALID_LOOP_POS; } if (!Memory::IsValidAddress(pcmAddr)) { - ERROR_LOG(SCESAS, "Ignoring invalid PCM audio address %08x", pcmAddr); + ERROR_LOG(Log::sceSas, "Ignoring invalid PCM audio address %08x", pcmAddr); return 0; } __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (v.type == VOICETYPE_ATRAC3) { - return hleLogError(SCESAS, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); + return hleLogError(Log::sceSas, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); } - DEBUG_LOG(SCESAS, "sceSasSetVoicePCM(%08x, %i, %08x, %i, %i)", core, voiceNum, pcmAddr, size, loopPos); + DEBUG_LOG(Log::sceSas, "sceSasSetVoicePCM(%08x, %i, %08x, %i, %i)", core, voiceNum, pcmAddr, size, loopPos); u32 prevPcmAddr = v.pcmAddr; v.type = VOICETYPE_PCM; @@ -415,12 +415,12 @@ static u32 sceSasGetPauseFlag(u32 core) { pauseFlag |= (1 << i); } - DEBUG_LOG(SCESAS, "sceSasGetPauseFlag(%08x)", pauseFlag); + DEBUG_LOG(Log::sceSas, "sceSasGetPauseFlag(%08x)", pauseFlag); return pauseFlag; } static u32 sceSasSetPause(u32 core, u32 voicebit, int pause) { - DEBUG_LOG(SCESAS, "sceSasSetPause(%08x, %08x, %i)", core, voicebit, pause); + DEBUG_LOG(Log::sceSas, "sceSasSetPause(%08x, %08x, %i)", core, voicebit, pause); __SasDrain(); for (int i = 0; voicebit != 0; i++, voicebit >>= 1) { @@ -434,10 +434,10 @@ static u32 sceSasSetPause(u32 core, u32 voicebit, int pause) { } static u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, int effectLeftVol, int effectRightVol) { - DEBUG_LOG(SCESAS, "sceSasSetVolume(%08x, %i, %i, %i, %i, %i)", core, voiceNum, leftVol, rightVol, effectLeftVol, effectRightVol); + DEBUG_LOG(Log::sceSas, "sceSasSetVolume(%08x, %i, %i, %i, %i, %i)", core, voiceNum, leftVol, rightVol, effectLeftVol, effectRightVol); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } bool overVolume = abs(leftVol) > PSP_SAS_VOL_MAX || abs(rightVol) > PSP_SAS_VOL_MAX; @@ -456,15 +456,15 @@ static u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, in static u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } if (pitch < PSP_SAS_PITCH_MIN || pitch > PSP_SAS_PITCH_MAX) { - WARN_LOG(SCESAS, "sceSasSetPitch(%08x, %i, %i): bad pitch", core, voiceNum, pitch); + WARN_LOG(Log::sceSas, "sceSasSetPitch(%08x, %i, %i): bad pitch", core, voiceNum, pitch); return ERROR_SAS_INVALID_PITCH; } - DEBUG_LOG(SCESAS, "sceSasSetPitch(%08x, %i, %i)", core, voiceNum, pitch); + DEBUG_LOG(Log::sceSas, "sceSasSetPitch(%08x, %i, %i)", core, voiceNum, pitch); __SasDrain(); SasVoice &v = sas->voices[voiceNum]; v.pitch = pitch; @@ -472,10 +472,10 @@ static u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) { } static u32 sceSasSetKeyOn(u32 core, int voiceNum) { - DEBUG_LOG(SCESAS, "sceSasSetKeyOn(%08x, %i)", core, voiceNum); + DEBUG_LOG(Log::sceSas, "sceSasSetKeyOn(%08x, %i)", core, voiceNum); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } @@ -492,10 +492,10 @@ static u32 sceSasSetKeyOn(u32 core, int voiceNum) { // sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase! static u32 sceSasSetKeyOff(u32 core, int voiceNum) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } else { - DEBUG_LOG(SCESAS, "sceSasSetKeyOff(%08x, %i)", core, voiceNum); + DEBUG_LOG(Log::sceSas, "sceSasSetKeyOff(%08x, %i)", core, voiceNum); __SasDrain(); if (sas->voices[voiceNum].paused || !sas->voices[voiceNum].on) { @@ -510,15 +510,15 @@ static u32 sceSasSetKeyOff(u32 core, int voiceNum) { static u32 sceSasSetNoise(u32 core, int voiceNum, int freq) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } if (freq < 0 || freq >= 64) { - DEBUG_LOG(SCESAS, "sceSasSetNoise(%08x, %i, %i)", core, voiceNum, freq); + DEBUG_LOG(Log::sceSas, "sceSasSetNoise(%08x, %i, %i)", core, voiceNum, freq); return ERROR_SAS_INVALID_NOISE_FREQ; } - DEBUG_LOG(SCESAS, "sceSasSetNoise(%08x, %i, %i)", core, voiceNum, freq); + DEBUG_LOG(Log::sceSas, "sceSasSetNoise(%08x, %i, %i)", core, voiceNum, freq); __SasDrain(); SasVoice &v = sas->voices[voiceNum]; @@ -529,11 +529,11 @@ static u32 sceSasSetNoise(u32 core, int voiceNum, int freq) { static u32 sceSasSetSL(u32 core, int voiceNum, int level) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } - DEBUG_LOG(SCESAS, "sceSasSetSL(%08x, %i, %08x)", core, voiceNum, level); + DEBUG_LOG(Log::sceSas, "sceSasSetSL(%08x, %i, %08x)", core, voiceNum, level); __SasDrain(); SasVoice &v = sas->voices[voiceNum]; v.envelope.SetSustainLevel(level); @@ -542,17 +542,17 @@ static u32 sceSasSetSL(u32 core, int voiceNum, int level) { static u32 sceSasSetADSR(u32 core, int voiceNum, int flag, int a, int d, int s, int r) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } // Create a mask like flag for the invalid values. int invalid = (a < 0 ? 0x1 : 0) | (d < 0 ? 0x2 : 0) | (s < 0 ? 0x4 : 0) | (r < 0 ? 0x8 : 0); if (invalid & flag) { - WARN_LOG_REPORT(SCESAS, "sceSasSetADSR(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid value", core, voiceNum, flag, a, d, s, r); + WARN_LOG_REPORT(Log::sceSas, "sceSasSetADSR(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid value", core, voiceNum, flag, a, d, s, r); return ERROR_SAS_INVALID_ADSR_RATE; } - DEBUG_LOG(SCESAS, "0=sceSasSetADSR(%08x, %i, %i, %08x, %08x, %08x, %08x)", core, voiceNum, flag, a, d, s, r); + DEBUG_LOG(Log::sceSas, "0=sceSasSetADSR(%08x, %i, %i, %08x, %08x, %08x, %08x)", core, voiceNum, flag, a, d, s, r); __SasDrain(); SasVoice &v = sas->voices[voiceNum]; @@ -562,7 +562,7 @@ static u32 sceSasSetADSR(u32 core, int voiceNum, int flag, int a, int d, int s, static u32 sceSasSetADSRMode(u32 core, int voiceNum, int flag, int a, int d, int s, int r) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } @@ -589,14 +589,14 @@ static u32 sceSasSetADSRMode(u32 core, int voiceNum, int flag, int a, int d, int if (invalid & flag) { if (a == 5 && d == 5 && s == 5 && r == 5) { // Some games do this right at init. It seems to fail even on a PSP, but let's not report it. - DEBUG_LOG(SCESAS, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid modes", core, voiceNum, flag, a, d, s, r); + DEBUG_LOG(Log::sceSas, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid modes", core, voiceNum, flag, a, d, s, r); } else { - WARN_LOG_REPORT(SCESAS, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid modes", core, voiceNum, flag, a, d, s, r); + WARN_LOG_REPORT(Log::sceSas, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid modes", core, voiceNum, flag, a, d, s, r); } return ERROR_SAS_INVALID_ADSR_CURVE_MODE; } - DEBUG_LOG(SCESAS, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x)", core, voiceNum, flag, a, d, s, r); + DEBUG_LOG(Log::sceSas, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x)", core, voiceNum, flag, a, d, s, r); __SasDrain(); SasVoice &v = sas->voices[voiceNum]; v.envelope.SetEnvelope(flag, a, d, s, r); @@ -606,16 +606,16 @@ static u32 sceSasSetADSRMode(u32 core, int voiceNum, int flag, int a, int d, int static u32 sceSasSetSimpleADSR(u32 core, int voiceNum, u32 ADSREnv1, u32 ADSREnv2) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - WARN_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + WARN_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } // This bit could be related to decay type or systain type, but gives an error if you try to set it. if ((ADSREnv2 >> 13) & 1) { - WARN_LOG_REPORT(SCESAS, "sceSasSetSimpleADSR(%08x, %d, %04x, %04x): Invalid ADSREnv2", core, voiceNum, ADSREnv1, ADSREnv2); + WARN_LOG_REPORT(Log::sceSas, "sceSasSetSimpleADSR(%08x, %d, %04x, %04x): Invalid ADSREnv2", core, voiceNum, ADSREnv1, ADSREnv2); return ERROR_SAS_INVALID_ADSR_CURVE_MODE; } - DEBUG_LOG(SCESAS, "sasSetSimpleADSR(%08x, %i, %08x, %08x)", core, voiceNum, ADSREnv1, ADSREnv2); + DEBUG_LOG(Log::sceSas, "sasSetSimpleADSR(%08x, %i, %08x, %08x)", core, voiceNum, ADSREnv1, ADSREnv2); __SasDrain(); SasVoice &v = sas->voices[voiceNum]; @@ -625,82 +625,82 @@ static u32 sceSasSetSimpleADSR(u32 core, int voiceNum, u32 ADSREnv1, u32 ADSREnv static u32 sceSasGetEnvelopeHeight(u32 core, int voiceNum) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - ERROR_LOG(SCESAS, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + ERROR_LOG(Log::sceSas, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } __SasDrain(); SasVoice &v = sas->voices[voiceNum]; int height = v.envelope.GetHeight(); - DEBUG_LOG(SCESAS, "%i = sceSasGetEnvelopeHeight(%08x, %i)", height, core, voiceNum); + DEBUG_LOG(Log::sceSas, "%i = sceSasGetEnvelopeHeight(%08x, %i)", height, core, voiceNum); return height; } static u32 sceSasRevType(u32 core, int type) { if (type < PSP_SAS_EFFECT_TYPE_OFF || type > PSP_SAS_EFFECT_TYPE_MAX) { - return hleLogError(SCESAS, ERROR_SAS_REV_INVALID_TYPE, "invalid type"); + return hleLogError(Log::sceSas, ERROR_SAS_REV_INVALID_TYPE, "invalid type"); } __SasDrain(); sas->SetWaveformEffectType(type); - return hleLogSuccessI(SCESAS, 0); + return hleLogSuccessI(Log::sceSas, 0); } static u32 sceSasRevParam(u32 core, int delay, int feedback) { if (delay < 0 || delay >= 128) { - return hleLogError(SCESAS, ERROR_SAS_REV_INVALID_DELAY, "invalid delay value"); + return hleLogError(Log::sceSas, ERROR_SAS_REV_INVALID_DELAY, "invalid delay value"); } if (feedback < 0 || feedback >= 128) { - return hleLogError(SCESAS, ERROR_SAS_REV_INVALID_FEEDBACK, "invalid feedback value"); + return hleLogError(Log::sceSas, ERROR_SAS_REV_INVALID_FEEDBACK, "invalid feedback value"); } __SasDrain(); sas->waveformEffect.delay = delay; sas->waveformEffect.feedback = feedback; - return hleLogSuccessI(SCESAS, 0); + return hleLogSuccessI(Log::sceSas, 0); } static u32 sceSasRevEVOL(u32 core, u32 lv, u32 rv) { if (lv > 0x1000 || rv > 0x1000) { - return hleReportDebug(SCESAS, ERROR_SAS_REV_INVALID_VOLUME, "invalid volume"); + return hleReportDebug(Log::sceSas, ERROR_SAS_REV_INVALID_VOLUME, "invalid volume"); } __SasDrain(); sas->waveformEffect.leftVol = lv; sas->waveformEffect.rightVol = rv; - return hleLogSuccessI(SCESAS, 0); + return hleLogSuccessI(Log::sceSas, 0); } static u32 sceSasRevVON(u32 core, int dry, int wet) { __SasDrain(); sas->waveformEffect.isDryOn = dry != 0; sas->waveformEffect.isWetOn = wet != 0; - return hleLogSuccessI(SCESAS, 0); + return hleLogSuccessI(Log::sceSas, 0); } static u32 sceSasGetGrain(u32 core) { - DEBUG_LOG(SCESAS, "sceSasGetGrain(%08x)", core); + DEBUG_LOG(Log::sceSas, "sceSasGetGrain(%08x)", core); return sas->GetGrainSize(); } static u32 sceSasSetGrain(u32 core, int grain) { - INFO_LOG(SCESAS, "sceSasSetGrain(%08x, %i)", core, grain); + INFO_LOG(Log::sceSas, "sceSasSetGrain(%08x, %i)", core, grain); __SasDrain(); sas->SetGrainSize(grain); return 0; } static u32 sceSasGetOutputMode(u32 core) { - DEBUG_LOG(SCESAS, "sceSasGetOutputMode(%08x)", core); + DEBUG_LOG(Log::sceSas, "sceSasGetOutputMode(%08x)", core); return sas->outputMode; } static u32 sceSasSetOutputMode(u32 core, u32 outputMode) { if (outputMode != 0 && outputMode != 1) { - ERROR_LOG_REPORT(SCESAS, "sceSasSetOutputMode(%08x, %i): bad output mode", core, outputMode); + ERROR_LOG_REPORT(Log::sceSas, "sceSasSetOutputMode(%08x, %i): bad output mode", core, outputMode); return ERROR_SAS_INVALID_OUTPUT_MODE; } - DEBUG_LOG(SCESAS, "sceSasSetOutputMode(%08x, %i)", core, outputMode); + DEBUG_LOG(Log::sceSas, "sceSasSetOutputMode(%08x, %i)", core, outputMode); __SasDrain(); sas->outputMode = outputMode; @@ -708,7 +708,7 @@ static u32 sceSasSetOutputMode(u32 core, u32 outputMode) { } static u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) { - DEBUG_LOG(SCESAS, "sceSasGetAllEnvelopeHeights(%08x, %i)", core, heightsAddr); + DEBUG_LOG(Log::sceSas, "sceSasGetAllEnvelopeHeights(%08x, %i)", core, heightsAddr); if (!Memory::IsValidAddress(heightsAddr)) { return ERROR_SAS_INVALID_PARAMETER; @@ -724,24 +724,24 @@ static u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) { } static u32 sceSasSetTriangularWave(u32 sasCore, int voice, int unknown) { - ERROR_LOG_REPORT(SCESAS, "UNIMPL sceSasSetTriangularWave(%08x, %i, %i)", sasCore, voice, unknown); + ERROR_LOG_REPORT(Log::sceSas, "UNIMPL sceSasSetTriangularWave(%08x, %i, %i)", sasCore, voice, unknown); return 0; } static u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown) { - ERROR_LOG_REPORT(SCESAS, "UNIMPL sceSasSetSteepWave(%08x, %i, %i)", sasCore, voice, unknown); + ERROR_LOG_REPORT(Log::sceSas, "UNIMPL sceSasSetSteepWave(%08x, %i, %i)", sasCore, voice, unknown); return 0; } static u32 __sceSasSetVoiceATRAC3(u32 core, int voiceNum, u32 atrac3Context) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(SCESAS, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); } __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (v.type == VOICETYPE_ATRAC3) { - return hleLogError(SCESAS, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); + return hleLogError(Log::sceSas, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); } v.type = VOICETYPE_ATRAC3; v.loop = false; @@ -749,15 +749,15 @@ static u32 __sceSasSetVoiceATRAC3(u32 core, int voiceNum, u32 atrac3Context) { v.atrac3.setContext(atrac3Context); Memory::Write_U32(atrac3Context, core + 56 * voiceNum + 20); - return hleLogSuccessI(SCESAS, 0); + return hleLogSuccessI(Log::sceSas, 0); } static u32 __sceSasConcatenateATRAC3(u32 core, int voiceNum, u32 atrac3DataAddr, int atrac3DataLength) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(SCESAS, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); } - DEBUG_LOG_REPORT(SCESAS, "__sceSasConcatenateATRAC3(%08x, %i, %08x, %i)", core, voiceNum, atrac3DataAddr, atrac3DataLength); + DEBUG_LOG_REPORT(Log::sceSas, "__sceSasConcatenateATRAC3(%08x, %i, %08x, %i)", core, voiceNum, atrac3DataAddr, atrac3DataLength); __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (Memory::IsValidAddress(atrac3DataAddr)) @@ -767,13 +767,13 @@ static u32 __sceSasConcatenateATRAC3(u32 core, int voiceNum, u32 atrac3DataAddr, static u32 __sceSasUnsetATRAC3(u32 core, int voiceNum) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(SCESAS, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); } __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (v.type != VOICETYPE_ATRAC3) { - return hleLogError(SCESAS, ERROR_SAS_ATRAC3_NOT_SET, "voice is not ATRAC3"); + return hleLogError(Log::sceSas, ERROR_SAS_ATRAC3_NOT_SET, "voice is not ATRAC3"); } v.type = VOICETYPE_OFF; v.playing = false; @@ -782,7 +782,7 @@ static u32 __sceSasUnsetATRAC3(u32 core, int voiceNum) { v.paused = false; Memory::Write_U32(0, core + 56 * voiceNum + 20); - return hleLogSuccessI(SCESAS, 0); + return hleLogSuccessI(Log::sceSas, 0); } void __SasGetDebugStats(char *stats, size_t bufsize) { diff --git a/Core/HLE/sceSfmt19937.cpp b/Core/HLE/sceSfmt19937.cpp index d0cc399094..4e56b97c41 100644 --- a/Core/HLE/sceSfmt19937.cpp +++ b/Core/HLE/sceSfmt19937.cpp @@ -28,10 +28,10 @@ static int sceSfmt19937InitGenRand(u32 sfmt, u32 seed) { if (!Memory::IsValidAddress(sfmt)) { - ERROR_LOG(HLE, "sceSfmt19937InitGenRand(sfmt=%08x, seed=%08x) - bad address(es)", sfmt, seed); + ERROR_LOG(Log::HLE, "sceSfmt19937InitGenRand(sfmt=%08x, seed=%08x) - bad address(es)", sfmt, seed); return -1; } - INFO_LOG(HLE, "sceSfmt19937InitGenRand(sfmt=%08x, seed=%08x)", sfmt, seed); + INFO_LOG(Log::HLE, "sceSfmt19937InitGenRand(sfmt=%08x, seed=%08x)", sfmt, seed); sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt); sfmt_init_gen_rand(psfmt, seed); @@ -41,10 +41,10 @@ static int sceSfmt19937InitGenRand(u32 sfmt, u32 seed) { static int sceSfmt19937InitByArray(u32 sfmt, u32 seeds, int seedslen) { if (!Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(seeds) || !Memory::IsValidAddress(seeds + 4 * (seedslen - 1))) { - ERROR_LOG(HLE, "sceSfmt19937InitByArray(sfmt=%08x, seeds=%08x, seedslen=%08x) - bad address(es)", sfmt, seeds, seedslen); + ERROR_LOG(Log::HLE, "sceSfmt19937InitByArray(sfmt=%08x, seeds=%08x, seedslen=%08x) - bad address(es)", sfmt, seeds, seedslen); return -1; } - INFO_LOG(HLE, "sceSfmt19937InitByArray(sfmt=%08x, seeds=%08x, seedslen=%08x)", sfmt, seeds, seedslen); + INFO_LOG(Log::HLE, "sceSfmt19937InitByArray(sfmt=%08x, seeds=%08x, seedslen=%08x)", sfmt, seeds, seedslen); sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt); uint32_t *pseeds = (uint32_t *)Memory::GetPointerUnchecked(seeds); @@ -55,10 +55,10 @@ static int sceSfmt19937InitByArray(u32 sfmt, u32 seeds, int seedslen) { static u32 sceSfmt19937GenRand32(u32 sfmt) { if (!Memory::IsValidAddress(sfmt)) { - ERROR_LOG(HLE, "sceSfmt19937GenRand32(sfmt=%08x) - bad address(es)", sfmt); + ERROR_LOG(Log::HLE, "sceSfmt19937GenRand32(sfmt=%08x) - bad address(es)", sfmt); return -1; } - INFO_LOG(HLE, "sceSfmt19937GenRand32(sfmt=%08x)", sfmt); + INFO_LOG(Log::HLE, "sceSfmt19937GenRand32(sfmt=%08x)", sfmt); sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt); u32 ret = sfmt_genrand_uint32(psfmt); @@ -68,10 +68,10 @@ static u32 sceSfmt19937GenRand32(u32 sfmt) { static u64 sceSfmt19937GenRand64(u32 sfmt) { if (!Memory::IsValidAddress(sfmt)) { - ERROR_LOG(HLE, "sceSfmt19937GenRand64(sfmt=%08x) - bad address(es)", sfmt); + ERROR_LOG(Log::HLE, "sceSfmt19937GenRand64(sfmt=%08x) - bad address(es)", sfmt); return -1; } - INFO_LOG(HLE, "sceSfmt19937GenRand64(sfmt=%08x)", sfmt); + INFO_LOG(Log::HLE, "sceSfmt19937GenRand64(sfmt=%08x)", sfmt); sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt); u64 ret = sfmt_genrand_uint64(psfmt); @@ -81,10 +81,10 @@ static u64 sceSfmt19937GenRand64(u32 sfmt) { static int sceSfmt19937FillArray32(u32 sfmt, u32 array, int arraylen) { if (!Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(array) || !Memory::IsValidAddress(array + 4 * (arraylen - 1))) { - ERROR_LOG(HLE, "sceSfmt19937FillArray32(sfmt=%08x, ar=%08x, arlen=%08x) - bad address(es)", sfmt, array, arraylen); + ERROR_LOG(Log::HLE, "sceSfmt19937FillArray32(sfmt=%08x, ar=%08x, arlen=%08x) - bad address(es)", sfmt, array, arraylen); return -1; } - INFO_LOG(HLE, "sceSfmt19937FillArray32(sfmt=%08x, ar=%08x, arlen=%08x)", sfmt, array, arraylen); + INFO_LOG(Log::HLE, "sceSfmt19937FillArray32(sfmt=%08x, ar=%08x, arlen=%08x)", sfmt, array, arraylen); sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt); uint32_t *parray = (uint32_t *)Memory::GetPointerUnchecked(array); @@ -95,10 +95,10 @@ static int sceSfmt19937FillArray32(u32 sfmt, u32 array, int arraylen) { static int sceSfmt19937FillArray64(u32 sfmt, u32 array, int arraylen) { if (!Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(array) || !Memory::IsValidAddress(array + 8 * (arraylen - 1))) { - ERROR_LOG(HLE, "sceSfmt19937FillArray64(sfmt=%08x, ar=%08x, arlen=%08x) - bad address(es)", sfmt, array, arraylen); + ERROR_LOG(Log::HLE, "sceSfmt19937FillArray64(sfmt=%08x, ar=%08x, arlen=%08x) - bad address(es)", sfmt, array, arraylen); return -1; } - INFO_LOG(HLE, "sceSfmt19937FillArray64(sfmt=%08x, ar=%08x, arlen=%08x)", sfmt, array, arraylen); + INFO_LOG(Log::HLE, "sceSfmt19937FillArray64(sfmt=%08x, ar=%08x, arlen=%08x)", sfmt, array, arraylen); sfmt_t *psfmt = (sfmt_t *)Memory::GetPointerUnchecked(sfmt); uint64_t *parray = (uint64_t *)Memory::GetPointerUnchecked(array); diff --git a/Core/HLE/sceSha256.cpp b/Core/HLE/sceSha256.cpp index a2dcef54ee..1663d64bba 100644 --- a/Core/HLE/sceSha256.cpp +++ b/Core/HLE/sceSha256.cpp @@ -23,10 +23,10 @@ static int sceSha256Digest(u32 data, int dataLen, u32 digestPtr) { if (!Memory::IsValidAddress(data) || !Memory::IsValidAddress(digestPtr) || !Memory::IsValidAddress(data + dataLen)) { - ERROR_LOG(HLE, "sceSha256Digest(data=%08x, len=%d, digest=%08x) - bad address(es)", data, dataLen, digestPtr); + ERROR_LOG(Log::HLE, "sceSha256Digest(data=%08x, len=%d, digest=%08x) - bad address(es)", data, dataLen, digestPtr); return -1; } - INFO_LOG(HLE, "sceSha256Digest(data=%08x, len=%d, digest=%08x)", data, dataLen, digestPtr); + INFO_LOG(Log::HLE, "sceSha256Digest(data=%08x, len=%d, digest=%08x)", data, dataLen, digestPtr); // Already checked above... u8 *digest = Memory::GetPointerWriteUnchecked(digestPtr); diff --git a/Core/HLE/sceSircs.cpp b/Core/HLE/sceSircs.cpp index c300f84367..cad58326eb 100644 --- a/Core/HLE/sceSircs.cpp +++ b/Core/HLE/sceSircs.cpp @@ -32,7 +32,7 @@ int sceSircsSend(u32 dataAddr, int count) { auto data = PSPPointer::Create(dataAddr); if (data.IsValid()) { - INFO_LOG(HLE, "%s (version=0x%x, command=0x%x, address=0x%x, count=%d)", + INFO_LOG(Log::HLE, "%s (version=0x%x, command=0x%x, address=0x%x, count=%d)", __FUNCTION__, data->version, data->command, data->address, count); #if PPSSPP_PLATFORM(ANDROID) char command[40] = {0}; diff --git a/Core/HLE/sceSsl.cpp b/Core/HLE/sceSsl.cpp index 7361962d1d..6e9afe7a6d 100644 --- a/Core/HLE/sceSsl.cpp +++ b/Core/HLE/sceSsl.cpp @@ -51,7 +51,7 @@ void __SslDoState(PointerWrap &p) static int sceSslInit(int heapSize) { - DEBUG_LOG(HLE, "sceSslInit %d", heapSize); + DEBUG_LOG(Log::HLE, "sceSslInit %d", heapSize); if (isSslInit) { return ERROR_SSL_ALREADY_INIT; @@ -69,7 +69,7 @@ static int sceSslInit(int heapSize) static int sceSslEnd() { - DEBUG_LOG(HLE, "sceSslEnd"); + DEBUG_LOG(Log::HLE, "sceSslEnd"); if (!isSslInit) { return ERROR_SSL_NOT_INIT; @@ -80,7 +80,7 @@ static int sceSslEnd() static int sceSslGetUsedMemoryMax(u32 maxMemPtr) { - DEBUG_LOG(HLE, "sceSslGetUsedMemoryMax %d", maxMemPtr); + DEBUG_LOG(Log::HLE, "sceSslGetUsedMemoryMax %d", maxMemPtr); if (!isSslInit) { return ERROR_SSL_NOT_INIT; @@ -95,7 +95,7 @@ static int sceSslGetUsedMemoryMax(u32 maxMemPtr) static int sceSslGetUsedMemoryCurrent(u32 currentMemPtr) { - DEBUG_LOG(HLE, "sceSslGetUsedMemoryCurrent %d", currentMemPtr); + DEBUG_LOG(Log::HLE, "sceSslGetUsedMemoryCurrent %d", currentMemPtr); if (!isSslInit) { return ERROR_SSL_NOT_INIT; diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 0257ee71ed..3e1b610195 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -213,10 +213,10 @@ static void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId) HLEKernel::RemoveWaitingThread(umdWaitingThreads, threadID); - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB: Suspending lock wait for callback"); + DEBUG_LOG(Log::sceIo, "sceUmdWaitDriveStatCB: Suspending lock wait for callback"); } else - WARN_LOG_REPORT(SCEIO, "sceUmdWaitDriveStatCB: beginning callback with bad wait id?"); + WARN_LOG_REPORT(Log::sceIo, "sceUmdWaitDriveStatCB: beginning callback with bad wait id?"); } static void __UmdEndCallback(SceUID threadID, SceUID prevCallbackId) @@ -227,7 +227,7 @@ static void __UmdEndCallback(SceUID threadID, SceUID prevCallbackId) u32 stat = __KernelGetWaitValue(threadID, error); if (umdPausedWaits.find(pauseKey) == umdPausedWaits.end()) { - WARN_LOG_REPORT(SCEIO, "__UmdEndCallback(): UMD paused wait missing"); + WARN_LOG_REPORT(Log::sceIo, "__UmdEndCallback(): UMD paused wait missing"); __KernelResumeThreadFromWait(threadID, 0); return; @@ -254,23 +254,23 @@ static void __UmdEndCallback(SceUID threadID, SceUID prevCallbackId) umdWaitingThreads.push_back(threadID); - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB: Resuming lock wait for callback"); + DEBUG_LOG(Log::sceIo, "sceUmdWaitDriveStatCB: Resuming lock wait for callback"); } } static int sceUmdCheckMedium() { if (UMDInserted) { - DEBUG_LOG(SCEIO, "1=sceUmdCheckMedium()"); + DEBUG_LOG(Log::sceIo, "1=sceUmdCheckMedium()"); return 1; //non-zero: disc in drive } - DEBUG_LOG(SCEIO, "0=sceUmdCheckMedium()"); + DEBUG_LOG(Log::sceIo, "0=sceUmdCheckMedium()"); return 0; } static u32 sceUmdGetDiscInfo(u32 infoAddr) { - DEBUG_LOG(SCEIO, "sceUmdGetDiscInfo(%08x)", infoAddr); + DEBUG_LOG(Log::sceIo, "sceUmdGetDiscInfo(%08x)", infoAddr); if (Memory::IsValidAddress(infoAddr)) { auto info = PSPPointer::Create(infoAddr); @@ -285,14 +285,14 @@ static u32 sceUmdGetDiscInfo(u32 infoAddr) static int sceUmdActivate(u32 mode, const char *name) { if (mode < 1 || mode > 2) - return hleLogWarning(SCEIO, PSP_ERROR_UMD_INVALID_PARAM); + return hleLogWarning(Log::sceIo, PSP_ERROR_UMD_INVALID_PARAM); __KernelUmdActivate(); if (mode != 1) { - return hleLogError(SCEIO, 0, "UNTESTED"); + return hleLogError(Log::sceIo, 0, "UNTESTED"); } - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } static int sceUmdDeactivate(u32 mode, const char *name) @@ -304,9 +304,9 @@ static int sceUmdDeactivate(u32 mode, const char *name) __KernelUmdDeactivate(); if (mode == 1) { - DEBUG_LOG(SCEIO, "0=sceUmdDeactivate(%d, %s)", mode, name); + DEBUG_LOG(Log::sceIo, "0=sceUmdDeactivate(%d, %s)", mode, name); } else { - ERROR_LOG(SCEIO, "UNTESTED 0=sceUmdDeactivate(%d, %s)", mode, name); + ERROR_LOG(Log::sceIo, "UNTESTED 0=sceUmdDeactivate(%d, %s)", mode, name); } return 0; @@ -323,7 +323,7 @@ static u32 sceUmdRegisterUMDCallBack(u32 cbId) // There's only ever one. driveCBId = cbId; } - DEBUG_LOG(SCEIO, "%d=sceUmdRegisterUMDCallback(id=%08x)", retVal, cbId); + DEBUG_LOG(Log::sceIo, "%d=sceUmdRegisterUMDCallback(id=%08x)", retVal, cbId); return retVal; } @@ -341,20 +341,20 @@ static int sceUmdUnRegisterUMDCallBack(int cbId) } driveCBId = 0; } - DEBUG_LOG(SCEIO, "%08x=sceUmdUnRegisterUMDCallBack(id=%08x)", retVal, cbId); + DEBUG_LOG(Log::sceIo, "%08x=sceUmdUnRegisterUMDCallBack(id=%08x)", retVal, cbId); return retVal; } static u32 sceUmdGetDriveStat() { if (!UMDInserted) { - WARN_LOG(SCEIO, "sceUmdGetDriveStat: UMD is taking out for switch UMD"); + WARN_LOG(Log::sceIo, "sceUmdGetDriveStat: UMD is taking out for switch UMD"); return PSP_UMD_NOT_PRESENT; } //u32 retVal = PSP_UMD_INITED | PSP_UMD_READY | PSP_UMD_PRESENT; u32 retVal = __KernelUmdGetState(); // This one can be very spammy. - VERBOSE_LOG(SCEIO,"0x%02x=sceUmdGetDriveStat()", retVal); + VERBOSE_LOG(Log::sceIo,"0x%02x=sceUmdGetDriveStat()", retVal); return retVal; } @@ -391,40 +391,40 @@ static void __UmdWaitStat(u32 timeout) */ static int sceUmdWaitDriveStat(u32 stat) { if ((stat & UMD_STAT_ALLOW_WAIT) == 0) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } if (!__KernelIsDispatchEnabled()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } if (__IsInInterrupt()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); } hleEatCycles(520); if ((stat & __KernelUmdGetState()) == 0) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStat(stat = %08x): waiting", stat); + DEBUG_LOG(Log::sceIo, "sceUmdWaitDriveStat(stat = %08x): waiting", stat); umdWaitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0, "umd stat waited"); return 0; } - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } static int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) { if ((stat & UMD_STAT_ALLOW_WAIT) == 0) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } if (!__KernelIsDispatchEnabled()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } if (__IsInInterrupt()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); } hleEatCycles(520); if ((stat & __KernelUmdGetState()) == 0) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): waiting", stat, timeout); + DEBUG_LOG(Log::sceIo, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): waiting", stat, timeout); __UmdWaitStat(timeout); umdWaitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, false, "umd stat waited with timer"); @@ -433,24 +433,24 @@ static int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) { hleReSchedule("umd stat checked"); } - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } static int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) { if ((stat & UMD_STAT_ALLOW_WAIT) == 0) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } if (!__KernelIsDispatchEnabled()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } if (__IsInInterrupt()) { - return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); + return hleLogDebug(Log::sceIo, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); } hleEatCycles(520); hleCheckCurrentCallbacks(); if ((stat & __KernelUmdGetState()) == 0) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): waiting", stat, timeout); + DEBUG_LOG(Log::sceIo, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): waiting", stat, timeout); if (timeout == 0) { timeout = 8000; } @@ -462,12 +462,12 @@ static int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) { hleReSchedule("umd stat waited"); } - return hleLogSuccessI(SCEIO, 0); + return hleLogSuccessI(Log::sceIo, 0); } static u32 sceUmdCancelWaitDriveStat() { - DEBUG_LOG(SCEIO, "0=sceUmdCancelWaitDriveStat()"); + DEBUG_LOG(Log::sceIo, "0=sceUmdCancelWaitDriveStat()"); for (size_t i = 0; i < umdWaitingThreads.size(); ++i) { const SceUID threadID = umdWaitingThreads[i]; @@ -481,7 +481,7 @@ static u32 sceUmdCancelWaitDriveStat() static u32 sceUmdGetErrorStat() { - DEBUG_LOG(SCEIO,"%i=sceUmdGetErrorStat()", umdErrorStat); + DEBUG_LOG(Log::sceIo,"%i=sceUmdGetErrorStat()", umdErrorStat); return umdErrorStat; } @@ -489,7 +489,7 @@ void __UmdReplace(const Path &filepath) { std::string error = ""; FileLoader *fileLoader; if (!UmdReplace(filepath, &fileLoader, error)) { - ERROR_LOG(SCEIO, "UMD Replace failed: %s", error.c_str()); + ERROR_LOG(Log::sceIo, "UMD Replace failed: %s", error.c_str()); return; } @@ -512,9 +512,9 @@ bool getUMDReplacePermit() { static u32 sceUmdReplaceProhibit() { - DEBUG_LOG(SCEIO, "sceUmdReplaceProhibit()"); + DEBUG_LOG(Log::sceIo, "sceUmdReplaceProhibit()"); if (g_UMDReplacePermit) { - INFO_LOG(SCEIO, "sceUmdReplaceProhibit() - prohibited"); + INFO_LOG(Log::sceIo, "sceUmdReplaceProhibit() - prohibited"); g_UMDReplacePermit = false; System_Notify(SystemNotification::SWITCH_UMD_UPDATED); } @@ -523,9 +523,9 @@ static u32 sceUmdReplaceProhibit() static u32 sceUmdReplacePermit() { - DEBUG_LOG(SCEIO, "sceUmdReplacePermit()"); + DEBUG_LOG(Log::sceIo, "sceUmdReplacePermit()"); if (!g_UMDReplacePermit) { - INFO_LOG(SCEIO, "sceUmdReplacePermit() - permitted"); + INFO_LOG(Log::sceIo, "sceUmdReplacePermit() - permitted"); g_UMDReplacePermit = true; System_Notify(SystemNotification::SWITCH_UMD_UPDATED); } diff --git a/Core/HLE/sceUsb.cpp b/Core/HLE/sceUsb.cpp index d47192a995..e6d08a9ddf 100644 --- a/Core/HLE/sceUsb.cpp +++ b/Core/HLE/sceUsb.cpp @@ -148,14 +148,14 @@ void __UsbDoState(PointerWrap &p) { } static int sceUsbStart(const char* driverName, u32 argsSize, u32 argsPtr) { - INFO_LOG(HLE, "sceUsbStart(%s, %i, %08x)", driverName, argsSize, argsPtr); + INFO_LOG(Log::HLE, "sceUsbStart(%s, %i, %08x)", driverName, argsSize, argsPtr); usbStarted = true; UsbUpdateState(); return 0; } static int sceUsbStop(const char* driverName, u32 argsSize, u32 argsPtr) { - INFO_LOG(HLE, "sceUsbStop(%s, %i, %08x)", driverName, argsSize, argsPtr); + INFO_LOG(Log::HLE, "sceUsbStop(%s, %i, %08x)", driverName, argsSize, argsPtr); usbStarted = false; UsbUpdateState(); return 0; @@ -168,19 +168,19 @@ static int sceUsbGetState() { } else { state = UsbCurrentState(); } - DEBUG_LOG(HLE, "sceUsbGetState: 0x%x", state); + DEBUG_LOG(Log::HLE, "sceUsbGetState: 0x%x", state); return state; } static int sceUsbActivate(u32 pid) { - INFO_LOG(HLE, "sceUsbActivate(%i)", pid); + INFO_LOG(Log::HLE, "sceUsbActivate(%i)", pid); usbActivated = true; UsbUpdateState(); return 0; } static int sceUsbDeactivate(u32 pid) { - INFO_LOG(HLE, "sceUsbDeactivate(%i)", pid); + INFO_LOG(Log::HLE, "sceUsbDeactivate(%i)", pid); usbActivated = false; UsbUpdateState(); return 0; @@ -190,12 +190,12 @@ static int sceUsbWaitState(int state, u32 waitMode, u32 timeoutPtr) { hleEatCycles(10000); if (waitMode >= 2) - return hleLogError(HLE, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode"); + return hleLogError(Log::HLE, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode"); if (state == 0) - return hleLogError(HLE, SCE_KERNEL_ERROR_EVF_ILPAT, "bad state"); + return hleLogError(Log::HLE, SCE_KERNEL_ERROR_EVF_ILPAT, "bad state"); if (UsbMatchState(state, waitMode)) { - return hleLogSuccessX(HLE, UsbCurrentState()); + return hleLogSuccessX(Log::HLE, UsbCurrentState()); } // We'll have to wait as long as it takes. Cleanup first, just in case. @@ -204,16 +204,16 @@ static int sceUsbWaitState(int state, u32 waitMode, u32 timeoutPtr) { UsbSetTimeout(PSPPointer::Create(timeoutPtr)); __KernelWaitCurThread(WAITTYPE_USB, state, waitMode, timeoutPtr, false, "usb state waited"); - return hleLogSuccessI(HLE, 0, "waiting"); + return hleLogSuccessI(Log::HLE, 0, "waiting"); } static int sceUsbWaitStateCB(int state, u32 waitMode, u32 timeoutPtr) { - ERROR_LOG_REPORT(HLE, "UNIMPL sceUsbWaitStateCB(%i, %i, %08x)", state, waitMode, timeoutPtr); + ERROR_LOG_REPORT(Log::HLE, "UNIMPL sceUsbWaitStateCB(%i, %i, %08x)", state, waitMode, timeoutPtr); return 0; } static int sceUsbstorBootSetCapacity(u32 capacity) { - return hleReportError(HLE, 0, "unimplemented"); + return hleReportError(Log::HLE, 0, "unimplemented"); } const HLEFunction sceUsb[] = diff --git a/Core/HLE/sceUsbAcc.cpp b/Core/HLE/sceUsbAcc.cpp index 93d6add3cb..d2b83ca67c 100644 --- a/Core/HLE/sceUsbAcc.cpp +++ b/Core/HLE/sceUsbAcc.cpp @@ -25,12 +25,12 @@ // we don't have to deal with physical Usb connection, so let's just always pass static int sceUsbAccGetAuthStat() { - INFO_LOG(HLE, "UNIMPL sceUsbAccGetAuthStat"); + INFO_LOG(Log::HLE, "UNIMPL sceUsbAccGetAuthStat"); return 0; } static int sceUsbAccGetInfo(u32 addr) { - INFO_LOG(HLE, "UNIMPL sceUsbAccGetInfo"); + INFO_LOG(Log::HLE, "UNIMPL sceUsbAccGetInfo"); return 0; } diff --git a/Core/HLE/sceUsbCam.cpp b/Core/HLE/sceUsbCam.cpp index 512bcfe15d..1deed656c0 100644 --- a/Core/HLE/sceUsbCam.cpp +++ b/Core/HLE/sceUsbCam.cpp @@ -119,36 +119,36 @@ static int sceUsbCamSetupMic(u32 paramAddr, u32 workareaAddr, int wasize) { config->micParam = *param; param.NotifyRead("UsbCamSetupMic"); } - return hleLogSuccessInfoI(SCEMISC, 0); + return hleLogSuccessInfoI(Log::sceMisc, 0); } static int sceUsbCamStartMic() { - INFO_LOG(HLE, "UNIMPL sceUsbCamStartMic"); + INFO_LOG(Log::HLE, "UNIMPL sceUsbCamStartMic"); return 0; } static int sceUsbCamStopMic() { - INFO_LOG(HLE, "UNIMPL sceUsbCamStopMic"); + INFO_LOG(Log::HLE, "UNIMPL sceUsbCamStopMic"); return 0; } static int sceUsbCamReadMicBlocking(u32 bufAddr, u32 size) { if (!Memory::IsValidAddress(bufAddr)) { - ERROR_LOG(HLE,"sceUsbCamReadMicBlocking(%08x, %d): invalid addresses", bufAddr, size); + ERROR_LOG(Log::HLE,"sceUsbCamReadMicBlocking(%08x, %d): invalid addresses", bufAddr, size); return -1; } - INFO_LOG(HLE, "sceUsbCamReadMicBlocking: size: %d", size); + INFO_LOG(Log::HLE, "sceUsbCamReadMicBlocking: size: %d", size); return __MicInput(size >> 1, config->micParam.frequency, bufAddr, CAMERAMIC); } static int sceUsbCamReadMic(u32 bufAddr, u32 size) { if (!Memory::IsValidAddress(bufAddr)) { - ERROR_LOG(HLE, "sceUsbCamReadMic(%08x, %d): invalid addresses", bufAddr, size); + ERROR_LOG(Log::HLE, "sceUsbCamReadMic(%08x, %d): invalid addresses", bufAddr, size); return -1; } - INFO_LOG(HLE, "sceUsbCamReadMic: size: %d", size); + INFO_LOG(Log::HLE, "sceUsbCamReadMic: size: %d", size); return __MicInput(size >> 1, config->micParam.frequency, bufAddr, CAMERAMIC, false); } @@ -222,12 +222,12 @@ static int sceUsbCamReadVideoFrame(u32 bufAddr, u32 size) { } static int sceUsbCamPollReadVideoFrameEnd() { - VERBOSE_LOG(HLE, "UNIMPL sceUsbCamPollReadVideoFrameEnd: %d", nextVideoFrame); + VERBOSE_LOG(Log::HLE, "UNIMPL sceUsbCamPollReadVideoFrameEnd: %d", nextVideoFrame); return nextVideoFrame; } static int sceUsbCamSetupStill(u32 paramAddr) { - INFO_LOG(HLE, "UNIMPL sceUsbCamSetupStill"); + INFO_LOG(Log::HLE, "UNIMPL sceUsbCamSetupStill"); auto param = PSPPointer::Create(paramAddr); if (param.IsValid()) { config->stillParam = *param; @@ -238,7 +238,7 @@ static int sceUsbCamSetupStill(u32 paramAddr) { } static int sceUsbCamSetupStillEx(u32 paramAddr) { - INFO_LOG(HLE, "UNIMPL sceUsbCamSetupStillEx"); + INFO_LOG(Log::HLE, "UNIMPL sceUsbCamSetupStillEx"); auto param = PSPPointer::Create(paramAddr); if (param.IsValid()) { config->stillExParam = *param; @@ -249,17 +249,17 @@ static int sceUsbCamSetupStillEx(u32 paramAddr) { } static int sceUsbCamAutoImageReverseSW(int on) { - INFO_LOG(HLE, "UNIMPL sceUsbCamAutoImageReverseSW: %d", on); + INFO_LOG(Log::HLE, "UNIMPL sceUsbCamAutoImageReverseSW: %d", on); return 0; } static int sceUsbCamGetLensDirection() { - INFO_LOG(HLE, "UNIMPL sceUsbCamGetLensDirection"); + INFO_LOG(Log::HLE, "UNIMPL sceUsbCamGetLensDirection"); return 0; } static int sceUsbCamSetReverseMode(int reverseflags) { - INFO_LOG(HLE, "UNIMPL sceUsbCamSetReverseMode %d", reverseflags); + INFO_LOG(Log::HLE, "UNIMPL sceUsbCamSetReverseMode %d", reverseflags); return 0; } @@ -345,7 +345,7 @@ std::vector Camera::getDeviceList() { int Camera::startCapture() { int width, height; getCameraResolution(config->type, &width, &height); - INFO_LOG(HLE, "%s resolution: %dx%d", __FUNCTION__, width, height); + INFO_LOG(Log::HLE, "%s resolution: %dx%d", __FUNCTION__, width, height); config->mode = Camera::Mode::Video; #ifdef HAVE_WIN32_CAMERA @@ -365,13 +365,13 @@ int Camera::startCapture() { #elif PPSSPP_PLATFORM(LINUX) __v4l_startCapture(width, height); #else - ERROR_LOG(HLE, "%s not implemented", __FUNCTION__); + ERROR_LOG(Log::HLE, "%s not implemented", __FUNCTION__); #endif return 0; } int Camera::stopCapture() { - INFO_LOG(HLE, "%s", __FUNCTION__); + INFO_LOG(Log::HLE, "%s", __FUNCTION__); #ifdef HAVE_WIN32_CAMERA if (winCamera) { winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::STOP, nullptr }); @@ -381,7 +381,7 @@ int Camera::stopCapture() { #elif PPSSPP_PLATFORM(LINUX) __v4l_stopCapture(); #else - ERROR_LOG(HLE, "%s not implemented", __FUNCTION__); + ERROR_LOG(Log::HLE, "%s not implemented", __FUNCTION__); #endif config->mode = Camera::Mode::Unused; return 0; @@ -402,7 +402,7 @@ void Camera::pushCameraImage(long long length, unsigned char* image) { memset(videoBuffer, 0, VIDEO_BUFFER_SIZE); if (length > VIDEO_BUFFER_SIZE) { videoBufferLength = 0; - ERROR_LOG(HLE, "pushCameraImage: length error: %lld > %d", length, VIDEO_BUFFER_SIZE); + ERROR_LOG(Log::HLE, "pushCameraImage: length error: %lld > %d", length, VIDEO_BUFFER_SIZE); } else { videoBufferLength = length; memcpy(videoBuffer, image, length); diff --git a/Core/HLE/sceUsbMic.cpp b/Core/HLE/sceUsbMic.cpp index 2d46b5e6a2..78a6b3ee22 100644 --- a/Core/HLE/sceUsbMic.cpp +++ b/Core/HLE/sceUsbMic.cpp @@ -68,7 +68,7 @@ static void __MicBlockingResume(u64 userdata, int cyclesLate) { if (Microphone::isHaveDevice()) { if (Microphone::getReadMicDataLength() >= waitingThread.needSize) { u32 ret = __KernelGetWaitValue(threadID, error); - DEBUG_LOG(HLE, "sceUsbMic: Waking up thread(%d)", (int)waitingThread.threadID); + DEBUG_LOG(Log::HLE, "sceUsbMic: Waking up thread(%d)", (int)waitingThread.threadID); __KernelResumeThreadFromWait(threadID, ret); waitingThreads.erase(waitingThreads.begin() + count); } else { @@ -82,7 +82,7 @@ static void __MicBlockingResume(u64 userdata, int cyclesLate) { } } u32 ret = __KernelGetWaitValue(threadID, error); - DEBUG_LOG(HLE, "sceUsbMic: Waking up thread(%d)", (int)waitingThread.threadID); + DEBUG_LOG(Log::HLE, "sceUsbMic: Waking up thread(%d)", (int)waitingThread.threadID); __KernelResumeThreadFromWait(threadID, ret); waitingThreads.erase(waitingThreads.begin() + count); readMicDataLength += waitingThread.needSize; @@ -260,17 +260,17 @@ u32 QueueBuf::getStartPos() { } static int sceUsbMicPollInputEnd() { - ERROR_LOG(HLE, "UNIMPL sceUsbMicPollInputEnd"); + ERROR_LOG(Log::HLE, "UNIMPL sceUsbMicPollInputEnd"); return 0; } static int sceUsbMicInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) { if (!Memory::IsValidAddress(bufAddr)) { - ERROR_LOG(HLE, "sceUsbMicInputBlocking(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr); + ERROR_LOG(Log::HLE, "sceUsbMicInputBlocking(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr); return -1; } - INFO_LOG(HLE, "sceUsbMicInputBlocking: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); + INFO_LOG(Log::HLE, "sceUsbMicInputBlocking: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); if (maxSamples <= 0 || (maxSamples & 0x3F) != 0) { return SCE_USBMIC_ERROR_INVALID_MAX_SAMPLES; } @@ -283,17 +283,17 @@ static int sceUsbMicInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) { } static int sceUsbMicInputInitEx(u32 paramAddr) { - ERROR_LOG(HLE, "UNIMPL sceUsbMicInputInitEx: %08x", paramAddr); + ERROR_LOG(Log::HLE, "UNIMPL sceUsbMicInputInitEx: %08x", paramAddr); return 0; } static int sceUsbMicInput(u32 maxSamples, u32 sampleRate, u32 bufAddr) { if (!Memory::IsValidAddress(bufAddr)) { - ERROR_LOG(HLE, "sceUsbMicInput(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr); + ERROR_LOG(Log::HLE, "sceUsbMicInput(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr); return -1; } - ERROR_LOG(HLE, "UNTEST sceUsbMicInput: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); + ERROR_LOG(Log::HLE, "UNTEST sceUsbMicInput: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr); if (maxSamples <= 0 || (maxSamples & 0x3F) != 0) { return SCE_USBMIC_ERROR_INVALID_MAX_SAMPLES; } @@ -306,17 +306,17 @@ static int sceUsbMicInput(u32 maxSamples, u32 sampleRate, u32 bufAddr) { } static int sceUsbMicGetInputLength() { int ret = Microphone::getReadMicDataLength() / 2; - ERROR_LOG(HLE, "UNTEST sceUsbMicGetInputLength(ret: %d)", ret); + ERROR_LOG(Log::HLE, "UNTEST sceUsbMicGetInputLength(ret: %d)", ret); return ret; } static int sceUsbMicInputInit(int unknown1, int inputVolume, int unknown2) { - ERROR_LOG(HLE, "UNIMPL sceUsbMicInputInit(unknown1: %d, inputVolume: %d, unknown2: %d)", unknown1, inputVolume, unknown2); + ERROR_LOG(Log::HLE, "UNIMPL sceUsbMicInputInit(unknown1: %d, inputVolume: %d, unknown2: %d)", unknown1, inputVolume, unknown2); return 0; } static int sceUsbMicWaitInputEnd() { - ERROR_LOG(HLE, "UNIMPL sceUsbMicWaitInputEnd"); + ERROR_LOG(Log::HLE, "UNIMPL sceUsbMicWaitInputEnd"); return 0; } @@ -328,7 +328,7 @@ int Microphone::startMic(void *param) { std::vector *micParam = static_cast*>(param); int sampleRate = micParam->at(0); int channels = micParam->at(1); - INFO_LOG(HLE, "microphone_command : sr = %d", sampleRate); + INFO_LOG(Log::HLE, "microphone_command : sr = %d", sampleRate); System_MicrophoneCommand("startRecording:" + std::to_string(sampleRate)); #endif micState = 1; @@ -456,7 +456,7 @@ u32 __MicInput(u32 maxSamples, u32 sampleRate, u32 bufAddr, MICTYPE type, bool b CoreTiming::ScheduleEvent(usToCycles(waitTimeus), eventMicBlockingResume, __KernelGetCurThread()); MicWaitInfo waitInfo = { __KernelGetCurThread(), bufAddr, size, sampleRate }; waitingThreads.push_back(waitInfo); - DEBUG_LOG(HLE, "MicInputBlocking: blocking thread(%d)", (int)__KernelGetCurThread()); + DEBUG_LOG(Log::HLE, "MicInputBlocking: blocking thread(%d)", (int)__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_MICINPUT, 1, size, 0, false, "blocking microphone"); return type == CAMERAMIC ? size : maxSamples; diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 0672de41be..39e547e295 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -156,7 +156,7 @@ static void CleanupDialogThreads(bool force = false) { accessThread = nullptr; accessThreadState = "cleaned up"; } else if (force) { - ERROR_LOG_REPORT(SCEUTILITY, "Utility access thread still running, state: %s, dialog=%d/%d", accessThreadState, (int)currentDialogType, currentDialogActive); + ERROR_LOG_REPORT(Log::sceUtility, "Utility access thread still running, state: %s, dialog=%d/%d", accessThreadState, (int)currentDialogType, currentDialogActive); // Try to force shutdown anyway. accessThread->Terminate(); @@ -402,8 +402,8 @@ static int UtilityInitDialog(int type) { accessThreadFinished = true; accessThreadState = "init finished"; if (dialog) - return hleLogSuccessI(SCEUTILITY, dialog->FinishInit()); - return hleLogError(SCEUTILITY, 0, "invalid dialog type?"); + return hleLogSuccessI(Log::sceUtility, dialog->FinishInit()); + return hleLogError(Log::sceUtility, 0, "invalid dialog type?"); } static int UtilityFinishDialog(int type) { @@ -411,14 +411,14 @@ static int UtilityFinishDialog(int type) { accessThreadFinished = true; accessThreadState = "shutdown finished"; if (dialog) - return hleLogSuccessI(SCEUTILITY, dialog->FinishShutdown()); - return hleLogError(SCEUTILITY, 0, "invalid dialog type?"); + return hleLogSuccessI(Log::sceUtility, dialog->FinishShutdown()); + return hleLogError(Log::sceUtility, 0, "invalid dialog type?"); } static int sceUtilitySavedataInitStart(u32 paramAddr) { if (currentDialogActive && currentDialogType != UtilityDialogType::SAVEDATA) { if (PSP_CoreParameter().compat.flags().YugiohSaveFix) { - WARN_LOG_REPORT(SCEUTILITY, "Yugioh Savedata Correction (state=%d)", lastSaveStateVersion); + WARN_LOG_REPORT(Log::sceUtility, "Yugioh Savedata Correction (state=%d)", lastSaveStateVersion); if (accessThread) { accessThread->Terminate(); delete accessThread; @@ -429,28 +429,28 @@ static int sceUtilitySavedataInitStart(u32 paramAddr) { KernelVolatileMemUnlock(0); } } else { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } } ActivateDialog(UtilityDialogType::SAVEDATA); - return hleLogSuccessX(SCEUTILITY, saveDialog->Init(paramAddr)); + return hleLogSuccessX(Log::sceUtility, saveDialog->Init(paramAddr)); } static int sceUtilitySavedataShutdownStart() { if (currentDialogType != UtilityDialogType::SAVEDATA) - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); DeactivateDialog(); int ret = saveDialog->Shutdown(); hleEatCycles(30000); - return hleLogSuccessX(SCEUTILITY, ret); + return hleLogSuccessX(Log::sceUtility, ret); } static int sceUtilitySavedataGetStatus() { if (currentDialogType != UtilityDialogType::SAVEDATA) { hleEatCycles(200); - return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } int status = saveDialog->GetStatus(); @@ -458,17 +458,17 @@ static int sceUtilitySavedataGetStatus() { CleanupDialogThreads(); if (oldStatus != status) { oldStatus = status; - return hleLogSuccessI(SCEUTILITY, status); + return hleLogSuccessI(Log::sceUtility, status); } - return hleLogSuccessVerboseI(SCEUTILITY, status); + return hleLogSuccessVerboseI(Log::sceUtility, status); } static int sceUtilitySavedataUpdate(int animSpeed) { if (currentDialogType != UtilityDialogType::SAVEDATA) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - int result = hleLogSuccessI(SCEUTILITY, saveDialog->Update(animSpeed)); + int result = hleLogSuccessI(Log::sceUtility, saveDialog->Update(animSpeed)); if (result >= 0) return hleDelayResult(result, "savedata update", 300); return result; @@ -478,11 +478,11 @@ static u32 sceUtilityLoadAvModule(u32 module) { if (module > 7) { - ERROR_LOG_REPORT(SCEUTILITY, "sceUtilityLoadAvModule(%i): invalid module id", module); + ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityLoadAvModule(%i): invalid module id", module); return SCE_ERROR_AV_MODULE_BAD_ID; } - INFO_LOG(SCEUTILITY, "0=sceUtilityLoadAvModule(%i)", module); + INFO_LOG(Log::sceUtility, "0=sceUtilityLoadAvModule(%i)", module); if (module == 0) JpegNotifyLoadStatus(1); return hleDelayResult(0, "utility av module loaded", 25000); @@ -490,7 +490,7 @@ static u32 sceUtilityLoadAvModule(u32 module) static u32 sceUtilityUnloadAvModule(u32 module) { - INFO_LOG(SCEUTILITY,"0=sceUtilityUnloadAvModule(%i)", module); + INFO_LOG(Log::sceUtility,"0=sceUtilityUnloadAvModule(%i)", module); if (module == 0) JpegNotifyLoadStatus(-1); return hleDelayResult(0, "utility av module unloaded", 800); @@ -510,16 +510,16 @@ static const ModuleLoadInfo *__UtilityModuleInfo(int module) { static u32 sceUtilityLoadModule(u32 module) { const ModuleLoadInfo *info = __UtilityModuleInfo(module); if (!info) { - return hleReportError(SCEUTILITY, SCE_ERROR_MODULE_BAD_ID, "invalid module id"); + return hleReportError(Log::sceUtility, SCE_ERROR_MODULE_BAD_ID, "invalid module id"); } if (currentlyLoadedModules.find(module) != currentlyLoadedModules.end()) { - return hleLogError(SCEUTILITY, SCE_ERROR_MODULE_ALREADY_LOADED, "already loaded"); + return hleLogError(Log::sceUtility, SCE_ERROR_MODULE_ALREADY_LOADED, "already loaded"); } // Some games, like Kamen Rider Climax Heroes OOO, require an error if dependencies aren't loaded yet. for (const int *dep = info->dependencies; *dep != 0; ++dep) { if (currentlyLoadedModules.find(*dep) == currentlyLoadedModules.end()) { - u32 result = hleLogError(SCEUTILITY, SCE_KERNEL_ERROR_LIBRARY_NOTFOUND, "dependent module %04x not loaded", *dep); + u32 result = hleLogError(Log::sceUtility, SCE_KERNEL_ERROR_LIBRARY_NOTFOUND, "dependent module %04x not loaded", *dep); return hleDelayResult(result, "utility module load attempt", 25000); } } @@ -538,19 +538,19 @@ static u32 sceUtilityLoadModule(u32 module) { // TODO: Each module has its own timing, technically, but this is a low-end. if (module == 0x3FF) - return hleDelayResult(hleLogSuccessInfoI(SCEUTILITY, 0), "utility module loaded", 130); + return hleDelayResult(hleLogSuccessInfoI(Log::sceUtility, 0), "utility module loaded", 130); else - return hleDelayResult(hleLogSuccessInfoI(SCEUTILITY, 0), "utility module loaded", 25000); + return hleDelayResult(hleLogSuccessInfoI(Log::sceUtility, 0), "utility module loaded", 25000); } static u32 sceUtilityUnloadModule(u32 module) { const ModuleLoadInfo *info = __UtilityModuleInfo(module); if (!info) { - return hleReportError(SCEUTILITY, SCE_ERROR_MODULE_BAD_ID, "invalid module id"); + return hleReportError(Log::sceUtility, SCE_ERROR_MODULE_BAD_ID, "invalid module id"); } if (currentlyLoadedModules.find(module) == currentlyLoadedModules.end()) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_MODULE_NOT_LOADED, "not yet loaded"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_MODULE_NOT_LOADED, "not yet loaded"); } if (currentlyLoadedModules[module] != 0) { userMemory.Free(currentlyLoadedModules[module]); @@ -562,35 +562,35 @@ static u32 sceUtilityUnloadModule(u32 module) { // TODO: Each module has its own timing, technically, but this is a low-end. if (module == 0x3FF) - return hleDelayResult(hleLogSuccessInfoI(SCEUTILITY, 0), "utility module unloaded", 110); + return hleDelayResult(hleLogSuccessInfoI(Log::sceUtility, 0), "utility module unloaded", 110); else - return hleDelayResult(hleLogSuccessInfoI(SCEUTILITY, 0), "utility module unloaded", 400); + return hleDelayResult(hleLogSuccessInfoI(Log::sceUtility, 0), "utility module unloaded", 400); } static int sceUtilityMsgDialogInitStart(u32 paramAddr) { if (currentDialogActive && currentDialogType != UtilityDialogType::MSG) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } ActivateDialog(UtilityDialogType::MSG); - return hleLogSuccessInfoX(SCEUTILITY, msgDialog->Init(paramAddr)); + return hleLogSuccessInfoX(Log::sceUtility, msgDialog->Init(paramAddr)); } static int sceUtilityMsgDialogShutdownStart() { if (currentDialogType != UtilityDialogType::MSG) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } DeactivateDialog(); - return hleLogSuccessX(SCEUTILITY, msgDialog->Shutdown()); + return hleLogSuccessX(Log::sceUtility, msgDialog->Shutdown()); } static int sceUtilityMsgDialogUpdate(int animSpeed) { if (currentDialogType != UtilityDialogType::MSG) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - int ret = hleLogSuccessX(SCEUTILITY, msgDialog->Update(animSpeed)); + int ret = hleLogSuccessX(Log::sceUtility, msgDialog->Update(animSpeed)); if (ret >= 0) return hleDelayResult(ret, "msgdialog update", 800); return ret; @@ -598,118 +598,118 @@ static int sceUtilityMsgDialogUpdate(int animSpeed) { static int sceUtilityMsgDialogGetStatus() { if (currentDialogType != UtilityDialogType::MSG) { - return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } int status = msgDialog->GetStatus(); CleanupDialogThreads(); if (oldStatus != status) { oldStatus = status; - return hleLogSuccessI(SCEUTILITY, status); + return hleLogSuccessI(Log::sceUtility, status); } - return hleLogSuccessVerboseI(SCEUTILITY, status); + return hleLogSuccessVerboseI(Log::sceUtility, status); } static int sceUtilityMsgDialogAbort() { if (currentDialogType != UtilityDialogType::MSG) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - return hleLogSuccessX(SCEUTILITY, msgDialog->Abort()); + return hleLogSuccessX(Log::sceUtility, msgDialog->Abort()); } // On screen keyboard static int sceUtilityOskInitStart(u32 oskPtr) { if (currentDialogActive && currentDialogType != UtilityDialogType::OSK) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } ActivateDialog(UtilityDialogType::OSK); - return hleLogSuccessInfoX(SCEUTILITY, oskDialog->Init(oskPtr)); + return hleLogSuccessInfoX(Log::sceUtility, oskDialog->Init(oskPtr)); } static int sceUtilityOskShutdownStart() { if (currentDialogType != UtilityDialogType::OSK) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } DeactivateDialog(); - return hleLogSuccessX(SCEUTILITY, oskDialog->Shutdown()); + return hleLogSuccessX(Log::sceUtility, oskDialog->Shutdown()); } static int sceUtilityOskUpdate(int animSpeed) { if (currentDialogType != UtilityDialogType::OSK) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } // This is the vblank period, plus a little slack. Needed to fix timing bug in Ghost Recon: Predator. // See issue #12044. hleEatCycles(msToCycles(0.7315 + 0.1)); - return hleLogSuccessX(SCEUTILITY, oskDialog->Update(animSpeed)); + return hleLogSuccessX(Log::sceUtility, oskDialog->Update(animSpeed)); } static int sceUtilityOskGetStatus() { if (currentDialogType != UtilityDialogType::OSK) { - return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } int status = oskDialog->GetStatus(); CleanupDialogThreads(); if (oldStatus != status) { oldStatus = status; - return hleLogSuccessI(SCEUTILITY, status); + return hleLogSuccessI(Log::sceUtility, status); } - return hleLogSuccessVerboseI(SCEUTILITY, status); + return hleLogSuccessVerboseI(Log::sceUtility, status); } static int sceUtilityNetconfInitStart(u32 paramsAddr) { if (currentDialogActive && currentDialogType != UtilityDialogType::NET) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } ActivateDialog(UtilityDialogType::NET); - return hleLogSuccessInfoI(SCEUTILITY, netDialog->Init(paramsAddr)); + return hleLogSuccessInfoI(Log::sceUtility, netDialog->Init(paramsAddr)); } static int sceUtilityNetconfShutdownStart() { if (currentDialogType != UtilityDialogType::NET) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } DeactivateDialog(); - return hleLogSuccessI(SCEUTILITY, netDialog->Shutdown()); + return hleLogSuccessI(Log::sceUtility, netDialog->Shutdown()); } static int sceUtilityNetconfUpdate(int animSpeed) { if (currentDialogType != UtilityDialogType::NET) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - return hleLogSuccessI(SCEUTILITY, netDialog->Update(animSpeed)); + return hleLogSuccessI(Log::sceUtility, netDialog->Update(animSpeed)); } static int sceUtilityNetconfGetStatus() { if (currentDialogType != UtilityDialogType::NET) { // Spam in Danball Senki BOOST. - return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } int status = netDialog->GetStatus(); CleanupDialogThreads(); if (oldStatus != status) { oldStatus = status; - return hleLogSuccessI(SCEUTILITY, status); + return hleLogSuccessI(Log::sceUtility, status); } - return hleLogSuccessVerboseI(SCEUTILITY, status); + return hleLogSuccessVerboseI(Log::sceUtility, status); } static int sceUtilityCheckNetParam(int id) { bool available = (id >= 0 && id <= 24); int ret = available ? 0 : 0X80110601; - DEBUG_LOG(SCEUTILITY, "%08x=sceUtilityCheckNetParam(%d)", ret, id); + DEBUG_LOG(Log::sceUtility, "%08x=sceUtilityCheckNetParam(%d)", ret, id); return ret; } @@ -718,106 +718,106 @@ static int sceUtilityCheckNetParam(int id) //but it requires more investigation static int sceUtilityScreenshotInitStart(u32 paramAddr) { if (currentDialogActive && currentDialogType != UtilityDialogType::SCREENSHOT) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } ActivateDialog(UtilityDialogType::SCREENSHOT); - return hleReportWarning(SCEUTILITY, screenshotDialog->Init(paramAddr)); + return hleReportWarning(Log::sceUtility, screenshotDialog->Init(paramAddr)); } static int sceUtilityScreenshotShutdownStart() { if (currentDialogType != UtilityDialogType::SCREENSHOT) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } DeactivateDialog(); - return hleLogWarning(SCEUTILITY, screenshotDialog->Shutdown()); + return hleLogWarning(Log::sceUtility, screenshotDialog->Shutdown()); } static int sceUtilityScreenshotUpdate(u32 animSpeed) { if (currentDialogType != UtilityDialogType::SCREENSHOT) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - return hleLogWarning(SCEUTILITY, screenshotDialog->Update(animSpeed)); + return hleLogWarning(Log::sceUtility, screenshotDialog->Update(animSpeed)); } static int sceUtilityScreenshotGetStatus() { if (currentDialogType != UtilityDialogType::SCREENSHOT) { - return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } int status = screenshotDialog->GetStatus(); CleanupDialogThreads(); if (oldStatus != status) { oldStatus = status; - return hleLogWarning(SCEUTILITY, status); + return hleLogWarning(Log::sceUtility, status); } - return hleLogSuccessVerboseI(SCEUTILITY, status); + return hleLogSuccessVerboseI(Log::sceUtility, status); } static int sceUtilityScreenshotContStart(u32 paramAddr) { if (currentDialogType != UtilityDialogType::SCREENSHOT) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - return hleLogWarning(SCEUTILITY, screenshotDialog->ContStart()); + return hleLogWarning(Log::sceUtility, screenshotDialog->ContStart()); } static int sceUtilityGamedataInstallInitStart(u32 paramsAddr) { if (currentDialogActive && currentDialogType != UtilityDialogType::GAMEDATAINSTALL) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } ActivateDialog(UtilityDialogType::GAMEDATAINSTALL); int result = gamedataInstallDialog->Init(paramsAddr); if (result < 0) DeactivateDialog(); - return hleLogSuccessInfoX(SCEUTILITY, result); + return hleLogSuccessInfoX(Log::sceUtility, result); } static int sceUtilityGamedataInstallShutdownStart() { if (!currentDialogActive || currentDialogType != UtilityDialogType::GAMEDATAINSTALL) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } DeactivateDialog(); - return hleLogSuccessX(SCEUTILITY, gamedataInstallDialog->Shutdown()); + return hleLogSuccessX(Log::sceUtility, gamedataInstallDialog->Shutdown()); } static int sceUtilityGamedataInstallUpdate(int animSpeed) { if (!currentDialogActive || currentDialogType != UtilityDialogType::GAMEDATAINSTALL) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - return hleLogSuccessX(SCEUTILITY, gamedataInstallDialog->Update(animSpeed)); + return hleLogSuccessX(Log::sceUtility, gamedataInstallDialog->Update(animSpeed)); } static int sceUtilityGamedataInstallGetStatus() { if (currentDialogType != UtilityDialogType::GAMEDATAINSTALL) { // This is called incorrectly all the time by some games. So let's not bother warning. hleEatCycles(200); - return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } int status = gamedataInstallDialog->GetStatus(); CleanupDialogThreads(); - return hleLogSuccessI(SCEUTILITY, status); + return hleLogSuccessI(Log::sceUtility, status); } static int sceUtilityGamedataInstallAbort() { if (!currentDialogActive || currentDialogType != UtilityDialogType::GAMEDATAINSTALL) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } DeactivateDialog(); - return hleLogSuccessX(SCEUTILITY, gamedataInstallDialog->Abort()); + return hleLogSuccessX(Log::sceUtility, gamedataInstallDialog->Abort()); } //TODO: should save to config file static u32 sceUtilitySetSystemParamString(u32 id, u32 strPtr) { - WARN_LOG_REPORT(SCEUTILITY, "sceUtilitySetSystemParamString(%i, %08x)", id, strPtr); + WARN_LOG_REPORT(Log::sceUtility, "sceUtilitySetSystemParamString(%i, %08x)", id, strPtr); return 0; } @@ -827,7 +827,7 @@ static u32 sceUtilityGetSystemParamString(u32 id, u32 destAddr, int destSize) // TODO: What error code? return -1; } - DEBUG_LOG(SCEUTILITY, "sceUtilityGetSystemParamString(%i, %08x, %i)", id, destAddr, destSize); + DEBUG_LOG(Log::sceUtility, "sceUtilityGetSystemParamString(%i, %08x, %i)", id, destAddr, destSize); char *buf = (char *)Memory::GetPointerWriteUnchecked(destAddr); switch (id) { case PSP_SYSTEMPARAM_ID_STRING_NICKNAME: @@ -866,7 +866,6 @@ static u32 sceUtilitySetSystemParamInt(u32 id, u32 value) static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) { - DEBUG_LOG(SCEUTILITY,"sceUtilityGetSystemParamInt(%i, %08x)", id,destaddr); u32 param = 0; switch (id) { case PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL: @@ -917,131 +916,131 @@ static u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr) return PSP_SYSTEMPARAM_RETVAL_FAIL; } + INFO_LOG(Log::sceUtility, "sceUtilityGetSystemParamInt(%i, %08x <- %08x)", id, destaddr, param); Memory::Write_U32(param, destaddr); - return 0; } static u32 sceUtilityLoadNetModule(u32 module) { - DEBUG_LOG(SCEUTILITY,"FAKE: sceUtilityLoadNetModule(%i)", module); + DEBUG_LOG(Log::sceUtility,"FAKE: sceUtilityLoadNetModule(%i)", module); return 0; } static u32 sceUtilityUnloadNetModule(u32 module) { - DEBUG_LOG(SCEUTILITY,"FAKE: sceUtilityUnloadNetModule(%i)", module); + DEBUG_LOG(Log::sceUtility,"FAKE: sceUtilityUnloadNetModule(%i)", module); return 0; } static int sceUtilityNpSigninInitStart(u32 paramsPtr) { if (currentDialogActive && currentDialogType != UtilityDialogType::NPSIGNIN) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } ActivateDialog(UtilityDialogType::NPSIGNIN); - return hleLogSuccessInfoI(SCEUTILITY, npSigninDialog->Init(paramsPtr)); + return hleLogSuccessInfoI(Log::sceUtility, npSigninDialog->Init(paramsPtr)); } static int sceUtilityNpSigninShutdownStart() { if (currentDialogType != UtilityDialogType::NPSIGNIN) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } DeactivateDialog(); - return hleLogSuccessI(SCEUTILITY, npSigninDialog->Shutdown()); + return hleLogSuccessI(Log::sceUtility, npSigninDialog->Shutdown()); } static int sceUtilityNpSigninUpdate(int animSpeed) { if (currentDialogType != UtilityDialogType::NPSIGNIN) { - return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - return hleLogSuccessI(SCEUTILITY, npSigninDialog->Update(animSpeed)); + return hleLogSuccessI(Log::sceUtility, npSigninDialog->Update(animSpeed)); } static int sceUtilityNpSigninGetStatus() { if (currentDialogType != UtilityDialogType::NPSIGNIN) { - return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } int status = npSigninDialog->GetStatus(); CleanupDialogThreads(); if (oldStatus != status) { oldStatus = status; - return hleLogSuccessI(SCEUTILITY, status); + return hleLogSuccessI(Log::sceUtility, status); } - return hleLogSuccessVerboseI(SCEUTILITY, status); + return hleLogSuccessVerboseI(Log::sceUtility, status); } static void sceUtilityInstallInitStart(u32 unknown) { - WARN_LOG_REPORT(SCEUTILITY, "UNIMPL sceUtilityInstallInitStart()"); + WARN_LOG_REPORT(Log::sceUtility, "UNIMPL sceUtilityInstallInitStart()"); } static int sceUtilityStoreCheckoutShutdownStart() { - ERROR_LOG(SCEUTILITY,"UNIMPL sceUtilityStoreCheckoutShutdownStart()"); + ERROR_LOG(Log::sceUtility,"UNIMPL sceUtilityStoreCheckoutShutdownStart()"); return 0; } static int sceUtilityStoreCheckoutInitStart(u32 paramsPtr) { - ERROR_LOG_REPORT(SCEUTILITY,"UNIMPL sceUtilityStoreCheckoutInitStart(%d)", paramsPtr); + ERROR_LOG_REPORT(Log::sceUtility,"UNIMPL sceUtilityStoreCheckoutInitStart(%d)", paramsPtr); return 0; } static int sceUtilityStoreCheckoutUpdate(int drawSpeed) { - ERROR_LOG(SCEUTILITY,"UNIMPL sceUtilityStoreCheckoutUpdate(%d)", drawSpeed); + ERROR_LOG(Log::sceUtility,"UNIMPL sceUtilityStoreCheckoutUpdate(%d)", drawSpeed); return 0; } static int sceUtilityStoreCheckoutGetStatus() { - ERROR_LOG(SCEUTILITY,"UNIMPL sceUtilityStoreCheckoutGetStatus()"); + ERROR_LOG(Log::sceUtility,"UNIMPL sceUtilityStoreCheckoutGetStatus()"); return 0; } static int sceUtilityGameSharingShutdownStart() { if (currentDialogType != UtilityDialogType::GAMESHARING) { - WARN_LOG(SCEUTILITY, "sceUtilityGameSharingShutdownStart(): wrong dialog type"); + WARN_LOG(Log::sceUtility, "sceUtilityGameSharingShutdownStart(): wrong dialog type"); return SCE_ERROR_UTILITY_WRONG_TYPE; } DeactivateDialog(); - ERROR_LOG(SCEUTILITY, "UNIMPL sceUtilityGameSharingShutdownStart()"); + ERROR_LOG(Log::sceUtility, "UNIMPL sceUtilityGameSharingShutdownStart()"); return 0; } static int sceUtilityGameSharingInitStart(u32 paramsPtr) { if (currentDialogActive && currentDialogType != UtilityDialogType::GAMESHARING) { - WARN_LOG(SCEUTILITY, "sceUtilityGameSharingInitStart(%08x)", paramsPtr); + WARN_LOG(Log::sceUtility, "sceUtilityGameSharingInitStart(%08x)", paramsPtr); return SCE_ERROR_UTILITY_WRONG_TYPE; } ActivateDialog(UtilityDialogType::GAMESHARING); - ERROR_LOG_REPORT(SCEUTILITY, "UNIMPL sceUtilityGameSharingInitStart(%08x)", paramsPtr); + ERROR_LOG_REPORT(Log::sceUtility, "UNIMPL sceUtilityGameSharingInitStart(%08x)", paramsPtr); return 0; } static int sceUtilityGameSharingUpdate(int animSpeed) { if (currentDialogType != UtilityDialogType::GAMESHARING) { - WARN_LOG(SCEUTILITY, "sceUtilityGameSharingUpdate(%i): wrong dialog type", animSpeed); + WARN_LOG(Log::sceUtility, "sceUtilityGameSharingUpdate(%i): wrong dialog type", animSpeed); return SCE_ERROR_UTILITY_WRONG_TYPE; } - ERROR_LOG(SCEUTILITY, "UNIMPL sceUtilityGameSharingUpdate(%i)", animSpeed); + ERROR_LOG(Log::sceUtility, "UNIMPL sceUtilityGameSharingUpdate(%i)", animSpeed); return 0; } static int sceUtilityGameSharingGetStatus() { if (currentDialogType != UtilityDialogType::GAMESHARING) { - DEBUG_LOG(SCEUTILITY, "sceUtilityGameSharingGetStatus(): wrong dialog type"); + DEBUG_LOG(Log::sceUtility, "sceUtilityGameSharingGetStatus(): wrong dialog type"); return SCE_ERROR_UTILITY_WRONG_TYPE; } - ERROR_LOG(SCEUTILITY, "UNIMPL sceUtilityGameSharingGetStatus()"); + ERROR_LOG(Log::sceUtility, "UNIMPL sceUtilityGameSharingGetStatus()"); CleanupDialogThreads(); return 0; } @@ -1050,10 +1049,10 @@ static u32 sceUtilityLoadUsbModule(u32 module) { if (module < 1 || module > 5) { - ERROR_LOG(SCEUTILITY, "sceUtilityLoadUsbModule(%i): invalid module id", module); + ERROR_LOG(Log::sceUtility, "sceUtilityLoadUsbModule(%i): invalid module id", module); } - ERROR_LOG_REPORT(SCEUTILITY, "UNIMPL sceUtilityLoadUsbModule(%i)", module); + ERROR_LOG_REPORT(Log::sceUtility, "UNIMPL sceUtilityLoadUsbModule(%i)", module); return 0; } @@ -1061,10 +1060,10 @@ static u32 sceUtilityUnloadUsbModule(u32 module) { if (module < 1 || module > 5) { - ERROR_LOG(SCEUTILITY, "sceUtilityUnloadUsbModule(%i): invalid module id", module); + ERROR_LOG(Log::sceUtility, "sceUtilityUnloadUsbModule(%i): invalid module id", module); } - ERROR_LOG_REPORT(SCEUTILITY, "UNIMPL sceUtilityUnloadUsbModule(%i)", module); + ERROR_LOG_REPORT(Log::sceUtility, "UNIMPL sceUtilityUnloadUsbModule(%i)", module); return 0; } diff --git a/Core/HLE/sceVaudio.cpp b/Core/HLE/sceVaudio.cpp index 7d5819114f..841de68681 100644 --- a/Core/HLE/sceVaudio.cpp +++ b/Core/HLE/sceVaudio.cpp @@ -42,15 +42,15 @@ void __VaudioDoState(PointerWrap &p) { static u32 sceVaudioChReserve(int sampleCount, int freq, int format) { if (vaudioReserved) { - ERROR_LOG(SCEAUDIO, "sceVaudioChReserve(%i, %i, %i) - already reserved", sampleCount, freq, format); + ERROR_LOG(Log::sceAudio, "sceVaudioChReserve(%i, %i, %i) - already reserved", sampleCount, freq, format); return SCE_KERNEL_ERROR_BUSY; } // We still have to check the channel also, which gives a different error. if (chans[PSP_AUDIO_CHANNEL_VAUDIO].reserved) { - ERROR_LOG(SCEAUDIO, "sceVaudioChReserve(%i, %i, %i) - channel already reserved", sampleCount, freq, format); + ERROR_LOG(Log::sceAudio, "sceVaudioChReserve(%i, %i, %i) - channel already reserved", sampleCount, freq, format); return SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED; } - DEBUG_LOG(SCEAUDIO, "sceVaudioChReserve(%i, %i, %i)", sampleCount, freq, format); + DEBUG_LOG(Log::sceAudio, "sceVaudioChReserve(%i, %i, %i)", sampleCount, freq, format); chans[PSP_AUDIO_CHANNEL_VAUDIO].reserved = true; chans[PSP_AUDIO_CHANNEL_VAUDIO].sampleCount = sampleCount; chans[PSP_AUDIO_CHANNEL_VAUDIO].format = format == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO; @@ -62,7 +62,7 @@ static u32 sceVaudioChReserve(int sampleCount, int freq, int format) { } static u32 sceVaudioChRelease() { - DEBUG_LOG(SCEAUDIO, "sceVaudioChRelease(...)"); + DEBUG_LOG(Log::sceAudio, "sceVaudioChRelease(...)"); if (!chans[PSP_AUDIO_CHANNEL_VAUDIO].reserved) { return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; } else { @@ -74,7 +74,7 @@ static u32 sceVaudioChRelease() { } static u32 sceVaudioOutputBlocking(int vol, u32 buffer) { - DEBUG_LOG(SCEAUDIO, "sceVaudioOutputBlocking(%i, %08x)", vol, buffer); + DEBUG_LOG(Log::sceAudio, "sceVaudioOutputBlocking(%i, %08x)", vol, buffer); chans[PSP_AUDIO_CHANNEL_VAUDIO].leftVolume = vol; chans[PSP_AUDIO_CHANNEL_VAUDIO].rightVolume = vol; // TODO: This may be wrong, not sure if's in a different format? @@ -83,12 +83,12 @@ static u32 sceVaudioOutputBlocking(int vol, u32 buffer) { } static u32 sceVaudioSetEffectType(int effectType, int vol) { - ERROR_LOG_REPORT(SCEAUDIO, "UNIMPL sceVaudioSetEffectType(%i, %i)", effectType, vol); + ERROR_LOG_REPORT(Log::sceAudio, "UNIMPL sceVaudioSetEffectType(%i, %i)", effectType, vol); return 0; } static u32 sceVaudioSetAlcMode(int alcMode) { - ERROR_LOG_REPORT(SCEAUDIO, "UNIMPL sceVaudioSetAlcMode(%i)", alcMode); + ERROR_LOG_REPORT(Log::sceAudio, "UNIMPL sceVaudioSetAlcMode(%i)", alcMode); return 0; } diff --git a/Core/HW/AsyncIOManager.cpp b/Core/HW/AsyncIOManager.cpp index 2156d5261a..ee842a0861 100644 --- a/Core/HW/AsyncIOManager.cpp +++ b/Core/HW/AsyncIOManager.cpp @@ -43,7 +43,7 @@ void AsyncIOManager::ScheduleOperation(const AsyncIOEvent &ev) { { std::lock_guard guard(resultsLock_); if (!resultsPending_.insert(ev.handle).second) { - ERROR_LOG_REPORT(SCEIO, "Scheduling operation for file %d while one is pending (type %d)", ev.handle, ev.type); + ERROR_LOG_REPORT(Log::sceIo, "Scheduling operation for file %d while one is pending (type %d)", ev.handle, ev.type); } } ScheduleEvent(ev); @@ -127,7 +127,7 @@ void AsyncIOManager::ProcessEvent(AsyncIOEvent ev) { break; default: - ERROR_LOG_REPORT(SCEIO, "Unsupported IO event type"); + ERROR_LOG_REPORT(Log::sceIo, "Unsupported IO event type"); } } @@ -146,7 +146,7 @@ void AsyncIOManager::Write(u32 handle, const u8 *buf, size_t bytes) { void AsyncIOManager::EventResult(u32 handle, const AsyncIOResult &result) { std::lock_guard guard(resultsLock_); if (results_.find(handle) != results_.end()) { - ERROR_LOG_REPORT(SCEIO, "Overwriting previous result for file action on handle %d", handle); + ERROR_LOG_REPORT(Log::sceIo, "Overwriting previous result for file action on handle %d", handle); } results_[handle] = result; resultsWait_.notify_one(); diff --git a/Core/HW/Atrac3Standalone.cpp b/Core/HW/Atrac3Standalone.cpp new file mode 100644 index 0000000000..4e8f4088b1 --- /dev/null +++ b/Core/HW/Atrac3Standalone.cpp @@ -0,0 +1,153 @@ +#include "SimpleAudioDec.h" +#include "Common/LogReporting.h" +#include "ext/at3_standalone/at3_decoders.h" + +inline int16_t clamp16(float f) { + if (f >= 1.0f) + return 32767; + else if (f <= -1.0f) + return -32767; + else + return (int)(f * 32767); +} + +// Uses our standalone AT3/AT3+ decoder derived from FFMPEG +// Test case for ATRAC3: Mega Man Maverick Hunter X, PSP menu sound +class Atrac3Audio : public AudioDecoder { +public: + Atrac3Audio(PSPAudioType audioType, int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) + : audioType_(audioType), channels_(channels) { + blockAlign_ = (int)blockAlign; + if (audioType == PSP_CODEC_AT3PLUS) { + at3pCtx_ = atrac3p_alloc(channels, &blockAlign_); + if (at3pCtx_) { + codecOpen_ = true; + } else { + ERROR_LOG(Log::ME, "Failed to open atrac3+ context! (channels=%d blockAlign=%d ed=%d)", channels, (int)blockAlign, (int)extraDataSize); + } + } else if (audioType_ == PSP_CODEC_AT3) { + at3Ctx_ = atrac3_alloc(channels, &blockAlign_, extraData, (int)extraDataSize); + if (at3Ctx_) { + codecOpen_ = true; + } else { + ERROR_LOG(Log::ME, "Failed to open atrac3 context! !channels=%d blockAlign=%d ed=%d)", channels, (int)blockAlign, (int)extraDataSize); + } + } + for (int i = 0; i < 2; i++) { + buffers_[i] = new float[4096]; + } + } + ~Atrac3Audio() { + if (at3Ctx_) { + atrac3_free(at3Ctx_); + } + if (at3pCtx_) { + atrac3p_free(at3pCtx_); + } + for (int i = 0; i < 2; i++) { + delete[] buffers_[i]; + } + } + + bool IsOK() const override { + return codecOpen_; + } + + void FlushBuffers() override { + if (at3Ctx_) { + atrac3_flush_buffers(at3Ctx_); + } + if (at3pCtx_) { + atrac3p_flush_buffers(at3pCtx_); + } + } + + bool Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override { + if (!codecOpen_) { + WARN_LOG_N_TIMES(codecNotOpen, 5, Log::ME, "Atrac3Audio:Decode: Codec not open, not decoding"); + if (outSamples) + *outSamples = 0; + if (inbytesConsumed) + *inbytesConsumed = 0; + return false; + } + if (inbytes != blockAlign_ && blockAlign_ != 0) { + WARN_LOG(Log::ME, "Atrac3Audio::Decode: Unexpected block align %d (expected %d). %s", inbytes, blockAlign_, at3pCtx_ ? "Atrac3+" : "Atrac3"); + } + blockAlign_ = inbytes; + // We just call the decode function directly without going through the whole packet machinery. + int result; + int nb_samples = 0; + if (audioType_ == PSP_CODEC_AT3PLUS) { + result = atrac3p_decode_frame(at3pCtx_, buffers_, &nb_samples, inbuf, inbytes); + } else { + result = atrac3_decode_frame(at3Ctx_, buffers_, &nb_samples, inbuf, inbytes); + } + if (result < 0) { + if (outSamples) { + *outSamples = 0; + } + return false; + } + if (inbytesConsumed) { + *inbytesConsumed = result; + } + if (outSamples) { + // Allow capping the output samples by setting *outSamples to non-zero. + if (*outSamples != 0) { + nb_samples = std::min(*outSamples, nb_samples); + } + *outSamples = nb_samples; + } + if (nb_samples > 0) { + if (outSamples) { + *outSamples = nb_samples; + } + if (outbuf) { + _dbg_assert_(outputChannels == 1 || outputChannels == 2); + const float *left = buffers_[0]; + if (outputChannels == 2) { + // Stereo output, standard. + const float *right = channels_ == 2 ? buffers_[1] : buffers_[0]; + for (int i = 0; i < nb_samples; i++) { + outbuf[i * 2] = clamp16(left[i]); + outbuf[i * 2 + 1] = clamp16(right[i]); + } + } else { + // Mono output, just take the left channel. + for (int i = 0; i < nb_samples; i++) { + outbuf[i] = clamp16(left[i]); + } + } + } + } + return true; + } + + void SetChannels(int channels) override { + // Hmm. ignore for now. + } + + PSPAudioType GetAudioType() const override { return audioType_; } + +private: + ATRAC3PContext *at3pCtx_ = nullptr; + ATRAC3Context *at3Ctx_ = nullptr; + + int channels_ = 0; + int blockAlign_ = 0; + + int srcPos_ = 0; + float *buffers_[2]{}; + + bool codecOpen_ = false; + + PSPAudioType audioType_; +}; + +AudioDecoder *CreateAtrac3Audio(int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) { + return new Atrac3Audio(PSP_CODEC_AT3, channels, blockAlign, extraData, extraDataSize); +} +AudioDecoder *CreateAtrac3PlusAudio(int channels, size_t blockAlign) { + return new Atrac3Audio(PSP_CODEC_AT3PLUS, channels, blockAlign, nullptr, 0); +} diff --git a/Core/HW/Atrac3Standalone.h b/Core/HW/Atrac3Standalone.h new file mode 100644 index 0000000000..a86fae1729 --- /dev/null +++ b/Core/HW/Atrac3Standalone.h @@ -0,0 +1,6 @@ +#pragma once + +#include "SimpleAudioDec.h" + +AudioDecoder *CreateAtrac3Audio(int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize); +AudioDecoder *CreateAtrac3PlusAudio(int channels, size_t blockAlign); diff --git a/Core/HW/Camera.cpp b/Core/HW/Camera.cpp index 9cf8138e21..7c542284c6 100644 --- a/Core/HW/Camera.cpp +++ b/Core/HW/Camera.cpp @@ -144,7 +144,7 @@ bool MyViewfinder::present(const QVideoFrame &frame) { int __qt_startCapture(int width, int height) { if (qt_camera != nullptr) { - ERROR_LOG(HLE, "camera already started"); + ERROR_LOG(Log::HLE, "camera already started"); return -1; } @@ -155,7 +155,7 @@ int __qt_startCapture(int width, int height) { if (availableCameras.size() < 1) { delete qt_camera; qt_camera = nullptr; - ERROR_LOG(HLE, "no camera found"); + ERROR_LOG(Log::HLE, "no camera found"); return -1; } for (const QCameraInfo &cameraInfo : availableCameras) { @@ -166,7 +166,7 @@ int __qt_startCapture(int width, int height) { if (qt_camera == nullptr) { qt_camera = new QCamera(); if (qt_camera == nullptr) { - ERROR_LOG(HLE, "cannot open camera"); + ERROR_LOG(Log::HLE, "cannot open camera"); return -1; } } @@ -213,12 +213,12 @@ std::vector __v4l_getDeviceList() { } int fd = -1; if((fd = open(path, O_RDONLY)) < 0) { - ERROR_LOG(HLE, "Cannot open '%s'; errno=%d(%s)", path, errno, strerror(errno)); + ERROR_LOG(Log::HLE, "Cannot open '%s'; errno=%d(%s)", path, errno, strerror(errno)); continue; } struct v4l2_capability video_cap; if(ioctl(fd, VIDIOC_QUERYCAP, &video_cap) < 0) { - ERROR_LOG(HLE, "VIDIOC_QUERYCAP"); + ERROR_LOG(Log::HLE, "VIDIOC_QUERYCAP"); goto cont; } else { char device[256]; @@ -243,7 +243,7 @@ void *v4l_loop(void *data) { buf.memory = V4L2_MEMORY_MMAP; if (ioctl(v4l_fd, VIDIOC_DQBUF, &buf) == -1) { - ERROR_LOG(HLE, "VIDIOC_DQBUF; errno=%d(%s)", errno, strerror(errno)); + ERROR_LOG(Log::HLE, "VIDIOC_DQBUF; errno=%d(%s)", errno, strerror(errno)); switch (errno) { case EAGAIN: continue; @@ -279,7 +279,7 @@ void *v4l_loop(void *data) { buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) { - ERROR_LOG(HLE, "VIDIOC_QBUF"); + ERROR_LOG(Log::HLE, "VIDIOC_QBUF"); return nullptr; } } @@ -301,22 +301,22 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { snprintf(dev_name, sizeof(dev_name), "/dev/video%d", dev_index); if ((v4l_fd = open(dev_name, O_RDWR)) == -1) { - ERROR_LOG(HLE, "Cannot open '%s'; errno=%d(%s)", dev_name, errno, strerror(errno)); + ERROR_LOG(Log::HLE, "Cannot open '%s'; errno=%d(%s)", dev_name, errno, strerror(errno)); return -1; } struct v4l2_capability cap; memset(&cap, 0, sizeof(cap)); if (ioctl(v4l_fd, VIDIOC_QUERYCAP, &cap) == -1) { - ERROR_LOG(HLE, "VIDIOC_QUERYCAP"); + ERROR_LOG(Log::HLE, "VIDIOC_QUERYCAP"); return -1; } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { - ERROR_LOG(HLE, "V4L2_CAP_VIDEO_CAPTURE"); + ERROR_LOG(Log::HLE, "V4L2_CAP_VIDEO_CAPTURE"); return -1; } if (!(cap.capabilities & V4L2_CAP_STREAMING)) { - ERROR_LOG(HLE, "V4L2_CAP_STREAMING"); + ERROR_LOG(Log::HLE, "V4L2_CAP_STREAMING"); return -1; } @@ -331,19 +331,19 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; while (ioctl(v4l_fd, VIDIOC_ENUM_FMT, &desc) == 0) { desc.index++; - INFO_LOG(HLE, "V4L2: pixel format supported: %s", desc.description); + INFO_LOG(Log::HLE, "V4L2: pixel format supported: %s", desc.description); if (fmt.fmt.pix.pixelformat != 0) { continue; } else if (desc.pixelformat == V4L2_PIX_FMT_YUYV || desc.pixelformat == V4L2_PIX_FMT_JPEG || desc.pixelformat == V4L2_PIX_FMT_MJPEG) { - INFO_LOG(HLE, "V4L2: %s selected", desc.description); + INFO_LOG(Log::HLE, "V4L2: %s selected", desc.description); fmt.fmt.pix.pixelformat = desc.pixelformat; v4l_format = desc.pixelformat; } } if (fmt.fmt.pix.pixelformat == 0) { - ERROR_LOG(HLE, "V4L2: No supported format found"); + ERROR_LOG(Log::HLE, "V4L2: No supported format found"); return -1; } @@ -356,7 +356,7 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { while (ioctl(v4l_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) { frmsize.index++; if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) { - INFO_LOG(HLE, "V4L2: frame size supported: %dx%d", frmsize.discrete.width, frmsize.discrete.height); + INFO_LOG(Log::HLE, "V4L2: frame size supported: %dx%d", frmsize.discrete.width, frmsize.discrete.height); bool matchesIdeal = frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height; bool zeroPix = fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0; bool pixLarger = frmsize.discrete.width < fmt.fmt.pix.width && frmsize.discrete.height < fmt.fmt.pix.height; @@ -371,16 +371,16 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { fmt.fmt.pix.width = ideal_width; fmt.fmt.pix.height = ideal_height; } - INFO_LOG(HLE, "V4L2: asking for %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height); + INFO_LOG(Log::HLE, "V4L2: asking for %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height); if (ioctl(v4l_fd, VIDIOC_S_FMT, &fmt) == -1) { - ERROR_LOG(HLE, "VIDIOC_S_FMT"); + ERROR_LOG(Log::HLE, "VIDIOC_S_FMT"); return -1; } v4l_hw_width = fmt.fmt.pix.width; v4l_hw_height = fmt.fmt.pix.height; - INFO_LOG(HLE, "V4L2: will receive %dx%d", v4l_hw_width, v4l_hw_height); + INFO_LOG(Log::HLE, "V4L2: will receive %dx%d", v4l_hw_width, v4l_hw_height); v4l_height_fixed_aspect = v4l_hw_width * ideal_height / ideal_width; - INFO_LOG(HLE, "V4L2: will use %dx%d", v4l_hw_width, v4l_height_fixed_aspect); + INFO_LOG(Log::HLE, "V4L2: will use %dx%d", v4l_hw_width, v4l_height_fixed_aspect); struct v4l2_requestbuffers req; memset(&req, 0, sizeof(req)); @@ -388,11 +388,11 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(v4l_fd, VIDIOC_REQBUFS, &req) == -1) { - ERROR_LOG(HLE, "VIDIOC_REQBUFS"); + ERROR_LOG(Log::HLE, "VIDIOC_REQBUFS"); return -1; } v4l_buffer_count = req.count; - INFO_LOG(HLE, "V4L2: buffer count: %d", v4l_buffer_count); + INFO_LOG(Log::HLE, "V4L2: buffer count: %d", v4l_buffer_count); v4l_buffers = (v4l_buf_t*) calloc(v4l_buffer_count, sizeof(v4l_buf_t)); for (int buf_id = 0; buf_id < v4l_buffer_count; buf_id++) { @@ -402,7 +402,7 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { buf.memory = V4L2_MEMORY_MMAP; buf.index = buf_id; if (ioctl(v4l_fd, VIDIOC_QUERYBUF, &buf) == -1) { - ERROR_LOG(HLE, "VIDIOC_QUERYBUF"); + ERROR_LOG(Log::HLE, "VIDIOC_QUERYBUF"); return -1; } @@ -413,7 +413,7 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { MAP_SHARED, v4l_fd, buf.m.offset); if (v4l_buffers[buf_id].start == MAP_FAILED) { - ERROR_LOG(HLE, "MAP_FAILED"); + ERROR_LOG(Log::HLE, "MAP_FAILED"); return -1; } @@ -422,14 +422,14 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { buf.memory = V4L2_MEMORY_MMAP; buf.index = buf_id; if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) { - ERROR_LOG(HLE, "VIDIOC_QBUF"); + ERROR_LOG(Log::HLE, "VIDIOC_QBUF"); return -1; } } enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(v4l_fd, VIDIOC_STREAMON, &type) == -1) { - ERROR_LOG(HLE, "VIDIOC_STREAMON"); + ERROR_LOG(Log::HLE, "VIDIOC_STREAMON"); return -1; } @@ -446,19 +446,19 @@ int __v4l_stopCapture() { } if (ioctl(v4l_fd, VIDIOC_STREAMOFF, &type) == -1) { - ERROR_LOG(HLE, "VIDIOC_STREAMOFF"); + ERROR_LOG(Log::HLE, "VIDIOC_STREAMOFF"); goto exit; } for (int buf_id = 0; buf_id < v4l_buffer_count; buf_id++) { if (munmap(v4l_buffers[buf_id].start, v4l_buffers[buf_id].length) == -1) { - ERROR_LOG(HLE, "munmap"); + ERROR_LOG(Log::HLE, "munmap"); goto exit; } } if (close(v4l_fd) == -1) { - ERROR_LOG(HLE, "close"); + ERROR_LOG(Log::HLE, "close"); goto exit; } diff --git a/Core/HW/Display.cpp b/Core/HW/Display.cpp index 0759d8a9ee..146aaf8cf2 100644 --- a/Core/HW/Display.cpp +++ b/Core/HW/Display.cpp @@ -78,7 +78,7 @@ static void CalculateFPS() { actualFps = (float)(actualFlips - lastActualFlips); fps = frames / (now - lastFpsTime); - flips = (float)(60.0 * (double)(gpuStats.numFlips - lastNumFlips) / frames); + flips = (float)(g_Config.iDisplayRefreshRate * (double)(gpuStats.numFlips - lastNumFlips) / frames); lastFpsFrame = numVBlanks; lastNumFlips = gpuStats.numFlips; diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 7e8b37d4dc..8da752aed7 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -18,6 +18,7 @@ #include "Common/Serialize/SerializeFuncs.h" #include "Common/Math/CrossSIMD.h" #include "Core/Config.h" +#include "Core/Core.h" #include "Core/Debugger/MemBlockInfo.h" #include "Core/HW/MediaEngine.h" #include "Core/MemMap.h" @@ -71,7 +72,7 @@ static AVPixelFormat getSwsFormat(int pspFormat) case GE_CMODE_32BIT_ABGR8888: return AV_PIX_FMT_RGBA; default: - ERROR_LOG(ME, "Unknown pixel format"); + ERROR_LOG(Log::ME, "Unknown pixel format"); return (AVPixelFormat)0; } } @@ -96,11 +97,11 @@ void ffmpeg_logger(void *, int level, const char *format, va_list va_args) { // Let's color the log line appropriately. if (level <= AV_LOG_PANIC) { - ERROR_LOG(ME, "FF: %s", tmp); + ERROR_LOG(Log::ME, "FF: %s", tmp); } else if (level >= AV_LOG_VERBOSE) { - DEBUG_LOG(ME, "FF: %s", tmp); + DEBUG_LOG(Log::ME, "FF: %s", tmp); } else { - INFO_LOG(ME, "FF: %s", tmp); + INFO_LOG(Log::ME, "FF: %s", tmp); } } @@ -128,7 +129,7 @@ static int getPixelFormatBytes(int pspFormat) return 4; default: - ERROR_LOG(ME, "Unknown pixel format"); + ERROR_LOG(Log::ME, "Unknown pixel format"); return 4; } } @@ -245,13 +246,13 @@ bool MediaEngine::SetupStreams() { #ifdef USE_FFMPEG const u32 magic = *(u32_le *)&m_mpegheader[0]; if (magic != PSMF_MAGIC) { - WARN_LOG_REPORT(ME, "Could not setup streams, bad magic: %08x", magic); + WARN_LOG_REPORT(Log::ME, "Could not setup streams, bad magic: %08x", magic); return false; } int numStreams = *(u16_be *)&m_mpegheader[0x80]; if (numStreams <= 0 || numStreams > 8) { // Looks crazy. Let's bail out and let FFmpeg handle it. - WARN_LOG_REPORT(ME, "Could not setup streams, unexpected stream count: %d", numStreams); + WARN_LOG_REPORT(Log::ME, "Could not setup streams, unexpected stream count: %d", numStreams); return false; } @@ -303,18 +304,20 @@ bool MediaEngine::openContext(bool keepReadPos) { } av_dict_free(&open_opt); - if (!SetupStreams()) { + bool usedFFMPEGFindStreamInfo = false; + if (!SetupStreams() || PSP_CoreParameter().compat.flags().UseFFMPEGFindStreamInfo) { // Fallback to old behavior. Reads too much and corrupts when game doesn't read fast enough. // SetupStreams sometimes work for newer FFmpeg 3.1+ now, but sometimes framerate is missing. - WARN_LOG_REPORT_ONCE(setupStreams, ME, "Failed to read valid video stream data from header"); + WARN_LOG_REPORT_ONCE(setupStreams, Log::ME, "Failed to read valid video stream data from header"); if (avformat_find_stream_info(m_pFormatCtx, nullptr) < 0) { closeContext(); return false; } + usedFFMPEGFindStreamInfo = true; } if (m_videoStream >= (int)m_pFormatCtx->nb_streams) { - WARN_LOG_REPORT(ME, "Bad video stream %d", m_videoStream); + WARN_LOG_REPORT(Log::ME, "Bad video stream %d", m_videoStream); m_videoStream = -1; } @@ -340,8 +343,13 @@ bool MediaEngine::openContext(bool keepReadPos) { return false; setVideoDim(); - m_audioContext = new SimpleAudio(m_audioType, 44100, 2); + m_audioContext = CreateAudioDecoder((PSPAudioType)m_audioType); m_isVideoEnd = false; + + if (PSP_CoreParameter().compat.flags().UseFFMPEGFindStreamInfo && usedFFMPEGFindStreamInfo) { + m_mpegheaderReadPos++; + av_seek_frame(m_pFormatCtx, m_videoStream, 0, 0); + } #endif // USE_FFMPEG return true; } @@ -523,13 +531,13 @@ bool MediaEngine::setVideoStream(int streamNum, bool force) { #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) AVCodec *pCodec = avcodec_find_decoder(stream->codecpar->codec_id); if (!pCodec) { - WARN_LOG_REPORT(ME, "Could not find decoder for %d", (int)stream->codecpar->codec_id); + WARN_LOG_REPORT(Log::ME, "Could not find decoder for %d", (int)stream->codecpar->codec_id); return false; } AVCodecContext *m_pCodecCtx = avcodec_alloc_context3(pCodec); int paramResult = avcodec_parameters_to_context(m_pCodecCtx, stream->codecpar); if (paramResult < 0) { - WARN_LOG_REPORT(ME, "Failed to prepare context parameters: %08x", paramResult); + WARN_LOG_REPORT(Log::ME, "Failed to prepare context parameters: %08x", paramResult); return false; } #else @@ -841,7 +849,7 @@ int MediaEngine::writeVideoImage(u32 bufferPtr, int frameWidth, int videoPixelMo if (!Memory::IsValidRange(bufferPtr, videoImageSize) || frameWidth > 2048) { // Clearly invalid values. Let's just not. - ERROR_LOG_REPORT(ME, "Ignoring invalid video decode address %08x/%x", bufferPtr, frameWidth); + ERROR_LOG_REPORT(Log::ME, "Ignoring invalid video decode address %08x/%x", bufferPtr, frameWidth); return 0; } @@ -892,7 +900,7 @@ int MediaEngine::writeVideoImage(u32 bufferPtr, int frameWidth, int videoPixelMo break; default: - ERROR_LOG_REPORT(ME, "Unsupported video pixel format %d", videoPixelMode); + ERROR_LOG_REPORT(Log::ME, "Unsupported video pixel format %d", videoPixelMode); break; } @@ -930,7 +938,7 @@ int MediaEngine::writeVideoImageWithRange(u32 bufferPtr, int frameWidth, int vid if (!Memory::IsValidRange(bufferPtr, videoImageSize) || frameWidth > 2048) { // Clearly invalid values. Let's just not. - ERROR_LOG_REPORT(ME, "Ignoring invalid video decode address %08x/%x", bufferPtr, frameWidth); + ERROR_LOG_REPORT(Log::ME, "Ignoring invalid video decode address %08x/%x", bufferPtr, frameWidth); return 0; } @@ -992,12 +1000,12 @@ int MediaEngine::writeVideoImageWithRange(u32 bufferPtr, int frameWidth, int vid break; default: - ERROR_LOG_REPORT(ME, "Unsupported video pixel format %d", videoPixelMode); + ERROR_LOG_REPORT(Log::ME, "Unsupported video pixel format %d", videoPixelMode); break; } if (swizzle) { - WARN_LOG_REPORT_ONCE(vidswizzle, ME, "Swizzling Video with range"); + WARN_LOG_REPORT_ONCE(vidswizzle, Log::ME, "Swizzling Video with range"); const int bxc = videoLineSize / 16; int byc = (height + 7) / 8; @@ -1054,9 +1062,9 @@ int MediaEngine::getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2) } int MediaEngine::getAudioSamples(u32 bufferPtr) { - u8 *buffer = Memory::GetPointerWriteRange(bufferPtr, 8192); + int16_t *buffer = (int16_t *)Memory::GetPointerWriteRange(bufferPtr, 8192); if (buffer == nullptr) { - ERROR_LOG_REPORT(ME, "Ignoring bad audio decode address %08x during video playback", bufferPtr); + ERROR_LOG_REPORT(Log::ME, "Ignoring bad audio decode address %08x during video playback", bufferPtr); } if (!m_demux) { return 0; @@ -1068,7 +1076,7 @@ int MediaEngine::getAudioSamples(u32 bufferPtr) { if (frameSize == 0) { return 0; } - int outbytes = 0; + int outSamples = 0; if (m_audioContext != nullptr) { if (headerCode1 == 0x24) { @@ -1077,11 +1085,13 @@ int MediaEngine::getAudioSamples(u32 bufferPtr) { m_audioContext->SetChannels(1); } - if (!m_audioContext->Decode(audioFrame, frameSize, buffer, &outbytes)) { - ERROR_LOG(ME, "Audio (%s) decode failed during video playback", GetCodecName(m_audioType)); + int inbytesConsumed = 0; + if (!m_audioContext->Decode(audioFrame, frameSize, &inbytesConsumed, 2, buffer, &outSamples)) { + ERROR_LOG(Log::ME, "Audio (%s) decode failed during video playback", GetCodecName(m_audioType)); } + int outBytes = outSamples * sizeof(int16_t) * 2; - NotifyMemInfo(MemBlockFlags::WRITE, bufferPtr, outbytes, "VideoDecodeAudio"); + NotifyMemInfo(MemBlockFlags::WRITE, bufferPtr, outBytes, "VideoDecodeAudio"); } return 0x2000; diff --git a/Core/HW/MediaEngine.h b/Core/HW/MediaEngine.h index 251916685f..e0a54c1343 100644 --- a/Core/HW/MediaEngine.h +++ b/Core/HW/MediaEngine.h @@ -31,7 +31,7 @@ #include "Core/HW/SimpleAudioDec.h" class PointerWrap; -class SimpleAudio; +class AudioDecoder; #ifdef USE_FFMPEG struct SwsContext; @@ -50,8 +50,7 @@ inline s64 getMpegTimeStamp(const u8 *buf) { bool InitFFmpeg(); #endif -class MediaEngine -{ +class MediaEngine { public: MediaEngine(); ~MediaEngine(); @@ -144,7 +143,7 @@ private: s64 m_lastPts = -1; MpegDemux *m_demux = nullptr; - SimpleAudio *m_audioContext = nullptr; + AudioDecoder *m_audioContext = nullptr; s64 m_audiopts = 0; // used for audio type diff --git a/Core/HW/MpegDemux.cpp b/Core/HW/MpegDemux.cpp index 6dbfa5ec44..ab5dcd5a23 100644 --- a/Core/HW/MpegDemux.cpp +++ b/Core/HW/MpegDemux.cpp @@ -197,7 +197,7 @@ bool MpegDemux::demux(int audioChannel) while (m_index < m_readSize && !needMore) { // Search for start code - int startCode = 0xFF; + u32 startCode = 0xFF; while ((startCode & PACKET_START_CODE_MASK) != PACKET_START_CODE_PREFIX && !isEOF()) { startCode = (startCode << 8) | read8(); } @@ -237,7 +237,7 @@ bool MpegDemux::demux(int audioChannel) break; } case PRIVATE_STREAM_1: { - // Audio stream + // AUDIO stream int length = read16(); // Check for PES header marker. looksValid = (m_buf[m_index] & 0xC0) == 0x80; @@ -270,7 +270,7 @@ bool MpegDemux::demux(int audioChannel) // User data, probably same as queried by sceMpegGetUserdataAu. // Not sure what exactly to do or how much to read. // TODO: implement properly. - WARN_LOG_REPORT_ONCE(mpeguserdata, ME, "MPEG user data found"); + WARN_LOG_REPORT_ONCE(mpeguserdata, Log::ME, "MPEG user data found"); looksValid = true; break; } diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 39ab2564c8..6c54fbda2e 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -79,7 +79,7 @@ void VagDecoder::DecodeBlock(const u8 *&read_pointer) { predict_nr >>= 4; int flags = *readp++; if (flags == 7) { - VERBOSE_LOG(SASMIX, "VAG ending block at %d", curBlock_); + VERBOSE_LOG(Log::SasMix, "VAG ending block at %d", curBlock_); end_ = true; return; } @@ -124,7 +124,7 @@ void VagDecoder::GetSamples(s16 *outSamples, int numSamples) { return; } if (!Memory::IsValidRange(read_, numBlocks_ * 16)) { - WARN_LOG_REPORT(SASMIX, "Bad VAG samples address? %08x / %d", read_, numBlocks_); + WARN_LOG_REPORT(Log::SasMix, "Bad VAG samples address? %08x / %d", read_, numBlocks_); return; } @@ -134,7 +134,7 @@ void VagDecoder::GetSamples(s16 *outSamples, int numSamples) { for (int i = 0; i < numSamples; i++) { if (curSample == 28) { if (loopAtNextBlock_) { - VERBOSE_LOG(SASMIX, "Looping VAG from block %d/%d to %d", curBlock_, numBlocks_, loopStartBlock_); + VERBOSE_LOG(Log::SasMix, "Looping VAG from block %d/%d to %d", curBlock_, numBlocks_, loopStartBlock_); // data_ starts at curBlock = -1. read_ = data_ + 16 * loopStartBlock_ + 16; readp = Memory::GetPointerUnchecked(read_); @@ -192,7 +192,7 @@ void VagDecoder::DoState(PointerWrap &p) { int SasAtrac3::setContext(u32 context) { contextAddr_ = context; - atracID_ = _AtracGetIDByContext(context); + atracID_ = AtracSasGetIDByContext(context); if (!sampleQueue_) sampleQueue_ = new BufferQueue(); sampleQueue_->clear(); @@ -211,7 +211,7 @@ void SasAtrac3::getNextSamples(s16 *outbuf, int wantedSamples) { u32 numSamples = 0; int remains = 0; static s16 buf[0x800]; - _AtracDecodeData(atracID_, (u8*)buf, 0, &numSamples, &finish, &remains); + AtracSasDecodeData(atracID_, (u8*)buf, 0, &numSamples, &finish, &remains); if (numSamples > 0) sampleQueue_->push((u8*)buf, numSamples * sizeof(s16)); else @@ -223,7 +223,7 @@ void SasAtrac3::getNextSamples(s16 *outbuf, int wantedSamples) { int SasAtrac3::addStreamData(u32 bufPtr, u32 addbytes) { if (atracID_ > 0) { - _AtracAddStreamData(atracID_, bufPtr, addbytes); + AtracSasAddStreamData(atracID_, bufPtr, addbytes); } return 0; } @@ -364,7 +364,7 @@ void ADSREnvelope::SetSimpleEnvelope(u32 ADSREnv1, u32 ADSREnv2) { } if (attackRate < 0 || decayRate < 0 || sustainRate < 0 || releaseRate < 0) { - ERROR_LOG_REPORT(SASMIX, "Simple ADSR resulted in invalid rates: %04x, %04x", ADSREnv1, ADSREnv2); + ERROR_LOG_REPORT(Log::SasMix, "Simple ADSR resulted in invalid rates: %04x, %04x", ADSREnv1, ADSREnv2); } } @@ -558,7 +558,7 @@ void SasInstance::MixVoice(SasVoice &voice) { u32 sampleFrac = voice.sampleFrac; int samplesToRead = (sampleFrac + voicePitch * std::max(0, grainSize - delay)) >> PSP_SAS_PITCH_BASE_SHIFT; if (samplesToRead > ARRAY_SIZE(mixTemp_) - 2) { - ERROR_LOG(SCESAS, "Too many samples to read (%d)! This shouldn't happen.", samplesToRead); + ERROR_LOG(Log::sceSas, "Too many samples to read (%d)! This shouldn't happen.", samplesToRead); samplesToRead = ARRAY_SIZE(mixTemp_) - 2; } int readPos = 2; @@ -614,7 +614,7 @@ void SasInstance::MixVoice(SasVoice &voice) { if (voice.HaveSamplesEnded()) voice.envelope.End(); if (voice.envelope.HasEnded()) { - // NOTICE_LOG(SASMIX, "Hit end of envelope"); + // NOTICE_LOG(Log::SasMix, "Hit end of envelope"); voice.playing = false; voice.on = false; } @@ -635,7 +635,7 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) { s16 *outp = (s16 *)Memory::GetPointerWriteRange(outAddr, 4 * grainSize); const s16 *inp = inAddr ? (const s16 *)Memory::GetPointerRange(inAddr, 4 * grainSize) : 0; if (!outp) { - WARN_LOG_REPORT(SCESAS, "Bad SAS Mix output address: %08x, grain=%d", outAddr, grainSize); + WARN_LOG_REPORT(Log::sceSas, "Bad SAS Mix output address: %08x, grain=%d", outAddr, grainSize); } else if (outputMode == PSP_SAS_OUTPUTMODE_MIXED) { // Okay, apply effects processing to the Send buffer. WriteMixedOutput(outp, inp, leftVol, rightVol); @@ -649,7 +649,7 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) { s16 *outpR = outp + grainSize * 1; s16 *outpSendL = outp + grainSize * 2; s16 *outpSendR = outp + grainSize * 3; - WARN_LOG_REPORT_ONCE(sasraw, SASMIX, "sceSasCore: raw outputMode"); + WARN_LOG_REPORT_ONCE(sasraw, Log::SasMix, "sceSasCore: raw outputMode"); for (int i = 0; i < grainSize * 2; i += 2) { *outpL++ = clamp_s16(mixBuffer[i + 0]); *outpR++ = clamp_s16(mixBuffer[i + 1]); @@ -776,7 +776,7 @@ void SasInstance::DoState(PointerWrap &p) { int n = PSP_SAS_VOICES_MAX; Do(p, n); if (n != PSP_SAS_VOICES_MAX) { - ERROR_LOG(SAVESTATE, "Wrong number of SAS voices"); + ERROR_LOG(Log::SaveState, "Wrong number of SAS voices"); return; } DoArray(p, voices, ARRAY_SIZE(voices)); @@ -798,7 +798,7 @@ void SasVoice::KeyOn() { if (Memory::IsValidAddress(vagAddr)) { vag.Start(vagAddr, vagSize, loop); } else { - ERROR_LOG(SASMIX, "Invalid VAG address %08x", vagAddr); + ERROR_LOG(Log::SasMix, "Invalid VAG address %08x", vagAddr); return; } break; diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 80397bf6da..61324125c8 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include "Common/Serialize/SerializeFuncs.h" #include "Core/Config.h" @@ -24,6 +25,9 @@ #include "Core/HW/SimpleAudioDec.h" #include "Core/HW/MediaEngine.h" #include "Core/HW/BufferQueue.h" +#include "Core/HW/Atrac3Standalone.h" + +#include "ext/minimp3/minimp3.h" #ifdef USE_FFMPEG @@ -32,12 +36,110 @@ extern "C" { #include "libswresample/swresample.h" #include "libavutil/samplefmt.h" #include "libavcodec/avcodec.h" -} +#include "libavutil/version.h" + #include "Core/FFMPEGCompat.h" +} + +#else + +extern "C" { + struct AVCodec; + struct AVCodecContext; + struct SwrContext; + struct AVFrame; +} #endif // USE_FFMPEG -int SimpleAudio::GetAudioCodecID(int audioType) { +// AAC decoder candidates: +// * https://github.com/mstorsjo/fdk-aac/tree/master + +// h.264 decoder candidates: +// * https://github.com/meerkat-cv/h264_decoder +// * https://github.com/shengbinmeng/ffmpeg-h264-dec + +// minimp3-based decoder. +class MiniMp3Audio : public AudioDecoder { +public: + MiniMp3Audio() { + mp3dec_init(&mp3_); + } + ~MiniMp3Audio() {} + + bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override { + _dbg_assert_(outputChannels == 2); + + mp3dec_frame_info_t info{}; + int samplesWritten = mp3dec_decode_frame(&mp3_, inbuf, inbytes, (mp3d_sample_t *)outbuf, &info); + *inbytesConsumed = info.frame_bytes; + *outSamples = samplesWritten; + return true; + } + + bool IsOK() const override { return true; } + void SetChannels(int channels) override { + // Hmm. ignore for now. + } + + PSPAudioType GetAudioType() const override { return PSP_CODEC_MP3; } + +private: + // We use the lowest-level API. + mp3dec_t mp3_{}; +}; + +// FFMPEG-based decoder. TODO: Replace with individual codecs. +// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13 +class FFmpegAudioDecoder : public AudioDecoder { +public: + FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2); + ~FFmpegAudioDecoder(); + + bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override; + bool IsOK() const override { +#ifdef USE_FFMPEG + return codec_ != 0; +#else + return 0; +#endif + } + + void SetChannels(int channels) override; + + // These two are only here because of save states. + PSPAudioType GetAudioType() const override { return audioType; } + +private: + bool OpenCodec(int block_align); + + PSPAudioType audioType; + int sample_rate_; + int channels_; + + AVFrame *frame_ = nullptr; + AVCodec *codec_ = nullptr; + AVCodecContext *codecCtx_ = nullptr; + SwrContext *swrCtx_ = nullptr; + + bool codecOpen_ = false; +}; + +AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) { + switch (audioType) { + case PSP_CODEC_MP3: + return new MiniMp3Audio(); + case PSP_CODEC_AT3: + return CreateAtrac3Audio(channels, blockAlign, extraData, extraDataSize); + case PSP_CODEC_AT3PLUS: + return CreateAtrac3PlusAudio(channels, blockAlign); + default: + // Only AAC falls back to FFMPEG now. + return new FFmpegAudioDecoder(audioType, sampleRateHz, channels); + } +} + +static int GetAudioCodecID(int audioType) { #ifdef USE_FFMPEG switch (audioType) { case PSP_CODEC_AAC: @@ -56,14 +158,9 @@ int SimpleAudio::GetAudioCodecID(int audioType) { #endif // USE_FFMPEG } -SimpleAudio::SimpleAudio(int audioType, int sample_rate, int channels) -: ctxPtr(0xFFFFFFFF), audioType(audioType), sample_rate_(sample_rate), channels_(channels), - outSamples(0), srcPos(0), wanted_resample_freq(44100), frame_(0), codec_(0), codecCtx_(0), swrCtx_(0), - codecOpen_(false) { - Init(); -} +FFmpegAudioDecoder::FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels) + : audioType(audioType), sample_rate_(sampleRateHz), channels_(channels) { -void SimpleAudio::Init() { #ifdef USE_FFMPEG #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100) avcodec_register_all(); @@ -75,23 +172,23 @@ void SimpleAudio::Init() { frame_ = av_frame_alloc(); - // Get Audio Codec ctx + // Get AUDIO Codec ctx int audioCodecId = GetAudioCodecID(audioType); if (!audioCodecId) { - ERROR_LOG(ME, "This version of FFMPEG does not support Audio codec type: %08x. Update your submodule.", audioType); + ERROR_LOG(Log::ME, "This version of FFMPEG does not support Audio codec type: %08x. Update your submodule.", audioType); return; } // Find decoder codec_ = avcodec_find_decoder((AVCodecID)audioCodecId); if (!codec_) { // Eh, we shouldn't even have managed to compile. But meh. - ERROR_LOG(ME, "This version of FFMPEG does not support AV_CODEC_ctx for audio (%s). Update your submodule.", GetCodecName(audioType)); + ERROR_LOG(Log::ME, "This version of FFMPEG does not support AV_CODEC_ctx for audio (%s). Update your submodule.", GetCodecName(audioType)); return; } // Allocate codec context codecCtx_ = avcodec_alloc_context3(codec_); if (!codecCtx_) { - ERROR_LOG(ME, "Failed to allocate a codec context"); + ERROR_LOG(Log::ME, "Failed to allocate a codec context"); return; } codecCtx_->channels = channels_; @@ -101,7 +198,7 @@ void SimpleAudio::Init() { #endif // USE_FFMPEG } -bool SimpleAudio::OpenCodec(int block_align) { +bool FFmpegAudioDecoder::OpenCodec(int block_align) { #ifdef USE_FFMPEG // Some versions of FFmpeg require this set. May be set in SetExtraData(), but optional. // When decoding, we decode by packet, so we know the size. @@ -112,7 +209,7 @@ bool SimpleAudio::OpenCodec(int block_align) { AVDictionary *opts = 0; int retval = avcodec_open2(codecCtx_, codec_, &opts); if (retval < 0) { - ERROR_LOG(ME, "Failed to open codec: retval = %i", retval); + ERROR_LOG(Log::ME, "Failed to open codec: retval = %i", retval); } av_dict_free(&opts); codecOpen_ = true; @@ -122,22 +219,7 @@ bool SimpleAudio::OpenCodec(int block_align) { #endif // USE_FFMPEG } -void SimpleAudio::SetExtraData(const u8 *data, int size, int wav_bytes_per_packet) { -#ifdef USE_FFMPEG - if (codecCtx_) { - codecCtx_->extradata = (uint8_t *)av_mallocz(size); - codecCtx_->extradata_size = size; - codecCtx_->block_align = wav_bytes_per_packet; - codecOpen_ = false; - - if (data != nullptr) { - memcpy(codecCtx_->extradata, data, size); - } - } -#endif -} - -void SimpleAudio::SetChannels(int channels) { +void FFmpegAudioDecoder::SetChannels(int channels) { if (channels_ == channels) { // Do nothing, already set. return; @@ -145,7 +227,7 @@ void SimpleAudio::SetChannels(int channels) { #ifdef USE_FFMPEG if (codecOpen_) { - ERROR_LOG(ME, "Codec already open, cannot change channels"); + ERROR_LOG(Log::ME, "Codec already open, cannot change channels"); } else { channels_ = channels; codecCtx_->channels = channels_; @@ -154,7 +236,7 @@ void SimpleAudio::SetChannels(int channels) { #endif } -SimpleAudio::~SimpleAudio() { +FFmpegAudioDecoder::~FFmpegAudioDecoder() { #ifdef USE_FFMPEG swr_free(&swrCtx_); av_frame_free(&frame_); @@ -171,15 +253,8 @@ SimpleAudio::~SimpleAudio() { #endif // USE_FFMPEG } -bool SimpleAudio::IsOK() const { -#ifdef USE_FFMPEG - return codec_ != 0; -#else - return 0; -#endif -} - -bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int *outbytes) { +// Decodes a single input frame. +bool FFmpegAudioDecoder::Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) { #ifdef USE_FFMPEG if (!codecOpen_) { OpenCodec(inbytes); @@ -193,13 +268,17 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int int got_frame = 0; av_frame_unref(frame_); - *outbytes = 0; - srcPos = 0; + if (outSamples) { + *outSamples = 0; + } + if (inbytesConsumed) { + *inbytesConsumed = 0; + } #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) if (inbytes != 0) { int err = avcodec_send_packet(codecCtx_, &packet); if (err < 0) { - ERROR_LOG(ME, "Error sending audio frame to decoder (%d bytes): %d (%08x)", inbytes, err, err); + ERROR_LOG(Log::ME, "Error sending audio frame to decoder (%d bytes): %d (%08x)", inbytes, err, err); return false; } } @@ -221,15 +300,16 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int #endif if (len < 0) { - ERROR_LOG(ME, "Error decoding Audio frame (%i bytes): %i (%08x)", inbytes, len, len); + ERROR_LOG(Log::ME, "Error decoding Audio frame (%i bytes): %i (%08x)", inbytes, len, len); return false; } // get bytes consumed in source - srcPos = len; + *inbytesConsumed = len; if (got_frame) { // Initializing the sample rate convert. We will use it to convert float output into int. + _dbg_assert_(outputChannels == 2); int64_t wanted_channel_layout = AV_CH_LAYOUT_STEREO; // we want stereo output layout int64_t dec_channel_layout = frame_->channel_layout; // decoded channel layout @@ -238,7 +318,7 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int swrCtx_, wanted_channel_layout, AV_SAMPLE_FMT_S16, - wanted_resample_freq, + codecCtx_->sample_rate, dec_channel_layout, codecCtx_->sample_fmt, codecCtx_->sample_rate, @@ -246,7 +326,7 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int NULL); if (!swrCtx_ || swr_init(swrCtx_) < 0) { - ERROR_LOG(ME, "swr_init: Failed to initialize the resampling context"); + ERROR_LOG(Log::ME, "swr_init: Failed to initialize the resampling context"); avcodec_close(codecCtx_); codec_ = 0; return false; @@ -256,17 +336,14 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int // convert audio to AV_SAMPLE_FMT_S16 int swrRet = 0; if (outbuf != nullptr) { - swrRet = swr_convert(swrCtx_, &outbuf, frame_->nb_samples, (const u8 **)frame_->extended_data, frame_->nb_samples); + swrRet = swr_convert(swrCtx_, (uint8_t **)&outbuf, frame_->nb_samples, (const u8 **)frame_->extended_data, frame_->nb_samples); } if (swrRet < 0) { - ERROR_LOG(ME, "swr_convert: Error while converting: %d", swrRet); + ERROR_LOG(Log::ME, "swr_convert: Error while converting: %d", swrRet); return false; } - // output samples per frame, we should *2 since we have two channels - outSamples = swrRet * 2; - - // each sample occupies 2 bytes - *outbytes = outSamples * 2; + // output stereo samples per frame + *outSamples = swrRet; // Save outbuf into pcm audio, you can uncomment this line to save and check the decoded audio into pcm file. // SaveAudio("dump.pcm", outbuf, *outbytes); @@ -279,21 +356,19 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int #endif // USE_FFMPEG } -int SimpleAudio::GetOutSamples() { - return outSamples; -} - -int SimpleAudio::GetSourcePos() { - return srcPos; -} - -void AudioClose(SimpleAudio **ctx) { +void AudioClose(AudioDecoder **ctx) { #ifdef USE_FFMPEG delete *ctx; *ctx = 0; #endif // USE_FFMPEG } +void AudioClose(FFmpegAudioDecoder **ctx) { +#ifdef USE_FFMPEG + delete *ctx; + *ctx = 0; +#endif // USE_FFMPEG +} static const char *const codecNames[4] = { "AT3+", "AT3", "MP3", "AAC", @@ -307,7 +382,7 @@ const char *GetCodecName(int codec) { } }; -bool IsValidCodec(int codec){ +bool IsValidCodec(PSPAudioType codec){ if (codec >= PSP_CODEC_AT3PLUS && codec <= PSP_CODEC_AAC) { return true; } @@ -328,10 +403,6 @@ AuCtx::~AuCtx() { } size_t AuCtx::FindNextMp3Sync() { - if (audioType != PSP_CODEC_MP3) { - return 0; - } - for (size_t i = 0; i < sourcebuff.size() - 2; ++i) { if ((sourcebuff[i] & 0xFF) == 0xFF && (sourcebuff[i + 1] & 0xC0) == 0xC0) { return i; @@ -352,8 +423,14 @@ u32 AuCtx::AuDecode(u32 pcmAddr) { // Decode a single frame in sourcebuff and output into PCMBuf. if (!sourcebuff.empty()) { // FFmpeg doesn't seem to search for a sync for us, so let's do that. - int nextSync = (int)FindNextMp3Sync(); - decoder->Decode(&sourcebuff[nextSync], (int)sourcebuff.size() - nextSync, outbuf, &outpcmbufsize); + int nextSync = 0; + if (decoder->GetAudioType() == PSP_CODEC_MP3) { + nextSync = (int)FindNextMp3Sync(); + } + int inbytesConsumed = 0; + int outSamples = 0; + decoder->Decode(&sourcebuff[nextSync], (int)sourcebuff.size() - nextSync, &inbytesConsumed, 2, (int16_t *)outbuf, &outSamples); + outpcmbufsize = outSamples * 2 * sizeof(int16_t); if (outpcmbufsize == 0) { // Nothing was output, hopefully we're at the end of the stream. @@ -361,9 +438,9 @@ u32 AuCtx::AuDecode(u32 pcmAddr) { sourcebuff.clear(); } else { // Update our total decoded samples, but don't count stereo. - SumDecodedSamples += decoder->GetOutSamples() / 2; + SumDecodedSamples += outSamples; // get consumed source length - int srcPos = decoder->GetSourcePos() + nextSync; + int srcPos = inbytesConsumed + nextSync; // remove the consumed source if (srcPos > 0) sourcebuff.erase(sourcebuff.begin(), sourcebuff.begin() + srcPos); @@ -400,17 +477,6 @@ u32 AuCtx::AuDecode(u32 pcmAddr) { return outpcmbufsize; } -u32 AuCtx::AuGetLoopNum() -{ - return LoopNum; -} - -u32 AuCtx::AuSetLoopNum(int loop) -{ - LoopNum = loop; - return 0; -} - // return 1 to read more data stream, 0 don't read int AuCtx::AuCheckStreamDataNeeded() { // If we would ask for bytes, then some are needed. @@ -421,7 +487,7 @@ int AuCtx::AuCheckStreamDataNeeded() { } int AuCtx::AuStreamBytesNeeded() { - if (audioType == PSP_CODEC_MP3) { + if (decoder->GetAudioType() == PSP_CODEC_MP3) { // The endPos and readPos are not considered, except when you've read to the end. if (readPos >= endPos) return 0; @@ -436,7 +502,7 @@ int AuCtx::AuStreamBytesNeeded() { int AuCtx::AuStreamWorkareaSize() { // Note that this is 31 bytes more than the max layer 3 frame size. - if (audioType == PSP_CODEC_MP3) + if (decoder->GetAudioType() == PSP_CODEC_MP3) return 0x05c0; return 0; } @@ -476,18 +542,18 @@ u32 AuCtx::AuGetInfoToAddStreamData(u32 bufPtr, u32 sizePtr, u32 srcPosPtr) { // we can recharge AuBuf from its beginning if (readsize != 0) { if (Memory::IsValidAddress(bufPtr)) - Memory::Write_U32(AuBuf + offset, bufPtr); + Memory::WriteUnchecked_U32(AuBuf + offset, bufPtr); if (Memory::IsValidAddress(sizePtr)) - Memory::Write_U32(readsize, sizePtr); + Memory::WriteUnchecked_U32(readsize, sizePtr); if (Memory::IsValidAddress(srcPosPtr)) - Memory::Write_U32(readPos, srcPosPtr); + Memory::WriteUnchecked_U32(readPos, srcPosPtr); } else { if (Memory::IsValidAddress(bufPtr)) - Memory::Write_U32(0, bufPtr); + Memory::WriteUnchecked_U32(0, bufPtr); if (Memory::IsValidAddress(sizePtr)) - Memory::Write_U32(0, sizePtr); + Memory::WriteUnchecked_U32(0, sizePtr); if (Memory::IsValidAddress(srcPosPtr)) - Memory::Write_U32(0, srcPosPtr); + Memory::WriteUnchecked_U32(0, srcPosPtr); } // Just for old save states. @@ -533,6 +599,7 @@ void AuCtx::DoState(PointerWrap &p) { Do(p, Channels); Do(p, MaxOutputSample); Do(p, readPos); + int audioType = decoder ? (int)decoder->GetAudioType() : 0; Do(p, audioType); Do(p, BitRate); Do(p, SamplingRate); @@ -552,6 +619,6 @@ void AuCtx::DoState(PointerWrap &p) { } if (p.mode == p.MODE_READ) { - decoder = new SimpleAudio(audioType); + decoder = CreateAudioDecoder((PSPAudioType)audioType); } } diff --git a/Core/HW/SimpleAudioDec.h b/Core/HW/SimpleAudioDec.h index 9bf2427a4a..40d724c565 100644 --- a/Core/HW/SimpleAudioDec.h +++ b/Core/HW/SimpleAudioDec.h @@ -17,88 +17,47 @@ #pragma once -#include - #include "Core/HW/MediaEngine.h" #include "Core/HLE/sceAudio.h" -struct AVFrame; -struct AVCodec; -struct AVCodecContext; -struct SwrContext; - -#ifdef USE_FFMPEG - -extern "C" { -#include "libavutil/version.h" -}; - -#endif - -// Wraps FFMPEG for audio decoding in a nice interface. // Decodes packet by packet - does NOT demux. -// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13 - // audioType -enum { +enum PSPAudioType { PSP_CODEC_AT3PLUS = 0x00001000, PSP_CODEC_AT3 = 0x00001001, PSP_CODEC_MP3 = 0x00001002, PSP_CODEC_AAC = 0x00001003, }; -class SimpleAudio { +class AudioDecoder { public: - SimpleAudio(int audioType, int sample_rate = 44100, int channels = 2); - ~SimpleAudio(); + virtual ~AudioDecoder() {} - bool Decode(const uint8_t* inbuf, int inbytes, uint8_t *outbuf, int *outbytes); - bool IsOK() const; + virtual PSPAudioType GetAudioType() const = 0; - int GetOutSamples(); - int GetSourcePos(); - int GetAudioCodecID(int audioType); // Get audioCodecId from audioType + // inbytesConsumed can include skipping metadata. + // outSamples is in stereo samples. So you have to multiply by 4 for 16-bit stereo audio to get bytes. + // For Atrac3, if *outSamples != 0, it'll cap the number of samples to output. In this case, its value can only shrink. + // TODO: Implement that in the other decoders too, if needed. + virtual bool Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) = 0; + virtual bool IsOK() const = 0; - // Not save stated, only used by UI. Used for ATRAC3 (non+) files. - void SetExtraData(const u8 *data, int size, int wav_bytes_per_packet); - - void SetChannels(int channels); - - // These two are only here because of save states. - int GetAudioType() const { return audioType; } - void SetResampleFrequency(int freq) { wanted_resample_freq = freq; } + virtual void SetChannels(int channels) = 0; + virtual void FlushBuffers() {} // Just metadata. - void SetCtxPtr(u32 ptr) { ctxPtr = ptr; } - u32 GetCtxPtr() const { return ctxPtr; } + void SetCtxPtr(uint32_t ptr) { ctxPtr = ptr; } + uint32_t GetCtxPtr() const { return ctxPtr; } private: - void Init(); - bool OpenCodec(int block_align); - - u32 ctxPtr; - int audioType; - int sample_rate_; - int channels_; - int outSamples; // output samples per frame - int srcPos; // bytes consumed in source during the last decoding - int wanted_resample_freq; // wanted resampling rate/frequency - - AVFrame *frame_; -#if HAVE_LIBAVCODEC_CONST_AVCODEC // USE_FFMPEG is implied - const -#endif - AVCodec *codec_; - AVCodecContext *codecCtx_; - SwrContext *swrCtx_; - - bool codecOpen_; + uint32_t ctxPtr = 0xFFFFFFFF; }; -void AudioClose(SimpleAudio **ctx); +void AudioClose(AudioDecoder **ctx); const char *GetCodecName(int codec); // audioType -bool IsValidCodec(int codec); +bool IsValidCodec(PSPAudioType codec); +AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2, size_t blockAlign = 0, const uint8_t *extraData = nullptr, size_t extraDataSize = 0); class AuCtx { public: @@ -113,18 +72,7 @@ public: int AuStreamWorkareaSize(); u32 AuResetPlayPosition(); u32 AuResetPlayPositionByFrame(int position); - - u32 AuSetLoopNum(int loop); - u32 AuGetLoopNum(); - u32 AuGetInfoToAddStreamData(u32 bufPtr, u32 sizePtr, u32 srcPosPtr); - u32 AuGetMaxOutputSample() const { return MaxOutputSample; } - u32 AuGetSumDecodedSample() const { return SumDecodedSamples; } - int AuGetChannelNum() const { return Channels; } - int AuGetBitRate() const { return BitRate; } - int AuGetSamplingRate() const { return SamplingRate; } - int AuGetVersion() const { return Version; } - int AuGetFrameNum() const { return FrameNum; } void SetReadPos(int pos) { readPos = pos; } int ReadPos() { return readPos; } @@ -146,7 +94,8 @@ public: u32 AuBufSize = 0; u32 PCMBuf = 0; u32 PCMBufSize = 0; - int freq = -1; + + int freq = -1; // used by AAC only? int BitRate = 0; int SamplingRate = -1; int Channels = 0; @@ -159,10 +108,7 @@ public: int FrameNum = 0; // Au decoder - SimpleAudio *decoder = nullptr; - - // Au type - int audioType = 0; + AudioDecoder *decoder = nullptr; private: size_t FindNextMp3Sync(); @@ -171,7 +117,7 @@ private: // buffers informations int AuBufAvailable = 0; // the available buffer of AuBuf to be able to recharge data - int readPos; // read position in audio source file + int readPos = 0; // read position in audio source file int askedReadSize = 0; // the size of data requied to be read from file by the game int nextOutputHalf = 0; }; diff --git a/Core/HW/StereoResampler.cpp b/Core/HW/StereoResampler.cpp index 6abf607eda..56c5bdc52d 100644 --- a/Core/HW/StereoResampler.cpp +++ b/Core/HW/StereoResampler.cpp @@ -73,7 +73,7 @@ StereoResampler::StereoResampler() // If framerate is "close"... if (refresh != 60.0f && refresh > 50.0f && refresh < 70.0f) { int input_sample_rate = (int)(44100 * (refresh / 60.0f)); - INFO_LOG(AUDIO, "StereoResampler: Adjusting target sample rate to %dHz", input_sample_rate); + INFO_LOG(Log::Audio, "StereoResampler: Adjusting target sample rate to %dHz", input_sample_rate); m_input_sample_rate = input_sample_rate; } @@ -165,7 +165,13 @@ void StereoResampler::Clear() { } inline int16_t MixSingleSample(int16_t s1, int16_t s2, uint16_t frac) { - return s1 + (((s2 - s1) * frac) >> 16); + int32_t value = s1 + (((s2 - s1) * frac) >> 16); + if (value < -32767) + return -32767; + else if (value > 32767) + return 32767; + else + return (int16_t)value; } // Executed from sound stream thread, pulling sound out of the buffer. diff --git a/Core/Instance.cpp b/Core/Instance.cpp index b8ecfd8d41..fcb350f82e 100644 --- a/Core/Instance.cpp +++ b/Core/Instance.cpp @@ -66,7 +66,7 @@ static bool UpdateInstanceCounter(void (*callback)(volatile InstanceInfo *)) { if (!buf) { auto err = GetLastError(); - ERROR_LOG(SCENET, "Could not map view of file %s, %08x %s", ID_SHM_NAME, (uint32_t)err, GetStringErrorMsg(err).c_str()); + ERROR_LOG(Log::sceNet, "Could not map view of file %s, %08x %s", ID_SHM_NAME, (uint32_t)err, GetStringErrorMsg(err).c_str()); return false; } @@ -91,7 +91,7 @@ static bool UpdateInstanceCounter(void (*callback)(volatile InstanceInfo *)) { InstanceInfo *buf = (InstanceInfo *)mmap(0, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, hIDMapFile, 0); if (buf == MAP_FAILED) { - ERROR_LOG(SCENET, "mmap(%s) failure.", ID_SHM_NAME); + ERROR_LOG(Log::sceNet, "mmap(%s) failure.", ID_SHM_NAME); return false; } @@ -138,7 +138,7 @@ void InitInstanceCounter() { DWORD lasterr = GetLastError(); if (!hIDMapFile) { - ERROR_LOG(SCENET, "Could not create %s file mapping object, %08x %s", ID_SHM_NAME, (uint32_t)lasterr, GetStringErrorMsg(lasterr).c_str()); + ERROR_LOG(Log::sceNet, "Could not create %s file mapping object, %08x %s", ID_SHM_NAME, (uint32_t)lasterr, GetStringErrorMsg(lasterr).c_str()); PPSSPP_ID = 1; return; } @@ -150,7 +150,7 @@ void InitInstanceCounter() { BUF_SIZE = (BUF_SIZE < sysconf(_SC_PAGE_SIZE)) ? sysconf(_SC_PAGE_SIZE) : BUF_SIZE; if (hIDMapFile < 0 || (ftruncate(hIDMapFile, BUF_SIZE)) == -1) { // Set the size - ERROR_LOG(SCENET, "ftruncate(%s) failure.", ID_SHM_NAME); + ERROR_LOG(Log::sceNet, "ftruncate(%s) failure.", ID_SHM_NAME); PPSSPP_ID = 1; return; } diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index d9af549746..db32c28506 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -76,7 +76,7 @@ void SingleInputMappingFromPspButton(int btn, std::vector *mapping if (!mapping.empty()) { mappings->push_back(mapping.mappings[0]); } else { - WARN_LOG(COMMON, "Encountered empty mapping in multi-mapping for button %d", btn); + WARN_LOG(Log::Common, "Encountered empty mapping in multi-mapping for button %d", btn); } } } @@ -348,20 +348,12 @@ static const KeyMap_IntStrPair key_names[] = { {NKCODE_EXT_MOUSEWHEEL_UP, "MWheelU"}, {NKCODE_EXT_MOUSEWHEEL_DOWN, "MWheelD"}, - - {NKCODE_EXT_MOTION_UP, "MotionUp"}, - {NKCODE_EXT_MOTION_DOWN, "MotionDown"}, - {NKCODE_EXT_MOTION_LEFT, "MotionLeft"}, - {NKCODE_EXT_MOTION_RIGHT, "MotionRight"}, - {NKCODE_EXT_MOTION_FORWARD, "MotionFwd"}, - {NKCODE_EXT_ROTATION_UP, "RotationUp"}, - {NKCODE_EXT_ROTATION_DOWN, "RotationDown"}, - {NKCODE_EXT_ROTATION_LEFT, "RotationLeft"}, - {NKCODE_EXT_ROTATION_RIGHT, "RotationRight"}, - {NKCODE_START_QUESTION, "¿"}, {NKCODE_LEFTBRACE, "{"}, {NKCODE_RIGHTBRACE, "}"}, + + {NKCODE_GUIDE, "Guide"}, + {NKCODE_INFO, "Info"}, }; static const KeyMap_IntStrPair axis_names[] = { @@ -741,6 +733,8 @@ void RestoreDefault() { } else { SetDefaultKeyMap(DEFAULT_MAPPING_ANDROID_PAD, false); } +#elif PPSSPP_PLATFORM(IOS) + SetDefaultKeyMap(DEFAULT_MAPPING_IOS_PAD, false); #else SetDefaultKeyMap(DEFAULT_MAPPING_KEYBOARD, true); SetDefaultKeyMap(DEFAULT_MAPPING_PAD, false); @@ -850,7 +844,7 @@ void AutoConfForPad(const std::string &name) { std::lock_guard guard(g_controllerMapLock); g_controllerMap.clear(); - INFO_LOG(SYSTEM, "Autoconfiguring pad for '%s'", name.c_str()); + INFO_LOG(Log::System, "Autoconfiguring pad for '%s'", name.c_str()); #if PPSSPP_PLATFORM(ANDROID) if (name.find("Xbox") != std::string::npos) { diff --git a/Core/KeyMapDefaults.cpp b/Core/KeyMapDefaults.cpp index 3c08f2c94c..e796bdfe52 100644 --- a/Core/KeyMapDefaults.cpp +++ b/Core/KeyMapDefaults.cpp @@ -275,6 +275,27 @@ static const DefMappingStruct defaultPadMap[] = { {VIRTKEY_PAUSE , NKCODE_BUTTON_L2 }, }; +static const DefMappingStruct defaultPadMapIOS[] = { + {CTRL_CROSS , NKCODE_BUTTON_2}, + {CTRL_CIRCLE , NKCODE_BUTTON_3}, + {CTRL_SQUARE , NKCODE_BUTTON_4}, + {CTRL_TRIANGLE , NKCODE_BUTTON_1}, + {CTRL_UP , NKCODE_DPAD_UP}, + {CTRL_RIGHT , NKCODE_DPAD_RIGHT}, + {CTRL_DOWN , NKCODE_DPAD_DOWN}, + {CTRL_LEFT , NKCODE_DPAD_LEFT}, + {CTRL_START , NKCODE_BUTTON_START}, + {CTRL_SELECT , NKCODE_BUTTON_SELECT}, + {CTRL_LTRIGGER , NKCODE_BUTTON_L1}, + {CTRL_RTRIGGER , NKCODE_BUTTON_R1}, + {VIRTKEY_AXIS_X_MIN, JOYSTICK_AXIS_X, -1}, + {VIRTKEY_AXIS_X_MAX, JOYSTICK_AXIS_X, +1}, + {VIRTKEY_AXIS_Y_MIN, JOYSTICK_AXIS_Y, +1}, + {VIRTKEY_AXIS_Y_MAX, JOYSTICK_AXIS_Y, -1}, + {VIRTKEY_PAUSE , NKCODE_BUTTON_THUMBL }, + {VIRTKEY_FASTFORWARD , JOYSTICK_AXIS_RTRIGGER, +1}, +}; + static const DefMappingStruct defaultOuyaMap[] = { {CTRL_CROSS , NKCODE_BUTTON_A}, {CTRL_CIRCLE , NKCODE_BUTTON_B}, @@ -352,7 +373,7 @@ void SetDefaultKeyMap(DefaultMaps dmap, bool replace) { switch (dmap) { case DEFAULT_MAPPING_KEYBOARD: { - int keyboardLayout = System_GetPropertyInt(SYSPROP_KEYBOARD_LAYOUT); + int keyboardLayout = (int)System_GetPropertyInt(SYSPROP_KEYBOARD_LAYOUT); switch (keyboardLayout) { case KEYBOARD_LAYOUT_QWERTZ: SetDefaultKeyMap(DEVICE_ID_KEYBOARD, defaultQwertzKeyboardKeyMap, ARRAY_SIZE(defaultQwertzKeyboardKeyMap), replace); @@ -382,6 +403,9 @@ void SetDefaultKeyMap(DefaultMaps dmap, bool replace) { case DEFAULT_MAPPING_ANDROID_PAD: SetDefaultKeyMap(DEVICE_ID_PAD_0, defaultPadMapAndroid, ARRAY_SIZE(defaultPadMapAndroid), replace); break; + case DEFAULT_MAPPING_IOS_PAD: + SetDefaultKeyMap(DEVICE_ID_PAD_0, defaultPadMapIOS, ARRAY_SIZE(defaultPadMapIOS), replace); + break; case DEFAULT_MAPPING_OUYA: SetDefaultKeyMap(DEVICE_ID_PAD_0, defaultOuyaMap, ARRAY_SIZE(defaultOuyaMap), replace); break; diff --git a/Core/KeyMapDefaults.h b/Core/KeyMapDefaults.h index 072649bf89..f38f7d7f07 100644 --- a/Core/KeyMapDefaults.h +++ b/Core/KeyMapDefaults.h @@ -6,6 +6,7 @@ enum DefaultMaps { DEFAULT_MAPPING_KEYBOARD, DEFAULT_MAPPING_PAD, DEFAULT_MAPPING_ANDROID_PAD, + DEFAULT_MAPPING_IOS_PAD, DEFAULT_MAPPING_XINPUT, DEFAULT_MAPPING_ANDROID_XBOX, // XBox controller or similar on Android DEFAULT_MAPPING_SHIELD, diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index f15a071397..b7ec039512 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -35,12 +35,6 @@ #include "Core/ELF/PBPReader.h" #include "Core/ELF/ParamSFO.h" -static std::map> factories; - -void RegisterFileLoaderFactory(const std::string &prefix, std::unique_ptr factory) { - factories[prefix] = std::move(factory); -} - FileLoader *ConstructFileLoader(const Path &filename) { if (filename.Type() == PathType::HTTP) { FileLoader *baseLoader = new RetryingFileLoader(new HTTPFileLoader(filename)); @@ -50,12 +44,6 @@ FileLoader *ConstructFileLoader(const Path &filename) { } return new CachingFileLoader(baseLoader); } - - for (auto &iter : factories) { - if (startsWith(filename.ToString(), iter.first)) { - return iter.second->ConstructFileLoader(filename); - } - } return new LocalFileLoader(filename); } @@ -215,7 +203,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin } return IdentifiedFileType::PSP_PBP; } else if (extension == ".pbp") { - ERROR_LOG(LOADER, "A PBP with the wrong magic number?"); + ERROR_LOG(Log::Loader, "A PBP with the wrong magic number?"); return IdentifiedFileType::PSP_PBP; } else if (extension == ".bin") { return IdentifiedFileType::UNKNOWN_BIN; @@ -271,7 +259,7 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { { fileLoader = ResolveFileLoaderTarget(fileLoader); if (fileLoader->Exists()) { - INFO_LOG(LOADER, "File is a PBP in a directory: %s", fileLoader->GetPath().c_str()); + INFO_LOG(Log::Loader, "File is a PBP in a directory: %s", fileLoader->GetPath().c_str()); IdentifiedFileType ebootType = Identify_File(fileLoader, error_string); if (ebootType == IdentifiedFileType::PSP_ISO_NP) { InitMemoryForGameISO(fileLoader); @@ -309,7 +297,7 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { case IdentifiedFileType::PSP_PBP: case IdentifiedFileType::PSP_ELF: { - INFO_LOG(LOADER, "File is an ELF or loose PBP! %s", fileLoader->GetPath().c_str()); + INFO_LOG(Log::Loader, "File is an ELF or loose PBP! %s", fileLoader->GetPath().c_str()); return Load_PSP_ELF_PBP(fileLoader, error_string); } @@ -352,7 +340,7 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { break; case IdentifiedFileType::NORMAL_DIRECTORY: - ERROR_LOG(LOADER, "Just a directory."); + ERROR_LOG(Log::Loader, "Just a directory."); *error_string = "Just a directory."; break; @@ -371,18 +359,18 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) { case IdentifiedFileType::UNKNOWN_ELF: case IdentifiedFileType::UNKNOWN_ISO: case IdentifiedFileType::UNKNOWN: - ERROR_LOG(LOADER, "Unknown file type: %s (%s)", fileLoader->GetPath().c_str(), error_string->c_str()); + ERROR_LOG(Log::Loader, "Unknown file type: %s (%s)", fileLoader->GetPath().c_str(), error_string->c_str()); *error_string = "Unknown file type: " + fileLoader->GetPath().ToString(); break; case IdentifiedFileType::ERROR_IDENTIFYING: *error_string = *error_string + ": " + (fileLoader ? fileLoader->LatestError() : ""); - ERROR_LOG(LOADER, "Error while identifying file: %s", error_string->c_str()); + ERROR_LOG(Log::Loader, "Error while identifying file: %s", error_string->c_str()); break; default: *error_string = StringFromFormat("Unhandled identified file type %d", (int)type); - ERROR_LOG(LOADER, "%s", error_string->c_str()); + ERROR_LOG(Log::Loader, "%s", error_string->c_str()); break; } diff --git a/Core/Loaders.h b/Core/Loaders.h index 3eeb301fc3..7cb0c1938e 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -147,13 +147,6 @@ Path ResolvePBPFile(const Path &filename); IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorString); -class FileLoaderFactory { -public: - virtual ~FileLoaderFactory() {} - virtual FileLoader *ConstructFileLoader(const Path &filename) = 0; -}; -void RegisterFileLoaderFactory(const std::string &prefix, std::unique_ptr factory); - // Can modify the string filename, as it calls IdentifyFile above. bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string); diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index f90dd237ec..2b00b1573a 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -56,7 +56,7 @@ static const bool disasm = false; extern volatile CoreState coreState; void ShowPC(u32 sp) { - ERROR_LOG(JIT, "ShowPC : %08x ArmSP : %08x", currentMIPS->pc, sp); + ERROR_LOG(Log::JIT, "ShowPC : %08x ArmSP : %08x", currentMIPS->pc, sp); // Sleep(1); } @@ -127,7 +127,7 @@ void ArmJit::GenerateFixedCode() { enterDispatcher = AlignCode16(); - DEBUG_LOG(JIT, "Base: %08x", (u32)Memory::base); + DEBUG_LOG(Log::JIT, "Base: %08x", (u32)Memory::base); SetCC(CC_AL); @@ -256,9 +256,9 @@ void ArmJit::GenerateFixedCode() { // Uncomment if you want to see the output... if (disasm) { - INFO_LOG(JIT, "THE DISASM ========================"); + INFO_LOG(Log::JIT, "THE DISASM ========================"); DisassembleArm(start, GetCodePtr() - start); - INFO_LOG(JIT, "END OF THE DISASM ========================"); + INFO_LOG(Log::JIT, "END OF THE DISASM ========================"); } // Don't forget to zap the instruction cache! diff --git a/Core/MIPS/ARM/ArmCompBranch.cpp b/Core/MIPS/ARM/ArmCompBranch.cpp index ee6a96a620..526da54a68 100644 --- a/Core/MIPS/ARM/ArmCompBranch.cpp +++ b/Core/MIPS/ARM/ArmCompBranch.cpp @@ -68,7 +68,7 @@ namespace MIPSComp void ArmJit::BranchRSRTComp(MIPSOpcode op, CCFlags cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -195,7 +195,7 @@ void ArmJit::BranchRSRTComp(MIPSOpcode op, CCFlags cc, bool likely) void ArmJit::BranchRSZeroComp(MIPSOpcode op, CCFlags cc, bool andLink, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -355,7 +355,7 @@ void ArmJit::Comp_RelBranchRI(MIPSOpcode op) void ArmJit::BranchFPFlag(MIPSOpcode op, CCFlags cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -426,7 +426,7 @@ void ArmJit::Comp_FPUBranch(MIPSOpcode op) void ArmJit::BranchVFPUFlag(MIPSOpcode op, CCFlags cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -503,7 +503,7 @@ static void HitInvalidJump(uint32_t dest) { void ArmJit::Comp_Jump(MIPSOpcode op) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } u32 off = TARGET26; @@ -512,7 +512,7 @@ void ArmJit::Comp_Jump(MIPSOpcode op) { // Might be a stubbed address or something? if (!Memory::IsValidAddress(targetAddr) || (targetAddr & 3) != 0) { if (js.nextExit == 0) { - ERROR_LOG_REPORT(JIT, "Jump to invalid address: %08x", targetAddr); + ERROR_LOG_REPORT(Log::JIT, "Jump to invalid address: %08x", targetAddr); } else { js.compiling = false; } @@ -570,7 +570,7 @@ void ArmJit::Comp_Jump(MIPSOpcode op) { void ArmJit::Comp_JumpReg(MIPSOpcode op) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } MIPSGPReg rs = _RS; @@ -650,7 +650,7 @@ void ArmJit::Comp_JumpReg(MIPSOpcode op) void ArmJit::Comp_Syscall(MIPSOpcode op) { if (op.encoding == 0x03FFFFcc) { - WARN_LOG(JIT, "Encountered bad syscall instruction at %08x (%08x)", js.compilerPC, op.encoding); + WARN_LOG(Log::JIT, "Encountered bad syscall instruction at %08x (%08x)", js.compilerPC, op.encoding); } if (!g_Config.bSkipDeadbeefFilling) diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index b843e84cbb..7577ad26cc 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -107,7 +107,7 @@ namespace MIPSComp js.prefixDFlag = JitState::PREFIX_KNOWN_DIRTY; break; default: - ERROR_LOG(CPU, "VPFX - bad regnum %i : data=%08x", regnum, data); + ERROR_LOG(Log::CPU, "VPFX - bad regnum %i : data=%08x", regnum, data); break; } } @@ -142,7 +142,7 @@ namespace MIPSComp // Prefix may say "z, z, z, z" but if this is a pair, we force to x. // TODO: But some ops seem to use const 0 instead? if (regnum >= n) { - WARN_LOG(CPU, "JIT: Invalid VFPU swizzle: %08x : %d / %d at PC = %08x (%s)", prefix, regnum, n, GetCompilerPC(), MIPSDisasmAt(GetCompilerPC()).c_str()); + WARN_LOG(Log::CPU, "JIT: Invalid VFPU swizzle: %08x : %d / %d at PC = %08x (%s)", prefix, regnum, n, GetCompilerPC(), MIPSDisasmAt(GetCompilerPC()).c_str()); regnum = 0; } @@ -1060,7 +1060,7 @@ namespace MIPSComp VDIV(fpr.V(tempregs[i]), S0, fpr.V(sregs[i])); break; default: - ERROR_LOG(JIT, "case missing in vfpu vv2op"); + ERROR_LOG(Log::JIT, "case missing in vfpu vv2op"); DISABLE; break; } @@ -1283,7 +1283,7 @@ namespace MIPSComp } } else { //ERROR - maybe need to make this value too an "interlock" value? - ERROR_LOG(CPU, "mfv - invalid register %i", imm); + ERROR_LOG(Log::CPU, "mfv - invalid register %i", imm); } } break; @@ -2174,7 +2174,7 @@ namespace MIPSComp break; } default: - ERROR_LOG(JIT, "Bad what in vrot"); + ERROR_LOG(Log::JIT, "Bad what in vrot"); break; } } @@ -2211,7 +2211,7 @@ namespace MIPSComp // Pair of vrot. Let's join them. vd2 = MIPS_GET_VD(nextOp); imm2 = (nextOp >> 16) & 0x1f; - // NOTICE_LOG(JIT, "Joint VFPU at %08x", js.blockStart); + // NOTICE_LOG(Log::JIT, "Joint VFPU at %08x", js.blockStart); } u8 sreg; GetVectorRegs(dregs, sz, vd); diff --git a/Core/MIPS/ARM/ArmCompVFPUNEON.cpp b/Core/MIPS/ARM/ArmCompVFPUNEON.cpp index 1f4f783e76..71838d6837 100644 --- a/Core/MIPS/ARM/ArmCompVFPUNEON.cpp +++ b/Core/MIPS/ARM/ArmCompVFPUNEON.cpp @@ -55,7 +55,7 @@ // #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } -#define DISABLE_UNKNOWN_PREFIX { WARN_LOG(JIT, "DISABLE: Unknown Prefix in %s", __FUNCTION__); fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } +#define DISABLE_UNKNOWN_PREFIX { WARN_LOG(Log::JIT, "DISABLE: Unknown Prefix in %s", __FUNCTION__); fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } #define _RS MIPS_GET_RS(op) #define _RT MIPS_GET_RT(op) @@ -182,7 +182,7 @@ void ArmJit::CompNEON_SV(MIPSOpcode op) { case 50: //lv.s // VI(vt) = Memory::Read_U32(addr); { if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset < 0x400 && offset > -0x400) { - INFO_LOG(HLE, "LV.S fastmode!"); + INFO_LOG(Log::HLE, "LV.S fastmode!"); // TODO: Also look forward and combine multiple loads. gpr.MapRegAsPointer(rs); ARMReg ar = fpr.QMapReg(vt, V_Single, MAP_NOINIT | MAP_DIRTY); @@ -194,7 +194,7 @@ void ArmJit::CompNEON_SV(MIPSOpcode op) { } break; } - INFO_LOG(HLE, "LV.S slowmode!"); + INFO_LOG(Log::HLE, "LV.S slowmode!"); // CC might be set by slow path below, so load regs first. ARMReg ar = fpr.QMapReg(vt, V_Single, MAP_DIRTY | MAP_NOINIT); @@ -226,7 +226,7 @@ void ArmJit::CompNEON_SV(MIPSOpcode op) { case 58: //sv.s // Memory::Write_U32(VI(vt), addr); { if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset < 0x400 && offset > -0x400) { - INFO_LOG(HLE, "SV.S fastmode!"); + INFO_LOG(Log::HLE, "SV.S fastmode!"); // TODO: Also look forward and combine multiple stores. gpr.MapRegAsPointer(rs); ARMReg ar = fpr.QMapReg(vt, V_Single, 0); @@ -239,7 +239,7 @@ void ArmJit::CompNEON_SV(MIPSOpcode op) { break; } - INFO_LOG(HLE, "SV.S slowmode!"); + INFO_LOG(Log::HLE, "SV.S slowmode!"); // CC might be set by slow path below, so load regs first. ARMReg ar = fpr.QMapReg(vt, V_Single, 0); if (gpr.IsImm(rs)) { @@ -303,7 +303,7 @@ void ArmJit::CompNEON_SVQ(MIPSOpcode op) { // Detected four consecutive ones! // gpr.MapRegAsPointer(rs); // fpr.QLoad4x4(vts[4], rs, offset); - INFO_LOG(JIT, "Matrix load detected! TODO: optimize"); + INFO_LOG(Log::JIT, "Matrix load detected! TODO: optimize"); // break; } } @@ -368,7 +368,7 @@ void ArmJit::CompNEON_SVQ(MIPSOpcode op) { // Detected four consecutive ones! // gpr.MapRegAsPointer(rs); // fpr.QLoad4x4(vts[4], rs, offset); - INFO_LOG(JIT, "Matrix store detected! TODO: optimize"); + INFO_LOG(Log::JIT, "Matrix store detected! TODO: optimize"); // break; } } @@ -690,7 +690,7 @@ void ArmJit::CompNEON_Mftv(MIPSOpcode op) { } } else { //ERROR - maybe need to make this value too an "interlock" value? - ERROR_LOG(CPU, "mfv - invalid register %i", imm); + ERROR_LOG(Log::CPU, "mfv - invalid register %i", imm); } } break; @@ -869,7 +869,7 @@ void ArmJit::CompNEON_Vmmul(MIPSOpcode op) { bool overlap = GetMatrixOverlap(_VD, _VS, msz) || GetMatrixOverlap(_VD, _VT, msz); if (overlap) { // Later. Fortunately, the VFPU also seems to prohibit overlap for matrix mul. - INFO_LOG(JIT, "Matrix overlap, ignoring."); + INFO_LOG(Log::JIT, "Matrix overlap, ignoring."); DISABLE; } @@ -1036,7 +1036,7 @@ void ArmJit::CompNEON_Vh2f(MIPSOpcode op) { outsize = V_Quad; break; default: - ERROR_LOG(JIT, "Vh2f: Must be pair or quad"); + ERROR_LOG(Log::JIT, "Vh2f: Must be pair or quad"); break; } diff --git a/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp b/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp index 5a6f727456..01fdc40b83 100644 --- a/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp +++ b/Core/MIPS/ARM/ArmCompVFPUNEONUtil.cpp @@ -177,7 +177,7 @@ ARMReg ArmJit::NEONMapPrefixST(int mipsReg, VectorSize sz, u32 prefix, int mapFl } else { // Do some special cases if (regnum[0] == 1 && regnum[1] == 0) { - INFO_LOG(HLE, "PREFIXST: Bottom swap!"); + INFO_LOG(Log::HLE, "PREFIXST: Bottom swap!"); VREV64(I_32, ar, inputAR); regnum[0] = 0; regnum[1] = 1; @@ -193,7 +193,7 @@ ARMReg ArmJit::NEONMapPrefixST(int mipsReg, VectorSize sz, u32 prefix, int mapFl // TODO: Cannot do this permutation yet! if (!match) { - ERROR_LOG(HLE, "PREFIXST: Unsupported permute! %i %i %i %i / %i", regnum[0], regnum[1], regnum[2], regnum[3], n); + ERROR_LOG(Log::HLE, "PREFIXST: Unsupported permute! %i %i %i %i / %i", regnum[0], regnum[1], regnum[2], regnum[3], n); VMOV(ar, inputAR); } } @@ -218,7 +218,7 @@ ARMReg ArmJit::NEONMapPrefixST(int mipsReg, VectorSize sz, u32 prefix, int mapFl } } VMOV(ar, MatchSize(Q0, ar)); - INFO_LOG(HLE, "PREFIXST: Partial ABS %i/%i! Slow fallback generated.", abs_mask, full_mask); + INFO_LOG(Log::HLE, "PREFIXST: Partial ABS %i/%i! Slow fallback generated.", abs_mask, full_mask); } } @@ -240,7 +240,7 @@ ARMReg ArmJit::NEONMapPrefixST(int mipsReg, VectorSize sz, u32 prefix, int mapFl } } VMOV(ar, MatchSize(Q0, ar)); - INFO_LOG(HLE, "PREFIXST: Partial Negate %i/%i! Slow fallback generated.", negate_mask, full_mask); + INFO_LOG(Log::HLE, "PREFIXST: Partial Negate %i/%i! Slow fallback generated.", negate_mask, full_mask); } } @@ -270,7 +270,7 @@ ArmJit::DestARMReg ArmJit::NEONMapPrefixD(int vreg, VectorSize sz, int mapFlags) dest.backingRd = dest.rd; } else { // Allocate a temporary register. - ERROR_LOG(JIT, "PREFIXD: Write mask allocated! %i/%i", writeMask, full_mask); + ERROR_LOG(Log::JIT, "PREFIXD: Write mask allocated! %i/%i", writeMask, full_mask); dest.rd = fpr.QAllocTemp(sz); dest.backingRd = fpr.QMapReg(vreg, sz, mapFlags & ~MAP_NOINIT); // Force initialization of the backing reg. } @@ -294,12 +294,12 @@ void ArmJit::NEONApplyPrefixD(DestARMReg dest) { if (sat1_mask && sat3_mask) { // Why would anyone do this? - ERROR_LOG(JIT, "PREFIXD: Can't have both sat[0-1] and sat[-1-1] at the same time yet"); + ERROR_LOG(Log::JIT, "PREFIXD: Can't have both sat[0-1] and sat[-1-1] at the same time yet"); } if (sat1_mask) { if (sat1_mask != full_mask) { - ERROR_LOG(JIT, "PREFIXD: Can't have partial sat1 mask yet (%i vs %i)", sat1_mask, full_mask); + ERROR_LOG(Log::JIT, "PREFIXD: Can't have partial sat1 mask yet (%i vs %i)", sat1_mask, full_mask); } if (IsD(dest.rd)) { VMOV_immf(D0, 0.0); @@ -316,7 +316,7 @@ void ArmJit::NEONApplyPrefixD(DestARMReg dest) { if (sat3_mask && sat1_mask != full_mask) { if (sat3_mask != full_mask) { - ERROR_LOG(JIT, "PREFIXD: Can't have partial sat3 mask yet (%i vs %i)", sat3_mask, full_mask); + ERROR_LOG(Log::JIT, "PREFIXD: Can't have partial sat3 mask yet (%i vs %i)", sat3_mask, full_mask); } if (IsD(dest.rd)) { VMOV_immf(D0, 0.0); @@ -340,11 +340,11 @@ void ArmJit::NEONApplyPrefixD(DestARMReg dest) { int writeMask = (~(js.prefixD >> 8)) & 0xF; if (writeMask == 3) { - INFO_LOG(JIT, "Doing writemask = 3"); + INFO_LOG(Log::JIT, "Doing writemask = 3"); VMOV(D_0(dest.rd), D_0(dest.backingRd)); } else { // TODO - ERROR_LOG(JIT, "PREFIXD: Arbitrary write masks not supported (%i / %i)", writeMask, full_mask); + ERROR_LOG(Log::JIT, "PREFIXD: Arbitrary write masks not supported (%i / %i)", writeMask, full_mask); VMOV(dest.backingRd, dest.rd); } } diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index e830a6b310..2b05f9a4e1 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -63,13 +63,13 @@ void DisassembleArm(const u8 *data, int size) { int reg1 = (next & 0x0000F000) >> 12; if (reg0 == reg1) { snprintf(temp, sizeof(temp), "%08x MOV32 %s, %04x%04x", (u32)inst, ArmRegName(reg0), hi, low); - INFO_LOG(JIT, "A: %s", temp); + INFO_LOG(Log::JIT, "A: %s", temp); i += 4; continue; } } ArmDis((u32)codePtr, inst, temp, sizeof(temp), true); - INFO_LOG(JIT, "A: %s", temp); + INFO_LOG(Log::JIT, "A: %s", temp); } } @@ -114,7 +114,7 @@ ArmJit::ArmJit(MIPSState *mipsState) : blocks(mipsState, this), gpr(mipsState, & AllocCodeSpace(1024 * 1024 * 16); // 32MB is the absolute max because that's what an ARM branch instruction can reach, backwards and forwards. GenerateFixedCode(); - INFO_LOG(JIT, "ARM JIT initialized: %lld MB of code space", (long long)(GetSpaceLeft() / (1024 * 1024))); + INFO_LOG(Log::JIT, "ARM JIT initialized: %lld MB of code space", (long long)(GetSpaceLeft() / (1024 * 1024))); js.startDefaultPrefix = mips_->HasDefaultPrefix(); @@ -133,7 +133,7 @@ void ArmJit::DoState(PointerWrap &p) return; if (p.mode == PointerWrap::MODE_READ && !js.startDefaultPrefix) { - WARN_LOG(CPU, "Jit: An uneaten prefix was previously detected. Jitting in unknown-prefix mode."); + WARN_LOG(Log::CPU, "Jit: An uneaten prefix was previously detected. Jitting in unknown-prefix mode."); } Do(p, js.startDefaultPrefix); if (s >= 2) { @@ -208,10 +208,10 @@ void ArmJit::InvalidateCacheAt(u32 em_address, int length) { void ArmJit::EatInstruction(MIPSOpcode op) { MIPSInfo info = MIPSGetInfo(op); if (info & DELAYSLOT) { - ERROR_LOG_REPORT_ONCE(ateDelaySlot, JIT, "Ate a branch op."); + ERROR_LOG_REPORT_ONCE(ateDelaySlot, Log::JIT, "Ate a branch op."); } if (js.inDelaySlot) { - ERROR_LOG_REPORT_ONCE(ateInDelaySlot, JIT, "Ate an instruction inside a delay slot."); + ERROR_LOG_REPORT_ONCE(ateInDelaySlot, Log::JIT, "Ate an instruction inside a delay slot."); } CheckJitBreakpoint(GetCompilerPC() + 4, 0); @@ -244,7 +244,7 @@ void ArmJit::CompileDelaySlot(int flags) { void ArmJit::Compile(u32 em_address) { PROFILE_THIS_SCOPE("jitc"); - // INFO_LOG(JIT, "Compiling at %08x", em_address); + // INFO_LOG(Log::JIT, "Compiling at %08x", em_address); if (GetSpaceLeft() < 0x10000 || blocks.IsFull()) { ClearCache(); @@ -263,7 +263,7 @@ void ArmJit::Compile(u32 em_address) { bool cleanSlate = false; if (js.hasSetRounding && !js.lastSetRounding) { - WARN_LOG(JIT, "Detected rounding mode usage, rebuilding jit with checks"); + WARN_LOG(Log::JIT, "Detected rounding mode usage, rebuilding jit with checks"); // Won't loop, since hasSetRounding is only ever set to 1. js.lastSetRounding = js.hasSetRounding; cleanSlate = true; @@ -271,7 +271,7 @@ void ArmJit::Compile(u32 em_address) { // Drat. The VFPU hit an uneaten prefix at the end of a block. if (js.startDefaultPrefix && js.MayHavePrefix()) { - WARN_LOG_REPORT(JIT, "An uneaten prefix at end of block: %08x", GetCompilerPC() - 4); + WARN_LOG_REPORT(Log::JIT, "An uneaten prefix at end of block: %08x", GetCompilerPC() - 4); js.LogPrefix(); // Let's try that one more time. We won't get back here because we toggled the value. @@ -398,17 +398,17 @@ const u8 *ArmJit::DoJit(u32 em_address, JitBlock *b) char temp[256]; if (logBlocks > 0 && dontLogBlocks == 0) { - INFO_LOG(JIT, "=============== mips ==============="); + INFO_LOG(Log::JIT, "=============== mips ==============="); for (u32 cpc = em_address; cpc != GetCompilerPC() + 4; cpc += 4) { MIPSDisAsm(Memory::Read_Opcode_JIT(cpc), cpc, temp, sizeof(temp), true); - INFO_LOG(JIT, "M: %08x %s", cpc, temp); + INFO_LOG(Log::JIT, "M: %08x %s", cpc, temp); } } b->codeSize = GetCodePtr() - b->normalEntry; if (logBlocks > 0 && dontLogBlocks == 0) { - INFO_LOG(JIT, "=============== ARM ==============="); + INFO_LOG(Log::JIT, "=============== ARM ==============="); DisassembleArm(b->normalEntry, GetCodePtr() - b->normalEntry); } if (logBlocks > 0) @@ -449,7 +449,7 @@ bool ArmJit::DescribeCodePtr(const u8 *ptr, std::string &name) void ArmJit::Comp_RunBlock(MIPSOpcode op) { // This shouldn't be necessary, the dispatcher should catch us before we get here. - ERROR_LOG(JIT, "Comp_RunBlock should never be reached!"); + ERROR_LOG(Log::JIT, "Comp_RunBlock should never be reached!"); } void ArmJit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) { @@ -561,7 +561,7 @@ void ArmJit::Comp_ReplacementFunc(MIPSOpcode op) const ReplacementTableEntry *entry = GetReplacementFunc(index); if (!entry) { - ERROR_LOG_REPORT_ONCE(replFunc, HLE, "Invalid replacement op %08x at %08x", op.encoding, js.compilerPC); + ERROR_LOG_REPORT_ONCE(replFunc, Log::HLE, "Invalid replacement op %08x at %08x", op.encoding, js.compilerPC); return; } @@ -634,7 +634,7 @@ void ArmJit::Comp_ReplacementFunc(MIPSOpcode op) js.compiling = false; } } else { - ERROR_LOG(HLE, "Replacement function %s has neither jit nor regular impl", entry->name); + ERROR_LOG(Log::HLE, "Replacement function %s has neither jit nor regular impl", entry->name); } } diff --git a/Core/MIPS/ARM/ArmRegCache.cpp b/Core/MIPS/ARM/ArmRegCache.cpp index 61b16b5c53..40369d82cf 100644 --- a/Core/MIPS/ARM/ArmRegCache.cpp +++ b/Core/MIPS/ARM/ArmRegCache.cpp @@ -229,7 +229,7 @@ ARMReg ArmRegCache::MapReg(MIPSGPReg mipsReg, int mapFlags) { if (mr[mipsReg].loc == ML_ARMREG || mr[mipsReg].loc == ML_ARMREG_IMM) { ARMReg armReg = mr[mipsReg].reg; if (ar[armReg].mipsReg != mipsReg) { - ERROR_LOG_REPORT(JIT, "Register mapping out of sync! %i", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Register mapping out of sync! %i", mipsReg); } if (mapFlags & MAP_DIRTY) { // Mapping dirty means the old imm value is invalid. @@ -292,7 +292,7 @@ allocate: } if (bestToSpill != INVALID_REG) { - // ERROR_LOG(JIT, "Out of registers at PC %08x - spills register %i.", mips_->pc, bestToSpill); + // ERROR_LOG(Log::JIT, "Out of registers at PC %08x - spills register %i.", mips_->pc, bestToSpill); // TODO: Broken somehow in Dante's Inferno, but most games work. Bad flags in MIPSTables somewhere? if (clobbered) { DiscardR(ar[bestToSpill].mipsReg); @@ -303,7 +303,7 @@ allocate: } // Uh oh, we have all of them spilllocked.... - ERROR_LOG_REPORT(JIT, "Out of spillable registers at PC %08x!!!", mips_->pc); + ERROR_LOG_REPORT(Log::JIT, "Out of spillable registers at PC %08x!!!", mips_->pc); return INVALID_REG; } @@ -356,7 +356,7 @@ void ArmRegCache::FlushArmReg(ARMReg r) { if (ar[r].mipsReg == MIPS_REG_INVALID) { // Nothing to do, reg not mapped. if (ar[r].isDirty) { - ERROR_LOG_REPORT(JIT, "Dirty but no mipsreg?"); + ERROR_LOG_REPORT(Log::JIT, "Dirty but no mipsreg?"); } return; } @@ -411,7 +411,7 @@ void ArmRegCache::FlushR(MIPSGPReg r) { case ML_ARMREG: case ML_ARMREG_IMM: if (mr[r].reg == INVALID_REG) { - ERROR_LOG_REPORT(JIT, "FlushR: MipsReg %d had bad ArmReg", r); + ERROR_LOG_REPORT(Log::JIT, "FlushR: MipsReg %d had bad ArmReg", r); } if (ar[mr[r].reg].isDirty) { if (r != MIPS_REG_ZERO) { @@ -425,7 +425,7 @@ void ArmRegCache::FlushR(MIPSGPReg r) { case ML_ARMREG_AS_PTR: // Never dirty. if (ar[mr[r].reg].isDirty) { - ERROR_LOG_REPORT(JIT, "ARMREG_AS_PTR cannot be dirty (yet)"); + ERROR_LOG_REPORT(Log::JIT, "ARMREG_AS_PTR cannot be dirty (yet)"); } ar[mr[r].reg].mipsReg = MIPS_REG_INVALID; break; @@ -435,7 +435,7 @@ void ArmRegCache::FlushR(MIPSGPReg r) { break; default: - ERROR_LOG_REPORT(JIT, "FlushR: MipsReg %d with invalid location %d", r, mr[r].loc); + ERROR_LOG_REPORT(Log::JIT, "FlushR: MipsReg %d with invalid location %d", r, mr[r].loc); break; } if (r == MIPS_REG_ZERO) { @@ -544,14 +544,14 @@ void ArmRegCache::FlushAll() { // Sanity check for (int i = 0; i < NUM_ARMREG; i++) { if (ar[i].mipsReg != MIPS_REG_INVALID) { - ERROR_LOG_REPORT(JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); } } } void ArmRegCache::SetImm(MIPSGPReg r, u32 immVal) { if (r == MIPS_REG_ZERO && immVal != 0) { - ERROR_LOG_REPORT(JIT, "Trying to set immediate %08x to r0 at %08x", immVal, compilerPC_); + ERROR_LOG_REPORT(Log::JIT, "Trying to set immediate %08x to r0 at %08x", immVal, compilerPC_); return; } @@ -577,7 +577,7 @@ bool ArmRegCache::IsImm(MIPSGPReg r) const { u32 ArmRegCache::GetImm(MIPSGPReg r) const { if (r == MIPS_REG_ZERO) return 0; if (mr[r].loc != ML_IMM && mr[r].loc != ML_ARMREG_IMM) { - ERROR_LOG_REPORT(JIT, "Trying to get imm from non-imm register %i", r); + ERROR_LOG_REPORT(Log::JIT, "Trying to get imm from non-imm register %i", r); } return mr[r].imm; } @@ -595,7 +595,7 @@ int ArmRegCache::GetMipsRegOffset(MIPSGPReg r) { case MIPS_REG_VFPUCC: return offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_CC]); default: - ERROR_LOG_REPORT(JIT, "bad mips register %i", r); + ERROR_LOG_REPORT(Log::JIT, "bad mips register %i", r); return 0; // or what? } } @@ -621,7 +621,7 @@ ARMReg ArmRegCache::R(MIPSGPReg mipsReg) { if (mr[mipsReg].loc == ML_ARMREG || mr[mipsReg].loc == ML_ARMREG_IMM) { return (ARMReg)mr[mipsReg].reg; } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_); return INVALID_REG; // BAAAD } } @@ -630,7 +630,7 @@ ARMReg ArmRegCache::RPtr(MIPSGPReg mipsReg) { if (mr[mipsReg].loc == ML_ARMREG_AS_PTR) { return (ARMReg)mr[mipsReg].reg; } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in arm reg as pointer. compilerPC = %08x", mipsReg, compilerPC_); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in arm reg as pointer. compilerPC = %08x", mipsReg, compilerPC_); return INVALID_REG; // BAAAD } } diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.cpp b/Core/MIPS/ARM/ArmRegCacheFPU.cpp index c3df5301e1..c6d514ace0 100644 --- a/Core/MIPS/ARM/ArmRegCacheFPU.cpp +++ b/Core/MIPS/ARM/ArmRegCacheFPU.cpp @@ -113,9 +113,9 @@ bool ArmRegCacheFPU::IsMapped(MIPSReg r) { } ARMReg ArmRegCacheFPU::MapReg(MIPSReg mipsReg, int mapFlags) { - // INFO_LOG(JIT, "FPR MapReg: %i flags=%i", mipsReg, mapFlags); + // INFO_LOG(Log::JIT, "FPR MapReg: %i flags=%i", mipsReg, mapFlags); if (jo_->useNEONVFPU && mipsReg >= 32) { - ERROR_LOG(JIT, "Cannot map VFPU registers to ARM VFP registers in NEON mode. PC=%08x", js_->compilerPC); + ERROR_LOG(Log::JIT, "Cannot map VFPU registers to ARM VFP registers in NEON mode. PC=%08x", js_->compilerPC); return S0; } @@ -125,12 +125,12 @@ ARMReg ArmRegCacheFPU::MapReg(MIPSReg mipsReg, int mapFlags) { // with that flag immediately writes a "known" value to the register. if (mr[mipsReg].loc == ML_ARMREG) { if (ar[mr[mipsReg].reg].mipsReg != mipsReg) { - ERROR_LOG(JIT, "Reg mapping out of sync! MR %i", mipsReg); + ERROR_LOG(Log::JIT, "Reg mapping out of sync! MR %i", mipsReg); } if (mapFlags & MAP_DIRTY) { ar[mr[mipsReg].reg].isDirty = true; } - //INFO_LOG(JIT, "Already mapped %i to %i", mipsReg, mr[mipsReg].reg); + //INFO_LOG(Log::JIT, "Already mapped %i to %i", mipsReg, mr[mipsReg].reg); return (ARMReg)(mr[mipsReg].reg + S0); } @@ -154,7 +154,7 @@ allocate: ar[reg].mipsReg = mipsReg; mr[mipsReg].loc = ML_ARMREG; mr[mipsReg].reg = reg; - //INFO_LOG(JIT, "Mapped %i to %i", mipsReg, mr[mipsReg].reg); + //INFO_LOG(Log::JIT, "Mapped %i to %i", mipsReg, mr[mipsReg].reg); return (ARMReg)(reg + S0); } } @@ -178,7 +178,7 @@ allocate: } // Uh oh, we have all them spilllocked.... - ERROR_LOG(JIT, "Out of spillable registers at PC %08x!!!", js_->compilerPC); + ERROR_LOG(Log::JIT, "Out of spillable registers at PC %08x!!!", js_->compilerPC); return INVALID_REG; } @@ -293,14 +293,14 @@ void ArmRegCacheFPU::FlushArmReg(ARMReg r) { if (ar[reg].mipsReg != -1) { if (ar[reg].isDirty && mr[ar[reg].mipsReg].loc == ML_ARMREG) { - //INFO_LOG(JIT, "Flushing ARM reg %i", reg); + //INFO_LOG(Log::JIT, "Flushing ARM reg %i", reg); emit_->VSTR(r, CTXREG, GetMipsRegOffset(ar[reg].mipsReg)); } // IMMs won't be in an ARM reg. mr[ar[reg].mipsReg].loc = ML_MEM; mr[ar[reg].mipsReg].reg = INVALID_REG; } else { - ERROR_LOG(JIT, "Dirty but no mipsreg?"); + ERROR_LOG(Log::JIT, "Dirty but no mipsreg?"); } ar[reg].isDirty = false; ar[reg].mipsReg = -1; @@ -338,7 +338,7 @@ void ArmRegCacheFPU::FlushQWithV(MIPSReg r) { } if (flushCount > 1) { - WARN_LOG(JIT, "ERROR: More than one quad was flushed to flush reg %i", r); + WARN_LOG(Log::JIT, "ERROR: More than one quad was flushed to flush reg %i", r); } } */ @@ -348,12 +348,12 @@ void ArmRegCacheFPU::FlushR(MIPSReg r) { case ML_IMM: // IMM is always "dirty". // IMM is not allowed for FP (yet). - ERROR_LOG(JIT, "Imm in FP register?"); + ERROR_LOG(Log::JIT, "Imm in FP register?"); break; case ML_ARMREG: if (mr[r].reg == INVALID_REG) { - ERROR_LOG(JIT, "FlushR: MipsReg had bad ArmReg"); + ERROR_LOG(Log::JIT, "FlushR: MipsReg had bad ArmReg"); } if (mr[r].reg >= Q0 && mr[r].reg <= Q15) { @@ -361,13 +361,13 @@ void ArmRegCacheFPU::FlushR(MIPSReg r) { // mipsreg that's been part of a quad. int quad = mr[r].reg - Q0; if (qr[quad].isDirty) { - WARN_LOG(JIT, "FlushR found quad register %i - PC=%08x", quad, js_->compilerPC); + WARN_LOG(Log::JIT, "FlushR found quad register %i - PC=%08x", quad, js_->compilerPC); emit_->ADDI2R(R0, CTXREG, GetMipsRegOffset(r), R1); emit_->VST1_lane(F_32, (ARMReg)mr[r].reg, R0, mr[r].lane, true); } } else { if (ar[mr[r].reg].isDirty) { - //INFO_LOG(JIT, "Flushing dirty reg %i", mr[r].reg); + //INFO_LOG(Log::JIT, "Flushing dirty reg %i", mr[r].reg); emit_->VSTR((ARMReg)(mr[r].reg + S0), CTXREG, GetMipsRegOffset(r)); ar[mr[r].reg].isDirty = false; } @@ -438,13 +438,13 @@ void ArmRegCacheFPU::FlushAll() { if (ar[a].isDirty) { if (m == -1) { - INFO_LOG(JIT, "ARM reg %i is dirty but has no mipsreg", a); + INFO_LOG(Log::JIT, "ARM reg %i is dirty but has no mipsreg", a); continue; } int c = FlushGetSequential(a); if (c == 1) { - // INFO_LOG(JIT, "Got single register: %i (%i)", a, m); + // INFO_LOG(Log::JIT, "Got single register: %i (%i)", a, m); emit_->VSTR((ARMReg)(a + S0), CTXREG, GetMipsRegOffset(m)); } else if (c == 2) { // Probably not worth using VSTMIA for two. @@ -452,9 +452,9 @@ void ArmRegCacheFPU::FlushAll() { emit_->VSTR((ARMReg)(a + S0), CTXREG, offset); emit_->VSTR((ARMReg)(a + 1 + S0), CTXREG, offset + 4); } else { - // INFO_LOG(JIT, "Got sequence: %i at %i (%i)", c, a, m); + // INFO_LOG(Log::JIT, "Got sequence: %i at %i (%i)", c, a, m); emit_->ADDI2R(SCRATCHREG1, CTXREG, GetMipsRegOffset(m), SCRATCHREG2); - // INFO_LOG(JIT, "VSTMIA R0, %i, %i", a, c); + // INFO_LOG(Log::JIT, "VSTMIA R0, %i, %i", a, c); emit_->VSTMIA(SCRATCHREG1, false, (ARMReg)(S0 + a), c); } @@ -480,7 +480,7 @@ void ArmRegCacheFPU::FlushAll() { // Sanity check for (int i = 0; i < NUM_ARMFPUREG; i++) { if (ar[i].mipsReg != -1) { - ERROR_LOG(JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); + ERROR_LOG(Log::JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); } } pendingFlush = false; @@ -491,12 +491,12 @@ void ArmRegCacheFPU::DiscardR(MIPSReg r) { case ML_IMM: // IMM is always "dirty". // IMM is not allowed for FP (yet). - ERROR_LOG(JIT, "Imm in FP register?"); + ERROR_LOG(Log::JIT, "Imm in FP register?"); break; case ML_ARMREG: if (mr[r].reg == INVALID_REG) { - ERROR_LOG(JIT, "DiscardR: MipsReg had bad ArmReg"); + ERROR_LOG(Log::JIT, "DiscardR: MipsReg had bad ArmReg"); } else { // Note that we DO NOT write it back here. That's the whole point of Discard. ar[mr[r].reg].isDirty = false; @@ -524,7 +524,7 @@ bool ArmRegCacheFPU::IsTempX(ARMReg r) const { int ArmRegCacheFPU::GetTempR() { if (jo_->useNEONVFPU) { - ERROR_LOG(JIT, "VFP temps not allowed in NEON mode"); + ERROR_LOG(Log::JIT, "VFP temps not allowed in NEON mode"); return 0; } pendingFlush = true; @@ -535,7 +535,7 @@ int ArmRegCacheFPU::GetTempR() { } } - ERROR_LOG(CPU, "Out of temp regs! Might need to DiscardR() some"); + ERROR_LOG(Log::CPU, "Out of temp regs! Might need to DiscardR() some"); _assert_msg_(false, "Regcache ran out of temp regs, might need to DiscardR() some."); return -1; } @@ -543,7 +543,7 @@ int ArmRegCacheFPU::GetTempR() { int ArmRegCacheFPU::GetMipsRegOffset(MIPSReg r) { // These are offsets within the MIPSState structure. First there are the GPRS, then FPRS, then the "VFPURs", then the VFPU ctrls. if (r < 0 || r > 32 + 128 + NUM_TEMPS) { - ERROR_LOG(JIT, "bad mips register %i, out of range", r); + ERROR_LOG(Log::JIT, "bad mips register %i, out of range", r); return 0; // or what? } @@ -584,11 +584,11 @@ ARMReg ArmRegCacheFPU::R(int mipsReg) { return (ARMReg)(mr[mipsReg].reg + S0); } else { if (mipsReg < 32) { - ERROR_LOG(JIT, "FReg %i not in ARM reg. compilerPC = %08x : %s", mipsReg, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); + ERROR_LOG(Log::JIT, "FReg %i not in ARM reg. compilerPC = %08x : %s", mipsReg, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); } else if (mipsReg < 32 + 128) { - ERROR_LOG(JIT, "VReg %i not in ARM reg. compilerPC = %08x : %s", mipsReg - 32, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); + ERROR_LOG(Log::JIT, "VReg %i not in ARM reg. compilerPC = %08x : %s", mipsReg - 32, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); } else { - ERROR_LOG(JIT, "Tempreg %i not in ARM reg. compilerPC = %08x : %s", mipsReg - 128 - 32, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); + ERROR_LOG(Log::JIT, "Tempreg %i not in ARM reg. compilerPC = %08x : %s", mipsReg - 128 - 32, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); } return INVALID_REG; // BAAAD } @@ -607,18 +607,18 @@ bool MappableQ(int quad) { } void ArmRegCacheFPU::QLoad4x4(MIPSGPReg regPtr, int vquads[4]) { - ERROR_LOG(JIT, "QLoad4x4 not implemented"); + ERROR_LOG(Log::JIT, "QLoad4x4 not implemented"); // TODO } void ArmRegCacheFPU::QFlush(int quad) { if (!MappableQ(quad)) { - ERROR_LOG(JIT, "Cannot flush non-mappable quad %i", quad); + ERROR_LOG(Log::JIT, "Cannot flush non-mappable quad %i", quad); return; } if (qr[quad].isDirty && !qr[quad].isTemp) { - INFO_LOG(JIT, "Flushing Q%i (%s)", quad, GetVectorNotation(qr[quad].mipsVec, qr[quad].sz).c_str()); + INFO_LOG(Log::JIT, "Flushing Q%i (%s)", quad, GetVectorNotation(qr[quad].mipsVec, qr[quad].sz).c_str()); ARMReg q = QuadAsQ(quad); // Unlike reads, when writing to the register file we need to be careful to write the correct @@ -628,7 +628,7 @@ void ArmRegCacheFPU::QFlush(int quad) { case V_Single: emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[0]), R1); emit_->VST1_lane(F_32, q, R0, 0, true); - // WARN_LOG(JIT, "S: Falling back to individual flush: pc=%08x", js_->compilerPC); + // WARN_LOG(Log::JIT, "S: Falling back to individual flush: pc=%08x", js_->compilerPC); break; case V_Pair: if (Consecutive(qr[quad].vregs[0], qr[quad].vregs[1])) { @@ -636,7 +636,7 @@ void ArmRegCacheFPU::QFlush(int quad) { emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[0]), R1); emit_->VST1(F_32, q, R0, 1, ALIGN_NONE); // TODO: Allow ALIGN_64 when applicable } else { - // WARN_LOG(JIT, "P: Falling back to individual flush: pc=%08x", js_->compilerPC); + // WARN_LOG(Log::JIT, "P: Falling back to individual flush: pc=%08x", js_->compilerPC); emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[0]), R1); emit_->VST1_lane(F_32, q, R0, 0, true); emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[1]), R1); @@ -649,7 +649,7 @@ void ArmRegCacheFPU::QFlush(int quad) { emit_->VST1(F_32, QuadAsD(quad), R0, 1, ALIGN_NONE, REG_UPDATE); // TODO: Allow ALIGN_64 when applicable emit_->VST1_lane(F_32, q, R0, 2, true); } else { - // WARN_LOG(JIT, "T: Falling back to individual flush: pc=%08x", js_->compilerPC); + // WARN_LOG(Log::JIT, "T: Falling back to individual flush: pc=%08x", js_->compilerPC); emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[0]), R1); emit_->VST1_lane(F_32, q, R0, 0, true); emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[1]), R1); @@ -663,7 +663,7 @@ void ArmRegCacheFPU::QFlush(int quad) { emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[0]), R1); emit_->VST1(F_32, QuadAsD(quad), R0, 2, ALIGN_NONE); // TODO: Allow ALIGN_64 when applicable } else { - // WARN_LOG(JIT, "Q: Falling back to individual flush: pc=%08x", js_->compilerPC); + // WARN_LOG(Log::JIT, "Q: Falling back to individual flush: pc=%08x", js_->compilerPC); emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[0]), R1); emit_->VST1_lane(F_32, q, R0, 0, true); emit_->ADDI2R(R0, CTXREG, GetMipsRegOffsetV(qr[quad].vregs[1]), R1); @@ -675,7 +675,7 @@ void ArmRegCacheFPU::QFlush(int quad) { } break; default: - ERROR_LOG(JIT, "Unknown quad size %i", qr[quad].sz); + ERROR_LOG(Log::JIT, "Unknown quad size %i", qr[quad].sz); break; } @@ -685,7 +685,7 @@ void ArmRegCacheFPU::QFlush(int quad) { for (int i = 0; i < n; i++) { int vr = qr[quad].vregs[i]; if (vr < 0 || vr > 128) { - ERROR_LOG(JIT, "Bad vr %i", vr); + ERROR_LOG(Log::JIT, "Bad vr %i", vr); } FPURegMIPS &m = mr[32 + vr]; m.loc = ML_MEM; @@ -695,7 +695,7 @@ void ArmRegCacheFPU::QFlush(int quad) { } else { if (qr[quad].isTemp) { - WARN_LOG(JIT, "Not flushing quad %i; dirty = %i, isTemp = %i", quad, qr[quad].isDirty, qr[quad].isTemp); + WARN_LOG(Log::JIT, "Not flushing quad %i; dirty = %i, isTemp = %i", quad, qr[quad].isDirty, qr[quad].isTemp); } } @@ -715,7 +715,7 @@ int ArmRegCacheFPU::QGetFreeQuad(int start, int count, const char *reason) { // Don't steal temp quads! if (qr[q].mipsVec == (int)INVALID_REG && !qr[q].isTemp) { - // INFO_LOG(JIT, "Free quad: %i", q); + // INFO_LOG(Log::JIT, "Free quad: %i", q); // Oh yeah! Free quad! return q; } @@ -747,10 +747,10 @@ int ArmRegCacheFPU::QGetFreeQuad(int start, int count, const char *reason) { } if (bestQuad == -1) { - ERROR_LOG(JIT, "Failed finding a free quad. Things will now go haywire!"); + ERROR_LOG(Log::JIT, "Failed finding a free quad. Things will now go haywire!"); return -1; } else { - INFO_LOG(JIT, "No register found in %i and the next %i, kicked out #%i (%s)", start, count, bestQuad, reason ? reason : "no reason"); + INFO_LOG(Log::JIT, "No register found in %i and the next %i, kicked out #%i (%s)", start, count, bestQuad, reason ? reason : "no reason"); QFlush(bestQuad); return bestQuad; } @@ -759,7 +759,7 @@ int ArmRegCacheFPU::QGetFreeQuad(int start, int count, const char *reason) { ARMReg ArmRegCacheFPU::QAllocTemp(VectorSize sz) { int q = QGetFreeQuad(8, 16, "allocating temporary"); // Prefer high quads as temps if (q < 0) { - ERROR_LOG(JIT, "Failed to allocate temp quad"); + ERROR_LOG(Log::JIT, "Failed to allocate temp quad"); q = 0; } qr[q].spillLock = true; @@ -767,7 +767,7 @@ ARMReg ArmRegCacheFPU::QAllocTemp(VectorSize sz) { qr[q].sz = sz; qr[q].isDirty = false; // doesn't matter - INFO_LOG(JIT, "Allocated temp quad %i", q); + INFO_LOG(Log::JIT, "Allocated temp quad %i", q); if (sz == V_Single || sz == V_Pair) { return D_0(ARMReg(Q0 + q)); @@ -845,20 +845,20 @@ ARMReg ArmRegCacheFPU::QMapReg(int vreg, VectorSize sz, int flags) { // Check if completely there already. If so, set spill-lock, transfer dirty flag and exit. if (vreg == qr[q].mipsVec && sz == qr[q].sz) { if (i < count) { - INFO_LOG(JIT, "Quad already mapped: %i : %i (size %i)", q, vreg, sz); + INFO_LOG(Log::JIT, "Quad already mapped: %i : %i (size %i)", q, vreg, sz); qr[q].isDirty = qr[q].isDirty || (flags & MAP_DIRTY); qr[q].spillLock = true; // Sanity check vregs for (int i = 0; i < n; i++) { if (vregs[i] != qr[q].vregs[i]) { - ERROR_LOG(JIT, "Sanity check failed: %i vs %i", vregs[i], qr[q].vregs[i]); + ERROR_LOG(Log::JIT, "Sanity check failed: %i vs %i", vregs[i], qr[q].vregs[i]); } } return (ARMReg)(Q0 + q); } else { - INFO_LOG(JIT, "Quad already mapped at %i which is out of requested range [%i-%i) (count = %i), needs moving. For now we flush.", q, start, start+count, count); + INFO_LOG(Log::JIT, "Quad already mapped at %i which is out of requested range [%i-%i) (count = %i), needs moving. For now we flush.", q, start, start+count, count); quadsToFlush.push_back(q); continue; } @@ -881,7 +881,7 @@ ARMReg ArmRegCacheFPU::QMapReg(int vreg, VectorSize sz, int flags) { // We didn't find the extra register, but we got a list of regs to flush. Flush 'em. // Here we can check for opportunities to do a "transpose-flush" of row vectors, etc. if (!quadsToFlush.empty()) { - INFO_LOG(JIT, "New mapping %s collided with %d quads, flushing them.", GetVectorNotation(vreg, sz).c_str(), (int)quadsToFlush.size()); + INFO_LOG(Log::JIT, "New mapping %s collided with %d quads, flushing them.", GetVectorNotation(vreg, sz).c_str(), (int)quadsToFlush.size()); } for (size_t i = 0; i < quadsToFlush.size(); i++) { QFlush(quadsToFlush[i]); @@ -973,7 +973,7 @@ ARMReg ArmRegCacheFPU::QMapReg(int vreg, VectorSize sz, int flags) { qr[quad].isDirty = (flags & MAP_DIRTY) != 0; qr[quad].spillLock = true; - INFO_LOG(JIT, "Mapped Q%i to vfpu %i (%s), sz=%i, dirty=%i", quad, vreg, GetVectorNotation(vreg, sz).c_str(), (int)sz, qr[quad].isDirty); + INFO_LOG(Log::JIT, "Mapped Q%i to vfpu %i (%s), sz=%i, dirty=%i", quad, vreg, GetVectorNotation(vreg, sz).c_str(), (int)sz, qr[quad].isDirty); if (sz == V_Single || sz == V_Pair) { return D_0(QuadAsQ(quad)); } else { diff --git a/Core/MIPS/ARM64/Arm64Asm.cpp b/Core/MIPS/ARM64/Arm64Asm.cpp index 5a0b12ce65..727f26a7cf 100644 --- a/Core/MIPS/ARM64/Arm64Asm.cpp +++ b/Core/MIPS/ARM64/Arm64Asm.cpp @@ -77,9 +77,9 @@ extern volatile CoreState coreState; void ShowPC(u32 downcount, void *membase, void *jitbase) { static int count = 0; if (currentMIPS) { - ERROR_LOG(JIT, "ShowPC : %08x Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); + ERROR_LOG(Log::JIT, "ShowPC : %08x Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); } else { - ERROR_LOG(JIT, "Universe corrupt?"); + ERROR_LOG(Log::JIT, "Universe corrupt?"); } //if (count > 2000) // exit(0); @@ -314,7 +314,7 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { if (enableDisasm) { std::vector lines = DisassembleArm64(start, (int)(GetCodePtr() - start)); for (auto s : lines) { - INFO_LOG(JIT, "%s", s.c_str()); + INFO_LOG(Log::JIT, "%s", s.c_str()); } } diff --git a/Core/MIPS/ARM64/Arm64CompBranch.cpp b/Core/MIPS/ARM64/Arm64CompBranch.cpp index 26713ecce2..be030c8eba 100644 --- a/Core/MIPS/ARM64/Arm64CompBranch.cpp +++ b/Core/MIPS/ARM64/Arm64CompBranch.cpp @@ -68,7 +68,7 @@ namespace MIPSComp void Arm64Jit::BranchRSRTComp(MIPSOpcode op, CCFlags cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -212,7 +212,7 @@ void Arm64Jit::BranchRSRTComp(MIPSOpcode op, CCFlags cc, bool likely) void Arm64Jit::BranchRSZeroComp(MIPSOpcode op, CCFlags cc, bool andLink, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -371,7 +371,7 @@ void Arm64Jit::Comp_RelBranchRI(MIPSOpcode op) // If likely is set, discard the branch slot if NOT taken. void Arm64Jit::BranchFPFlag(MIPSOpcode op, CCFlags cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -441,7 +441,7 @@ void Arm64Jit::Comp_FPUBranch(MIPSOpcode op) { // If likely is set, discard the branch slot if NOT taken. void Arm64Jit::BranchVFPUFlag(MIPSOpcode op, CCFlags cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -518,7 +518,7 @@ static void HitInvalidJump(uint32_t dest) { void Arm64Jit::Comp_Jump(MIPSOpcode op) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } u32 off = TARGET26; @@ -527,7 +527,7 @@ void Arm64Jit::Comp_Jump(MIPSOpcode op) { // Might be a stubbed address or something? if (!Memory::IsValidAddress(targetAddr) || (targetAddr & 3) != 0) { if (js.nextExit == 0) { - ERROR_LOG_REPORT(JIT, "Jump to invalid address: %08x", targetAddr); + ERROR_LOG_REPORT(Log::JIT, "Jump to invalid address: %08x", targetAddr); } else { js.compiling = false; } @@ -585,7 +585,7 @@ void Arm64Jit::Comp_Jump(MIPSOpcode op) { void Arm64Jit::Comp_JumpReg(MIPSOpcode op) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } MIPSGPReg rs = _RS; @@ -667,7 +667,7 @@ void Arm64Jit::Comp_JumpReg(MIPSOpcode op) void Arm64Jit::Comp_Syscall(MIPSOpcode op) { if (op.encoding == 0x03FFFFcc) { - WARN_LOG(JIT, "Encountered bad syscall instruction at %08x (%08x)", js.compilerPC, op.encoding); + WARN_LOG(Log::JIT, "Encountered bad syscall instruction at %08x (%08x)", js.compilerPC, op.encoding); } if (!g_Config.bSkipDeadbeefFilling) { diff --git a/Core/MIPS/ARM64/Arm64CompVFPU.cpp b/Core/MIPS/ARM64/Arm64CompVFPU.cpp index d5dd416d6f..d722deb0f6 100644 --- a/Core/MIPS/ARM64/Arm64CompVFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompVFPU.cpp @@ -99,7 +99,7 @@ namespace MIPSComp { js.prefixDFlag = JitState::PREFIX_KNOWN_DIRTY; break; default: - ERROR_LOG(CPU, "VPFX - bad regnum %i : data=%08x", regnum, data); + ERROR_LOG(Log::CPU, "VPFX - bad regnum %i : data=%08x", regnum, data); break; } } @@ -134,7 +134,7 @@ namespace MIPSComp { // Prefix may say "z, z, z, z" but if this is a pair, we force to x. // TODO: But some ops seem to use const 0 instead? if (regnum >= n) { - WARN_LOG(CPU, "JIT: Invalid VFPU swizzle: %08x : %d / %d at PC = %08x (%s)", prefix, regnum, n, GetCompilerPC(), MIPSDisasmAt(GetCompilerPC()).c_str()); + WARN_LOG(Log::CPU, "JIT: Invalid VFPU swizzle: %08x : %d / %d at PC = %08x (%s)", prefix, regnum, n, GetCompilerPC(), MIPSDisasmAt(GetCompilerPC()).c_str()); regnum = 0; } @@ -882,7 +882,7 @@ namespace MIPSComp { fp.FDIV(fpr.V(tempregs[i]), S0, fpr.V(sregs[i])); break; default: - ERROR_LOG(JIT, "case missing in vfpu vv2op"); + ERROR_LOG(Log::JIT, "case missing in vfpu vv2op"); DISABLE; break; } @@ -948,6 +948,12 @@ namespace MIPSComp { } void Arm64Jit::Comp_Vh2f(MIPSOpcode op) { + // TODO: Fix by porting the general SSE solution to NEON + // FCVTL doesn't provide identical results to the PSP hardware, according to the unit test: + // O vh2f: 00000000,400c0000,00000000,7ff00000 + // E vh2f: 00000000,400c0000,00000000,7f800380 + DISABLE; + CONDITIONAL_DISABLE(VFPU_VEC); if (js.HasUnknownPrefix()) { DISABLE; @@ -1027,7 +1033,7 @@ namespace MIPSComp { } } else { //ERROR - maybe need to make this value too an "interlock" value? - ERROR_LOG(CPU, "mfv - invalid register %i", imm); + ERROR_LOG(Log::CPU, "mfv - invalid register %i", imm); } } break; @@ -1910,7 +1916,7 @@ namespace MIPSComp { break; } default: - ERROR_LOG(JIT, "Bad what in vrot"); + ERROR_LOG(Log::JIT, "Bad what in vrot"); break; } } @@ -1941,7 +1947,7 @@ namespace MIPSComp { // Pair of vrot. Let's join them. vd2 = MIPS_GET_VD(nextOp); imm2 = (nextOp >> 16) & 0x1f; - // NOTICE_LOG(JIT, "Joint VFPU at %08x", js.blockStart); + // NOTICE_LOG(Log::JIT, "Joint VFPU at %08x", js.blockStart); } u8 sreg; GetVectorRegs(dregs, sz, vd); diff --git a/Core/MIPS/ARM64/Arm64IRAsm.cpp b/Core/MIPS/ARM64/Arm64IRAsm.cpp index d623c6cd58..7783045b08 100644 --- a/Core/MIPS/ARM64/Arm64IRAsm.cpp +++ b/Core/MIPS/ARM64/Arm64IRAsm.cpp @@ -40,9 +40,9 @@ static void ShowPC(void *membase, void *jitbase) { static int count = 0; if (currentMIPS) { u32 downcount = currentMIPS->downcount; - ERROR_LOG(JIT, "[%08x] ShowPC Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); + ERROR_LOG(Log::JIT, "[%08x] ShowPC Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); } else { - ERROR_LOG(JIT, "Universe corrupt?"); + ERROR_LOG(Log::JIT, "Universe corrupt?"); } //if (count > 2000) // exit(0); @@ -269,7 +269,7 @@ void Arm64JitBackend::GenerateFixedCode(MIPSState *mipsState) { if (enableDisasm) { std::vector lines = DisassembleArm64(disasmStart, (int)(GetCodePtr() - disasmStart)); for (auto s : lines) { - INFO_LOG(JIT, "%s", s.c_str()); + INFO_LOG(Log::JIT, "%s", s.c_str()); } } diff --git a/Core/MIPS/ARM64/Arm64IRJit.cpp b/Core/MIPS/ARM64/Arm64IRJit.cpp index 10438af30b..4e4b6c24cb 100644 --- a/Core/MIPS/ARM64/Arm64IRJit.cpp +++ b/Core/MIPS/ARM64/Arm64IRJit.cpp @@ -44,6 +44,7 @@ Arm64JitBackend::Arm64JitBackend(JitOptions &jitopt, IRBlockCache &blocks) if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) { jo.enablePointerify = false; } + jo.optimizeForInterpreter = false; #ifdef MASKED_PSP_MEMORY jo.enablePointerify = false; #endif @@ -64,11 +65,12 @@ static void NoBlockExits() { _assert_msg_(false, "Never exited block, invalid IR?"); } -bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { +bool Arm64JitBackend::CompileBlock(IRBlockCache *irBlockCache, int block_num, bool preload) { if (GetSpaceLeft() < 0x800) return false; - BeginWrite(std::min(GetSpaceLeft(), (size_t)block->GetNumInstructions() * 32)); + IRBlock *block = irBlockCache->GetBlock(block_num); + BeginWrite(std::min(GetSpaceLeft(), (size_t)block->GetNumIRInstructions() * 32)); u32 startPC = block->GetOriginalStart(); bool wroteCheckedOffset = false; @@ -87,16 +89,17 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) // Don't worry, the codespace isn't large enough to overflow offsets. const u8 *blockStart = GetCodePointer(); - block->SetTargetOffset((int)GetOffset(blockStart)); + block->SetNativeOffset((int)GetOffset(blockStart)); compilingBlockNum_ = block_num; lastConstPC_ = 0; - regs_.Start(block); + regs_.Start(irBlockCache, block_num); std::vector addresses; - addresses.reserve(block->GetNumInstructions()); - for (int i = 0; i < block->GetNumInstructions(); ++i) { - const IRInst &inst = block->GetInstructions()[i]; + addresses.reserve(block->GetNumIRInstructions()); + const IRInst *instructions = irBlockCache->GetBlockInstructionPtr(*block); + for (int i = 0; i < block->GetNumIRInstructions(); ++i) { + const IRInst &inst = instructions[i]; regs_.SetIRIndex(i); addresses.push_back(GetCodePtr()); @@ -119,7 +122,7 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) B(hooks_.crashHandler); } - int len = (int)GetOffset(GetCodePointer()) - block->GetTargetOffset(); + int len = (int)GetOffset(GetCodePointer()) - block->GetNativeOffset(); if (len < MIN_BLOCK_NORMAL_LEN) { // We need at least 10 bytes to invalidate blocks with. ReserveCodeSpace(MIN_BLOCK_NORMAL_LEN - len); @@ -154,15 +157,16 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) for (int i = 0; i < (int)addresses.size(); ++i) addressesLookup[addresses[i]] = i; - INFO_LOG(JIT, "=============== ARM64 (%08x, %d bytes) ===============", startPC, len); + INFO_LOG(Log::JIT, "=============== ARM64 (%08x, %d bytes) ===============", startPC, len); + const IRInst *instructions = irBlockCache->GetBlockInstructionPtr(*block); for (const u8 *p = blockStart; p < GetCodePointer(); ) { auto it = addressesLookup.find(p); if (it != addressesLookup.end()) { - const IRInst &inst = block->GetInstructions()[it->second]; + const IRInst &inst = instructions[it->second]; char temp[512]; DisassembleIR(temp, sizeof(temp), inst); - INFO_LOG(JIT, "IR: #%d %s", it->second, temp); + INFO_LOG(Log::JIT, "IR: #%d %s", it->second, temp); } auto next = std::next(it); @@ -170,7 +174,7 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) auto lines = DisassembleArm64(p, (int)(nextp - p)); for (const auto &line : lines) - INFO_LOG(JIT, " A: %s", line.c_str()); + INFO_LOG(Log::JIT, " A: %s", line.c_str()); p = nextp; } } @@ -318,8 +322,9 @@ void Arm64JitBackend::ClearAllBlocks() { EraseAllLinks(-1); } -void Arm64JitBackend::InvalidateBlock(IRBlock *block, int block_num) { - int offset = block->GetTargetOffset(); +void Arm64JitBackend::InvalidateBlock(IRBlockCache *irBlockCache, int block_num) { + IRBlock *block = irBlockCache->GetBlock(block_num); + int offset = block->GetNativeOffset(); u8 *writable = GetWritablePtrFromCodePtr(GetBasePtr()) + offset; // Overwrite the block with a jump to compile it again. diff --git a/Core/MIPS/ARM64/Arm64IRJit.h b/Core/MIPS/ARM64/Arm64IRJit.h index 055e525565..c2992f3520 100644 --- a/Core/MIPS/ARM64/Arm64IRJit.h +++ b/Core/MIPS/ARM64/Arm64IRJit.h @@ -40,9 +40,9 @@ public: bool DescribeCodePtr(const u8 *ptr, std::string &name) const override; void GenerateFixedCode(MIPSState *mipsState) override; - bool CompileBlock(IRBlock *block, int block_num, bool preload) override; + bool CompileBlock(IRBlockCache *irBlockCache, int block_num, bool preload) override; void ClearAllBlocks() override; - void InvalidateBlock(IRBlock *block, int block_num) override; + void InvalidateBlock(IRBlockCache *irBlockCache, int block_num) override; void UpdateFCR31(MIPSState *mipsState) override; diff --git a/Core/MIPS/ARM64/Arm64IRRegCache.cpp b/Core/MIPS/ARM64/Arm64IRRegCache.cpp index 84564877a7..41281be57d 100644 --- a/Core/MIPS/ARM64/Arm64IRRegCache.cpp +++ b/Core/MIPS/ARM64/Arm64IRRegCache.cpp @@ -814,7 +814,7 @@ ARM64Reg Arm64IRRegCache::R(IRReg mipsReg) { if (mr[mipsReg].loc == MIPSLoc::REG || mr[mipsReg].loc == MIPSLoc::REG_IMM) { return FromNativeReg(mr[mipsReg].nReg); } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in arm64 reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in arm64 reg", mipsReg); return INVALID_REG; // BAAAD } } @@ -834,11 +834,11 @@ ARM64Reg Arm64IRRegCache::RPtr(IRReg mipsReg) { if (nr[r].pointerified) { return FromNativeReg64(mr[mipsReg].nReg); } else { - ERROR_LOG(JIT, "Tried to use a non-pointer register as a pointer"); + ERROR_LOG(Log::JIT, "Tried to use a non-pointer register as a pointer"); return INVALID_REG; } } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in arm64 reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in arm64 reg", mipsReg); return INVALID_REG; // BAAAD } } @@ -849,7 +849,7 @@ ARM64Reg Arm64IRRegCache::F(IRReg mipsReg) { if (mr[mipsReg + 32].loc == MIPSLoc::FREG) { return FromNativeReg(mr[mipsReg + 32].nReg); } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in arm64 reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in arm64 reg", mipsReg); return INVALID_REG; // BAAAD } } diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index a82b791d13..92d481b6d3 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -51,17 +51,17 @@ using namespace Arm64JitConstants; static void DisassembleArm64Print(const u8 *data, int size) { std::vector lines = DisassembleArm64(data, size); for (auto s : lines) { - INFO_LOG(JIT, "%s", s.c_str()); + INFO_LOG(Log::JIT, "%s", s.c_str()); } /* - INFO_LOG(JIT, "+++"); + INFO_LOG(Log::JIT, "+++"); // A format friendly to Online Disassembler which gets endianness wrong for (size_t i = 0; i < lines.size(); i++) { uint32_t opcode = ((const uint32_t *)data)[i]; - INFO_LOG(JIT, "%d/%d: %08x", (int)(i+1), (int)lines.size(), swap32(opcode)); + INFO_LOG(Log::JIT, "%d/%d: %08x", (int)(i+1), (int)lines.size(), swap32(opcode)); } - INFO_LOG(JIT, "==="); - INFO_LOG(JIT, "===");*/ + INFO_LOG(Log::JIT, "==="); + INFO_LOG(Log::JIT, "===");*/ } static u32 JitBreakpoint(uint32_t addr) { @@ -131,7 +131,7 @@ void Arm64Jit::DoState(PointerWrap &p) { Do(p, js.startDefaultPrefix); if (p.mode == PointerWrap::MODE_READ && !js.startDefaultPrefix) { - WARN_LOG(CPU, "Jit: An uneaten prefix was previously detected. Jitting in unknown-prefix mode."); + WARN_LOG(Log::CPU, "Jit: An uneaten prefix was previously detected. Jitting in unknown-prefix mode."); } if (s >= 2) { Do(p, js.hasSetRounding); @@ -192,7 +192,7 @@ void Arm64Jit::FlushPrefixV() { } void Arm64Jit::ClearCache() { - INFO_LOG(JIT, "ARM64Jit: Clearing the cache!"); + INFO_LOG(Log::JIT, "ARM64Jit: Clearing the cache!"); blocks.Clear(); ClearCodeSpace(jitStartOffset); FlushIcacheSection(region + jitStartOffset, region + region_size - jitStartOffset); @@ -207,10 +207,10 @@ void Arm64Jit::InvalidateCacheAt(u32 em_address, int length) { void Arm64Jit::EatInstruction(MIPSOpcode op) { MIPSInfo info = MIPSGetInfo(op); if (info & DELAYSLOT) { - ERROR_LOG_REPORT_ONCE(ateDelaySlot, JIT, "Ate a branch op."); + ERROR_LOG_REPORT_ONCE(ateDelaySlot, Log::JIT, "Ate a branch op."); } if (js.inDelaySlot) { - ERROR_LOG_REPORT_ONCE(ateInDelaySlot, JIT, "Ate an instruction inside a delay slot."); + ERROR_LOG_REPORT_ONCE(ateInDelaySlot, Log::JIT, "Ate an instruction inside a delay slot."); } CheckJitBreakpoint(GetCompilerPC() + 4, 0); @@ -244,7 +244,7 @@ void Arm64Jit::CompileDelaySlot(int flags) { void Arm64Jit::Compile(u32 em_address) { PROFILE_THIS_SCOPE("jitc"); if (GetSpaceLeft() < 0x10000 || blocks.IsFull()) { - INFO_LOG(JIT, "Space left: %d", (int)GetSpaceLeft()); + INFO_LOG(Log::JIT, "Space left: %d", (int)GetSpaceLeft()); ClearCache(); } @@ -263,7 +263,7 @@ void Arm64Jit::Compile(u32 em_address) { bool cleanSlate = false; if (js.hasSetRounding && !js.lastSetRounding) { - WARN_LOG(JIT, "Detected rounding mode usage, rebuilding jit with checks"); + WARN_LOG(Log::JIT, "Detected rounding mode usage, rebuilding jit with checks"); // Won't loop, since hasSetRounding is only ever set to 1. js.lastSetRounding = js.hasSetRounding; cleanSlate = true; @@ -271,7 +271,7 @@ void Arm64Jit::Compile(u32 em_address) { // Drat. The VFPU hit an uneaten prefix at the end of a block. if (js.startDefaultPrefix && js.MayHavePrefix()) { - WARN_LOG_REPORT(JIT, "An uneaten prefix at end of block: %08x", GetCompilerPC() - 4); + WARN_LOG_REPORT(Log::JIT, "An uneaten prefix at end of block: %08x", GetCompilerPC() - 4); js.LogPrefix(); // Let's try that one more time. We won't get back here because we toggled the value. @@ -387,16 +387,16 @@ const u8 *Arm64Jit::DoJit(u32 em_address, JitBlock *b) { char temp[256]; if (logBlocks > 0 && dontLogBlocks == 0) { - INFO_LOG(JIT, "=============== mips %d ===============", blocks.GetNumBlocks()); + INFO_LOG(Log::JIT, "=============== mips %d ===============", blocks.GetNumBlocks()); for (u32 cpc = em_address; cpc != GetCompilerPC() + 4; cpc += 4) { MIPSDisAsm(Memory::Read_Opcode_JIT(cpc), cpc, temp, sizeof(temp), true); - INFO_LOG(JIT, "M: %08x %s", cpc, temp); + INFO_LOG(Log::JIT, "M: %08x %s", cpc, temp); } } b->codeSize = GetCodePtr() - b->normalEntry; if (logBlocks > 0 && dontLogBlocks == 0) { - INFO_LOG(JIT, "=============== ARM (%d instructions -> %d bytes) ===============", js.numInstructions, b->codeSize); + INFO_LOG(Log::JIT, "=============== ARM (%d instructions -> %d bytes) ===============", js.numInstructions, b->codeSize); DisassembleArm64Print(b->normalEntry, GetCodePtr() - b->normalEntry); } if (logBlocks > 0) @@ -470,7 +470,7 @@ bool Arm64Jit::DescribeCodePtr(const u8 *ptr, std::string &name) { void Arm64Jit::Comp_RunBlock(MIPSOpcode op) { // This shouldn't be necessary, the dispatcher should catch us before we get here. - ERROR_LOG(JIT, "Comp_RunBlock should never be reached!"); + ERROR_LOG(Log::JIT, "Comp_RunBlock should never be reached!"); } void Arm64Jit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) { @@ -562,7 +562,7 @@ void Arm64Jit::Comp_ReplacementFunc(MIPSOpcode op) const ReplacementTableEntry *entry = GetReplacementFunc(index); if (!entry) { - ERROR_LOG_REPORT_ONCE(replFunc, HLE, "Invalid replacement op %08x at %08x", op.encoding, js.compilerPC); + ERROR_LOG_REPORT_ONCE(replFunc, Log::HLE, "Invalid replacement op %08x at %08x", op.encoding, js.compilerPC); // TODO: What should we do here? We're way off in the weeds probably. return; } @@ -631,7 +631,7 @@ void Arm64Jit::Comp_ReplacementFunc(MIPSOpcode op) js.compiling = false; } } else { - ERROR_LOG(HLE, "Replacement function %s has neither jit nor regular impl", entry->name); + ERROR_LOG(Log::HLE, "Replacement function %s has neither jit nor regular impl", entry->name); } } diff --git a/Core/MIPS/ARM64/Arm64RegCache.cpp b/Core/MIPS/ARM64/Arm64RegCache.cpp index 7dc2ba1ddf..0dc7f8c999 100644 --- a/Core/MIPS/ARM64/Arm64RegCache.cpp +++ b/Core/MIPS/ARM64/Arm64RegCache.cpp @@ -150,7 +150,7 @@ bool Arm64RegCache::IsMappedAsPointer(MIPSGPReg mipsReg) { return ar[mr[mipsReg].reg].pointerified; } else if (mr[mipsReg].loc == ML_ARMREG_IMM) { if (ar[mr[mipsReg].reg].pointerified) { - ERROR_LOG(JIT, "Really shouldn't be pointerified here"); + ERROR_LOG(Log::JIT, "Really shouldn't be pointerified here"); } } else if (mr[mipsReg].loc == ML_ARMREG_AS_PTR) { return true; @@ -164,7 +164,7 @@ void Arm64RegCache::MarkDirty(ARM64Reg reg) { void Arm64RegCache::SetRegImm(ARM64Reg reg, u64 imm) { if (reg == INVALID_REG) { - ERROR_LOG(JIT, "SetRegImm to invalid register: at %08x", js_->compilerPC); + ERROR_LOG(Log::JIT, "SetRegImm to invalid register: at %08x", js_->compilerPC); return; } // On ARM64, at least Cortex A57, good old MOVT/MOVW (MOVK in 64-bit) is really fast. @@ -174,7 +174,7 @@ void Arm64RegCache::SetRegImm(ARM64Reg reg, u64 imm) { void Arm64RegCache::MapRegTo(ARM64Reg reg, MIPSGPReg mipsReg, int mapFlags) { if (mr[mipsReg].isStatic) { - ERROR_LOG(JIT, "Cannot MapRegTo static register %d", mipsReg); + ERROR_LOG(Log::JIT, "Cannot MapRegTo static register %d", mipsReg); return; } ar[reg].isDirty = (mapFlags & MAP_DIRTY) ? true : false; @@ -193,7 +193,7 @@ void Arm64RegCache::MapRegTo(ARM64Reg reg, MIPSGPReg mipsReg, int mapFlags) { { int offset = GetMipsRegOffset(mipsReg); ARM64Reg loadReg = reg; - // INFO_LOG(JIT, "MapRegTo %d mips: %d offset %d", (int)reg, mipsReg, offset); + // INFO_LOG(Log::JIT, "MapRegTo %d mips: %d offset %d", (int)reg, mipsReg, offset); if (mipsReg == MIPS_REG_LO) { loadReg = EncodeRegTo64(loadReg); } @@ -261,7 +261,7 @@ allocate: } // Uh oh, we have all of them spilllocked.... - ERROR_LOG_REPORT(JIT, "Out of spillable registers at PC %08x!!!", mips_->pc); + ERROR_LOG_REPORT(Log::JIT, "Out of spillable registers at PC %08x!!!", mips_->pc); return INVALID_REG; } @@ -340,12 +340,12 @@ ARM64Reg Arm64RegCache::GetAndLockTempR() { // round robin or FIFO or something. ARM64Reg Arm64RegCache::MapReg(MIPSGPReg mipsReg, int mapFlags) { if (mipsReg == MIPS_REG_HI) { - ERROR_LOG_REPORT(JIT, "Cannot map HI in Arm64RegCache"); + ERROR_LOG_REPORT(Log::JIT, "Cannot map HI in Arm64RegCache"); return INVALID_REG; } if (mipsReg == MIPS_REG_INVALID) { - ERROR_LOG(JIT, "Cannot map invalid register"); + ERROR_LOG(Log::JIT, "Cannot map invalid register"); return INVALID_REG; } @@ -353,7 +353,7 @@ ARM64Reg Arm64RegCache::MapReg(MIPSGPReg mipsReg, int mapFlags) { if (mr[mipsReg].isStatic) { if (armReg == INVALID_REG) { - ERROR_LOG(JIT, "MapReg on statically mapped reg %d failed - armReg got lost", mipsReg); + ERROR_LOG(Log::JIT, "MapReg on statically mapped reg %d failed - armReg got lost", mipsReg); } if (mr[mipsReg].loc == ML_IMM) { // Back into the register, with or without the imm value. @@ -386,7 +386,7 @@ ARM64Reg Arm64RegCache::MapReg(MIPSGPReg mipsReg, int mapFlags) { // with that flag immediately writes a "known" value to the register. if (mr[mipsReg].loc == ML_ARMREG || mr[mipsReg].loc == ML_ARMREG_IMM) { if (ar[armReg].mipsReg != mipsReg) { - ERROR_LOG_REPORT(JIT, "Register mapping out of sync! %i", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Register mapping out of sync! %i", mipsReg); } if (mapFlags & MAP_DIRTY) { // Mapping dirty means the old imm value is invalid. @@ -450,7 +450,7 @@ Arm64Gen::ARM64Reg Arm64RegCache::MapRegAsPointer(MIPSGPReg reg) { ar[a].pointerified = true; } } else { - ERROR_LOG(JIT, "MapRegAsPointer : MapReg failed to allocate a register?"); + ERROR_LOG(Log::JIT, "MapRegAsPointer : MapReg failed to allocate a register?"); } return retval; } @@ -506,18 +506,18 @@ void Arm64RegCache::MapDirtyDirtyInIn(MIPSGPReg rd1, MIPSGPReg rd2, MIPSGPReg rs void Arm64RegCache::FlushArmReg(ARM64Reg r) { if (r == INVALID_REG) { - ERROR_LOG(JIT, "FlushArmReg called on invalid register %d", r); + ERROR_LOG(Log::JIT, "FlushArmReg called on invalid register %d", r); return; } if (ar[r].mipsReg == MIPS_REG_INVALID) { // Nothing to do, reg not mapped. if (ar[r].isDirty) { - ERROR_LOG_REPORT(JIT, "Dirty but no mipsreg?"); + ERROR_LOG_REPORT(Log::JIT, "Dirty but no mipsreg?"); } return; } if (mr[ar[r].mipsReg].isStatic) { - ERROR_LOG(JIT, "Cannot FlushArmReg a statically mapped register"); + ERROR_LOG(Log::JIT, "Cannot FlushArmReg a statically mapped register"); return; } auto &mreg = mr[ar[r].mipsReg]; @@ -603,7 +603,7 @@ ARM64Reg Arm64RegCache::ARM64RegForFlush(MIPSGPReg r) { case ML_ARMREG: case ML_ARMREG_IMM: if (mr[r].reg == INVALID_REG) { - ERROR_LOG_REPORT(JIT, "ARM64RegForFlush: MipsReg %d had bad ArmReg", r); + ERROR_LOG_REPORT(Log::JIT, "ARM64RegForFlush: MipsReg %d had bad ArmReg", r); return INVALID_REG; } // No need to flush if it's zero or not dirty. @@ -622,14 +622,14 @@ ARM64Reg Arm64RegCache::ARM64RegForFlush(MIPSGPReg r) { return INVALID_REG; default: - ERROR_LOG_REPORT(JIT, "ARM64RegForFlush: MipsReg %d with invalid location %d", r, mr[r].loc); + ERROR_LOG_REPORT(Log::JIT, "ARM64RegForFlush: MipsReg %d with invalid location %d", r, mr[r].loc); return INVALID_REG; } } void Arm64RegCache::FlushR(MIPSGPReg r) { if (mr[r].isStatic) { - ERROR_LOG(JIT, "Cannot flush static reg %d", r); + ERROR_LOG(Log::JIT, "Cannot flush static reg %d", r); return; } @@ -683,7 +683,7 @@ void Arm64RegCache::FlushR(MIPSGPReg r) { break; default: - ERROR_LOG_REPORT(JIT, "FlushR: MipsReg %d with invalid location %d", r, mr[r].loc); + ERROR_LOG_REPORT(Log::JIT, "FlushR: MipsReg %d with invalid location %d", r, mr[r].loc); break; } if (r == MIPS_REG_ZERO) { @@ -753,7 +753,7 @@ void Arm64RegCache::FlushAll() { } else if (mr[i].loc == ML_ARMREG_IMM) { // The register already contains the immediate. if (ar[armReg].pointerified) { - ERROR_LOG(JIT, "ML_ARMREG_IMM but pointerified. Wrong."); + ERROR_LOG(Log::JIT, "ML_ARMREG_IMM but pointerified. Wrong."); ar[armReg].pointerified = false; } mr[i].loc = ML_ARMREG; @@ -762,7 +762,7 @@ void Arm64RegCache::FlushAll() { mr[i].loc = ML_ARMREG; } if (i != MIPS_REG_ZERO && mr[i].reg == INVALID_REG) { - ERROR_LOG(JIT, "ARM reg of static %i is invalid", i); + ERROR_LOG(Log::JIT, "ARM reg of static %i is invalid", i); continue; } } else { @@ -785,18 +785,18 @@ void Arm64RegCache::FlushAll() { // Sanity check for (int i = 0; i < NUM_ARMREG; i++) { if (ar[i].mipsReg != MIPS_REG_INVALID && mr[ar[i].mipsReg].isStatic == false) { - ERROR_LOG_REPORT(JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); } } } void Arm64RegCache::SetImm(MIPSGPReg r, u64 immVal) { if (r == MIPS_REG_HI) { - ERROR_LOG_REPORT(JIT, "Cannot set HI imm in Arm64RegCache"); + ERROR_LOG_REPORT(Log::JIT, "Cannot set HI imm in Arm64RegCache"); return; } if (r == MIPS_REG_ZERO && immVal != 0) { - ERROR_LOG_REPORT(JIT, "Trying to set immediate %08x to r0 at %08x", (u32)immVal, compilerPC_); + ERROR_LOG_REPORT(Log::JIT, "Trying to set immediate %08x to r0 at %08x", (u32)immVal, compilerPC_); return; } @@ -846,7 +846,7 @@ u64 Arm64RegCache::GetImm(MIPSGPReg r) const { if (r == MIPS_REG_ZERO) return 0; if (mr[r].loc != ML_IMM && mr[r].loc != ML_ARMREG_IMM) { - ERROR_LOG_REPORT(JIT, "Trying to get imm from non-imm register %i", r); + ERROR_LOG_REPORT(Log::JIT, "Trying to get imm from non-imm register %i", r); } return mr[r].imm; } @@ -864,7 +864,7 @@ int Arm64RegCache::GetMipsRegOffset(MIPSGPReg r) { case MIPS_REG_VFPUCC: return offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_CC]); default: - ERROR_LOG_REPORT(JIT, "bad mips register %i", r); + ERROR_LOG_REPORT(Log::JIT, "bad mips register %i", r); return 0; // or what? } } @@ -901,7 +901,7 @@ ARM64Reg Arm64RegCache::R(MIPSGPReg mipsReg) { if (mr[mipsReg].loc == ML_ARMREG || mr[mipsReg].loc == ML_ARMREG_IMM) { return mr[mipsReg].reg; } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_); return INVALID_REG; // BAAAD } } @@ -914,11 +914,11 @@ ARM64Reg Arm64RegCache::RPtr(MIPSGPReg mipsReg) { if (ar[a].pointerified) { return (ARM64Reg)mr[mipsReg].reg; } else { - ERROR_LOG(JIT, "Tried to use a non-pointer register as a pointer"); + ERROR_LOG(Log::JIT, "Tried to use a non-pointer register as a pointer"); return INVALID_REG; } } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_); return INVALID_REG; // BAAAD } } diff --git a/Core/MIPS/ARM64/Arm64RegCacheFPU.cpp b/Core/MIPS/ARM64/Arm64RegCacheFPU.cpp index 6771713652..4b0fd4d502 100644 --- a/Core/MIPS/ARM64/Arm64RegCacheFPU.cpp +++ b/Core/MIPS/ARM64/Arm64RegCacheFPU.cpp @@ -110,9 +110,9 @@ bool Arm64RegCacheFPU::IsInRAM(MIPSReg r) { } ARM64Reg Arm64RegCacheFPU::MapReg(MIPSReg mipsReg, int mapFlags) { - // INFO_LOG(JIT, "FPR MapReg: %i flags=%i", mipsReg, mapFlags); + // INFO_LOG(Log::JIT, "FPR MapReg: %i flags=%i", mipsReg, mapFlags); if (jo_->useASIMDVFPU && mipsReg >= 32) { - ERROR_LOG(JIT, "Cannot map VFPU registers to ARM VFP registers in NEON mode. PC=%08x", js_->compilerPC); + ERROR_LOG(Log::JIT, "Cannot map VFPU registers to ARM VFP registers in NEON mode. PC=%08x", js_->compilerPC); return S0; } @@ -122,12 +122,12 @@ ARM64Reg Arm64RegCacheFPU::MapReg(MIPSReg mipsReg, int mapFlags) { // with that flag immediately writes a "known" value to the register. if (mr[mipsReg].loc == ML_ARMREG) { if (ar[mr[mipsReg].reg].mipsReg != mipsReg) { - ERROR_LOG(JIT, "Reg mapping out of sync! MR %i", mipsReg); + ERROR_LOG(Log::JIT, "Reg mapping out of sync! MR %i", mipsReg); } if (mapFlags & MAP_DIRTY) { ar[mr[mipsReg].reg].isDirty = true; } - //INFO_LOG(JIT, "Already mapped %i to %i", mipsReg, mr[mipsReg].reg); + //INFO_LOG(Log::JIT, "Already mapped %i to %i", mipsReg, mr[mipsReg].reg); return (ARM64Reg)(mr[mipsReg].reg + S0); } @@ -151,7 +151,7 @@ allocate: ar[reg].mipsReg = mipsReg; mr[mipsReg].loc = ML_ARMREG; mr[mipsReg].reg = reg; - //INFO_LOG(JIT, "Mapped %i to %i", mipsReg, mr[mipsReg].reg); + //INFO_LOG(Log::JIT, "Mapped %i to %i", mipsReg, mr[mipsReg].reg); return (ARM64Reg)(reg + S0); } } @@ -175,7 +175,7 @@ allocate: } // Uh oh, we have all them spilllocked.... - ERROR_LOG(JIT, "Out of spillable registers at PC %08x!!!", js_->compilerPC); + ERROR_LOG(Log::JIT, "Out of spillable registers at PC %08x!!!", js_->compilerPC); return INVALID_REG; } @@ -289,14 +289,14 @@ void Arm64RegCacheFPU::FlushArmReg(ARM64Reg r) { } if (ar[reg].mipsReg != -1) { if (ar[reg].isDirty && mr[ar[reg].mipsReg].loc == ML_ARMREG){ - //INFO_LOG(JIT, "Flushing ARM reg %i", reg); + //INFO_LOG(Log::JIT, "Flushing ARM reg %i", reg); fp_->STR(32, INDEX_UNSIGNED, r, CTXREG, GetMipsRegOffset(ar[reg].mipsReg)); } // IMMs won't be in an ARM reg. mr[ar[reg].mipsReg].loc = ML_MEM; mr[ar[reg].mipsReg].reg = INVALID_REG; } else { - ERROR_LOG(JIT, "Dirty but no mipsreg?"); + ERROR_LOG(Log::JIT, "Dirty but no mipsreg?"); } ar[reg].mipsReg = -1; ar[reg].isDirty = false; @@ -312,12 +312,12 @@ void Arm64RegCacheFPU::FlushR(MIPSReg r) { case ML_IMM: // IMM is always "dirty". // IMM is not allowed for FP (yet). - ERROR_LOG(JIT, "Imm in FP register?"); + ERROR_LOG(Log::JIT, "Imm in FP register?"); break; case ML_ARMREG: if (mr[r].reg == INVALID_REG) { - ERROR_LOG(JIT, "FlushR: MipsReg had bad ArmReg"); + ERROR_LOG(Log::JIT, "FlushR: MipsReg had bad ArmReg"); } FlushArmReg((ARM64Reg)(S0 + mr[r].reg)); break; @@ -337,12 +337,12 @@ Arm64Gen::ARM64Reg Arm64RegCacheFPU::ARM64RegForFlush(int r) { case ML_IMM: // IMM is always "dirty". // IMM is not allowed for FP (yet). - ERROR_LOG(JIT, "Imm in FP register?"); + ERROR_LOG(Log::JIT, "Imm in FP register?"); return INVALID_REG; case ML_ARMREG: if (mr[r].reg == INVALID_REG) { - ERROR_LOG_REPORT(JIT, "ARM64RegForFlush: MipsReg %d had bad ArmReg", r); + ERROR_LOG_REPORT(Log::JIT, "ARM64RegForFlush: MipsReg %d had bad ArmReg", r); return INVALID_REG; } // No need to flush if it's not dirty. @@ -355,7 +355,7 @@ Arm64Gen::ARM64Reg Arm64RegCacheFPU::ARM64RegForFlush(int r) { return INVALID_REG; default: - ERROR_LOG_REPORT(JIT, "ARM64RegForFlush: MipsReg %d with invalid location %d", r, mr[r].loc); + ERROR_LOG_REPORT(Log::JIT, "ARM64RegForFlush: MipsReg %d with invalid location %d", r, mr[r].loc); return INVALID_REG; } } @@ -399,7 +399,7 @@ void Arm64RegCacheFPU::FlushAll() { if (ar[a].isDirty) { if (m == -1) { - INFO_LOG(JIT, "ARM reg %d is dirty but has no mipsreg", a); + INFO_LOG(Log::JIT, "ARM reg %d is dirty but has no mipsreg", a); continue; } @@ -422,7 +422,7 @@ void Arm64RegCacheFPU::FlushAll() { // Sanity check for (int i = 0; i < numARMFpuReg_; i++) { if (ar[i].mipsReg != -1) { - ERROR_LOG(JIT, "Flush fail: ar[%d].mipsReg=%d", i, ar[i].mipsReg); + ERROR_LOG(Log::JIT, "Flush fail: ar[%d].mipsReg=%d", i, ar[i].mipsReg); } } pendingFlush = false; @@ -433,12 +433,12 @@ void Arm64RegCacheFPU::DiscardR(MIPSReg r) { case ML_IMM: // IMM is always "dirty". // IMM is not allowed for FP (yet). - ERROR_LOG(JIT, "Imm in FP register?"); + ERROR_LOG(Log::JIT, "Imm in FP register?"); break; case ML_ARMREG: if (mr[r].reg == INVALID_REG) { - ERROR_LOG(JIT, "DiscardR: MipsReg had bad ArmReg"); + ERROR_LOG(Log::JIT, "DiscardR: MipsReg had bad ArmReg"); } else { // Note that we DO NOT write it back here. That's the whole point of Discard. ar[mr[r].reg].isDirty = false; @@ -466,7 +466,7 @@ bool Arm64RegCacheFPU::IsTempX(ARM64Reg r) const { int Arm64RegCacheFPU::GetTempR() { if (jo_->useASIMDVFPU) { - ERROR_LOG(JIT, "VFP temps not allowed in NEON mode"); + ERROR_LOG(Log::JIT, "VFP temps not allowed in NEON mode"); return 0; } pendingFlush = true; @@ -477,7 +477,7 @@ int Arm64RegCacheFPU::GetTempR() { } } - ERROR_LOG(CPU, "Out of temp regs! Might need to DiscardR() some"); + ERROR_LOG(Log::CPU, "Out of temp regs! Might need to DiscardR() some"); _assert_msg_(false, "Regcache ran out of temp regs, might need to DiscardR() some."); return -1; } @@ -485,7 +485,7 @@ int Arm64RegCacheFPU::GetTempR() { int Arm64RegCacheFPU::GetMipsRegOffset(MIPSReg r) { // These are offsets within the MIPSState structure. First there are the GPRS, then FPRS, then the "VFPURs", then the VFPU ctrls. if (r < 0 || r > 32 + 128 + NUM_TEMPS) { - ERROR_LOG(JIT, "bad mips register %i, out of range", r); + ERROR_LOG(Log::JIT, "bad mips register %i, out of range", r); return 0; // or what? } @@ -519,11 +519,11 @@ ARM64Reg Arm64RegCacheFPU::R(int mipsReg) { return (ARM64Reg)(mr[mipsReg].reg + S0); } else { if (mipsReg < 32) { - ERROR_LOG(JIT, "FReg %i not in ARM reg. compilerPC = %08x : %s", mipsReg, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); + ERROR_LOG(Log::JIT, "FReg %i not in ARM reg. compilerPC = %08x : %s", mipsReg, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); } else if (mipsReg < 32 + 128) { - ERROR_LOG(JIT, "VReg %i not in ARM reg. compilerPC = %08x : %s", mipsReg - 32, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); + ERROR_LOG(Log::JIT, "VReg %i not in ARM reg. compilerPC = %08x : %s", mipsReg - 32, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); } else { - ERROR_LOG(JIT, "Tempreg %i not in ARM reg. compilerPC = %08x : %s", mipsReg - 128 - 32, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); + ERROR_LOG(Log::JIT, "Tempreg %i not in ARM reg. compilerPC = %08x : %s", mipsReg - 128 - 32, js_->compilerPC, MIPSDisasmAt(js_->compilerPC).c_str()); } return INVALID_REG; // BAAAD } diff --git a/Core/MIPS/IR/IRCompALU.cpp b/Core/MIPS/IR/IRCompALU.cpp index e8fe1c46b6..d3813bacad 100644 --- a/Core/MIPS/IR/IRCompALU.cpp +++ b/Core/MIPS/IR/IRCompALU.cpp @@ -192,8 +192,14 @@ void IRFrontend::CompShiftVar(MIPSOpcode op, IROp shiftOp) { MIPSGPReg rd = _RD; MIPSGPReg rt = _RT; MIPSGPReg rs = _RS; - ir.Write(IROp::AndConst, IRTEMP_0, rs, ir.AddConstant(31)); - ir.Write(shiftOp, rd, rt, IRTEMP_0); + + if (opts.optimizeForInterpreter) { + // The interpreter already masks where needed, don't need to generate extra ops. + ir.Write(shiftOp, rd, rt, rs); + } else { + ir.Write(IROp::AndConst, IRTEMP_0, rs, ir.AddConstant(31)); + ir.Write(shiftOp, rd, rt, IRTEMP_0); + } } void IRFrontend::Comp_ShiftType(MIPSOpcode op) { @@ -246,11 +252,24 @@ void IRFrontend::Comp_Special3(MIPSOpcode op) { case 0x4: //ins { + // TODO: Might be good to support natively in the interpreter. Though, would have to + // abuse a register as a constant u32 sourcemask = mask >> pos; u32 destmask = ~(sourcemask << pos); - ir.Write(IROp::AndConst, IRTEMP_0, rs, ir.AddConstant(sourcemask)); - if (pos != 0) { - ir.Write(IROp::ShlImm, IRTEMP_0, IRTEMP_0, pos); + + if (size != 32) { + // Need to use the sourcemask. + ir.Write(IROp::AndConst, IRTEMP_0, rs, ir.AddConstant(sourcemask)); + if (pos != 0) { + ir.Write(IROp::ShlImm, IRTEMP_0, IRTEMP_0, pos); + } + } else { + // If the shl takes care of the sourcemask, don't need to and. + if (pos != 0) { + ir.Write(IROp::ShlImm, IRTEMP_0, rs, pos); + } else { + ir.Write(IROp::Mov, IRTEMP_0, rs); + } } ir.Write(IROp::AndConst, rt, rt, ir.AddConstant(destmask)); ir.Write(IROp::Or, rt, rt, IRTEMP_0); diff --git a/Core/MIPS/IR/IRCompBranch.cpp b/Core/MIPS/IR/IRCompBranch.cpp index 49f0f7d5eb..b43d9d2f9f 100644 --- a/Core/MIPS/IR/IRCompBranch.cpp +++ b/Core/MIPS/IR/IRCompBranch.cpp @@ -56,7 +56,7 @@ namespace MIPSComp void IRFrontend::BranchRSRTComp(MIPSOpcode op, IRComparison cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -123,7 +123,7 @@ void IRFrontend::BranchRSRTComp(MIPSOpcode op, IRComparison cc, bool likely) { void IRFrontend::BranchRSZeroComp(MIPSOpcode op, IRComparison cc, bool andLink, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -212,7 +212,7 @@ void IRFrontend::Comp_RelBranchRI(MIPSOpcode op) { // If likely is set, discard the branch slot if NOT taken. void IRFrontend::BranchFPFlag(MIPSOpcode op, IRComparison cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -266,7 +266,7 @@ void IRFrontend::Comp_FPUBranch(MIPSOpcode op) { // If likely is set, discard the branch slot if NOT taken. void IRFrontend::BranchVFPUFlag(MIPSOpcode op, IRComparison cc, bool likely) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -324,7 +324,7 @@ void IRFrontend::Comp_VBranch(MIPSOpcode op) { void IRFrontend::Comp_Jump(MIPSOpcode op) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } @@ -337,7 +337,7 @@ void IRFrontend::Comp_Jump(MIPSOpcode op) { if (js.preloading) js.cancel = true; else - ERROR_LOG_REPORT(JIT, "Jump to invalid address: %08x", targetAddr); + ERROR_LOG_REPORT(Log::JIT, "Jump to invalid address: %08x", targetAddr); // TODO: Mark this block dirty or something? May be indication it will be changed by imports. // Continue so the block gets completed and crashes properly. } @@ -371,7 +371,7 @@ void IRFrontend::Comp_Jump(MIPSOpcode op) { void IRFrontend::Comp_JumpReg(MIPSOpcode op) { if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } MIPSGPReg rs = _RS; diff --git a/Core/MIPS/IR/IRCompFPU.cpp b/Core/MIPS/IR/IRCompFPU.cpp index e83f3a709f..ca603199ea 100644 --- a/Core/MIPS/IR/IRCompFPU.cpp +++ b/Core/MIPS/IR/IRCompFPU.cpp @@ -223,6 +223,7 @@ void IRFrontend::Comp_mxc1(MIPSOpcode op) { // Set rounding mode RestoreRoundingMode(); ir.Write(IROp::FpCtrlFromReg, 0, rt); + // TODO: Do the UpdateRoundingMode check at runtime? UpdateRoundingMode(); ApplyRoundingMode(); } else { diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 6f44c2ccdd..5507d6f041 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -177,7 +177,7 @@ namespace MIPSComp { js.prefixDFlag = JitState::PREFIX_KNOWN_DIRTY; break; default: - ERROR_LOG(CPU, "VPFX - bad regnum %i : data=%08x", regnum, data); + ERROR_LOG(Log::CPU, "VPFX - bad regnum %i : data=%08x", regnum, data); break; } } @@ -969,6 +969,11 @@ namespace MIPSComp { void IRFrontend::Comp_VV2Op(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); + + if (js.HasUnknownPrefix()) { + DISABLE; + } + int optype = (op >> 16) & 0x1f; if (optype == 0) { if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op)) diff --git a/Core/MIPS/IR/IRFrontend.cpp b/Core/MIPS/IR/IRFrontend.cpp index 2270484391..6c8e59fa38 100644 --- a/Core/MIPS/IR/IRFrontend.cpp +++ b/Core/MIPS/IR/IRFrontend.cpp @@ -28,6 +28,9 @@ #include "Core/MIPS/IR/IRRegCache.h" #include "Core/MIPS/IR/IRPassSimplify.h" #include "Core/MIPS/IR/IRInterpreter.h" +#include "Core/MIPS/MIPSTracer.h" + +#include namespace MIPSComp { @@ -94,10 +97,10 @@ void IRFrontend::FlushPrefixV() { void IRFrontend::EatInstruction(MIPSOpcode op) { MIPSInfo info = MIPSGetInfo(op); if (info & DELAYSLOT) { - ERROR_LOG_REPORT_ONCE(ateDelaySlot, JIT, "Ate a branch op."); + ERROR_LOG_REPORT_ONCE(ateDelaySlot, Log::JIT, "Ate a branch op."); } if (js.inDelaySlot) { - ERROR_LOG_REPORT_ONCE(ateInDelaySlot, JIT, "Ate an instruction inside a delay slot."); + ERROR_LOG_REPORT_ONCE(ateInDelaySlot, Log::JIT, "Ate an instruction inside a delay slot."); } CheckBreakpoint(GetCompilerPC() + 4); @@ -117,7 +120,7 @@ void IRFrontend::CompileDelaySlot() { bool IRFrontend::CheckRounding(u32 blockAddress) { bool cleanSlate = false; if (js.hasSetRounding && !js.lastSetRounding) { - WARN_LOG(JIT, "Detected rounding mode usage, rebuilding jit with checks"); + WARN_LOG(Log::JIT, "Detected rounding mode usage, rebuilding jit with checks"); // Won't loop, since hasSetRounding is only ever set to 1. js.lastSetRounding = js.hasSetRounding; cleanSlate = true; @@ -125,7 +128,7 @@ bool IRFrontend::CheckRounding(u32 blockAddress) { // Drat. The VFPU hit an uneaten prefix at the end of a block. if (js.startDefaultPrefix && js.MayHavePrefix()) { - WARN_LOG_REPORT(JIT, "An uneaten prefix at end of block for %08x", blockAddress); + WARN_LOG_REPORT(Log::JIT, "An uneaten prefix at end of block for %08x", blockAddress); logBlocks = 1; js.LogPrefix(); @@ -133,17 +136,15 @@ bool IRFrontend::CheckRounding(u32 blockAddress) { js.startDefaultPrefix = false; cleanSlate = true; } - return cleanSlate; } - void IRFrontend::Comp_ReplacementFunc(MIPSOpcode op) { int index = op.encoding & MIPS_EMUHACK_VALUE_MASK; const ReplacementTableEntry *entry = GetReplacementFunc(index); if (!entry) { - ERROR_LOG(HLE, "Invalid replacement op %08x", op.encoding); + ERROR_LOG(Log::HLE, "Invalid replacement op %08x", op.encoding); return; } @@ -180,7 +181,7 @@ void IRFrontend::Comp_ReplacementFunc(MIPSOpcode op) { js.compiling = false; } } else { - ERROR_LOG(HLE, "Replacement function %s has neither jit nor regular impl", entry->name); + ERROR_LOG(Log::HLE, "Replacement function %s has neither jit nor regular impl", entry->name); } } @@ -277,54 +278,70 @@ void IRFrontend::DoJit(u32 em_address, std::vector &instructions, u32 &m IRWriter simplified; IRWriter *code = &ir; if (!js.hadBreakpoints) { - static const IRPassFunc passes[] = { + std::vector passes{ &ApplyMemoryValidation, &RemoveLoadStoreLeftRight, &OptimizeFPMoves, &PropagateConstants, &PurgeTemps, &ReduceVec4Flush, + &OptimizeLoadsAfterStores, // &ReorderLoadStore, // &MergeLoadStore, // &ThreeOpToTwoOp, }; - if (IRApplyPasses(passes, ARRAY_SIZE(passes), ir, simplified, opts)) + + if (opts.optimizeForInterpreter) { + // Add special passes here. + passes.push_back(&OptimizeForInterpreter); + } + if (IRApplyPasses(passes.data(), passes.size(), ir, simplified, opts)) logBlocks = 1; code = &simplified; //if (ir.GetInstructions().size() >= 24) // logBlocks = 1; } - instructions = code->GetInstructions(); + if (!mipsTracer.tracing_enabled) { + instructions = code->GetInstructions(); + } + else { + std::vector block_instructions = code->GetInstructions(); + instructions.reserve(block_instructions.capacity()); + // The first instruction is "Downcount" + instructions.push_back(block_instructions.front()); + instructions.push_back({ IROp::LogIRBlock, 0, 0, 0, 0 }); + std::copy(block_instructions.begin() + 1, block_instructions.end(), std::back_inserter(instructions)); + } if (logBlocks > 0 && dontLogBlocks == 0) { char temp2[256]; - NOTICE_LOG(JIT, "=============== mips %08x ===============", em_address); + NOTICE_LOG(Log::JIT, "=============== mips %08x ===============", em_address); for (u32 cpc = em_address; cpc != GetCompilerPC(); cpc += 4) { temp2[0] = 0; MIPSDisAsm(Memory::Read_Opcode_JIT(cpc), cpc, temp2, sizeof(temp2), true); - NOTICE_LOG(JIT, "M: %08x %s", cpc, temp2); + NOTICE_LOG(Log::JIT, "M: %08x %s", cpc, temp2); } } if (logBlocks > 0 && dontLogBlocks == 0) { - NOTICE_LOG(JIT, "=============== Original IR (%d instructions) ===============", (int)ir.GetInstructions().size()); + NOTICE_LOG(Log::JIT, "=============== Original IR (%d instructions) ===============", (int)ir.GetInstructions().size()); for (size_t i = 0; i < ir.GetInstructions().size(); i++) { char buf[256]; DisassembleIR(buf, sizeof(buf), ir.GetInstructions()[i]); - NOTICE_LOG(JIT, "%s", buf); + NOTICE_LOG(Log::JIT, "%s", buf); } - NOTICE_LOG(JIT, "=============== end ================="); + NOTICE_LOG(Log::JIT, "=============== end ================="); } if (logBlocks > 0 && dontLogBlocks == 0) { - NOTICE_LOG(JIT, "=============== IR (%d instructions) ===============", (int)code->GetInstructions().size()); + NOTICE_LOG(Log::JIT, "=============== IR (%d instructions) ===============", (int)code->GetInstructions().size()); for (size_t i = 0; i < code->GetInstructions().size(); i++) { char buf[256]; DisassembleIR(buf, sizeof(buf), code->GetInstructions()[i]); - NOTICE_LOG(JIT, "%s", buf); + NOTICE_LOG(Log::JIT, "%s", buf); } - NOTICE_LOG(JIT, "=============== end ================="); + NOTICE_LOG(Log::JIT, "=============== end ================="); } if (logBlocks > 0) @@ -335,7 +352,7 @@ void IRFrontend::DoJit(u32 em_address, std::vector &instructions, u32 &m void IRFrontend::Comp_RunBlock(MIPSOpcode op) { // This shouldn't be necessary, the dispatcher should catch us before we get here. - ERROR_LOG(JIT, "Comp_RunBlock should never be reached!"); + ERROR_LOG(Log::JIT, "Comp_RunBlock should never be reached!"); } void IRFrontend::CheckBreakpoint(u32 addr) { diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp index 376f9951b2..13eb16a52f 100644 --- a/Core/MIPS/IR/IRInst.cpp +++ b/Core/MIPS/IR/IRInst.cpp @@ -1,18 +1,25 @@ #include "Common/CommonFuncs.h" +#include "Common/Log.h" #include "Core/MIPS/IR/IRInst.h" #include "Core/MIPS/MIPSDebugInterface.h" +#include "Core/HLE/ReplaceTables.h" // Legend // ====================== // _ = ignore // G = GPR register // C = 32-bit constant from array +// c = 8-bit constant from array // I = immediate value from instruction // F = FPR register, single // V = FPR register, Vec4. Reg number always divisible by 4. // 2 = FPR register, Vec2 (uncommon) // v = Vec4Init constant, chosen by immediate // s = Shuffle immediate (4 2-bit fields, choosing a xyzw shuffle) +// r = Replacement function (in constant field) +// +// WARNING: The IRJit compiler also uses these letters for semantic information! +// So if you add new letters, don't forget to add them to IRNativeRegCacheBase::MappingFromInst. static const IRMeta irMeta[] = { { IROp::Nop, "Nop", "" }, @@ -27,10 +34,13 @@ static const IRMeta irMeta[] = { { IROp::Or, "Or", "GGG" }, { IROp::Xor, "Xor", "GGG" }, { IROp::AddConst, "AddConst", "GGC" }, + { IROp::OptAddConst, "OptAddConst", "GC" }, { IROp::SubConst, "SubConst", "GGC" }, { IROp::AndConst, "AndConst", "GGC" }, { IROp::OrConst, "OrConst", "GGC" }, { IROp::XorConst, "XorConst", "GGC" }, + { IROp::OptAndConst, "OptAndConst", "GC" }, + { IROp::OptOrConst, "OptOrConst", "GC" }, { IROp::Shl, "Shl", "GGG" }, { IROp::Shr, "Shr", "GGG" }, { IROp::Sar, "Sar", "GGG" }, @@ -113,6 +123,8 @@ static const IRMeta irMeta[] = { { IROp::FSatMinus1_1, "FSat(-1 - 1)", "FF" }, { IROp::FMovFromGPR, "FMovFromGPR", "FG" }, { IROp::FMovToGPR, "FMovToGPR", "GF" }, + { IROp::OptFMovToGPRShr8, "OptFMovToGPRShr8", "GF" }, + { IROp::OptFCvtSWFromGPR, "OptFCvtSWFromGPR", "FG" }, { IROp::FpCondFromReg, "FpCondFromReg", "_G" }, { IROp::FpCondToReg, "FpCondToReg", "G" }, { IROp::FpCtrlFromReg, "FpCtrlFromReg", "_G" }, @@ -126,7 +138,7 @@ static const IRMeta irMeta[] = { { IROp::FCmpVfpuAggregate, "FCmpVfpuAggregate", "I" }, { IROp::Vec4Init, "Vec4Init", "Vv" }, { IROp::Vec4Shuffle, "Vec4Shuffle", "VVs" }, - { IROp::Vec4Blend, "Vec4Blend", "VVVC" }, + { IROp::Vec4Blend, "Vec4Blend", "VVVc" }, { IROp::Vec4Mov, "Vec4Mov", "VV" }, { IROp::Vec4Add, "Vec4Add", "VVV" }, { IROp::Vec4Sub, "Vec4Sub", "VVV" }, @@ -165,7 +177,7 @@ static const IRMeta irMeta[] = { { IROp::Break, "Break", "", IRFLAG_EXIT }, { IROp::SetPC, "SetPC", "_G" }, { IROp::SetPCConst, "SetPC", "_C" }, - { IROp::CallReplacement, "CallRepl", "GC", IRFLAG_BARRIER }, + { IROp::CallReplacement, "CallRepl", "Gr", IRFLAG_BARRIER }, { IROp::Breakpoint, "Breakpoint", "_C", IRFLAG_BARRIER }, { IROp::MemoryCheck, "MemoryCheck", "IGC", IRFLAG_BARRIER }, @@ -177,11 +189,16 @@ static const IRMeta irMeta[] = { { IROp::RestoreRoundingMode, "RestoreRoundingMode", "" }, { IROp::ApplyRoundingMode, "ApplyRoundingMode", "" }, { IROp::UpdateRoundingMode, "UpdateRoundingMode", "" }, + + { IROp::LogIRBlock, "LogIRBlock", "" }, }; const IRMeta *metaIndex[256]; +// Is there a way to constexpr this? void InitIR() { + if (metaIndex[0]) + return; for (size_t i = 0; i < ARRAY_SIZE(irMeta); i++) { metaIndex[(int)irMeta[i].op] = &irMeta[i]; } @@ -214,6 +231,11 @@ int IRWriter::AddConstantFloat(float value) { return AddConstant(val); } +void IRWriter::ReplaceConstant(size_t instNumber, u32 newConstant) { + _dbg_assert_(instNumber < insts_.size()); + insts_[instNumber].constant = newConstant; +} + static std::string GetGPRName(int r) { if (r < 32) { return currentDebugMIPS->GetRegName(0, r); @@ -289,10 +311,13 @@ void DisassembleParam(char *buf, int bufSize, u8 param, char type, u32 constant) } break; case 'C': - snprintf(buf, bufSize, "%08x", constant); + snprintf(buf, bufSize, "0x%08x", constant); + break; + case 'c': + snprintf(buf, bufSize, "0x%02x", constant); break; case 'I': - snprintf(buf, bufSize, "%02x", param); + snprintf(buf, bufSize, "0x%02x", param); break; case 'm': snprintf(buf, bufSize, "%d", param); @@ -306,6 +331,16 @@ void DisassembleParam(char *buf, int bufSize, u8 param, char type, u32 constant) case 's': snprintf(buf, bufSize, "%c%c%c%c", xyzw[param & 3], xyzw[(param >> 2) & 3], xyzw[(param >> 4) & 3], xyzw[(param >> 6) & 3]); break; + case 'r': + { + const ReplacementTableEntry *entry = GetReplacementFunc(constant); + if (entry) { + snprintf(buf, bufSize, "%s", entry->name); + } else { + snprintf(buf, bufSize, "(unkn. repl %d)", constant); + } + break; + } case '_': case '\0': buf[0] = 0; diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index e727697d3f..0dbfa67905 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -17,9 +17,10 @@ // even be directly JIT-ed, but the gains will probably be tiny over our older direct // MIPS->target JITs. -enum class IROp : uint8_t { - Nop, +// Ops beginning with "OI" are specialized for IR Interpreter use. These will not be produced +// for the IR JITs. +enum class IROp : uint8_t { SetConst, SetConstF, @@ -35,11 +36,14 @@ enum class IROp : uint8_t { Xor, AddConst, + OptAddConst, SubConst, AndConst, OrConst, XorConst, + OptAndConst, + OptOrConst, Shl, Shr, @@ -134,7 +138,9 @@ enum class IROp : uint8_t { FCvtScaledSW, FMovFromGPR, + OptFCvtSWFromGPR, FMovToGPR, + OptFMovToGPRShr8, FSat0_1, FSatMinus1_1, @@ -230,6 +236,12 @@ enum class IROp : uint8_t { ValidateAddress16, ValidateAddress32, ValidateAddress128, + + // Tracing support. + LogIRBlock, + + Nop, + Bad, }; enum IRComparison { @@ -358,7 +370,7 @@ struct IRInst { }; // Returns the new PC. -u32 IRInterpret(MIPSState *ms, const IRInst *inst, int count); +u32 IRInterpret(MIPSState *ms, const IRInst *inst); // Each IR block gets a constant pool. class IRWriter { @@ -391,6 +403,7 @@ public: void Clear() { insts_.clear(); } + void ReplaceConstant(size_t instNumber, u32 newConstant); const std::vector &GetInstructions() const { return insts_; } @@ -405,6 +418,7 @@ struct IROptions { bool unalignedLoadStoreVec4; bool preferVec4; bool preferVec4Dot; + bool optimizeForInterpreter; }; const IRMeta *GetIRMeta(IROp op); diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index 2590b0ea9a..0d482b485d 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -2,6 +2,7 @@ #include #include "ppsspp_config.h" +#include "Common/BitSet.h" #include "Common/BitScan.h" #include "Common/Common.h" #include "Common/Data/Convert/SmallDataConvert.h" @@ -31,6 +32,7 @@ #include "Core/MIPS/IR/IRInst.h" #include "Core/MIPS/IR/IRInterpreter.h" #include "Core/System.h" +#include "Core/MIPS/MIPSTracer.h" #ifdef mips // Why do MIPS compilers define something so generic? Try to keep defined, at least... @@ -88,33 +90,68 @@ u32 IRRunMemCheck(u32 pc, u32 addr) { return coreState != CORE_RUNNING ? 1 : 0; } -template -u32 RunValidateAddress(u32 pc, u32 addr, u32 isWrite) { - const auto toss = [&](MemoryExceptionType t) { - Core_MemoryException(addr, alignment, pc, t); - return coreState != CORE_RUNNING ? 1 : 0; - }; +void IRApplyRounding(MIPSState *mips) { + u32 fcr1Bits = mips->fcr31 & 0x01000003; + // If these are 0, we just leave things as they are. + if (fcr1Bits) { + int rmode = fcr1Bits & 3; + bool ftz = (fcr1Bits & 0x01000000) != 0; +#if PPSSPP_ARCH(SSE2) + u32 csr = _mm_getcsr() & ~0x6000; + // Translate the rounding mode bits to X86, the same way as in Asm.cpp. + if (rmode & 1) { + rmode ^= 2; + } + csr |= rmode << 13; - if (!Memory::IsValidRange(addr, alignment)) { - MemoryExceptionType t = isWrite == 1 ? MemoryExceptionType::WRITE_WORD : MemoryExceptionType::READ_WORD; - if constexpr (alignment > 4) - t = isWrite ? MemoryExceptionType::WRITE_BLOCK : MemoryExceptionType::READ_BLOCK; - return toss(t); + if (ftz) { + // Flush to zero + csr |= 0x8000; + } + _mm_setcsr(csr); +#elif PPSSPP_ARCH(ARM64) && !PPSSPP_PLATFORM(WINDOWS) + // On ARM64 we need to use inline assembly for a portable solution. + // Unfortunately we don't have this possibility on Windows with MSVC, so ifdeffed out above. + // Note that in the JIT, for fcvts, we use specific conversions. We could use the FCVTS variants + // directly through inline assembly. + u64 fpcr; // not really 64-bit, just to match the register size. + asm volatile ("mrs %0, fpcr" : "=r" (fpcr)); + + // Translate MIPS to ARM rounding mode + static const u8 lookup[4] = {0, 3, 1, 2}; + + fpcr &= ~(3 << 22); // Clear bits [23:22] + fpcr |= (lookup[rmode] << 22); + + if (ftz) { + fpcr |= 1 << 24; + } + // Write back the modified FPCR + asm volatile ("msr fpcr, %0" : : "r" (fpcr)); +#endif } - if constexpr (alignment > 1) - if ((addr & (alignment - 1)) != 0) - return toss(MemoryExceptionType::ALIGNMENT); - return 0; +} + +void IRRestoreRounding() { +#if PPSSPP_ARCH(SSE2) + // TODO: We should avoid this if we didn't apply rounding in the first place. + // In the meantime, clear out FTZ and rounding mode bits. + u32 csr = _mm_getcsr(); + csr &= ~(7 << 13); + _mm_setcsr(csr); +#elif PPSSPP_ARCH(ARM64) && !PPSSPP_PLATFORM(WINDOWS) + u64 fpcr; // not really 64-bit, just to match the regsiter size. + asm volatile ("mrs %0, fpcr" : "=r" (fpcr)); + fpcr &= ~(7 << 22); // Clear bits [23:22] for rounding, 24 for FTZ + // Write back the modified FPCR + asm volatile ("msr fpcr, %0" : : "r" (fpcr)); +#endif } // We cannot use NEON on ARM32 here until we make it a hard dependency. We can, however, on ARM64. -u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { - const IRInst *end = inst + count; - while (inst != end) { +u32 IRInterpret(MIPSState *mips, const IRInst *inst) { + while (true) { switch (inst->op) { - case IROp::Nop: - _assert_(false); - break; case IROp::SetConst: mips->r[inst->dest] = inst->constant; break; @@ -142,20 +179,29 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::AddConst: mips->r[inst->dest] = mips->r[inst->src1] + inst->constant; break; + case IROp::OptAddConst: // For this one, it's worth having a "unary" variant of the above that only needs to read one register param. + mips->r[inst->dest] += inst->constant; + break; case IROp::SubConst: mips->r[inst->dest] = mips->r[inst->src1] - inst->constant; break; case IROp::AndConst: mips->r[inst->dest] = mips->r[inst->src1] & inst->constant; break; + case IROp::OptAndConst: // For this one, it's worth having a "unary" variant of the above that only needs to read one register param. + mips->r[inst->dest] &= inst->constant; + break; case IROp::OrConst: mips->r[inst->dest] = mips->r[inst->src1] | inst->constant; break; + case IROp::OptOrConst: + mips->r[inst->dest] |= inst->constant; + break; case IROp::XorConst: mips->r[inst->dest] = mips->r[inst->src1] ^ inst->constant; break; case IROp::Neg: - mips->r[inst->dest] = -(s32)mips->r[inst->src1]; + mips->r[inst->dest] = (u32)(-(s32)mips->r[inst->src1]); break; case IROp::Not: mips->r[inst->dest] = ~mips->r[inst->src1]; @@ -170,31 +216,6 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { mips->r[inst->dest] = ReverseBits32(mips->r[inst->src1]); break; - case IROp::ValidateAddress8: - if (RunValidateAddress<1>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) { - CoreTiming::ForceCheck(); - return mips->pc; - } - break; - case IROp::ValidateAddress16: - if (RunValidateAddress<2>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) { - CoreTiming::ForceCheck(); - return mips->pc; - } - break; - case IROp::ValidateAddress32: - if (RunValidateAddress<4>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) { - CoreTiming::ForceCheck(); - return mips->pc; - } - break; - case IROp::ValidateAddress128: - if (RunValidateAddress<16>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) { - CoreTiming::ForceCheck(); - return mips->pc; - } - break; - case IROp::Load8: mips->r[inst->dest] = Memory::ReadUnchecked_U8(mips->r[inst->src1] + inst->constant); break; @@ -283,33 +304,20 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::LoadVec4: { u32 base = mips->r[inst->src1] + inst->constant; -#if defined(_M_SSE) - _mm_store_ps(&mips->f[inst->dest], _mm_load_ps((const float *)Memory::GetPointerUnchecked(base))); -#else - for (int i = 0; i < 4; i++) - mips->f[inst->dest + i] = Memory::ReadUnchecked_Float(base + 4 * i); -#endif + // This compiles to a nice SSE load/store on x86, and hopefully similar on ARM. + memcpy(&mips->f[inst->dest], Memory::GetPointerUnchecked(base), 4 * 4); break; } case IROp::StoreVec4: { u32 base = mips->r[inst->src1] + inst->constant; -#if defined(_M_SSE) - _mm_store_ps((float *)Memory::GetPointerUnchecked(base), _mm_load_ps(&mips->f[inst->dest])); -#else - for (int i = 0; i < 4; i++) - Memory::WriteUnchecked_Float(mips->f[inst->dest + i], base + 4 * i); -#endif + memcpy((float *)Memory::GetPointerUnchecked(base), &mips->f[inst->dest], 4 * 4); break; } case IROp::Vec4Init: { -#if defined(_M_SSE) - _mm_store_ps(&mips->f[inst->dest], _mm_load_ps(vec4InitValues[inst->src1])); -#else memcpy(&mips->f[inst->dest], vec4InitValues[inst->src1], 4 * sizeof(float)); -#endif break; } @@ -320,16 +328,24 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { float temp[4]; for (int i = 0; i < 4; i++) temp[i] = mips->f[inst->src1 + ((inst->src2 >> (i * 2)) & 3)]; + const int dest = inst->dest; for (int i = 0; i < 4; i++) - mips->f[inst->dest + i] = temp[i]; + mips->f[dest + i] = temp[i]; break; } case IROp::Vec4Blend: + { + const int dest = inst->dest; + const int src1 = inst->src1; + const int src2 = inst->src2; + const int constant = inst->constant; + // 90% of calls to this is inst->constant == 7 or inst->constant == 8. Some are 1 and 4, others very rare. // Could use _mm_blendv_ps (SSE4+BMI), vbslq_f32 (ARM), __riscv_vmerge_vvm (RISC-V) for (int i = 0; i < 4; i++) - mips->f[inst->dest + i] = ((inst->constant >> i) & 1) ? mips->f[inst->src2 + i] : mips->f[inst->src1 + i]; + mips->f[dest + i] = ((constant >> i) & 1) ? mips->f[src2 + i] : mips->f[src1 + i]; break; + } case IROp::Vec4Mov: { @@ -386,6 +402,8 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { { #if defined(_M_SSE) _mm_store_ps(&mips->f[inst->dest], _mm_div_ps(_mm_load_ps(&mips->f[inst->src1]), _mm_load_ps(&mips->f[inst->src2]))); +#elif PPSSPP_ARCH(ARM64_NEON) + vst1q_f32(&mips->f[inst->dest], vdivq_f32(vld1q_f32(&mips->f[inst->src1]), vld1q_f32(&mips->f[inst->src2]))); #else for (int i = 0; i < 4; i++) mips->f[inst->dest + i] = mips->f[inst->src1 + i] / mips->f[inst->src2 + i]; @@ -397,9 +415,12 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { { #if defined(_M_SSE) _mm_store_ps(&mips->f[inst->dest], _mm_mul_ps(_mm_load_ps(&mips->f[inst->src1]), _mm_set1_ps(mips->f[inst->src2]))); +#elif PPSSPP_ARCH(ARM_NEON) + vst1q_f32(&mips->f[inst->dest], vmulq_lane_f32(vld1q_f32(&mips->f[inst->src1]), vdup_n_f32(mips->f[inst->src2]), 0)); #else + const float factor = mips->f[inst->src2]; for (int i = 0; i < 4; i++) - mips->f[inst->dest + i] = mips->f[inst->src1 + i] * mips->f[inst->src2]; + mips->f[inst->dest + i] = mips->f[inst->src1 + i] * factor; #endif break; } @@ -432,15 +453,19 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::Vec2Unpack16To31: { - mips->fi[inst->dest] = (mips->fi[inst->src1] << 16) >> 1; - mips->fi[inst->dest + 1] = (mips->fi[inst->src1] & 0xFFFF0000) >> 1; + const int dest = inst->dest; + const int src1 = inst->src1; + mips->fi[dest] = (mips->fi[src1] << 16) >> 1; + mips->fi[dest + 1] = (mips->fi[src1] & 0xFFFF0000) >> 1; break; } case IROp::Vec2Unpack16To32: { - mips->fi[inst->dest] = (mips->fi[inst->src1] << 16); - mips->fi[inst->dest + 1] = (mips->fi[inst->src1] & 0xFFFF0000); + const int dest = inst->dest; + const int src1 = inst->src1; + mips->fi[dest] = (mips->fi[src1] << 16); + mips->fi[dest + 1] = (mips->fi[src1] & 0xFFFF0000); break; } @@ -451,6 +476,11 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { src = _mm_unpacklo_epi8(src, _mm_setzero_si128()); src = _mm_unpacklo_epi16(src, _mm_setzero_si128()); _mm_store_si128((__m128i *)&mips->fi[inst->dest], _mm_slli_epi32(src, 24)); +#elif PPSSPP_ARCH(ARM_NEON) && 0 // Untested + const uint8x8_t value = (uint8x8_t)vdup_n_u32(mips->fi[inst->src1]); + const uint16x8_t value16 = vmovl_u8(value); + const uint32x4_t value32 = vshll_n_u16(vget_low_u16(value16), 24); + vst1q_u32(&mips->fi[inst->dest], value32); #else mips->fi[inst->dest] = (mips->fi[inst->src1] << 24); mips->fi[inst->dest + 1] = (mips->fi[inst->src1] << 16) & 0xFF000000; @@ -469,6 +499,8 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::Vec2Pack31To16: { + // Used in Tekken 6 + u32 val = (mips->fi[inst->src1] >> 15) & 0xFFFF; val |= (mips->fi[inst->src1 + 1] << 1) & 0xFFFF0000; mips->fi[inst->dest] = val; @@ -489,13 +521,24 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::Vec4Pack31To8: { + // Used in Tekken 6 + // Removed previous SSE code due to the need for unsigned 16-bit pack, which I'm too lazy to work around the lack of in SSE2. // pshufb or SSE4 instructions can be used instead. +#if PPSSPP_ARCH(ARM_NEON) && 0 + // Untested + uint32x4_t value = vld1q_u32(&mips->fi[inst->src1]); + value = vshlq_n_u32(value, 1); + uint32x2_t halved = vshrn_n_u32(value, 8); + uint32x2_t halvedAgain = vshrn_n_u32(vcombine_u32(halved, vdup_n_u32(0)), 8); + mips->fi[inst->dest] = vget_lane_u32(halvedAgain, 0); +#else u32 val = (mips->fi[inst->src1] >> 23) & 0xFF; val |= (mips->fi[inst->src1 + 1] >> 15) & 0xFF00; val |= (mips->fi[inst->src1 + 2] >> 7) & 0xFF0000; val |= (mips->fi[inst->src1 + 3] << 1) & 0xFF000000; mips->fi[inst->dest] = val; +#endif break; } @@ -517,9 +560,11 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { val = _mm_andnot_si128(mask, val); _mm_store_si128((__m128i *)&mips->fi[inst->dest], val); #else + const int src1 = inst->src1; + const int dest = inst->dest; for (int i = 0; i < 4; i++) { - u32 val = mips->fi[inst->src1 + i]; - mips->fi[inst->dest + i] = (int)val >= 0 ? val : 0; + u32 val = mips->fi[src1 + i]; + mips->fi[dest + i] = (int)val >= 0 ? val : 0; } #endif break; @@ -527,20 +572,22 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::Vec4DuplicateUpperBitsAndShift1: // For vuc2i, the weird one. { + const int src1 = inst->src1; + const int dest = inst->dest; for (int i = 0; i < 4; i++) { - u32 val = mips->fi[inst->src1 + i]; + u32 val = mips->fi[src1 + i]; val = val | (val >> 8); val = val | (val >> 16); val >>= 1; - mips->fi[inst->dest + i] = val; + mips->fi[dest + i] = val; } break; } case IROp::FCmpVfpuBit: { - int op = inst->dest & 0xF; - int bit = inst->dest >> 4; + const int op = inst->dest & 0xF; + const int bit = inst->dest >> 4; int result = 0; switch (op) { case VC_EQ: result = mips->f[inst->src1] == mips->f[inst->src2]; break; @@ -572,8 +619,8 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::FCmpVfpuAggregate: { - u32 mask = inst->dest; - u32 cc = mips->vfpuCtrl[VFPU_CTRL_CC]; + const u32 mask = inst->dest; + const u32 cc = mips->vfpuCtrl[VFPU_CTRL_CC]; int anyBit = (cc & mask) ? 0x10 : 0x00; int allBit = (cc & mask) == mask ? 0x20 : 0x00; mips->vfpuCtrl[VFPU_CTRL_CC] = (cc & ~0x30) | anyBit | allBit; @@ -586,9 +633,11 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { } break; - // Not quickly implementable on all platforms, unfortunately. case IROp::Vec4Dot: { + // Not quickly implementable on all platforms, unfortunately. + // Though, this is still pretty fast compared to one split into multiple IR instructions. + // This might be good though: https://gist.github.com/rikusalminen/3040241 float dot = mips->f[inst->src1] * mips->f[inst->src2]; for (int i = 1; i < 4; i++) dot += mips->f[inst->src1 + i] * mips->f[inst->src2 + i]; @@ -775,13 +824,13 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::BSwap16: { u32 x = mips->r[inst->src1]; + // Don't think we can beat this with intrinsics. mips->r[inst->dest] = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); break; } case IROp::BSwap32: { - u32 x = mips->r[inst->src1]; - mips->r[inst->dest] = ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24); + mips->r[inst->dest] = swap32(mips->r[inst->src1]); break; } @@ -792,12 +841,31 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { mips->f[inst->dest] = mips->f[inst->src1] - mips->f[inst->src2]; break; case IROp::FMul: - if ((my_isinf(mips->f[inst->src1]) && mips->f[inst->src2] == 0.0f) || (my_isinf(mips->f[inst->src2]) && mips->f[inst->src1] == 0.0f)) { +#if 1 + { + float a = mips->f[inst->src1]; + float b = mips->f[inst->src2]; + if ((b == 0.0f && my_isinf(a)) || (a == 0.0f && my_isinf(b))) { mips->fi[inst->dest] = 0x7fc00000; } else { - mips->f[inst->dest] = mips->f[inst->src1] * mips->f[inst->src2]; + mips->f[inst->dest] = a * b; } + } break; +#else + // Not sure if faster since it needs to load the operands twice? But the code is simpler. + { + // Takes care of negative zero by masking away the top bit, which also makes the inf check shorter. + u32 a = mips->fi[inst->src1] & 0x7FFFFFFF; + u32 b = mips->fi[inst->src2] & 0x7FFFFFFF; + if ((a == 0 && b == 0x7F800000) || (b == 0 && a == 0x7F800000)) { + mips->fi[inst->dest] = 0x7fc00000; + } else { + mips->f[inst->dest] = mips->f[inst->src1] * mips->f[inst->src2]; + } + break; + } +#endif case IROp::FDiv: mips->f[inst->dest] = mips->f[inst->src1] / mips->f[inst->src2]; break; @@ -846,9 +914,9 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { mips->f[inst->dest] = vfpu_clamp(mips->f[inst->src1], -1.0f, 1.0f); break; - // Bitwise trickery case IROp::FSign: { + // Bitwise trickery u32 val; memcpy(&val, &mips->f[inst->src1], sizeof(u32)); if (val == 0 || val == 0x80000000) @@ -976,6 +1044,7 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { mips->fs[inst->dest] = my_isinf(src) && src < 0.0f ? -2147483648LL : 2147483647LL; break; } + // TODO: Inline assembly to use here would be better. switch (IRRoundMode(mips->fcr31 & 3)) { case IRRoundMode::RINT_0: mips->fs[inst->dest] = (int)round_ieee_754(src); break; case IRRoundMode::CAST_1: mips->fs[inst->dest] = (int)src; break; @@ -1017,9 +1086,19 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { case IROp::FMovFromGPR: memcpy(&mips->f[inst->dest], &mips->r[inst->src1], 4); break; + case IROp::OptFCvtSWFromGPR: + mips->f[inst->dest] = (float)(int)mips->r[inst->src1]; + break; case IROp::FMovToGPR: memcpy(&mips->r[inst->dest], &mips->f[inst->src1], 4); break; + case IROp::OptFMovToGPRShr8: + { + u32 temp; + memcpy(&temp, &mips->f[inst->src1], 4); + mips->r[inst->dest] = temp >> 8; + break; + } case IROp::ExitToConst: return inst->constant; @@ -1094,10 +1173,6 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { break; } - case IROp::Break: - Core_Break(mips->pc); - return mips->pc + 4; - case IROp::SetCtrlVFPU: mips->vfpuCtrl[inst->dest] = inst->constant; break; @@ -1110,6 +1185,20 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { memcpy(&mips->vfpuCtrl[inst->dest], &mips->f[inst->src1], 4); break; + case IROp::ApplyRoundingMode: + IRApplyRounding(mips); + break; + case IROp::RestoreRoundingMode: + IRRestoreRounding(); + break; + case IROp::UpdateRoundingMode: + // TODO: Implement + break; + + case IROp::Break: + Core_Break(mips->pc); + return mips->pc + 4; + case IROp::Breakpoint: if (IRRunBreakpoint(inst->constant)) { CoreTiming::ForceCheck(); @@ -1124,20 +1213,44 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { } break; - case IROp::ApplyRoundingMode: - // TODO: Implement + case IROp::ValidateAddress8: + if (RunValidateAddress<1>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) { + CoreTiming::ForceCheck(); + return mips->pc; + } break; - case IROp::RestoreRoundingMode: - // TODO: Implement + case IROp::ValidateAddress16: + if (RunValidateAddress<2>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) { + CoreTiming::ForceCheck(); + return mips->pc; + } break; - case IROp::UpdateRoundingMode: - // TODO: Implement + case IROp::ValidateAddress32: + if (RunValidateAddress<4>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) { + CoreTiming::ForceCheck(); + return mips->pc; + } + break; + case IROp::ValidateAddress128: + if (RunValidateAddress<16>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) { + CoreTiming::ForceCheck(); + return mips->pc; + } + break; + case IROp::LogIRBlock: + if (mipsTracer.tracing_enabled) { + mipsTracer.executed_blocks.push_back(inst->constant); + } break; + case IROp::Nop: // TODO: This shouldn't crash, but for now we should not emit nops, so... + case IROp::Bad: default: - // Unimplemented IR op. Bad. Crash(); + break; + // Unimplemented IR op. Bad. } + #ifdef _DEBUG if (mips->r[0] != 0) Crash(); @@ -1145,6 +1258,6 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { inst++; } - // We hit count. If this is a full block, it was badly constructed. + // We should not reach here anymore. return 0; } diff --git a/Core/MIPS/IR/IRInterpreter.h b/Core/MIPS/IR/IRInterpreter.h index 21e7f15dc7..0939e982d0 100644 --- a/Core/MIPS/IR/IRInterpreter.h +++ b/Core/MIPS/IR/IRInterpreter.h @@ -1,26 +1,34 @@ #pragma once #include "Common/CommonTypes.h" +#include "Core/Core.h" +#include "Core/MemMap.h" class MIPSState; struct IRInst; -inline static u32 ReverseBits32(u32 v) { - // http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel - // swap odd and even bits - v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); - // swap consecutive pairs - v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); - // swap nibbles ... - v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); - // swap bytes - v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); - // swap 2-byte long pairs - v = ( v >> 16 ) | ( v << 16); - return v; -} - u32 IRRunBreakpoint(u32 pc); u32 IRRunMemCheck(u32 pc, u32 addr); +u32 IRInterpret(MIPSState *ms, const IRInst *inst); -u32 IRInterpret(MIPSState *ms, const IRInst *inst, int count); +void IRApplyRounding(); +void IRRestoreRounding(); + +template +u32 RunValidateAddress(u32 pc, u32 addr, u32 isWrite) { + const auto toss = [&](MemoryExceptionType t) { + Core_MemoryException(addr, alignment, pc, t); + return coreState != CORE_RUNNING ? 1 : 0; + }; + + if (!Memory::IsValidRange(addr, alignment)) { + MemoryExceptionType t = isWrite == 1 ? MemoryExceptionType::WRITE_WORD : MemoryExceptionType::READ_WORD; + if constexpr (alignment > 4) + t = isWrite ? MemoryExceptionType::WRITE_BLOCK : MemoryExceptionType::READ_BLOCK; + return toss(t); + } + if constexpr (alignment > 1) + if ((addr & (alignment - 1)) != 0) + return toss(MemoryExceptionType::ALIGNMENT); + return 0; +} diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index bc866ee04b..a06d76b655 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -17,6 +17,7 @@ #include "ppsspp_config.h" #include +#include #include "ext/xxhash.h" #include "Common/Profiler/Profiler.h" @@ -40,14 +41,21 @@ #include "Core/MIPS/IR/IRNativeCommon.h" #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/Reporting.h" +#include "Common/TimeUtil.h" +#include "Core/MIPS/MIPSTracer.h" + namespace MIPSComp { -IRJit::IRJit(MIPSState *mipsState) : frontend_(mipsState->HasDefaultPrefix()), mips_(mipsState) { +IRJit::IRJit(MIPSState *mipsState, bool actualJit) : frontend_(mipsState->HasDefaultPrefix()), mips_(mipsState), blocks_(actualJit) { // u32 size = 128 * 1024; - // blTrampolines_ = kernelMemory.Alloc(size, true, "trampoline"); InitIR(); + compileToNative_ = actualJit; + + // If this IRJit instance will be used to drive a "JIT using IR", don't optimize for interpretation. + jo.optimizeForInterpreter = !actualJit; + IROptions opts{}; opts.disableFlags = g_Config.uJitDisableFlags; #if PPSSPP_ARCH(RISCV64) @@ -55,16 +63,17 @@ IRJit::IRJit(MIPSState *mipsState) : frontend_(mipsState->HasDefaultPrefix()), m opts.unalignedLoadStore = false; opts.unalignedLoadStoreVec4 = true; opts.preferVec4 = cpu_info.RiscV_V; -#elif PPSSPP_ARCH(ARM) +#elif PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) opts.unalignedLoadStore = (opts.disableFlags & (uint32_t)JitDisable::LSU_UNALIGNED) == 0; opts.unalignedLoadStoreVec4 = true; - opts.preferVec4 = cpu_info.bASIMD || cpu_info.bNEON; + opts.preferVec4 = true; #else opts.unalignedLoadStore = (opts.disableFlags & (uint32_t)JitDisable::LSU_UNALIGNED) == 0; // TODO: Could allow on x86 pretty easily... opts.unalignedLoadStoreVec4 = false; opts.preferVec4 = true; #endif + opts.optimizeForInterpreter = jo.optimizeForInterpreter; frontend_.SetOptions(opts); } @@ -79,33 +88,45 @@ void IRJit::UpdateFCR31() { } void IRJit::ClearCache() { - INFO_LOG(JIT, "IRJit: Clearing the cache!"); + INFO_LOG(Log::JIT, "IRJit: Clearing the block cache!"); blocks_.Clear(); } void IRJit::InvalidateCacheAt(u32 em_address, int length) { std::vector numbers = blocks_.FindInvalidatedBlockNumbers(em_address, length); + if (numbers.empty()) { + return; + } + + DEBUG_LOG(Log::JIT, "Invalidating IR block cache at %08x (%d bytes): %d blocks", em_address, length, (int)numbers.size()); + for (int block_num : numbers) { auto block = blocks_.GetBlock(block_num); - int cookie = block->GetTargetOffset() < 0 ? block_num : block->GetTargetOffset(); + // TODO: We are invalidating a lot of blocks that are already invalid (yu gi oh). + // INFO_LOG(Log::JIT, "Block at %08x invalidated: valid: %d", block->GetOriginalStart(), block->IsValid()); + // If we're a native JIT (IR->JIT, not just IR interpreter), we write native offsets into the blocks. + int cookie = compileToNative_ ? block->GetNativeOffset() : block->GetIRArenaOffset(); + blocks_.RemoveBlockFromPageLookup(block_num); block->Destroy(cookie); } } void IRJit::Compile(u32 em_address) { + _dbg_assert_(compilerEnabled_); + PROFILE_THIS_SCOPE("jitc"); if (g_Config.bPreloadFunctions) { // Look to see if we've preloaded this block. int block_num = blocks_.FindPreloadBlock(em_address); if (block_num != -1) { - IRBlock *b = blocks_.GetBlock(block_num); + IRBlock *block = blocks_.GetBlock(block_num); // Okay, let's link and finalize the block now. - int cookie = b->GetTargetOffset() < 0 ? block_num : b->GetTargetOffset(); - b->Finalize(cookie); - if (b->IsValid()) { + int cookie = compileToNative_ ? block->GetNativeOffset() : block->GetIRArenaOffset(); + block->Finalize(cookie); + if (block->IsValid()) { // Success, we're done. - FinalizeTargetBlock(b, block_num); + FinalizeNativeBlock(&blocks_, block_num); return; } } @@ -115,7 +136,7 @@ void IRJit::Compile(u32 em_address) { u32 mipsBytes; if (!CompileBlock(em_address, instructions, mipsBytes, false)) { // Ran out of block numbers - need to reset. - ERROR_LOG(JIT, "Ran out of block numbers, clearing cache"); + ERROR_LOG(Log::JIT, "Ran out of block numbers, clearing cache"); ClearCache(); CompileBlock(em_address, instructions, mipsBytes, false); } @@ -127,7 +148,10 @@ void IRJit::Compile(u32 em_address) { } } +// WARNING! This can be called from IRInterpret / the JIT, through the function preload stuff! bool IRJit::CompileBlock(u32 em_address, std::vector &instructions, u32 &mipsBytes, bool preload) { + _dbg_assert_(compilerEnabled_); + frontend_.DoJit(em_address, instructions, mipsBytes, preload); if (instructions.empty()) { _dbg_assert_(preload); @@ -135,31 +159,37 @@ bool IRJit::CompileBlock(u32 em_address, std::vector &instructions, u32 return preload; } - int block_num = blocks_.AllocateBlock(em_address); + int block_num = blocks_.AllocateBlock(em_address, mipsBytes, instructions); if ((block_num & ~MIPS_EMUHACK_VALUE_MASK) != 0) { + WARN_LOG(Log::JIT, "Failed to allocate block for %08x (%d instructions)", em_address, (int)instructions.size()); // Out of block numbers. Caller will handle. return false; } IRBlock *b = blocks_.GetBlock(block_num); - b->SetInstructions(instructions); - b->SetOriginalSize(mipsBytes); - if (preload) { + if (preload || mipsTracer.tracing_enabled) { // Hash, then only update page stats, don't link yet. // TODO: Should we always hash? Then we can reuse blocks. b->UpdateHash(); } - if (!CompileTargetBlock(b, block_num, preload)) + + if (!CompileNativeBlock(&blocks_, block_num, preload)) return false; - // Overwrites the first instruction, and also updates stats. + + if (mipsTracer.tracing_enabled) { + mipsTracer.prepare_block(b, blocks_); + } + + // Updates stats, also patches the first MIPS instruction into an emuhack if 'preload == false' blocks_.FinalizeBlock(block_num, preload); if (!preload) - FinalizeTargetBlock(b, block_num); - + FinalizeNativeBlock(&blocks_, block_num); return true; } void IRJit::CompileFunction(u32 start_address, u32 length) { + _dbg_assert_(compilerEnabled_); + PROFILE_THIS_SCOPE("jitc"); // Note: we don't actually write emuhacks yet, so we can validate hashes. @@ -186,7 +216,7 @@ void IRJit::CompileFunction(u32 start_address, u32 length) { if (!CompileBlock(em_address, instructions, mipsBytes, true)) { // Ran out of block numbers - let's hope there's no more code it needs to run. // Will flush when actually compiling. - ERROR_LOG(JIT, "Ran out of block numbers while compiling function"); + ERROR_LOG(Log::JIT, "Ran out of block numbers while compiling function"); return; } @@ -246,32 +276,62 @@ void IRJit::RunLoopUntil(u64 globalticks) { if (coreState != 0) { break; } - while (mips_->downcount >= 0) { - u32 inst = Memory::ReadUnchecked_U32(mips_->pc); + + MIPSState *mips = mips_; +#ifdef _DEBUG + compilerEnabled_ = false; +#endif + while (mips->downcount >= 0) { + u32 inst = Memory::ReadUnchecked_U32(mips->pc); u32 opcode = inst & 0xFF000000; if (opcode == MIPS_EMUHACK_OPCODE) { - u32 data = inst & 0xFFFFFF; - IRBlock *block = blocks_.GetBlock(data); - u32 startPC = mips_->pc; - mips_->pc = IRInterpret(mips_, block->GetInstructions(), block->GetNumInstructions()); + u32 offset = inst & 0x00FFFFFF; // Alternatively, inst - opcode + const IRInst *instPtr = blocks_.GetArenaPtr() + offset; + // First op is always, except when using breakpoints, downcount, to save one dispatch inside IRInterpret. + // This branch is very cpu-branch-predictor-friendly so this still beats the dispatch. + if (instPtr->op == IROp::Downcount) { + mips->downcount -= instPtr->constant; + instPtr++; + } +#ifdef IR_PROFILING + IRBlock *block = blocks_.GetBlock(blocks_.GetBlockNumFromOffset(offset)); + Instant start = Instant::Now(); + mips->pc = IRInterpret(mips, instPtr); + int64_t elapsedNanos = start.ElapsedNanos(); + block->profileStats_.executions += 1; + block->profileStats_.totalNanos += elapsedNanos; +#else + mips->pc = IRInterpret(mips, instPtr); +#endif // Note: this will "jump to zero" on a badly constructed block missing exits. - if (!Memory::IsValidAddress(mips_->pc) || (mips_->pc & 3) != 0) { - Core_ExecException(mips_->pc, startPC, ExecExceptionType::JUMP); + if (!Memory::IsValid4AlignedAddress(mips->pc)) { + int blockNum = blocks_.GetBlockNumFromIRArenaOffset(offset); + IRBlock *block = blocks_.GetBlockUnchecked(blockNum); + Core_ExecException(mips->pc, block->GetOriginalStart(), ExecExceptionType::JUMP); break; } } else { // RestoreRoundingMode(true); - Compile(mips_->pc); +#ifdef _DEBUG + compilerEnabled_ = true; +#endif + Compile(mips->pc); +#ifdef _DEBUG + compilerEnabled_ = false; +#endif // ApplyRoundingMode(true); } } +#ifdef _DEBUG + compilerEnabled_ = true; +#endif } // RestoreRoundingMode(true); } bool IRJit::DescribeCodePtr(const u8 *ptr, std::string &name) { - // Used in target disassembly viewer. + // Used in native disassembly viewer. return false; } @@ -285,16 +345,72 @@ void IRJit::UnlinkBlock(u8 *checkedEntry, u32 originalAddress) { void IRBlockCache::Clear() { for (int i = 0; i < (int)blocks_.size(); ++i) { - int cookie = blocks_[i].GetTargetOffset() < 0 ? i : blocks_[i].GetTargetOffset(); + int cookie = compileToNative_ ? blocks_[i].GetNativeOffset() : blocks_[i].GetIRArenaOffset(); blocks_[i].Destroy(cookie); } blocks_.clear(); byPage_.clear(); + arena_.clear(); + arena_.shrink_to_fit(); } -std::vector IRBlockCache::FindInvalidatedBlockNumbers(u32 address, u32 length) { +IRBlockCache::IRBlockCache(bool compileToNative) : compileToNative_(compileToNative) {} + +int IRBlockCache::AllocateBlock(int emAddr, u32 origSize, const std::vector &insts) { + // We have 24 bits to represent offsets with. + const u32 MAX_ARENA_SIZE = 0x1000000 - 1; + int offset = (int)arena_.size(); + if (offset >= MAX_ARENA_SIZE) { + WARN_LOG(Log::JIT, "Filled JIT arena, restarting"); + return -1; + } + // TODO: Use memcpy. + for (int i = 0; i < insts.size(); i++) { + arena_.push_back(insts[i]); + } + int newBlockIndex = (int)blocks_.size(); + blocks_.push_back(IRBlock(emAddr, origSize, offset, (u32)insts.size())); + return newBlockIndex; +} + +int IRBlockCache::GetBlockNumFromIRArenaOffset(int offset) const { + // Block offsets are always in rising order (we don't go back and replace them when invalidated). So we can binary search. + int low = 0; + int high = (int)blocks_.size() - 1; + int found = -1; + while (low <= high) { + int mid = low + (high - low) / 2; + const int blockOffset = blocks_[mid].GetIRArenaOffset(); + if (blockOffset == offset) { + found = mid; + break; + } + if (blockOffset < offset) { + low = mid + 1; + } else { + high = mid - 1; + } + } + +#ifndef _DEBUG + // Then, in debug builds, cross check the result. + return found; +#else + // TODO: Optimize if we need to call this often. + for (int i = 0; i < (int)blocks_.size(); i++) { + if (blocks_[i].GetIRArenaOffset() == offset) { + _dbg_assert_(i == found); + return i; + } + } +#endif + _dbg_assert_(found == -1); + return -1; +} + +std::vector IRBlockCache::FindInvalidatedBlockNumbers(u32 address, u32 lengthInBytes) { u32 startPage = AddressToPage(address); - u32 endPage = AddressToPage(address + length); + u32 endPage = AddressToPage(address + lengthInBytes); std::vector found; for (u32 page = startPage; page <= endPage; ++page) { @@ -304,8 +420,8 @@ std::vector IRBlockCache::FindInvalidatedBlockNumbers(u32 address, u32 leng const std::vector &blocksInPage = iter->second; for (int i : blocksInPage) { - if (blocks_[i].OverlapsRange(address, length)) { - // Not removing from the page, hopefully doesn't build up with small recompiles. + if (blocks_[i].OverlapsRange(address, lengthInBytes)) { + // We now try to remove these during invalidation. found.push_back(i); } } @@ -314,23 +430,56 @@ std::vector IRBlockCache::FindInvalidatedBlockNumbers(u32 address, u32 leng return found; } -void IRBlockCache::FinalizeBlock(int i, bool preload) { +void IRBlockCache::FinalizeBlock(int blockIndex, bool preload) { + // TODO: What's different about preload blocks? + IRBlock &block = blocks_[blockIndex]; if (!preload) { - int cookie = blocks_[i].GetTargetOffset() < 0 ? i : blocks_[i].GetTargetOffset(); - blocks_[i].Finalize(cookie); + int cookie = compileToNative_ ? block.GetNativeOffset() : block.GetIRArenaOffset(); + block.Finalize(cookie); } u32 startAddr, size; - blocks_[i].GetRange(startAddr, size); + block.GetRange(&startAddr, &size); u32 startPage = AddressToPage(startAddr); u32 endPage = AddressToPage(startAddr + size); for (u32 page = startPage; page <= endPage; ++page) { - byPage_[page].push_back(i); + byPage_[page].push_back(blockIndex); } } +// Call after Destroy-ing it. +void IRBlockCache::RemoveBlockFromPageLookup(int blockIndex) { + // We need to remove the block from the byPage lookup. + IRBlock &block = blocks_[blockIndex]; + + u32 startAddr, size; + block.GetRange(&startAddr, &size); + + u32 startPage = AddressToPage(startAddr); + u32 endPage = AddressToPage(startAddr + size); + + for (u32 page = startPage; page <= endPage; ++page) { + auto iter = std::find(byPage_[page].begin(), byPage_[page].end(), blockIndex); + if (iter != byPage_[page].end()) { + byPage_[page].erase(iter); + } else if (block.IsValid()) { + // If it was previously invalidated, we don't care, hence the above check. + WARN_LOG(Log::JIT, "RemoveBlock: Block at %08x was not found where expected in byPage table.", startAddr); + } + } + + // Additionally, we'd like to zap the block in the IR arena. + // However, this breaks if calling sceKernelIcacheClearAll(), since as soon as we return, we'll be executing garbage. + /* + IRInst bad{ IROp::Bad }; + for (int off = block.GetIRArenaOffset(); off < (int)(block.GetIRArenaOffset() + block.GetNumIRInstructions()); off++) { + arena_[off] = bad; + } + */ +} + u32 IRBlockCache::AddressToPage(u32 addr) const { // Use relatively small pages since basic blocks are typically small. return (addr & 0x3FFFFFFF) >> 10; @@ -357,16 +506,18 @@ int IRBlockCache::FindPreloadBlock(u32 em_address) { int IRBlockCache::FindByCookie(int cookie) { if (blocks_.empty()) return -1; - // TODO: Maybe a flag to determine target offset mode? - if (blocks_[0].GetTargetOffset() < 0) - return cookie; + // TODO: Maybe a flag to determine native offset mode? + if (!compileToNative_) { + return GetBlockNumFromIRArenaOffset(cookie); + } + + // TODO: This could also use a binary search. for (int i = 0; i < GetNumBlocks(); ++i) { - int offset = blocks_[i].GetTargetOffset(); + int offset = blocks_[i].GetNativeOffset(); if (offset == cookie) return i; } - return -1; } @@ -376,7 +527,7 @@ std::vector IRBlockCache::SaveAndClearEmuHackOps() { for (int number = 0; number < (int)blocks_.size(); ++number) { IRBlock &b = blocks_[number]; - int cookie = b.GetTargetOffset() < 0 ? number : b.GetTargetOffset(); + int cookie = compileToNative_ ? b.GetNativeOffset() : b.GetIRArenaOffset(); if (b.IsValid() && b.RestoreOriginalFirstOp(cookie)) { result[number] = number; } else { @@ -389,7 +540,7 @@ std::vector IRBlockCache::SaveAndClearEmuHackOps() { void IRBlockCache::RestoreSavedEmuHackOps(const std::vector &saved) { if ((int)blocks_.size() != (int)saved.size()) { - ERROR_LOG(JIT, "RestoreSavedEmuHackOps: Wrong saved block size."); + ERROR_LOG(Log::JIT, "RestoreSavedEmuHackOps: Wrong saved block size."); return; } @@ -397,7 +548,7 @@ void IRBlockCache::RestoreSavedEmuHackOps(const std::vector &saved) { IRBlock &b = blocks_[number]; // Only if we restored it, write it back. if (b.IsValid() && saved[number] != 0 && b.HasOriginalFirstOp()) { - int cookie = b.GetTargetOffset() < 0 ? number : b.GetTargetOffset(); + int cookie = compileToNative_ ? b.GetNativeOffset() : b.GetIRArenaOffset(); b.Finalize(cookie); } } @@ -407,7 +558,7 @@ JitBlockDebugInfo IRBlockCache::GetBlockDebugInfo(int blockNum) const { const IRBlock &ir = blocks_[blockNum]; JitBlockDebugInfo debugInfo{}; uint32_t start, size; - ir.GetRange(start, size); + ir.GetRange(&start, &size); debugInfo.originalAddress = start; // TODO debugInfo.origDisasm.reserve(((start + size) - start) / 4); @@ -418,9 +569,10 @@ JitBlockDebugInfo IRBlockCache::GetBlockDebugInfo(int blockNum) const { debugInfo.origDisasm.push_back(mipsDis); } - debugInfo.irDisasm.reserve(ir.GetNumInstructions()); - for (int i = 0; i < ir.GetNumInstructions(); i++) { - IRInst inst = ir.GetInstructions()[i]; + debugInfo.irDisasm.reserve(ir.GetNumIRInstructions()); + const IRInst *instructions = GetBlockInstructionPtr(ir); + for (int i = 0; i < ir.GetNumIRInstructions(); i++) { + IRInst inst = instructions[i]; char buffer[256]; DisassembleIR(buffer, sizeof(buffer), inst); debugInfo.irDisasm.push_back(buffer); @@ -433,12 +585,11 @@ void IRBlockCache::ComputeStats(BlockCacheStats &bcStats) const { double maxBloat = 0.0; double minBloat = 1000000000.0; for (const auto &b : blocks_) { - double codeSize = (double)b.GetNumInstructions() * sizeof(IRInst); + double codeSize = (double)b.GetNumIRInstructions() * 4; // We count bloat in instructions, not bytes. sizeof(IRInst); if (codeSize == 0) continue; - u32 origAddr, mipsBytes; - b.GetRange(origAddr, mipsBytes); + b.GetRange(&origAddr, &mipsBytes); double origSize = (double)mipsBytes; double bloat = codeSize / origSize; if (bloat < minBloat) { @@ -450,7 +601,6 @@ void IRBlockCache::ComputeStats(BlockCacheStats &bcStats) const { bcStats.maxBloatBlock = origAddr; } totalBloat += bloat; - bcStats.bloatMap[bloat] = origAddr; } bcStats.numBlocks = (int)blocks_.size(); bcStats.minBloat = minBloat; @@ -498,15 +648,22 @@ void IRBlock::Finalize(int cookie) { origFirstOpcode_ = Memory::Read_Opcode_JIT(origAddr_); MIPSOpcode opcode = MIPSOpcode(MIPS_EMUHACK_OPCODE | cookie); Memory::Write_Opcode_JIT(origAddr_, opcode); + } else { + WARN_LOG(Log::JIT, "Finalizing invalid block (cookie: %d)", cookie); } } void IRBlock::Destroy(int cookie) { if (origAddr_) { MIPSOpcode opcode = MIPSOpcode(MIPS_EMUHACK_OPCODE | cookie); - if (Memory::ReadUnchecked_U32(origAddr_) == opcode.encoding) + u32 memOp = Memory::ReadUnchecked_U32(origAddr_); + if (memOp == opcode.encoding) { Memory::Write_Opcode_JIT(origAddr_, origFirstOpcode_); - + } else { + // NOTE: This is not an error. Just interesting to log. + DEBUG_LOG(Log::JIT, "IRBlock::Destroy: Note: Block at %08x was overwritten - checked for %08x, got %08x when restoring the MIPS op to %08x", origAddr_, opcode.encoding, memOp, origFirstOpcode_.encoding); + } + // TODO: Also wipe the block in the IR opcode arena. // Let's mark this invalid so we don't try to clear it again. origAddr_ = 0; } @@ -514,7 +671,8 @@ void IRBlock::Destroy(int cookie) { u64 IRBlock::CalculateHash() const { if (origAddr_) { - // This is unfortunate. In case of emuhacks, we have to make a copy. + // This is unfortunate. In case there are emuhacks, we have to make a copy. + // If we could hash while reading we could avoid this. std::vector buffer; buffer.resize(origSize_ / 4); size_t pos = 0; @@ -523,10 +681,8 @@ u64 IRBlock::CalculateHash() const { MIPSOpcode instr = Memory::ReadUnchecked_Instruction(origAddr_ + off, false); buffer[pos++] = instr.encoding; } - return XXH3_64bits(&buffer[0], origSize_); } - return 0; } diff --git a/Core/MIPS/IR/IRJit.h b/Core/MIPS/IR/IRJit.h index 60460ea878..c8ef2d5192 100644 --- a/Core/MIPS/IR/IRJit.h +++ b/Core/MIPS/IR/IRJit.h @@ -33,50 +33,48 @@ #include "stddef.h" #endif +// Very expensive, time-profiles every block. +// Not to be released with this enabled. +// +// #define IR_PROFILING + +// Try to catch obvious misses of be above rule. +#if defined(IR_PROFILING) && defined(GOLD) +#error +#endif + namespace MIPSComp { // TODO : Use arena allocators. For now let's just malloc. class IRBlock { public: IRBlock() {} - IRBlock(u32 emAddr) : origAddr_(emAddr) {} + IRBlock(u32 emAddr, u32 origSize, int instOffset, u32 numInstructions) + : origAddr_(emAddr), origSize_(origSize), arenaOffset_(instOffset), numIRInstructions_(numInstructions) {} IRBlock(IRBlock &&b) { - instr_ = b.instr_; + arenaOffset_ = b.arenaOffset_; hash_ = b.hash_; origAddr_ = b.origAddr_; origSize_ = b.origSize_; origFirstOpcode_ = b.origFirstOpcode_; - targetOffset_ = b.targetOffset_; - numInstructions_ = b.numInstructions_; - b.instr_ = nullptr; + nativeOffset_ = b.nativeOffset_; + numIRInstructions_ = b.numIRInstructions_; + b.arenaOffset_ = 0xFFFFFFFF; } - ~IRBlock() { - delete[] instr_; - } + ~IRBlock() {} - void SetInstructions(const std::vector &inst) { - instr_ = new IRInst[inst.size()]; - numInstructions_ = (u16)inst.size(); - if (!inst.empty()) { - memcpy(instr_, &inst[0], sizeof(IRInst) * inst.size()); - } - } - - const IRInst *GetInstructions() const { return instr_; } - int GetNumInstructions() const { return numInstructions_; } + u32 GetIRArenaOffset() const { return arenaOffset_; } + int GetNumIRInstructions() const { return numIRInstructions_; } MIPSOpcode GetOriginalFirstOp() const { return origFirstOpcode_; } bool HasOriginalFirstOp() const; bool RestoreOriginalFirstOp(int number); bool IsValid() const { return origAddr_ != 0 && origFirstOpcode_.encoding != 0x68FFFFFF; } - void SetOriginalSize(u32 size) { - origSize_ = size; + void SetNativeOffset(int offset) { + nativeOffset_ = offset; } - void SetTargetOffset(int offset) { - targetOffset_ = offset; - } - int GetTargetOffset() const { - return targetOffset_; + int GetNativeOffset() const { + return nativeOffset_; } void UpdateHash() { hash_ = CalculateHash(); @@ -86,75 +84,125 @@ public: } bool OverlapsRange(u32 addr, u32 size) const; - void GetRange(u32 &start, u32 &size) const { - start = origAddr_; - size = origSize_; + void GetRange(u32 *start, u32 *size) const { + *start = origAddr_; + *size = origSize_; } u32 GetOriginalStart() const { return origAddr_; } + u64 GetHash() const { + return hash_; + } void Finalize(int number); void Destroy(int number); +#ifdef IR_PROFILING + JitBlockProfileStats profileStats_{}; +#endif + private: u64 CalculateHash() const; - IRInst *instr_ = nullptr; + // Offset into the block cache's Arena + u32 arenaOffset_ = 0; + // Offset into the native code buffer. + int nativeOffset_ = -1; u64 hash_ = 0; u32 origAddr_ = 0; u32 origSize_ = 0; MIPSOpcode origFirstOpcode_ = MIPSOpcode(0x68FFFFFF); - int targetOffset_ = -1; - u16 numInstructions_ = 0; + u32 numIRInstructions_ = 0; }; class IRBlockCache : public JitBlockCacheDebugInterface { public: - IRBlockCache() {} + IRBlockCache(bool compileToNative); + void Clear(); std::vector FindInvalidatedBlockNumbers(u32 address, u32 length); - void FinalizeBlock(int i, bool preload = false); + void FinalizeBlock(int blockNum, bool preload = false); int GetNumBlocks() const override { return (int)blocks_.size(); } - int AllocateBlock(int emAddr) { - blocks_.push_back(IRBlock(emAddr)); - return (int)blocks_.size() - 1; - } - IRBlock *GetBlock(int i) { - if (i >= 0 && i < (int)blocks_.size()) { - return &blocks_[i]; + int AllocateBlock(int emAddr, u32 origSize, const std::vector &inst); + IRBlock *GetBlock(int blockNum) { + if (blockNum >= 0 && blockNum < (int)blocks_.size()) { + return &blocks_[blockNum]; } else { return nullptr; } } - const IRBlock *GetBlock(int i) const { - if (i >= 0 && i < (int)blocks_.size()) { - return &blocks_[i]; + void RemoveBlockFromPageLookup(int blockNum); + int GetBlockNumFromIRArenaOffset(int offset) const; + const IRInst *GetBlockInstructionPtr(const IRBlock &block) const { + return arena_.data() + block.GetIRArenaOffset(); + } + const IRInst *GetBlockInstructionPtr(int blockNum) const { + return arena_.data() + blocks_[blockNum].GetIRArenaOffset(); + } + const IRInst *GetArenaPtr() const { + return arena_.data(); + } + bool IsValidBlock(int blockNum) const override { + return blockNum >= 0 && blockNum < (int)blocks_.size() && blocks_[blockNum].IsValid(); + } + IRBlock *GetBlockUnchecked(int blockNum) { + return &blocks_[blockNum]; + } + const IRBlock *GetBlock(int blockNum) const { + if (blockNum >= 0 && blockNum < (int)blocks_.size()) { + return &blocks_[blockNum]; } else { return nullptr; } } int FindPreloadBlock(u32 em_address); + + // "Cookie" means the 24 bits we inject into the first instruction of each block. int FindByCookie(int cookie); std::vector SaveAndClearEmuHackOps(); void RestoreSavedEmuHackOps(const std::vector &saved); JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override; + JitBlockMeta GetBlockMeta(int blockNum) const override { + JitBlockMeta meta{}; + if (IsValidBlock(blockNum)) { + meta.valid = true; + blocks_[blockNum].GetRange(&meta.addr, &meta.sizeInBytes); + } + return meta; + } + JitBlockProfileStats GetBlockProfileStats(int blockNum) const override { +#ifdef IR_PROFILING + return blocks_[blockNum].profileStats_; +#else + return JitBlockProfileStats{}; +#endif + } void ComputeStats(BlockCacheStats &bcStats) const override; int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override; + bool SupportsProfiling() const override { +#ifdef IR_PROFILING + return true; +#else + return false; +#endif + } + private: u32 AddressToPage(u32 addr) const; - + bool compileToNative_; std::vector blocks_; + std::vector arena_; std::unordered_map> byPage_; }; class IRJit : public JitInterface { public: - IRJit(MIPSState *mipsState); + IRJit(MIPSState *mipsState, bool actualJit); ~IRJit(); void DoState(PointerWrap &p) override; @@ -191,8 +239,10 @@ public: protected: bool CompileBlock(u32 em_address, std::vector &instructions, u32 &mipsBytes, bool preload); - virtual bool CompileTargetBlock(IRBlock *block, int block_num, bool preload) { return true; } - virtual void FinalizeTargetBlock(IRBlock *block, int block_num) {} + virtual bool CompileNativeBlock(IRBlockCache *irBlockCache, int block_num, bool preload) { return true; } + virtual void FinalizeNativeBlock(IRBlockCache *irBlockCache, int block_num) {} + + bool compileToNative_; JitOptions jo; @@ -201,6 +251,8 @@ protected: MIPSState *mips_; + bool compilerEnabled_ = true; + // where to write branch-likely trampolines. not used atm // u32 blTrampolines_; // int blTrampolineCount_; diff --git a/Core/MIPS/IR/IRNativeCommon.cpp b/Core/MIPS/IR/IRNativeCommon.cpp index bb1589303b..0c3d7ccc59 100644 --- a/Core/MIPS/IR/IRNativeCommon.cpp +++ b/Core/MIPS/IR/IRNativeCommon.cpp @@ -116,15 +116,15 @@ static void LogDebugStats() { debugSeenPCUsage.clear(); if (worstIROp != -1) - WARN_LOG(JIT, "Most not compiled IR op: %s (%d)", GetIRMeta((IROp)worstIROp)->name, worstIRVal); + WARN_LOG(Log::JIT, "Most not compiled IR op: %s (%d)", GetIRMeta((IROp)worstIROp)->name, worstIRVal); if (worstName != nullptr) - WARN_LOG(JIT, "Most not compiled op: %s (%d)", worstName, worstVal); + WARN_LOG(Log::JIT, "Most not compiled op: %s (%d)", worstName, worstVal); if (slowestPCs.counts[0] != 0) { for (int i = 0; i < 4; ++i) { uint32_t pc = slowestPCs.values[i].first; const char *status = IRProfilerStatusToString(slowestPCs.values[i].second); const std::string label = g_symbolMap ? g_symbolMap->GetDescription(pc) : ""; - WARN_LOG(JIT, "Slowest sampled PC #%d: %08x (%s)/%s (%f%%)", i, pc, label.c_str(), status, 100.0 * (double)slowestPCs.counts[i] / (double)totalCount); + WARN_LOG(Log::JIT, "Slowest sampled PC #%d: %08x (%s)/%s (%f%%)", i, pc, label.c_str(), status, 100.0 * (double)slowestPCs.counts[i] / (double)totalCount); } } } @@ -152,14 +152,16 @@ void IRNativeBackend::DoMIPSInst(uint32_t value) { MIPSInterpret(op); } +// This is called from IR->JIT implementation to fall back to the IR interpreter for missing ops. +// Not fast. uint32_t IRNativeBackend::DoIRInst(uint64_t value) { - IRInst inst; - memcpy(&inst, &value, sizeof(inst)); - + IRInst inst[2]{}; + memcpy(&inst[0], &value, sizeof(value)); if constexpr (enableDebugStats) - debugSeenNotCompiledIR[(uint8_t)inst.op]++; - - return IRInterpret(currentMIPS, &inst, 1); + debugSeenNotCompiledIR[(uint8_t)inst[0].op]++; + // Doesn't really matter what value it returns as PC. + inst[1].op = IROp::ExitToPC; + return IRInterpret(currentMIPS, &inst[0]); } int IRNativeBackend::ReportBadAddress(uint32_t addr, uint32_t alignment, uint32_t isWrite) { @@ -480,7 +482,7 @@ void IRNativeBackend::CompileIRInst(IRInst inst) { } IRNativeJit::IRNativeJit(MIPSState *mipsState) - : IRJit(mipsState), debugInterface_(blocks_) {} + : IRJit(mipsState, true), debugInterface_(blocks_) {} void IRNativeJit::Init(IRNativeBackend &backend) { backend_ = &backend; @@ -505,12 +507,12 @@ void IRNativeJit::Init(IRNativeBackend &backend) { } } -bool IRNativeJit::CompileTargetBlock(IRBlock *block, int block_num, bool preload) { - return backend_->CompileBlock(block, block_num, preload); +bool IRNativeJit::CompileNativeBlock(IRBlockCache *irblockCache, int block_num, bool preload) { + return backend_->CompileBlock(irblockCache, block_num, preload); } -void IRNativeJit::FinalizeTargetBlock(IRBlock *block, int block_num) { - backend_->FinalizeBlock(block, block_num, jo); +void IRNativeJit::FinalizeNativeBlock(IRBlockCache *irblockCache, int block_num) { + backend_->FinalizeBlock(irblockCache, block_num, jo); } void IRNativeJit::RunLoopUntil(u64 globalticks) { @@ -527,15 +529,6 @@ void IRNativeJit::ClearCache() { backend_->ClearAllBlocks(); } -void IRNativeJit::InvalidateCacheAt(u32 em_address, int length) { - std::vector numbers = blocks_.FindInvalidatedBlockNumbers(em_address, length); - for (int block_num : numbers) { - auto block = blocks_.GetBlock(block_num); - backend_->InvalidateBlock(block, block_num); - block->Destroy(block->GetTargetOffset()); - } -} - bool IRNativeJit::DescribeCodePtr(const u8 *ptr, std::string &name) { if (ptr != nullptr && backend_->DescribeCodePtr(ptr, name)) return true; @@ -548,7 +541,7 @@ bool IRNativeJit::DescribeCodePtr(const u8 *ptr, std::string &name) { int block_offset = INT_MAX; for (int i = 0; i < blocks_.GetNumBlocks(); ++i) { const auto &b = blocks_.GetBlock(i); - int b_start = b->GetTargetOffset(); + int b_start = b->GetNativeOffset(); if (b_start > offset) continue; @@ -577,7 +570,7 @@ bool IRNativeJit::DescribeCodePtr(const u8 *ptr, std::string &name) { const IRBlock *block = blocks_.GetBlock(block_num); if (block) { u32 start = 0, size = 0; - block->GetRange(start, size); + block->GetRange(&start, &size); // It helps to know which func this block is inside. const std::string label = g_symbolMap ? g_symbolMap->GetDescription(start) : ""; @@ -644,7 +637,8 @@ int IRNativeBackend::OffsetFromCodePtr(const u8 *ptr) { return (int)codeBlock.GetOffset(ptr); } -void IRNativeBackend::FinalizeBlock(IRBlock *block, int block_num, const JitOptions &jo) { +void IRNativeBackend::FinalizeBlock(IRBlockCache *irBlockCache, int block_num, const JitOptions &jo) { + IRBlock *block = irBlockCache->GetBlock(block_num); if (jo.enableBlocklink) { uint32_t pc = block->GetOriginalStart(); @@ -713,6 +707,14 @@ void IRNativeBlockCacheDebugInterface::Init(const IRNativeBackend *backend) { backend_ = backend; } +bool IRNativeBlockCacheDebugInterface::IsValidBlock(int blockNum) const { + return irBlocks_.IsValidBlock(blockNum); +} + +JitBlockMeta IRNativeBlockCacheDebugInterface::GetBlockMeta(int blockNum) const { + return irBlocks_.GetBlockMeta(blockNum); +} + int IRNativeBlockCacheDebugInterface::GetNumBlocks() const { return irBlocks_.GetNumBlocks(); } @@ -721,8 +723,12 @@ int IRNativeBlockCacheDebugInterface::GetBlockNumberFromStartAddress(u32 em_addr return irBlocks_.GetBlockNumberFromStartAddress(em_address, realBlocksOnly); } +JitBlockProfileStats IRNativeBlockCacheDebugInterface::GetBlockProfileStats(int blockNum) const { + return irBlocks_.GetBlockProfileStats(blockNum); +} + void IRNativeBlockCacheDebugInterface::GetBlockCodeRange(int blockNum, int *startOffset, int *size) const { - int blockOffset = irBlocks_.GetBlock(blockNum)->GetTargetOffset(); + int blockOffset = irBlocks_.GetBlock(blockNum)->GetNativeOffset(); int endOffset = backend_->GetNativeBlock(blockNum)->checkedOffset; // If endOffset is before, the checked entry is before the block start. @@ -732,7 +738,7 @@ void IRNativeBlockCacheDebugInterface::GetBlockCodeRange(int blockNum, int *star // Last block, get from current code pointer. endOffset = (int)codeBlock_->GetOffset(codeBlock_->GetCodePtr()); } else { - endOffset = irBlocks_.GetBlock(blockNum + 1)->GetTargetOffset(); + endOffset = irBlocks_.GetBlock(blockNum + 1)->GetNativeOffset(); _assert_msg_(endOffset >= blockOffset, "Next block not sequential, block=%d/%08x, next=%d/%08x", blockNum, blockOffset, blockNum + 1, endOffset); } } @@ -776,7 +782,7 @@ void IRNativeBlockCacheDebugInterface::ComputeStats(BlockCacheStats &bcStats) co // MIPS (PSP) size. u32 origAddr, origSize; - b.GetRange(origAddr, origSize); + b.GetRange(&origAddr, &origSize); double bloat = (double)codeSize / (double)origSize; if (bloat < minBloat) { @@ -788,7 +794,6 @@ void IRNativeBlockCacheDebugInterface::ComputeStats(BlockCacheStats &bcStats) co bcStats.maxBloatBlock = origAddr; } totalBloat += bloat; - bcStats.bloatMap[(float)bloat] = origAddr; } bcStats.numBlocks = numBlocks; bcStats.minBloat = (float)minBloat; diff --git a/Core/MIPS/IR/IRNativeCommon.h b/Core/MIPS/IR/IRNativeCommon.h index 4afc503698..a49ab07343 100644 --- a/Core/MIPS/IR/IRNativeCommon.h +++ b/Core/MIPS/IR/IRNativeCommon.h @@ -71,10 +71,10 @@ public: int OffsetFromCodePtr(const u8 *ptr); virtual void GenerateFixedCode(MIPSState *mipsState) = 0; - virtual bool CompileBlock(IRBlock *block, int block_num, bool preload) = 0; + virtual bool CompileBlock(IRBlockCache *irBlockCache, int block_num, bool preload) = 0; virtual void ClearAllBlocks() = 0; - virtual void InvalidateBlock(IRBlock *block, int block_num) = 0; - void FinalizeBlock(IRBlock *block, int block_num, const JitOptions &jo); + virtual void InvalidateBlock(IRBlockCache *irBlockCache, int block_num) = 0; + void FinalizeBlock(IRBlockCache *irBlockCache, int block_num, const JitOptions &jo); virtual void UpdateFCR31(MIPSState *mipsState) {} @@ -162,10 +162,13 @@ class IRNativeBlockCacheDebugInterface : public JitBlockCacheDebugInterface { public: IRNativeBlockCacheDebugInterface(const MIPSComp::IRBlockCache &irBlocks); void Init(const IRNativeBackend *backend); - int GetNumBlocks() const; - int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const; - JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const; - void ComputeStats(BlockCacheStats &bcStats) const; + int GetNumBlocks() const override; + int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override; + JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override; + JitBlockMeta GetBlockMeta(int blockNum) const override; + JitBlockProfileStats GetBlockProfileStats(int blockNum) const override; + void ComputeStats(BlockCacheStats &bcStats) const override; + bool IsValidBlock(int blockNum) const override; private: void GetBlockCodeRange(int blockNum, int *startOffset, int *size) const; @@ -182,7 +185,6 @@ public: void RunLoopUntil(u64 globalticks) override; void ClearCache() override; - void InvalidateCacheAt(u32 em_address, int length = 4) override; bool DescribeCodePtr(const u8 *ptr, std::string &name) override; bool CodeInRange(const u8 *ptr) const override; @@ -196,8 +198,8 @@ public: protected: void Init(IRNativeBackend &backend); - bool CompileTargetBlock(IRBlock *block, int block_num, bool preload) override; - void FinalizeTargetBlock(IRBlock *block, int block_num) override; + bool CompileNativeBlock(IRBlockCache *irBlockCache, int block_num, bool preload) override; + void FinalizeNativeBlock(IRBlockCache *irBlockCache, int block_num) override; IRNativeBackend *backend_ = nullptr; IRNativeHooks hooks_; diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index 2d368d0191..08455eee01 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -229,6 +229,15 @@ bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions CONDITIONAL_DISABLE; bool logBlocks = false; + + bool letThroughHalves = false; + if (opts.optimizeForInterpreter) { + // If we're using the interpreter, which can handle these instructions directly, + // don't break "half" instructions up. + // Of course, we still want to combine if possible. + letThroughHalves = true; + } + for (int i = 0, n = (int)in.GetInstructions().size(); i < n; ++i) { const IRInst &inst = in.GetInstructions()[i]; @@ -305,6 +314,11 @@ bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions switch (inst.op) { case IROp::Load32Left: if (!combineOpposite(IROp::Load32Right, -3, IROp::Load32, -3)) { + if (letThroughHalves) { + out.Write(inst); + break; + } + addCommonProlog(); // dest &= (0x00ffffff >> shift) // Alternatively, could shift to a wall and back (but would require two shifts each way.) @@ -339,6 +353,10 @@ bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions case IROp::Load32Right: if (!combineOpposite(IROp::Load32Left, 3, IROp::Load32, 0)) { + if (letThroughHalves) { + out.Write(inst); + break; + } addCommonProlog(); // IRTEMP_LR_VALUE >>= shift out.Write(IROp::Shr, IRTEMP_LR_VALUE, IRTEMP_LR_VALUE, IRTEMP_LR_SHIFT); @@ -382,6 +400,10 @@ bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions case IROp::Store32Left: if (!combineOpposite(IROp::Store32Right, -3, IROp::Store32, -3)) { + if (letThroughHalves) { + out.Write(inst); + break; + } addCommonProlog(); // IRTEMP_LR_VALUE &= 0xffffff00 << shift out.WriteSetConstant(IRTEMP_LR_MASK, 0xffffff00); @@ -399,6 +421,10 @@ bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions case IROp::Store32Right: if (!combineOpposite(IROp::Store32Left, 3, IROp::Store32, 0)) { + if (letThroughHalves) { + out.Write(inst); + break; + } addCommonProlog(); // IRTEMP_LR_VALUE &= 0x00ffffff << (24 - shift) out.WriteSetConstant(IRTEMP_LR_MASK, 0x00ffffff); @@ -1175,16 +1201,21 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { case IRTEMP_LR_VALUE: case IRTEMP_LR_MASK: case IRTEMP_LR_SHIFT: - // Unlike other registers, these don't need to persist between blocks. - // So we consider them not read unless proven read. - lastWrittenTo[dest] = i; - // If this is a copy, we might be able to optimize out the copy. - if (inst.op == IROp::Mov) { - Check check(dest, i, false); - check.srcReg = inst.src1; - checks.push_back(check); + // Check that it's not a barrier instruction (like CallReplacement). Don't want to even consider optimizing those. + if (!(inst.m.flags & IRFLAG_BARRIER)) { + // Unlike other registers, these don't need to persist between blocks. + // So we consider them not read unless proven read. + lastWrittenTo[dest] = i; + // If this is a copy, we might be able to optimize out the copy. + if (inst.op == IROp::Mov) { + Check check(dest, i, false); + check.srcReg = inst.src1; + checks.push_back(check); + } else { + checks.push_back(Check(dest, i, false)); + } } else { - checks.push_back(Check(dest, i, false)); + lastWrittenTo[dest] = i; } break; @@ -2136,7 +2167,7 @@ bool ReduceVec4Flush(const IRWriter &in, IRWriter &out, const IROptions &opts) { downgrade = true; if (downgrade) { - //WARN_LOG(JIT, "Vec4 downgrade by: %s", m->name); + //WARN_LOG(Log::JIT, "Vec4 downgrade by: %s", m->name); } if (!skip) @@ -2144,3 +2175,128 @@ bool ReduceVec4Flush(const IRWriter &in, IRWriter &out, const IROptions &opts) { } return logBlocks; } + +// This optimizes away redundant loads-after-stores, which are surprisingly not that uncommon. +bool OptimizeLoadsAfterStores(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; + // This tells us to skip an AND op that has been optimized out. + // Maybe we could skip multiple, but that'd slow things down and is pretty uncommon. + int nextSkip = -1; + + bool logBlocks = false; + for (int i = 0, n = (int)in.GetInstructions().size(); i < n; i++) { + IRInst inst = in.GetInstructions()[i]; + + // Just copy the last instruction. + if (i == n - 1) { + out.Write(inst); + break; + } + + out.Write(inst); + + IRInst next = in.GetInstructions()[i + 1]; + switch (inst.op) { + case IROp::Store32: + if (next.op == IROp::Load32 && + next.constant == inst.constant && + next.dest == inst.dest && + next.src1 == inst.src1) { + // The upcoming load is completely redundant. + // Skip it. + i++; + } + break; + case IROp::StoreVec4: + if (next.op == IROp::LoadVec4 && + next.constant == inst.constant && + next.dest == inst.dest && + next.src1 == inst.src1) { + // The upcoming load is completely redundant. These are common in Wipeout. + // Skip it. NOTE: It looks like vector load/stores uses different register assignments, but there's a union between dest and src3. + i++; + } + break; + default: + break; + } + } + + return logBlocks; +} + +bool OptimizeForInterpreter(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; + // This tells us to skip an AND op that has been optimized out. + // Maybe we could skip multiple, but that'd slow things down and is pretty uncommon. + int nextSkip = -1; + + bool logBlocks = false; + // We also move the downcount to the top so the interpreter can assume that it's there. + bool foundDowncount = false; + out.Write(IROp::Downcount); + + for (int i = 0, n = (int)in.GetInstructions().size(); i < n; i++) { + IRInst inst = in.GetInstructions()[i]; + + bool last = i == n - 1; + + // Specialize some instructions. + switch (inst.op) { + case IROp::Downcount: + if (!foundDowncount) { + // Move the value into the initial Downcount. + foundDowncount = true; + out.ReplaceConstant(0, inst.constant); + } else { + // Already had a downcount. Let's just re-emit it. + out.Write(inst); + } + break; + case IROp::AddConst: + if (inst.src1 == inst.dest) { + inst.op = IROp::OptAddConst; + } + out.Write(inst); + break; + case IROp::AndConst: + if (inst.src1 == inst.dest) { + inst.op = IROp::OptAndConst; + } + out.Write(inst); + break; + case IROp::OrConst: + if (inst.src1 == inst.dest) { + inst.op = IROp::OptOrConst; + } + out.Write(inst); + break; + case IROp::FMovToGPR: + if (!last) { + IRInst next = in.GetInstructions()[i + 1]; + if (next.op == IROp::ShrImm && next.src2 == 8 && next.src1 == next.dest && next.src1 == inst.dest) { + // Heavily used when writing display lists. + inst.op = IROp::OptFMovToGPRShr8; + i++; // Skip the next instruction. + } + } + out.Write(inst); + break; + case IROp::FMovFromGPR: + if (!last) { + IRInst next = in.GetInstructions()[i + 1]; + if (next.op == IROp::FCvtSW && next.src1 == inst.dest && next.dest == inst.dest) { + inst.op = IROp::OptFCvtSWFromGPR; + i++; // Skip the next + } + } + out.Write(inst); + break; + default: + out.Write(inst); + break; + } + } + + return logBlocks; +} diff --git a/Core/MIPS/IR/IRPassSimplify.h b/Core/MIPS/IR/IRPassSimplify.h index c7c644351e..5fbd2a8fba 100644 --- a/Core/MIPS/IR/IRPassSimplify.h +++ b/Core/MIPS/IR/IRPassSimplify.h @@ -16,3 +16,6 @@ bool ReorderLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts); bool MergeLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts); bool ApplyMemoryValidation(const IRWriter &in, IRWriter &out, const IROptions &opts); bool ReduceVec4Flush(const IRWriter &in, IRWriter &out, const IROptions &opts); + +bool OptimizeLoadsAfterStores(const IRWriter &in, IRWriter &out, const IROptions &opts); +bool OptimizeForInterpreter(const IRWriter &in, IRWriter &out, const IROptions &opts); diff --git a/Core/MIPS/IR/IRRegCache.cpp b/Core/MIPS/IR/IRRegCache.cpp index 01eed63fae..0b6b316821 100644 --- a/Core/MIPS/IR/IRRegCache.cpp +++ b/Core/MIPS/IR/IRRegCache.cpp @@ -105,7 +105,7 @@ void IRImmRegCache::MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt) { IRNativeRegCacheBase::IRNativeRegCacheBase(MIPSComp::JitOptions *jo) : jo_(jo) {} -void IRNativeRegCacheBase::Start(MIPSComp::IRBlock *irBlock) { +void IRNativeRegCacheBase::Start(MIPSComp::IRBlockCache *irBlockCache, int blockNum) { if (!initialReady_) { SetupInitialRegs(); initialReady_ = true; @@ -114,6 +114,8 @@ void IRNativeRegCacheBase::Start(MIPSComp::IRBlock *irBlock) { memcpy(nr, nrInitial_, sizeof(nr[0]) * config_.totalNativeRegs); memcpy(mr, mrInitial_, sizeof(mr)); + irBlock_ = irBlockCache->GetBlock(blockNum); + int numStatics; const StaticAllocation *statics = GetStaticAllocations(numStatics); for (int i = 0; i < numStatics; i++) { @@ -124,10 +126,11 @@ void IRNativeRegCacheBase::Start(MIPSComp::IRBlock *irBlock) { mr[statics[i].mr].nReg = statics[i].nr; mr[statics[i].mr].isStatic = true; // Lock it until the very end. - mr[statics[i].mr].spillLockIRIndex = irBlock->GetNumInstructions(); + mr[statics[i].mr].spillLockIRIndex = irBlock_->GetNumIRInstructions(); } - irBlock_ = irBlock; + irBlockNum_ = blockNum; + irBlockCache_ = irBlockCache; irIndex_ = 0; } @@ -235,7 +238,7 @@ uint64_t IRNativeRegCacheBase::GetGPR2Imm(IRReg base) { void IRNativeRegCacheBase::SetGPRImm(IRReg gpr, uint32_t immVal) { _dbg_assert_(IsValidGPR(gpr)); if (gpr == MIPS_REG_ZERO && immVal != 0) { - ERROR_LOG_REPORT(JIT, "Trying to set immediate %08x to r0", immVal); + ERROR_LOG_REPORT(Log::JIT, "Trying to set immediate %08x to r0", immVal); return; } @@ -384,7 +387,7 @@ IRNativeReg IRNativeRegCacheBase::AllocateReg(MIPSLoc type, MIPSMap flags) { } // Uh oh, we have all of them spilllocked.... - ERROR_LOG_REPORT(JIT, "Out of spillable registers in block PC %08x, index %d", irBlock_->GetOriginalStart(), irIndex_); + ERROR_LOG_REPORT(Log::JIT, "Out of spillable registers in block PC %08x, index %d", irBlock_->GetOriginalStart(), irIndex_); _assert_(bestToSpill != -1); return -1; } @@ -430,8 +433,8 @@ bool IRNativeRegCacheBase::IsRegClobbered(MIPSLoc type, IRReg r) const { info.lookaheadCount = UNUSED_LOOKAHEAD_OPS; // We look starting one ahead, unlike spilling. We want to know if it clobbers later. info.currentIndex = irIndex_ + 1; - info.instructions = irBlock_->GetInstructions(); - info.numInstructions = irBlock_->GetNumInstructions(); + info.instructions = irBlockCache_->GetBlockInstructionPtr(irBlockNum_); + info.numInstructions = irBlock_->GetNumIRInstructions(); // Make sure we're on the first one if this is multi-lane. IRReg first = r; @@ -457,8 +460,8 @@ bool IRNativeRegCacheBase::IsRegRead(MIPSLoc type, IRReg first) const { info.lookaheadCount = UNUSED_LOOKAHEAD_OPS; // We look starting one ahead, unlike spilling. info.currentIndex = irIndex_ + 1; - info.instructions = irBlock_->GetInstructions(); - info.numInstructions = irBlock_->GetNumInstructions(); + info.instructions = irBlockCache_->GetBlockInstructionPtr(irBlockNum_); + info.numInstructions = irBlock_->GetNumIRInstructions(); // Note: this intentionally doesn't look at the full reg, only the lane. IRUsage usage = GetNextRegUsage(info, type, first); @@ -474,8 +477,8 @@ IRNativeReg IRNativeRegCacheBase::FindBestToSpill(MIPSLoc type, MIPSMap flags, b IRSituation info; info.lookaheadCount = UNUSED_LOOKAHEAD_OPS; info.currentIndex = irIndex_; - info.instructions = irBlock_->GetInstructions(); - info.numInstructions = irBlock_->GetNumInstructions(); + info.instructions = irBlockCache_->GetBlockInstructionPtr(irBlockNum_); + info.numInstructions = irBlock_->GetNumIRInstructions(); *clobbered = false; for (int i = 0; i < allocCount; i++) { @@ -583,7 +586,7 @@ void IRNativeRegCacheBase::FlushNativeReg(IRNativeReg nreg) { } _dbg_assert_(!mr[nr[nreg].mipsReg].isStatic); if (mr[nr[nreg].mipsReg].isStatic) { - ERROR_LOG(JIT, "Cannot FlushNativeReg a statically mapped register"); + ERROR_LOG(Log::JIT, "Cannot FlushNativeReg a statically mapped register"); return; } @@ -705,7 +708,7 @@ void IRNativeRegCacheBase::FlushAll(bool gprs, bool fprs) { } else if (mr[i].loc == MIPSLoc::REG_IMM) { // The register already contains the immediate. if (nr[nreg].pointerified) { - ERROR_LOG(JIT, "RVREG_IMM but pointerified. Wrong."); + ERROR_LOG(Log::JIT, "RVREG_IMM but pointerified. Wrong."); nr[nreg].pointerified = false; } mr[i].loc = MIPSLoc::REG; @@ -743,7 +746,7 @@ void IRNativeRegCacheBase::FlushAll(bool gprs, bool fprs) { // Sanity check for (int i = 0; i < config_.totalNativeRegs; i++) { if (nr[i].mipsReg != IRREG_INVALID && !mr[nr[i].mipsReg].isStatic) { - ERROR_LOG_REPORT(JIT, "Flush fail: nr[%i].mipsReg=%i", i, nr[i].mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Flush fail: nr[%i].mipsReg=%i", i, nr[i].mipsReg); } } } @@ -908,6 +911,7 @@ void IRNativeRegCacheBase::MappingFromInst(const IRInst &inst, Mapping mapping[3 case '\0': case '_': case 'C': + case 'r': case 'I': case 'v': case 's': @@ -1026,8 +1030,8 @@ void IRNativeRegCacheBase::MapNativeReg(MIPSLoc type, IRNativeReg nreg, IRReg fi IRSituation info; info.lookaheadCount = 16; info.currentIndex = irIndex_; - info.instructions = irBlock_->GetInstructions(); - info.numInstructions = irBlock_->GetNumInstructions(); + info.instructions = irBlockCache_->GetBlockInstructionPtr(irBlockNum_); + info.numInstructions = irBlock_->GetNumIRInstructions(); IRReg basefpr = first - oldlane - 32; clobbered = true; @@ -1213,7 +1217,7 @@ IRNativeReg IRNativeRegCacheBase::MapNativeRegAsPointer(IRReg gpr) { nr[nreg].pointerified = true; } } else { - ERROR_LOG(JIT, "MapNativeRegAsPointer: MapNativeReg failed to allocate a register?"); + ERROR_LOG(Log::JIT, "MapNativeRegAsPointer: MapNativeReg failed to allocate a register?"); } return nreg; } diff --git a/Core/MIPS/IR/IRRegCache.h b/Core/MIPS/IR/IRRegCache.h index 4301886b44..742d1cae33 100644 --- a/Core/MIPS/IR/IRRegCache.h +++ b/Core/MIPS/IR/IRRegCache.h @@ -40,6 +40,7 @@ class MIPSState; namespace MIPSComp { class IRBlock; +class IRBlockCache; struct JitOptions; } @@ -153,7 +154,7 @@ public: IRNativeRegCacheBase(MIPSComp::JitOptions *jo); virtual ~IRNativeRegCacheBase() {} - virtual void Start(MIPSComp::IRBlock *irBlock); + virtual void Start(MIPSComp::IRBlockCache *irBlockCache, int blockNum); void SetIRIndex(int index) { irIndex_ = index; } @@ -248,7 +249,9 @@ protected: bool IsValidFPR(IRReg r) const; MIPSComp::JitOptions *jo_; + int irBlockNum_ = 0; const MIPSComp::IRBlock *irBlock_ = nullptr; + const MIPSComp::IRBlockCache *irBlockCache_ = nullptr; int irIndex_ = 0; struct { diff --git a/Core/MIPS/JitCommon/JitBlockCache.cpp b/Core/MIPS/JitCommon/JitBlockCache.cpp index 120207eb60..7c04a1436a 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.cpp +++ b/Core/MIPS/JitCommon/JitBlockCache.cpp @@ -181,7 +181,7 @@ void JitBlockCache::ProxyBlock(u32 rootAddress, u32 startAddress, u32 size, cons // instead of creating a new block. int num = GetBlockNumberFromStartAddress(startAddress, false); if (num != -1) { - DEBUG_LOG(HLE, "Adding proxy root %08x to block at %08x", rootAddress, startAddress); + DEBUG_LOG(Log::HLE, "Adding proxy root %08x to block at %08x", rootAddress, startAddress); if (!blocks_[num].proxyFor) { blocks_[num].proxyFor = new std::vector(); } @@ -334,7 +334,7 @@ int JitBlockCache::GetBlockNumberFromEmuHackOp(MIPSOpcode inst, bool ignoreBad) const u8 *baseoff = codeBlock_->GetBasePtr() + off; if (baseoff < codeBlock_->GetBasePtr() || baseoff >= codeBlock_->GetCodePtr()) { if (!ignoreBad) { - ERROR_LOG(JIT, "JitBlockCache: Invalid Emuhack Op %08x", inst.encoding); + ERROR_LOG(Log::JIT, "JitBlockCache: Invalid Emuhack Op %08x", inst.encoding); } return -1; } @@ -451,7 +451,7 @@ void JitBlockCache::LinkBlock(int i) { if (ppp.first == ppp.second) return; for (auto iter = ppp.first; iter != ppp.second; ++iter) { - // INFO_LOG(JIT, "Linking block %i to block %i", iter->second, i); + // INFO_LOG(Log::JIT, "Linking block %i to block %i", iter->second, i); LinkBlockExits(iter->second); } } @@ -464,7 +464,7 @@ void JitBlockCache::UnlinkBlock(int i) { for (auto iter = ppp.first; iter != ppp.second; ++iter) { if ((size_t)iter->second >= num_blocks_) { // Something probably went very wrong. Try to stumble along nevertheless. - ERROR_LOG(JIT, "UnlinkBlock: Invalid block number %d", iter->second); + ERROR_LOG(Log::JIT, "UnlinkBlock: Invalid block number %d", iter->second); continue; } JitBlock &sourceBlock = blocks_[iter->second]; @@ -499,7 +499,7 @@ std::vector JitBlockCache::SaveAndClearEmuHackOps() { void JitBlockCache::RestoreSavedEmuHackOps(const std::vector &saved) { if (num_blocks_ != (int)saved.size()) { - ERROR_LOG(JIT, "RestoreSavedEmuHackOps: Wrong saved block size."); + ERROR_LOG(Log::JIT, "RestoreSavedEmuHackOps: Wrong saved block size."); return; } @@ -516,7 +516,7 @@ void JitBlockCache::RestoreSavedEmuHackOps(const std::vector &saved) { void JitBlockCache::DestroyBlock(int block_num, DestroyType type) { if (block_num < 0 || block_num >= num_blocks_) { - ERROR_LOG_REPORT(JIT, "DestroyBlock: Invalid block number %d", block_num); + ERROR_LOG_REPORT(Log::JIT, "DestroyBlock: Invalid block number %d", block_num); return; } JitBlock *b = &blocks_[block_num]; @@ -554,7 +554,7 @@ void JitBlockCache::DestroyBlock(int block_num, DestroyType type) { if (b->invalid) { if (type == DestroyType::INVALIDATE) - ERROR_LOG(JIT, "Invalidating invalid block %d", block_num); + ERROR_LOG(Log::JIT, "Invalidating invalid block %d", block_num); return; } @@ -581,7 +581,7 @@ void JitBlockCache::DestroyBlock(int block_num, DestroyType type) { MIPSComp::jit->UnlinkBlock(writableEntry, b->originalAddress); } } else { - ERROR_LOG(JIT, "Unlinking block with no entry: %08x (%d)", b->originalAddress, block_num); + ERROR_LOG(Log::JIT, "Unlinking block with no entry: %08x (%d)", b->originalAddress, block_num); } } @@ -591,7 +591,7 @@ void JitBlockCache::InvalidateICache(u32 address, const u32 length) { const u32 pEnd = pAddr + length; if (pEnd < pAddr) { - ERROR_LOG(JIT, "Bad InvalidateICache: %08x with len=%d", address, length); + ERROR_LOG(Log::JIT, "Bad InvalidateICache: %08x with len=%d", address, length); return; } @@ -637,7 +637,7 @@ void JitBlockCache::InvalidateChangedBlocks() { } if (changed) { - DEBUG_LOG(JIT, "Invalidating changed block at %08x", b.originalAddress); + DEBUG_LOG(Log::JIT, "Invalidating changed block at %08x", b.originalAddress); DestroyBlock(block_num, DestroyType::INVALIDATE); } } @@ -681,7 +681,6 @@ void JitBlockCache::ComputeStats(BlockCacheStats &bcStats) const { bcStats.maxBloatBlock = b->originalAddress; } totalBloat += bloat; - bcStats.bloatMap[(float)bloat] = b->originalAddress; } bcStats.numBlocks = num_blocks_; bcStats.minBloat = (float)minBloat; @@ -710,6 +709,5 @@ JitBlockDebugInfo JitBlockCache::GetBlockDebugInfo(int blockNum) const { #elif PPSSPP_ARCH(RISCV64) debugInfo.targetDisasm = DisassembleRV64(block->normalEntry, block->codeSize); #endif - return debugInfo; } diff --git a/Core/MIPS/JitCommon/JitBlockCache.h b/Core/MIPS/JitCommon/JitBlockCache.h index bcf1f5c083..16457b0b06 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.h +++ b/Core/MIPS/JitCommon/JitBlockCache.h @@ -42,7 +42,6 @@ struct BlockCacheStats { u32 minBloatBlock; float maxBloat; u32 maxBloatBlock; - std::map bloatMap; }; enum class DestroyType { @@ -103,12 +102,27 @@ struct JitBlockDebugInfo { std::vector targetDisasm; }; +struct JitBlockMeta { + bool valid; + uint32_t addr; + uint32_t sizeInBytes; +}; + +struct JitBlockProfileStats { + int64_t executions; + int64_t totalNanos; +}; + class JitBlockCacheDebugInterface { public: virtual int GetNumBlocks() const = 0; virtual int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const = 0; - virtual JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const = 0; + virtual JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const = 0; // Expensive + virtual JitBlockMeta GetBlockMeta(int blockNum) const = 0; + virtual JitBlockProfileStats GetBlockProfileStats(int blockNum) const = 0; virtual void ComputeStats(BlockCacheStats &bcStats) const = 0; + virtual bool IsValidBlock(int blockNum) const = 0; + virtual bool SupportsProfiling() const { return false; } virtual ~JitBlockCacheDebugInterface() {} }; @@ -164,6 +178,19 @@ public: void RestoreSavedEmuHackOps(const std::vector &saved); int GetNumBlocks() const override { return num_blocks_; } + bool IsValidBlock(int blockNum) const override { return blockNum >= 0 && blockNum < num_blocks_ && !blocks_[blockNum].invalid; } + JitBlockMeta GetBlockMeta(int blockNum) const override { + JitBlockMeta meta{}; + if (IsValidBlock(blockNum)) { + meta.valid = true; + meta.addr = blocks_[blockNum].originalAddress; + meta.sizeInBytes = blocks_[blockNum].originalSize; + } + return meta; + } + JitBlockProfileStats GetBlockProfileStats(int blockNum) const override { + return JitBlockProfileStats{}; + } static int GetBlockExitSize(); diff --git a/Core/MIPS/JitCommon/JitCommon.cpp b/Core/MIPS/JitCommon/JitCommon.cpp index 752cb67b7f..1708bf1ea6 100644 --- a/Core/MIPS/JitCommon/JitCommon.cpp +++ b/Core/MIPS/JitCommon/JitCommon.cpp @@ -96,9 +96,9 @@ namespace MIPSComp { // For a branch (not a jump), it actually should try the delay slot and take its target potentially. // This is similar to the VFPU case and has not been seen, so just report it. if (!isJump && SignExtend16ToU32(branchInfo.delaySlotOp) != SignExtend16ToU32(branchInfo.op) - 1) - ERROR_LOG_REPORT(JIT, "Branch in branch delay slot at %08x with different target", branchInfo.compilerPC); + ERROR_LOG_REPORT(Log::JIT, "Branch in branch delay slot at %08x with different target", branchInfo.compilerPC); if (isJump && branchInfo.likely && (branchInfo.delaySlotInfo & (OUT_RA | OUT_RD)) != 0) - ERROR_LOG_REPORT(JIT, "Jump in likely branch delay slot with link at %08x", branchInfo.compilerPC); + ERROR_LOG_REPORT(Log::JIT, "Jump in likely branch delay slot with link at %08x", branchInfo.compilerPC); } return notTakenTarget; } diff --git a/Core/MIPS/JitCommon/JitState.h b/Core/MIPS/JitCommon/JitState.h index 37acde3b62..ef90409e36 100644 --- a/Core/MIPS/JitCommon/JitState.h +++ b/Core/MIPS/JitCommon/JitState.h @@ -162,20 +162,20 @@ namespace MIPSComp { private: void LogSTPrefix(const char *name, int p, int pflag) { if ((prefixSFlag & PREFIX_KNOWN) == 0) { - ERROR_LOG(JIT, "%s: unknown (%08x %i)", name, p, pflag); + ERROR_LOG(Log::JIT, "%s: unknown (%08x %i)", name, p, pflag); } else if (prefixS != 0xE4) { - ERROR_LOG(JIT, "%s: %08x flag: %i", name, p, pflag); + ERROR_LOG(Log::JIT, "%s: %08x flag: %i", name, p, pflag); } else { - WARN_LOG(JIT, "%s: %08x flag: %i", name, p, pflag); + WARN_LOG(Log::JIT, "%s: %08x flag: %i", name, p, pflag); } } void LogDPrefix() { if ((prefixDFlag & PREFIX_KNOWN) == 0) { - ERROR_LOG(JIT, "D: unknown (%08x %i)", prefixD, prefixDFlag); + ERROR_LOG(Log::JIT, "D: unknown (%08x %i)", prefixD, prefixDFlag); } else if (prefixD != 0) { - ERROR_LOG(JIT, "D: (%08x %i)", prefixD, prefixDFlag); + ERROR_LOG(Log::JIT, "D: (%08x %i)", prefixD, prefixDFlag); } else { - WARN_LOG(JIT, "D: %08x flag: %i", prefixD, prefixDFlag); + WARN_LOG(Log::JIT, "D: %08x flag: %i", prefixD, prefixDFlag); } } }; @@ -237,6 +237,8 @@ namespace MIPSComp { // ARM64 and RV64 bool useStaticAlloc; bool enablePointerify; + // IR Interpreter + bool optimizeForInterpreter; // Common bool enableBlocklink; @@ -245,6 +247,4 @@ namespace MIPSComp { bool continueJumps; int continueMaxInstructions; }; - } - diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index 91223bd637..a5e522ce6b 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -45,7 +45,6 @@ MIPSDebugInterface *currentDebugMIPS = &debugr4k; u8 voffset[128]; u8 fromvoffset[128]; - #ifndef M_LOG2E #define M_E 2.71828182845904523536f #define M_LOG2E 1.44269504088896340736f @@ -89,7 +88,6 @@ const float cst_constants[32] = { sqrtf(3.0f)/2.0f, }; - MIPSState::MIPSState() { MIPSComp::jit = nullptr; @@ -154,13 +152,12 @@ MIPSState::MIPSState() { for (int i = 0; i < (int)ARRAY_SIZE(firstThirtyTwo); i++) { if (voffset[firstThirtyTwo[i]] != i) { - ERROR_LOG(CPU, "Wrong voffset order! %i: %i should have been %i", firstThirtyTwo[i], voffset[firstThirtyTwo[i]], i); + ERROR_LOG(Log::CPU, "Wrong voffset order! %i: %i should have been %i", firstThirtyTwo[i], voffset[firstThirtyTwo[i]], i); } } } MIPSState::~MIPSState() { - Shutdown(); } void MIPSState::Shutdown() { @@ -214,7 +211,7 @@ void MIPSState::Init() { if (PSP_CoreParameter().cpuCore == CPUCore::JIT || PSP_CoreParameter().cpuCore == CPUCore::JIT_IR) { MIPSComp::jit = MIPSComp::CreateNativeJit(this, PSP_CoreParameter().cpuCore == CPUCore::JIT_IR); } else if (PSP_CoreParameter().cpuCore == CPUCore::IR_INTERPRETER) { - MIPSComp::jit = new MIPSComp::IRJit(this); + MIPSComp::jit = new MIPSComp::IRJit(this, false); } else { MIPSComp::jit = nullptr; } @@ -236,7 +233,7 @@ void MIPSState::UpdateCore(CPUCore desired) { switch (PSP_CoreParameter().cpuCore) { case CPUCore::JIT: case CPUCore::JIT_IR: - INFO_LOG(CPU, "Switching to JIT%s", PSP_CoreParameter().cpuCore == CPUCore::JIT_IR ? " IR" : ""); + INFO_LOG(Log::CPU, "Switching to JIT%s", PSP_CoreParameter().cpuCore == CPUCore::JIT_IR ? " IR" : ""); if (oldjit) { std::lock_guard guard(MIPSComp::jitLock); MIPSComp::jit = nullptr; @@ -246,17 +243,17 @@ void MIPSState::UpdateCore(CPUCore desired) { break; case CPUCore::IR_INTERPRETER: - INFO_LOG(CPU, "Switching to IR interpreter"); + INFO_LOG(Log::CPU, "Switching to IR interpreter"); if (oldjit) { std::lock_guard guard(MIPSComp::jitLock); MIPSComp::jit = nullptr; delete oldjit; } - newjit = new MIPSComp::IRJit(this); + newjit = new MIPSComp::IRJit(this, false); break; case CPUCore::INTERPRETER: - INFO_LOG(CPU, "Switching to interpreter"); + INFO_LOG(Log::CPU, "Switching to interpreter"); if (oldjit) { std::lock_guard guard(MIPSComp::jitLock); MIPSComp::jit = nullptr; diff --git a/Core/MIPS/MIPS.h b/Core/MIPS/MIPS.h index dad324609a..4b53fe2e58 100644 --- a/Core/MIPS/MIPS.h +++ b/Core/MIPS/MIPS.h @@ -194,7 +194,8 @@ public: // Register-allocated JIT Temps don't get flushed so we don't reserve space for them. // However, the IR interpreter needs some temps that can stick around between ops. - // Can be indexed through r[] using indices 192+. + // Can be indexed through r[] using indices 192+, thanks to predictable struct layout. + // Unfortunately, UBSAN isn't too happy about these. u32 t[16]; //192 // If vfpuCtrl (prefixes) get mysterious values, check the VFPU regcache code. @@ -219,7 +220,7 @@ public: }; u32 nextPC; - int downcount; // This really doesn't belong here, it belongs in CoreTiming. But you gotta do what you gotta do, this needs to be reachable in the ARM JIT. + int downcount; // This really doesn't belong here, it belongs in CoreTiming. But you gotta do what you gotta do, this needs to be reachable in the JITs without additional pointers. bool inDelaySlot; int llBit; // ll/sc @@ -261,7 +262,6 @@ public: int RunLoopUntil(u64 globalTicks); // To clear jit caches, etc. void InvalidateICache(u32 address, int length = 4); - void ClearJitCache(); void ProcessPendingClears(); @@ -271,7 +271,6 @@ public: volatile bool hasPendingClears = false; }; - class MIPSDebugInterface; //The one we are compiling or running currently diff --git a/Core/MIPS/MIPS/MipsJit.cpp b/Core/MIPS/MIPS/MipsJit.cpp index eef7938668..4086ef847d 100644 --- a/Core/MIPS/MIPS/MipsJit.cpp +++ b/Core/MIPS/MIPS/MipsJit.cpp @@ -149,7 +149,7 @@ void MipsJit::Compile(u32 em_address) { bool cleanSlate = false; if (js.hasSetRounding && !js.lastSetRounding) { - WARN_LOG(JIT, "Detected rounding mode usage, rebuilding jit with checks"); + WARN_LOG(Log::JIT, "Detected rounding mode usage, rebuilding jit with checks"); // Won't loop, since hasSetRounding is only ever set to 1. js.lastSetRounding = js.hasSetRounding; cleanSlate = true; @@ -237,7 +237,7 @@ bool MipsJit::DescribeCodePtr(const u8 *ptr, std::string &name) void MipsJit::Comp_RunBlock(MIPSOpcode op) { // This shouldn't be necessary, the dispatcher should catch us before we get here. - ERROR_LOG(JIT, "Comp_RunBlock should never be reached!"); + ERROR_LOG(Log::JIT, "Comp_RunBlock should never be reached!"); } void MipsJit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) { diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 45ff5e14c2..6816d9172d 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -514,6 +514,8 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x795d940ad0a605f8, 40, "gow_fps_hack", }, // God of War (all) { 0x4c75043b7b0c643b, 512, "gow_vortex_hack", }, // God of War: Ghost of Sparta vortex timer hack, avoids softlock #8299 { 0x7624dde603717640, 288, "ZZT3_select_hack", }, // Zettai Zetsumei Toshi 3 - bypasses softlock on character select screen #4901 + { 0x0dc5ca84f707863c, 452, "blitz_fps_hack", }, // Blitz: Overtime + { 0xf93d3cd093595a6c, 856, "brian_lara_fps_hack", }, // Brian Lara 2007: Pressure Play }; namespace MIPSAnalyst { @@ -735,7 +737,7 @@ namespace MIPSAnalyst { } totalUsedRegs += numUsedRegs; numAnalyzings++; - VERBOSE_LOG(CPU, "[ %08x ] Used regs: %i Average: %f", address, numUsedRegs, (float)totalUsedRegs / (float)numAnalyzings); + VERBOSE_LOG(Log::CPU, "[ %08x ] Used regs: %i Average: %f", address, numUsedRegs, (float)totalUsedRegs / (float)numAnalyzings); return results; } @@ -928,7 +930,7 @@ skip: } double et = time_now_d(); - NOTICE_LOG(JIT, "Precompiled %d MIPS functions in %0.2f milliseconds", (int)functions.size(), (et - st) * 1000.0); + NOTICE_LOG(Log::JIT, "Precompiled %d MIPS functions in %0.2f milliseconds", (int)functions.size(), (et - st) * 1000.0); } static const char *DefaultFunctionName(char buffer[256], u32 startAddr) { @@ -1217,7 +1219,7 @@ skip: hashMap.insert(hfun); return; } else if (!iter->hasHash || size == 0) { - ERROR_LOG(HLE, "%s: %08x %08x : match but no hash (%i) or no size", name, startAddr, size, iter->hasHash); + ERROR_LOG(Log::HLE, "%s: %08x %08x : match but no hash (%i) or no size", name, startAddr, size, iter->hasHash); } } } @@ -1327,7 +1329,7 @@ skip: FILE *file = File::OpenCFile(filename, "wt"); if (!file) { - WARN_LOG(LOADER, "Could not store hash map: %s", filename.c_str()); + WARN_LOG(Log::Loader, "Could not store hash map: %s", filename.c_str()); return; } @@ -1335,7 +1337,7 @@ skip: const HashMapFunc &mf = *it; if (!mf.hardcoded) { if (fprintf(file, "%016llx:%d = %s\n", mf.hash, mf.size, mf.name) <= 0) { - WARN_LOG(LOADER, "Could not store hash map: %s", filename.c_str()); + WARN_LOG(Log::Loader, "Could not store hash map: %s", filename.c_str()); break; } } @@ -1384,7 +1386,7 @@ skip: void LoadHashMap(const Path &filename) { FILE *file = File::OpenCFile(filename, "rt"); if (!file) { - WARN_LOG(LOADER, "Could not load hash map: %s", filename.c_str()); + WARN_LOG(Log::Loader, "Could not load hash map: %s", filename.c_str()); return; } hashmapFileName = filename; @@ -1395,7 +1397,7 @@ skip: if (fscanf(file, "%llx:%d = %63s\n", &mf.hash, &mf.size, mf.name) < 3) { char temp[1024]; if (!fgets(temp, 1024, file)) { - WARN_LOG(LOADER, "Could not read from hash map: %s", filename.c_str()); + WARN_LOG(Log::Loader, "Could not read from hash map: %s", filename.c_str()); } continue; } diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index 93644706d6..ade4f32cd1 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -42,6 +42,7 @@ #define FsI(i) (currentMIPS->fs[i]) #define PC (currentMIPS->pc) +#define _SIMM16_SHL2 ((u32)(s32)(s16)(op & 0xFFFF) << 2) #define _RS ((op>>21) & 0x1F) #define _RT ((op>>16) & 0x1F) #define _RD ((op>>11) & 0x1F) @@ -94,7 +95,7 @@ namespace MIPSInt { void Int_Cache(MIPSOpcode op) { - int imm = SignExtend16ToS32(op & 0xFFFF); + int imm = SignExtend16ToS32(op); int rs = _RS; uint32_t addr = R(rs) + imm; int func = (op >> 16) & 0x1F; @@ -120,12 +121,12 @@ namespace MIPSInt MIPSComp::jit->InvalidateCacheAt(alignedAddr, size); // Using a bool to avoid locking/etc. in case it's slow. if (!reportedAlignment && (addr & 0x3F) != 0) { - WARN_LOG_REPORT(JIT, "Unaligned icache invalidation of %08x (%08x + %d) at PC=%08x", addr, R(rs), imm, PC); + WARN_LOG_REPORT(Log::JIT, "Unaligned icache invalidation of %08x (%08x + %d) at PC=%08x", addr, R(rs), imm, PC); reportedAlignment = true; } if (alignedAddr <= PC + 4 && alignedAddr + size >= PC - 4) { // This is probably rare so we don't use a static bool. - WARN_LOG_REPORT_ONCE(icacheInvalidatePC, JIT, "Invalidating address near PC: %08x (%08x + %d) at PC=%08x", addr, R(rs), imm, PC); + WARN_LOG_REPORT_ONCE(icacheInvalidatePC, Log::JIT, "Invalidating address near PC: %08x (%08x + %d) at PC=%08x", addr, R(rs), imm, PC); } } break; @@ -144,7 +145,7 @@ namespace MIPSInt break; default: - DEBUG_LOG(CPU, "cache instruction affecting %08x : function %i", addr, func); + DEBUG_LOG(Log::CPU, "cache instruction affecting %08x : function %i", addr, func); } PC += 4; @@ -153,7 +154,7 @@ namespace MIPSInt void Int_Syscall(MIPSOpcode op) { // Need to pre-move PC, as CallSyscall may result in a rescheduling! - // To do this neater, we'll need a little generated kernel loop that syscall can jump to and then RFI from + // To do this neater, we'll need a little generated kernel loop that syscall can jump to and then RFI from // but I don't see a need to bother. if (mipsr4k.inDelaySlot) { @@ -169,7 +170,7 @@ namespace MIPSInt void Int_Sync(MIPSOpcode op) { - //DEBUG_LOG(CPU, "sync"); + //DEBUG_LOG(Log::CPU, "sync"); PC += 4; } @@ -182,12 +183,12 @@ namespace MIPSInt void Int_RelBranch(MIPSOpcode op) { - int imm = (signed short)(op&0xFFFF)<<2; + int imm = _SIMM16_SHL2; int rs = _RS; int rt = _RT; u32 addr = PC + imm + 4; - switch (op >> 26) + switch (op >> 26) { case 4: if (R(rt) == R(rs)) DelayBranchTo(addr); else PC += 4; break; //beq case 5: if (R(rt) != R(rs)) DelayBranchTo(addr); else PC += 4; break; //bne @@ -207,7 +208,7 @@ namespace MIPSInt void Int_RelBranchRI(MIPSOpcode op) { - int imm = (signed short)(op&0xFFFF)<<2; + int imm = _SIMM16_SHL2; int rs = _RS; u32 addr = PC + imm + 4; @@ -230,7 +231,7 @@ namespace MIPSInt void Int_VBranch(MIPSOpcode op) { - int imm = (signed short)(op&0xFFFF)<<2; + int imm = _SIMM16_SHL2; u32 addr = PC + imm + 4; // x, y, z, w, any, all, (invalid), (invalid) @@ -248,7 +249,7 @@ namespace MIPSInt void Int_FPUBranch(MIPSOpcode op) { - int imm = (signed short)(op&0xFFFF)<<2; + int imm = _SIMM16_SHL2; u32 addr = PC + imm + 4; switch((op>>16)&0x1f) { @@ -261,16 +262,16 @@ namespace MIPSInt break; } } - + void Int_JumpType(MIPSOpcode op) { if (mipsr4k.inDelaySlot) - ERROR_LOG(CPU, "Jump in delay slot :("); + ERROR_LOG(Log::CPU, "Jump in delay slot :("); u32 off = ((op & 0x03FFFFFF) << 2); u32 addr = (currentMIPS->pc & 0xF0000000) | off; - switch (op>>26) + switch (op>>26) { case 2: //j if (!mipsr4k.inDelaySlot) @@ -292,13 +293,13 @@ namespace MIPSInt if (mipsr4k.inDelaySlot) { // There's one of these in Star Soldier at 0881808c, which seems benign. - ERROR_LOG(CPU, "Jump in delay slot :("); + ERROR_LOG(Log::CPU, "Jump in delay slot :("); } int rs = _RS; int rd = _RD; u32 addr = R(rs); - switch (op & 0x3f) + switch (op & 0x3f) { case 8: //jr if (!mipsr4k.inDelaySlot) @@ -328,7 +329,7 @@ namespace MIPSInt return; //nop } - switch (op>>26) + switch (op>>26) { case 8: R(rt) = R(rs) + simm; break; //addi case 9: R(rt) = R(rs) + simm; break; //addiu @@ -391,7 +392,7 @@ namespace MIPSInt return; } - switch (op & 63) + switch (op & 63) { case 10: if (R(rt) == 0) R(rd) = R(rs); break; //movz case 11: if (R(rt) != 0) R(rd) = R(rs); break; //movn @@ -428,7 +429,7 @@ namespace MIPSInt return; } - switch (op >> 26) + switch (op >> 26) { case 32: R(rt) = SignExtend8ToU32(Memory::Read_U8(addr)); break; //lb case 33: R(rt) = SignExtend16ToU32(Memory::Read_U16(addr)); break; //lh @@ -522,7 +523,7 @@ namespace MIPSInt } else if (fs == 0) { R(rt) = MIPSState::FCR0_VALUE; } else { - WARN_LOG_REPORT(CPU, "ReadFCR: Unexpected reg %d", fs); + WARN_LOG_REPORT(Log::CPU, "ReadFCR: Unexpected reg %d", fs); R(rt) = 0; } break; @@ -544,12 +545,12 @@ namespace MIPSInt MIPSComp::jit->UpdateFCR31(); } } else { - WARN_LOG_REPORT(CPU, "WriteFCR: Unexpected reg %d (value %08x)", fs, value); + WARN_LOG_REPORT(Log::CPU, "WriteFCR: Unexpected reg %d (value %08x)", fs, value); } - DEBUG_LOG(CPU, "FCR%i written to, value %08x", fs, value); + DEBUG_LOG(Log::CPU, "FCR%i written to, value %08x", fs, value); break; } - + default: _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; @@ -590,7 +591,7 @@ namespace MIPSInt int rs = _RS; int rd = _RD; - switch (op & 63) + switch (op & 63) { case 24: //mult { @@ -702,16 +703,16 @@ namespace MIPSInt PC += 4; return; } - + switch (op & 0x3f) { case 0: R(rd) = R(rt) << sa; break; //sll - case 2: + case 2: if (_RS == 0) //srl { R(rd) = R(rt) >> sa; - break; - } + break; + } else if (_RS == 1) //rotr { R(rd) = __rotr(R(rt), sa); @@ -726,7 +727,7 @@ namespace MIPSInt if (_FD == 0) //srlv { R(rd) = R(rt) >> (R(rs)&0x1F); - break; + break; } else if (_FD == 1) // rotrv { @@ -821,14 +822,14 @@ namespace MIPSInt case 36: // mfic if (!reported) { Reporting::ReportMessage("MFIC instruction hit (%08x) at %08x", op.encoding, currentMIPS->pc); - WARN_LOG(CPU,"MFIC Disable/Enable Interrupt CPU instruction"); + WARN_LOG(Log::CPU,"MFIC Disable/Enable Interrupt CPU instruction"); reported = 1; } break; case 38: // mtic if (!reported) { Reporting::ReportMessage("MTIC instruction hit (%08x) at %08x", op.encoding, currentMIPS->pc); - WARN_LOG(CPU,"MTIC Disable/Enable Interrupt CPU instruction"); + WARN_LOG(Log::CPU,"MTIC Disable/Enable Interrupt CPU instruction"); reported = 1; } break; @@ -1021,7 +1022,7 @@ namespace MIPSInt case 0: if (!reported) { Reporting::ReportMessage("INTERRUPT instruction hit (%08x) at %08x", op.encoding, currentMIPS->pc); - WARN_LOG(CPU,"Disable/Enable Interrupt CPU instruction"); + WARN_LOG(Log::CPU,"Disable/Enable Interrupt CPU instruction"); reported = 1; } break; @@ -1052,7 +1053,7 @@ namespace MIPSInt } } else { if (!entry || !entry->replaceFunc) { - ERROR_LOG(CPU, "Bad replacement function index %i", index); + ERROR_LOG(Log::CPU, "Bad replacement function index %i", index); } // Interpret the original instruction under it. MIPSInterpret(Memory::Read_Instruction(PC, true)); diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 9edb668226..c5d712beff 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -123,7 +123,7 @@ static void ApplyPrefixST(float *r, u32 data, VectorSize size, float invalid = 0 if (!constants) { if (regnum >= n) { // We mostly handle this now, but still worth reporting. - ERROR_LOG_REPORT(CPU, "Invalid VFPU swizzle: %08x: %i / %d at PC = %08x (%s)", data, regnum, n, currentMIPS->pc, MIPSDisasmAt(currentMIPS->pc).c_str()); + ERROR_LOG_REPORT(Log::CPU, "Invalid VFPU swizzle: %08x: %i / %d at PC = %08x (%s)", data, regnum, n, currentMIPS->pc, MIPSDisasmAt(currentMIPS->pc).c_str()); } r[i] = origV[regnum]; if (abs) @@ -576,7 +576,7 @@ namespace MIPSInt void Int_Vflush(MIPSOpcode op) { - VERBOSE_LOG(CPU, "vflush"); + VERBOSE_LOG(Log::CPU, "vflush"); PC += 4; // Anything with 0xFC000000 is a nop, but only 0xFFFF0000 retains prefixes. if ((op & 0xFFFF0000) != 0xFFFF0000) @@ -621,8 +621,9 @@ namespace MIPSInt break; default: ApplySwizzleS(s, sz); + break; } - for (int i = 0; i < n; i++) { + for (int i = 0; i < (int)n; i++) { switch (optype) { case 0: d[i] = s[i]; break; //vmov case 1: d[i] = s[i]; break; //vabs (prefix) @@ -904,7 +905,7 @@ namespace MIPSInt break; default: - ERROR_LOG_REPORT(CPU, "vf2h with invalid elements"); + ERROR_LOG_REPORT(Log::CPU, "vf2h with invalid elements"); break; } ApplyPrefixD(reinterpret_cast(d), outsize); @@ -972,7 +973,7 @@ namespace MIPSInt break; default: - ERROR_LOG_REPORT(CPU, "vus2i with more than 2 elements"); + ERROR_LOG_REPORT(Log::CPU, "vus2i with more than 2 elements"); break; } break; @@ -996,7 +997,7 @@ namespace MIPSInt break; default: - ERROR_LOG_REPORT(CPU, "vs2i with more than 2 elements"); + ERROR_LOG_REPORT(Log::CPU, "vs2i with more than 2 elements"); break; } break; @@ -1255,7 +1256,7 @@ namespace MIPSInt // Other sizes don't seem completely predictable. if (sz != V_Quad) { - ERROR_LOG_REPORT_ONCE(vbfy2, CPU, "vfby2 with incorrect size"); + ERROR_LOG_REPORT_ONCE(vbfy2, Log::CPU, "vfby2 with incorrect size"); } } else { // vbfy1 @@ -1270,7 +1271,7 @@ namespace MIPSInt ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz); if (sz != V_Quad && sz != V_Pair) { - ERROR_LOG_REPORT_ONCE(vbfy2, CPU, "vfby1 with incorrect size"); + ERROR_LOG_REPORT_ONCE(vbfy2, Log::CPU, "vfby1 with incorrect size"); } } @@ -2075,7 +2076,7 @@ namespace MIPSInt d[i] = s[i]; } } else { - ERROR_LOG_REPORT(CPU, "Bad Imm3 in cmov: %d", imm3); + ERROR_LOG_REPORT(Log::CPU, "Bad Imm3 in cmov: %d", imm3); } ApplyPrefixD(d, sz); WriteVector(d, sz, vd); @@ -2127,7 +2128,7 @@ namespace MIPSInt ApplySwizzleT(&t[n - 1], V_Single, -INFINITY); } - for (int i = 0; i < n; i++) { + for (int i = 0; i < (int)n; i++) { switch (optype) { case 0: d.f[i] = s[i] + t[i]; break; //vadd case 1: d.f[i] = s[i] - t[i]; break; //vsub @@ -2247,7 +2248,7 @@ namespace MIPSInt break; default: - ERROR_LOG_REPORT(CPU, "vcrsp/vqmul with invalid elements"); + ERROR_LOG_REPORT(Log::CPU, "vcrsp/vqmul with invalid elements"); break; } diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 4b909c2d03..cb3ab2e5a2 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -188,7 +188,7 @@ static const MIPSInstruction tableSpecial[64] = // 000000 ..... ..... ..... .... INSTR("jalr", JITFUNC(Comp_JumpReg), Dis_JumpRegType, Int_JumpRegType, IS_JUMP|IN_RS|OUT_RD|DELAYSLOT), INSTR("movz", JITFUNC(Comp_RType3), Dis_RType3, Int_RType3, OUT_RD|IN_RS|IN_RT|IS_CONDMOVE|CONDTYPE_EQ), INSTR("movn", JITFUNC(Comp_RType3), Dis_RType3, Int_RType3, OUT_RD|IN_RS|IN_RT|IS_CONDMOVE|CONDTYPE_NE), - INSTR("syscall", JITFUNC(Comp_Syscall), Dis_Syscall, Int_Syscall, IN_MEM|IN_OTHER|OUT_MEM|OUT_OTHER), + INSTR("syscall", JITFUNC(Comp_Syscall), Dis_Syscall, Int_Syscall, IN_MEM|IN_OTHER|OUT_MEM|OUT_OTHER|IS_SYSCALL), INSTR("break", JITFUNC(Comp_Break), Dis_Generic, Int_Break, 0), INVALID, INSTR("sync", JITFUNC(Comp_DoNothing), Dis_Generic, Int_Sync, 0), @@ -887,7 +887,7 @@ const MIPSInstruction *MIPSGetInstruction(MIPSOpcode op) { const MIPSInstruction *instr = &tableImmediate[op.encoding >> 26]; while (instr->altEncoding != Instruc) { if (instr->altEncoding == Inval) { - //ERROR_LOG(CPU, "Invalid instruction %08x in table %i, entry %i", op, (int)encoding, subop); + //ERROR_LOG(Log::CPU, "Invalid instruction %08x in table %i, entry %i", op, (int)encoding, subop); return 0; //invalid instruction } encoding = instr->altEncoding; @@ -909,12 +909,12 @@ void MIPSCompileOp(MIPSOpcode op, MIPSComp::MIPSFrontendInterface *jit) { if (instr->compile) { (jit->*(instr->compile))(op); } else { - ERROR_LOG_REPORT(CPU,"MIPSCompileOp %08x failed",op.encoding); + ERROR_LOG_REPORT(Log::CPU,"MIPSCompileOp %08x failed",op.encoding); } if (info & OUT_EAT_PREFIX) jit->EatPrefix(); } else { - ERROR_LOG_REPORT(CPU, "MIPSCompileOp: Invalid instruction %08x", op.encoding); + ERROR_LOG_REPORT(Log::CPU, "MIPSCompileOp: Invalid instruction %08x", op.encoding); } } @@ -942,7 +942,7 @@ static inline void Interpret(const MIPSInstruction *instr, MIPSOpcode op) { if (instr && instr->interpret) { instr->interpret(op); } else { - ERROR_LOG_REPORT(CPU, "Unknown instruction %08x at %08x", op.encoding, currentMIPS->pc); + ERROR_LOG_REPORT(Log::CPU, "Unknown instruction %08x at %08x", op.encoding, currentMIPS->pc); // Try to disassemble it char disasm[256]; MIPSDisAsm(op, currentMIPS->pc, disasm, sizeof(disasm)); @@ -1054,7 +1054,7 @@ int MIPSInterpret_RunUntil(u64 globalTicks) { RunUntilFast(); if (CoreTiming::GetTicks() > globalTicks) { - // DEBUG_LOG(CPU, "Hit the max ticks, bailing 1 : %llu, %llu", globalTicks, CoreTiming::GetTicks()); + // DEBUG_LOG(Log::CPU, "Hit the max ticks, bailing 1 : %llu, %llu", globalTicks, CoreTiming::GetTicks()); return 1; } } diff --git a/Core/MIPS/MIPSTables.h b/Core/MIPS/MIPSTables.h index 9c53a07ea0..905c69d6be 100644 --- a/Core/MIPS/MIPSTables.h +++ b/Core/MIPS/MIPSTables.h @@ -92,6 +92,8 @@ #define OUT_VD 0x100000000000ULL +#define IS_SYSCALL 0x200000000000ULL + #ifndef CDECL #define CDECL #endif diff --git a/Core/MIPS/MIPSTracer.cpp b/Core/MIPS/MIPSTracer.cpp new file mode 100644 index 0000000000..20289a5d92 --- /dev/null +++ b/Core/MIPS/MIPSTracer.cpp @@ -0,0 +1,207 @@ +// Copyright (c) 2024- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Core/MIPS/MIPSTracer.h" + +#include // for std::memcpy +#include "Core/MIPS/MIPSTables.h" // for MIPSDisAsm +#include "Core/MemMap.h" // for Memory::GetPointerUnchecked +#include "Common/File/FileUtil.h" // for the File::OpenCFile + + +bool TraceBlockStorage::save_block(const u32* instructions, u32 size) { + // 'size' is measured in bytes + const auto indexes_count = size / 4; + + if (cur_index + 1 + indexes_count >= raw_instructions.size()) { + return false; + } + + // Save the size first + *cur_data_ptr = size; + ++cur_data_ptr; + + // Now save the MIPS instructions + std::memcpy(cur_data_ptr, instructions, size); + cur_data_ptr += indexes_count; + + cur_index += 1 + indexes_count; + return true; +} + +void TraceBlockStorage::initialize(u32 capacity) { + raw_instructions.resize(capacity); + cur_index = 0; + cur_data_ptr = raw_instructions.data(); + INFO_LOG(Log::JIT, "TraceBlockStorage initialized: capacity=0x%x", capacity); +} + +void TraceBlockStorage::clear() { + raw_instructions.clear(); + cur_index = 0; + cur_data_ptr = nullptr; + INFO_LOG(Log::JIT, "TraceBlockStorage cleared"); +} + +void MIPSTracer::prepare_block(const MIPSComp::IRBlock* block, MIPSComp::IRBlockCache& blocks) { + u32 virt_addr, size; + block->GetRange(&virt_addr, &size); + + u64 hash = block->GetHash(); + auto it = hash_to_storage_index.find(hash); + + u32 storage_index; + if (it != hash_to_storage_index.end()) { + // We've seen this one before => it's saved in our storage + storage_index = it->second; + } + else { + // We haven't seen a block like that before, let's save it + auto mips_instructions_ptr = (const u32*)Memory::GetPointerUnchecked(virt_addr); + + storage_index = storage.cur_index; + if (!storage.save_block(mips_instructions_ptr, size)) { + // We ran out of storage! + WARN_LOG(Log::JIT, "The MIPSTracer ran out of storage for the blocks, cannot proceed!"); + stop_tracing(); + return; + } + // Successfully inserted the block at index 'storage_index'! + + hash_to_storage_index.emplace(hash, storage_index); + } + + // NB! + // If for some reason the blocks get invalidated while tracing, PPSSPP will be forced to recompile + // the same code again => the 'trace_info' will be filled with duplicates, because we can't detect that... + // If we store the TraceBlockInfo instances in an unordered_map, we won't be able to reference the entries + // by using the 4 byte IRInst field 'constant' (the iterators won't fit there). + // And, of course, doing a linear search in the vector is not worth the conserved space. + trace_info.push_back({ virt_addr, storage_index }); + + + u32 index = trace_info.size() - 1; + auto ir_ptr = (IRInst*)blocks.GetBlockInstructionPtr(*block); + ir_ptr[1].constant = index; +} + +bool MIPSTracer::flush_to_file() { + INFO_LOG(Log::JIT, "Flushing the trace to a file..."); + output = File::OpenCFile(logging_path, "w"); + + if (!output) { + WARN_LOG(Log::JIT, "MIPSTracer failed to open the file '%s'", logging_path.c_str()); + return false; + } + auto trace = executed_blocks.get_content(); + for (auto index : trace) { + auto& block_info = trace_info[index]; + flush_block_to_file(block_info); + } + + INFO_LOG(Log::JIT, "Trace flushed, closing the file..."); + std::fclose(output); + + clear(); + return true; +} + +void MIPSTracer::flush_block_to_file(const TraceBlockInfo& block_info) { + char buffer[512]; + + // The log format is '{prefix}{disassembled line}', where 'prefix' is '0x{8 hex digits of the address}: ' + const auto prefix_size = 2 + 8 + 2; + + u32 addr = block_info.virt_address; + u32 index = block_info.storage_index; + + u32 size = storage[index]; + ++index; + + u32 end_addr = addr + size; + + + for (; addr < end_addr; addr += 4, ++index) { + snprintf(buffer, sizeof(buffer), "0x%08x: ", addr); + MIPSDisAsm(storage.read_asm(index), addr, buffer + prefix_size, sizeof(buffer) - prefix_size, true); + + std::fprintf(output, "%s\n", buffer); + } +} + +void MIPSTracer::start_tracing() { + if (!tracing_enabled) { + INFO_LOG(Log::JIT, "MIPSTracer enabled"); + tracing_enabled = true; + } +} + +void MIPSTracer::stop_tracing() { + if (tracing_enabled) { + INFO_LOG(Log::JIT, "MIPSTracer disabled"); + tracing_enabled = false; + +#ifdef _DEBUG + print_stats(); +#endif + } +} + +inline void MIPSTracer::print_stats() const { + // First, the storage + INFO_LOG(Log::JIT, "=============== MIPSTracer storage ==============="); + INFO_LOG(Log::JIT, "Current index = %d, storage size = %d", storage.cur_index, storage.raw_instructions.size()); + + // Then the cyclic buffer + if (executed_blocks.overflow) { + INFO_LOG(Log::JIT, "=============== MIPSTracer cyclic buffer (overflow) ==============="); + INFO_LOG(Log::JIT, "Trace size = %d, starts from index %d", executed_blocks.buffer.size(), executed_blocks.current_index); + } + else { + INFO_LOG(Log::JIT, "=============== MIPSTracer cyclic buffer (no overflow) ==============="); + INFO_LOG(Log::JIT, "Trace size = %d, starts from index 0", executed_blocks.current_index); + } + // Next, the hash-to-index mapping + INFO_LOG(Log::JIT, "=============== MIPSTracer hashes ==============="); + INFO_LOG(Log::JIT, "Number of unique hashes = %d", hash_to_storage_index.size()); + + // Finally, the basic block list + INFO_LOG(Log::JIT, "=============== MIPSTracer basic block list ==============="); + INFO_LOG(Log::JIT, "Number of processed basic blocks = %d", trace_info.size()); + + INFO_LOG(Log::JIT, "=============== MIPSTracer stats end ==============="); +} + +void MIPSTracer::initialize(u32 storage_capacity, u32 max_trace_size) { + executed_blocks.resize(max_trace_size); + hash_to_storage_index.reserve(max_trace_size); + storage.initialize(storage_capacity); + trace_info.reserve(max_trace_size); + INFO_LOG(Log::JIT, "MIPSTracer initialized: storage_capacity=0x%x, max_trace_size=%d", storage_capacity, max_trace_size); +} + +void MIPSTracer::clear() { + executed_blocks.clear(); + hash_to_storage_index.clear(); + storage.clear(); + trace_info.clear(); + INFO_LOG(Log::JIT, "MIPSTracer cleared"); +} + +MIPSTracer mipsTracer; + + diff --git a/Core/MIPS/MIPSTracer.h b/Core/MIPS/MIPSTracer.h new file mode 100644 index 0000000000..8ba1bef6e8 --- /dev/null +++ b/Core/MIPS/MIPSTracer.h @@ -0,0 +1,172 @@ +// Copyright (c) 2024- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "Core/Opcode.h" +#include "Core/MIPS/IR/IRJit.h" +#include "Common/Log.h" +#include "Common/File/Path.h" + + +struct TraceBlockInfo { + u32 virt_address; + u32 storage_index; +}; + +struct TraceBlockStorage { + std::vector raw_instructions; + u32 cur_index; + u32* cur_data_ptr; + + TraceBlockStorage(u32 capacity): + raw_instructions(capacity, 0), + cur_index(0), + cur_data_ptr(raw_instructions.data()) + {} + + TraceBlockStorage(): raw_instructions(), cur_index(0), cur_data_ptr(nullptr) {} + + bool save_block(const u32* instructions, u32 size); + + void initialize(u32 capacity); + void clear(); + + u32 operator[](u32 index) { + return raw_instructions[index]; + } + Memory::Opcode read_asm(u32 index) { + return Memory::Opcode(raw_instructions[index]); + } +}; + + +template +struct CyclicBuffer { + std::vector buffer; + u32 current_index; + bool overflow; + + explicit CyclicBuffer(u32 capacity) : buffer(capacity, T()), current_index(0), overflow(false) {} + + CyclicBuffer(): buffer(), current_index(0), overflow(false) {} + + void push_back(const T& value); + void push_back(T&& value); + + void clear(); + void resize(u32 new_capacity); + + std::vector get_content() const; +}; + +template +std::vector CyclicBuffer::get_content() const { + if (!overflow) { + return std::vector(buffer.begin(), buffer.begin() + current_index); + } + + std::vector ans; + ans.reserve(buffer.size()); + std::copy(buffer.begin() + current_index, buffer.end(), std::back_inserter(ans)); + std::copy(buffer.begin(), buffer.begin() + current_index, std::back_inserter(ans)); + return ans; +} + +template +void CyclicBuffer::push_back(const T& value) { + buffer[current_index] = value; + ++current_index; + if (current_index == buffer.size()) { + current_index = 0; + overflow = true; + } +} + +template +void CyclicBuffer::push_back(T&& value) { + buffer[current_index] = std::move(value); + ++current_index; + if (current_index == buffer.size()) { + current_index = 0; + overflow = true; + } +} + +template +void CyclicBuffer::clear() { + buffer.clear(); + current_index = 0; + overflow = false; +} + +template +void CyclicBuffer::resize(u32 new_capacity) { + buffer.resize(new_capacity); +} + + +// This system is meant for trace recording. +// A trace here stands for a sequence of instructions and their respective addresses in RAM. +// The register/memory changes (or thread switches) are not included! +// Note: the tracer stores the basic blocks inside, which causes the last block to be dumped as a whole, +// despite the fact that it may not have executed to its end by the time the tracer is stopped. +struct MIPSTracer { + std::vector trace_info; + + // The trace might be very big, in that case I don't mind losing the oldest entries. + CyclicBuffer executed_blocks; + + std::unordered_map hash_to_storage_index; + + TraceBlockStorage storage; + + Path logging_path; + FILE* output; + bool tracing_enabled = false; + + int in_storage_capacity = 0x10'0000; + int in_max_trace_size = 0x10'0000; + + void start_tracing(); + void stop_tracing(); + + void prepare_block(const MIPSComp::IRBlock* block, MIPSComp::IRBlockCache& blocks); + void set_logging_path(std::string path) { + logging_path = Path(path); + } + std::string get_logging_path() const { + return logging_path.ToString(); + } + + bool flush_to_file(); + void flush_block_to_file(const TraceBlockInfo& block); + + void initialize(u32 storage_capacity, u32 max_trace_size); + void clear(); + + inline void print_stats() const; + + MIPSTracer(): trace_info(), executed_blocks(), hash_to_storage_index(), storage(), logging_path() {} +}; + +extern MIPSTracer mipsTracer; diff --git a/Core/MIPS/MIPSVFPUUtils.cpp b/Core/MIPS/MIPSVFPUUtils.cpp index d8196999eb..6e65702304 100644 --- a/Core/MIPS/MIPSVFPUUtils.cpp +++ b/Core/MIPS/MIPSVFPUUtils.cpp @@ -97,26 +97,26 @@ int GetMatrixName(int matrix, MatrixSize msize, int column, int row, bool transp switch (msize) { case M_4x4: if (row || column) { - ERROR_LOG(JIT, "GetMatrixName: Invalid row %i or column %i for size %i", row, column, msize); + ERROR_LOG(Log::JIT, "GetMatrixName: Invalid row %i or column %i for size %i", row, column, msize); } break; case M_3x3: if (row & ~2) { - ERROR_LOG(JIT, "GetMatrixName: Invalid row %i for size %i", row, msize); + ERROR_LOG(Log::JIT, "GetMatrixName: Invalid row %i for size %i", row, msize); } if (column & ~2) { - ERROR_LOG(JIT, "GetMatrixName: Invalid col %i for size %i", column, msize); + ERROR_LOG(Log::JIT, "GetMatrixName: Invalid col %i for size %i", column, msize); } name |= (row << 6) | column; break; case M_2x2: if (row & ~2) { - ERROR_LOG(JIT, "GetMatrixName: Invalid row %i for size %i", row, msize); + ERROR_LOG(Log::JIT, "GetMatrixName: Invalid row %i for size %i", row, msize); } if (column & ~2) { - ERROR_LOG(JIT, "GetMatrixName: Invalid col %i for size %i", column, msize); + ERROR_LOG(Log::JIT, "GetMatrixName: Invalid col %i for size %i", column, msize); } name |= (row << 5) | column; break; @@ -301,7 +301,7 @@ void WriteMatrix(const float *rd, MatrixSize size, int reg) { } if (currentMIPS->VfpuWriteMask() != 0) { - ERROR_LOG_REPORT(CPU, "Write mask used with vfpu matrix instruction."); + ERROR_LOG_REPORT(Log::CPU, "Write mask used with vfpu matrix instruction."); } // The voffset ordering is now integrated in these formulas, @@ -998,16 +998,16 @@ static inline bool load_vfpu_table(T *&ptr, const char *filename, size_t expecte #endif if (ptr) return true; // Already loaded. size_t size = 0u; - INFO_LOG(CPU, "Loading '%s'...", filename); + INFO_LOG(Log::CPU, "Loading '%s'...", filename); ptr = reinterpret_cast(g_VFS.ReadFile(filename, &size)); if(!ptr || size != expected_size) { - ERROR_LOG(CPU, "Error loading '%s' (size=%u, expected: %u)", filename, (unsigned)size, (unsigned)expected_size); + ERROR_LOG(Log::CPU, "Error loading '%s' (size=%u, expected: %u)", filename, (unsigned)size, (unsigned)expected_size); if(ptr) delete[] ptr; ptr = nullptr; return false; } - INFO_LOG(CPU, "Successfully loaded '%s'", filename); + INFO_LOG(Log::CPU, "Successfully loaded '%s'", filename); return true; } diff --git a/Core/MIPS/RiscV/RiscVAsm.cpp b/Core/MIPS/RiscV/RiscVAsm.cpp index 730a6d9dcc..63e68a345b 100644 --- a/Core/MIPS/RiscV/RiscVAsm.cpp +++ b/Core/MIPS/RiscV/RiscVAsm.cpp @@ -35,9 +35,9 @@ static const bool enableDisasm = false; static void ShowPC(u32 downcount, void *membase, void *jitbase) { static int count = 0; if (currentMIPS) { - ERROR_LOG(JIT, "[%08x] ShowPC Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); + ERROR_LOG(Log::JIT, "[%08x] ShowPC Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); } else { - ERROR_LOG(JIT, "Universe corrupt?"); + ERROR_LOG(Log::JIT, "Universe corrupt?"); } //if (count > 2000) // exit(0); @@ -240,7 +240,7 @@ void RiscVJitBackend::GenerateFixedCode(MIPSState *mipsState) { #if PPSSPP_ARCH(RISCV64) std::vector lines = DisassembleRV64(start, GetCodePtr() - start); for (auto s : lines) { - INFO_LOG(JIT, "%s", s.c_str()); + INFO_LOG(Log::JIT, "%s", s.c_str()); } #endif } diff --git a/Core/MIPS/RiscV/RiscVJit.cpp b/Core/MIPS/RiscV/RiscVJit.cpp index 60d5c5f929..87b1a14dcc 100644 --- a/Core/MIPS/RiscV/RiscVJit.cpp +++ b/Core/MIPS/RiscV/RiscVJit.cpp @@ -39,6 +39,7 @@ RiscVJitBackend::RiscVJitBackend(JitOptions &jitopt, IRBlockCache &blocks) if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) { jo.enablePointerify = false; } + jo.optimizeForInterpreter = false; // Since we store the offset, this is as big as it can be. // We could shift off one bit to double it, would need to change RiscVAsm. @@ -55,11 +56,12 @@ static void NoBlockExits() { _assert_msg_(false, "Never exited block, invalid IR?"); } -bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { +bool RiscVJitBackend::CompileBlock(IRBlockCache *irBlockCache, int block_num, bool preload) { if (GetSpaceLeft() < 0x800) return false; - BeginWrite(std::min(GetSpaceLeft(), (size_t)block->GetNumInstructions() * 32)); + IRBlock *block = irBlockCache->GetBlock(block_num); + BeginWrite(std::min(GetSpaceLeft(), (size_t)block->GetNumIRInstructions() * 32)); u32 startPC = block->GetOriginalStart(); bool wroteCheckedOffset = false; @@ -77,14 +79,15 @@ bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) // Don't worry, the codespace isn't large enough to overflow offsets. const u8 *blockStart = GetCodePointer(); - block->SetTargetOffset((int)GetOffset(blockStart)); + block->SetNativeOffset((int)GetOffset(blockStart)); compilingBlockNum_ = block_num; - regs_.Start(block); + regs_.Start(irBlockCache, block_num); std::vector addresses; - for (int i = 0; i < block->GetNumInstructions(); ++i) { - const IRInst &inst = block->GetInstructions()[i]; + const IRInst *instructions = irBlockCache->GetBlockInstructionPtr(*block); + for (int i = 0; i < block->GetNumIRInstructions(); ++i) { + const IRInst &inst = instructions[i]; regs_.SetIRIndex(i); addresses.push_back(GetCodePtr()); @@ -107,7 +110,7 @@ bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) QuickJ(R_RA, hooks_.crashHandler); } - int len = (int)GetOffset(GetCodePointer()) - block->GetTargetOffset(); + int len = (int)GetOffset(GetCodePointer()) - block->GetNativeOffset(); if (len < MIN_BLOCK_NORMAL_LEN) { // We need at least 16 bytes to invalidate blocks with, but larger doesn't need to align. ReserveCodeSpace(MIN_BLOCK_NORMAL_LEN - len); @@ -140,15 +143,16 @@ bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) for (int i = 0; i < (int)addresses.size(); ++i) addressesLookup[addresses[i]] = i; - INFO_LOG(JIT, "=============== RISCV (%08x, %d bytes) ===============", startPC, len); + INFO_LOG(Log::JIT, "=============== RISCV (%08x, %d bytes) ===============", startPC, len); + const IRInst *instructions = irBlockCache->GetBlockInstructionPtr(*block); for (const u8 *p = blockStart; p < GetCodePointer(); ) { auto it = addressesLookup.find(p); if (it != addressesLookup.end()) { - const IRInst &inst = block->GetInstructions()[it->second]; + const IRInst &inst = instructions[it->second]; char temp[512]; DisassembleIR(temp, sizeof(temp), inst); - INFO_LOG(JIT, "IR: #%d %s", it->second, temp); + INFO_LOG(Log::JIT, "IR: #%d %s", it->second, temp); } auto next = std::next(it); @@ -157,7 +161,7 @@ bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) #if PPSSPP_ARCH(RISCV64) || (PPSSPP_PLATFORM(WINDOWS) && !defined(__LIBRETRO__)) auto lines = DisassembleRV64(p, (int)(nextp - p)); for (const auto &line : lines) - INFO_LOG(JIT, "RV: %s", line.c_str()); + INFO_LOG(Log::JIT, "RV: %s", line.c_str()); #endif p = nextp; } @@ -294,8 +298,9 @@ void RiscVJitBackend::ClearAllBlocks() { EraseAllLinks(-1); } -void RiscVJitBackend::InvalidateBlock(IRBlock *block, int block_num) { - int offset = block->GetTargetOffset(); +void RiscVJitBackend::InvalidateBlock(IRBlockCache *irBlockCache, int block_num) { + IRBlock *block = irBlockCache->GetBlock(block_num); + int offset = block->GetNativeOffset(); u8 *writable = GetWritablePtrFromCodePtr(GetBasePtr()) + offset; // Overwrite the block with a jump to compile it again. diff --git a/Core/MIPS/RiscV/RiscVJit.h b/Core/MIPS/RiscV/RiscVJit.h index 7ccbcce90b..2bc0b1ec51 100644 --- a/Core/MIPS/RiscV/RiscVJit.h +++ b/Core/MIPS/RiscV/RiscVJit.h @@ -36,9 +36,9 @@ public: bool DescribeCodePtr(const u8 *ptr, std::string &name) const override; void GenerateFixedCode(MIPSState *mipsState) override; - bool CompileBlock(IRBlock *block, int block_num, bool preload) override; + bool CompileBlock(IRBlockCache *irBlockCache, int block_num, bool preload) override; void ClearAllBlocks() override; - void InvalidateBlock(IRBlock *block, int block_num) override; + void InvalidateBlock(IRBlockCache *irBlockCache, int block_num) override; protected: const CodeBlockCommon &CodeBlock() const override { diff --git a/Core/MIPS/RiscV/RiscVRegCache.cpp b/Core/MIPS/RiscV/RiscVRegCache.cpp index 25528aa3aa..0e5965bf36 100644 --- a/Core/MIPS/RiscV/RiscVRegCache.cpp +++ b/Core/MIPS/RiscV/RiscVRegCache.cpp @@ -405,7 +405,7 @@ RiscVReg RiscVRegCache::R(IRReg mipsReg) { if (mr[mipsReg].loc == MIPSLoc::REG || mr[mipsReg].loc == MIPSLoc::REG_IMM) { return (RiscVReg)mr[mipsReg].nReg; } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in riscv reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in riscv reg", mipsReg); return INVALID_REG; // BAAAD } } @@ -421,11 +421,11 @@ RiscVReg RiscVRegCache::RPtr(IRReg mipsReg) { if (nr[rv].pointerified) { return (RiscVReg)mr[mipsReg].nReg; } else { - ERROR_LOG(JIT, "Tried to use a non-pointer register as a pointer"); + ERROR_LOG(Log::JIT, "Tried to use a non-pointer register as a pointer"); return INVALID_REG; } } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in riscv reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in riscv reg", mipsReg); return INVALID_REG; // BAAAD } } @@ -436,7 +436,7 @@ RiscVReg RiscVRegCache::F(IRReg mipsReg) { if (mr[mipsReg + 32].loc == MIPSLoc::FREG) { return (RiscVReg)mr[mipsReg + 32].nReg; } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in riscv reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in riscv reg", mipsReg); return INVALID_REG; // BAAAD } } diff --git a/Core/MIPS/fake/FakeJit.cpp b/Core/MIPS/fake/FakeJit.cpp index 3e696814c8..081655752b 100644 --- a/Core/MIPS/fake/FakeJit.cpp +++ b/Core/MIPS/fake/FakeJit.cpp @@ -40,7 +40,7 @@ void DisassembleFake(const u8 *data, int size) { namespace MIPSComp { -FakeJit::FakeJit(MIPSState *mipsState) : blocks(mipsState, this), mips_(mipsState) +FakeJit::FakeJit(MIPSState *mipsState) : blocks(mipsState, this), mips_(mipsState), js() { logBlocks = 0; dontLogBlocks = 0; @@ -109,10 +109,10 @@ void FakeJit::InvalidateCacheAt(u32 em_address, int length) { void FakeJit::EatInstruction(MIPSOpcode op) { MIPSInfo info = MIPSGetInfo(op); if (info & DELAYSLOT) { - ERROR_LOG_REPORT_ONCE(ateDelaySlot, JIT, "Ate a branch op."); + ERROR_LOG_REPORT_ONCE(ateDelaySlot, Log::JIT, "Ate a branch op."); } if (js.inDelaySlot) { - ERROR_LOG_REPORT_ONCE(ateInDelaySlot, JIT, "Ate an instruction inside a delay slot."); + ERROR_LOG_REPORT_ONCE(ateInDelaySlot, Log::JIT, "Ate an instruction inside a delay slot."); } js.numInstructions++; @@ -150,7 +150,7 @@ bool FakeJit::DescribeCodePtr(const u8 *ptr, std::string &name) void FakeJit::Comp_RunBlock(MIPSOpcode op) { // This shouldn't be necessary, the dispatcher should catch us before we get here. - ERROR_LOG(JIT, "Comp_RunBlock should never be reached!"); + ERROR_LOG(Log::JIT, "Comp_RunBlock should never be reached!"); } void FakeJit::Comp_ReplacementFunc(MIPSOpcode op) diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index 471414e453..0c5d5924f0 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -62,7 +62,7 @@ static bool enableDebug = false; //R15 - Pointer to array of block pointers void ImHere() { - DEBUG_LOG(CPU, "JIT Here: %08x", currentMIPS->pc); + DEBUG_LOG(Log::CPU, "JIT Here: %08x", currentMIPS->pc); } void Jit::GenerateFixedCode(JitOptions &jo) { diff --git a/Core/MIPS/x86/CompBranch.cpp b/Core/MIPS/x86/CompBranch.cpp index 52655319c1..0e58a14ce9 100644 --- a/Core/MIPS/x86/CompBranch.cpp +++ b/Core/MIPS/x86/CompBranch.cpp @@ -108,7 +108,7 @@ static void JitBranchLogMismatch(MIPSOpcode op, u32 pc) { char temp[256]; MIPSDisAsm(op, pc, temp, sizeof(temp), true); - ERROR_LOG(JIT, "Bad jump: %s - int:%08x jit:%08x", temp, currentMIPS->intBranchExit, currentMIPS->jitBranchExit); + ERROR_LOG(Log::JIT, "Bad jump: %s - int:%08x jit:%08x", temp, currentMIPS->intBranchExit, currentMIPS->jitBranchExit); Core_EnableStepping(true, "jit.branchdebug", pc); } @@ -155,7 +155,7 @@ CCFlags Jit::FlipCCFlag(CCFlags flag) case CC_LE: return CC_NLE; case CC_NLE: return CC_LE; } - ERROR_LOG_REPORT(JIT, "FlipCCFlag: Unexpected CC flag: %d", flag); + ERROR_LOG_REPORT(Log::JIT, "FlipCCFlag: Unexpected CC flag: %d", flag); return CC_O; } @@ -181,7 +181,7 @@ CCFlags Jit::SwapCCFlag(CCFlags flag) case CC_LE: return CC_GE; case CC_NLE: return CC_NGE; } - ERROR_LOG_REPORT(JIT, "SwapCCFlag: Unexpected CC flag: %d", flag); + ERROR_LOG_REPORT(Log::JIT, "SwapCCFlag: Unexpected CC flag: %d", flag); return CC_O; } @@ -340,7 +340,7 @@ void Jit::BranchRSRTComp(MIPSOpcode op, Gen::CCFlags cc, bool likely) { CONDITIONAL_LOG; if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -419,7 +419,7 @@ void Jit::BranchRSZeroComp(MIPSOpcode op, Gen::CCFlags cc, bool andLink, bool li { CONDITIONAL_LOG; if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -539,7 +539,7 @@ void Jit::BranchFPFlag(MIPSOpcode op, Gen::CCFlags cc, bool likely) { CONDITIONAL_LOG; if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -582,7 +582,7 @@ void Jit::BranchVFPUFlag(MIPSOpcode op, Gen::CCFlags cc, bool likely) if (js.inDelaySlot) { // I think we can safely just warn-log this without reporting, it's pretty clear that this type // of branch is ignored. - WARN_LOG(JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + WARN_LOG(Log::JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } int offset = TARGET16; @@ -631,7 +631,7 @@ static void HitInvalidJump(uint32_t dest) { void Jit::Comp_Jump(MIPSOpcode op) { CONDITIONAL_LOG; if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in Jump delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } u32 off = TARGET26; @@ -640,7 +640,7 @@ void Jit::Comp_Jump(MIPSOpcode op) { // Might be a stubbed address or something? if (!Memory::IsValidAddress(targetAddr) || (targetAddr & 3) != 0) { if (js.nextExit == 0) { - ERROR_LOG_REPORT(JIT, "Jump to invalid address: %08x PC %08x LR %08x", targetAddr, GetCompilerPC(), currentMIPS->r[MIPS_REG_RA]); + ERROR_LOG_REPORT(Log::JIT, "Jump to invalid address: %08x PC %08x LR %08x", targetAddr, GetCompilerPC(), currentMIPS->r[MIPS_REG_RA]); } else { js.compiling = false; } @@ -707,7 +707,7 @@ void Jit::Comp_JumpReg(MIPSOpcode op) { CONDITIONAL_LOG; if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); + ERROR_LOG_REPORT(Log::JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", GetCompilerPC(), js.blockStart); return; } MIPSGPReg rs = _RS; @@ -798,7 +798,7 @@ void Jit::Comp_JumpReg(MIPSOpcode op) void Jit::Comp_Syscall(MIPSOpcode op) { if (op.encoding == 0x03FFFFcc) { - WARN_LOG(JIT, "Encountered bad syscall instruction at %08x (%08x)", js.compilerPC, op.encoding); + WARN_LOG(Log::JIT, "Encountered bad syscall instruction at %08x (%08x)", js.compilerPC, op.encoding); } if (!g_Config.bSkipDeadbeefFilling) diff --git a/Core/MIPS/x86/CompLoadStore.cpp b/Core/MIPS/x86/CompLoadStore.cpp index 9509f63d68..69c8b29963 100644 --- a/Core/MIPS/x86/CompLoadStore.cpp +++ b/Core/MIPS/x86/CompLoadStore.cpp @@ -93,7 +93,7 @@ namespace MIPSComp { if (makeRTWritable) { gpr.MapReg(rt, true, true); } - // NOTICE_LOG(JIT, "%d-bit Imm at %08x : %08x", bits, js.blockStart, (u32)gpr.R(rt).GetImmValue()); + // NOTICE_LOG(Log::JIT, "%d-bit Imm at %08x : %08x", bits, js.blockStart, (u32)gpr.R(rt).GetImmValue()); } else { gpr.MapReg(rt, true, false); } diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 99f6640c94..610772e97b 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -123,7 +123,7 @@ void Jit::ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz) { // Prefix may say "z, z, z, z" but if this is a pair, we force to x. // TODO: But some ops seem to use const 0 instead? if (regnum >= n) { - ERROR_LOG_REPORT(CPU, "Invalid VFPU swizzle: %08x / %d", prefix, sz); + ERROR_LOG_REPORT(Log::CPU, "Invalid VFPU swizzle: %08x / %d", prefix, sz); regnum = 0; } fpr.SimpleRegV(origV[regnum], 0); @@ -3556,7 +3556,7 @@ void Jit::CompVrotShuffle(u8 *dregs, int imm, int n, bool negSin) { break; } default: - ERROR_LOG(JIT, "Bad what in vrot"); + ERROR_LOG(Log::JIT, "Bad what in vrot"); break; } } @@ -3570,7 +3570,7 @@ void Jit::Comp_VRot(MIPSOpcode op) { } if (!js.HasNoPrefix()) { // Prefixes work strangely for this, see IRCompVFPU. - WARN_LOG_REPORT(JIT, "vrot instruction using prefixes at %08x", GetCompilerPC()); + WARN_LOG_REPORT(Log::JIT, "vrot instruction using prefixes at %08x", GetCompilerPC()); DISABLE; } @@ -3590,7 +3590,7 @@ void Jit::Comp_VRot(MIPSOpcode op) { // Pair of vrot with the same angle argument. Let's join them (can share sin/cos results). vd2 = MIPS_GET_VD(nextOp); imm2 = (nextOp >> 16) & 0x1f; - // NOTICE_LOG(JIT, "Joint VFPU at %08x", js.blockStart); + // NOTICE_LOG(Log::JIT, "Joint VFPU at %08x", js.blockStart); } u8 sreg; diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 249d12a143..4077ba815e 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -85,7 +85,7 @@ u32 JitBreakpoint(uint32_t addr) if (message.size() > 2) message.resize(message.size() - 2); - NOTICE_LOG(JIT, "Top ops compiled to interpreter: %s", message.c_str()); + NOTICE_LOG(Log::JIT, "Top ops compiled to interpreter: %s", message.c_str()); } return 1; @@ -145,7 +145,7 @@ void Jit::DoState(PointerWrap &p) { Do(p, js.startDefaultPrefix); if (p.mode == PointerWrap::MODE_READ && !js.startDefaultPrefix) { - WARN_LOG(CPU, "Jit: An uneaten prefix was previously detected. Jitting in unknown-prefix mode."); + WARN_LOG(Log::CPU, "Jit: An uneaten prefix was previously detected. Jitting in unknown-prefix mode."); } if (s >= 2) { Do(p, js.hasSetRounding); @@ -286,10 +286,10 @@ void Jit::CompileDelaySlot(int flags, RegCacheState *state) { void Jit::EatInstruction(MIPSOpcode op) { MIPSInfo info = MIPSGetInfo(op); if (info & DELAYSLOT) { - ERROR_LOG_REPORT_ONCE(ateDelaySlot, JIT, "Ate a branch op."); + ERROR_LOG_REPORT_ONCE(ateDelaySlot, Log::JIT, "Ate a branch op."); } if (js.inDelaySlot) { - ERROR_LOG_REPORT_ONCE(ateInDelaySlot, JIT, "Ate an instruction inside a delay slot."); + ERROR_LOG_REPORT_ONCE(ateInDelaySlot, Log::JIT, "Ate an instruction inside a delay slot."); } CheckJitBreakpoint(GetCompilerPC() + 4, 0); @@ -323,7 +323,7 @@ void Jit::Compile(u32 em_address) { bool cleanSlate = false; if (js.hasSetRounding && !js.lastSetRounding) { - WARN_LOG(JIT, "Detected rounding mode usage, rebuilding jit with checks"); + WARN_LOG(Log::JIT, "Detected rounding mode usage, rebuilding jit with checks"); // Won't loop, since hasSetRounding is only ever set to 1. js.lastSetRounding = js.hasSetRounding; cleanSlate = true; @@ -331,7 +331,7 @@ void Jit::Compile(u32 em_address) { // Drat. The VFPU hit an uneaten prefix at the end of a block. if (js.startDefaultPrefix && js.MayHavePrefix()) { - WARN_LOG_REPORT(JIT, "An uneaten prefix at end of block: %08x", GetCompilerPC() - 4); + WARN_LOG_REPORT(Log::JIT, "An uneaten prefix at end of block: %08x", GetCompilerPC() - 4); js.LogPrefix(); // Let's try that one more time. We won't get back here because we toggled the value. @@ -513,7 +513,7 @@ bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name) { void Jit::Comp_RunBlock(MIPSOpcode op) { // This shouldn't be necessary, the dispatcher should catch us before we get here. - ERROR_LOG(JIT, "Comp_RunBlock"); + ERROR_LOG(Log::JIT, "Comp_RunBlock"); } void Jit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) { @@ -605,7 +605,7 @@ void Jit::Comp_ReplacementFunc(MIPSOpcode op) { const ReplacementTableEntry *entry = GetReplacementFunc(index); if (!entry) { - ERROR_LOG_REPORT_ONCE(replFunc, HLE, "Invalid replacement op %08x at %08x", op.encoding, js.compilerPC); + ERROR_LOG_REPORT_ONCE(replFunc, Log::HLE, "Invalid replacement op %08x at %08x", op.encoding, js.compilerPC); return; } @@ -624,7 +624,7 @@ void Jit::Comp_ReplacementFunc(MIPSOpcode op) { // Not sure about the cause. Memory::Opcode origInstruction = Memory::Read_Instruction(GetCompilerPC(), true); if (origInstruction.encoding == op.encoding) { - ERROR_LOG(HLE, "Replacement broken (savestate problem?): %08x at %08x", op.encoding, GetCompilerPC()); + ERROR_LOG(Log::HLE, "Replacement broken (savestate problem?): %08x at %08x", op.encoding, GetCompilerPC()); return; } @@ -677,7 +677,7 @@ void Jit::Comp_ReplacementFunc(MIPSOpcode op) { js.compiling = false; } } else { - ERROR_LOG(HLE, "Replacement function %s has neither jit nor regular impl", entry->name); + ERROR_LOG(Log::HLE, "Replacement function %s has neither jit nor regular impl", entry->name); } } @@ -698,7 +698,7 @@ void Jit::Comp_Generic(MIPSOpcode op) { ApplyRoundingMode(); } else - ERROR_LOG_REPORT(JIT, "Trying to compile instruction %08x that can't be interpreted", op.encoding); + ERROR_LOG_REPORT(Log::JIT, "Trying to compile instruction %08x that can't be interpreted", op.encoding); const MIPSInfo info = MIPSGetInfo(op); if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0) @@ -721,7 +721,7 @@ void Jit::WriteExit(u32 destination, int exit_num) { _assert_msg_(exit_num < MAX_JIT_BLOCK_EXITS, "Expected a valid exit_num. dest=%08x", destination); if (!Memory::IsValidAddress(destination) || (destination & 3) != 0) { - ERROR_LOG_REPORT(JIT, "Trying to write block exit to illegal destination %08x: pc = %08x", destination, currentMIPS->pc); + ERROR_LOG_REPORT(Log::JIT, "Trying to write block exit to illegal destination %08x: pc = %08x", destination, currentMIPS->pc); MOV(32, MIPSSTATE_VAR(pc), Imm32(GetCompilerPC())); ABI_CallFunctionC(&HitInvalidBranch, destination); js.afterOp |= JitState::AFTER_CORE_STATE; diff --git a/Core/MIPS/x86/RegCache.cpp b/Core/MIPS/x86/RegCache.cpp index 10b2676526..e8c3ecea72 100644 --- a/Core/MIPS/x86/RegCache.cpp +++ b/Core/MIPS/x86/RegCache.cpp @@ -330,7 +330,7 @@ OpArg GPRRegCache::GetDefaultLocation(MIPSGPReg reg) const { case MIPS_REG_VFPUCC: return MIPSSTATE_VAR(vfpuCtrl[VFPU_CTRL_CC]); default: - ERROR_LOG_REPORT(JIT, "Bad mips register %d", reg); + ERROR_LOG_REPORT(Log::JIT, "Bad mips register %d", reg); return MIPSSTATE_VAR(r[0]); } } diff --git a/Core/MIPS/x86/X64IRAsm.cpp b/Core/MIPS/x86/X64IRAsm.cpp index 86cb3929cb..3745bde4f8 100644 --- a/Core/MIPS/x86/X64IRAsm.cpp +++ b/Core/MIPS/x86/X64IRAsm.cpp @@ -39,9 +39,9 @@ static void ShowPC(void *membase, void *jitbase) { static int count = 0; if (currentMIPS) { u32 downcount = currentMIPS->downcount; - ERROR_LOG(JIT, "[%08x] ShowPC Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); + ERROR_LOG(Log::JIT, "[%08x] ShowPC Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase); } else { - ERROR_LOG(JIT, "Universe corrupt?"); + ERROR_LOG(Log::JIT, "Universe corrupt?"); } //if (count > 2000) // exit(0); @@ -304,7 +304,7 @@ void X64JitBackend::GenerateFixedCode(MIPSState *mipsState) { #if PPSSPP_ARCH(AMD64) std::vector lines = DisassembleX86(disasmStart, (int)(GetCodePtr() - disasmStart)); for (auto s : lines) { - INFO_LOG(JIT, "%s", s.c_str()); + INFO_LOG(Log::JIT, "%s", s.c_str()); } #endif } diff --git a/Core/MIPS/x86/X64IRJit.cpp b/Core/MIPS/x86/X64IRJit.cpp index dbcddee3f5..5bb0e011b3 100644 --- a/Core/MIPS/x86/X64IRJit.cpp +++ b/Core/MIPS/x86/X64IRJit.cpp @@ -41,6 +41,7 @@ X64JitBackend::X64JitBackend(JitOptions &jitopt, IRBlockCache &blocks) if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) { jo.enablePointerify = false; } + jo.optimizeForInterpreter = false; // Since we store the offset, this is as big as it can be. AllocCodeSpace(1024 * 1024 * 16); @@ -54,10 +55,11 @@ static void NoBlockExits() { _assert_msg_(false, "Never exited block, invalid IR?"); } -bool X64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { +bool X64JitBackend::CompileBlock(IRBlockCache *irBlockCache, int block_num, bool preload) { if (GetSpaceLeft() < 0x800) return false; + IRBlock *block = irBlockCache->GetBlock(block_num); u32 startPC = block->GetOriginalStart(); bool wroteCheckedOffset = false; if (jo.enableBlocklink && !jo.useBackJump) { @@ -80,16 +82,17 @@ bool X64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { // Don't worry, the codespace isn't large enough to overflow offsets. const u8 *blockStart = GetCodePointer(); - block->SetTargetOffset((int)GetOffset(blockStart)); + block->SetNativeOffset((int)GetOffset(blockStart)); compilingBlockNum_ = block_num; lastConstPC_ = 0; - regs_.Start(block); + regs_.Start(irBlockCache, block_num); std::vector addresses; - addresses.reserve(block->GetNumInstructions()); - for (int i = 0; i < block->GetNumInstructions(); ++i) { - const IRInst &inst = block->GetInstructions()[i]; + addresses.reserve(block->GetNumIRInstructions()); + const IRInst *instructions = irBlockCache->GetBlockInstructionPtr(*block); + for (int i = 0; i < block->GetNumIRInstructions(); ++i) { + const IRInst &inst = instructions[i]; regs_.SetIRIndex(i); addresses.push_back(GetCodePtr()); @@ -112,7 +115,7 @@ bool X64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { JMP(hooks_.crashHandler, true); } - int len = (int)GetOffset(GetCodePointer()) - block->GetTargetOffset(); + int len = (int)GetOffset(GetCodePointer()) - block->GetNativeOffset(); if (len < MIN_BLOCK_NORMAL_LEN) { // We need at least 10 bytes to invalidate blocks with. ReserveCodeSpace(MIN_BLOCK_NORMAL_LEN - len); @@ -144,15 +147,16 @@ bool X64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { for (int i = 0; i < (int)addresses.size(); ++i) addressesLookup[addresses[i]] = i; - INFO_LOG(JIT, "=============== x86 (%08x, %d bytes) ===============", startPC, len); + INFO_LOG(Log::JIT, "=============== x86 (%08x, %d bytes) ===============", startPC, len); + const IRInst *instructions = irBlockCache->GetBlockInstructionPtr(*block); for (const u8 *p = blockStart; p < GetCodePointer(); ) { auto it = addressesLookup.find(p); if (it != addressesLookup.end()) { - const IRInst &inst = block->GetInstructions()[it->second]; + const IRInst &inst = instructions[it->second]; char temp[512]; DisassembleIR(temp, sizeof(temp), inst); - INFO_LOG(JIT, "IR: #%d %s", it->second, temp); + INFO_LOG(Log::JIT, "IR: #%d %s", it->second, temp); } auto next = std::next(it); @@ -160,7 +164,7 @@ bool X64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { auto lines = DisassembleX86(p, (int)(nextp - p)); for (const auto &line : lines) - INFO_LOG(JIT, " X: %s", line.c_str()); + INFO_LOG(Log::JIT, " X: %s", line.c_str()); p = nextp; } } @@ -315,8 +319,9 @@ void X64JitBackend::ClearAllBlocks() { EraseAllLinks(-1); } -void X64JitBackend::InvalidateBlock(IRBlock *block, int block_num) { - int offset = block->GetTargetOffset(); +void X64JitBackend::InvalidateBlock(IRBlockCache *irBlockCache, int block_num) { + IRBlock *block = irBlockCache->GetBlock(block_num); + int offset = block->GetNativeOffset(); u8 *writable = GetWritablePtrFromCodePtr(GetBasePtr()) + offset; // Overwrite the block with a jump to compile it again. diff --git a/Core/MIPS/x86/X64IRJit.h b/Core/MIPS/x86/X64IRJit.h index 15a2fb9b44..e80a8544d2 100644 --- a/Core/MIPS/x86/X64IRJit.h +++ b/Core/MIPS/x86/X64IRJit.h @@ -52,9 +52,9 @@ public: bool DescribeCodePtr(const u8 *ptr, std::string &name) const override; void GenerateFixedCode(MIPSState *mipsState) override; - bool CompileBlock(IRBlock *block, int block_num, bool preload) override; + bool CompileBlock(IRBlockCache *irBlockCache, int block_num, bool preload) override; void ClearAllBlocks() override; - void InvalidateBlock(IRBlock *block, int block_num) override; + void InvalidateBlock(IRBlockCache *irBlockCache, int block_num) override; protected: const CodeBlockCommon &CodeBlock() const override { diff --git a/Core/MIPS/x86/X64IRRegCache.cpp b/Core/MIPS/x86/X64IRRegCache.cpp index cfbb57712e..8ea13ef775 100644 --- a/Core/MIPS/x86/X64IRRegCache.cpp +++ b/Core/MIPS/x86/X64IRRegCache.cpp @@ -766,7 +766,7 @@ X64Reg X64IRRegCache::RX(IRReg mipsReg) { if (mr[mipsReg].loc == MIPSLoc::REG || mr[mipsReg].loc == MIPSLoc::REG_IMM) { return FromNativeReg(mr[mipsReg].nReg); } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in x64 reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in x64 reg", mipsReg); return INVALID_REG; // BAAAD } } @@ -782,11 +782,11 @@ X64Reg X64IRRegCache::RXPtr(IRReg mipsReg) { if (nr[r].pointerified) { return FromNativeReg(mr[mipsReg].nReg); } else { - ERROR_LOG(JIT, "Tried to use a non-pointer register as a pointer"); + ERROR_LOG(Log::JIT, "Tried to use a non-pointer register as a pointer"); return INVALID_REG; } } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in x64 reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in x64 reg", mipsReg); return INVALID_REG; // BAAAD } } @@ -797,7 +797,7 @@ X64Reg X64IRRegCache::FX(IRReg mipsReg) { if (mr[mipsReg + 32].loc == MIPSLoc::FREG) { return FromNativeReg(mr[mipsReg + 32].nReg); } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in x64 reg", mipsReg); + ERROR_LOG_REPORT(Log::JIT, "Reg %i not in x64 reg", mipsReg); return INVALID_REG; // BAAAD } } diff --git a/Core/MemFault.cpp b/Core/MemFault.cpp index ae98e199e4..e788c72420 100644 --- a/Core/MemFault.cpp +++ b/Core/MemFault.cpp @@ -250,7 +250,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { uintptr_t crashHandler = (uintptr_t)MIPSComp::jit->GetCrashHandler(); if (crashHandler != 0) { context->CTX_PC = crashHandler; - ERROR_LOG(MEMMAP, "Bad execution access detected, halting: %08x (last known pc %08x, host: %p)", targetAddr, currentMIPS->pc, (void *)hostAddress); + ERROR_LOG(Log::MemMap, "Bad execution access detected, halting: %08x (last known pc %08x, host: %p)", targetAddr, currentMIPS->pc, (void *)hostAddress); inCrashHandler = false; return true; } @@ -278,7 +278,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { context->CTX_PC += info.instructionSize; g_numReportedBadAccesses++; if (g_numReportedBadAccesses < 100) { - ERROR_LOG(MEMMAP, "Bad memory access detected and ignored: %08x (%p)", guestAddress, (void *)hostAddress); + ERROR_LOG(Log::MemMap, "Bad memory access detected and ignored: %08x (%p)", guestAddress, (void *)hostAddress); } } else { std::string infoString = ""; @@ -309,7 +309,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { context->CTX_PC = crashHandler; else handled = false; - ERROR_LOG(MEMMAP, "Bad memory access detected! %08x (%p) Stopping emulation. Info:\n%s", guestAddress, (void *)hostAddress, infoString.c_str()); + ERROR_LOG(Log::MemMap, "Bad memory access detected! %08x (%p) Stopping emulation. Info:\n%s", guestAddress, (void *)hostAddress, infoString.c_str()); } inCrashHandler = false; @@ -319,7 +319,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { #else bool HandleFault(uintptr_t hostAddress, void *ctx) { - ERROR_LOG(MEMMAP, "Exception handling not supported"); + ERROR_LOG(Log::MemMap, "Exception handling not supported"); return false; } diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index f47836dc5e..67bbe6f9f3 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -159,7 +159,7 @@ static bool Memory_TryBase(u32 flags) { position, view.size, base + view.virtual_address); if (!*view.out_ptr) { goto bail; - DEBUG_LOG(MEMMAP, "Failed at view %d", i); + DEBUG_LOG(Log::MemMap, "Failed at view %d", i); } #else if (CanIgnoreView(view)) { @@ -169,7 +169,7 @@ static bool Memory_TryBase(u32 flags) { *view.out_ptr = (u8*)g_arena.CreateView( position, view.size, base + (view.virtual_address & MEMVIEW32_MASK)); if (!*view.out_ptr) { - DEBUG_LOG(MEMMAP, "Failed at view %d", i); + DEBUG_LOG(Log::MemMap, "Failed at view %d", i); goto bail; } } @@ -235,18 +235,18 @@ bool MemoryMap_Setup(u32 flags) { uintptr_t max_base_addr = 0; uintptr_t min_base_addr = 0; uintptr_t stride = 0; - ERROR_LOG(MEMMAP, "MemoryMap_Setup: Hit a wrong path, should not be needed on this platform."); + ERROR_LOG(Log::MemMap, "MemoryMap_Setup: Hit a wrong path, should not be needed on this platform."); return false; #endif for (uintptr_t base_addr = min_base_addr; base_addr < max_base_addr; base_addr += stride) { base_attempts++; base = (u8 *)base_addr; if (Memory_TryBase(flags)) { - INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); + INFO_LOG(Log::MemMap, "Found valid memory base at %p after %i tries.", base, base_attempts); return true; } } - ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); + ERROR_LOG(Log::MemMap, "MemoryMap_Setup: Failed finding a memory base."); return false; } else @@ -309,7 +309,7 @@ bool Init() { return false; } - INFO_LOG(MEMMAP, "Memory system initialized. Base at %p (RAM at @ %p, uncached @ %p)", + INFO_LOG(Log::MemMap, "Memory system initialized. Base at %p (RAM at @ %p, uncached @ %p)", base, m_pPhysicalRAM, m_pUncachedRAM); MemFault_Init(); @@ -400,7 +400,7 @@ void Shutdown() { u32 flags = 0; MemoryMap_Shutdown(flags); base = nullptr; - DEBUG_LOG(MEMMAP, "Memory system shut down."); + DEBUG_LOG(Log::MemMap, "Memory system shut down."); } bool IsActive() { @@ -435,13 +435,13 @@ __forceinline static Opcode Read_Instruction(u32 address, bool resolveReplacemen u32 op; if (GetReplacedOpAt(address, &op)) { if (MIPS_IS_EMUHACK(op)) { - ERROR_LOG(MEMMAP, "WTF 1"); + ERROR_LOG(Log::MemMap, "WTF 1"); return Opcode(op); } else { return Opcode(op); } } else { - ERROR_LOG(MEMMAP, "Replacement, but no replacement op? %08x", inst.encoding); + ERROR_LOG(Log::MemMap, "Replacement, but no replacement op? %08x", inst.encoding); } } return inst; @@ -449,7 +449,7 @@ __forceinline static Opcode Read_Instruction(u32 address, bool resolveReplacemen u32 op; if (GetReplacedOpAt(address, &op)) { if (MIPS_IS_EMUHACK(op)) { - ERROR_LOG(MEMMAP, "WTF 2"); + ERROR_LOG(Log::MemMap, "WTF 2"); return Opcode(op); } else { return Opcode(op); diff --git a/Core/MemMap.h b/Core/MemMap.h index 67e17babcd..001e6d1feb 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -270,20 +270,6 @@ inline bool IsKernelAndNotVolatileAddress(const u32 address) { bool IsScratchpadAddress(const u32 address); -// Used for auto-converted char * parameters, which can sometimes legitimately be null - -// so we don't want to get caught in GetPointer's crash reporting. -inline const char* GetCharPointer(const u32 address) { - if (address) { - return (const char *)GetPointer(address); - } else { - return nullptr; - } -} - -inline const char *GetCharPointerUnchecked(const u32 address) { - return (const char *)GetPointerUnchecked(address); -} - inline void MemcpyUnchecked(void *to_data, const u32 from_address, const u32 len) { memcpy(to_data, GetPointerUnchecked(from_address), len); } @@ -310,30 +296,78 @@ inline bool IsValidAddress(const u32 address) { } } -inline u32 ValidSize(const u32 address, const u32 requested_size) { - u32 max_size; - if ((address & 0x3E000000) == 0x08000000) { - max_size = 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF); - } else if ((address & 0x3F800000) == 0x04000000) { - max_size = 0x04800000 - (address & 0x3FFFFFFF); - } else if ((address & 0xBFFFC000) == 0x00010000) { - max_size = 0x00014000 - (address & 0x3FFFFFFF); +inline bool IsValid4AlignedAddress(const u32 address) { + if ((address & 0x3E000003) == 0x08000000) { + return true; + } else if ((address & 0x3F800003) == 0x04000000) { + return true; + } else if ((address & 0xBFFFC003) == 0x00010000) { + return true; } else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) { - max_size = 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF); + return (address & 3) == 0; } else { - max_size = 0; + return false; + } +} + + +inline u32 MaxSizeAtAddress(const u32 address){ + if ((address & 0x3E000000) == 0x08000000) { + return 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF); + } else if ((address & 0x3F800000) == 0x04000000) { + return 0x04800000 - (address & 0x3FFFFFFF); + } else if ((address & 0xBFFFC000) == 0x00010000) { + return 0x00014000 - (address & 0x3FFFFFFF); + } else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) { + return 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF); + } else { + return 0; + } +} + +inline const char *GetCharPointerUnchecked(const u32 address) { + return (const char *)GetPointerUnchecked(address); +} + +// NOTE: Unlike the similar IsValidRange/IsValidAddress functions, this one is linear cost vs the size of the string, +// for hopefully-obvious reasons. +inline bool IsValidNullTerminatedString(const u32 address) { + u32 max_size = MaxSizeAtAddress(address); + if (max_size == 0) { + return false; } + const char *c = GetCharPointerUnchecked(address); + if (memchr(c, '\0', max_size)) { + return true; + } + return false; +} + +inline u32 ValidSize(const u32 address, const u32 requested_size) { + u32 max_size = MaxSizeAtAddress(address); if (requested_size > max_size) { return max_size; } return requested_size; } +// NOTE: If size == 0, any address will be accepted. This may not be ideal for all cases. inline bool IsValidRange(const u32 address, const u32 size) { return ValidSize(address, size) == size; } +// Used for auto-converted char * parameters, which can sometimes legitimately be null - +// so we don't want to get caught in GetPointer's crash reporting +// TODO: This should use IsValidNullTerminatedString, but may be expensive since this is used so much - needs evaluation. +inline const char *GetCharPointer(const u32 address) { + if (address && IsValidAddress(address)) { + return GetCharPointerUnchecked(address); + } else { + return nullptr; + } +} + } // namespace Memory // Avoiding a global include for NotifyMemInfo. @@ -487,7 +521,6 @@ struct PSPPointer } }; - constexpr u32 PSP_GetScratchpadMemoryBase() { return 0x00010000;} constexpr u32 PSP_GetScratchpadMemoryEnd() { return 0x00014000;} diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index e126310f2d..e115558167 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -56,7 +56,7 @@ #include "Core/HLE/sceKernelModule.h" #include "Core/HLE/sceKernelMemory.h" -static std::thread loadingThread; +static std::thread g_loadingThread; static void UseLargeMem(int memsize) { if (memsize != 1) { @@ -65,10 +65,10 @@ static void UseLargeMem(int memsize) { } if (Memory::g_PSPModel != PSP_MODEL_FAT) { - INFO_LOG(LOADER, "Game requested full PSP-2000 memory access"); + INFO_LOG(Log::Loader, "Game requested full PSP-2000 memory access"); Memory::g_MemorySize = Memory::RAM_DOUBLE_SIZE; } else { - WARN_LOG(LOADER, "Game requested full PSP-2000 memory access, ignoring in PSP-1000 mode"); + WARN_LOG(Log::Loader, "Game requested full PSP-2000 memory access, ignoring in PSP-1000 mode"); } } @@ -139,7 +139,7 @@ void InitMemoryForGameISO(FileLoader *fileLoader) { break; } if (g_RemasterMode) { - INFO_LOG(LOADER, "HDRemaster found, using increased memory"); + INFO_LOG(Log::Loader, "HDRemaster found, using increased memory"); } } @@ -247,7 +247,7 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) { pspFileSystem.ReadEntireFile(sfoPath, paramsfo); if (g_paramSFO.ReadSFO(paramsfo)) { std::string title = StringFromFormat("%s : %s", g_paramSFO.GetValueString("DISC_ID").c_str(), g_paramSFO.GetValueString("TITLE").c_str()); - INFO_LOG(LOADER, "%s", title.c_str()); + INFO_LOG(Log::Loader, "%s", title.c_str()); System_SetWindowTitle(title); } } @@ -282,7 +282,7 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) { pspFileSystem.CloseFile(fd); } if (!hasEncrypted) { - // try unencrypted BOOT.BIN + // try unencrypted Boot.BIN bootpath = "disc0:/PSP_GAME/SYSDIR/BOOT.BIN"; } @@ -307,13 +307,13 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) { //in case we didn't go through EmuScreen::boot g_Config.loadGameConfig(id, g_paramSFO.GetValueString("TITLE")); System_PostUIMessage(UIMessage::CONFIG_LOADED); - INFO_LOG(LOADER, "Loading %s...", bootpath.c_str()); + INFO_LOG(Log::Loader, "Loading %s...", bootpath.c_str()); PSPLoaders_Shutdown(); // Note: this thread reads the game binary, loads caches, and links HLE while UI spins. // To do something deterministically when the game starts, disabling this thread won't be enough. // Instead: Use Core_ListenLifecycle() or watch coreState. - loadingThread = std::thread([bootpath] { + g_loadingThread = std::thread([bootpath] { SetCurrentThreadName("ExecLoader"); PSP_LoadingLock guard; if (coreState != CORE_POWERUP) @@ -436,7 +436,7 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { std::string finalName = ms_path + file; std::string homebrewName = PSP_CoreParameter().fileToStart.ToVisualString(); - std::size_t lslash = homebrewName.find_last_of("/"); + std::size_t lslash = homebrewName.find_last_of('/'); #if PPSSPP_PLATFORM(UWP) if (lslash == homebrewName.npos) { lslash = homebrewName.find_last_of("\\"); @@ -452,7 +452,7 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { std::string madeUpID = g_paramSFO.GenerateFakeID(Path()); std::string title = StringFromFormat("%s : %s", discID.c_str(), homebrewTitle.c_str()); - INFO_LOG(LOADER, "%s", title.c_str()); + INFO_LOG(Log::Loader, "%s", title.c_str()); System_SetWindowTitle(title); // Migrate old save states from old versions of fake game IDs. @@ -474,7 +474,7 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { PSPLoaders_Shutdown(); // Note: See Load_PSP_ISO for notes about this thread. - loadingThread = std::thread([finalName] { + g_loadingThread = std::thread([finalName] { SetCurrentThreadName("ExecLoader"); PSP_LoadingLock guard; if (coreState != CORE_POWERUP) @@ -500,7 +500,7 @@ bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) { PSPLoaders_Shutdown(); // Note: See Load_PSP_ISO for notes about this thread. - loadingThread = std::thread([] { + g_loadingThread = std::thread([] { SetCurrentThreadName("ExecLoader"); PSP_LoadingLock guard; if (coreState != CORE_POWERUP) @@ -521,6 +521,6 @@ bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) { } void PSPLoaders_Shutdown() { - if (loadingThread.joinable()) - loadingThread.join(); + if (g_loadingThread.joinable()) + g_loadingThread.join(); } diff --git a/Core/Replay.cpp b/Core/Replay.cpp index 4b375c45ef..00fc62eb22 100644 --- a/Core/Replay.cpp +++ b/Core/Replay.cpp @@ -138,11 +138,11 @@ static bool diskFailed = false; bool ReplayExecuteBlob(int version, const std::vector &data) { if (version < REPLAY_VERSION_MIN || version > REPLAY_VERSION_CURRENT) { - ERROR_LOG(SYSTEM, "Bad replay data version: %d", version); + ERROR_LOG(Log::System, "Bad replay data version: %d", version); return false; } if (data.size() == 0) { - ERROR_LOG(SYSTEM, "Empty replay data"); + ERROR_LOG(Log::System, "Empty replay data"); return false; } @@ -152,7 +152,7 @@ bool ReplayExecuteBlob(int version, const std::vector &data) { replayItems.reserve(data.size() / sizeof(ReplayItemHeader)); for (size_t i = 0, sz = data.size(); i < sz; ) { if (i + sizeof(ReplayItemHeader) > sz) { - ERROR_LOG(SYSTEM, "Truncated replay data at %lld during item header", (long long)i); + ERROR_LOG(Log::System, "Truncated replay data at %lld during item header", (long long)i); break; } ReplayItemHeader *info = (ReplayItemHeader *)&data[i]; @@ -161,7 +161,7 @@ bool ReplayExecuteBlob(int version, const std::vector &data) { if ((int)item.info.action & (int)ReplayAction::MASK_SIDEDATA) { if (i + item.info.size > sz) { - ERROR_LOG(SYSTEM, "Truncated replay data at %lld during side data", (long long)i); + ERROR_LOG(Log::System, "Truncated replay data at %lld during side data", (long long)i); break; } if (item.info.size != 0) { @@ -175,7 +175,7 @@ bool ReplayExecuteBlob(int version, const std::vector &data) { } replayState = ReplayState::EXECUTE; - INFO_LOG(SYSTEM, "Executing replay with %lld items", (long long)replayItems.size()); + INFO_LOG(Log::System, "Executing replay with %lld items", (long long)replayItems.size()); return true; } @@ -184,7 +184,7 @@ bool ReplayExecuteFile(const Path &filename) { FILE *fp = File::OpenCFile(filename, "rb"); if (!fp) { - DEBUG_LOG(SYSTEM, "Failed to open replay file: %s", filename.c_str()); + DEBUG_LOG(Log::System, "Failed to open replay file: %s", filename.c_str()); return false; } @@ -194,27 +194,27 @@ bool ReplayExecuteFile(const Path &filename) { // TODO: Maybe stream instead. size_t sz = File::GetFileSize(fp); if (sz <= sizeof(ReplayFileHeader)) { - ERROR_LOG(SYSTEM, "Empty replay data"); + ERROR_LOG(Log::System, "Empty replay data"); return false; } ReplayFileHeader fh; if (fread(&fh, sizeof(fh), 1, fp) != 1) { - ERROR_LOG(SYSTEM, "Could not read replay file header"); + ERROR_LOG(Log::System, "Could not read replay file header"); return false; } sz -= sizeof(fh); if (memcmp(fh.magic, REPLAY_MAGIC, sizeof(fh.magic)) != 0) { - ERROR_LOG(SYSTEM, "Replay header corrupt"); + ERROR_LOG(Log::System, "Replay header corrupt"); return false; } if (fh.version < REPLAY_VERSION_MIN) { - ERROR_LOG(SYSTEM, "Replay version %d unsupported", fh.version); + ERROR_LOG(Log::System, "Replay version %d unsupported", fh.version); return false; } else if (fh.version > REPLAY_VERSION_CURRENT) { - WARN_LOG(SYSTEM, "Replay version %d scary and futuristic, trying anyway", fh.version); + WARN_LOG(Log::System, "Replay version %d scary and futuristic, trying anyway", fh.version); } RtcSetBaseTime((int32_t)fh.rtcBaseSeconds, 0); @@ -223,7 +223,7 @@ bool ReplayExecuteFile(const Path &filename) { data.resize(sz); if (fread(&data[0], sz, 1, fp) != 1) { - ERROR_LOG(SYSTEM, "Could not read replay data"); + ERROR_LOG(Log::System, "Could not read replay data"); return false; } @@ -286,7 +286,7 @@ void ReplayFlushBlob(std::vector *data) { bool ReplayFlushFile(const Path &filename) { FILE *fp = File::OpenCFile(filename, replaySaveWroteHeader ? "ab" : "wb"); if (!fp) { - ERROR_LOG(SYSTEM, "Failed to open replay file: %s", filename.c_str()); + ERROR_LOG(Log::System, "Failed to open replay file: %s", filename.c_str()); return false; } @@ -311,9 +311,9 @@ bool ReplayFlushFile(const Path &filename) { fclose(fp); if (success) { - DEBUG_LOG(SYSTEM, "Flushed %lld replay items", (long long)c); + DEBUG_LOG(Log::System, "Flushed %lld replay items", (long long)c); } else { - ERROR_LOG(SYSTEM, "Could not write %lld replay items (disk full?)", (long long)c); + ERROR_LOG(Log::System, "Could not write %lld replay items (disk full?)", (long long)c); } return success; } diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 1a04c9a903..5e01300afa 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -131,7 +131,7 @@ namespace Reporting return 0; } if (!blockDevice->ReadBlock(i, block, true)) { - ERROR_LOG(FILESYS, "Failed to read block for CRC"); + ERROR_LOG(Log::FileSystem, "Failed to read block for CRC"); g_OSD.RemoveProgressBar("crc", false, 0.0f); return 0; } @@ -181,7 +181,7 @@ namespace Reporting return; } - INFO_LOG(SYSTEM, "Starting CRC calculation"); + INFO_LOG(Log::System, "Starting CRC calculation"); crcFilename = gamePath; crcPending = true; crcCancel = false; @@ -204,7 +204,7 @@ namespace Reporting } if (crcThread.joinable()) { - INFO_LOG(SYSTEM, "Finished CRC calculation"); + INFO_LOG(Log::System, "Finished CRC calculation"); crcThread.join(); } return it->second; @@ -222,13 +222,13 @@ namespace Reporting static void PurgeCRC() { std::unique_lock guard(crcLock); if (crcPending) { - INFO_LOG(SYSTEM, "Cancelling CRC calculation"); + INFO_LOG(Log::System, "Cancelling CRC calculation"); crcCancel = true; while (crcPending) { crcCond.wait(guard); } } else { - DEBUG_LOG(SYSTEM, "No CRC pending"); + DEBUG_LOG(Log::System, "No CRC pending"); } if (crcThread.joinable()) diff --git a/Core/RetroAchievements.cpp b/Core/RetroAchievements.cpp index 8ef5be7b89..7ca969c7fc 100644 --- a/Core/RetroAchievements.cpp +++ b/Core/RetroAchievements.cpp @@ -25,6 +25,7 @@ #include "ext/rcheevos/include/rcheevos.h" #include "ext/rcheevos/include/rc_client.h" +#include "ext/rcheevos/include/rc_client_raintegration.h" #include "ext/rcheevos/include/rc_api_user.h" #include "ext/rcheevos/include/rc_api_info.h" #include "ext/rcheevos/include/rc_api_request.h" @@ -38,8 +39,6 @@ #include "Common/Log.h" #include "Common/File/Path.h" #include "Common/File/FileUtil.h" -#include "Core/FileLoaders/LocalFileLoader.h" -#include "Core/FileSystems/BlockDevices.h" #include "Common/Net/HTTPClient.h" #include "Common/System/OSD.h" #include "Common/System/System.h" @@ -55,19 +54,28 @@ #include "Core/MemMap.h" #include "Core/Config.h" #include "Core/CoreParameter.h" -#include "Core/ELF/ParamSFO.h" +#include "Core/Core.h" #include "Core/System.h" +#include "Core/FileLoaders/LocalFileLoader.h" +#include "Core/FileSystems/BlockDevices.h" +#include "Core/ELF/ParamSFO.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/RetroAchievements.h" +#if RC_CLIENT_SUPPORTS_RAINTEGRATION + +#include "Windows/MainWindow.h" + +#endif + static bool HashISOFile(ISOFileSystem *fs, const std::string filename, md5_context *md5) { int handle = fs->OpenFile(filename, FILEACCESS_READ); if (handle < 0) { return false; } - uint32_t sz = fs->SeekFile(handle, 0, FILEMOVE_END); + uint32_t sz = (uint32_t)fs->SeekFile(handle, 0, FILEMOVE_END); fs->SeekFile(handle, 0, FILEMOVE_BEGIN); if (!sz) { return false; @@ -83,9 +91,19 @@ static bool HashISOFile(ISOFileSystem *fs, const std::string filename, md5_conte return true; } +static std::string FormatRCheevosMD5(uint8_t digest[16]) { + char hashStr[33]; + /* NOTE: sizeof(hash) is 4 because it's still treated like a pointer, despite specifying a size */ + snprintf(hashStr, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], + digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15] + ); + return std::string(hashStr); +} + // Consumes the blockDevice. // If failed, returns an empty string, otherwise a 32-character string with the hash in hex format. -static std::string ComputePSPHash(BlockDevice *blockDevice) { +static std::string ComputePSPISOHash(BlockDevice *blockDevice) { md5_context md5; ppsspp_md5_starts(&md5); @@ -103,14 +121,23 @@ static std::string ComputePSPHash(BlockDevice *blockDevice) { uint8_t digest[16]; ppsspp_md5_finish(&md5, digest); + return FormatRCheevosMD5(digest); +} - char hashStr[33]; - /* NOTE: sizeof(hash) is 4 because it's still treated like a pointer, despite specifying a size */ - snprintf(hashStr, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], - digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15] - ); - return std::string(hashStr); +static std::string ComputePSPHomebrewHash(FileLoader *fileLoader) { + md5_context md5; + ppsspp_md5_starts(&md5); + + // Cap the data we read to 64MB (MAX_BUFFER_SIZE in rcheevos' hash.c), and hash that. + std::vector buffer; + size_t fileSize = std::min((s64)(1024 * 1024 * 64), fileLoader->FileSize()); + buffer.resize(fileSize); + fileLoader->ReadAt(0, fileSize, buffer.data(), FileLoader::Flags::NONE); + ppsspp_md5_update(&md5, buffer.data(), (int)buffer.size()); + + uint8_t digest[16]; + ppsspp_md5_finish(&md5, digest); + return FormatRCheevosMD5(digest); } static inline const char *DeNull(const char *ptr) { @@ -131,7 +158,7 @@ static Achievements::Statistics g_stats; const std::string g_gameIconCachePrefix = "game:"; const std::string g_iconCachePrefix = "badge:"; -Path s_game_path; +Path g_gamePath; std::string s_game_hash; std::set g_activeChallenges; @@ -219,7 +246,7 @@ bool WarnUserIfHardcoreModeActive(bool isSaveStateAction, std::string_view messa bool IsBlockingExecution() { if (g_isLoggingIn || g_isIdentifying) { // Useful for debugging race conditions. - // INFO_LOG(ACHIEVEMENTS, "isLoggingIn: %d isIdentifying: %d", (int)g_isLoggingIn, (int)g_isIdentifying); + // INFO_LOG(Log::Achievements, "isLoggingIn: %d isIdentifying: %d", (int)g_isLoggingIn, (int)g_isIdentifying); } return g_isLoggingIn || g_isIdentifying; } @@ -228,6 +255,15 @@ bool IsActive() { return GetGameID() != 0; } +static void raintegration_write_memory_handler(uint32_t address, uint8_t *buffer, uint32_t num_bytes, rc_client_t *client) { + // convert_retroachievements_address_to_real_address + uint32_t realAddress = address + PSP_MEMORY_OFFSET; + uint8_t *writePtr = Memory::GetPointerWriteRange(realAddress, num_bytes); + if (writePtr) { + memcpy(writePtr, buffer, num_bytes); + } +} + static uint32_t read_memory_callback(uint32_t address, uint8_t *buffer, uint32_t num_bytes, rc_client_t *client) { // Achievements are traditionally defined relative to the base of main memory of the emulated console. // This is some kind of RetroArch-related legacy. In the PSP's case, this is simply a straight offset of 0x08000000. @@ -239,7 +275,7 @@ static uint32_t read_memory_callback(uint32_t address, uint8_t *buffer, uint32_t // So we'll just count the bad accesses. Achievements::g_stats.badMemoryAccessCount++; if (g_Config.bAchievementsLogBadMemReads) { - WARN_LOG(G3D, "RetroAchievements PeekMemory: Bad address %08x (%d bytes) (%08x was passed in)", address, num_bytes, orig_address); + WARN_LOG(Log::G3D, "RetroAchievements PeekMemory: Bad address %08x (%d bytes) (%08x was passed in)", address, num_bytes, orig_address); } // This tells rcheevos that the access was bad, which should now be handled properly. @@ -281,7 +317,7 @@ static void server_call_callback(const rc_api_request_t *request, } static void log_message_callback(const char *message, const rc_client_t *client) { - INFO_LOG(ACHIEVEMENTS, "RetroAchievements: %s", message); + INFO_LOG(Log::Achievements, "RetroAchievements: %s", message); } // For detailed documentation, see https://github.com/RetroAchievements/rcheevos/wiki/rc_client_set_event_handler. @@ -293,7 +329,7 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * // An achievement was earned by the player. The handler should notify the player that the achievement was earned. g_OSD.ShowAchievementUnlocked(event->achievement->id); System_PostUIMessage(UIMessage::REQUEST_PLAY_SOUND, "achievement_unlocked"); - INFO_LOG(ACHIEVEMENTS, "Achievement unlocked: '%s' (%d)", event->achievement->title, event->achievement->id); + INFO_LOG(Log::Achievements, "Achievement unlocked: '%s' (%d)", event->achievement->title, event->achievement->id); break; case RC_CLIENT_EVENT_GAME_COMPLETED: @@ -317,7 +353,7 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * System_PostUIMessage(UIMessage::REQUEST_PLAY_SOUND, "achievement_unlocked"); - INFO_LOG(ACHIEVEMENTS, "%s", message.c_str()); + INFO_LOG(Log::Achievements, "%s", message.c_str()); break; } case RC_CLIENT_EVENT_LEADERBOARD_STARTED: @@ -334,39 +370,53 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * } else { title = event->leaderboard->description; } - INFO_LOG(ACHIEVEMENTS, "Attempt %s: %s", started ? "started" : "failed", title); + INFO_LOG(Log::Achievements, "Attempt %s: %s", started ? "started" : "failed", title); g_OSD.ShowLeaderboardStartEnd(ApplySafeSubstitutions(ac->T(started ? "%1: Attempt started" : "%1: Attempt failed"), title), description, started); break; } case RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED: { - INFO_LOG(ACHIEVEMENTS, "Leaderboard result submitted: %s", event->leaderboard->title); - const char *title = ""; + INFO_LOG(Log::Achievements, "Leaderboard result submitted: %s", event->leaderboard->title); + // Actually showing the result when we get the scoreboard message and have the new rank. + break; + } + case RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD: + { + const char *title = event->leaderboard->title; // Hack around some problematic events in Burnout Legends. Hopefully this can be fixed in the backend. - if (strlen(event->leaderboard->title) > 0) { - title = event->leaderboard->title; + std::string msg; + const rc_client_leaderboard_scoreboard_t *scoreboard = event->leaderboard_scoreboard; + if (event->leaderboard_scoreboard) { + msg = ApplySafeSubstitutions(ac->T("Submitted %1 for %2"), DeNull(scoreboard->submitted_score), title); + if (!strcmp(scoreboard->best_score, scoreboard->submitted_score)) { + msg += ": "; + msg += ApplySafeSubstitutions(ac->T("Rank: %1"), scoreboard->new_rank); + } else { + msg += ": "; + msg += ApplySafeSubstitutions(ac->T("Best: %1"), scoreboard->best_score); + } } else { - title = event->leaderboard->description; + msg = ApplySafeSubstitutions(ac->T("Submitted %1 for %2"), DeNull(event->leaderboard->tracker_value), title); } - g_OSD.ShowLeaderboardSubmitted(ApplySafeSubstitutions(ac->T("Submitted %1 for %2"), DeNull(event->leaderboard->tracker_value), title), ""); + g_OSD.ShowLeaderboardSubmitted(msg, ""); System_PostUIMessage(UIMessage::REQUEST_PLAY_SOUND, "leaderboard_submitted"); break; } case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW: - INFO_LOG(ACHIEVEMENTS, "Challenge indicator show: %s", event->achievement->title); + INFO_LOG(Log::Achievements, "Challenge indicator show: %s", event->achievement->title); g_OSD.ShowChallengeIndicator(event->achievement->id, true); g_activeChallenges.insert(event->achievement->id); // A challenge achievement has become active. The handler should show a small version of the achievement icon // to indicate the challenge is active. break; case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE: - INFO_LOG(ACHIEVEMENTS, "Challenge indicator hide: %s", event->achievement->title); + INFO_LOG(Log::Achievements, "Challenge indicator hide: %s", event->achievement->title); g_OSD.ShowChallengeIndicator(event->achievement->id, false); g_activeChallenges.erase(event->achievement->id); // The handler should hide the small version of the achievement icon that was shown by the corresponding RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW event. break; case RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW: - INFO_LOG(ACHIEVEMENTS, "Progress indicator show: %s, progress: '%s' (%f)", event->achievement->title, event->achievement->measured_progress, event->achievement->measured_percent); + INFO_LOG(Log::Achievements, "Progress indicator show: %s, progress: '%s' (%f)", event->achievement->title, event->achievement->measured_progress, event->achievement->measured_percent); // An achievement that tracks progress has changed the amount of progress that has been made. // The handler should show a small version of the achievement icon along with the achievement->measured_progress text (for two seconds). // Only one progress indicator should be shown at a time. @@ -374,11 +424,11 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * g_OSD.ShowAchievementProgress(event->achievement->id, true); break; case RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_UPDATE: - INFO_LOG(ACHIEVEMENTS, "Progress indicator update: %s, progress: '%s' (%f)", event->achievement->title, event->achievement->measured_progress, event->achievement->measured_percent); + INFO_LOG(Log::Achievements, "Progress indicator update: %s, progress: '%s' (%f)", event->achievement->title, event->achievement->measured_progress, event->achievement->measured_percent); g_OSD.ShowAchievementProgress(event->achievement->id, true); break; case RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_HIDE: - INFO_LOG(ACHIEVEMENTS, "Progress indicator hide"); + INFO_LOG(Log::Achievements, "Progress indicator hide"); // An achievement that tracks progress has changed the amount of progress that has been made. // The handler should show a small version of the achievement icon along with the achievement->measured_progress text (for two seconds). // Only one progress indicator should be shown at a time. @@ -386,7 +436,7 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * g_OSD.ShowAchievementProgress(0, false); break; case RC_CLIENT_EVENT_LEADERBOARD_TRACKER_SHOW: - INFO_LOG(ACHIEVEMENTS, "Leaderboard tracker show: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); + INFO_LOG(Log::Achievements, "Leaderboard tracker show: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); // A leaderboard_tracker has become active. The handler should show the tracker text on screen. // Multiple active leaderboards may share a single tracker if they have the same definition and value. // As such, the leaderboard tracker IDs are unique amongst the leaderboard trackers, and have no correlation to the active leaderboard(s). @@ -395,25 +445,25 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * break; case RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE: // A leaderboard_tracker has become inactive. The handler should hide the tracker text from the screen. - INFO_LOG(ACHIEVEMENTS, "Leaderboard tracker hide: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); + INFO_LOG(Log::Achievements, "Leaderboard tracker hide: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); g_OSD.ShowLeaderboardTracker(event->leaderboard_tracker->id, nullptr, false); break; case RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE: // A leaderboard_tracker value has been updated. The handler should update the tracker text on the screen. - INFO_LOG(ACHIEVEMENTS, "Leaderboard tracker update: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); + INFO_LOG(Log::Achievements, "Leaderboard tracker update: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); g_OSD.ShowLeaderboardTracker(event->leaderboard_tracker->id, event->leaderboard_tracker->display, true); break; case RC_CLIENT_EVENT_RESET: - WARN_LOG(ACHIEVEMENTS, "Resetting game due to achievement setting change!"); + WARN_LOG(Log::Achievements, "Resetting game due to achievement setting change!"); // Hardcore mode was enabled, or something else that forces a game reset. System_PostUIMessage(UIMessage::REQUEST_GAME_RESET); break; case RC_CLIENT_EVENT_SERVER_ERROR: - ERROR_LOG(ACHIEVEMENTS, "Server error: %s: %s", event->server_error->api, event->server_error->error_message); + ERROR_LOG(Log::Achievements, "Server error: %s: %s", event->server_error->api, event->server_error->error_message); g_OSD.Show(OSDType::MESSAGE_ERROR, "Server error", "", g_RAImageID); break; default: - WARN_LOG(ACHIEVEMENTS, "Unhandled rc_client event %d, ignoring", event->type); + WARN_LOG(Log::Achievements, "Unhandled rc_client event %d, ignoring", event->type); break; } } @@ -423,7 +473,7 @@ static void login_token_callback(int result, const char *error_message, rc_clien switch (result) { case RC_OK: { - INFO_LOG(ACHIEVEMENTS, "Successful login by token."); + INFO_LOG(Log::Achievements, "Successful login by token."); OnAchievementsLoginStateChange(); if (!isInitialAttempt) { auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS); @@ -448,7 +498,7 @@ static void login_token_callback(int result, const char *error_message, rc_clien case RC_INVALID_JSON: default: { - ERROR_LOG(ACHIEVEMENTS, "Callback: Failure logging in via token: %d, %s", result, error_message); + ERROR_LOG(Log::Achievements, "Callback: Failure logging in via token: %d, %s", result, error_message); if (isInitialAttempt) { auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS); g_OSD.Show(OSDType::MESSAGE_WARNING, ac->T("Failed logging in to RetroAchievements"), "", g_RAImageID); @@ -461,10 +511,94 @@ static void login_token_callback(int result, const char *error_message, rc_clien g_isLoggingIn = false; } +bool RAIntegrationDirty() { +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION + return rc_client_raintegration_has_modifications(g_rcClient); +#else + return false; +#endif +} + +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION + +static void raintegration_get_game_name_handler(char *buffer, uint32_t buffer_size, rc_client_t *client) { + snprintf(buffer, buffer_size, "%s", g_gamePath.GetFilename().c_str()); +} + +static void raintegration_write_memory_handler(uint32_t address, uint8_t *buffer, uint32_t num_bytes, rc_client_t *client); + +static void raintegration_event_handler(const rc_client_raintegration_event_t *event, rc_client_t *client) { + switch (event->type) { + case RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED: + // The checked state of one of the menu items has changed and should be reflected in the UI. + // Call the handy helper function if the menu was created by rc_client_raintegration_rebuild_submenu. + System_RunCallbackInWndProc([](void *vhWnd, void *userdata) { + auto menuItem = reinterpret_cast(userdata); + rc_client_raintegration_update_menu_item(g_rcClient, menuItem); + }, reinterpret_cast(reinterpret_cast(event->menu_item))); + break; + case RC_CLIENT_RAINTEGRATION_EVENT_PAUSE: + // The toolkit has hit a breakpoint and wants to pause the emulator. Do so. + Core_EnableStepping(true, "ra_breakpoint"); + break; + case RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED: + // Hardcore mode has been changed (either directly by the user, or disabled through the use of the tools). + // The frontend doesn't necessarily need to know that this value changed, they can still query it whenever + // it's appropriate, but the event lets the frontend do things like enable/disable rewind or cheats. + g_Config.bAchievementsHardcoreMode = rc_client_get_hardcore_enabled(client); + break; + default: + ERROR_LOG(Log::Achievements, "Unsupported raintegration event %u\n", event->type); + break; + } +} + +static void load_integration_callback(int result, const char *error_message, rc_client_t *client, void *userdata) { + auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS); + + // If DLL not present, do nothing. User can still play without the toolkit. + switch (result) { + case RC_OK: + { + // DLL was loaded correctly. + g_OSD.Show(OSDType::MESSAGE_SUCCESS, ac->T("RAIntegration DLL loaded.")); + + rc_client_raintegration_set_console_id(g_rcClient, RC_CONSOLE_PSP); + rc_client_raintegration_set_event_handler(g_rcClient, &raintegration_event_handler); + rc_client_raintegration_set_write_memory_function(g_rcClient, &raintegration_write_memory_handler); + rc_client_raintegration_set_get_game_name_function(g_rcClient, &raintegration_get_game_name_handler); + + System_RunCallbackInWndProc([](void *vhWnd, void *userdata) { + HWND hWnd = reinterpret_cast(vhWnd); + rc_client_raintegration_rebuild_submenu(g_rcClient, GetMenu(hWnd)); + }, nullptr); + break; + } + case RC_MISSING_VALUE: + // This is fine, proceeding to login. + g_OSD.Show(OSDType::MESSAGE_WARNING, ac->T("RAIntegration is enabled, but RAIntegration-x64.dll was not found.")); + break; + case RC_ABORTED: + // This is fine, proceeding to login. + g_OSD.Show(OSDType::MESSAGE_WARNING, ac->T("Wrong version of RAIntegration-x64.dll?")); + break; + default: + g_OSD.Show(OSDType::MESSAGE_ERROR, StringFromFormat("RAIntegration init failed: %s", error_message)); + // Bailing. + return; + } + + // Things are ready to load a game. If the DLL was initialized, calling rc_client_begin_load_game will be redirected + // through the DLL so the toolkit has access to the game data. Similarly, things like rc_create_leaderboard_list will + // be redirected through the DLL to reflect any local changes made by the user. + TryLoginByToken(true); +} +#endif + void Initialize() { if (!g_Config.bAchievementsEnable) { _dbg_assert_(!g_rcClient); - INFO_LOG(ACHIEVEMENTS, "Achievements are disabled, not initializing."); + INFO_LOG(Log::Achievements, "Achievements are disabled, not initializing."); return; } _assert_msg_(!g_rcClient, "Achievements already initialized"); @@ -477,7 +611,6 @@ void Initialize() { // Provide a logging function to simplify debugging rc_client_enable_logging(g_rcClient, RC_CLIENT_LOG_LEVEL_VERBOSE, log_message_callback); - if (!System_GetPropertyBool(SYSPROP_SUPPORTS_HTTPS)) { // Disable SSL if not supported by our platform implementation. rc_client_set_host(g_rcClient, "http://retroachievements.org"); @@ -485,6 +618,26 @@ void Initialize() { rc_client_set_event_handler(g_rcClient, event_handler_callback); + // Set initial settings properly. Hardcore mode is checked by RAIntegration. + rc_client_set_hardcore_enabled(g_rcClient, g_Config.bAchievementsHardcoreMode ? 1 : 0); + rc_client_set_encore_mode_enabled(g_rcClient, g_Config.bAchievementsEncoreMode ? 1 : 0); + rc_client_set_unofficial_enabled(g_rcClient, g_Config.bAchievementsUnofficial ? 1 : 0); + +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION + if (g_Config.bAchievementsEnableRAIntegration) { + wchar_t szFilePath[MAX_PATH]; + GetModuleFileNameW(NULL, szFilePath, MAX_PATH); + for (int64_t i = wcslen(szFilePath) - 1; i > 0; i--) { + if (szFilePath[i] == '\\') { + szFilePath[i] = '\0'; + break; + } + } + HWND hWnd = (HWND)System_GetPropertyInt(SYSPROP_MAIN_WINDOW_HANDLE); + rc_client_begin_load_raintegration(g_rcClient, szFilePath, hWnd, "PPSSPP", PPSSPP_GIT_VERSION, &load_integration_callback, hWnd); + return; + } +#endif TryLoginByToken(true); } @@ -537,7 +690,7 @@ static void login_password_callback(int result, const char *error_message, rc_cl case RC_EXPIRED_TOKEN: default: { - ERROR_LOG(ACHIEVEMENTS, "Failure logging in via password: %d, %s", result, error_message); + ERROR_LOG(Log::Achievements, "Failure logging in via password: %d, %s", result, error_message); g_OSD.Show(OSDType::MESSAGE_WARNING, di->T("Failed to log in, check your username and password."), "", g_RAImageID); OnAchievementsLoginStateChange(); break; @@ -551,7 +704,7 @@ static void login_password_callback(int result, const char *error_message, rc_cl bool LoginAsync(const char *username, const char *password) { auto di = GetI18NCategory(I18NCat::DIALOG); - if (IsLoggedIn() || std::strlen(username) == 0 || std::strlen(password) == 0 || IsUsingRAIntegration()) + if (IsLoggedIn() || std::strlen(username) == 0 || std::strlen(password) == 0) return false; g_OSD.SetProgressBar("cheevos_async_login", di->T("Logging in..."), 0, 0, 0, 0.0f); @@ -587,14 +740,17 @@ void UpdateSettings() { bool Shutdown() { g_activeChallenges.clear(); +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION + rc_client_unload_raintegration(g_rcClient); +#endif rc_client_destroy(g_rcClient); g_rcClient = nullptr; - INFO_LOG(ACHIEVEMENTS, "Achievements shut down."); + INFO_LOG(Log::Achievements, "Achievements shut down."); return true; } void ResetRuntime() { - INFO_LOG(ACHIEVEMENTS, "Resetting rcheevos state..."); + INFO_LOG(Log::Achievements, "Resetting rcheevos state..."); rc_client_reset(g_rcClient); g_activeChallenges.clear(); } @@ -625,7 +781,7 @@ void Idle() { // In this situation, there's a token, but we're not logged in. Probably disrupted internet connection // during startup. // Let's make an attempt. - INFO_LOG(ACHIEVEMENTS, "Retrying login.."); + INFO_LOG(Log::Achievements, "Retrying login.."); TryLoginByToken(false); } } @@ -648,7 +804,7 @@ void DoState(PointerWrap &p) { if (!IsActive()) { Do(p, data_size); if (p.mode == PointerWrap::MODE_READ) { - WARN_LOG(ACHIEVEMENTS, "Save state contained achievement data, but achievements are not active. Ignore."); + WARN_LOG(Log::Achievements, "Save state contained achievement data, but achievements are not active. Ignore."); } p.SkipBytes(data_size); return; @@ -669,7 +825,7 @@ void DoState(PointerWrap &p) { { int retval = rc_client_serialize_progress(g_rcClient, buffer); if (retval != RC_OK) { - ERROR_LOG(ACHIEVEMENTS, "Error %d serializing achievement data. Ignoring.", retval); + ERROR_LOG(Log::Achievements, "Error %d serializing achievement data. Ignoring.", retval); } break; } @@ -685,7 +841,7 @@ void DoState(PointerWrap &p) { int retval = rc_client_deserialize_progress(g_rcClient, buffer); if (retval != RC_OK) { // TODO: What should we really do here? - ERROR_LOG(ACHIEVEMENTS, "Error %d deserializing achievement data. Ignoring.", retval); + ERROR_LOG(Log::Achievements, "Error %d deserializing achievement data. Ignoring.", retval); } break; } @@ -711,7 +867,7 @@ bool HasAchievementsOrLeaderboards() { void DownloadImageIfMissing(const std::string &cache_key, std::string &&url) { if (g_iconCache.MarkPending(cache_key)) { - INFO_LOG(ACHIEVEMENTS, "Downloading image: %s (%s)", url.c_str(), cache_key.c_str()); + INFO_LOG(Log::Achievements, "Downloading image: %s (%s)", url.c_str(), cache_key.c_str()); g_DownloadManager.StartDownloadWithCallback(url, Path(), http::ProgressBarMode::NONE, [cache_key](http::Request &download) { if (download.ResultCode() != 200) return; @@ -764,7 +920,7 @@ void ShowNotLoggedInMessage() { void identify_and_load_callback(int result, const char *error_message, rc_client_t *client, void *userdata) { auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS); - NOTICE_LOG(ACHIEVEMENTS, "Load callback: %d (%s)", result, error_message); + NOTICE_LOG(Log::Achievements, "Load callback: %d (%s)", result, error_message); switch (result) { case RC_OK: @@ -792,7 +948,7 @@ void identify_and_load_callback(int result, const char *error_message, rc_client break; default: // Other various errors. - ERROR_LOG(ACHIEVEMENTS, "Failed to identify/load game: %d (%s)", result, error_message); + ERROR_LOG(Log::Achievements, "Failed to identify/load game: %d (%s)", result, error_message); g_OSD.Show(OSDType::MESSAGE_ERROR, ac->T("Failed to identify game. Achievements will not unlock."), "", g_RAImageID, 6.0f); break; } @@ -805,22 +961,28 @@ bool IsReadyToStart() { } void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoader) { + bool homebrew = false; switch (fileType) { case IdentifiedFileType::PSP_ISO: case IdentifiedFileType::PSP_ISO_NP: // These file types are OK. break; + case IdentifiedFileType::PSP_PBP_DIRECTORY: + // This should be a homebrew, which we now support as well. + // We select the homebrew hashing method. + homebrew = true; + break; default: // Other file types are not yet supported. // TODO: Should we show an OSD popup here? - WARN_LOG(ACHIEVEMENTS, "File type of '%s' is not yet compatible with RetroAchievements", path.c_str()); + WARN_LOG(Log::Achievements, "File type of '%s' is not yet compatible with RetroAchievements", path.c_str()); return; } if (g_isLoggingIn) { // IsReadyToStart should have been checked the same frame, so we shouldn't be here. // Maybe there's a race condition possible, but don't think so. - ERROR_LOG(ACHIEVEMENTS, "Still logging in during SetGame - shouldn't happen"); + ERROR_LOG(Log::Achievements, "Still logging in during SetGame - shouldn't happen"); } if (!g_rcClient || !IsLoggedIn()) { @@ -832,26 +994,33 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad } // The caller should hold off on executing game code until this turns false, checking with IsBlockingExecution() + g_gamePath = path; g_isIdentifying = true; - // TODO: Fish the block device out of the loading process somewhere else. Though, probably easier to just do it here. - { + if (homebrew) { + // Homebrew hashing method - just hash the eboot. + s_game_hash = ComputePSPHomebrewHash(fileLoader); + } else { + // ISO hashing method. + // + // TODO: Fish the block device out of the loading process somewhere else. Though, probably easier to just do it here, + // we need a temporary blockdevice anyway since it gets consumed by ComputePSPISOHash. BlockDevice *blockDevice(constructBlockDevice(fileLoader)); if (!blockDevice) { - ERROR_LOG(ACHIEVEMENTS, "Failed to construct block device for '%s' - can't identify", path.c_str()); + ERROR_LOG(Log::Achievements, "Failed to construct block device for '%s' - can't identify", path.c_str()); g_isIdentifying = false; return; } // This consumes the blockDevice. - s_game_hash = ComputePSPHash(blockDevice); + s_game_hash = ComputePSPISOHash(blockDevice); if (!s_game_hash.empty()) { - INFO_LOG(ACHIEVEMENTS, "Hash: %s", s_game_hash.c_str()); + INFO_LOG(Log::Achievements, "Hash: %s", s_game_hash.c_str()); } } // Apply pre-load settings. - rc_client_set_hardcore_enabled(g_rcClient, g_Config.bAchievementsChallengeMode ? 1 : 0); + rc_client_set_hardcore_enabled(g_rcClient, g_Config.bAchievementsHardcoreMode ? 1 : 0); rc_client_set_encore_mode_enabled(g_rcClient, g_Config.bAchievementsEncoreMode ? 1 : 0); rc_client_set_unofficial_enabled(g_rcClient, g_Config.bAchievementsUnofficial ? 1 : 0); @@ -861,12 +1030,14 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad void UnloadGame() { if (g_rcClient) { rc_client_unload_game(g_rcClient); + g_gamePath.clear(); + s_game_hash.clear(); } } void change_media_callback(int result, const char *error_message, rc_client_t *client, void *userdata) { auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS); - NOTICE_LOG(ACHIEVEMENTS, "Change media callback: %d (%s)", result, error_message); + NOTICE_LOG(Log::Achievements, "Change media callback: %d (%s)", result, error_message); g_isIdentifying = false; switch (result) { @@ -885,7 +1056,7 @@ void change_media_callback(int result, const char *error_message, rc_client_t *c break; default: // Other various errors. - ERROR_LOG(ACHIEVEMENTS, "Failed to identify/load game: %d (%s)", result, error_message); + ERROR_LOG(Log::Achievements, "Failed to identify/load game: %d (%s)", result, error_message); g_OSD.Show(OSDType::MESSAGE_ERROR, ac->T("Failed to identify game. Achievements will not unlock."), "", g_RAImageID, 6.0f); break; } @@ -899,16 +1070,16 @@ void ChangeUMD(const Path &path, FileLoader *fileLoader) { BlockDevice *blockDevice = constructBlockDevice(fileLoader); if (!blockDevice) { - ERROR_LOG(ACHIEVEMENTS, "Failed to construct block device for '%s' - can't identify", path.c_str()); + ERROR_LOG(Log::Achievements, "Failed to construct block device for '%s' - can't identify", path.c_str()); return; } g_isIdentifying = true; // This consumes the blockDevice. - s_game_hash = ComputePSPHash(blockDevice); + s_game_hash = ComputePSPISOHash(blockDevice); if (s_game_hash.empty()) { - ERROR_LOG(ACHIEVEMENTS, "Failed to hash - can't identify"); + ERROR_LOG(Log::Achievements, "Failed to hash - can't identify"); return; } diff --git a/Core/RetroAchievements.h b/Core/RetroAchievements.h index 324976128b..3646b53236 100644 --- a/Core/RetroAchievements.h +++ b/Core/RetroAchievements.h @@ -34,20 +34,6 @@ struct Statistics { int badMemoryAccessCount; }; -// RAIntegration only exists for Windows, so no point checking it on other platforms. -#ifdef WITH_RAINTEGRATION - -bool IsUsingRAIntegration(); - -#else - -static inline bool IsUsingRAIntegration() -{ - return false; -} - -#endif - // Returns true if the user is logged in properly, and everything is set up for playing games with achievements. bool IsLoggedIn(); @@ -71,7 +57,7 @@ bool IsBlockingExecution(); bool HardcoreModeActive(); // Same as ChallengeModeActive but comes with a convenient user message. Don't use for every-frame checks or UI enablement, -// only for shortcut keys and commands. You should look up the message in I18NCat::ACHIEVEMENTS. +// only for shortcut keys and commands. You should look up the message in I18NCat::Achievements. // If no message is specified, a standard "This feature is not available in Hardcore Mode" message will be shown. // Also returns true if hardcore mode is active. // Specify isSaveAction so we can still permit saves (but not loads) in hardcore mode if that option is enabled. @@ -80,6 +66,9 @@ bool WarnUserIfHardcoreModeActive(bool isSaveStateAction, std::string_view messa // Returns the length of the string. If (size_t)-1, there's no message. size_t GetRichPresenceMessage(char *buffer, size_t bufSize); +// Returns true if the user has unsaved RAIntegration changes. Should prompt the user to be sure they want to exit. +bool RAIntegrationDirty(); + // The new API is so much nicer that we can use it directly instead of wrapping it. So let's expose the client. // Will of course return nullptr if not active. rc_client_t *GetClient(); diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index fdb283e577..49ac73c0af 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -211,7 +211,7 @@ namespace SaveState } double taken_s = time_now_d() - start_time; - DEBUG_LOG(SAVESTATE, "Rewind: Compressed save from %d bytes to %d in %0.2f ms.", (int)state.size(), (int)result.size(), taken_s * 1000.0); + DEBUG_LOG(Log::SaveState, "Rewind: Compressed save from %d bytes to %d in %0.2f ms.", (int)state.size(), (int)result.size(), taken_s * 1000.0); } void LockedDecompress(std::vector &result, const std::vector &compressed, const std::vector &base) @@ -285,7 +285,7 @@ namespace SaveState if (diff < g_Config.iRewindSnapshotInterval) return; - DEBUG_LOG(SAVESTATE, "Saving rewind state"); + DEBUG_LOG(Log::SaveState, "Saving rewind state"); Save(); } @@ -588,7 +588,7 @@ namespace SaveState g_Config.sStateLoadUndoGame = GenerateFullDiscId(gameFilename); g_Config.Save("Saving config for savestate last load undo"); } else { - ERROR_LOG(SAVESTATE, "Saving load undo state failed: %.*s", (int)message.size(), message.data()); + ERROR_LOG(Log::SaveState, "Saving load undo state failed: %.*s", (int)message.size(), message.data()); } Load(fn, slot, callback, cbUserData); }; @@ -596,7 +596,7 @@ namespace SaveState if (!backup.empty()) { Save(backup.WithExtraExtension(".tmp"), LOAD_UNDO_SLOT, saveCallback, cbUserData); } else { - ERROR_LOG(SAVESTATE, "Saving load undo state failed. Error in the file system."); + ERROR_LOG(Log::SaveState, "Saving load undo state failed. Error in the file system."); Load(fn, slot, callback, cbUserData); } } else { @@ -835,20 +835,21 @@ namespace SaveState return copy; } - bool HandleLoadFailure() + bool HandleLoadFailure(bool wasRewinding) { - WARN_LOG(SAVESTATE, "HandleLoadFailure - trying a rewind state."); + if (wasRewinding) { + WARN_LOG(Log::SaveState, "HandleLoadFailure - trying a rewind state."); + // Okay, first, let's give the next rewind state a shot - maybe we can at least not reset entirely. + // Actually, this seems like a bad thing - some systems can end up in bad states, like sceFont :( + CChunkFileReader::Error result; + do { + std::string errorString; + result = rewindStates.Restore(&errorString); + } while (result == CChunkFileReader::ERROR_BROKEN_STATE); - // Okay, first, let's give the rewind state a shot - maybe we can at least not reset entirely. - // Even if this was a rewind, maybe we can still load a previous one. - CChunkFileReader::Error result; - do { - std::string errorString; - result = rewindStates.Restore(&errorString); - } while (result == CChunkFileReader::ERROR_BROKEN_STATE); - - if (result == CChunkFileReader::ERROR_NONE) { - return true; + if (result == CChunkFileReader::ERROR_NONE) { + return true; + } } // We tried, our only remaining option is to reset the game. @@ -922,7 +923,7 @@ namespace SaveState if (!__KernelIsRunning()) { - ERROR_LOG(SAVESTATE, "Savestate failure: Unable to load without kernel, this should never happen."); + ERROR_LOG(Log::SaveState, "Savestate failure: Unable to load without kernel, this should never happen."); return; } @@ -948,7 +949,7 @@ namespace SaveState switch (op.type) { case SAVESTATE_LOAD: - INFO_LOG(SAVESTATE, "Loading state from '%s'", op.filename.c_str()); + INFO_LOG(Log::SaveState, "Loading state from '%s'", op.filename.c_str()); // Use the state's latest version as a guess for saveStateInitialGitVersion. result = CChunkFileReader::Load(op.filename, &saveStateInitialGitVersion, state, &errorString); if (result == CChunkFileReader::ERROR_NONE) { @@ -972,9 +973,9 @@ namespace SaveState } #endif } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { - HandleLoadFailure(); + HandleLoadFailure(false); callbackMessage = std::string(i18nLoadFailure) + ": " + errorString; - ERROR_LOG(SAVESTATE, "Load state failure: %s", errorString.c_str()); + ERROR_LOG(Log::SaveState, "Load state failure: %s", errorString.c_str()); callbackResult = Status::FAILURE; } else { callbackMessage = sc->T(errorString.c_str(), i18nLoadFailure); @@ -983,12 +984,12 @@ namespace SaveState break; case SAVESTATE_SAVE: - INFO_LOG(SAVESTATE, "Saving state to %s", op.filename.c_str()); + INFO_LOG(Log::SaveState, "Saving state to %s", op.filename.c_str()); title = g_paramSFO.GetValueString("TITLE"); if (title.empty()) { // Homebrew title title = PSP_CoreParameter().fileToStart.ToVisualString(); - std::size_t lslash = title.find_last_of("/"); + std::size_t lslash = title.find_last_of('/'); title = title.substr(lslash + 1); } result = CChunkFileReader::Save(op.filename, title, PPSSPP_GIT_VERSION, state); @@ -1009,7 +1010,7 @@ namespace SaveState } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { // TODO: What else might we want to do here? This should be very unusual. callbackMessage = i18nSaveFailure; - ERROR_LOG(SAVESTATE, "Save state failure"); + ERROR_LOG(Log::SaveState, "Save state failure"); callbackResult = Status::FAILURE; } else { callbackMessage = i18nSaveFailure; @@ -1021,14 +1022,14 @@ namespace SaveState tempResult = CChunkFileReader::Verify(state) == CChunkFileReader::ERROR_NONE; callbackResult = tempResult ? Status::SUCCESS : Status::FAILURE; if (tempResult) { - INFO_LOG(SAVESTATE, "Verified save state system"); + INFO_LOG(Log::SaveState, "Verified save state system"); } else { - ERROR_LOG(SAVESTATE, "Save state system verification failed"); + ERROR_LOG(Log::SaveState, "Save state system verification failed"); } break; case SAVESTATE_REWIND: - INFO_LOG(SAVESTATE, "Rewinding to recent savestate snapshot"); + INFO_LOG(Log::SaveState, "Rewinding to recent savestate snapshot"); result = rewindStates.Restore(&errorString); if (result == CChunkFileReader::ERROR_NONE) { callbackMessage = sc->T("Loaded State"); @@ -1037,7 +1038,7 @@ namespace SaveState Core_ResetException(); } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { // Cripes. Good news is, we might have more. Let's try those too, better than a reset. - if (HandleLoadFailure()) { + if (HandleLoadFailure(true)) { // Well, we did rewind, even if too much... callbackMessage = sc->T("Loaded State"); callbackResult = Status::SUCCESS; @@ -1056,10 +1057,10 @@ namespace SaveState case SAVESTATE_SAVE_SCREENSHOT: { int maxResMultiplier = 2; - tempResult = TakeGameScreenshot(op.filename, ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, nullptr, nullptr, maxResMultiplier); + tempResult = TakeGameScreenshot(nullptr, op.filename, ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, nullptr, nullptr, maxResMultiplier); callbackResult = tempResult ? Status::SUCCESS : Status::FAILURE; if (!tempResult) { - ERROR_LOG(SAVESTATE, "Failed to take a screenshot for the savestate! %s", op.filename.c_str()); + ERROR_LOG(Log::SaveState, "Failed to take a screenshot for the savestate! %s", op.filename.c_str()); if (screenshotFailures++ < SCREENSHOT_FAILURE_RETRIES) { // Requeue for next frame. SaveScreenshot(op.filename, op.callback, op.cbUserData); @@ -1070,7 +1071,7 @@ namespace SaveState break; } default: - ERROR_LOG(SAVESTATE, "Savestate failure: unknown operation type %d", op.type); + ERROR_LOG(Log::SaveState, "Savestate failure: unknown operation type %d", op.type); callbackResult = Status::FAILURE; break; } @@ -1094,7 +1095,7 @@ namespace SaveState PSP_Shutdown(); std::string resetError; if (!PSP_Init(PSP_CoreParameter(), &resetError)) { - ERROR_LOG(BOOT, "Error resetting: %s", resetError.c_str()); + ERROR_LOG(Log::Boot, "Error resetting: %s", resetError.c_str()); // TODO: This probably doesn't clean up well enough. Core_Stop(); return; diff --git a/Core/Screenshot.cpp b/Core/Screenshot.cpp index a1bbaaafc8..bb12cb3b31 100644 --- a/Core/Screenshot.cpp +++ b/Core/Screenshot.cpp @@ -30,6 +30,7 @@ #include "Core/Screenshot.h" #include "Core/Core.h" #include "GPU/Common/GPUDebugInterface.h" +#include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" @@ -69,7 +70,7 @@ private: static bool WriteScreenshotToJPEG(const Path &filename, int width, int height, int num_channels, const uint8_t *image_data, const jpge::params &comp_params) { JPEGFileStream dst_stream(filename); if (!dst_stream.Valid()) { - ERROR_LOG(IO, "Unable to open screenshot file for writing."); + ERROR_LOG(Log::IO, "Unable to open screenshot file for writing."); return false; } @@ -91,7 +92,7 @@ static bool WriteScreenshotToJPEG(const Path &filename, int width, int height, i } if (!dst_stream.Valid()) { - ERROR_LOG(SYSTEM, "Screenshot file write failed."); + ERROR_LOG(Log::System, "Screenshot file write failed."); } dst_image.deinit(); @@ -101,7 +102,7 @@ static bool WriteScreenshotToJPEG(const Path &filename, int width, int height, i static bool WriteScreenshotToPNG(png_imagep image, const Path &filename, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { FILE *fp = File::OpenCFile(filename, "wb"); if (!fp) { - ERROR_LOG(IO, "Unable to open screenshot file for writing."); + ERROR_LOG(Log::IO, "Unable to open screenshot file for writing."); return false; } @@ -109,7 +110,7 @@ static bool WriteScreenshotToPNG(png_imagep image, const Path &filename, int con fclose(fp); return true; } else { - ERROR_LOG(IO, "Screenshot PNG encode failed."); + ERROR_LOG(Log::IO, "Screenshot PNG encode failed."); fclose(fp); // Should we even do this? File::Delete(filename); @@ -328,32 +329,34 @@ static GPUDebugBuffer ApplyRotation(const GPUDebugBuffer &buf, DisplayRotation r return rotated; } -bool TakeGameScreenshot(const Path &filename, ScreenshotFormat fmt, ScreenshotType type, int *width, int *height, int maxRes) { - if (!gpuDebug) { - ERROR_LOG(SYSTEM, "Can't take screenshots when GPU not running"); - return false; - } +bool TakeGameScreenshot(Draw::DrawContext *draw, const Path &filename, ScreenshotFormat fmt, ScreenshotType type, int *width, int *height, int maxRes) { GPUDebugBuffer buf; bool success = false; u32 w = (u32)-1; u32 h = (u32)-1; if (type == SCREENSHOT_DISPLAY || type == SCREENSHOT_RENDER) { + if (!gpuDebug) { + ERROR_LOG(Log::System, "Can't take screenshots when GPU not running"); + return false; + } success = gpuDebug->GetCurrentFramebuffer(buf, type == SCREENSHOT_RENDER ? GPU_DBG_FRAMEBUF_RENDER : GPU_DBG_FRAMEBUF_DISPLAY, maxRes); w = maxRes > 0 ? 480 * maxRes : PSP_CoreParameter().renderWidth; h = maxRes > 0 ? 272 * maxRes : PSP_CoreParameter().renderHeight; } else if (g_display.rotation != DisplayRotation::ROTATE_0) { + _dbg_assert_(draw); GPUDebugBuffer temp; - success = gpuDebug->GetOutputFramebuffer(temp); + success = ::GetOutputFramebuffer(draw, buf); if (success) { buf = ApplyRotation(temp, g_display.rotation); } } else { - success = gpuDebug->GetOutputFramebuffer(buf); + _dbg_assert_(draw); + success = ::GetOutputFramebuffer(draw, buf); } if (!success) { - ERROR_LOG(G3D, "Failed to obtain screenshot data."); + ERROR_LOG(Log::G3D, "Failed to obtain screenshot data."); return false; } @@ -373,7 +376,7 @@ bool TakeGameScreenshot(const Path &filename, ScreenshotFormat fmt, ScreenshotTy } if (!success) { - ERROR_LOG(IO, "Failed to write screenshot."); + ERROR_LOG(Log::IO, "Failed to write screenshot."); } return success; @@ -391,7 +394,7 @@ bool Save888RGBScreenshot(const Path &filename, ScreenshotFormat fmt, const u8 * png_image_free(&png); if (png.warning_or_error >= 2) { - ERROR_LOG(IO, "Saving screenshot to PNG produced errors."); + ERROR_LOG(Log::IO, "Saving screenshot to PNG produced errors."); success = false; } return success; @@ -414,7 +417,7 @@ bool Save8888RGBAScreenshot(const Path &filename, const u8 *buffer, int w, int h png_image_free(&png); if (png.warning_or_error >= 2) { - ERROR_LOG(IO, "Saving screenshot to PNG produced errors."); + ERROR_LOG(Log::IO, "Saving screenshot to PNG produced errors."); success = false; } return success; @@ -441,7 +444,7 @@ bool Save8888RGBAScreenshot(std::vector &bufferPNG, const u8 *bufferRGB png_image_free(&png); if (!success) { - ERROR_LOG(IO, "Buffering screenshot to PNG produced errors."); + ERROR_LOG(Log::IO, "Buffering screenshot to PNG produced errors."); bufferPNG.clear(); } return success; diff --git a/Core/Screenshot.h b/Core/Screenshot.h index ac124fef9a..69794bb6de 100644 --- a/Core/Screenshot.h +++ b/Core/Screenshot.h @@ -20,6 +20,9 @@ #include "Common/File/Path.h" struct GPUDebugBuffer; +namespace Draw { +class DrawContext; +} enum class ScreenshotFormat { PNG, @@ -38,7 +41,7 @@ enum ScreenshotType { const u8 *ConvertBufferToScreenshot(const GPUDebugBuffer &buf, bool alpha, u8 *&temp, u32 &w, u32 &h); // Can only be used while in game. -bool TakeGameScreenshot(const Path &filename, ScreenshotFormat fmt, ScreenshotType type, int *width = nullptr, int *height = nullptr, int maxRes = -1); +bool TakeGameScreenshot(Draw::DrawContext *draw, const Path &filename, ScreenshotFormat fmt, ScreenshotType type, int *width = nullptr, int *height = nullptr, int maxRes = -1); bool Save888RGBScreenshot(const Path &filename, ScreenshotFormat fmt, const u8 *bufferRGB888, int w, int h); bool Save8888RGBAScreenshot(const Path &filename, const u8 *bufferRGBA8888, int w, int h); diff --git a/Core/System.cpp b/Core/System.cpp index 8e800b747e..155c3bbba3 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -67,7 +67,6 @@ #include "Core/PSPLoaders.h" #include "Core/ELF/ParamSFO.h" #include "Core/SaveState.h" -#include "Common/LogManager.h" #include "Common/ExceptionHandlerSetup.h" #include "Core/HLE/sceAudiocodec.h" #include "GPU/GPUState.h" @@ -128,17 +127,8 @@ void UpdateUIState(GlobalUIState newState) { if (globalUIState != newState && globalUIState != UISTATE_EXIT) { globalUIState = newState; System_Notify(SystemNotification::DISASSEMBLY); - const char *state = nullptr; - switch (globalUIState) { - case UISTATE_EXIT: state = "exit"; break; - case UISTATE_INGAME: state = "ingame"; break; - case UISTATE_MENU: state = "menu"; break; - case UISTATE_PAUSEMENU: state = "pausemenu"; break; - case UISTATE_EXCEPTION: state = "exception"; break; - } - if (state) { - System_NotifyUIState(state); - } + System_Notify(SystemNotification::UI_STATE_CHANGED); + System_SetKeepScreenBright(globalUIState == UISTATE_INGAME); } } @@ -280,12 +270,12 @@ bool CPU_Init(std::string *errorString, FileLoader *loadedFile) { case IdentifiedFileType::PSP_PBP: case IdentifiedFileType::PSP_PBP_DIRECTORY: // This is normal for homebrew. - // ERROR_LOG(LOADER, "PBP directory resolution failed."); + // ERROR_LOG(Log::Loader, "PBP directory resolution failed."); InitMemoryForGamePBP(loadedFile); break; case IdentifiedFileType::PSP_ELF: if (Memory::g_PSPModel != PSP_MODEL_FAT) { - INFO_LOG(LOADER, "ELF, using full PSP-2000 memory access"); + INFO_LOG(Log::Loader, "ELF, using full PSP-2000 memory access"); Memory::g_MemorySize = Memory::RAM_DOUBLE_SIZE; } break; @@ -299,7 +289,7 @@ bool CPU_Init(std::string *errorString, FileLoader *loadedFile) { break; default: // Can we even get here? - WARN_LOG(LOADER, "CPU_Init didn't recognize file. %s", errorString->c_str()); + WARN_LOG(Log::Loader, "CPU_Init didn't recognize file. %s", errorString->c_str()); break; } @@ -430,11 +420,11 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) { } #if defined(_WIN32) && PPSSPP_ARCH(AMD64) - NOTICE_LOG(BOOT, "PPSSPP %s Windows 64 bit", PPSSPP_GIT_VERSION); + NOTICE_LOG(Log::Boot, "PPSSPP %s Windows 64 bit", PPSSPP_GIT_VERSION); #elif defined(_WIN32) && !PPSSPP_ARCH(AMD64) - NOTICE_LOG(BOOT, "PPSSPP %s Windows 32 bit", PPSSPP_GIT_VERSION); + NOTICE_LOG(Log::Boot, "PPSSPP %s Windows 32 bit", PPSSPP_GIT_VERSION); #else - NOTICE_LOG(BOOT, "PPSSPP %s", PPSSPP_GIT_VERSION); + NOTICE_LOG(Log::Boot, "PPSSPP %s", PPSSPP_GIT_VERSION); #endif Core_NotifyLifecycle(CoreLifecycle::STARTING); @@ -641,7 +631,9 @@ void PSP_RunLoopUntil(u64 globalticks) { return; } - mipsr4k.RunLoopUntil(globalticks); + if (coreState != CORE_NEXTFRAME) { // Can be set by SaveState as well as by sceDisplay + mipsr4k.RunLoopUntil(globalticks); + } } void PSP_RunLoopFor(int cycles) { @@ -713,7 +705,7 @@ Path GetSysDirectory(PSPDirectories directoryType) { return g_Config.memStickDirectory; // Just return the memory stick root if we run into some sort of problem. default: - ERROR_LOG(FILESYS, "Unknown directory type."); + ERROR_LOG(Log::FileSystem, "Unknown directory type."); return g_Config.memStickDirectory; } } @@ -726,10 +718,10 @@ bool CreateSysDirectories() { #endif Path pspDir = GetSysDirectory(DIRECTORY_PSP); - INFO_LOG(IO, "Creating '%s' and subdirs:", pspDir.c_str()); + INFO_LOG(Log::IO, "Creating '%s' and subdirs:", pspDir.c_str()); File::CreateDir(pspDir); if (!File::Exists(pspDir)) { - INFO_LOG(IO, "Not a workable memstick directory. Giving up"); + INFO_LOG(Log::IO, "Not a workable memstick directory. Giving up"); return false; } @@ -754,6 +746,5 @@ bool CreateSysDirectories() { File::CreateEmptyFile(path / ".nomedia"); } } - return true; } diff --git a/Core/Util/BlockAllocator.cpp b/Core/Util/BlockAllocator.cpp index 270cca6508..72907d7aea 100644 --- a/Core/Util/BlockAllocator.cpp +++ b/Core/Util/BlockAllocator.cpp @@ -61,7 +61,7 @@ u32 BlockAllocator::AllocAligned(u32 &size, u32 sizeGrain, u32 grain, bool fromT { // Sanity check if (size == 0 || size > rangeSize_) { - ERROR_LOG(SCEKERNEL, "Clearly bogus size: %08x - failing allocation", size); + ERROR_LOG(Log::sceKernel, "Clearly bogus size: %08x - failing allocation", size); return -1; } @@ -139,7 +139,7 @@ u32 BlockAllocator::AllocAligned(u32 &size, u32 sizeGrain, u32 grain, bool fromT //Out of memory :( ListBlocks(); - ERROR_LOG(SCEKERNEL, "Block Allocator (%08x-%08x) failed to allocate %i (%08x) bytes of contiguous memory", rangeStart_, rangeStart_ + rangeSize_, size, size); + ERROR_LOG(Log::sceKernel, "Block Allocator (%08x-%08x) failed to allocate %i (%08x) bytes of contiguous memory", rangeStart_, rangeStart_ + rangeSize_, size, size); return -1; } @@ -153,7 +153,7 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) { CheckBlocks(); if (size > rangeSize_) { - ERROR_LOG(SCEKERNEL, "Clearly bogus size: %08x - failing allocation", size); + ERROR_LOG(Log::sceKernel, "Clearly bogus size: %08x - failing allocation", size); return -1; } @@ -161,7 +161,7 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) u32 alignedPosition = position; u32 alignedSize = size; if (position & (grain_ - 1)) { - DEBUG_LOG(SCEKERNEL, "Position %08x does not align to grain.", position); + DEBUG_LOG(Log::sceKernel, "Position %08x does not align to grain.", position); alignedPosition &= ~(grain_ - 1); // Since the position was decreased, size must increase. @@ -179,7 +179,7 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) Block &b = *bp; if (b.taken) { - ERROR_LOG(SCEKERNEL, "Block allocator AllocAt failed, block taken! %08x, %i", position, size); + ERROR_LOG(Log::sceKernel, "Block allocator AllocAt failed, block taken! %08x, %i", position, size); return -1; } else @@ -187,7 +187,7 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) // Make sure the block is big enough to split. if (b.start + b.size < alignedPosition + alignedSize) { - ERROR_LOG(SCEKERNEL, "Block allocator AllocAt failed, not enough contiguous space %08x, %i", position, size); + ERROR_LOG(Log::sceKernel, "Block allocator AllocAt failed, not enough contiguous space %08x, %i", position, size); return -1; } //good to go @@ -214,24 +214,24 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) } else { - ERROR_LOG(SCEKERNEL, "Block allocator AllocAt failed :( %08x, %i", position, size); + ERROR_LOG(Log::sceKernel, "Block allocator AllocAt failed :( %08x, %i", position, size); } //Out of memory :( ListBlocks(); - ERROR_LOG(SCEKERNEL, "Block Allocator (%08x-%08x) failed to allocate %i (%08x) bytes of contiguous memory", rangeStart_, rangeStart_ + rangeSize_, alignedSize, alignedSize); + ERROR_LOG(Log::sceKernel, "Block Allocator (%08x-%08x) failed to allocate %i (%08x) bytes of contiguous memory", rangeStart_, rangeStart_ + rangeSize_, alignedSize, alignedSize); return -1; } void BlockAllocator::MergeFreeBlocks(Block *fromBlock) { - DEBUG_LOG(SCEKERNEL, "Merging Blocks"); + DEBUG_LOG(Log::sceKernel, "Merging Blocks"); Block *prev = fromBlock->prev; while (prev != NULL && prev->taken == false) { - DEBUG_LOG(SCEKERNEL, "Block Alloc found adjacent free blocks - merging"); + DEBUG_LOG(Log::sceKernel, "Block Alloc found adjacent free blocks - merging"); prev->size += fromBlock->size; if (fromBlock->next == NULL) top_ = prev; @@ -251,7 +251,7 @@ void BlockAllocator::MergeFreeBlocks(Block *fromBlock) Block *next = fromBlock->next; while (next != NULL && next->taken == false) { - DEBUG_LOG(SCEKERNEL, "Block Alloc found adjacent free blocks - merging"); + DEBUG_LOG(Log::sceKernel, "Block Alloc found adjacent free blocks - merging"); fromBlock->size += next->size; fromBlock->next = next->next; delete next; @@ -276,7 +276,7 @@ bool BlockAllocator::Free(u32 position) } else { - ERROR_LOG(SCEKERNEL, "BlockAllocator : invalid free %08x", position); + ERROR_LOG(Log::sceKernel, "BlockAllocator : invalid free %08x", position); return false; } } @@ -293,7 +293,7 @@ bool BlockAllocator::FreeExact(u32 position) } else { - ERROR_LOG(SCEKERNEL, "BlockAllocator : invalid free %08x", position); + ERROR_LOG(Log::sceKernel, "BlockAllocator : invalid free %08x", position); return false; } } @@ -331,11 +331,11 @@ void BlockAllocator::CheckBlocks() const { const Block &b = *bp; if (b.start > 0xc0000000) { // probably free'd debug values - ERROR_LOG_REPORT(HLE, "Bogus block in allocator"); + ERROR_LOG_REPORT(Log::HLE, "Bogus block in allocator"); } // Outside the valid range, probably logic bug in allocation. if (b.start + b.size > rangeStart_ + rangeSize_ || b.start < rangeStart_) { - ERROR_LOG_REPORT(HLE, "Bogus block in allocator"); + ERROR_LOG_REPORT(Log::HLE, "Bogus block in allocator"); } } } @@ -393,13 +393,13 @@ u32 BlockAllocator::GetBlockSizeFromAddress(u32 addr) const void BlockAllocator::ListBlocks() const { - DEBUG_LOG(SCEKERNEL,"-----------"); + DEBUG_LOG(Log::sceKernel,"-----------"); for (const Block *bp = bottom_; bp != NULL; bp = bp->next) { const Block &b = *bp; - DEBUG_LOG(SCEKERNEL, "Block: %08x - %08x size %08x taken=%i tag=%s", b.start, b.start+b.size, b.size, b.taken ? 1:0, b.tag); + DEBUG_LOG(Log::sceKernel, "Block: %08x - %08x size %08x taken=%i tag=%s", b.start, b.start+b.size, b.size, b.taken ? 1:0, b.tag); } - DEBUG_LOG(SCEKERNEL,"-----------"); + DEBUG_LOG(Log::sceKernel,"-----------"); } u32 BlockAllocator::GetLargestFreeBlockSize() const @@ -415,7 +415,7 @@ u32 BlockAllocator::GetLargestFreeBlockSize() const } } if (maxFreeBlock & (grain_ - 1)) - WARN_LOG_REPORT(HLE, "GetLargestFreeBlockSize: free size %08x does not align to grain %08x.", maxFreeBlock, grain_); + WARN_LOG_REPORT(Log::HLE, "GetLargestFreeBlockSize: free size %08x does not align to grain %08x.", maxFreeBlock, grain_); return maxFreeBlock; } @@ -431,7 +431,7 @@ u32 BlockAllocator::GetTotalFreeBytes() const } } if (sum & (grain_ - 1)) - WARN_LOG_REPORT(HLE, "GetTotalFreeBytes: free size %08x does not align to grain %08x.", sum, grain_); + WARN_LOG_REPORT(Log::HLE, "GetTotalFreeBytes: free size %08x does not align to grain %08x.", sum, grain_); return sum; } diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index 43be22b454..aa49af09cd 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -749,15 +749,21 @@ static void FPandASIMD1(uint32_t w, uint64_t addr, Instruction *instr) { int dst_index = imm5 >> (size + 1); int src_index = imm4 >> size; int op = (w >> 29) & 1; - char s = "bhsd"[size]; + char s; + switch (size) { + case 0x00: s = 'b'; break; + case 0x01: s = 'h'; break; + case 0x02: s = 's'; break; + case 0x03: s = 'd'; break; + } if (op == 0 && imm4 == 0) { // DUP (element) int idxdsize = (imm5 & 8) ? 128 : 64; - char r = "dq"[idxdsize == 128]; + char r = (idxdsize == 128) ? 'q' : 'd'; snprintf(instr->text, sizeof(instr->text), "dup %c%d, %c%d.%c[%d]", r, Rd, r, Rn, s, dst_index); } else { int idxdsize = (imm4 & 8) ? 128 : 64; - char r = "dq"[idxdsize == 128]; + char r = (idxdsize == 128) ? 'q' : 'd'; snprintf(instr->text, sizeof(instr->text), "ins %c%d.%c[%d], %c%d.%c[%d]", r, Rd, s, dst_index, r, Rn, s, src_index); } } @@ -916,8 +922,6 @@ static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) { } else if (((w >> 10) & 0x3f) == 0x0 && opcode == 0) { char ir = sf ? 'x' : 'w'; char roundmode = "npmz"[(w >> 19) & 3]; - if (opcode & 0x4) - roundmode = 'a'; char fr = ((w >> 22) & 1) ? 'd' : 's'; snprintf(instr->text, sizeof(instr->text), "fcvt%cs %c%d, %c%d", roundmode, ir, Rd, fr, Rn); } else if ((opcode & 6) == 2) { diff --git a/Core/Util/GameDB.cpp b/Core/Util/GameDB.cpp index 804aa055a0..6d815f0582 100644 --- a/Core/Util/GameDB.cpp +++ b/Core/Util/GameDB.cpp @@ -97,7 +97,7 @@ void GameDB::LoadIfNeeded() { SplitCSVLine(lineString, items); if (items.size() != columns_.size()) { // Bad line - ERROR_LOG(SYSTEM, "Bad line in CSV file: %s", std::string(lineString).c_str()); + ERROR_LOG(Log::System, "Bad line in CSV file: %s", std::string(lineString).c_str()); continue; } diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index ebbcb74b60..7c2045236c 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -24,13 +24,13 @@ #include #include #include - #ifdef SHARED_LIBZIP #include #else #include "ext/libzip/zip.h" #endif #ifdef _WIN32 + #include "Common/CommonWindows.h" #endif #include "Common/Data/Encoding/Utf8.h" @@ -51,7 +51,7 @@ GameManager g_GameManager; -static struct zip *ZipOpenPath(Path fileName) { +struct zip *ZipOpenPath(Path fileName) { int error = 0; // Need to special case for content URI here, similar to OpenCFile. struct zip *z; @@ -66,11 +66,15 @@ static struct zip *ZipOpenPath(Path fileName) { } if (!z) { - ERROR_LOG(HLE, "Failed to open ZIP file '%s', error code=%i", fileName.c_str(), error); + ERROR_LOG(Log::HLE, "Failed to open ZIP file '%s', error code=%i", fileName.c_str(), error); } return z; } +void ZipClose(struct zip *z) { + zip_close(z); +} + GameManager::GameManager() { } @@ -93,11 +97,11 @@ bool GameManager::IsGameInstalled(const std::string &name) { bool GameManager::DownloadAndInstall(const std::string &storeFileUrl) { if (curDownload_.get() != nullptr) { - ERROR_LOG(HLE, "Can only process one download at a time"); + ERROR_LOG(Log::HLE, "Can only process one download at a time"); return false; } if (InstallInProgress()) { - ERROR_LOG(HLE, "Can't download when an install is in progress (yet)"); + ERROR_LOG(Log::HLE, "Can't download when an install is in progress (yet)"); return false; } @@ -136,21 +140,21 @@ void GameManager::UninstallGame(const std::string &name) { Path gameDir = GetSysDirectory(DIRECTORY_GAME) / name; auto st = GetI18NCategory(I18NCat::STORE); - INFO_LOG(HLE, "Uninstalling '%s'", gameDir.c_str()); + INFO_LOG(Log::HLE, "Uninstalling '%s'", gameDir.c_str()); if (!File::Exists(gameDir)) { - ERROR_LOG(HLE, "Game '%s' not installed, cannot uninstall", name.c_str()); + ERROR_LOG(Log::HLE, "Game '%s' not installed, cannot uninstall", name.c_str()); return; } g_OSD.SetProgressBar("install", st->T("Uninstall"), 0.0f, 0.0f, 0.0f, 0.1f); bool success = File::DeleteDirRecursively(gameDir); g_OSD.RemoveProgressBar("install", success, 0.5f); if (success) { - INFO_LOG(HLE, "Successfully uninstalled game '%s'", name.c_str()); + INFO_LOG(Log::HLE, "Successfully uninstalled game '%s'", name.c_str()); InstallDone(); cleanRecentsAfter_ = true; return; } else { - ERROR_LOG(HLE, "Failed to uninstalled game '%s'", name.c_str()); + ERROR_LOG(Log::HLE, "Failed to uninstalled game '%s'", name.c_str()); InstallDone(); return; } @@ -158,18 +162,22 @@ void GameManager::UninstallGame(const std::string &name) { void GameManager::Update() { if (curDownload_.get() && curDownload_->Done()) { - INFO_LOG(HLE, "Download completed! Status = %d", curDownload_->ResultCode()); + INFO_LOG(Log::HLE, "Download completed! Status = %d", curDownload_->ResultCode()); Path fileName = curDownload_->outfile(); if (curDownload_->ResultCode() == 200) { if (!File::Exists(fileName)) { - ERROR_LOG(HLE, "Downloaded file '%s' does not exist :(", fileName.c_str()); + ERROR_LOG(Log::HLE, "Downloaded file '%s' does not exist :(", fileName.c_str()); curDownload_.reset(); return; } // Game downloaded to temporary file - install it! - InstallGameOnThread(Path(curDownload_->url()), fileName, true); + ZipFileTask task; + task.url = Path(curDownload_->url()); + task.fileName = fileName; + task.deleteAfter = true; + InstallZipOnThread(task); } else { - ERROR_LOG(HLE, "Expected HTTP status code 200, got status code %d. Install cancelled, deleting partial file '%s'", + ERROR_LOG(Log::HLE, "Expected HTTP status code 200, got status code %d. Install cancelled, deleting partial file '%s'", curDownload_->ResultCode(), fileName.c_str()); File::Delete(fileName); } @@ -186,27 +194,34 @@ void GameManager::Update() { } } -static void countSlashes(const std::string &fileName, int *slashLocation, int *slashCount) { - *slashCount = 0; +static int countSlashes(const std::string &fileName, int *slashLocation) { + int slashCount = 0; int lastSlashLocation = -1; - *slashLocation = -1; + if (slashLocation) { + *slashLocation = -1; + } for (size_t i = 0; i < fileName.size(); i++) { if (fileName[i] == '/') { - (*slashCount)++; - *slashLocation = lastSlashLocation; - lastSlashLocation = (int)i; + slashCount++; + if (slashLocation) { + *slashLocation = lastSlashLocation; + lastSlashLocation = (int)i; + } } } + + return slashCount; } -ZipFileContents DetectZipFileContents(const Path &fileName, ZipFileInfo *info) { +bool DetectZipFileContents(const Path &fileName, ZipFileInfo *info) { struct zip *z = ZipOpenPath(fileName); if (!z) { - return ZipFileContents::UNKNOWN; + info->contents = ZipFileContents::UNKNOWN; + return false; } - ZipFileContents retVal = DetectZipFileContents(z, info); + DetectZipFileContents(z, info); zip_close(z); - return retVal; + return true; } inline char asciitolower(char in) { @@ -215,7 +230,28 @@ inline char asciitolower(char in) { return in; } -ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info) { +bool CanExtractWithoutOverwrite(struct zip *z, const Path &destination, int maxOkFiles) { + int numFiles = zip_get_num_files(z); + if (numFiles > maxOkFiles && maxOkFiles >= 0) { + // Ignore the check, just assume we can't. + return false; + } + for (int i = 0; i < numFiles; i++) { + const char *fn = zip_get_name(z, i, 0); + if (endsWith(fn, "/")) { + // we don't care about directory overwrites, that's fine. + continue; + } + Path p = destination / fn; + if (File::Exists(p)) { + INFO_LOG(Log::HLE, "Extract zip check: %s exists, can't extract without overwrite", p.ToVisualString().c_str()); + return false; + } + } + return true; +} + +void DetectZipFileContents(struct zip *z, ZipFileInfo *info) { int numFiles = zip_get_num_files(z); // Verify that this is a PSP zip file with the correct layout. We also try @@ -228,30 +264,54 @@ ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info) { int isoFileIndex = -1; int stripCharsTexturePack = -1; int textureIniIndex = -1; + int filesInRoot = 0; + int directoriesInRoot = 0; + bool hasParamSFO = false; + bool hasIcon0PNG = false; + s64 totalFileSize = 0; + // TODO: It might be cleaner to write separate detection functions, but this big loop doing it all at once + // is quite convenient and makes it easy to add shared heuristics. for (int i = 0; i < numFiles; i++) { const char *fn = zip_get_name(z, i, 0); + + zip_stat_t stat{}; + zip_stat_index(z, i, 0, &stat); + totalFileSize += stat.size; + std::string zippedName = fn; std::transform(zippedName.begin(), zippedName.end(), zippedName.begin(), [](unsigned char c) { return asciitolower(c); }); // Not using std::tolower to avoid Turkish I->ı conversion. + // Ignore macos metadata stuff + if (startsWith(zippedName, "__macosx/")) { + continue; + } + if (endsWith(zippedName, "/")) { + // A directory. Not all zips bother including these. + continue; + } + + int prevSlashLocation = -1; + int slashCount = countSlashes(zippedName, &prevSlashLocation); if (zippedName.find("eboot.pbp") != std::string::npos) { - int slashCount = 0; - int slashLocation = -1; - countSlashes(zippedName, &slashLocation, &slashCount); - if (slashCount >= 1 && (!isPSPMemstickGame || slashLocation < stripChars + 1)) { - stripChars = slashLocation + 1; + if (slashCount >= 1 && (!isPSPMemstickGame || prevSlashLocation < stripChars + 1)) { + stripChars = prevSlashLocation + 1; isPSPMemstickGame = true; } else { - INFO_LOG(HLE, "Wrong number of slashes (%i) in '%s'", slashCount, fn); + INFO_LOG(Log::HLE, "Wrong number of slashes (%i) in '%s'", slashCount, fn); } + // TODO: Extract icon and param.sfo from the pbp to be able to display it on the install screen. } else if (endsWith(zippedName, ".iso") || endsWith(zippedName, ".cso") || endsWith(zippedName, ".chd")) { - int slashCount = 0; - int slashLocation = -1; - countSlashes(zippedName, &slashLocation, &slashCount); if (slashCount <= 1) { // We only do this if the ISO file is in the root or one level down. isZippedISO = true; - isoFileIndex = i; + INFO_LOG(Log::HLE, "ISO found in zip: %s", zippedName.c_str()); + if (isoFileIndex != -1) { + INFO_LOG(Log::HLE, "More than one ISO file found in zip. Ignoring additional ones."); + } else { + isoFileIndex = i; + info->contentName = zippedName; + } } } else if (zippedName.find("textures.ini") != std::string::npos) { int slashLocation = (int)zippedName.find_last_of('/'); @@ -260,6 +320,29 @@ ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info) { isTexturePack = true; textureIniIndex = i; } + } else if (endsWith(zippedName, "/param.sfo")) { + // Get the game name so we can display it. + std::string paramSFOContents; + if (ZipExtractFileToMemory(z, i, ¶mSFOContents)) { + ParamSFOData sfo; + if (sfo.ReadSFO((const u8 *)paramSFOContents.data(), paramSFOContents.size())) { + if (sfo.HasKey("TITLE")) { + info->gameTitle = sfo.GetValueString("TITLE"); + info->savedataTitle = sfo.GetValueString("SAVEDATA_TITLE"); + char buff[20]; + strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&stat.mtime)); + info->mTime = buff; + info->savedataDetails = sfo.GetValueString("SAVEDATA_DETAIL"); + info->savedataDir = sfo.GetValueString("SAVEDATA_DIRECTORY"); // should also be parsable from the path. + hasParamSFO = true; + } + } + } + } else if (endsWith(zippedName, "/icon0.png")) { + hasIcon0PNG = true; + } + if (slashCount == 0) { + filesInRoot++; } } @@ -268,103 +351,157 @@ ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info) { info->isoFileIndex = isoFileIndex; info->textureIniIndex = textureIniIndex; info->ignoreMetaFiles = false; + info->totalFileSize = totalFileSize; - // If a ZIP is detected as both, let's let the memstick game interpretation prevail. + // Priority ordering for detecting the various kinds of zip file content.s if (isPSPMemstickGame) { - return ZipFileContents::PSP_GAME_DIR; + info->contents = ZipFileContents::PSP_GAME_DIR; } else if (isZippedISO) { - return ZipFileContents::ISO_FILE; + info->contents = ZipFileContents::ISO_FILE; } else if (isTexturePack) { info->stripChars = stripCharsTexturePack; info->ignoreMetaFiles = true; - return ZipFileContents::TEXTURE_PACK; + info->contents = ZipFileContents::TEXTURE_PACK; + } else if (stripChars == 0 && filesInRoot == 0 && hasParamSFO && hasIcon0PNG) { + // As downloaded from GameFAQs, for example. + info->contents = ZipFileContents::SAVE_DATA; } else { - return ZipFileContents::UNKNOWN; + info->contents = ZipFileContents::UNKNOWN; } } // Parameters need to be by value, since this is a thread func. -bool GameManager::InstallGame(const Path &url, const Path &fileName, bool deleteAfter) { - SetCurrentThreadName("InstallGame"); +void GameManager::InstallZipContents(ZipFileTask task) { + SetCurrentThreadName("InstallZipContents"); if (installDonePending_) { - ERROR_LOG(HLE, "Cannot have two installs in progress at the same time"); - return false; + ERROR_LOG(Log::HLE, "Cannot have two installs in progress at the same time"); + return; } AndroidJNIThreadContext context; // Destructor detaches. - if (!File::Exists(fileName)) { - ERROR_LOG(HLE, "Game file '%s' doesn't exist", fileName.c_str()); - return false; + if (!File::Exists(task.fileName)) { + ERROR_LOG(Log::HLE, "Game file '%s' doesn't exist", task.fileName.c_str()); + return; } auto st = GetI18NCategory(I18NCat::STORE); auto di = GetI18NCategory(I18NCat::DIALOG); auto sy = GetI18NCategory(I18NCat::SYSTEM); - std::string extension = url.GetFileExtension(); + std::string urlExtension = task.url.GetFileExtension(); // Examine the URL to guess out what we're installing. - if (extension == ".cso" || extension == ".iso" || extension == ".chd") { - // It's a raw ISO or CSO file. We just copy it to the destination. - std::string shortFilename = url.GetFilename(); - bool success = InstallRawISO(fileName, shortFilename, deleteAfter); - return success; + // TODO: Bad idea due to Android content api where we don't always get the filename. + if (urlExtension == ".cso" || urlExtension == ".iso" || urlExtension == ".chd") { + // It's a raw ISO or CSO file. We just copy it to the destination, which is the + // currently selected directory in the game browser. Note: This might not be a good option! + Path destPath = Path(g_Config.currentDirectory) / task.url.GetFilename(); + if (!File::Exists(destPath)) { + // Fall back to the root of the memstick. + destPath = g_Config.memStickDirectory; + } + g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f); + + // TODO: To save disk space, we should probably attempt a move first, if deleteAfter is true. + // TODO: Update the progress bar continuously. + bool success = File::Copy(task.fileName, destPath); + + if (!success) { + ERROR_LOG(Log::HLE, "Raw ISO install failed"); + // This shouldn't normally happen at all (only when putting ISOs in a store, which is not a normal use case), so skipping the translation string + SetInstallError("Failed to install raw ISO"); + } + if (task.deleteAfter) { + File::Delete(task.fileName); + } + g_OSD.RemoveProgressBar("install", success, 0.5f); + installProgress_ = 1.0f; + InstallDone(); + return; } - Path pspGame = GetSysDirectory(DIRECTORY_GAME); - Path dest = pspGame; int error = 0; - struct zip *z = ZipOpenPath(fileName); + struct zip *z = ZipOpenPath(task.fileName); if (!z) { - g_OSD.RemoveProgressBar("install", false, 0.5f); + g_OSD.RemoveProgressBar("install", false, 1.5f); SetInstallError(sy->T("Unable to open zip file")); - return false; + installProgress_ = 1.0f; + InstallDone(); + return; } - ZipFileInfo info; - ZipFileContents contents = DetectZipFileContents(z, &info); bool success = false; - switch (contents) { + + ZipFileInfo zipInfo; + if (task.zipFileInfo) { + // The normal case + zipInfo = *task.zipFileInfo; + } else { + DetectZipFileContents(z, &zipInfo); + } + + switch (zipInfo.contents) { case ZipFileContents::PSP_GAME_DIR: - INFO_LOG(HLE, "Installing '%s' into '%s'", fileName.c_str(), pspGame.c_str()); - // InstallMemstickGame contains code to close (and delete) z. - success = InstallMemstickGame(z, fileName, pspGame, info, false, deleteAfter); + { + Path pspGame = GetSysDirectory(DIRECTORY_GAME); + INFO_LOG(Log::HLE, "Installing '%s' into '%s'", task.fileName.c_str(), pspGame.c_str()); + // InstallZipContents contains code to close z. + success = ExtractZipContents(z, pspGame, zipInfo, false); break; + } case ZipFileContents::ISO_FILE: - INFO_LOG(HLE, "Installing '%s' into its containing directory", fileName.c_str()); + { + INFO_LOG(Log::HLE, "Installing '%s' into '%s'", task.fileName.c_str(), task.destination.c_str()); // InstallZippedISO contains code to close z. - success = InstallZippedISO(z, info.isoFileIndex, fileName, deleteAfter); + success = InstallZippedISO(z, zipInfo.isoFileIndex, task.destination); break; + } case ZipFileContents::TEXTURE_PACK: + { // InstallMemstickGame contains code to close z, and works for textures too. - if (DetectTexturePackDest(z, info.textureIniIndex, dest)) { - INFO_LOG(HLE, "Installing texture pack '%s' into '%s'", fileName.c_str(), dest.c_str()); + Path dest; + if (DetectTexturePackDest(z, zipInfo.textureIniIndex, dest)) { + INFO_LOG(Log::HLE, "Installing texture pack '%s' into '%s'", task.fileName.c_str(), dest.c_str()); File::CreateFullPath(dest); // Install as a zip file if textures.ini is in the root. Performs better on Android. - if (info.stripChars == 0) { - success = InstallMemstickZip(z, fileName, dest / "textures.zip", info, deleteAfter); + if (zipInfo.stripChars == 0) { + success = InstallMemstickZip(z, task.fileName, dest / "textures.zip", zipInfo); } else { // TODO: Can probably remove this, as we now put .nomedia in /TEXTURES directly. File::CreateEmptyFile(dest / ".nomedia"); - success = InstallMemstickGame(z, fileName, dest, info, true, deleteAfter); + success = ExtractZipContents(z, dest, zipInfo, true); } } else { zip_close(z); z = nullptr; } break; + } + case ZipFileContents::SAVE_DATA: + { + Path pspSaveData = GetSysDirectory(DIRECTORY_SAVEDATA); + success = ExtractZipContents(z, pspSaveData, zipInfo, false); + break; + } default: - ERROR_LOG(HLE, "File not a PSP game, no EBOOT.PBP found."); + ERROR_LOG(Log::HLE, "File not a PSP game, no EBOOT.PBP found."); SetInstallError(sy->T("Not a PSP game")); zip_close(z); z = nullptr; - if (deleteAfter) - File::Delete(fileName); break; } + + // Common functionality. + if (task.deleteAfter && success) { + File::Delete(task.fileName); + } g_OSD.RemoveProgressBar("install", success, 0.5f); - return success; + installProgress_ = 1.0f; + InstallDone(); + if (success) { + ResetInstallError(); + } } bool GameManager::DetectTexturePackDest(struct zip *z, int iniIndex, Path &dest) { @@ -488,24 +625,45 @@ std::string GameManager::GetISOGameID(FileLoader *loader) const { return sfo.GetValueString("DISC_ID"); } +bool ZipExtractFileToMemory(struct zip *z, int fileIndex, std::string *data) { + struct zip_stat zstat; + zip_stat_index(z, fileIndex, 0, &zstat); + if (zstat.size == 0) { + data->clear(); + return true; + } + + size_t readSize = zstat.size; + data->resize(readSize); + + zip_file *zf = zip_fopen_index(z, fileIndex, 0); + zip_int64_t retval = zip_fread(zf, data->data(), readSize); + zip_fclose(zf); + + if (retval < 0 || retval < (int)readSize) { + ERROR_LOG(Log::HLE, "Failed to read %d bytes from zip (%d) - archive corrupt?", (int)readSize, (int)retval); + return false; + } else { + return true; + } +} + bool GameManager::ExtractFile(struct zip *z, int file_index, const Path &outFilename, size_t *bytesCopied, size_t allBytes) { struct zip_stat zstat; zip_stat_index(z, file_index, 0, &zstat); size_t size = zstat.size; - - // Don't spam the log. - if (file_index < 10) { - INFO_LOG(HLE, "Writing %d bytes to '%s'", (int)size, outFilename.c_str()); - } - zip_file *zf = zip_fopen_index(z, file_index, 0); if (!zf) { - ERROR_LOG(HLE, "Failed to open file by index (%d) (%s)", file_index, outFilename.c_str()); + ERROR_LOG(Log::HLE, "Failed to open file by index (%d) (%s)", file_index, outFilename.c_str()); return false; } FILE *f = File::OpenCFile(outFilename, "wb"); if (f) { + // Don't spam the log. + if (file_index < 10) { + INFO_LOG(Log::HLE, "Writing %d bytes to '%s'", (int)size, outFilename.c_str()); + } size_t pos = 0; const size_t blockSize = 1024 * 128; u8 *buffer = new u8[blockSize]; @@ -513,7 +671,7 @@ bool GameManager::ExtractFile(struct zip *z, int file_index, const Path &outFile size_t readSize = std::min(blockSize, size - pos); zip_int64_t retval = zip_fread(zf, buffer, readSize); if (retval < 0 || (size_t)retval < readSize) { - ERROR_LOG(HLE, "Failed to read %d bytes from zip (%d) - archive corrupt?", (int)readSize, (int)retval); + ERROR_LOG(Log::HLE, "Failed to read %d bytes from zip (%d) - archive corrupt?", (int)readSize, (int)retval); delete[] buffer; fclose(f); zip_fclose(zf); @@ -522,7 +680,7 @@ bool GameManager::ExtractFile(struct zip *z, int file_index, const Path &outFile } size_t written = fwrite(buffer, 1, readSize, f); if (written != readSize) { - ERROR_LOG(HLE, "Wrote %d bytes out of %d - Disk full?", (int)written, (int)readSize); + ERROR_LOG(Log::HLE, "Wrote %d bytes out of %d - Disk full?", (int)written, (int)readSize); delete[] buffer; fclose(f); zip_fclose(zf); @@ -534,19 +692,26 @@ bool GameManager::ExtractFile(struct zip *z, int file_index, const Path &outFile *bytesCopied += readSize; installProgress_ = (float)*bytesCopied / (float)allBytes; } + zip_fclose(zf); fclose(f); + + // Copy the mtime, too. May not be possible on Android? + if (zstat.mtime) { + File::ChangeMTime(outFilename, zstat.mtime); + } delete[] buffer; return true; } else { auto iz = GetI18NCategory(I18NCat::INSTALLZIP); - g_OSD.Show(OSDType::MESSAGE_ERROR, iz->T("Installation failed")); - ERROR_LOG(HLE, "Failed to open file for writing: %s", outFilename.c_str()); + g_OSD.Show(OSDType::MESSAGE_ERROR, iz->T("Installation failed"), outFilename.ToVisualString()); + ERROR_LOG(Log::HLE, "Failed to open file for writing: %s", outFilename.c_str()); return false; } } -bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const Path &dest, const ZipFileInfo &info, bool allowRoot, bool deleteAfter) { +// Doesn't care what it is, just extracts the whole ZIP to the requested location. +bool GameManager::ExtractZipContents(struct zip *z, const Path &dest, const ZipFileInfo &info, bool allowRoot) { size_t allBytes = 0; size_t bytesCopied = 0; @@ -581,7 +746,7 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const Path outFilename = dest / zippedName.substr(info.stripChars); bool isDir = zippedName.empty() || zippedName.back() == '/'; - if (!isDir && zippedName.find("/") != std::string::npos) { + if (!isDir && zippedName.find('/') != std::string::npos) { outFilename = dest / zippedName.substr(0, zippedName.rfind('/')); } else if (!isDir) { outFilename = dest; @@ -601,6 +766,8 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, info.numFiles, (i + 1) * 0.1f, 0.1f); } + INFO_LOG(Log::HLE, "Created %d directories", (int)createdDirs.size()); + // Now, loop through again in a second pass, writing files. std::vector createdFiles; for (int i = 0; i < info.numFiles; i++) { @@ -616,7 +783,7 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const continue; if (!ExtractFile(z, i, outFilename, &bytesCopied, allBytes)) { - ERROR_LOG(HLE, "Bailing: Failed to extract file: %s -> %s", zippedName.c_str(), outFilename.c_str()); + ERROR_LOG(Log::HLE, "Bailing: Failed to extract file: %s -> %s", zippedName.c_str(), outFilename.c_str()); goto bail; } else { createdFiles.push_back(outFilename); @@ -625,17 +792,9 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 1.0f, 0.1f + (i + 1) / (float)info.numFiles * 0.9f, 0.1f); } - INFO_LOG(HLE, "Unzipped %d files (%d bytes / %d).", info.numFiles, (int)bytesCopied, (int)allBytes); + INFO_LOG(Log::HLE, "Unzipped %d files (%d bytes / %d).", info.numFiles, (int)bytesCopied, (int)allBytes); zip_close(z); z = nullptr; - installProgress_ = 1.0f; - if (deleteAfter) { - INFO_LOG(HLE, "Deleting '%s' after extraction", zipfile.c_str()); - File::Delete(zipfile); - } - InstallDone(); - ResetInstallError(); - g_OSD.RemoveProgressBar("install", true, 0.5f); return true; bail: @@ -649,11 +808,10 @@ bail: File::DeleteDir(iter); } SetInstallError(sy->T("Storage full")); - g_OSD.RemoveProgressBar("install", false, 0.5f); return false; } -bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const Path &dest, const ZipFileInfo &info, bool deleteAfter) { +bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const Path &dest, const ZipFileInfo &info) { size_t allBytes = 0; size_t bytesCopied = 0; @@ -703,16 +861,13 @@ bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const P } installProgress_ = 1.0f; - if (deleteAfter) { - File::Delete(zipfile); - } InstallDone(); ResetInstallError(); g_OSD.RemoveProgressBar("install", true, 0.5f); return true; } -bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter) { +bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &destDir) { // Let's place the output file in the currently selected Games directory. std::string fn = zip_get_name(z, isoFileIndex, 0); size_t nameOffset = fn.rfind('/'); @@ -727,20 +882,30 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path & allBytes += zstat.size; } - Path outputISOFilename = Path(g_Config.currentDirectory) / fn.substr(nameOffset); + std::string name = fn.substr(nameOffset); + + INFO_LOG(Log::IO, "Name in zip: %s size: %d", name.c_str(), (int)zstat.size); + + if (startsWith(name, "._")) { + // Not sure why Apple seems to add this when zipping file? + name = name.substr(2); + } + + Path outputISOFilename = destDir; + if (outputISOFilename.empty()) { + outputISOFilename = Path(g_Config.currentDirectory); + } + outputISOFilename = outputISOFilename / name; + size_t bytesCopied = 0; bool success = false; auto di = GetI18NCategory(I18NCat::DIALOG); g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f); if (ExtractFile(z, isoFileIndex, outputISOFilename, &bytesCopied, allBytes)) { - INFO_LOG(IO, "Successfully unzipped ISO file to '%s'", outputISOFilename.c_str()); + INFO_LOG(Log::IO, "Successfully unzipped ISO file to '%s'", outputISOFilename.c_str()); success = true; } zip_close(z); - if (success && deleteAfter) { - File::Delete(zipfile); - g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f); - } g_OSD.RemoveProgressBar("install", success, 0.5f); z = 0; @@ -750,17 +915,18 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path & return true; } -bool GameManager::InstallGameOnThread(const Path &url, const Path &fileName, bool deleteAfter) { +bool GameManager::InstallZipOnThread(ZipFileTask task) { if (InstallInProgress() || installDonePending_) { return false; } - installThread_ = std::thread(std::bind(&GameManager::InstallGame, this, url, fileName, deleteAfter)); + + installThread_ = std::thread(std::bind(&GameManager::InstallZipContents, this, task)); return true; } bool GameManager::UninstallGameOnThread(const std::string &name) { if (name.empty()) { - ERROR_LOG(HLE, "Cannot uninstall an empty-named game"); + ERROR_LOG(Log::HLE, "Cannot uninstall an empty-named game"); return false; } if (InstallInProgress() || installDonePending_ || curDownload_.get() != nullptr) { @@ -770,25 +936,6 @@ bool GameManager::UninstallGameOnThread(const std::string &name) { return true; } -bool GameManager::InstallRawISO(const Path &file, const std::string &originalName, bool deleteAfter) { - Path destPath = Path(g_Config.currentDirectory) / originalName; - auto di = GetI18NCategory(I18NCat::DIALOG); - g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f); - // TODO: To save disk space, we should probably attempt a move first. - if (File::Copy(file, destPath)) { - if (deleteAfter) { - File::Delete(file); - } - g_OSD.RemoveProgressBar("install", true, 0.5f); - } else { - g_OSD.RemoveProgressBar("install", false, 0.5f); - } - installProgress_ = 1.0f; - InstallDone(); - ResetInstallError(); - return true; -} - void GameManager::ResetInstallError() { if (!InstallInProgress()) { installError_.clear(); diff --git a/Core/Util/GameManager.h b/Core/Util/GameManager.h index 8ac0c6d028..27d7422d2b 100644 --- a/Core/Util/GameManager.h +++ b/Core/Util/GameManager.h @@ -24,6 +24,7 @@ #include #include +#include #include "Common/Net/HTTPClient.h" #include "Common/File/Path.h" @@ -34,6 +35,39 @@ enum class GameManagerState { INSTALLING, }; +enum class ZipFileContents { + UNKNOWN, + PSP_GAME_DIR, + ISO_FILE, + TEXTURE_PACK, + SAVE_DATA, +}; + +struct ZipFileInfo { + ZipFileContents contents; + int numFiles; + int stripChars; // for PSP game - how much to strip from the path. + int isoFileIndex; // for ISO + int textureIniIndex; // for textures + bool ignoreMetaFiles; + std::string gameTitle; // from PARAM.SFO if available + std::string savedataTitle; + std::string savedataDetails; + std::string savedataDir; + std::string mTime; + s64 totalFileSize; + + std::string contentName; +}; + +struct ZipFileTask { + std::optional zipFileInfo; + Path url; // Same as filename if installing from disk. Probably not really useful. + Path fileName; + Path destination; // If set, will override the default destination. + bool deleteAfter; +}; + struct zip; class FileLoader; struct ZipFileInfo; @@ -74,16 +108,17 @@ public: } // Only returns false if there's already an installation in progress. - bool InstallGameOnThread(const Path &url, const Path &tempFileName, bool deleteAfter); + bool InstallZipOnThread(ZipFileTask task); + + // Separate kind of functionality from InstallZipOnThread, so doesn't re-use the task struct. bool UninstallGameOnThread(const std::string &name); private: - // TODO: The return value on this is a bit pointless, we can't get at it. - bool InstallGame(const Path &url, const Path &tempFileName, bool deleteAfter); - bool InstallMemstickGame(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info, bool allowRoot, bool deleteAfter); - bool InstallMemstickZip(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info, bool deleteAfter); - bool InstallZippedISO(struct zip *z, int isoFileIndex, const Path &zipfile, bool deleteAfter); - bool InstallRawISO(const Path &zipFile, const std::string &originalName, bool deleteAfter); + void InstallZipContents(ZipFileTask task); + + bool ExtractZipContents(struct zip *z, const Path &dest, const ZipFileInfo &info, bool allowRoot); + bool InstallMemstickZip(struct zip *z, const Path &zipFile, const Path &dest, const ZipFileInfo &info); + bool InstallZippedISO(struct zip *z, int isoFileIndex, const Path &destDir); void UninstallGame(const std::string &name); void InstallDone(); @@ -109,20 +144,11 @@ private: extern GameManager g_GameManager; -enum class ZipFileContents { - UNKNOWN, - PSP_GAME_DIR, - ISO_FILE, - TEXTURE_PACK, -}; +struct zip *ZipOpenPath(Path fileName); +void ZipClose(zip *z); -struct ZipFileInfo { - int numFiles; - int stripChars; // for PSP game - int isoFileIndex; // for ISO - int textureIniIndex; // for textures - bool ignoreMetaFiles; -}; +void DetectZipFileContents(struct zip *z, ZipFileInfo *info); +bool DetectZipFileContents(const Path &fileName, ZipFileInfo *info); -ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info); -ZipFileContents DetectZipFileContents(const Path &fileName, ZipFileInfo *info); +bool ZipExtractFileToMemory(struct zip *z, int fileIndex, std::string *data); +bool CanExtractWithoutOverwrite(struct zip *z, const Path &destination, int maxOkFiles); diff --git a/Core/Util/MemStick.cpp b/Core/Util/MemStick.cpp index ceca99e9e3..511caabfde 100644 --- a/Core/Util/MemStick.cpp +++ b/Core/Util/MemStick.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "Common/File/Path.h" #include "Common/File/FileUtil.h" #include "Common/File/DirListing.h" @@ -47,7 +50,7 @@ bool SwitchMemstickFolderTo(Path newMemstickFolder) { std::string str = newMemstickFolder.ToString(); if (!File::WriteDataToFile(true, str.c_str(), str.size(), memStickDirFile)) { - ERROR_LOG(SYSTEM, "Failed to write memstick path '%s' to '%s'", newMemstickFolder.c_str(), memStickDirFile.c_str()); + ERROR_LOG(Log::System, "Failed to write memstick path '%s' to '%s'", newMemstickFolder.c_str(), memStickDirFile.c_str()); // Not sure what to do if this file can't be written. Disk full? } @@ -85,7 +88,7 @@ static bool ListFileSuffixesRecursively(const Path &root, const Path &folder, st progressReporter.SetProgress(file.name, fileSuffixes.size(), (size_t)-1); } } else { - ERROR_LOG_REPORT(SYSTEM, "Failed to compute PathTo from '%s' to '%s'", root.c_str(), folder.c_str()); + ERROR_LOG_REPORT(Log::System, "Failed to compute PathTo from '%s' to '%s'", root.c_str(), folder.c_str()); } } else { std::string fileSuffix; @@ -112,7 +115,7 @@ bool MoveChildrenFast(const Path &moveSrc, const Path &moveDest, MoveProgressRep Path fileSrc = file.fullName; Path fileDest = moveDest / file.name; progressReporter.SetProgress(file.name, i, files.size()); - INFO_LOG(SYSTEM, "About to move PSP data from '%s' to '%s'", fileSrc.c_str(), fileDest.c_str()); + INFO_LOG(Log::System, "About to move PSP data from '%s' to '%s'", fileSrc.c_str(), fileDest.c_str()); bool result = File::MoveIfFast(fileSrc, fileDest); if (!result) { // TODO: Should we try to move back anything that succeeded before this one? @@ -147,12 +150,12 @@ MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressR File::CreateDir(moveDest); } - INFO_LOG(SYSTEM, "About to move PSP data from '%s' to '%s'", moveSrc.c_str(), moveDest.c_str()); + INFO_LOG(Log::System, "About to move PSP data from '%s' to '%s'", moveSrc.c_str(), moveDest.c_str()); // First, we try the cheapest and safest way to move: Can we move files directly within the same device? // We loop through the files/dirs in the source directory and just try to move them, it should work. if (MoveChildrenFast(moveSrc, moveDest, progressReporter)) { - INFO_LOG(SYSTEM, "Quick-move succeeded"); + INFO_LOG(Log::System, "Quick-move succeeded"); progressReporter.SetProgress(ms->T("Done!")); return new MoveResult{ true, "" @@ -171,14 +174,14 @@ MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressR if (!ListFileSuffixesRecursively(moveSrc, moveSrc, directorySuffixesToCreate, fileSuffixesToMove, progressReporter)) { // TODO: Handle failure listing files. std::string error = "Failed to read old directory"; - INFO_LOG(SYSTEM, "%s", error.c_str()); + INFO_LOG(Log::System, "%s", error.c_str()); progressReporter.SetProgress(ms->T(error.c_str())); return new MoveResult{ false, error }; } bool dryRun = false; // Useful for debugging. - size_t failedFiles = 0; + size_t failedFileCount = 0; // We're not moving huge files like ISOs during this process, unless // they can be directly moved, without rewriting the file. @@ -196,9 +199,9 @@ MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressR const auto &dirSuffix = directorySuffixesToCreate[i]; Path dir = moveDest / dirSuffix; if (dryRun) { - INFO_LOG(SYSTEM, "dry run: Would have created dir '%s'", dir.c_str()); + INFO_LOG(Log::System, "dry run: Would have created dir '%s'", dir.c_str()); } else { - INFO_LOG(SYSTEM, "Creating dir '%s'", dir.c_str()); + INFO_LOG(Log::System, "Creating dir '%s'", dir.c_str()); progressReporter.SetProgress(dirSuffix); // Just ignore already-exists errors. File::CreateDir(dir); @@ -214,30 +217,37 @@ MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressR Path to = moveDest / fileSuffix.suffix; if (dryRun) { - INFO_LOG(SYSTEM, "dry run: Would have moved '%s' to '%s' (%d bytes)", from.c_str(), to.c_str(), (int)fileSuffix.fileSize); + INFO_LOG(Log::System, "dry run: Would have moved '%s' to '%s' (%d bytes)", from.c_str(), to.c_str(), (int)fileSuffix.fileSize); } else { // Remove the "from" prefix from the path. // We have to drop down to string operations for this. + if (File::Exists(to)) { + WARN_LOG(Log::System, "Target file '%s' already exists. Will be overwritten", to.c_str()); + } + if (!File::Copy(from, to)) { - ERROR_LOG(SYSTEM, "Failed to copy file '%s' to '%s'", from.c_str(), to.c_str()); - failedFiles++; + ERROR_LOG(Log::System, "Failed to copy file '%s' to '%s'", from.c_str(), to.c_str()); + failedFileCount++; // Should probably just bail? } else { - INFO_LOG(SYSTEM, "Copied file '%s' to '%s'", from.c_str(), to.c_str()); + INFO_LOG(Log::System, "Copied file '%s' to '%s' (size: %d)", from.c_str(), to.c_str(), (int)fileSuffix.fileSize); } } } - if (failedFiles) { - return new MoveResult{ false, "", failedFiles }; + if (failedFileCount) { + ERROR_LOG(Log::System, "Copy failed (%d files failed)", (int)failedFileCount); + return new MoveResult{ false, "", failedFileCount }; } + INFO_LOG(Log::System, "Done copying. Moving to verification."); + // After the whole move, verify that all the files arrived correctly. // If there's a single error, we do not delete the source data. bool ok = true; for (size_t i = 0; i < fileSuffixesToMove.size(); i++) { const auto &fileSuffix = fileSuffixesToMove[i]; - progressReporter.SetProgress(ms->T("Checking..."), (int)i, (int)fileSuffixesToMove.size()); + progressReporter.SetProgress(ms->T("Checking..."), i, fileSuffixesToMove.size()); Path to = moveDest / fileSuffix.suffix; @@ -247,29 +257,39 @@ MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressR break; } - if (fileSuffix.fileSize != info.size) { - ERROR_LOG(SYSTEM, "Mismatched size in target file %s. Verification failed.", fileSuffix.suffix.c_str()); + if (!info.exists) { + ERROR_LOG(Log::System, "File '%s' missing at target location '%s'.", fileSuffix.suffix.c_str(), to.c_str()); ok = false; - failedFiles++; + failedFileCount++; + break; + } + + // More lenient handling for .nomedia files. + if (fileSuffix.fileSize != info.size && !endsWithNoCase(fileSuffix.suffix, ".nomedia")) { + ERROR_LOG(Log::System, "Mismatched size in target file %s (expected %d, was %d bytes). Verification failed.", fileSuffix.suffix.c_str(), (int)fileSuffix.fileSize, (int)info.size); + ok = false; + failedFileCount++; break; } } if (!ok) { - return new MoveResult{ false, "", failedFiles }; + return new MoveResult{ false, "", failedFileCount }; } - INFO_LOG(SYSTEM, "Verification complete"); + INFO_LOG(Log::System, "Verification complete"); // Delete all the old, now hopefully empty, directories. // Hopefully DeleteDir actually fails if it contains a file... + // Reverse the order to delete subfolders before parents. + std::reverse(directorySuffixesToCreate.begin(), directorySuffixesToCreate.end()); for (size_t i = 0; i < directorySuffixesToCreate.size(); i++) { const auto &dirSuffix = directorySuffixesToCreate[i]; Path dir = moveSrc / dirSuffix; if (dryRun) { - INFO_LOG(SYSTEM, "dry run: Would have deleted dir '%s'", dir.c_str()); + INFO_LOG(Log::System, "dry run: Would have deleted dir '%s'", dir.c_str()); } else { - INFO_LOG(SYSTEM, "Deleting dir '%s'", dir.c_str()); + INFO_LOG(Log::System, "Deleting dir '%s'", dir.c_str()); progressReporter.SetProgress(dirSuffix, i, directorySuffixesToCreate.size()); if (File::Exists(dir)) { File::DeleteDir(dir); diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index bfc2ee64e7..b206d5e6c0 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -126,10 +126,13 @@ struct PPGeTextDrawerCacheKey { int align; float wrapWidth; }; + struct PPGeTextDrawerImage { + PPGeTextDrawerImage() : entry(0) {} TextStringEntry entry; u32 ptr; }; + static std::map textDrawerImages; void PPGeSetDrawContext(Draw::DrawContext *draw) { @@ -249,7 +252,7 @@ void __PPGeInit() { bool loadedZIM = !skipZIM && LoadZIM("ppge_atlas.zim", width, height, &flags, imageData); if (!skipZIM && !loadedZIM) { - ERROR_LOG(SCEGE, "Failed to load ppge_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory.\n\nPPGe stuff will not be drawn."); + ERROR_LOG(Log::sceGe, "Failed to load ppge_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory.\n\nPPGe stuff will not be drawn."); } if (loadedZIM) { @@ -306,7 +309,7 @@ void __PPGeInit() { atlasRequiresReset = false; - INFO_LOG(SCEGE, "PPGe drawing library initialized. DL: %08x Data: %08x Atlas: %08x (%i) Args: %08x", + INFO_LOG(Log::sceGe, "PPGe drawing library initialized. DL: %08x Data: %08x Atlas: %08x (%i) Args: %08x", dlPtr, dataPtr, atlasPtr, atlasSize, listArgs.ptr); } @@ -467,7 +470,7 @@ void PPGeEnd() gpu->EnableInterrupts(false); NotifyMemInfo(MemBlockFlags::WRITE, dlPtr, dlWritePtr - dlPtr, "PPGe ListCmds"); u32 list = sceGeListEnQueue(dlPtr, dlWritePtr, -1, listArgs.ptr); - DEBUG_LOG(SCEGE, "PPGe enqueued display list %i", list); + DEBUG_LOG(Log::sceGe, "PPGe enqueued display list %i", list); gpu->EnableInterrupts(true); } } @@ -785,7 +788,7 @@ void PPGeMeasureText(float *w, float *h, std::string_view text, float scale, int if (WrapType & PPGE_LINE_USE_ELLIPSIS) dtalign |= FLAG_ELLIPSIZE_TEXT; Bounds b(0, 0, wrapWidth <= 0 ? 480.0f : wrapWidth, 272.0f); - textDrawer->MeasureStringRect(s2.c_str(), s2.size(), b, &mw, &mh, dtalign); + textDrawer->MeasureStringRect(s2, b, &mw, &mh, dtalign); if (w) *w = mw; @@ -914,7 +917,7 @@ static PPGeTextDrawerImage PPGeGetTextImage(const char *text, const PPGeStyle &s textDrawer->SetFontScale(style.scale, style.scale); Bounds b(0, 0, maxWidth, 272.0f); std::string cleaned = ReplaceAll(text, "\r", ""); - textDrawer->DrawStringBitmapRect(bitmapData, im.entry, Draw::DataFormat::R8_UNORM, cleaned.c_str(), b, tdalign); + textDrawer->DrawStringBitmapRect(bitmapData, im.entry, Draw::DataFormat::R8_UNORM, cleaned.c_str(), b, tdalign, false); int bufwBytes = ((im.entry.bmWidth + 31) / 32) * 16; u32 sz = bufwBytes * (im.entry.bmHeight + 1); @@ -1119,15 +1122,15 @@ void PPGeDrawTextWrapped(std::string_view text, float x, float y, float wrapWidt Bounds b(0, 0, wrapWidth <= 0 ? 480.0f - x : wrapWidth, wrapHeight); int tdalign = 0; textDrawer->SetFontScale(style.scale, style.scale); - textDrawer->MeasureStringRect(s2.c_str(), s2.size(), b, &actualWidth, &actualHeight, tdalign | FLAG_WRAP_TEXT); + textDrawer->MeasureStringRect(s2, b, &actualWidth, &actualHeight, tdalign | FLAG_WRAP_TEXT); // Check if we need to scale the text down to fit better. PPGeStyle adjustedStyle = style; if (wrapHeight != 0.0f && actualHeight > wrapHeight) { // Cheap way to get the line height. float oneLine, twoLines; - textDrawer->MeasureString("|", 1, &actualWidth, &oneLine); - textDrawer->MeasureStringRect("|\n|", 3, Bounds(0, 0, 480, 272), &actualWidth, &twoLines); + textDrawer->MeasureString("|", &actualWidth, &oneLine); + textDrawer->MeasureStringRect("|\n|", Bounds(0, 0, 480, 272), &actualWidth, &twoLines); float lineHeight = twoLines - oneLine; if (actualHeight > wrapHeight * maxScaleDown) { @@ -1370,7 +1373,7 @@ bool PPGeImage::Load() { } else { std::vector pngData; if (pspFileSystem.ReadEntireFile(filename_, pngData) < 0) { - WARN_LOG(SCEGE, "PPGeImage cannot load file %s", filename_.c_str()); + WARN_LOG(Log::sceGe, "PPGeImage cannot load file %s", filename_.c_str()); loadFailed_ = true; return false; } @@ -1378,7 +1381,7 @@ bool PPGeImage::Load() { success = pngLoadPtr((const unsigned char *)&pngData[0], pngData.size(), &width_, &height_, &textureData); } if (!success) { - WARN_LOG(SCEGE, "Bad PPGeImage - not a valid png"); + WARN_LOG(Log::sceGe, "Bad PPGeImage - not a valid png"); loadFailed_ = true; return false; } @@ -1388,7 +1391,7 @@ bool PPGeImage::Load() { texture_ = __PPGeDoAlloc(texSize, true, "Savedata Icon"); if (texture_ == 0) { free(textureData); - WARN_LOG(SCEGE, "Bad PPGeImage - unable to allocate space for texture"); + WARN_LOG(Log::sceGe, "Bad PPGeImage - unable to allocate space for texture"); // Don't set loadFailed_ here, we'll try again if there's more memory later. return false; } diff --git a/Core/Util/PortManager.cpp b/Core/Util/PortManager.cpp index cfb81e9dbd..d3221242a8 100644 --- a/Core/Util/PortManager.cpp +++ b/Core/Util/PortManager.cpp @@ -66,7 +66,7 @@ void PortManager::Shutdown() { } void PortManager::Terminate() { - VERBOSE_LOG(SCENET, "PortManager::Terminate()"); + VERBOSE_LOG(Log::sceNet, "PortManager::Terminate()"); if (urls) { #ifdef WITH_UPNP FreeUPNPUrls(urls); @@ -100,9 +100,9 @@ bool PortManager::Initialize(const unsigned int timeout) { unsigned char ttl = 2; // defaulting to 2 int error = 0; - VERBOSE_LOG(SCENET, "PortManager::Initialize(%d)", timeout); + VERBOSE_LOG(Log::sceNet, "PortManager::Initialize(%d)", timeout); if (!g_Config.bEnableUPnP) { - ERROR_LOG(SCENET, "PortManager::Initialize - UPnP is Disabled on Networking Settings"); + ERROR_LOG(Log::sceNet, "PortManager::Initialize - UPnP is Disabled on Networking Settings"); return false; } @@ -110,12 +110,12 @@ bool PortManager::Initialize(const unsigned int timeout) { switch (m_InitState) { case UPNP_INITSTATE_BUSY: { - WARN_LOG(SCENET, "PortManager - Initialization already in progress"); + WARN_LOG(Log::sceNet, "PortManager - Initialization already in progress"); return false; } // Should we redetect UPnP? just in case the player switched to a different network in the middle case UPNP_INITSTATE_DONE: { - WARN_LOG(SCENET, "PortManager - Already Initialized"); + WARN_LOG(Log::sceNet, "PortManager - Already Initialized"); return true; } default: @@ -149,7 +149,7 @@ bool PortManager::Initialize(const unsigned int timeout) { if (!dev) dev = devlist; // defaulting to first device - INFO_LOG(SCENET, "PortManager - UPnP device: [desc: %s] [st: %s]", dev->descURL, dev->st); + INFO_LOG(Log::sceNet, "PortManager - UPnP device: [desc: %s] [st: %s]", dev->descURL, dev->st); descXML = (char*)miniwget(dev->descURL, &descXMLsize, dev->scope_id, &descXMLstatus); if (descXML) @@ -161,17 +161,29 @@ bool PortManager::Initialize(const unsigned int timeout) { // Get LAN IP address that connects to the router char lanaddr[64] = "unset"; - int status = UPNP_GetValidIGD(devlist, urls, datas, lanaddr, sizeof(lanaddr)); //possible "status" values, 0 = NO IGD found, 1 = A valid connected IGD has been found, 2 = A valid IGD has been found but it reported as not connected, 3 = an UPnP device has been found but was not recognized as an IGD + + // possible "status" values: + // -1 = Internal error + // 0 = NO IGD found + // 1 = A valid connected IGD has been found + // 2 = A valid connected IGD has been found but its IP address is reserved (non routable) + // 3 = A valid IGD has been found but it reported as not connected + // 4 = an UPnP device has been found but was not recognized as an IGD +#if (MINIUPNPC_API_VERSION >= 18) + int status = UPNP_GetValidIGD(devlist, urls, datas, lanaddr, sizeof(lanaddr), nullptr, 0); +#else + int status = UPNP_GetValidIGD(devlist, urls, datas, lanaddr, sizeof(lanaddr)); +#endif m_lanip = std::string(lanaddr); - INFO_LOG(SCENET, "PortManager - Detected LAN IP: %s", m_lanip.c_str()); + INFO_LOG(Log::sceNet, "PortManager - Detected LAN IP: %s (status=%d)", m_lanip.c_str(), status); // Additional Info char connectionType[64] = ""; if (UPNP_GetConnectionTypeInfo(urls->controlURL, datas->first.servicetype, connectionType) != UPNPCOMMAND_SUCCESS) { - WARN_LOG(SCENET, "PortManager - GetConnectionTypeInfo failed"); + WARN_LOG(Log::sceNet, "PortManager - GetConnectionTypeInfo failed"); } else { - INFO_LOG(SCENET, "PortManager - Connection Type: %s", connectionType); + INFO_LOG(Log::sceNet, "PortManager - Connection Type: %s", connectionType); } // Using Game ID & Player Name as default description for mapping @@ -186,7 +198,7 @@ bool PortManager::Initialize(const unsigned int timeout) { return true; } - ERROR_LOG(SCENET, "PortManager - upnpDiscover failed (error: %i) or No UPnP device detected", error); + ERROR_LOG(Log::sceNet, "PortManager - upnpDiscover failed (error: %i) or No UPnP device detected", error); if (g_Config.bEnableUPnP) { auto n = GetI18NCategory(I18NCat::NETWORKING); g_OSD.Show(OSDType::MESSAGE_ERROR, n->T("Unable to find UPnP device")); @@ -209,11 +221,11 @@ bool PortManager::Add(const char* protocol, unsigned short port, unsigned short if (intport == 0) intport = port; - INFO_LOG(SCENET, "PortManager::Add(%s, %d, %d)", protocol, port, intport); + INFO_LOG(Log::sceNet, "PortManager::Add(%s, %d, %d)", protocol, port, intport); if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') { if (g_Config.bEnableUPnP) { - WARN_LOG(SCENET, "PortManager::Add - the init was not done !"); + WARN_LOG(Log::sceNet, "PortManager::Add - the init was not done !"); g_OSD.Show(OSDType::MESSAGE_INFO, n->T("UPnP need to be reinitialized")); } Terminate(); @@ -241,7 +253,7 @@ bool PortManager::Add(const char* protocol, unsigned short port, unsigned short } if (r != 0) { - ERROR_LOG(SCENET, "PortManager - AddPortMapping failed (error: %i)", r); + ERROR_LOG(Log::sceNet, "PortManager - AddPortMapping failed (error: %i)", r); if (r == UPNPCOMMAND_HTTP_ERROR) { if (g_Config.bEnableUPnP) { g_OSD.Show(OSDType::MESSAGE_INFO, n->T("UPnP need to be reinitialized")); @@ -265,11 +277,11 @@ bool PortManager::Remove(const char* protocol, unsigned short port) { char port_str[16]; auto n = GetI18NCategory(I18NCat::NETWORKING); - INFO_LOG(SCENET, "PortManager::Remove(%s, %d)", protocol, port); + INFO_LOG(Log::sceNet, "PortManager::Remove(%s, %d)", protocol, port); if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') { if (g_Config.bEnableUPnP) { - WARN_LOG(SCENET, "PortManager::Remove - the init was not done !"); + WARN_LOG(Log::sceNet, "PortManager::Remove - the init was not done !"); g_OSD.Show(OSDType::MESSAGE_INFO, n->T("UPnP need to be reinitialized")); } Terminate(); @@ -279,7 +291,7 @@ bool PortManager::Remove(const char* protocol, unsigned short port) { int r = UPNP_DeletePortMapping(urls->controlURL, datas->first.servicetype, port_str, protocol, NULL); if (r != 0) { - ERROR_LOG(SCENET, "PortManager - DeletePortMapping failed (error: %i)", r); + ERROR_LOG(Log::sceNet, "PortManager - DeletePortMapping failed (error: %i)", r); if (r == UPNPCOMMAND_HTTP_ERROR) { if (g_Config.bEnableUPnP) { g_OSD.Show(OSDType::MESSAGE_INFO, n->T("UPnP need to be reinitialized")); @@ -300,10 +312,10 @@ bool PortManager::Remove(const char* protocol, unsigned short port) { bool PortManager::Restore() { #ifdef WITH_UPNP int r; - VERBOSE_LOG(SCENET, "PortManager::Restore()"); + VERBOSE_LOG(Log::sceNet, "PortManager::Restore()"); if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') { - if (g_Config.bEnableUPnP) WARN_LOG(SCENET, "PortManager::Remove - the init was not done !"); + if (g_Config.bEnableUPnP) WARN_LOG(Log::sceNet, "PortManager::Remove - the init was not done !"); return false; } for (auto it = m_otherPortList.begin(); it != m_otherPortList.end(); ++it) { @@ -319,7 +331,7 @@ bool PortManager::Restore() { m_portList.erase(el_it); } else { - ERROR_LOG(SCENET, "PortManager::Restore - DeletePortMapping failed (error: %i)", r); + ERROR_LOG(Log::sceNet, "PortManager::Restore - DeletePortMapping failed (error: %i)", r); if (r == UPNPCOMMAND_HTTP_ERROR) return false; // Might be better not to exit here, but exiting a loop will avoid long timeouts in the case the router is no longer reachable } @@ -331,7 +343,7 @@ bool PortManager::Restore() { it->taken = false; } else { - ERROR_LOG(SCENET, "PortManager::Restore - AddPortMapping failed (error: %i)", r); + ERROR_LOG(Log::sceNet, "PortManager::Restore - AddPortMapping failed (error: %i)", r); if (r == UPNPCOMMAND_HTTP_ERROR) return false; // Might be better not to exit here, but exiting a loop will avoid long timeouts in the case the router is no longer reachable } @@ -357,10 +369,10 @@ bool PortManager::Clear() { char rHost[64]; char duration[16]; - VERBOSE_LOG(SCENET, "PortManager::Clear()"); + VERBOSE_LOG(Log::sceNet, "PortManager::Clear()"); if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') { - if (g_Config.bEnableUPnP) WARN_LOG(SCENET, "PortManager::Clear - the init was not done !"); + if (g_Config.bEnableUPnP) WARN_LOG(Log::sceNet, "PortManager::Clear - the init was not done !"); return false; } //unsigned int num = 0; @@ -382,7 +394,7 @@ bool PortManager::Clear() { int r2 = UPNP_DeletePortMapping(urls->controlURL, datas->first.servicetype, extPort, protocol, rHost); if (r2 != 0) { - ERROR_LOG(SCENET, "PortManager::Clear - DeletePortMapping(%s, %s) failed (error: %i)", extPort, protocol, r2); + ERROR_LOG(Log::sceNet, "PortManager::Clear - DeletePortMapping(%s, %s) failed (error: %i)", extPort, protocol, r2); if (r2 == UPNPCOMMAND_HTTP_ERROR) return false; } @@ -415,10 +427,10 @@ bool PortManager::RefreshPortList() { char rHost[64]; char duration[16]; - INFO_LOG(SCENET, "PortManager::RefreshPortList()"); + INFO_LOG(Log::sceNet, "PortManager::RefreshPortList()"); if (urls == NULL || urls->controlURL == NULL || urls->controlURL[0] == '\0') { - if (g_Config.bEnableUPnP) WARN_LOG(SCENET, "PortManager::RefreshPortList - the init was not done !"); + if (g_Config.bEnableUPnP) WARN_LOG(Log::sceNet, "PortManager::RefreshPortList - the init was not done !"); return false; } m_portList.clear(); @@ -461,7 +473,7 @@ bool PortManager::RefreshPortList() { int upnpService(const unsigned int timeout) { SetCurrentThreadName("UPnPService"); - INFO_LOG(SCENET, "UPnPService: Begin of UPnPService Thread"); + INFO_LOG(Log::sceNet, "UPnPService: Begin of UPnPService Thread"); // Service Loop while (upnpServiceRunning && coreState != CORE_POWERDOWN) { @@ -509,7 +521,7 @@ int upnpService(const unsigned int timeout) upnpReqs.clear(); upnpLock.unlock(); - INFO_LOG(SCENET, "UPnPService: End of UPnPService Thread"); + INFO_LOG(Log::sceNet, "UPnPService: End of UPnPService Thread"); return 0; } diff --git a/Core/Util/PortManager.h b/Core/Util/PortManager.h index e5d778283f..039d1ea52d 100644 --- a/Core/Util/PortManager.h +++ b/Core/Util/PortManager.h @@ -22,16 +22,16 @@ #pragma once #ifdef USE_SYSTEM_MINIUPNPC -#include -#include -#include +#include +#include +#include #else #ifndef MINIUPNP_STATICLIB #define MINIUPNP_STATICLIB #endif -#include "ext/miniupnp/miniupnpc/miniwget.h" -#include "ext/miniupnp/miniupnpc/miniupnpc.h" -#include "ext/miniupnp/miniupnpc/upnpcommands.h" +#include "ext/miniupnp/miniupnpc/include/miniwget.h" +#include "ext/miniupnp/miniupnpc/include/miniupnpc.h" +#include "ext/miniupnp/miniupnpc/include/upnpcommands.h" #endif #include diff --git a/Core/Util/VulkanEmuThread.cpp b/Core/Util/VulkanEmuThread.cpp new file mode 100644 index 0000000000..798e45af51 --- /dev/null +++ b/Core/Util/VulkanEmuThread.cpp @@ -0,0 +1,2 @@ +#include "Core/Util/VulkanEmuThread.h" + diff --git a/Core/WaveFile.cpp b/Core/WaveFile.cpp index 551d33bd36..44ce0fa421 100644 --- a/Core/WaveFile.cpp +++ b/Core/WaveFile.cpp @@ -19,13 +19,13 @@ bool WaveFileWriter::Start(const Path &filename, unsigned int HLESampleRate) { // Check if the file is already open if (file) { - ERROR_LOG(SYSTEM, "The file %s was already open, the file header will not be written.", filename.c_str()); + ERROR_LOG(Log::System, "The file %s was already open, the file header will not be written.", filename.c_str()); return false; } file.Open(filename, "wb"); if (!file) { - ERROR_LOG(IO, "The file %s could not be opened for writing. Please check if it's already opened by another program.", filename.c_str()); + ERROR_LOG(Log::IO, "The file %s could not be opened for writing. Please check if it's already opened by another program.", filename.c_str()); return false; } diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp index e7a80ae486..1aa5a23d96 100644 --- a/Core/WebServer.cpp +++ b/Core/WebServer.cpp @@ -332,7 +332,7 @@ static bool ServeDebuggerFile(const http::ServerRequest &request) { mimeType = "text/css"; } - request.WriteHttpResponseHeader("1.0", 200, (int)size, mimeType); + request.WriteHttpResponseHeader("1.0", 200, size, mimeType); request.Out()->Push((char *)data, size); delete[] data; @@ -341,7 +341,7 @@ static bool ServeDebuggerFile(const http::ServerRequest &request) { static void RedirectToDebugger(const http::ServerRequest &request) { static const std::string payload = "Redirecting to debugger UI...\r\n"; - request.WriteHttpResponseHeader("1.0", 301, (int)payload.size(), "text/plain", "Location: /debugger/index.html\r\n"); + request.WriteHttpResponseHeader("1.0", 301, payload.size(), "text/plain", "Location: /debugger/index.html\r\n"); request.Out()->Push(payload); } @@ -353,7 +353,7 @@ static void HandleFallback(const http::ServerRequest &request) { if (serverFlags & (int)WebServerFlags::DISCS) { std::string resource = request.resource(); Path localPath = LocalFromRemotePath(resource); - INFO_LOG(LOADER, "Serving %s from %s", resource.c_str(), localPath.c_str()); + INFO_LOG(Log::Loader, "Serving %s from %s", resource.c_str(), localPath.c_str()); if (!localPath.empty()) { if (File::IsDirectory(localPath)) { HandleListing(request); @@ -375,7 +375,7 @@ static void HandleFallback(const http::ServerRequest &request) { } static const std::string payload = "404 not found\r\n"; - request.WriteHttpResponseHeader("1.0", 404, (int)payload.size(), "text/plain"); + request.WriteHttpResponseHeader("1.0", 404, payload.size(), "text/plain"); request.Out()->Push(payload); } @@ -415,7 +415,7 @@ static void ExecuteWebServer() { if (!http->Listen(g_Config.iRemoteISOPort)) { if (!http->Listen(0)) { - ERROR_LOG(FILESYS, "Unable to listen on any port"); + ERROR_LOG(Log::FileSystem, "Unable to listen on any port"); UpdateStatus(ServerStatus::FINISHED); return; } diff --git a/Dockerfile b/Dockerfile index 0d4ae5bc07..7cacfbeb3f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,17 +4,7 @@ FROM alpine:latest COPY . /src -RUN apk add build-base wget git bash cmake python3 glu-dev - -# Installing SDL2 from source because current SDL2 package in alpine -# has some tricks that make PPSSPP compilation to fail -ENV SDL_VERSION=2.0.20 -RUN wget https://github.com/libsdl-org/SDL/archive/refs/tags/release-${SDL_VERSION}.tar.gz && \ - tar -xf release-${SDL_VERSION}.tar.gz && cd SDL-release-${SDL_VERSION} && mkdir build && cd build && \ - cmake -DCMAKE_BUILD_TYPE=Release .. && \ - make -j$(getconf _NPROCESSORS_ONLN) clean && \ - make -j$(getconf _NPROCESSORS_ONLN) && \ - make -j$(getconf _NPROCESSORS_ONLN) install +RUN apk add build-base wget git bash cmake python3 glu-dev sdl2-dev RUN cd src/ffmpeg && ./linux_x86-64.sh RUN cd src && ./b.sh --headless diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index bb78b80875..b8162d26f9 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -313,7 +313,7 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config) { // index_multiplier -= 0.01f / texturePixels; if (!formatOK) { - ERROR_LOG_REPORT_ONCE(depal, G3D, "%s depal unsupported: shift=%d mask=%02x offset=%d", GeBufferFormatToString(config.bufferFormat), shift, mask, config.startPos); + ERROR_LOG_REPORT_ONCE(depal, Log::G3D, "%s depal unsupported: shift=%d mask=%02x offset=%d", GeBufferFormatToString(config.bufferFormat), shift, mask, config.startPos); } // Offset by half a texel (plus clutBase) to turn NEAREST filtering into FLOOR. diff --git a/GPU/Common/DepthBufferCommon.cpp b/GPU/Common/DepthBufferCommon.cpp index ebc936c10a..0de297f743 100644 --- a/GPU/Common/DepthBufferCommon.cpp +++ b/GPU/Common/DepthBufferCommon.cpp @@ -166,7 +166,7 @@ bool FramebufferManagerCommon::ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x using namespace Draw; if (!fbo) { - ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackDepthbufferSync: bad fbo"); + ERROR_LOG_REPORT_ONCE(vfbfbozero, Log::sceGe, "ReadbackDepthbufferSync: bad fbo"); return false; } // Old desktop GL can download depth, but not upload. diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 77ef5d5dd9..b517850ee3 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -170,10 +170,10 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex // TODO: Handle fog and secondary color somehow? if (gstate.isFogEnabled() && !gstate.isModeThrough()) { - WARN_LOG_REPORT_ONCE(geimmfog, G3D, "Imm vertex used fog"); + WARN_LOG_REPORT_ONCE(geimmfog, Log::G3D, "Imm vertex used fog"); } if (color1Used != 0 && gstate.isUsingSecondaryColor() && !gstate.isModeThrough()) { - WARN_LOG_REPORT_ONCE(geimmcolor1, G3D, "Imm vertex used secondary color"); + WARN_LOG_REPORT_ONCE(geimmcolor1, Log::G3D, "Imm vertex used secondary color"); } bool prevThrough = gstate.isModeThrough(); @@ -595,11 +595,11 @@ bool DrawEngineCommon::GetCurrentSimpleVertices(int count, std::vectorfb_format != format) { - WARN_LOG_ONCE(resolvevfb, G3D, "ResolveVFB: Resolving from %s to %s at %08x/%d", GeBufferFormatToString(newest->fb_format), GeBufferFormatToString(format), addr, stride); + WARN_LOG_ONCE(resolvevfb, Log::G3D, "ResolveVFB: Resolving from %s to %s at %08x/%d", GeBufferFormatToString(newest->fb_format), GeBufferFormatToString(format), addr, stride); return ResolveFramebufferColorToFormat(newest, format); } @@ -313,7 +313,7 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, int fb_stride } } - DEBUG_LOG(G3D, "Est: %08x V: %ix%i, R: %ix%i, S: %ix%i, STR: %i, THR:%i, Z:%08x = %ix%i %s", fb_address, viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough(), gstate.isDepthWriteEnabled() ? gstate.getDepthBufAddress() : 0, drawing_width, drawing_height, margin ? " (margin!)" : ""); + DEBUG_LOG(Log::G3D, "Est: %08x V: %ix%i, R: %ix%i, S: %ix%i, STR: %i, THR:%i, Z:%08x = %ix%i %s", fb_address, viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough(), gstate.isDepthWriteEnabled() ? gstate.getDepthBufAddress() : 0, drawing_width, drawing_height, margin ? " (margin!)" : ""); } void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPUgstate &gstate) { @@ -370,7 +370,7 @@ void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPU params->scissorBottom = gstate.getScissorY2() + 1; if (gstate.getRegionRateX() != 0x100 || gstate.getRegionRateY() != 0x100) { - WARN_LOG_REPORT_ONCE(regionRate, G3D, "Drawing region rate add non-zero: %04x, %04x of %04x, %04x", gstate.getRegionRateX(), gstate.getRegionRateY(), gstate.getRegionX2(), gstate.getRegionY2()); + WARN_LOG_REPORT_ONCE(regionRate, Log::G3D, "Drawing region rate add non-zero: %04x, %04x of %04x, %04x", gstate.getRegionRateX(), gstate.getRegionRateY(), gstate.getRegionX2(), gstate.getRegionY2()); } } @@ -390,7 +390,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer if (params.fb_address == params.z_address) { // Most likely Z will not be used in this pass, as that would wreak havoc (undefined behavior for sure) // We probably don't need to do anything about that, but let's log it. - WARN_LOG_ONCE(color_equal_z, G3D, "Framebuffer bound with color addr == z addr, likely will not use Z in this pass: %08x", params.fb_address); + WARN_LOG_ONCE(color_equal_z, Log::G3D, "Framebuffer bound with color addr == z addr, likely will not use Z in this pass: %08x", params.fb_address); } // Compatibility hack for Killzone, see issue #6207. @@ -421,7 +421,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer const int x_offset = (params.fb_address - v->fb_address) / bpp; if (x_offset < params.fb_stride && v->height >= drawing_height) { // Pretty certainly a pure render-to-X-offset. - WARN_LOG_REPORT_ONCE(renderoffset, HLE, "Rendering to framebuffer offset at %08x +%dx%d (stride %d)", v->fb_address, x_offset, 0, v->fb_stride); + WARN_LOG_REPORT_ONCE(renderoffset, Log::FrameBuf, "Rendering to framebuffer offset at %08x +%dx%d (stride %d)", v->fb_address, x_offset, 0, v->fb_stride); normal_vfb = v; gstate_c.SetCurRTOffset(x_offset, 0); normal_vfb->width = std::max((int)normal_vfb->width, x_offset + drawing_width); @@ -446,7 +446,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer // These are prioritized over normal VFBs matches, to ensure things work even if the higher-address one // is created first. Only enabled under compat flag. vfb = large_offset_vfb; - WARN_LOG_REPORT_ONCE(tokimeki, FRAMEBUF, "Detected FBO at Y offset %d of %08x: %08x", y_offset, large_offset_vfb->fb_address, params.fb_address); + WARN_LOG_REPORT_ONCE(tokimeki, Log::FrameBuf, "Detected FBO at Y offset %d of %08x: %08x", y_offset, large_offset_vfb->fb_address, params.fb_address); gstate_c.SetCurRTOffset(0, y_offset); vfb->height = std::max((int)vfb->height, y_offset + drawing_height); drawing_height += y_offset; @@ -552,7 +552,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer CopyToColorFromOverlappingFramebuffers(vfb); SetColorUpdated(vfb, skipDrawReason); - INFO_LOG(FRAMEBUF, "Creating FBO for %08x (z: %08x) : %d x %d x %s", vfb->fb_address, vfb->z_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->fb_format)); + INFO_LOG(Log::FrameBuf, "Creating FBO for %08x (z: %08x) : %d x %d x %s", vfb->fb_address, vfb->z_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->fb_format)); vfb->last_frame_render = gpuStats.numFlips; frameLastFramebufUsed_ = gpuStats.numFlips; @@ -572,7 +572,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer // We already have it! } else if (vfb != currentRenderVfb_) { // Use it as a render target. - DEBUG_LOG(FRAMEBUF, "Switching render target to FBO for %08x: %d x %d x %d ", vfb->fb_address, vfb->width, vfb->height, vfb->fb_format); + DEBUG_LOG(Log::FrameBuf, "Switching render target to FBO for %08x: %d x %d x %d ", vfb->fb_address, vfb->width, vfb->height, vfb->fb_format); vfb->usageFlags |= FB_USAGE_RENDER_COLOR; vfb->last_frame_render = gpuStats.numFlips; frameLastFramebufUsed_ = gpuStats.numFlips; @@ -622,11 +622,11 @@ void FramebufferManagerCommon::SetDepthFrameBuffer(bool isClearingDepth) { if (currentRenderVfb_->z_address != boundDepthBuffer || currentRenderVfb_->z_stride != boundDepthStride) { if (currentRenderVfb_->fb_address == boundDepthBuffer) { // Disallow setting depth buffer to the same address as the color buffer, usually means it's not used. - WARN_LOG_N_TIMES(z_reassign, 5, G3D, "Ignoring color matching depth buffer at %08x", boundDepthBuffer); + WARN_LOG_N_TIMES(z_reassign, 5, Log::FrameBuf, "Ignoring color matching depth buffer at %08x", boundDepthBuffer); boundDepthBuffer = 0; boundDepthStride = 0; } - WARN_LOG_N_TIMES(z_reassign, 5, G3D, "Framebuffer at %08x/%d has switched associated depth buffer from %08x to %08x, updating.", + WARN_LOG_N_TIMES(z_reassign, 5, Log::FrameBuf, "Framebuffer at %08x/%d has switched associated depth buffer from %08x to %08x, updating.", currentRenderVfb_->fb_address, currentRenderVfb_->fb_stride, currentRenderVfb_->z_address, boundDepthBuffer); // Technically, here we should copy away the depth buffer to another framebuffer that uses that z_address, or maybe @@ -717,7 +717,7 @@ void FramebufferManagerCommon::CopyToDepthFromOverlappingFramebuffers(VirtualFra } else if (source.channel == RASTER_COLOR && draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { VirtualFramebuffer *src = source.vfb; if (src->fb_format != GE_FORMAT_565) { - WARN_LOG_ONCE(not565, G3D, "fb_format of buffer at %08x not 565 as expected", src->fb_address); + WARN_LOG_ONCE(not565, Log::FrameBuf, "fb_format of buffer at %08x not 565 as expected", src->fb_address); } // Really hate to do this, but tracking the depth swizzle state across multiple @@ -880,11 +880,11 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra pass_name = "copy_color"; } else { if (PSP_CoreParameter().compat.flags().BlueToAlpha) { - WARN_LOG_ONCE(bta, G3D, "WARNING: Reinterpret encountered with BlueToAlpha on"); + WARN_LOG_ONCE(bta, Log::FrameBuf, "WARNING: Reinterpret encountered with BlueToAlpha on"); } // Reinterpret! - WARN_LOG_N_TIMES(reint, 5, G3D, "Reinterpret detected from %08x_%s to %08x_%s", + WARN_LOG_N_TIMES(reint, 5, Log::FrameBuf, "Reinterpret detected from %08x_%s to %08x_%s", src->fb_address, GeBufferFormatToString(src->fb_format), dst->fb_address, GeBufferFormatToString(dst->fb_format)); @@ -1047,7 +1047,7 @@ void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *v // Saving each frame would be slow. // TODO: This type of download could be made async, for less stutter on framebuffer creation. - if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO_SKIP && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { + if (GetSkipGPUReadbackMode() == SkipGPUReadbackMode::NO_SKIP && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight, RASTER_COLOR, Draw::ReadbackMode::BLOCK); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; vfb->safeWidth = 0; @@ -1063,7 +1063,7 @@ bool FramebufferManagerCommon::ShouldDownloadFramebufferColor(const VirtualFrame bool FramebufferManagerCommon::ShouldDownloadFramebufferDepth(const VirtualFramebuffer *vfb) { // Download depth buffer for Syphon Filter lens flares - if (!PSP_CoreParameter().compat.flags().ReadbackDepth || g_Config.iSkipGPUReadbackMode != (int)SkipGPUReadbackMode::NO_SKIP) { + if (!PSP_CoreParameter().compat.flags().ReadbackDepth || GetSkipGPUReadbackMode() != SkipGPUReadbackMode::NO_SKIP) { return false; } return (vfb->usageFlags & FB_USAGE_RENDER_DEPTH) != 0 && vfb->width >= 480 && vfb->height >= 272; @@ -1123,9 +1123,10 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe void FramebufferManagerCommon::PerformWriteFormattedFromMemory(u32 addr, int size, int stride, GEBufferFormat fmt) { // Note: UpdateFromMemory() is still called later. - // This is a special case where we have extra information prior to the invalidation. + // This is a special case where we have extra information prior to the invalidation, + // because it's called from sceJpeg, sceMpeg, scePsmf etc. - // TODO: Could possibly be an offset... + // TODO: Could possibly be at an offset... // Also, stride needs better handling. VirtualFramebuffer *vfb = ResolveVFB(addr, stride, fmt); if (vfb) { @@ -1134,7 +1135,7 @@ void FramebufferManagerCommon::PerformWriteFormattedFromMemory(u32 addr, int siz vfb->colorBindSeq = GetBindSeqCount(); if (vfb->fb_stride < stride) { - DEBUG_LOG(ME, "Changing stride for %08x from %d to %d", addr, vfb->fb_stride, stride); + INFO_LOG(Log::FrameBuf, "Changing stride for %08x from %d to %d", addr, vfb->fb_stride, stride); const int bpp = BufferFormatBytesPerPixel(fmt); ResizeFramebufFBO(vfb, stride, size / (bpp * stride)); // Resizing may change the viewport/etc. @@ -1174,7 +1175,7 @@ void FramebufferManagerCommon::UpdateFromMemory(u32 addr, int size) { DrawPixels(vfb, 0, 0, Memory::GetPointerUnchecked(addr), fmt, vfb->fb_stride, vfb->width, vfb->height, RASTER_COLOR, "UpdateFromMemory_DrawPixels"); SetColorUpdated(vfb, gstate_c.skipDrawReason); } else { - INFO_LOG(FRAMEBUF, "Invalidating FBO for %08x (%dx%d %s)", vfb->fb_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->fb_format)); + INFO_LOG(Log::FrameBuf, "Invalidating FBO for %08x (%dx%d %s)", vfb->fb_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->fb_format)); DestroyFramebuf(vfb); vfbs_.erase(vfbs_.begin() + i--); } @@ -1255,7 +1256,7 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF // Currently rendering to this framebuffer. Need to make a copy. if (!skipCopy && framebuffer == currentRenderVfb_) { // Self-texturing, need a copy currently (some backends can potentially support it though). - WARN_LOG_ONCE(selfTextureCopy, G3D, "Attempting to texture from current render target (src=%08x / target=%08x / flags=%d), making a copy", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); + WARN_LOG_ONCE(selfTextureCopy, Log::G3D, "Attempting to texture from current render target (src=%08x / target=%08x / flags=%d), making a copy", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); // TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size. if (currentFramebufferCopy_ && (flags & BINDFBCOLOR_UNCACHED) == 0) { // We have a copy already that hasn't been invalidated, let's keep using it. @@ -1289,7 +1290,7 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF return true; } else { // Here it's an error because for some reason skipCopy is true. That shouldn't really happen. - ERROR_LOG_REPORT_ONCE(selfTextureFail, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); + ERROR_LOG_REPORT_ONCE(selfTextureFail, Log::G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); // To do this safely in Vulkan, we need to use input attachments. // Actually if the texture region and render regions don't overlap, this is safe, but we need // to transition to GENERAL image layout which will take some trickery. @@ -1499,11 +1500,11 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G // better be fast. So does God of War, a lot of the time, a bit unclear what it's doing. Draw::Texture *tex = draw_->CreateTexture(desc); if (!tex) { - ERROR_LOG(G3D, "Failed to create DrawPixels texture"); + ERROR_LOG(Log::G3D, "Failed to create DrawPixels texture"); } // We don't need to count here, already counted by numUploads by the caller. - // INFO_LOG(G3D, "Creating drawPixelsCache texture: %dx%d", tex->Width(), tex->Height()); + // INFO_LOG(Log::G3D, "Creating drawPixelsCache texture: %dx%d", tex->Width(), tex->Height()); DrawPixelsEntry entry{ tex, imageHash, frameNumber }; drawPixelsCache_.push_back(entry); @@ -1554,9 +1555,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { if (displayFramebufPtr_ == 0) { if (GetUIState() != UISTATE_PAUSEMENU) { if (Core_IsStepping()) - VERBOSE_LOG(FRAMEBUF, "Display disabled, displaying only black"); + VERBOSE_LOG(Log::FrameBuf, "Display disabled, displaying only black"); else - DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); + DEBUG_LOG(Log::FrameBuf, "Display disabled, displaying only black"); } // No framebuffer to display! Clear to black. if (useBufferedRendering_) { @@ -1609,7 +1610,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { if (vfb) { // Okay, we found one above. // Log should be "Displaying from framebuf" but not worth changing the report. - INFO_LOG_REPORT_ONCE(displayoffset, FRAMEBUF, "Rendering from framebuf with offset %08x -> %08x+%dx%d", addr, vfb->fb_address, offsetX, offsetY); + INFO_LOG_REPORT_ONCE(displayoffset, Log::FrameBuf, "Rendering from framebuf with offset %08x -> %08x+%dx%d", addr, vfb->fb_address, offsetX, offsetY); } } @@ -1624,7 +1625,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { DrawFramebufferToOutput(Memory::GetPointerUnchecked(fbaddr), displayStride_, displayFormat_); return; } else { - DEBUG_LOG(FRAMEBUF, "Found no FBO to display! displayFBPtr = %08x", fbaddr); + DEBUG_LOG(Log::FrameBuf, "Found no FBO to display! displayFBPtr = %08x", fbaddr); // No framebuffer to display! Clear to black. if (useBufferedRendering_) { // Bind and clear the backbuffer. This should be the first time during the frame that it's bound. @@ -1651,9 +1652,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { if (vfb->fbo) { if (GetUIState() != UISTATE_PAUSEMENU) { if (Core_IsStepping()) - VERBOSE_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); + VERBOSE_LOG(Log::FrameBuf, "Displaying FBO %08x", vfb->fb_address); else - DEBUG_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); + DEBUG_LOG(Log::FrameBuf, "Displaying FBO %08x", vfb->fb_address); } float u0 = offsetX / (float)vfb->bufferWidth; @@ -1663,13 +1664,13 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { //clip the VR framebuffer to keep the aspect ratio if (IsVREnabled() && !IsFlatVRGame() && !IsGameVRScene()) { - float aspect = 272.0f / 480.0f; + float aspect = 272.0f / 480.0f * (IsImmersiveVRMode() ? 2.0f : 1.0f); float clipY = 272.0f * (1.0f - aspect) / 2.0f; v0 = (clipY + offsetY) / (float)vfb->bufferHeight; v1 = (272.0f - clipY + offsetY) / (float)vfb->bufferHeight; //zoom inside - float zoom = 0.1f; + float zoom = IsImmersiveVRMode() ? 0.4f : 0.1f; u0 += zoom / aspect; u1 -= zoom / aspect; v0 += zoom; @@ -1694,7 +1695,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { presentation_->SourceFramebuffer(vfb->fbo, actualWidth, actualHeight); presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1); } else if (useBufferedRendering_) { - WARN_LOG(FRAMEBUF, "Current VFB lacks an FBO: %08x", vfb->fb_address); + WARN_LOG(Log::FrameBuf, "Current VFB lacks an FBO: %08x", vfb->fb_address); } // This may get called mid-draw if the game uses an immediate flip. @@ -1727,7 +1728,7 @@ void FramebufferManagerCommon::DecimateFBOs() { if (vfb != displayFramebuf_ && vfb != prevDisplayFramebuf_ && vfb != prevPrevDisplayFramebuf_) { if (age > FBO_OLD_AGE) { - INFO_LOG(FRAMEBUF, "Decimating FBO for %08x (%ix%i %s), age %i", vfb->fb_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->fb_format), age); + INFO_LOG(Log::FrameBuf, "Decimating FBO for %08x (%ix%i %s), age %i", vfb->fb_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->fb_format), age); DestroyFramebuf(vfb); vfbs_.erase(vfbs_.begin() + i--); } @@ -1749,7 +1750,7 @@ void FramebufferManagerCommon::DecimateFBOs() { VirtualFramebuffer *vfb = bvfbs_[i]; int age = frameLastFramebufUsed_ - vfb->last_frame_render; if (age > FBO_OLD_AGE) { - INFO_LOG(FRAMEBUF, "Decimating FBO for %08x (%dx%d %s), age %i", vfb->fb_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->fb_format), age); + INFO_LOG(Log::FrameBuf, "Decimating FBO for %08x (%dx%d %s), age %i", vfb->fb_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->fb_format), age); DestroyFramebuf(vfb); bvfbs_.erase(bvfbs_.begin() + i--); } @@ -1760,7 +1761,7 @@ void FramebufferManagerCommon::DecimateFBOs() { for (auto it = drawPixelsCache_.begin(); it != drawPixelsCache_.end(); ) { int age = draw_->GetFrameCount() - it->frameNumber; if (age > 10) { - // INFO_LOG(G3D, "Releasing drawPixelsCache texture: %dx%d", it->tex->Width(), it->tex->Height()); + // INFO_LOG(Log::G3D, "Releasing drawPixelsCache texture: %dx%d", it->tex->Width(), it->tex->Height()); it->tex->Release(); it->tex = nullptr; it = drawPixelsCache_.erase(it); @@ -1824,9 +1825,9 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, bool creating = old.bufferWidth == 0; if (creating) { - WARN_LOG(FRAMEBUF, "Creating %s FBO at %08x/%08x stride=%d %dx%d (force=%d)", GeBufferFormatToString(vfb->fb_format), vfb->fb_address, vfb->z_address, vfb->fb_stride, vfb->bufferWidth, vfb->bufferHeight, (int)force); + WARN_LOG(Log::FrameBuf, "Creating %s FBO at %08x/%08x stride=%d %dx%d (force=%d)", GeBufferFormatToString(vfb->fb_format), vfb->fb_address, vfb->z_address, vfb->fb_stride, vfb->bufferWidth, vfb->bufferHeight, (int)force); } else { - WARN_LOG(FRAMEBUF, "Resizing %s FBO at %08x/%08x stride=%d from %dx%d to %dx%d (force=%d, skipCopy=%d)", GeBufferFormatToString(vfb->fb_format), vfb->fb_address, vfb->z_address, vfb->fb_stride, old.bufferWidth, old.bufferHeight, vfb->bufferWidth, vfb->bufferHeight, (int)force, (int)skipCopy); + WARN_LOG(Log::FrameBuf, "Resizing %s FBO at %08x/%08x stride=%d from %dx%d to %dx%d (force=%d, skipCopy=%d)", GeBufferFormatToString(vfb->fb_format), vfb->fb_address, vfb->z_address, vfb->fb_stride, old.bufferWidth, old.bufferHeight, vfb->bufferWidth, vfb->bufferHeight, (int)force, (int)skipCopy); } // During hardware rendering, we always render at full color depth even if the game wouldn't on real hardware. @@ -1861,7 +1862,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, NotifyMemInfo(MemBlockFlags::ALLOC, vfb->z_address, vfb->z_stride * vfb->height * sizeof(uint16_t), buf, len); } if (old.fbo) { - INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->fb_format)); + INFO_LOG(Log::FrameBuf, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->fb_format)); if (vfb->fbo) { draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); if (!skipCopy) { @@ -1880,7 +1881,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, currentRenderVfb_ = vfb; if (!vfb->fbo) { - ERROR_LOG(FRAMEBUF, "Error creating FBO during resize! %dx%d", vfb->renderWidth, vfb->renderHeight); + ERROR_LOG(Log::FrameBuf, "Error creating FBO during resize! %dx%d", vfb->renderWidth, vfb->renderHeight); vfb->last_frame_failed = gpuStats.numFlips; } } @@ -1986,7 +1987,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, // Not likely to be a correct color format copy for this buffer. Ignore it, there will either be RAM // that can be displayed from, or another matching buffer with the right format if rendering is going on. // If we had scoring here, we should strongly penalize this target instead of ignoring it. - WARN_LOG_N_TIMES(notify_copy_2x, 5, G3D, "Framebuffer size %08x conspicuously not matching copy size %08x for source in NotifyFramebufferCopy. Ignoring.", size, vfb_size); + WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::FrameBuf, "Framebuffer size %08x conspicuously not matching copy size %08x for source in NotifyFramebufferCopy. Ignoring.", size, vfb_size); continue; } @@ -1994,7 +1995,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, // Seems likely we are looking at a potential copy of 32-bit pixels (like video) to an old 16-bit buffer, // which is very likely simply the wrong target, so skip it. See issue #17740 where this happens in Naruto Ultimate Ninja Heroes 2. // Probably no point to give it a bad score and let it pass to sorting, as we're pretty sure here. - WARN_LOG_N_TIMES(notify_copy_2x, 5, G3D, "Framebuffer size %08x too small for %08x bytes of data and also 16-bit (%s), and not rendered to this frame. Ignoring.", vfb_size, size, GeBufferFormatToString(vfb->fb_format)); + WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::FrameBuf, "Framebuffer size %08x too small for %08x bytes of data and also 16-bit (%s), and not rendered to this frame. Ignoring.", vfb_size, size, GeBufferFormatToString(vfb->fb_format)); continue; } @@ -2034,7 +2035,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, // Not likely to be a correct color format copy for this buffer. Ignore it, there will either be RAM // that can be displayed from, or another matching buffer with the right format if rendering is going on. // If we had scoring here, we should strongly penalize this target instead of ignoring it. - WARN_LOG_N_TIMES(notify_copy_2x, 5, G3D, "Framebuffer size %08x conspicuously not matching copy size %08x for dest in NotifyFramebufferCopy. Ignoring.", size, vfb_size); + WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::FrameBuf, "Framebuffer size %08x conspicuously not matching copy size %08x for dest in NotifyFramebufferCopy. Ignoring.", size, vfb_size); continue; } @@ -2095,7 +2096,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, log += "\n"; } } - WARN_LOG(G3D, "Copy: Multiple src vfb candidates for (src: %08x, size: %d):\n%s (%s)", src, size, log.c_str(), RasterChannelToString(channel)); + WARN_LOG(Log::FrameBuf, "Copy: Multiple src vfb candidates for (src: %08x, size: %d):\n%s (%s)", src, size, log.c_str(), RasterChannelToString(channel)); } } @@ -2110,7 +2111,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, log += "\n"; } } - WARN_LOG(G3D, "Copy: Multiple dst vfb candidates for (dst: %08x, size: %d):\n%s (%s)", src, size, log.c_str(), RasterChannelToString(channel)); + WARN_LOG(Log::FrameBuf, "Copy: Multiple dst vfb candidates for (dst: %08x, size: %d):\n%s (%s)", src, size, log.c_str(), RasterChannelToString(channel)); } } @@ -2124,7 +2125,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, if (!dstBuffer && srcBuffer && channel != RASTER_DEPTH) { // Note - if we're here, we're in a memcpy, not a block transfer. Not allowing IntraVRAMBlockTransferAllowCreateFB. // Technically, that makes BlockTransferAllowCreateFB a bit of a misnomer. - bool allowCreateFB = (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB || g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::COPY_TO_TEXTURE); + bool allowCreateFB = (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB || GetSkipGPUReadbackMode() == SkipGPUReadbackMode::COPY_TO_TEXTURE); if (allowCreateFB && !(flags & GPUCopyFlag::DISALLOW_CREATE_VFB)) { dstBuffer = CreateRAMFramebuffer(dst, srcBuffer->width, srcBuffer->height, srcBuffer->fb_stride, srcBuffer->fb_format); dstY = 0; @@ -2140,9 +2141,9 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, if (dstBuffer && srcBuffer) { if (srcBuffer == dstBuffer) { - WARN_LOG_ONCE(dstsrccpy, G3D, "Intra-buffer memcpy (not supported) %08x -> %08x (size: %x)", src, dst, size); + WARN_LOG_ONCE(dstsrccpy, Log::FrameBuf, "Intra-buffer memcpy (not supported) %08x -> %08x (size: %x)", src, dst, size); } else { - WARN_LOG_ONCE(dstnotsrccpy, G3D, "Inter-buffer memcpy %08x -> %08x (size: %x)", src, dst, size); + WARN_LOG_ONCE(dstnotsrccpy, Log::FrameBuf, "Inter-buffer memcpy %08x -> %08x (size: %x)", src, dst, size); // Just do the blit! BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0, channel, "Blit_InterBufferMemcpy"); SetColorUpdated(dstBuffer, skipDrawReason); @@ -2153,7 +2154,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, if (flags & GPUCopyFlag::MEMSET) { gpuStats.numClears++; } - WARN_LOG_N_TIMES(btucpy, 5, G3D, "Memcpy fbo upload %08x -> %08x (size: %x)", src, dst, size); + WARN_LOG_N_TIMES(btucpy, 5, Log::FrameBuf, "Memcpy fbo upload %08x -> %08x (size: %x)", src, dst, size); FlushBeforeCopy(); // TODO: Hot Shots Golf makes a lot of these during the "meter", to copy back the image to the screen, it copies line by line. @@ -2168,13 +2169,13 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, // This is a memcpy, let's still copy just in case. return false; } else if (srcBuffer) { - WARN_LOG_N_TIMES(btdcpy, 5, G3D, "Memcpy fbo download %08x -> %08x", src, dst); + WARN_LOG_N_TIMES(btdcpy, 5, Log::FrameBuf, "Memcpy fbo download %08x -> %08x", src, dst); FlushBeforeCopy(); // TODO: In Hot Shots Golf, check if we can do a readback to a framebuffer here. // Again we have the problem though that it's doing a lot of small copies here, one for each line. if (srcH == 0 || srcY + srcH > srcBuffer->bufferHeight) { - WARN_LOG_ONCE(btdcpyheight, G3D, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight); - } else if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO_SKIP && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { + WARN_LOG_ONCE(btdcpyheight, Log::FrameBuf, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight); + } else if (GetSkipGPUReadbackMode() == SkipGPUReadbackMode::NO_SKIP && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { Draw::ReadbackMode readbackMode = Draw::ReadbackMode::BLOCK; if (PSP_CoreParameter().compat.flags().AllowDelayedReadbacks) { readbackMode = Draw::ReadbackMode::OLD_DATA_OK; @@ -2203,7 +2204,7 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p rect->vfb = nullptr; if (!stride_pixels) { - WARN_LOG(G3D, "Zero stride in FindTransferFrameBuffer, ignoring"); + WARN_LOG(Log::FrameBuf, "Zero stride in FindTransferFrameBuffer, ignoring"); return false; } @@ -2226,7 +2227,7 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p // and also #17878 where a game does ram->buffer to an auto-swizzling (|0x600000) address, // to initialize Z with a pre-rendered depth buffer. if (vfb->z_address == basePtr && vfb->BufferByteStride(RASTER_DEPTH) == byteStride && PSP_CoreParameter().compat.flags().BlockTransferDepth) { - WARN_LOG_N_TIMES(z_xfer, 5, G3D, "FindTransferFramebuffer: found matching depth buffer, %08x (dest=%d, bpp=%d)", basePtr, (int)destination, bpp); + WARN_LOG_N_TIMES(z_xfer, 5, Log::FrameBuf, "FindTransferFramebuffer: found matching depth buffer, %08x (dest=%d, bpp=%d)", basePtr, (int)destination, bpp); candidate.channel = RASTER_DEPTH; candidate.x_bytes = x_pixels * bpp; candidate.w_bytes = w_pixels * bpp; @@ -2336,7 +2337,7 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p for (size_t i = 0; i < candidates.size(); i++) { log += " - " + candidates[i].ToString() + "\n"; } - WARN_LOG(G3D, "Multiple framebuffer candidates for %08x/%d/%d %d,%d %dx%d (dest = %d):\n%s", basePtr, stride_pixels, bpp, x_pixels, y, w_pixels, h, (int)destination, log.c_str()); + WARN_LOG(Log::FrameBuf, "Multiple framebuffer candidates for %08x/%d/%d %d,%d %dx%d (dest = %d):\n%s", basePtr, stride_pixels, bpp, x_pixels, y, w_pixels, h, (int)destination, log.c_str()); } } @@ -2345,14 +2346,14 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p return true; } else { if (Memory::IsVRAMAddress(basePtr) && destination && h >= 128) { - WARN_LOG_N_TIMES(nocands, 5, G3D, "Didn't find a destination candidate for %08x/%d/%d %d,%d %dx%d", basePtr, stride_pixels, bpp, x_pixels, y, w_pixels, h); + WARN_LOG_N_TIMES(nocands, 5, Log::FrameBuf, "Didn't find a destination candidate for %08x/%d/%d %d,%d %dx%d", basePtr, stride_pixels, bpp, x_pixels, y, w_pixels, h); } return false; } } VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format) { - INFO_LOG(G3D, "Creating RAM framebuffer at %08x (%dx%d, stride %d, fb_format %d)", fbAddress, width, height, stride, format); + INFO_LOG(Log::FrameBuf, "Creating RAM framebuffer at %08x (%dx%d, stride %d, fb_format %d)", fbAddress, width, height, stride, format); RasterChannel channel = format == GE_FORMAT_DEPTH16 ? RASTER_DEPTH : RASTER_COLOR; @@ -2453,7 +2454,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram // We always create a color-only framebuffer here - readbacks of depth convert to color while translating the values. nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, 0, false, name }); if (!nvfb->fbo) { - ERROR_LOG(FRAMEBUF, "Error creating FBO! %d x %d", nvfb->renderWidth, nvfb->renderHeight); + ERROR_LOG(Log::FrameBuf, "Error creating FBO! %d x %d", nvfb->renderWidth, nvfb->renderHeight); delete nvfb; return nullptr; } @@ -2588,7 +2589,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst if (srcBuffer && !dstBuffer) { // In here, we can't read from dstRect. if (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB || - g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::COPY_TO_TEXTURE || + GetSkipGPUReadbackMode() == SkipGPUReadbackMode::COPY_TO_TEXTURE || (PSP_CoreParameter().compat.flags().IntraVRAMBlockTransferAllowCreateFB && Memory::IsVRAMAddress(srcRect.vfb->fb_address) && Memory::IsVRAMAddress(dstBasePtr))) { GEBufferFormat ramFormat; @@ -2642,12 +2643,12 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst int buffer_bpp = BufferFormatBytesPerPixel(srcRect.vfb->Format(srcRect.channel)); if (bpp != buffer_bpp) { - WARN_LOG_ONCE(intrabpp, G3D, "Mismatched transfer bpp in intra-buffer block transfer. Was %d, expected %d.", bpp, buffer_bpp); + WARN_LOG_ONCE(intrabpp, Log::G3D, "Mismatched transfer bpp in intra-buffer block transfer. Was %d, expected %d.", bpp, buffer_bpp); // We just switch to using the buffer's bpp, since we've already converted the rectangle to byte offsets. bpp = buffer_bpp; } - WARN_LOG_N_TIMES(dstsrc, 5, G3D, "Intra-buffer block transfer %dx%d %dbpp from %08x (x:%d y:%d stride:%d) -> %08x (x:%d y:%d stride:%d)", + WARN_LOG_N_TIMES(dstsrc, 5, Log::G3D, "Intra-buffer block transfer %dx%d %dbpp from %08x (x:%d y:%d stride:%d) -> %08x (x:%d y:%d stride:%d)", width, height, bpp, srcBasePtr, srcRect.x_bytes / bpp, srcRect.y, srcStride, dstBasePtr, dstRect.x_bytes / bpp, dstRect.y, dstStride); @@ -2661,7 +2662,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst // Straightforward blit between two same-format framebuffers. if (srcRect.vfb && srcRect.channel == dstRect.channel && srcRect.vfb->Format(srcRect.channel) == dstRect.vfb->Format(dstRect.channel)) { - WARN_LOG_N_TIMES(dstnotsrc, 5, G3D, "Inter-buffer %s block transfer %dx%d %dbpp from %08x (x:%d y:%d stride:%d %s) -> %08x (x:%d y:%d stride:%d %s)", + WARN_LOG_N_TIMES(dstnotsrc, 5, Log::G3D, "Inter-buffer %s block transfer %dx%d %dbpp from %08x (x:%d y:%d stride:%d %s) -> %08x (x:%d y:%d stride:%d %s)", RasterChannelToString(srcRect.channel), width, height, bpp, srcBasePtr, srcRect.x_bytes / bpp, srcRect.y, srcStride, GeBufferFormatToString(srcRect.vfb->fb_format), @@ -2670,7 +2671,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst // Straight blit will do, but check the bpp, we might need to convert coordinates differently. int buffer_bpp = BufferFormatBytesPerPixel(srcRect.vfb->Format(srcRect.channel)); if (bpp != buffer_bpp) { - WARN_LOG_ONCE(intrabpp, G3D, "Mismatched transfer bpp in inter-buffer block transfer. Was %d, expected %d.", bpp, buffer_bpp); + WARN_LOG_ONCE(intrabpp, Log::G3D, "Mismatched transfer bpp in inter-buffer block transfer. Was %d, expected %d.", bpp, buffer_bpp); // We just switch to using the buffer's bpp, since we've already converted the rectangle to byte offsets. bpp = buffer_bpp; } @@ -2682,7 +2683,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst } // Getting to the more complex cases. Have not actually seen much of these yet. - WARN_LOG_N_TIMES(blockformat, 5, G3D, "Mismatched buffer formats in block transfer: %s->%s (%dx%d)", + WARN_LOG_N_TIMES(blockformat, 5, Log::G3D, "Mismatched buffer formats in block transfer: %s->%s (%dx%d)", GeBufferFormatToString(srcRect.vfb->Format(srcRect.channel)), GeBufferFormatToString(dstRect.vfb->Format(dstRect.channel)), width, height); @@ -2695,7 +2696,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst // Handle depth uploads directly here, and let's not bother copying the data. This is compat-flag-gated for now, // may generalize it when I remove the compat flag. if (dstRect.channel == RASTER_DEPTH) { - WARN_LOG_ONCE(btud, G3D, "Block transfer upload %08x -> %08x (%dx%d %d,%d bpp=%d %s)", srcBasePtr, dstBasePtr, width, height, dstX, dstY, bpp, RasterChannelToString(dstRect.channel)); + WARN_LOG_ONCE(btud, Log::G3D, "Block transfer upload %08x -> %08x (%dx%d %d,%d bpp=%d %s)", srcBasePtr, dstBasePtr, width, height, dstX, dstY, bpp, RasterChannelToString(dstRect.channel)); FlushBeforeCopy(); const u8 *srcBase = Memory::GetPointerUnchecked(srcBasePtr) + (srcX + srcY * srcStride) * bpp; DrawPixels(dstRect.vfb, dstX, dstY, srcBase, dstRect.vfb->Format(dstRect.channel), srcStride * bpp / 2, (int)(dstRect.w_bytes / 2), dstRect.h, dstRect.channel, "BlockTransferCopy_DrawPixelsDepth"); @@ -2711,20 +2712,20 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst return false; } - WARN_LOG_N_TIMES(btd, 10, G3D, "Block transfer readback %dx%d %dbpp from %08x (x:%d y:%d stride:%d) -> %08x (x:%d y:%d stride:%d)", + WARN_LOG_N_TIMES(btd, 10, Log::G3D, "Block transfer readback %dx%d %dbpp from %08x (x:%d y:%d stride:%d) -> %08x (x:%d y:%d stride:%d)", width, height, bpp, srcBasePtr, srcRect.x_bytes / bpp, srcRect.y, srcStride, dstBasePtr, dstRect.x_bytes / bpp, dstRect.y, dstStride); FlushBeforeCopy(); - if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO_SKIP && !srcRect.vfb->memoryUpdated) { + if (GetSkipGPUReadbackMode() == SkipGPUReadbackMode::NO_SKIP && !srcRect.vfb->memoryUpdated) { const int srcBpp = BufferFormatBytesPerPixel(srcRect.vfb->fb_format); const float srcXFactor = (float)bpp / srcBpp; const bool tooTall = srcY + srcRect.h > srcRect.vfb->bufferHeight; if (srcRect.h <= 0 || (tooTall && srcY != 0)) { - WARN_LOG_ONCE(btdheight, G3D, "Block transfer download %08x -> %08x skipped, %d+%d is taller than %d", srcBasePtr, dstBasePtr, srcRect.y, srcRect.h, srcRect.vfb->bufferHeight); + WARN_LOG_ONCE(btdheight, Log::G3D, "Block transfer download %08x -> %08x skipped, %d+%d is taller than %d", srcBasePtr, dstBasePtr, srcRect.y, srcRect.h, srcRect.vfb->bufferHeight); } else { if (tooTall) { - WARN_LOG_ONCE(btdheight, G3D, "Block transfer download %08x -> %08x dangerous, %d+%d is taller than %d", srcBasePtr, dstBasePtr, srcRect.y, srcRect.h, srcRect.vfb->bufferHeight); + WARN_LOG_ONCE(btdheight, Log::G3D, "Block transfer download %08x -> %08x dangerous, %d+%d is taller than %d", srcBasePtr, dstBasePtr, srcRect.y, srcRect.h, srcRect.vfb->bufferHeight); } Draw::ReadbackMode readbackMode = Draw::ReadbackMode::BLOCK; if (PSP_CoreParameter().compat.flags().AllowDelayedReadbacks) { @@ -2740,6 +2741,14 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst } } +SkipGPUReadbackMode FramebufferManagerCommon::GetSkipGPUReadbackMode() { + if (PSP_CoreParameter().compat.flags().ForceEnableGPUReadback) { + return SkipGPUReadbackMode::NO_SKIP; + } else { + return (SkipGPUReadbackMode)g_Config.iSkipGPUReadbackMode; + } +} + void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int width, int height, int bpp, u32 skipDrawReason) { // If it's a block transfer direct to the screen, and we're not using buffers, draw immediately. // We may still do a partial block draw below if this doesn't pass. @@ -2770,7 +2779,7 @@ void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstS } if (dstBuffer && !srcBuffer) { - WARN_LOG_ONCE(btu, G3D, "Block transfer upload %08x -> %08x (%dx%d %d,%d bpp=%d)", srcBasePtr, dstBasePtr, width, height, dstX, dstY, bpp); + WARN_LOG_ONCE(btu, Log::G3D, "Block transfer upload %08x -> %08x (%dx%d %d,%d bpp=%d)", srcBasePtr, dstBasePtr, width, height, dstX, dstY, bpp); FlushBeforeCopy(); const u8 *srcBase = Memory::GetPointerUnchecked(srcBasePtr) + (srcX + srcY * srcStride) * bpp; @@ -2808,7 +2817,7 @@ void FramebufferManagerCommon::NotifyDisplayResized() { pixelHeight_ = PSP_CoreParameter().pixelHeight; presentation_->UpdateDisplaySize(pixelWidth_, pixelHeight_); - INFO_LOG(G3D, "FramebufferManagerCommon::NotifyDisplayResized: %dx%d", pixelWidth_, pixelHeight_); + INFO_LOG(Log::G3D, "FramebufferManagerCommon::NotifyDisplayResized: %dx%d", pixelWidth_, pixelHeight_); // No drawing is allowed here. This includes anything that might potentially touch a command buffer, like creating images! // So we need to defer the post processing initialization. @@ -2847,7 +2856,7 @@ void FramebufferManagerCommon::DestroyAllFBOs() { prevPrevDisplayFramebuf_ = nullptr; for (VirtualFramebuffer *vfb : vfbs_) { - INFO_LOG(FRAMEBUF, "Destroying FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->fb_format); + INFO_LOG(Log::FrameBuf, "Destroying FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->fb_format); DestroyFramebuf(vfb); } vfbs_.clear(); @@ -3076,15 +3085,22 @@ bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, G return retval; } -bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) { +bool GetOutputFramebuffer(Draw::DrawContext *draw, GPUDebugBuffer &buffer) { int w, h; - draw_->GetFramebufferDimensions(nullptr, &w, &h); - Draw::DataFormat fmt = draw_->PreferredFramebufferReadbackFormat(nullptr); + draw->GetFramebufferDimensions(nullptr, &w, &h); + Draw::DataFormat fmt = draw->PreferredFramebufferReadbackFormat(nullptr); // Ignore preferred formats other than BGRA. if (fmt != Draw::DataFormat::B8G8R8A8_UNORM) fmt = Draw::DataFormat::R8G8B8A8_UNORM; - buffer.Allocate(w, h, fmt == Draw::DataFormat::R8G8B8A8_UNORM ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_8888_BGRA, false); - bool retval = draw_->CopyFramebufferToMemory(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, fmt, buffer.GetData(), w, Draw::ReadbackMode::BLOCK, "GetOutputFramebuffer"); + + bool flipped = g_Config.iGPUBackend == (int)GPUBackend::OPENGL; + + buffer.Allocate(w, h, fmt == Draw::DataFormat::R8G8B8A8_UNORM ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_8888_BGRA, flipped); + return draw->CopyFramebufferToMemory(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, fmt, buffer.GetData(), w, Draw::ReadbackMode::BLOCK, "GetOutputFramebuffer"); +} + +bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) { + bool retval = ::GetOutputFramebuffer(draw_, buffer); // That may have unbound the framebuffer, rebind to avoid crashes when debugging. RebindFramebuffer("RebindFramebuffer - GetOutputFramebuffer"); return retval; @@ -3098,7 +3114,7 @@ bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) { // can't entirely be rid of the CPU path.) -- unknown void FramebufferManagerCommon::ReadbackFramebuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode) { if (w <= 0 || h <= 0) { - ERROR_LOG(G3D, "Bad inputs to ReadbackFramebufferSync: %d %d %d %d", x, y, w, h); + ERROR_LOG(Log::FrameBuf, "Bad inputs to ReadbackFramebufferSync: %d %d %d %d", x, y, w, h); return; } @@ -3126,7 +3142,7 @@ void FramebufferManagerCommon::ReadbackFramebuffer(VirtualFramebuffer *vfb, int const int dstSize = ((h - 1) * stride + w) * dstBpp; if (!Memory::IsValidRange(fb_address + dstByteOffset, dstSize)) { - ERROR_LOG_REPORT(G3D, "ReadbackFramebufferSync would write outside of memory, ignoring"); + ERROR_LOG_REPORT(Log::G3D, "ReadbackFramebufferSync would write outside of memory, ignoring"); return; } @@ -3134,7 +3150,7 @@ void FramebufferManagerCommon::ReadbackFramebuffer(VirtualFramebuffer *vfb, int // We always need to convert from the framebuffer native format. // Right now that's always 8888. - DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x, ptr=%p", fb_address, destPtr); + DEBUG_LOG(Log::FrameBuf, "Reading framebuffer to mem, fb_address = %08x, ptr=%p", fb_address, destPtr); if (channel == RASTER_DEPTH) { _assert_msg_(vfb && vfb->z_address != 0 && vfb->z_stride != 0, "Depth buffer invalid"); @@ -3265,8 +3281,8 @@ void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { if (currentRenderVfb_ && currentRenderVfb_->fbo) { draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); } else { - // Should this even happen? It could while debugging, but maybe we can just skip binding at all. - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad"); + // This can happen (like it does in Parappa) when a frame starts with copies instead of rendering. + // Let's do nothing and assume it'll take care of itself. } } @@ -3446,7 +3462,7 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX if (src == dst && srcX == dstX && srcY == dstY) { // Let's just skip a copy where the destination is equal to the source. - WARN_LOG_REPORT_ONCE(blitSame, G3D, "Skipped blit with equal dst and src"); + WARN_LOG_REPORT_ONCE(blitSame, Log::G3D, "Skipped blit with equal dst and src"); return; } @@ -3567,7 +3583,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi vfb->fb_format = newFormat; // stride stays the same since it's in pixels. - WARN_LOG(G3D, "Creating %s clone of %08x/%08x/%s (%dx%d -> %dx%d)", GeBufferFormatToString(newFormat), src->fb_address, src->z_address, GeBufferFormatToString(src->fb_format), src->width, src->height, vfb->width, vfb->height); + WARN_LOG(Log::FrameBuf, "Creating %s clone of %08x/%08x/%s (%dx%d -> %dx%d)", GeBufferFormatToString(newFormat), src->fb_address, src->z_address, GeBufferFormatToString(src->fb_format), src->width, src->height, vfb->width, vfb->height); char tag[128]; FormatFramebufferName(vfb, tag, sizeof(tag)); diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 99c45295b0..7428f8821b 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -30,6 +30,7 @@ #include "Common/CommonTypes.h" #include "Common/Log.h" #include "Common/GPU/thin3d.h" +#include "Core/ConfigValues.h" #include "GPU/GPU.h" #include "GPU/ge_constants.h" #include "GPU/GPUInterface.h" @@ -548,6 +549,8 @@ protected: return fbBindSeqCount_++; } + static SkipGPUReadbackMode GetSkipGPUReadbackMode(); + PresentationCommon *presentation_ = nullptr; Draw::DrawContext *draw_ = nullptr; @@ -647,3 +650,6 @@ protected: u8 *convBuf_ = nullptr; u32 convBufSize_ = 0; }; + +// Should probably live elsewhere. +bool GetOutputFramebuffer(Draw::DrawContext *draw, GPUDebugBuffer &buffer); diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2177bf31db..4097d5cce7 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -920,7 +920,7 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend return true; case GE_LOGIC_AND: case GE_LOGIC_AND_REVERSE: - WARN_LOG_REPORT_ONCE(d3dLogicOpAnd, G3D, "Unsupported AND logic op: %x", gstate.getLogicOp()); + WARN_LOG_REPORT_ONCE(d3dLogicOpAnd, Log::G3D, "Unsupported AND logic op: %x", gstate.getLogicOp()); break; case GE_LOGIC_COPY: // This is the same as off. @@ -933,13 +933,13 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend case GE_LOGIC_NAND: case GE_LOGIC_EQUIV: // Handled in the shader. - WARN_LOG_REPORT_ONCE(d3dLogicOpAndInverted, G3D, "Attempted invert for logic op: %x", gstate.getLogicOp()); + WARN_LOG_REPORT_ONCE(d3dLogicOpAndInverted, Log::G3D, "Attempted invert for logic op: %x", gstate.getLogicOp()); break; case GE_LOGIC_INVERTED: srcBlend = BlendFactor::ONE; dstBlend = BlendFactor::ONE; blendEq = BlendEq::SUBTRACT; - WARN_LOG_REPORT_ONCE(d3dLogicOpInverted, G3D, "Attempted inverse for logic op: %x", gstate.getLogicOp()); + WARN_LOG_REPORT_ONCE(d3dLogicOpInverted, Log::G3D, "Attempted inverse for logic op: %x", gstate.getLogicOp()); return true; case GE_LOGIC_NOOP: srcBlend = BlendFactor::ZERO; @@ -947,7 +947,7 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend blendEq = BlendEq::ADD; return true; case GE_LOGIC_XOR: - WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp()); + WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, Log::G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp()); break; case GE_LOGIC_OR: case GE_LOGIC_OR_INVERTED: @@ -955,16 +955,16 @@ static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend srcBlend = BlendFactor::ONE; dstBlend = BlendFactor::ONE; blendEq = BlendEq::ADD; - WARN_LOG_REPORT_ONCE(d3dLogicOpOr, G3D, "Attempted or for logic op: %x", gstate.getLogicOp()); + WARN_LOG_REPORT_ONCE(d3dLogicOpOr, Log::G3D, "Attempted or for logic op: %x", gstate.getLogicOp()); return true; case GE_LOGIC_OR_REVERSE: - WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp()); + WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, Log::G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp()); break; case GE_LOGIC_SET: srcBlend = BlendFactor::ONE; dstBlend = BlendFactor::ONE; blendEq = BlendEq::ADD; - WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp()); + WARN_LOG_REPORT_ONCE(d3dLogicOpSet, Log::G3D, "Attempted set for logic op: %x", gstate.getLogicOp()); return true; } } else { @@ -1284,7 +1284,7 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl glBlendFuncB = BlendFactor::CONSTANT_COLOR; blendState.setBlendColor(fixA, constantAlpha); } else { - DEBUG_LOG(G3D, "ERROR INVALID blendcolorstate: FixA=%06x FixB=%06x FuncA=%i FuncB=%i", fixA, fixB, blendFuncA, blendFuncB); + DEBUG_LOG(Log::G3D, "ERROR INVALID blendcolorstate: FixA=%06x FixB=%06x FuncA=%i FuncB=%i", fixA, fixB, blendFuncA, blendFuncB); // Let's approximate, at least. Close is better than totally off. const bool nearZeroA = blendColorSimilar(fixA, 0, 64); const bool nearZeroB = blendColorSimilar(fixB, 0, 64); @@ -1642,11 +1642,11 @@ void ConvertStencilFuncState(GenericStencilFuncState &state) { } void GenericMaskState::Log() { - WARN_LOG(G3D, "Mask: %08x %01X readfb=%d", uniformMask, channelMask, applyFramebufferRead); + WARN_LOG(Log::G3D, "Mask: %08x %01X readfb=%d", uniformMask, channelMask, applyFramebufferRead); } void GenericBlendState::Log() { - WARN_LOG(G3D, "Blend: hwenable=%d readfb=%d replblend=%d replalpha=%d", + WARN_LOG(Log::G3D, "Blend: hwenable=%d readfb=%d replblend=%d replalpha=%d", blendEnabled, applyFramebufferRead, replaceBlend, (int)replaceAlphaWithStencil); } diff --git a/GPU/Common/IndexGenerator.cpp b/GPU/Common/IndexGenerator.cpp index e3c042f4c3..482b78f569 100644 --- a/GPU/Common/IndexGenerator.cpp +++ b/GPU/Common/IndexGenerator.cpp @@ -86,13 +86,13 @@ void IndexGenerator::AddList(int numVerts, int indexOffset, bool clockwise) { alignas(16) static const u16 offsets_clockwise[24] = { 0, (u16)(0 + 1), (u16)(0 + 2), - 1, (u16)(1 + 2), (u16)(1 + 1), + (u16)(1 + 1), 1, (u16)(1 + 2), 2, (u16)(2 + 1), (u16)(2 + 2), - 3, (u16)(3 + 2), (u16)(3 + 1), + (u16)(3 + 1), 3, (u16)(3 + 2), 4, (u16)(4 + 1), (u16)(4 + 2), - 5, (u16)(5 + 2), (u16)(5 + 1), + (u16)(5 + 1), 5, (u16)(5 + 2), 6, (u16)(6 + 1), (u16)(6 + 2), - 7, (u16)(7 + 2), (u16)(7 + 1), + (u16)(7 + 1), 7, (u16)(7 + 2), }; alignas(16) static const uint16_t offsets_counter_clockwise[24] = { diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 6ffd58f5b0..97afc59bc9 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -204,7 +204,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct appendTextureShader(info); } } else if (!section.name().empty()) { - WARN_LOG(G3D, "Unrecognized shader type '%s' or invalid shader in section '%s'", shaderType.c_str(), section.name().c_str()); + WARN_LOG(Log::G3D, "Unrecognized shader type '%s' or invalid shader in section '%s'", shaderType.c_str(), section.name().c_str()); } } } diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 69e440a64c..178b2b10ea 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -257,7 +257,7 @@ bool PresentationCommon::UpdatePostShader() { stereoShaderInfo_ = new ShaderInfo(*stereoShaderInfo); } } else { - WARN_LOG(G3D, "Failed to get info about stereo shader '%s'", g_Config.sStereoToMonoShader.c_str()); + WARN_LOG(Log::G3D, "Failed to get info about stereo shader '%s'", g_Config.sStereoToMonoShader.c_str()); } } @@ -335,7 +335,7 @@ bool PresentationCommon::CompilePostShader(const ShaderInfo *shaderInfo, Draw::P std::string errorString = vsError + "\n" + fsError; // DO NOT turn this into an ERROR_LOG_REPORT, as it will pollute our logs with all kinds of // user shader experiments. - ERROR_LOG(FRAMEBUF, "Failed to build post-processing program from %s and %s!\n%s", shaderInfo->vertexShaderFile.c_str(), shaderInfo->fragmentShaderFile.c_str(), errorString.c_str()); + ERROR_LOG(Log::FrameBuf, "Failed to build post-processing program from %s and %s!\n%s", shaderInfo->vertexShaderFile.c_str(), shaderInfo->fragmentShaderFile.c_str(), errorString.c_str()); ShowPostShaderError(errorString); return false; } @@ -572,7 +572,7 @@ Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, S if (lang != lang_) { // Gonna have to upconvert the shader. if (!TranslateShader(&translated, lang_, draw_->GetShaderLanguageDesc(), nullptr, src, lang, stage, errorString)) { - ERROR_LOG(FRAMEBUF, "Failed to translate post-shader. Error string: '%s'\nSource code:\n%s\n", errorString->c_str(), src.c_str()); + ERROR_LOG(Log::FrameBuf, "Failed to translate post-shader. Error string: '%s'\nSource code:\n%s\n", errorString->c_str(), src.c_str()); return nullptr; } } diff --git a/GPU/Common/ReinterpretFramebuffer.h b/GPU/Common/ReinterpretFramebuffer.h index ac97e46a9e..f1a78a9b88 100644 --- a/GPU/Common/ReinterpretFramebuffer.h +++ b/GPU/Common/ReinterpretFramebuffer.h @@ -1,9 +1,7 @@ #pragma once #include "Common/GPU/ShaderWriter.h" - #include "GPU/ge_constants.h" -#include "GPU/GPUCommon.h" #include "GPU/Common/Draw2D.h" Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBufferFormat from, GEBufferFormat to); diff --git a/GPU/Common/ReplacedTexture.cpp b/GPU/Common/ReplacedTexture.cpp index fd24a3e1af..fb01001474 100644 --- a/GPU/Common/ReplacedTexture.cpp +++ b/GPU/Common/ReplacedTexture.cpp @@ -223,7 +223,7 @@ void ReplacedTexture::Prepare(VFSBackend *vfs) { VFSFileReference *fileRef = vfs_->GetFile(desc_.filenames[i].c_str()); if (!fileRef) { if (i == 0) { - INFO_LOG(G3D, "Texture replacement file '%s' not found", desc_.filenames[i].c_str()); + INFO_LOG(Log::G3D, "Texture replacement file '%s' not found", desc_.filenames[i].c_str()); // No file at all. Mark as NOT_FOUND. SetState(ReplacementState::NOT_FOUND); return; @@ -248,7 +248,7 @@ void ReplacedTexture::Prepare(VFSBackend *vfs) { fmt = pixelFormat; } else { if (fmt != pixelFormat) { - ERROR_LOG(G3D, "Replacement mipmap %d doesn't have the same pixel format as mipmap 0. Stopping.", i); + ERROR_LOG(Log::G3D, "Replacement mipmap %d doesn't have the same pixel format as mipmap 0. Stopping.", i); break; } } @@ -262,7 +262,7 @@ void ReplacedTexture::Prepare(VFSBackend *vfs) { // No replacement found. std::string name = TextureReplacer::HashName(desc_.cachekey, desc_.hash, 0); if (result == LoadLevelResult::LOAD_ERROR) { - WARN_LOG(G3D, "Failed to load replacement texture '%s'", name.c_str()); + WARN_LOG(Log::G3D, "Failed to load replacement texture '%s'", name.c_str()); } SetState(ReplacementState::NOT_FOUND); return; @@ -320,7 +320,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference // Additional quick checks good = good && header.layerCount <= 1; } else if (imageType == ReplacedImageType::BASIS) { - WARN_LOG(G3D, "The basis texture format is not supported. Use KTX2 (basisu texture.png -uastc -ktx2 -mipmap)"); + WARN_LOG(Log::G3D, "The basis texture format is not supported. Use KTX2 (basisu texture.png -uastc -ktx2 -mipmap)"); // We simply don't support basis files currently. good = false; @@ -333,7 +333,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference u32 format; if (good && (header.ddspf.dwFlags & DDPF_FOURCC)) { char *fcc = (char *)&header.ddspf.dwFourCC; - // INFO_LOG(G3D, "DDS fourcc: %c%c%c%c", fcc[0], fcc[1], fcc[2], fcc[3]); + // INFO_LOG(Log::G3D, "DDS fourcc: %c%c%c%c", fcc[0], fcc[1], fcc[2], fcc[3]); if (header.ddspf.dwFourCC == MK_FOURCC("DX10")) { ddsDX10 = true; good = good && vfs_->Read(openFile, &header10, sizeof(header10)) == sizeof(header10); @@ -342,7 +342,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference case 71: // DXGI_FORMAT_BC1_UNORM case 72: // DXGI_FORMAT_BC1_UNORM_SRGB if (!desc_.formatSupport.bc123) { - WARN_LOG(G3D, "BC1 format not supported, skipping texture"); + WARN_LOG(Log::G3D, "BC1 format not supported, skipping texture"); good = false; } *pixelFormat = Draw::DataFormat::BC1_RGBA_UNORM_BLOCK; @@ -350,7 +350,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference case 74: // DXGI_FORMAT_BC2_UNORM case 75: // DXGI_FORMAT_BC2_UNORM_SRGB if (!desc_.formatSupport.bc123) { - WARN_LOG(G3D, "BC2 format not supported, skipping texture"); + WARN_LOG(Log::G3D, "BC2 format not supported, skipping texture"); good = false; } *pixelFormat = Draw::DataFormat::BC2_UNORM_BLOCK; @@ -358,7 +358,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference case 77: // DXGI_FORMAT_BC3_UNORM case 78: // DXGI_FORMAT_BC3_UNORM_SRGB if (!desc_.formatSupport.bc123) { - WARN_LOG(G3D, "BC3 format not supported, skipping texture"); + WARN_LOG(Log::G3D, "BC3 format not supported, skipping texture"); good = false; } *pixelFormat = Draw::DataFormat::BC3_UNORM_BLOCK; @@ -366,18 +366,18 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference case 98: // DXGI_FORMAT_BC7_UNORM: case 99: // DXGI_FORMAT_BC7_UNORM_SRGB: if (!desc_.formatSupport.bc7) { - WARN_LOG(G3D, "BC7 format not supported, skipping texture"); + WARN_LOG(Log::G3D, "BC7 format not supported, skipping texture"); good = false; } *pixelFormat = Draw::DataFormat::BC7_UNORM_BLOCK; break; default: - WARN_LOG(G3D, "DXGI pixel format %d not supported.", header10.dxgiFormat); + WARN_LOG(Log::G3D, "DXGI pixel format %d not supported.", header10.dxgiFormat); good = false; } } else { if (!desc_.formatSupport.bc123) { - WARN_LOG(G3D, "BC1-3 formats not supported"); + WARN_LOG(Log::G3D, "BC1-3 formats not supported"); good = false; } format = header.ddspf.dwFourCC; @@ -394,12 +394,12 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference *pixelFormat = Draw::DataFormat::BC3_UNORM_BLOCK; break; default: - ERROR_LOG(G3D, "DDS pixel format not supported."); + ERROR_LOG(Log::G3D, "DDS pixel format not supported."); good = false; } } } else if (good) { - ERROR_LOG(G3D, "DDS non-fourCC format not supported."); + ERROR_LOG(Log::G3D, "DDS non-fourCC format not supported."); good = false; } @@ -427,12 +427,12 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference level.h = headerPeek.Height(); good = true; } else { - ERROR_LOG(G3D, "Could not get PNG dimensions: %s (zip)", filename.c_str()); + ERROR_LOG(Log::G3D, "Could not get PNG dimensions: %s (zip)", filename.c_str()); good = false; } *pixelFormat = Draw::DataFormat::R8G8B8A8_UNORM; } else { - ERROR_LOG(G3D, "Could not load texture replacement info: %s - unsupported format %s", filename.c_str(), magic.c_str()); + ERROR_LOG(Log::G3D, "Could not load texture replacement info: %s - unsupported format %s", filename.c_str(), magic.c_str()); } // TODO: We no longer really need to have a split in this function, the upper and lower parts can be merged now. @@ -441,7 +441,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference // If loading a low mip directly (through png most likely), check that the mipmap size is correct. // Can't load mips of the wrong size. if (level.w != std::max(1, (levels_[0].w >> mipLevel)) || level.h != std::max(1, (levels_[0].h >> mipLevel))) { - WARN_LOG(G3D, "Replacement mipmap invalid: size=%dx%d, expected=%dx%d (level %d)", + WARN_LOG(Log::G3D, "Replacement mipmap invalid: size=%dx%d, expected=%dx%d (level %d)", level.w, level.h, levels_[0].w >> mipLevel, levels_[0].h >> mipLevel, mipLevel); good = false; } @@ -464,7 +464,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference basist::ktx2_transcoder transcoder; if (!transcoder.init(buffer.data(), (int)buffer.size())) { - WARN_LOG(G3D, "Error reading KTX file"); + WARN_LOG(Log::G3D, "Error reading KTX file"); vfs_->CloseFile(openFile); return LoadLevelResult::LOAD_ERROR; } @@ -483,7 +483,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference *pixelFormat = Draw::DataFormat::ETC2_R8G8B8_UNORM_BLOCK; } else { // Transcode to RGBA8 instead as a fallback. A bit slow and takes a lot of memory, but better than nothing. - WARN_LOG(G3D, "Replacement texture format not supported - transcoding to RGBA8888"); + WARN_LOG(Log::G3D, "Replacement texture format not supported - transcoding to RGBA8888"); transcoderFormat = basist::transcoder_texture_format::cTFRGBA32; *pixelFormat = Draw::DataFormat::R8G8B8A8_UNORM; } @@ -499,12 +499,12 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference *pixelFormat = Draw::DataFormat::ASTC_4x4_UNORM_BLOCK; } else { // Transcode to RGBA8 instead as a fallback. A bit slow and takes a lot of memory, but better than nothing. - WARN_LOG(G3D, "Replacement texture format not supported - transcoding to RGBA8888"); + WARN_LOG(Log::G3D, "Replacement texture format not supported - transcoding to RGBA8888"); transcoderFormat = basist::transcoder_texture_format::cTFRGBA32; *pixelFormat = Draw::DataFormat::R8G8B8A8_UNORM; } } else { - WARN_LOG(G3D, "PPSSPP currently only supports KTX for basis/UASTC textures. This may change in the future."); + WARN_LOG(Log::G3D, "PPSSPP currently only supports KTX for basis/UASTC textures. This may change in the future."); vfs_->CloseFile(openFile); return LoadLevelResult::LOAD_ERROR; } @@ -514,7 +514,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference _dbg_assert_(bc || *pixelFormat == Draw::DataFormat::R8G8B8A8_UNORM); if (bc && ((level.w & 3) != 0 || (level.h & 3) != 0)) { - WARN_LOG(G3D, "Block compressed replacement texture '%s' not divisible by 4x4 (%dx%d). In D3D11 (only!) we will have to expand (potentially causing glitches).", filename.c_str(), level.w, level.h); + WARN_LOG(Log::G3D, "Block compressed replacement texture '%s' not divisible by 4x4 (%dx%d). In D3D11 (only!) we will have to expand (potentially causing glitches).", filename.c_str(), level.w, level.h); } data_.resize(numMips); @@ -569,7 +569,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference _dbg_assert_(bc); if (bc && ((level.w & 3) != 0 || (level.h & 3) != 0)) { - WARN_LOG(G3D, "Block compressed replacement texture '%s' not divisible by 4x4 (%dx%d). In D3D11 (only!) we will have to expand (potentially causing glitches).", filename.c_str(), level.w, level.h); + WARN_LOG(Log::G3D, "Block compressed replacement texture '%s' not divisible by 4x4 (%dx%d). In D3D11 (only!) we will have to expand (potentially causing glitches).", filename.c_str(), level.w, level.h); } data_.resize(numMips); @@ -584,7 +584,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference size_t read_bytes = vfs_->Read(openFile, &out[0], bytesToRead); if (read_bytes != bytesToRead) { - WARN_LOG(G3D, "DDS: Expected %d bytes, got %d", bytesToRead, (int)read_bytes); + WARN_LOG(Log::G3D, "DDS: Expected %d bytes, got %d", bytesToRead, (int)read_bytes); } levels_.push_back(level); @@ -601,13 +601,13 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference auto zim = std::make_unique(fileSize); if (!zim) { - ERROR_LOG(G3D, "Failed to allocate memory for texture replacement"); + ERROR_LOG(Log::G3D, "Failed to allocate memory for texture replacement"); vfs_->CloseFile(openFile); return LoadLevelResult::LOAD_ERROR; } if (vfs_->Read(openFile, &zim[0], fileSize) != fileSize) { - ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM", filename.c_str()); + ERROR_LOG(Log::G3D, "Could not load texture replacement: %s - failed to read ZIM", filename.c_str()); vfs_->CloseFile(openFile); return LoadLevelResult::LOAD_ERROR; } @@ -618,7 +618,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference // TODO: Zim files can actually hold mipmaps (although no tool has ever been made to create them :P) if (LoadZIMPtr(&zim[0], fileSize, &w, &h, &f, &image)) { if (w > level.w || h > level.h) { - ERROR_LOG(G3D, "Texture replacement changed since header read: %s", filename.c_str()); + ERROR_LOG(Log::G3D, "Texture replacement changed since header read: %s", filename.c_str()); vfs_->CloseFile(openFile); return LoadLevelResult::LOAD_ERROR; } @@ -653,12 +653,12 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference pngdata.resize(fileSize); pngdata.resize(vfs_->Read(openFile, &pngdata[0], fileSize)); if (!png_image_begin_read_from_memory(&png, &pngdata[0], pngdata.size())) { - ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", filename.c_str(), png.message); + ERROR_LOG(Log::G3D, "Could not load texture replacement info: %s - %s (zip)", filename.c_str(), png.message); vfs_->CloseFile(openFile); return LoadLevelResult::LOAD_ERROR; } if (png.width > (uint32_t)level.w || png.height > (uint32_t)level.h) { - ERROR_LOG(G3D, "Texture replacement changed since header read: %s", filename.c_str()); + ERROR_LOG(Log::G3D, "Texture replacement changed since header read: %s", filename.c_str()); vfs_->CloseFile(openFile); return LoadLevelResult::LOAD_ERROR; } @@ -677,7 +677,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference // TODO: Should probably try to handle out-of-memory gracefully here. out.resize(level.w * level.h * 4); if (!png_image_finish_read(&png, nullptr, &out[0], level.w * 4, nullptr)) { - ERROR_LOG(G3D, "Could not load texture replacement: %s - %s", filename.c_str(), png.message); + ERROR_LOG(Log::G3D, "Could not load texture replacement: %s - %s", filename.c_str(), png.message); vfs_->CloseFile(openFile); out.resize(0); return LoadLevelResult::LOAD_ERROR; @@ -697,7 +697,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference vfs_->CloseFile(openFile); return LoadLevelResult::CONTINUE; } else { - WARN_LOG(G3D, "Don't know how to load this image type! %d", (int)imageType); + WARN_LOG(Log::G3D, "Don't know how to load this image type! %d", (int)imageType); vfs_->CloseFile(openFile); } return LoadLevelResult::LOAD_ERROR; @@ -708,7 +708,7 @@ bool ReplacedTexture::CopyLevelTo(int level, uint8_t *out, size_t outDataSize, i _assert_msg_(out != nullptr && rowPitch > 0, "Invalid out/pitch"); if (State() != ReplacementState::ACTIVE) { - WARN_LOG(G3D, "Init not done yet"); + WARN_LOG(Log::G3D, "Init not done yet"); return false; } @@ -726,7 +726,7 @@ bool ReplacedTexture::CopyLevelTo(int level, uint8_t *out, size_t outDataSize, i const std::vector &data = data_[level]; if (data.empty()) { - WARN_LOG(G3D, "Level %d is empty", level); + WARN_LOG(Log::G3D, "Level %d is empty", level); return false; } @@ -735,12 +735,12 @@ bool ReplacedTexture::CopyLevelTo(int level, uint8_t *out, size_t outDataSize, i int blockSize; if (!Draw::DataFormatIsBlockCompressed(fmt, &blockSize)) { if (fmt != Draw::DataFormat::R8G8B8A8_UNORM) { - ERROR_LOG(G3D, "Unexpected linear data format"); + ERROR_LOG(Log::G3D, "Unexpected linear data format"); return false; } if (rowPitch < info.w * 4) { - ERROR_LOG(G3D, "Replacement rowPitch=%d, but w=%d (level=%d) (too small)", rowPitch, info.w * 4, level); + ERROR_LOG(Log::G3D, "Replacement rowPitch=%d, but w=%d (level=%d) (too small)", rowPitch, info.w * 4, level); return false; } diff --git a/GPU/Common/ReplacedTexture.h b/GPU/Common/ReplacedTexture.h index 7474bae115..2161a01783 100644 --- a/GPU/Common/ReplacedTexture.h +++ b/GPU/Common/ReplacedTexture.h @@ -121,7 +121,7 @@ public: void SetState(ReplacementState state) { _dbg_assert_(state != state_); #ifdef _DEBUG - // WARN_LOG(G3D, "Texture %s changed state from %s to %s", logId_.c_str(), StateString(state_), StateString(state)); + // WARN_LOG(Log::G3D, "Texture %s changed state from %s to %s", logId_.c_str(), StateString(state_), StateString(state)); #endif state_ = state; } diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 4acf2e5245..7e5a949a3d 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -283,6 +283,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView } // For "light ubershader" bits. +// TODO: We pack these bits even when not using ubershader lighting. Maybe not bother. uint32_t PackLightControlBits() { // Bit organization // Bottom 4 bits are enable bits for each light. diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 4e5cce6985..8d1624000c 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -125,33 +125,6 @@ static bool IsReallyAClear(const TransformedVertex *transformed, int numVerts, f return true; } -static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) { - if (shadeMode != GE_SHADE_FLAT || clearMode) { - return 0; - } - - switch (prim) { - case GE_PRIM_LINES: - case GE_PRIM_LINE_STRIP: - return 1; - - case GE_PRIM_TRIANGLES: - case GE_PRIM_TRIANGLE_STRIP: - return 2; - - case GE_PRIM_TRIANGLE_FAN: - return 1; - - case GE_PRIM_RECTANGLES: - // We already use BR color when expanding, so no need to offset. - return 0; - - default: - break; - } - return 0; -} - void SoftwareTransform::SetProjMatrix(const float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale) { memcpy(&projMatrix_.m, mtx, 16 * sizeof(float)); @@ -202,11 +175,6 @@ void SoftwareTransform::Transform(int prim, u32 vertType, const DecVtxFormat &de fog_slope = std::signbit(fog_slope) ? -65535.0f : 65535.0f; } - int provokeIndOffset = 0; - if (params_.provokeFlatFirst) { - provokeIndOffset = ColorIndexOffset(prim, gstate.getShadeMode(), gstate.isModeClear()); - } - VertexReader reader(decoded, decVtxFormat, vertType); if (throughmode) { const u32 materialAmbientRGBA = gstate.getMaterialAmbientRGBA(); @@ -221,13 +189,7 @@ void SoftwareTransform::Transform(int prim, u32 vertType, const DecVtxFormat &de vert.pos_w = 1.0f; if (hasColor) { - if (provokeIndOffset != 0 && index + provokeIndOffset < numDecodedVerts) { - reader.Goto(index + provokeIndOffset); - vert.color0_32 = reader.ReadColor0_8888(); - reader.Goto(index); - } else { - vert.color0_32 = reader.ReadColor0_8888(); - } + vert.color0_32 = reader.ReadColor0_8888(); } else { vert.color0_32 = materialAmbientRGBA; } @@ -268,10 +230,7 @@ void SoftwareTransform::Transform(int prim, u32 vertType, const DecVtxFormat &de if (reader.hasUV()) reader.ReadUV(ruv); - // Read all the provoking vertex values here. Vec4f unlitColor; - if (provokeIndOffset != 0 && index + provokeIndOffset < numDecodedVerts) - reader.Goto(index + provokeIndOffset); if (reader.hasColor0()) reader.ReadColor0(unlitColor.AsArray()); else @@ -342,36 +301,16 @@ void SoftwareTransform::Transform(int prim, u32 vertType, const DecVtxFormat &de break; case GE_PROJMAP_NORMALIZED_NORMAL: // Use normalized normal as source - // Flat uses the vertex normal, not provoking. - if (provokeIndOffset == 0) { - source = normal.Normalized(cpu_info.bSSE4_1); - } else { - reader.Goto(index); - if (reader.hasNormal()) - reader.ReadNrm(source.AsArray()); - if (gstate.areNormalsReversed()) - source = -source; - source.Normalize(); - } + source = normal.Normalized(cpu_info.bSSE4_1); if (!reader.hasNormal()) { - ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?"); + ERROR_LOG_REPORT(Log::G3D, "Normal projection mapping without normal?"); } break; case GE_PROJMAP_NORMAL: // Use non-normalized normal as source! - // Flat uses the vertex normal, not provoking. - if (provokeIndOffset == 0) { - source = normal; - } else { - // Need to read the normal for this vertex and weight it again.. - reader.Goto(index); - if (reader.hasNormal()) - reader.ReadNrm(source.AsArray()); - if (gstate.areNormalsReversed()) - source = -source; - } + source = normal; if (!reader.hasNormal()) { - ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?"); + ERROR_LOG_REPORT(Log::G3D, "Normal projection mapping without normal?"); } break; } @@ -409,7 +348,7 @@ void SoftwareTransform::Transform(int prim, u32 vertType, const DecVtxFormat &de default: // Illegal - ERROR_LOG_REPORT(G3D, "Impossible UV gen mode? %d", gstate.getUVGenMode()); + ERROR_LOG_REPORT(Log::G3D, "Impossible UV gen mode? %d", gstate.getUVGenMode()); break; } @@ -497,13 +436,11 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy if (prim == GE_PRIM_RECTANGLES) { if (!ExpandRectangles(vertexCount, numDecodedVerts, vertsSize, inds, indsSize, transformed, transformedExpanded, numTrans, throughmode, &result->pixelMapped)) { - result->drawIndexed = false; result->drawNumTrans = 0; result->pixelMapped = false; return; } result->drawBuffer = transformedExpanded; - result->drawIndexed = true; // We don't know the color until here, so we have to do it now, instead of in StateMapping. // Might want to reconsider the order of things later... @@ -521,25 +458,20 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy } else if (prim == GE_PRIM_POINTS) { result->pixelMapped = false; if (!ExpandPoints(vertexCount, numDecodedVerts, vertsSize, inds, indsSize, transformed, transformedExpanded, numTrans, throughmode)) { - result->drawIndexed = false; result->drawNumTrans = 0; return; } result->drawBuffer = transformedExpanded; - result->drawIndexed = true; } else if (prim == GE_PRIM_LINES) { result->pixelMapped = false; if (!ExpandLines(vertexCount, numDecodedVerts, vertsSize, inds, indsSize, transformed, transformedExpanded, numTrans, throughmode)) { - result->drawIndexed = false; result->drawNumTrans = 0; return; } result->drawBuffer = transformedExpanded; - result->drawIndexed = true; } else { // We can simply draw the unexpanded buffer. numTrans = vertexCount; - result->drawIndexed = true; result->pixelMapped = false; // If we don't support custom cull in the shader, process it here. @@ -635,7 +567,7 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy gpuStats.numClears++; } - result->action = SW_DRAW_PRIMITIVES; + result->action = SW_DRAW_INDEXED; result->drawNumTrans = numTrans; } @@ -758,6 +690,38 @@ bool SoftwareTransform::ExpandRectangles(int vertexCount, int &numDecodedVerts, return true; } +// In-place. So, better not be doing this on GPU memory! +void IndexBufferProvokingLastToFirst(int prim, u16 *inds, int indsSize) { + switch (prim) { + case GE_PRIM_LINES: + // Swap every two indices. + for (int i = 0; i < indsSize - 1; i += 2) { + u16 temp = inds[i]; + inds[i] = inds[i + 1]; + inds[i + 1] = temp; + } + break; + case GE_PRIM_TRIANGLES: + // Rotate the triangle so the last becomes the first, without changing the winding order. + // This could be done with a series of pshufb. + for (int i = 0; i < indsSize - 2; i += 3) { + u16 temp = inds[i + 2]; + inds[i + 2] = inds[i + 1]; + inds[i + 1] = inds[i]; + inds[i] = temp; + } + break; + case GE_PRIM_POINTS: + // Nothing to do, + break; + case GE_PRIM_RECTANGLES: + // Nothing to do, already using the 2nd vertex. + break; + default: + _dbg_assert_msg_(false, "IndexBufferProvokingFirstToLast: Only works with plain indexed primitives, no strips or fans") + } +} + bool SoftwareTransform::ExpandLines(int vertexCount, int &numDecodedVerts, int vertsSize, u16 *&inds, int indsSize, const TransformedVertex *transformed, TransformedVertex *transformedExpanded, int &numTrans, bool throughmode) { // Before we start, do a sanity check - does the output fit? if ((vertexCount / 2) * 6 > indsSize) { diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index 78717cdfa3..457fd6a253 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -26,7 +26,7 @@ class TextureCacheCommon; enum SoftwareTransformAction { SW_NOT_READY, - SW_DRAW_PRIMITIVES, + SW_DRAW_INDEXED, SW_CLEAR, }; @@ -44,8 +44,6 @@ struct SoftwareTransformResult { TransformedVertex *drawBuffer; int drawNumTrans; - bool drawIndexed; - bool pixelMapped; }; @@ -57,11 +55,15 @@ struct SoftwareTransformParams { TextureCacheCommon *texCache; bool allowClear; bool allowSeparateAlphaClear; - bool provokeFlatFirst; bool flippedY; bool usesHalfZ; }; +// Converts an index buffer to make the provoking vertex the last. +// In-place. So, better not be doing this on GPU memory! +// TODO: We could do this already during index decode. +void IndexBufferProvokingLastToFirst(int prim, u16 *inds, int indsSize); + class SoftwareTransform { public: SoftwareTransform(SoftwareTransformParams ¶ms) : params_(params) {} diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index bf0921c54a..de22c14fcf 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -514,13 +514,13 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic // There are normally not a lot of control points so just splitting decoded should be reasonably safe, although not great. SimpleVertex *simplified_control_points = (SimpleVertex *)managedBuf.Allocate(sizeof(SimpleVertex) * (index_upper_bound + 1)); if (!simplified_control_points) { - ERROR_LOG(G3D, "Failed to allocate space for simplified control points, skipping curve draw"); + ERROR_LOG(Log::G3D, "Failed to allocate space for simplified control points, skipping curve draw"); return; } u8 *temp_buffer = managedBuf.Allocate(sizeof(SimpleVertex) * num_points); if (!temp_buffer) { - ERROR_LOG(G3D, "Failed to allocate space for temp buffer, skipping curve draw"); + ERROR_LOG(Log::G3D, "Failed to allocate space for temp buffer, skipping curve draw"); return; } @@ -531,13 +531,13 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic int vertexSize = vdecoder->VertexSize(); if (vertexSize != sizeof(SimpleVertex)) { - ERROR_LOG(G3D, "Something went really wrong, vertex size: %d vs %d", vertexSize, (int)sizeof(SimpleVertex)); + ERROR_LOG(Log::G3D, "Something went really wrong, vertex size: %d vs %d", vertexSize, (int)sizeof(SimpleVertex)); } // Make an array of pointers to the control points, to get rid of indices. const SimpleVertex **points = (const SimpleVertex **)managedBuf.Allocate(sizeof(SimpleVertex *) * num_points); if (!points) { - ERROR_LOG(G3D, "Failed to allocate space for control point pointers, skipping curve draw"); + ERROR_LOG(Log::G3D, "Failed to allocate space for control point pointers, skipping curve draw"); return; } for (int idx = 0; idx < num_points; idx++) @@ -559,7 +559,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic if (cpoints.IsValid()) SoftwareTessellation(output, surface, origVertType, cpoints); else - ERROR_LOG(G3D, "Failed to allocate space for control point values, skipping curve draw"); + ERROR_LOG(Log::G3D, "Failed to allocate space for control point values, skipping curve draw"); } u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 2b57e6a5a8..43a8b33537 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -140,7 +140,7 @@ void TextureCacheCommon::StartFrame() { } if (texelsScaledThisFrame_) { - VERBOSE_LOG(G3D, "Scaled %d texels", texelsScaledThisFrame_); + VERBOSE_LOG(Log::G3D, "Scaled %d texels", texelsScaledThisFrame_); } texelsScaledThisFrame_ = 0; @@ -528,7 +528,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { if (match && (entry->status & TexCacheEntry::STATUS_TO_SCALE) && standardScaleFactor_ != 1 && texelsScaledThisFrame_ < TEXCACHE_MAX_TEXELS_SCALED) { if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) == 0) { - // INFO_LOG(G3D, "Reloading texture to do the scaling we skipped.."); + // INFO_LOG(Log::G3D, "Reloading texture to do the scaling we skipped.."); match = false; reason = "scaling"; } @@ -545,7 +545,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { switch (entry->replacedTexture->State()) { case ReplacementState::NOT_FOUND: // Didn't find a replacement, so stop looking. - // DEBUG_LOG(G3D, "No replacement for texture %dx%d", w0, h0); + // DEBUG_LOG(Log::G3D, "No replacement for texture %dx%d", w0, h0); entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE; if (g_Config.bSaveNewTextures) { // Load it once more to actually save it. Since we don't set STATUS_TO_REPLACE, we won't end up looping. @@ -588,7 +588,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { // Might need a rebuild if the hash fails, but that will be set later. nextNeedsRebuild_ = false; failedTexture_ = false; - VERBOSE_LOG(G3D, "Texture at %08x found in cache, applying", texaddr); + VERBOSE_LOG(Log::G3D, "Texture at %08x found in cache, applying", texaddr); return entry; //Done! } else { // Wasn't a match, we will rebuild. @@ -624,7 +624,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { // Didn't match a framebuffer, keep going. if (!entry) { - VERBOSE_LOG(G3D, "No texture in cache for %08x, decoding...", texaddr); + VERBOSE_LOG(Log::G3D, "No texture in cache for %08x, decoding...", texaddr); entry = new TexCacheEntry{}; cache_[cachekey].reset(entry); @@ -638,7 +638,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { } if (hasClutGPU) { - WARN_LOG_N_TIMES(clutUseRender, 5, G3D, "Using texture with dynamic CLUT: texfmt=%d, clutfmt=%d", gstate.getTextureFormat(), gstate.getClutPaletteFormat()); + WARN_LOG_N_TIMES(clutUseRender, 5, Log::G3D, "Using texture with dynamic CLUT: texfmt=%d, clutfmt=%d", gstate.getTextureFormat(), gstate.getClutPaletteFormat()); entry->status |= TexCacheEntry::STATUS_CLUT_GPU; } @@ -767,7 +767,7 @@ bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &en } cands += "\n"; - WARN_LOG(G3D, "GetFramebufferCandidates(tex): Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s", + WARN_LOG(Log::G3D, "GetFramebufferCandidates(tex): Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s", (int)candidates.size(), entry.addr, texAddrOffset, dimWidth(entry.dim), dimHeight(entry.dim), entry.bufw, GeTextureFormatToString(entry.format), cands.c_str() @@ -777,7 +777,7 @@ bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &en if (bestIndex != -1) { if (logging) { - WARN_LOG(G3D, "Chose candidate %d:\n%s\n", (int)bestIndex, candidates[bestIndex].ToString().c_str()); + WARN_LOG(Log::G3D, "Chose candidate %d:\n%s\n", (int)bestIndex, candidates[bestIndex].ToString().c_str()); } *bestCandidate = candidates[bestIndex]; return true; @@ -813,7 +813,7 @@ void TextureCacheCommon::Decimate(TexCacheEntry *exceptThisOne, bool forcePressu } } - VERBOSE_LOG(G3D, "Decimated texture cache, saved %d estimated bytes - now %d bytes", had - cacheSizeEstimate_, cacheSizeEstimate_); + VERBOSE_LOG(Log::G3D, "Decimated texture cache, saved %d estimated bytes - now %d bytes", had - cacheSizeEstimate_, cacheSizeEstimate_); } // If enabled, we also need to clear the secondary cache. @@ -835,7 +835,7 @@ void TextureCacheCommon::Decimate(TexCacheEntry *exceptThisOne, bool forcePressu } } - VERBOSE_LOG(G3D, "Decimated second texture cache, saved %d estimated bytes - now %d bytes", had - secondCacheSizeEstimate_, secondCacheSizeEstimate_); + VERBOSE_LOG(Log::G3D, "Decimated second texture cache, saved %d estimated bytes - now %d bytes", had - secondCacheSizeEstimate_, secondCacheSizeEstimate_); } DecimateVideos(); @@ -869,7 +869,7 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c cacheSizeEstimate_ -= EstimateTexMemoryUsage(entry); entry->numInvalidated++; gpuStats.numTextureInvalidations++; - DEBUG_LOG(G3D, "Texture different or overwritten, reloading at %08x: %s", entry->addr, reason); + DEBUG_LOG(Log::G3D, "Texture different or overwritten, reloading at %08x: %s", entry->addr, reason); if (doDelete) { ForgetLastTexture(); ReleaseTexture(entry, true); @@ -1019,7 +1019,7 @@ bool TextureCacheCommon::MatchFramebuffer( if (TextureFormatMatchesBufferFormat(entry.format, fb_format) || (framebuffer->usageFlags & FB_USAGE_BLUE_TO_ALPHA)) { return true; } else { - WARN_LOG_ONCE(diffFormat1, G3D, "Found matching framebuffer with reinterpretable fb_format: %s != %s at %08x", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address); + WARN_LOG_ONCE(diffFormat1, Log::G3D, "Found matching framebuffer with reinterpretable fb_format: %s != %s at %08x", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address); *matchInfo = FramebufferMatchInfo{ 0, 0, true, TextureFormatToBufferFormat(entry.format) }; return true; } @@ -1082,7 +1082,7 @@ bool TextureCacheCommon::MatchFramebuffer( // Trying to play it safe. Below 0x04110000 is almost always framebuffers. // TODO: Maybe we can reduce this check and find a better way above 0x04110000? if (matchInfo->yOffset > MAX_SUBAREA_Y_OFFSET_SAFE && addr > 0x04110000 && !PSP_CoreParameter().compat.flags().AllowLargeFBTextureOffsets) { - WARN_LOG_ONCE(subareaIgnored, G3D, "Ignoring possible texturing from framebuffer at %08x +%dx%d / %dx%d", fb_address, matchInfo->xOffset, matchInfo->yOffset, framebuffer->width, framebuffer->height); + WARN_LOG_ONCE(subareaIgnored, Log::G3D, "Ignoring possible texturing from framebuffer at %08x +%dx%d / %dx%d", fb_address, matchInfo->xOffset, matchInfo->yOffset, framebuffer->width, framebuffer->height); return false; } @@ -1097,26 +1097,26 @@ bool TextureCacheCommon::MatchFramebuffer( // 3rd Birthday (and a bunch of other games) render to a 16 bit clut texture. if (matchingClutFormat) { if (!noOffset) { - WARN_LOG_ONCE(subareaClut, G3D, "Matching framebuffer (%s) using %s with offset at %08x +%dx%d", RasterChannelToString(channel), GeTextureFormatToString(entry.format), fb_address, matchInfo->xOffset, matchInfo->yOffset); + WARN_LOG_ONCE(subareaClut, Log::G3D, "Matching framebuffer (%s) using %s with offset at %08x +%dx%d", RasterChannelToString(channel), GeTextureFormatToString(entry.format), fb_address, matchInfo->xOffset, matchInfo->yOffset); } return true; } else if (IsClutFormat((GETextureFormat)(entry.format)) || IsDXTFormat((GETextureFormat)(entry.format))) { - WARN_LOG_ONCE(fourEightBit, G3D, "%s texture format not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); + WARN_LOG_ONCE(fourEightBit, Log::G3D, "%s texture format not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); return false; } // This is either normal or we failed to generate a shader to depalettize if ((int)fb_format == (int)entry.format || matchingClutFormat) { if ((int)fb_format != (int)entry.format) { - WARN_LOG_ONCE(diffFormat2, G3D, "Matching framebuffer with different formats %s != %s at %08x", + WARN_LOG_ONCE(diffFormat2, Log::G3D, "Matching framebuffer with different formats %s != %s at %08x", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address); return true; } else { - WARN_LOG_ONCE(subarea, G3D, "Matching from framebuffer at %08x +%dx%d", fb_address, matchInfo->xOffset, matchInfo->yOffset); + WARN_LOG_ONCE(subarea, Log::G3D, "Matching from framebuffer at %08x +%dx%d", fb_address, matchInfo->xOffset, matchInfo->yOffset); return true; } } else { - WARN_LOG_ONCE(diffFormat2, G3D, "Ignoring possible texturing from framebuffer at %08x with incompatible format %s != %s (+%dx%d)", + WARN_LOG_ONCE(diffFormat2, Log::G3D, "Ignoring possible texturing from framebuffer at %08x with incompatible format %s != %s (+%dx%d)", fb_address, GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), matchInfo->xOffset, matchInfo->yOffset); return false; } @@ -1179,7 +1179,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) } if (channel == RASTER_DEPTH && !gstate_c.Use(GPU_USE_DEPTH_TEXTURE)) { - WARN_LOG_ONCE(ndepthtex, G3D, "Depth textures not supported, not binding"); + WARN_LOG_ONCE(ndepthtex, Log::G3D, "Depth textures not supported, not binding"); // Flag to bind a null texture if we can't support depth textures. // Should only happen on old OpenGL. nextFramebufferTexture_ = nullptr; @@ -1272,7 +1272,7 @@ bool TextureCacheCommon::GetCurrentFramebufferTextureDebug(GPUDebugBuffer &buffe // We may have blitted to a temp FBO. framebufferManager_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug"); if (!retval) - ERROR_LOG(G3D, "Failed to get debug texture: copy to memory failed"); + ERROR_LOG(Log::G3D, "Failed to get debug texture: copy to memory failed"); return retval; } @@ -1361,7 +1361,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { bool okAge = !PSP_CoreParameter().compat.flags().LoadCLUTFromCurrentFrameOnly || framebuffer->last_frame_render == gpuStats.numFlips; // Here we can try heuristics. if (matchRange && !inMargin && offset < (int)clutRenderOffset_) { if (okAge) { - WARN_LOG_N_TIMES(clutfb, 5, G3D, "Detected LoadCLUT(%d bytes) from framebuffer %08x (%s), last render %d frames ago, byte offset %d, pixel offset %d", + WARN_LOG_N_TIMES(clutfb, 5, Log::G3D, "Detected LoadCLUT(%d bytes) from framebuffer %08x (%s), last render %d frames ago, byte offset %d, pixel offset %d", loadBytes, fb_address, GeBufferFormatToString(framebuffer->fb_format), gpuStats.numFlips - framebuffer->last_frame_render, offset, offset / fb_bpp); framebuffer->last_frame_clut = gpuStats.numFlips; // Also mark used so it's not decimated. @@ -1375,7 +1375,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { break; } } else { - WARN_LOG(G3D, "Ignoring CLUT load from %d frames old buffer at %08x", gpuStats.numFlips - framebuffer->last_frame_render, fb_address); + WARN_LOG(Log::G3D, "Ignoring CLUT load from %d frames old buffer at %08x", gpuStats.numFlips - framebuffer->last_frame_render, fb_address); } } } @@ -1659,9 +1659,8 @@ static CheckAlphaResult DecodeDXTBlocks(uint8_t *out, int outPitch, uint32_t tex int outPitch32 = outPitch / sizeof(uint32_t); const DXTBlock *src = (const DXTBlock *)texptr; - if (!Memory::IsValidRange(texaddr, (h / 4) * (bufw / 4) * sizeof(DXTBlock))) { - ERROR_LOG_REPORT(G3D, "DXT%d texture extends beyond valid RAM: %08x + %d x %d", n, texaddr, bufw, h); + ERROR_LOG_REPORT(Log::G3D, "DXT%d texture extends beyond valid RAM: %08x + %d x %d", n, texaddr, bufw, h); uint32_t limited = Memory::ValidSize(texaddr, (h / 4) * (bufw / 4) * sizeof(DXTBlock)); // This might possibly be 0, but try to decode what we can (might even be how the PSP behaves.) h = (((int)limited / sizeof(DXTBlock)) / (bufw / 4)) * 4; @@ -1741,7 +1740,7 @@ CheckAlphaResult TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, G bool swizzled = gstate.isTextureSwizzled(); if ((texaddr & 0x00600000) != 0 && Memory::IsVRAMAddress(texaddr)) { // This means it's in a mirror, possibly a swizzled mirror. Let's report. - WARN_LOG_REPORT_ONCE(texmirror, G3D, "Decoding texture from VRAM mirror at %08x swizzle=%d", texaddr, swizzled ? 1 : 0); + WARN_LOG_REPORT_ONCE(texmirror, Log::G3D, "Decoding texture from VRAM mirror at %08x swizzle=%d", texaddr, swizzled ? 1 : 0); if ((texaddr & 0x00200000) == 0x00200000) { // Technically 2 and 6 are slightly different, but this is better than nothing probably. // We should only see this with depth textures anyway which we don't support uploading (yet). @@ -1843,7 +1842,7 @@ CheckAlphaResult TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, G break; default: - ERROR_LOG_REPORT(G3D, "Unknown CLUT4 texture mode %d", gstate.getClutPaletteFormat()); + ERROR_LOG_REPORT(Log::G3D, "Unknown CLUT4 texture mode %d", gstate.getClutPaletteFormat()); return CHECKALPHA_ANY; } } @@ -1980,7 +1979,7 @@ CheckAlphaResult TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, G return DecodeDXTBlocks(out, outPitch, texaddr, texptr, w, h, bufw, reverseColors); default: - ERROR_LOG_REPORT(G3D, "Unknown Texture Format %d!!!", format); + ERROR_LOG_REPORT(Log::G3D, "Unknown Texture Format %d!!!", format); break; } @@ -2077,7 +2076,7 @@ CheckAlphaResult TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int l break; default: - ERROR_LOG_REPORT(G3D, "Unhandled clut texture mode %d!!!", gstate.getClutPaletteFormat()); + ERROR_LOG_REPORT(Log::G3D, "Unhandled clut texture mode %d!!!", gstate.getClutPaletteFormat()); break; } @@ -2204,7 +2203,7 @@ static bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferForma // Shouldn't happen here. return false; } - WARN_LOG(G3D, "Invalid CLUT/framebuffer combination: %s vs %s", GeTextureFormatToString(texFormat), GeBufferFormatToString(bufferFormat)); + WARN_LOG(Log::G3D, "Invalid CLUT/framebuffer combination: %s vs %s", GeTextureFormatToString(texFormat), GeBufferFormatToString(bufferFormat)); return false; } else if (texFormat == GE_TFMT_5650 && bufferFormat == GE_FORMAT_DEPTH16) { // We can also "depal" 565 format, this is used to read depth buffers as 565 on occasion (#15491). @@ -2520,7 +2519,7 @@ void TextureCacheCommon::Clear(bool delete_them) { ReleaseTexture(iter->second.get(), delete_them); } if (cache_.size() + secondCache_.size()) { - INFO_LOG(G3D, "Texture cached cleared from %i textures", (int)(cache_.size() + secondCache_.size())); + INFO_LOG(Log::G3D, "Texture cached cleared from %i textures", (int)(cache_.size() + secondCache_.size())); cache_.clear(); secondCache_.clear(); cacheSizeEstimate_ = 0; @@ -2833,8 +2832,11 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt plan.scaleFactor = 1; } else if (!g_DoubleTextureCoordinates) { // Refuse to load invalid-ly sized textures, which can happen through display list corruption. - if (plan.w > 1024 || plan.h > 1024) { - ERROR_LOG(G3D, "Bad texture dimensions: %dx%d", plan.w, plan.h); + // However, turns out some games uses huge textures for font rendering for no apparent reason. + // These will only work correctly in the top 512x512 part. So, I've increased the threshold quite a bit. + // We probably should handle these differently, by clamping the texture size and texture coordinates, but meh. + if (plan.w > 2048 || plan.h > 2048) { + ERROR_LOG(Log::G3D, "Bad texture dimensions: %dx%d", plan.w, plan.h); return false; } } diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index 4976bbd958..5f1d38aa2a 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -22,7 +22,6 @@ #include "Common/Common.h" #include "Common/Swap.h" #include "Core/MemMap.h" -#include "Core/ConfigValues.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" diff --git a/GPU/Common/TextureReplacer.cpp b/GPU/Common/TextureReplacer.cpp index 53f7e716a8..b456d05875 100644 --- a/GPU/Common/TextureReplacer.cpp +++ b/GPU/Common/TextureReplacer.cpp @@ -88,7 +88,7 @@ void TextureReplacer::NotifyConfigChanged() { // If we're saving, auto-create the directory. if (saveEnabled_ && !File::Exists(newTextureDir_)) { - INFO_LOG(G3D, "Creating new texture directory: '%s'", newTextureDir_.ToVisualString().c_str()); + INFO_LOG(Log::G3D, "Creating new texture directory: '%s'", newTextureDir_.ToVisualString().c_str()); File::CreateFullPath(newTextureDir_); // We no longer create a nomedia file here, since we put one // in the TEXTURES root. @@ -135,7 +135,7 @@ bool TextureReplacer::LoadIni() { // First, check for textures.zip, which is used to reduce IO. VFSBackend *dir = ZipFileReader::Create(zipPath, "", false); if (!dir) { - INFO_LOG(G3D, "%s wasn't a zip file - opening the directory %s instead.", zipPath.c_str(), basePath_.c_str()); + INFO_LOG(Log::G3D, "%s wasn't a zip file - opening the directory %s instead.", zipPath.c_str(), basePath_.c_str()); vfsIsZip_ = false; dir = new DirectoryReader(basePath_); } else { @@ -158,14 +158,14 @@ bool TextureReplacer::LoadIni() { IniFile overrideIni; iniLoaded = overrideIni.LoadFromVFS(*dir, overrideFilename); if (!iniLoaded) { - ERROR_LOG(G3D, "Failed to load extra texture ini: %s", overrideFilename.c_str()); + ERROR_LOG(Log::G3D, "Failed to load extra texture ini: %s", overrideFilename.c_str()); // Since this error is most likely to occure for texture pack creators, let's just bail here // so that the creator is more likely to look in the logs for what happened. delete dir; return false; } - INFO_LOG(G3D, "Loading extra texture ini: %s", overrideFilename.c_str()); + INFO_LOG(Log::G3D, "Loading extra texture ini: %s", overrideFilename.c_str()); if (!LoadIniValues(overrideIni, nullptr, true)) { delete dir; return false; @@ -175,17 +175,17 @@ bool TextureReplacer::LoadIni() { } else { if (vfsIsZip_) { // We don't accept zip files without inis. - ERROR_LOG(G3D, "Texture pack lacking ini file: %s", basePath_.c_str()); + ERROR_LOG(Log::G3D, "Texture pack lacking ini file: %s", basePath_.c_str()); delete dir; return false; } else { - WARN_LOG(G3D, "Texture pack lacking ini file: %s", basePath_.c_str()); + WARN_LOG(Log::G3D, "Texture pack lacking ini file: %s", basePath_.c_str()); // Do what we can do anyway: Scan for textures and build the map. std::map> filenameMap; ScanForHashNamedFiles(dir, filenameMap); if (filenameMap.empty()) { - WARN_LOG(G3D, "No replacement textures found."); + WARN_LOG(Log::G3D, "No replacement textures found."); return false; } @@ -205,9 +205,9 @@ bool TextureReplacer::LoadIni() { } if (vfsIsZip_) { - INFO_LOG(G3D, "Texture pack activated from '%s'", (basePath_ / ZIP_FILENAME).c_str()); + INFO_LOG(Log::G3D, "Texture pack activated from '%s'", (basePath_ / ZIP_FILENAME).c_str()); } else { - INFO_LOG(G3D, "Texture pack activated from '%s'", basePath_.c_str()); + INFO_LOG(Log::G3D, "Texture pack activated from '%s'", basePath_.c_str()); } // The ini doesn't have to exist for the texture directory or zip to be valid. @@ -235,7 +235,7 @@ void TextureReplacer::ScanForHashNamedFiles(VFSBackend *dir, std::map= 1) { - // INFO_LOG(G3D, "hash-like file in root, adding: %s", file.name.c_str()); + // INFO_LOG(Log::G3D, "hash-like file in root, adding: %s", file.name.c_str()); filenameMap[key][level] = file.name; } } @@ -251,7 +251,7 @@ void TextureReplacer::ComputeAliasMap(const std::mapGet("ignoreMipmap", &ignoreMipmap_, ignoreMipmap_); if (reduceHash_ && hash_ == ReplacedTextureHash::QUICK) { reduceHash_ = false; - ERROR_LOG(G3D, "Texture Replacement: reduceHash option requires safer hash, use xxh32 or xxh64 instead."); + ERROR_LOG(Log::G3D, "Texture Replacement: reduceHash option requires safer hash, use xxh32 or xxh64 instead."); } if (ignoreAddress_ && hash_ == ReplacedTextureHash::QUICK) { ignoreAddress_ = false; - ERROR_LOG(G3D, "Texture Replacement: ignoreAddress option requires safer hash, use xxh32 or xxh64 instead."); + ERROR_LOG(Log::G3D, "Texture Replacement: ignoreAddress option requires safer hash, use xxh32 or xxh64 instead."); } int version = 0; if (options->Get("version", &version, 0) && version > VERSION) { - ERROR_LOG(G3D, "Unsupported texture replacement version %d, trying anyway", version); + ERROR_LOG(Log::G3D, "Unsupported texture replacement version %d, trying anyway", version); } int badFileNameCount = 0; @@ -346,9 +346,9 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, VFSBackend *dir, bool isOverri } } } else if (item.first.empty()) { - INFO_LOG(G3D, "Ignoring [hashes] line with empty key: '= %s'", item.second.c_str()); + INFO_LOG(Log::G3D, "Ignoring [hashes] line with empty key: '= %s'", item.second.c_str()); } else { - ERROR_LOG(G3D, "Unsupported syntax under [hashes], ignoring: %s = ", item.first.c_str()); + ERROR_LOG(Log::G3D, "Unsupported syntax under [hashes], ignoring: %s = ", item.first.c_str()); } } } @@ -359,7 +359,7 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, VFSBackend *dir, bool isOverri if (badFileNameCount > 0) { auto err = GetI18NCategory(I18NCat::ERRORS); g_OSD.Show(OSDType::MESSAGE_WARNING, err->T("textures.ini filenames may not be cross - platform(banned characters)"), badFilenames, 6.0f); - WARN_LOG(G3D, "Potentially bad filenames: %s", badFilenames.c_str()); + WARN_LOG(Log::G3D, "Potentially bad filenames: %s", badFilenames.c_str()); } if (ini.HasSection("hashranges")) { @@ -396,7 +396,7 @@ void TextureReplacer::ParseHashRange(const std::string &key, const std::string & SplitString(value, ',', valueParts); if (keyParts.size() != 3 || valueParts.size() != 2) { - ERROR_LOG(G3D, "Ignoring invalid hashrange %s = %s, expecting addr,w,h = w,h", key.c_str(), value.c_str()); + ERROR_LOG(Log::G3D, "Ignoring invalid hashrange %s = %s, expecting addr,w,h = w,h", key.c_str(), value.c_str()); return; } @@ -409,19 +409,19 @@ void TextureReplacer::ParseHashRange(const std::string &key, const std::string & u32 fromW; u32 fromH; if (!TryParse(keyParts[0], &addr) || !TryParse(keyParts[1], &fromW) || !TryParse(keyParts[2], &fromH)) { - ERROR_LOG(G3D, "Ignoring invalid hashrange %s = %s, key format is 0x12345678,512,512", key.c_str(), value.c_str()); + ERROR_LOG(Log::G3D, "Ignoring invalid hashrange %s = %s, key format is 0x12345678,512,512", key.c_str(), value.c_str()); return; } u32 toW; u32 toH; if (!TryParse(valueParts[0], &toW) || !TryParse(valueParts[1], &toH)) { - ERROR_LOG(G3D, "Ignoring invalid hashrange %s = %s, value format is 512,512", key.c_str(), value.c_str()); + ERROR_LOG(Log::G3D, "Ignoring invalid hashrange %s = %s, value format is 512,512", key.c_str(), value.c_str()); return; } if (toW > fromW || toH > fromH) { - ERROR_LOG(G3D, "Ignoring invalid hashrange %s = %s, range bigger than source", key.c_str(), value.c_str()); + ERROR_LOG(Log::G3D, "Ignoring invalid hashrange %s = %s, range bigger than source", key.c_str(), value.c_str()); return; } @@ -439,10 +439,10 @@ void TextureReplacer::ParseFiltering(const std::string &key, const std::string & } else if (!strcasecmp(value.c_str(), "auto")) { filtering_[itemKey] = TEX_FILTER_AUTO; } else { - ERROR_LOG(G3D, "Unsupported syntax under [filtering]: %s", value.c_str()); + ERROR_LOG(Log::G3D, "Unsupported syntax under [filtering]: %s", value.c_str()); } } else { - ERROR_LOG(G3D, "Unsupported syntax under [filtering]: %s", key.c_str()); + ERROR_LOG(Log::G3D, "Unsupported syntax under [filtering]: %s", key.c_str()); } } @@ -453,25 +453,25 @@ void TextureReplacer::ParseReduceHashRange(const std::string& key, const std::st SplitString(value, ',', valueParts); if (keyParts.size() != 2 || valueParts.size() != 1) { - ERROR_LOG(G3D, "Ignoring invalid reducehashrange %s = %s, expecting w,h = reducehashvalue", key.c_str(), value.c_str()); + ERROR_LOG(Log::G3D, "Ignoring invalid reducehashrange %s = %s, expecting w,h = reducehashvalue", key.c_str(), value.c_str()); return; } u32 forW; u32 forH; if (!TryParse(keyParts[0], &forW) || !TryParse(keyParts[1], &forH)) { - ERROR_LOG(G3D, "Ignoring invalid reducehashrange %s = %s, key format is 512,512", key.c_str(), value.c_str()); + ERROR_LOG(Log::G3D, "Ignoring invalid reducehashrange %s = %s, key format is 512,512", key.c_str(), value.c_str()); return; } float rhashvalue; if (!TryParse(valueParts[0], &rhashvalue)) { - ERROR_LOG(G3D, "Ignoring invalid reducehashrange %s = %s, value format is 0.5", key.c_str(), value.c_str()); + ERROR_LOG(Log::G3D, "Ignoring invalid reducehashrange %s = %s, value format is 0.5", key.c_str(), value.c_str()); return; } if (rhashvalue == 0) { - ERROR_LOG(G3D, "Ignoring invalid hashrange %s = %s, reducehashvalue can't be 0", key.c_str(), value.c_str()); + ERROR_LOG(Log::G3D, "Ignoring invalid hashrange %s = %s, reducehashvalue can't be 0", key.c_str(), value.c_str()); return; } @@ -582,7 +582,7 @@ ReplacedTexture *TextureReplacer::FindReplacement(u64 cachekey, u32 hash, int w, // Early-out for ignored textures, let's not bother even starting a thread task. if (ignored) { - // WARN_LOG(G3D, "Not found/ignored: %s (%d, %d)", hashfiles.c_str(), (int)foundReplacement, (int)ignored); + // WARN_LOG(Log::G3D, "Not found/ignored: %s (%d, %d)", hashfiles.c_str(), (int)foundReplacement, (int)ignored); // Insert an entry into the cache for faster lookup next time. ReplacedTextureRef ref{}; cache_.emplace(std::make_pair(replacementKey, ref)); @@ -645,7 +645,7 @@ ReplacedTexture *TextureReplacer::FindReplacement(u64 cachekey, u32 hash, int w, static bool WriteTextureToPNG(png_imagep image, const Path &filename, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { FILE *fp = File::OpenCFile(filename, "wb"); if (!fp) { - ERROR_LOG(IO, "Unable to open texture file '%s' for writing.", filename.c_str()); + ERROR_LOG(Log::IO, "Unable to open texture file '%s' for writing.", filename.c_str()); return false; } @@ -653,7 +653,7 @@ static bool WriteTextureToPNG(png_imagep image, const Path &filename, int conver fclose(fp); return true; } else { - ERROR_LOG(SYSTEM, "Texture PNG encode failed."); + ERROR_LOG(Log::System, "Texture PNG encode failed."); fclose(fp); remove(filename.c_str()); return false; @@ -714,11 +714,11 @@ public: bool success = WriteTextureToPNG(&png, saveFilename, 0, rgbaData.data(), pitch, nullptr); png_image_free(&png); if (png.warning_or_error >= 2) { - ERROR_LOG(G3D, "Saving screenshot to PNG produced errors."); + ERROR_LOG(Log::G3D, "Saving texture to PNG produced errors."); } else if (success) { - NOTICE_LOG(G3D, "Saving texture for replacement: %08x / %dx%d in '%s'", replacedInfoHash, w, h, saveFilename.ToVisualString().c_str()); + NOTICE_LOG(Log::G3D, "Saving texture for replacement: %08x / %dx%d in '%s'", replacedInfoHash, w, h, saveFilename.ToVisualString().c_str()); } else { - ERROR_LOG(G3D, "Failed to write '%s'", saveFilename.c_str()); + ERROR_LOG(Log::G3D, "Failed to write '%s'", saveFilename.c_str()); } } }; @@ -853,7 +853,7 @@ void TextureReplacer::Decimate(ReplacerDecimateMode mode) { double totalSizeGB = totalSize / (1024.0 * 1024.0 * 1024.0); if (totalSizeGB >= 1.0) { - WARN_LOG(G3D, "Decimated replacements older than %fs, currently using %f GB of RAM", age, totalSizeGB); + WARN_LOG(Log::G3D, "Decimated replacements older than %fs, currently using %f GB of RAM", age, totalSizeGB); } lastTextureCacheSizeGB_ = totalSizeGB; } diff --git a/GPU/Common/TextureScalerCommon.cpp b/GPU/Common/TextureScalerCommon.cpp index a27e109c5c..bbcb497b8f 100644 --- a/GPU/Common/TextureScalerCommon.cpp +++ b/GPU/Common/TextureScalerCommon.cpp @@ -503,7 +503,7 @@ void bilinearH(int factor, const u32 *data, u32 *out, int w, int l, int u) { case 3: bilinearHt<3>(data, out, w, l, u); break; case 4: bilinearHt<4>(data, out, w, l, u); break; case 5: bilinearHt<5>(data, out, w, l, u); break; - default: ERROR_LOG(G3D, "Bilinear upsampling only implemented for factors 2 to 5"); + default: ERROR_LOG(Log::G3D, "Bilinear upsampling only implemented for factors 2 to 5"); } } // integral bilinear upscaling by factor f, vertical part @@ -537,7 +537,7 @@ void bilinearV(int factor, const u32 *data, u32 *out, int w, int gl, int gu, int case 3: bilinearVt<3>(data, out, w, gl, gu, l, u); break; case 4: bilinearVt<4>(data, out, w, gl, gu, l, u); break; case 5: bilinearVt<5>(data, out, w, gl, gu, l, u); break; - default: ERROR_LOG(G3D, "Bilinear upsampling only implemented for factors 2 to 5"); + default: ERROR_LOG(Log::G3D, "Bilinear upsampling only implemented for factors 2 to 5"); } } @@ -658,7 +658,7 @@ bool TextureScalerCommon::ScaleInto(u32 *outputBuf, u32 *src, int width, int hei ScaleHybrid(factor, inputBuf, outputBuf, width, height, true); break; default: - ERROR_LOG(G3D, "Unknown scaling type: %d", g_Config.iTexScalingType); + ERROR_LOG(Log::G3D, "Unknown scaling type: %d", g_Config.iTexScalingType); } // update values accordingly @@ -668,7 +668,7 @@ bool TextureScalerCommon::ScaleInto(u32 *outputBuf, u32 *src, int width, int hei #ifdef SCALING_MEASURE_TIME if (*scaledWidth* *scaledHeight > 64 * 64 * factor*factor) { double t = time_now_d() - t_start; - NOTICE_LOG(G3D, "TextureScaler: processed %9d pixels in %6.5lf seconds. (%9.2lf Mpixels/second)", + NOTICE_LOG(Log::G3D, "TextureScaler: processed %9d pixels in %6.5lf seconds. (%9.2lf Mpixels/second)", *scaledWidth * *scaledHeight, t, (*scaledWidth * *scaledHeight) / (t * 1000 * 1000)); } #endif @@ -680,7 +680,7 @@ bool TextureScalerCommon::Scale(u32* &data, int width, int height, int *scaledWi // prevent processing empty or flat textures (this happens a lot in some games) // doesn't hurt the standard case, will be very quick for textures with actual texture if (IsEmptyOrFlat(data, width*height)) { - DEBUG_LOG(G3D, "TextureScaler: early exit -- empty/flat texture"); + DEBUG_LOG(Log::G3D, "TextureScaler: early exit -- empty/flat texture"); return false; } diff --git a/GPU/Common/TextureShaderCommon.h b/GPU/Common/TextureShaderCommon.h index b029c739a6..37d2c32a52 100644 --- a/GPU/Common/TextureShaderCommon.h +++ b/GPU/Common/TextureShaderCommon.h @@ -22,12 +22,10 @@ #include #include "Common/CommonTypes.h" -#include "Common/GPU/Shader.h" #include "Common/GPU/thin3d.h" #include "GPU/ge_constants.h" #include "GPU/Common/Draw2D.h" #include "GPU/Common/ShaderCommon.h" -#include "GPU/Common/DepalettizeShaderCommon.h" class ClutTexture { diff --git a/GPU/Common/VertexDecoderArm.cpp b/GPU/Common/VertexDecoderArm.cpp index 257a0aa96c..6dc39e2ed3 100644 --- a/GPU/Common/VertexDecoderArm.cpp +++ b/GPU/Common/VertexDecoderArm.cpp @@ -258,7 +258,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int ResetCodePtr(GetOffset(start)); char temp[1024] = {0}; dec.ToString(temp, true); - INFO_LOG(G3D, "Could not compile vertex decoder: %s", temp); + INFO_LOG(Log::G3D, "Could not compile vertex decoder: %s", temp); return 0; } } @@ -286,7 +286,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int DisassembleArm(start, GetCodePtr() - start); char temp[1024] = {0}; dec.ToString(temp, true); - INFO_LOG(G3D, "%s", temp); + INFO_LOG(Log::G3D, "%s", temp); */ *jittedSize = GetCodePtr() - start; diff --git a/GPU/Common/VertexDecoderArm64.cpp b/GPU/Common/VertexDecoderArm64.cpp index e3675ee553..c79fb5bfcc 100644 --- a/GPU/Common/VertexDecoderArm64.cpp +++ b/GPU/Common/VertexDecoderArm64.cpp @@ -254,7 +254,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int ResetCodePtr(GetOffset(start)); char temp[1024] = {0}; dec.ToString(temp, true); - ERROR_LOG(G3D, "Could not compile vertex decoder, failed at step %d: %s", i, temp); + ERROR_LOG(Log::G3D, "Could not compile vertex decoder, failed at step %d: %s", i, temp); return nullptr; } } @@ -289,12 +289,12 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int if (log) { char temp[1024] = { 0 }; dec.ToString(temp, true); - INFO_LOG(JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start)); + INFO_LOG(Log::JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start)); std::vector lines = DisassembleArm64(start, (int)(GetCodePtr() - start)); for (auto line : lines) { - INFO_LOG(JIT, "%s", line.c_str()); + INFO_LOG(Log::JIT, "%s", line.c_str()); } - INFO_LOG(JIT, "=========="); + INFO_LOG(Log::JIT, "=========="); } *jittedSize = (int)(GetCodePtr() - start); diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 4921e3bba8..b7eb2ca315 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -36,6 +36,7 @@ #include "GPU/ge_constants.h" #include "GPU/Math3D.h" #include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/VertexDecoderHandwritten.h" static const u8 tcsize[4] = { 0, 2, 4, 8 }, tcalign[4] = { 0, 1, 2, 4 }; static const u8 colsize[8] = { 0, 0, 0, 0, 2, 2, 2, 4 }, colalign[8] = { 0, 0, 0, 0, 2, 2, 2, 4 }; @@ -137,13 +138,13 @@ void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBo } else if (idx == GE_VTYPE_IDX_32BIT) { int lowerBound = 0x7FFFFFFF; int upperBound = 0; - WARN_LOG_REPORT_ONCE(indexBounds32, G3D, "GetIndexBounds: Decoding 32-bit indexes"); + WARN_LOG_REPORT_ONCE(indexBounds32, Log::G3D, "GetIndexBounds: Decoding 32-bit indexes"); const u32_le *ind32 = (const u32_le *)inds; for (int i = 0; i < count; i++) { u16 value = (u16)ind32[i]; // These aren't documented and should be rare. Let's bounds check each one. if (ind32[i] != value) { - ERROR_LOG_REPORT_ONCE(indexBounds32Bounds, G3D, "GetIndexBounds: Index outside 16-bit range"); + ERROR_LOG_REPORT_ONCE(indexBounds32Bounds, Log::G3D, "GetIndexBounds: Index outside 16-bit range"); } if (value > upperBound) upperBound = value; @@ -189,33 +190,33 @@ void PrintDecodedVertex(const VertexReader &vtx) { printf("P: %f %f %f\n", pos[0], pos[1], pos[2]); } -void VertexDecoder::Step_WeightsU8() const -{ - u8 *wt = (u8 *)(decoded_ + decFmt.w0off); - const u8 *wdata = (const u8*)(ptr_); +void VertexDecoder::Step_WeightsU8(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + u8 *wt = (u8 *)(decoded + dec->decFmt.w0off); + const u8 *wdata = (const u8*)(ptr); int j; + const int nweights = dec->nweights; for (j = 0; j < nweights; j++) wt[j] = wdata[j]; while (j & 3) // Zero additional weights rounding up to 4. wt[j++] = 0; } -void VertexDecoder::Step_WeightsU16() const -{ - u16 *wt = (u16 *)(decoded_ + decFmt.w0off); - const u16_le *wdata = (const u16_le *)(ptr_); +void VertexDecoder::Step_WeightsU16(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + u16 *wt = (u16 *)(decoded + dec->decFmt.w0off); + const u16_le *wdata = (const u16_le *)(ptr); int j; + const int nweights = dec->nweights; for (j = 0; j < nweights; j++) wt[j] = wdata[j]; while (j & 3) // Zero additional weights rounding up to 4. wt[j++] = 0; } -void VertexDecoder::Step_WeightsU8ToFloat() const -{ - float *wt = (float *)(decoded_ + decFmt.w0off); - const u8 *wdata = (const u8*)(ptr_); +void VertexDecoder::Step_WeightsU8ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *wt = (float *)(decoded + dec->decFmt.w0off); + const u8 *wdata = (const u8*)(ptr); int j; + const int nweights = dec->nweights; for (j = 0; j < nweights; j++) { wt[j] = (float)wdata[j] * (1.0f / 128.0f); } @@ -223,11 +224,11 @@ void VertexDecoder::Step_WeightsU8ToFloat() const wt[j++] = 0; } -void VertexDecoder::Step_WeightsU16ToFloat() const -{ - float *wt = (float *)(decoded_ + decFmt.w0off); - const u16_le *wdata = (const u16_le *)(ptr_); +void VertexDecoder::Step_WeightsU16ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *wt = (float *)(decoded + dec->decFmt.w0off); + const u16_le *wdata = (const u16_le *)(ptr); int j; + const int nweights = dec->nweights; for (j = 0; j < nweights; j++) { wt[j] = (float)wdata[j] * (1.0f / 32768.0f); } @@ -238,12 +239,11 @@ void VertexDecoder::Step_WeightsU16ToFloat() const // Float weights should be uncommon, we can live with having to multiply these by 2.0 // to avoid special checks in the vertex shader generator. // (PSP uses 0.0-2.0 fixed point numbers for weights) -void VertexDecoder::Step_WeightsFloat() const -{ - float *wt = (float *)(decoded_ + decFmt.w0off); - const float_le *wdata = (const float_le *)(ptr_); +void VertexDecoder::Step_WeightsFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *wt = (float *)(decoded + dec->decFmt.w0off); + const float_le *wdata = (const float_le *)(ptr); int j; - for (j = 0; j < nweights; j++) { + for (j = 0; j < dec->nweights; j++) { wt[j] = wdata[j]; } while (j & 3) // Zero additional weights rounding up to 4. @@ -252,7 +252,41 @@ void VertexDecoder::Step_WeightsFloat() const void VertexDecoder::ComputeSkinMatrix(const float weights[8]) const { memset(skinMatrix, 0, sizeof(skinMatrix)); - for (int j = 0; j < nweights; j++) { + const int count = nweights; +#if PPSSPP_ARCH(SSE2) + __m128 skin0 = _mm_setzero_ps(); + __m128 skin1 = _mm_setzero_ps(); + __m128 skin2 = _mm_setzero_ps(); + for (int j = 0; j < count; j++) { + const float *bone = &gstate.boneMatrix[j * 12]; + if (weights[j] != 0.0f) { + __m128 w = _mm_set1_ps(weights[j]); + skin0 = _mm_add_ps(skin0, _mm_mul_ps(_mm_loadu_ps(bone), w)); + skin1 = _mm_add_ps(skin1, _mm_mul_ps(_mm_loadu_ps(bone + 4), w)); + skin2 = _mm_add_ps(skin2, _mm_mul_ps(_mm_loadu_ps(bone + 8), w)); + } + } + _mm_store_ps(skinMatrix, skin0); + _mm_store_ps(skinMatrix + 4, skin1); + _mm_store_ps(skinMatrix + 8, skin2); +#elif PPSSPP_ARCH(ARM_NEON) + float32x4_t skin0 = vdupq_n_f32(0.0f); + float32x4_t skin1 = vdupq_n_f32(0.0f); + float32x4_t skin2 = vdupq_n_f32(0.0f); + for (int j = 0; j < count; j++) { + const float *bone = &gstate.boneMatrix[j * 12]; + if (weights[j] != 0.0f) { + float32x4_t w = vdupq_n_f32(weights[j]); + skin0 = vaddq_f32(skin0, vmulq_f32(vld1q_f32(bone), w)); + skin1 = vaddq_f32(skin1, vmulq_f32(vld1q_f32(bone + 4), w)); + skin2 = vaddq_f32(skin2, vmulq_f32(vld1q_f32(bone + 8), w)); + } + } + vst1q_f32(skinMatrix, skin0); + vst1q_f32(skinMatrix + 4, skin1); + vst1q_f32(skinMatrix + 8, skin2); +#else + for (int j = 0; j < count; j++) { const float *bone = &gstate.boneMatrix[j * 12]; if (weights[j] != 0.0f) { for (int i = 0; i < 12; i++) { @@ -260,58 +294,57 @@ void VertexDecoder::ComputeSkinMatrix(const float weights[8]) const { } } } +#endif } -void VertexDecoder::Step_WeightsU8Skin() const { - const u8 *wdata = (const u8*)(ptr_); +void VertexDecoder::Step_WeightsU8Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + const u8 *wdata = (const u8*)(ptr); float weights[8]; + const int nweights = dec->nweights; for (int j = 0; j < nweights; j++) weights[j] = wdata[j] * (1.0f / 128.0f); - ComputeSkinMatrix(weights); + dec->ComputeSkinMatrix(weights); } -void VertexDecoder::Step_WeightsU16Skin() const { - const u16_le *wdata = (const u16_le *)(ptr_); +void VertexDecoder::Step_WeightsU16Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + const u16_le *wdata = (const u16_le *)(ptr); float weights[8]; + const int nweights = dec->nweights; for (int j = 0; j < nweights; j++) weights[j] = wdata[j] * (1.0f / 32768.0f); - ComputeSkinMatrix(weights); + dec->ComputeSkinMatrix(weights); } -void VertexDecoder::Step_WeightsFloatSkin() const { - const float_le *wdata = (const float_le *)(ptr_); - ComputeSkinMatrix(wdata); +void VertexDecoder::Step_WeightsFloatSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + const float_le *wdata = (const float_le *)(ptr); + dec->ComputeSkinMatrix(wdata); } -void VertexDecoder::Step_TcU8ToFloat() const -{ +void VertexDecoder::Step_TcU8ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { // u32 to write two bytes of zeroes for free. - float *uv = (float *)(decoded_ + decFmt.uvoff); - const u8 *uvdata = (const u8*)(ptr_ + tcoff); + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const u8 *uvdata = (const u8*)(ptr + dec->tcoff); uv[0] = uvdata[0] * (1.0f / 128.0f); uv[1] = uvdata[1] * (1.0f / 128.0f); } -void VertexDecoder::Step_TcU16ToFloat() const -{ - float *uv = (float *)(decoded_ + decFmt.uvoff); - const u16_le *uvdata = (const u16_le *)(ptr_ + tcoff); +void VertexDecoder::Step_TcU16ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->tcoff); uv[0] = uvdata[0] * (1.0f / 32768.0f); uv[1] = uvdata[1] * (1.0f / 32768.0f); } -void VertexDecoder::Step_TcU16DoubleToFloat() const -{ - float *uv = (float*)(decoded_ + decFmt.uvoff); - const u16_le *uvdata = (const u16_le *)(ptr_ + tcoff); +void VertexDecoder::Step_TcU16DoubleToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float*)(decoded + dec->decFmt.uvoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->tcoff); uv[0] = uvdata[0] * (1.0f / 16384.0f); uv[1] = uvdata[1] * (1.0f / 16384.0f); } -void VertexDecoder::Step_TcU16ThroughToFloat() const -{ - float *uv = (float *)(decoded_ + decFmt.uvoff); - const u16_le *uvdata = (const u16_le *)(ptr_ + tcoff); +void VertexDecoder::Step_TcU16ThroughToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->tcoff); uv[0] = uvdata[0]; uv[1] = uvdata[1]; @@ -321,26 +354,23 @@ void VertexDecoder::Step_TcU16ThroughToFloat() const gstate_c.vertBounds.maxV = std::max(gstate_c.vertBounds.maxV, (u16)uvdata[1]); } -void VertexDecoder::Step_TcU16ThroughDoubleToFloat() const -{ - float *uv = (float *)(decoded_ + decFmt.uvoff); - const u16_le *uvdata = (const u16_le *)(ptr_ + tcoff); +void VertexDecoder::Step_TcU16ThroughDoubleToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->tcoff); uv[0] = uvdata[0] * 2; uv[1] = uvdata[1] * 2; } -void VertexDecoder::Step_TcFloat() const -{ - float *uv = (float *)(decoded_ + decFmt.uvoff); - const float_le *uvdata = (const float_le *)(ptr_ + tcoff); +void VertexDecoder::Step_TcFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const float_le *uvdata = (const float_le *)(ptr + dec->tcoff); uv[0] = uvdata[0]; uv[1] = uvdata[1]; } -void VertexDecoder::Step_TcFloatThrough() const -{ - float *uv = (float *)(decoded_ + decFmt.uvoff); - const float_le *uvdata = (const float_le *)(ptr_ + tcoff); +void VertexDecoder::Step_TcFloatThrough(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const float_le *uvdata = (const float_le *)(ptr + dec->tcoff); uv[0] = uvdata[0]; uv[1] = uvdata[1]; @@ -350,365 +380,361 @@ void VertexDecoder::Step_TcFloatThrough() const gstate_c.vertBounds.maxV = std::max(gstate_c.vertBounds.maxV, (u16)uvdata[1]); } -void VertexDecoder::Step_TcU8Prescale() const { - float *uv = (float *)(decoded_ + decFmt.uvoff); - const u8 *uvdata = (const u8 *)(ptr_ + tcoff); - uv[0] = (float)uvdata[0] * (1.f / 128.f) * prescaleUV_->uScale + prescaleUV_->uOff; - uv[1] = (float)uvdata[1] * (1.f / 128.f) * prescaleUV_->vScale + prescaleUV_->vOff; +void VertexDecoder::Step_TcU8Prescale(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const u8 *uvdata = (const u8 *)(ptr + dec->tcoff); + uv[0] = (float)uvdata[0] * (1.f / 128.f) * dec->prescaleUV_->uScale + dec->prescaleUV_->uOff; + uv[1] = (float)uvdata[1] * (1.f / 128.f) * dec->prescaleUV_->vScale + dec->prescaleUV_->vOff; } -void VertexDecoder::Step_TcU16Prescale() const { - float *uv = (float *)(decoded_ + decFmt.uvoff); - const u16_le *uvdata = (const u16_le *)(ptr_ + tcoff); - uv[0] = (float)uvdata[0] * (1.f / 32768.f) * prescaleUV_->uScale + prescaleUV_->uOff; - uv[1] = (float)uvdata[1] * (1.f / 32768.f) * prescaleUV_->vScale + prescaleUV_->vOff; +void VertexDecoder::Step_TcU16Prescale(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->tcoff); + uv[0] = (float)uvdata[0] * (1.f / 32768.f) * dec->prescaleUV_->uScale + dec->prescaleUV_->uOff; + uv[1] = (float)uvdata[1] * (1.f / 32768.f) * dec->prescaleUV_->vScale + dec->prescaleUV_->vOff; } -void VertexDecoder::Step_TcU16DoublePrescale() const { - float *uv = (float *)(decoded_ + decFmt.uvoff); - const u16_le *uvdata = (const u16_le *)(ptr_ + tcoff); - uv[0] = (float)uvdata[0] * (1.f / 16384.f) * prescaleUV_->uScale + prescaleUV_->uOff; - uv[1] = (float)uvdata[1] * (1.f / 16384.f) * prescaleUV_->vScale + prescaleUV_->vOff; +void VertexDecoder::Step_TcU16DoublePrescale(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->tcoff); + uv[0] = (float)uvdata[0] * (1.f / 16384.f) * dec->prescaleUV_->uScale + dec->prescaleUV_->uOff; + uv[1] = (float)uvdata[1] * (1.f / 16384.f) * dec->prescaleUV_->vScale + dec->prescaleUV_->vOff; } -void VertexDecoder::Step_TcFloatPrescale() const { - float *uv = (float *)(decoded_ + decFmt.uvoff); - const float_le *uvdata = (const float_le *)(ptr_ + tcoff); - uv[0] = uvdata[0] * prescaleUV_->uScale + prescaleUV_->uOff; - uv[1] = uvdata[1] * prescaleUV_->vScale + prescaleUV_->vOff; +void VertexDecoder::Step_TcFloatPrescale(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *uv = (float *)(decoded + dec->decFmt.uvoff); + const float_le *uvdata = (const float_le *)(ptr + dec->tcoff); + uv[0] = uvdata[0] * dec->prescaleUV_->uScale + dec->prescaleUV_->uOff; + uv[1] = uvdata[1] * dec->prescaleUV_->vScale + dec->prescaleUV_->vOff; } -void VertexDecoder::Step_TcU8MorphToFloat() const { +void VertexDecoder::Step_TcU8MorphToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float uv[2] = { 0, 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const u8 *uvdata = (const u8 *)(ptr_ + onesize_*n + tcoff); + const u8 *uvdata = (const u8 *)(ptr + dec->onesize_*n + dec->tcoff); uv[0] += (float)uvdata[0] * (1.f / 128.f) * w; uv[1] += (float)uvdata[1] * (1.f / 128.f) * w; } - float *out = (float *)(decoded_ + decFmt.uvoff); + float *out = (float *)(decoded + dec->decFmt.uvoff); out[0] = uv[0]; out[1] = uv[1]; } -void VertexDecoder::Step_TcU16MorphToFloat() const { +void VertexDecoder::Step_TcU16MorphToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float uv[2] = { 0, 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const u16_le *uvdata = (const u16_le *)(ptr_ + onesize_*n + tcoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->onesize_*n + dec->tcoff); uv[0] += (float)uvdata[0] * (1.f / 32768.f) * w; uv[1] += (float)uvdata[1] * (1.f / 32768.f) * w; } - float *out = (float *)(decoded_ + decFmt.uvoff); + float *out = (float *)(decoded + dec->decFmt.uvoff); out[0] = uv[0]; out[1] = uv[1]; } -void VertexDecoder::Step_TcU16DoubleMorphToFloat() const { +void VertexDecoder::Step_TcU16DoubleMorphToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float uv[2] = { 0, 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const u16_le *uvdata = (const u16_le *)(ptr_ + onesize_*n + tcoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->onesize_*n + dec->tcoff); uv[0] += (float)uvdata[0] * (1.f / 16384.f) * w; uv[1] += (float)uvdata[1] * (1.f / 16384.f) * w; } - float *out = (float *)(decoded_ + decFmt.uvoff); + float *out = (float *)(decoded + dec->decFmt.uvoff); out[0] = uv[0]; out[1] = uv[1]; } -void VertexDecoder::Step_TcFloatMorph() const { +void VertexDecoder::Step_TcFloatMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float uv[2] = { 0, 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const float_le *uvdata = (const float_le *)(ptr_ + onesize_*n + tcoff); + const float_le *uvdata = (const float_le *)(ptr + dec->onesize_*n + dec->tcoff); uv[0] += (float)uvdata[0] * w; uv[1] += (float)uvdata[1] * w; } - float *out = (float *)(decoded_ + decFmt.uvoff); + float *out = (float *)(decoded + dec->decFmt.uvoff); out[0] = uv[0]; out[1] = uv[1]; } -void VertexDecoder::Step_TcU8PrescaleMorph() const { +void VertexDecoder::Step_TcU8PrescaleMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float uv[2] = { 0, 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const u8 *uvdata = (const u8 *)(ptr_ + onesize_*n + tcoff); + const u8 *uvdata = (const u8 *)(ptr + dec->onesize_*n + dec->tcoff); uv[0] += (float)uvdata[0] * (1.f / 128.f) * w; uv[1] += (float)uvdata[1] * (1.f / 128.f) * w; } - float *out = (float *)(decoded_ + decFmt.uvoff); - out[0] = uv[0] * prescaleUV_->uScale + prescaleUV_->uOff; - out[1] = uv[1] * prescaleUV_->vScale + prescaleUV_->vOff; + float *out = (float *)(decoded + dec->decFmt.uvoff); + out[0] = uv[0] * dec->prescaleUV_->uScale + dec->prescaleUV_->uOff; + out[1] = uv[1] * dec->prescaleUV_->vScale + dec->prescaleUV_->vOff; } -void VertexDecoder::Step_TcU16PrescaleMorph() const { +void VertexDecoder::Step_TcU16PrescaleMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float uv[2] = { 0, 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const u16_le *uvdata = (const u16_le *)(ptr_ + onesize_*n + tcoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->onesize_*n + dec->tcoff); uv[0] += (float)uvdata[0] * (1.f / 32768.f) * w; uv[1] += (float)uvdata[1] * (1.f / 32768.f) * w; } - float *out = (float *)(decoded_ + decFmt.uvoff); - out[0] = uv[0] * prescaleUV_->uScale + prescaleUV_->uOff; - out[1] = uv[1] * prescaleUV_->vScale + prescaleUV_->vOff; + float *out = (float *)(decoded + dec->decFmt.uvoff); + out[0] = uv[0] * dec->prescaleUV_->uScale + dec->prescaleUV_->uOff; + out[1] = uv[1] * dec->prescaleUV_->vScale + dec->prescaleUV_->vOff; } -void VertexDecoder::Step_TcU16DoublePrescaleMorph() const { +void VertexDecoder::Step_TcU16DoublePrescaleMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float uv[2] = { 0, 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const u16_le *uvdata = (const u16_le *)(ptr_ + onesize_*n + tcoff); + const u16_le *uvdata = (const u16_le *)(ptr + dec->onesize_*n + dec->tcoff); uv[0] += (float)uvdata[0] * (1.f / 16384.f) * w; uv[1] += (float)uvdata[1] * (1.f / 16384.f) * w; } - float *out = (float *)(decoded_ + decFmt.uvoff); - out[0] = uv[0] * prescaleUV_->uScale + prescaleUV_->uOff; - out[1] = uv[1] * prescaleUV_->vScale + prescaleUV_->vOff; + float *out = (float *)(decoded + dec->decFmt.uvoff); + out[0] = uv[0] * dec->prescaleUV_->uScale + dec->prescaleUV_->uOff; + out[1] = uv[1] * dec->prescaleUV_->vScale + dec->prescaleUV_->vOff; } -void VertexDecoder::Step_TcFloatPrescaleMorph() const { +void VertexDecoder::Step_TcFloatPrescaleMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float uv[2] = { 0, 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const float_le *uvdata = (const float_le *)(ptr_ + onesize_*n + tcoff); + const float_le *uvdata = (const float_le *)(ptr + dec->onesize_*n + dec->tcoff); uv[0] += (float)uvdata[0] * w; uv[1] += (float)uvdata[1] * w; } - float *out = (float *)(decoded_ + decFmt.uvoff); - out[0] = uv[0] * prescaleUV_->uScale + prescaleUV_->uOff; - out[1] = uv[1] * prescaleUV_->vScale + prescaleUV_->vOff; + float *out = (float *)(decoded + dec->decFmt.uvoff); + out[0] = uv[0] * dec->prescaleUV_->uScale + dec->prescaleUV_->uOff; + out[1] = uv[1] * dec->prescaleUV_->vScale + dec->prescaleUV_->vOff; } -void VertexDecoder::Step_ColorInvalid() const -{ +void VertexDecoder::Step_ColorInvalid(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { // Do nothing. This is only here to prevent crashes. } -void VertexDecoder::Step_Color565() const -{ - u8 *c = decoded_ + decFmt.c0off; - u16 cdata = *(const u16_le *)(ptr_ + coloff); - c[0] = Convert5To8(cdata & 0x1f); - c[1] = Convert6To8((cdata >> 5) & 0x3f); - c[2] = Convert5To8((cdata >> 11) & 0x1f); - c[3] = 255; - // Always full alpha. +void VertexDecoder::Step_Color565(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + u16 cdata = *(const u16_le *)(ptr + dec->coloff); + u32 *c = (u32 *)(decoded + dec->decFmt.c0off); + *c = RGB565ToRGBA8888(cdata); } -void VertexDecoder::Step_Color5551() const -{ - u8 *c = decoded_ + decFmt.c0off; - u16 cdata = *(const u16_le *)(ptr_ + coloff); - gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (cdata >> 15) != 0; - c[0] = Convert5To8(cdata & 0x1f); - c[1] = Convert5To8((cdata >> 5) & 0x1f); - c[2] = Convert5To8((cdata >> 10) & 0x1f); - c[3] = (cdata >> 15) ? 255 : 0; +void VertexDecoder::Step_Color5551(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + u16 cdata = *(const u16_le *)(ptr + dec->coloff); + u32 *c = (u32 *)(decoded + dec->decFmt.c0off); + int alpha = (cdata >> 15); + if (!alpha) { + gstate_c.vertexFullAlpha = false; + } + *c = RGBA5551ToRGBA8888(cdata); } -void VertexDecoder::Step_Color4444() const -{ - u8 *c = decoded_ + decFmt.c0off; - u16 cdata = *(const u16_le *)(ptr_ + coloff); - gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (cdata >> 12) == 0xF; - for (int j = 0; j < 4; j++) - c[j] = Convert4To8((cdata >> (j * 4)) & 0xF); +void VertexDecoder::Step_Color4444(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + u16 cdata = *(const u16_le *)(ptr + dec->coloff); + u32 *c = (u32 *)(decoded + dec->decFmt.c0off); + if ((cdata >> 12) != 0xF) { + gstate_c.vertexFullAlpha = false; + } + *c = RGBA4444ToRGBA8888(cdata); } -void VertexDecoder::Step_Color8888() const -{ - u8 *c = decoded_ + decFmt.c0off; - const u8 *cdata = (const u8*)(ptr_ + coloff); - gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && cdata[3] == 255; +void VertexDecoder::Step_Color8888(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + u8 *c = decoded + dec->decFmt.c0off; + const u8 *cdata = (const u8*)(ptr + dec->coloff); + if (cdata[3] != 255) { + gstate_c.vertexFullAlpha = false; + } memcpy(c, cdata, sizeof(u8) * 4); } -void VertexDecoder::Step_Color565Morph() const -{ +void VertexDecoder::Step_Color565Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float col[3] = { 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - u16 cdata = *(const u16_le *)(ptr_ + onesize_*n + coloff); + u16 cdata = *(const u16_le *)(ptr + dec->onesize_*n + dec->coloff); col[0] += w * (cdata & 0x1f) * (255.0f / 31.0f); col[1] += w * ((cdata >> 5) & 0x3f) * (255.0f / 63.0f); col[2] += w * ((cdata >> 11) & 0x1f) * (255.0f / 31.0f); } - u8 *c = decoded_ + decFmt.c0off; + u8 *c = decoded + dec->decFmt.c0off; for (int i = 0; i < 3; i++) { c[i] = clamp_u8((int)col[i]); } c[3] = 255; - // Always full alpha. + // Always full alpha. (Is this true??) } -void VertexDecoder::Step_Color5551Morph() const -{ +void VertexDecoder::Step_Color5551Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float col[4] = { 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - u16 cdata = *(const u16_le *)(ptr_ + onesize_*n + coloff); + u16 cdata = *(const u16_le *)(ptr + dec->onesize_*n + dec->coloff); col[0] += w * (cdata & 0x1f) * (255.0f / 31.0f); col[1] += w * ((cdata >> 5) & 0x1f) * (255.0f / 31.0f); col[2] += w * ((cdata >> 10) & 0x1f) * (255.0f / 31.0f); col[3] += w * ((cdata >> 15) ? 255.0f : 0.0f); } - u8 *c = decoded_ + decFmt.c0off; + u8 *c = decoded + dec->decFmt.c0off; for (int i = 0; i < 4; i++) { c[i] = clamp_u8((int)col[i]); } gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (int)col[3] >= 255; } -void VertexDecoder::Step_Color4444Morph() const -{ +void VertexDecoder::Step_Color4444Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float col[4] = { 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - u16 cdata = *(const u16_le *)(ptr_ + onesize_*n + coloff); + u16 cdata = *(const u16_le *)(ptr + dec->onesize_*n + dec->coloff); for (int j = 0; j < 4; j++) col[j] += w * ((cdata >> (j * 4)) & 0xF) * (255.0f / 15.0f); } - u8 *c = decoded_ + decFmt.c0off; + u8 *c = decoded + dec->decFmt.c0off; for (int i = 0; i < 4; i++) { c[i] = clamp_u8((int)col[i]); } gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (int)col[3] >= 255; } -void VertexDecoder::Step_Color8888Morph() const -{ +void VertexDecoder::Step_Color8888Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { float col[4] = { 0 }; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float w = gstate_c.morphWeights[n]; - const u8 *cdata = (const u8*)(ptr_ + onesize_*n + coloff); + const u8 *cdata = (const u8*)(ptr + dec->onesize_*n + dec->coloff); for (int j = 0; j < 4; j++) col[j] += w * cdata[j]; } - u8 *c = decoded_ + decFmt.c0off; + u8 *c = decoded + dec->decFmt.c0off; for (int i = 0; i < 4; i++) { c[i] = clamp_u8((int)col[i]); } gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (int)col[3] >= 255; } -void VertexDecoder::Step_NormalS8() const -{ - s8 *normal = (s8 *)(decoded_ + decFmt.nrmoff); - const s8 *sv = (const s8*)(ptr_ + nrmoff); +void VertexDecoder::Step_NormalS8(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + s8 *normal = (s8 *)(decoded + dec->decFmt.nrmoff); + const s8 *sv = (const s8*)(ptr + dec->nrmoff); for (int j = 0; j < 3; j++) normal[j] = sv[j]; normal[3] = 0; } -void VertexDecoder::Step_NormalS8ToFloat() const -{ - float *normal = (float *)(decoded_ + decFmt.nrmoff); - const s8 *sv = (const s8*)(ptr_ + nrmoff); - normal[0] = sv[0] * (1.0f / 128.0f); - normal[1] = sv[1] * (1.0f / 128.0f); - normal[2] = sv[2] * (1.0f / 128.0f); +void VertexDecoder::Step_NormalS8ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); + const s8 *sv = (const s8*)(ptr + dec->nrmoff); + normal[0] = (float)sv[0] * (1.0f / 128.0f); + normal[1] = (float)sv[1] * (1.0f / 128.0f); + normal[2] = (float)sv[2] * (1.0f / 128.0f); } -void VertexDecoder::Step_NormalS16() const -{ - s16 *normal = (s16 *)(decoded_ + decFmt.nrmoff); - const s16_le *sv = (const s16_le *)(ptr_ + nrmoff); +void VertexDecoder::Step_NormalS16(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + s16 *normal = (s16 *)(decoded + dec->decFmt.nrmoff); + const s16_le *sv = (const s16_le *)(ptr + dec->nrmoff); for (int j = 0; j < 3; j++) normal[j] = sv[j]; normal[3] = 0; } -void VertexDecoder::Step_NormalFloat() const -{ - u32 *normal = (u32 *)(decoded_ + decFmt.nrmoff); - const u32_le *fv = (const u32_le *)(ptr_ + nrmoff); +void VertexDecoder::Step_NormalFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + u32 *normal = (u32 *)(decoded + dec->decFmt.nrmoff); + const u32_le *fv = (const u32_le *)(ptr + dec->nrmoff); for (int j = 0; j < 3; j++) normal[j] = fv[j]; } -void VertexDecoder::Step_NormalS8Skin() const -{ - float *normal = (float *)(decoded_ + decFmt.nrmoff); - const s8 *sv = (const s8*)(ptr_ + nrmoff); +void VertexDecoder::Step_NormalS8Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); + const s8 *sv = (const s8*)(ptr + dec->nrmoff); const float fn[3] = { sv[0] * (1.0f / 128.0f), sv[1] * (1.0f / 128.0f), sv[2] * (1.0f / 128.0f) }; Norm3ByMatrix43(normal, fn, skinMatrix); } -void VertexDecoder::Step_NormalS16Skin() const -{ - float *normal = (float *)(decoded_ + decFmt.nrmoff); - const s16_le *sv = (const s16_le *)(ptr_ + nrmoff); +void VertexDecoder::Step_NormalS16Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); + const s16_le *sv = (const s16_le *)(ptr + dec->nrmoff); const float fn[3] = { sv[0] * (1.0f / 32768.0f), sv[1] * (1.0f / 32768.0f), sv[2] * (1.0f / 32768.0f) }; Norm3ByMatrix43(normal, fn, skinMatrix); } -void VertexDecoder::Step_NormalFloatSkin() const -{ - float *normal = (float *)(decoded_ + decFmt.nrmoff); - const float_le *fn = (const float_le *)(ptr_ + nrmoff); +void VertexDecoder::Step_NormalFloatSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); + const float_le *fn = (const float_le *)(ptr + dec->nrmoff); Norm3ByMatrix43(normal, fn, skinMatrix); } -void VertexDecoder::Step_NormalS8Morph() const -{ - float *normal = (float *)(decoded_ + decFmt.nrmoff); +void VertexDecoder::Step_NormalS8Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); memset(normal, 0, sizeof(float) * 3); + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { - const s8 *bv = (const s8*)(ptr_ + onesize_*n + nrmoff); + const s8 *bv = (const s8*)(ptr + dec->onesize_*n + dec->nrmoff); const float multiplier = gstate_c.morphWeights[n] * (1.0f / 128.0f); for (int j = 0; j < 3; j++) normal[j] += bv[j] * multiplier; } } -void VertexDecoder::Step_NormalS16Morph() const -{ - float *normal = (float *)(decoded_ + decFmt.nrmoff); +void VertexDecoder::Step_NormalS16Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); memset(normal, 0, sizeof(float) * 3); + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { - const s16_le *sv = (const s16_le *)(ptr_ + onesize_*n + nrmoff); + const s16_le *sv = (const s16_le *)(ptr + dec->onesize_*n + dec->nrmoff); const float multiplier = gstate_c.morphWeights[n] * (1.0f / 32768.0f); for (int j = 0; j < 3; j++) normal[j] += sv[j] * multiplier; } } -void VertexDecoder::Step_NormalFloatMorph() const -{ - float *normal = (float *)(decoded_ + decFmt.nrmoff); +void VertexDecoder::Step_NormalFloatMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); memset(normal, 0, sizeof(float) * 3); + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float multiplier = gstate_c.morphWeights[n]; - const float_le *fv = (const float_le *)(ptr_ + onesize_*n + nrmoff); + const float_le *fv = (const float_le *)(ptr + dec->onesize_*n + dec->nrmoff); for (int j = 0; j < 3; j++) normal[j] += fv[j] * multiplier; } } -void VertexDecoder::Step_NormalS8MorphSkin() const { - float *normal = (float *)(decoded_ + decFmt.nrmoff); +void VertexDecoder::Step_NormalS8MorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); float nrm[3]{}; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { - const s8 *bv = (const s8*)(ptr_ + onesize_ * n + nrmoff); + const s8 *bv = (const s8*)(ptr + dec->onesize_ * n + dec->nrmoff); const float multiplier = gstate_c.morphWeights[n] * (1.0f / 128.0f); for (int j = 0; j < 3; j++) nrm[j] += bv[j] * multiplier; @@ -716,11 +742,12 @@ void VertexDecoder::Step_NormalS8MorphSkin() const { Norm3ByMatrix43(normal, nrm, skinMatrix); } -void VertexDecoder::Step_NormalS16MorphSkin() const { - float *normal = (float *)(decoded_ + decFmt.nrmoff); +void VertexDecoder::Step_NormalS16MorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); float nrm[3]{}; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { - const s16_le *sv = (const s16_le *)(ptr_ + onesize_ * n + nrmoff); + const s16_le *sv = (const s16_le *)(ptr + dec->onesize_ * n + dec->nrmoff); const float multiplier = gstate_c.morphWeights[n] * (1.0f / 32768.0f); for (int j = 0; j < 3; j++) nrm[j] += sv[j] * multiplier; @@ -728,162 +755,158 @@ void VertexDecoder::Step_NormalS16MorphSkin() const { Norm3ByMatrix43(normal, nrm, skinMatrix); } -void VertexDecoder::Step_NormalFloatMorphSkin() const { - float *normal = (float *)(decoded_ + decFmt.nrmoff); +void VertexDecoder::Step_NormalFloatMorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *normal = (float *)(decoded + dec->decFmt.nrmoff); float nrm[3]{}; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { float multiplier = gstate_c.morphWeights[n]; - const float_le *fv = (const float_le *)(ptr_ + onesize_ * n + nrmoff); + const float_le *fv = (const float_le *)(ptr + dec->onesize_ * n + dec->nrmoff); for (int j = 0; j < 3; j++) nrm[j] += fv[j] * multiplier; } Norm3ByMatrix43(normal, nrm, skinMatrix); } -void VertexDecoder::Step_PosS8() const -{ - float *pos = (float *)(decoded_ + decFmt.posoff); - const s8 *sv = (const s8*)(ptr_ + posoff); +void VertexDecoder::Step_PosS8(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *pos = (float *)(decoded + dec->decFmt.posoff); + const s8 *sv = (const s8*)(ptr + dec->posoff); for (int j = 0; j < 3; j++) pos[j] = sv[j] * (1.0f / 128.0f); } -void VertexDecoder::Step_PosS16() const -{ - float *pos = (float *)(decoded_ + decFmt.posoff); - const s16_le *sv = (const s16_le *)(ptr_ + posoff); +void VertexDecoder::Step_PosS16(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *pos = (float *)(decoded + dec->decFmt.posoff); + const s16_le *sv = (const s16_le *)(ptr + dec->posoff); for (int j = 0; j < 3; j++) pos[j] = sv[j] * (1.0f / 32768.0f); } -void VertexDecoder::Step_PosFloat() const -{ - u8 *v = (u8 *)(decoded_ + decFmt.posoff); - const u8 *fv = (const u8*)(ptr_ + posoff); +void VertexDecoder::Step_PosFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + u8 *v = (u8 *)(decoded + dec->decFmt.posoff); + const u8 *fv = (const u8*)(ptr + dec->posoff); memcpy(v, fv, 12); } -void VertexDecoder::Step_PosS8Skin() const -{ - float *pos = (float *)(decoded_ + decFmt.posoff); - const s8 *sv = (const s8*)(ptr_ + posoff); +void VertexDecoder::Step_PosS8Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *pos = (float *)(decoded + dec->decFmt.posoff); + const s8 *sv = (const s8*)(ptr + dec->posoff); const float fn[3] = { sv[0] * (1.0f / 128.0f), sv[1] * (1.0f / 128.0f), sv[2] * (1.0f / 128.0f) }; Vec3ByMatrix43(pos, fn, skinMatrix); } -void VertexDecoder::Step_PosS16Skin() const -{ - float *pos = (float *)(decoded_ + decFmt.posoff); - const s16_le *sv = (const s16_le *)(ptr_ + posoff); +void VertexDecoder::Step_PosS16Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *pos = (float *)(decoded + dec->decFmt.posoff); + const s16_le *sv = (const s16_le *)(ptr + dec->posoff); const float fn[3] = { sv[0] * (1.0f / 32768.0f), sv[1] * (1.0f / 32768.0f), sv[2] * (1.0f / 32768.0f) }; Vec3ByMatrix43(pos, fn, skinMatrix); } -void VertexDecoder::Step_PosFloatSkin() const -{ - float *pos = (float *)(decoded_ + decFmt.posoff); - const float_le *fn = (const float_le *)(ptr_ + posoff); +void VertexDecoder::Step_PosFloatSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *pos = (float *)(decoded + dec->decFmt.posoff); + const float_le *fn = (const float_le *)(ptr + dec->posoff); Vec3ByMatrix43(pos, fn, skinMatrix); } -void VertexDecoder::Step_PosInvalid() const { +void VertexDecoder::Step_PosInvalid(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { // Invalid positions are just culled. Simulate by forcing invalid values. - float *v = (float *)(decoded_ + decFmt.posoff); + float *v = (float *)(decoded + dec->decFmt.posoff); v[0] = std::numeric_limits::infinity(); v[1] = std::numeric_limits::infinity(); v[2] = std::numeric_limits::infinity(); } -void VertexDecoder::Step_PosS8Through() const { +void VertexDecoder::Step_PosS8Through(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { // 8-bit positions in throughmode always decode to 0, depth included. - float *v = (float *)(decoded_ + decFmt.posoff); + float *v = (float *)(decoded + dec->decFmt.posoff); v[0] = 0; v[1] = 0; v[2] = 0; } -void VertexDecoder::Step_PosS16Through() const -{ - float *v = (float *)(decoded_ + decFmt.posoff); - const s16_le *sv = (const s16_le *)(ptr_ + posoff); - const u16_le *uv = (const u16_le *)(ptr_ + posoff); +void VertexDecoder::Step_PosS16Through(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *v = (float *)(decoded + dec->decFmt.posoff); + const s16_le *sv = (const s16_le *)(ptr + dec->posoff); + const u16_le *uv = (const u16_le *)(ptr + dec->posoff); v[0] = sv[0]; v[1] = sv[1]; v[2] = uv[2]; } -void VertexDecoder::Step_PosFloatThrough() const -{ - float *v = (float *)(decoded_ + decFmt.posoff); - const float *fv = (const float *)(ptr_ + posoff); +void VertexDecoder::Step_PosFloatThrough(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *v = (float *)(decoded + dec->decFmt.posoff); + const float *fv = (const float *)(ptr + dec->posoff); memcpy(v, fv, 8); v[2] = fv[2] > 65535.0f ? 65535.0f : (fv[2] < 0.0f ? 0.0f : fv[2]); } -void VertexDecoder::Step_PosS8Morph() const -{ - float *v = (float *)(decoded_ + decFmt.posoff); +void VertexDecoder::Step_PosS8Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *v = (float *)(decoded + dec->decFmt.posoff); memset(v, 0, sizeof(float) * 3); + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { const float multiplier = 1.0f / 128.0f; - const s8 *sv = (const s8*)(ptr_ + onesize_*n + posoff); + const s8 *sv = (const s8*)(ptr + dec->onesize_*n + dec->posoff); for (int j = 0; j < 3; j++) v[j] += (float)sv[j] * (multiplier * gstate_c.morphWeights[n]); } } -void VertexDecoder::Step_PosS16Morph() const -{ - float *v = (float *)(decoded_ + decFmt.posoff); +void VertexDecoder::Step_PosS16Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *v = (float *)(decoded + dec->decFmt.posoff); memset(v, 0, sizeof(float) * 3); + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { const float multiplier = 1.0f / 32768.0f; - const s16_le *sv = (const s16_le *)(ptr_ + onesize_*n + posoff); + const s16_le *sv = (const s16_le *)(ptr + dec->onesize_*n + dec->posoff); for (int j = 0; j < 3; j++) v[j] += (float)sv[j] * (multiplier * gstate_c.morphWeights[n]); } } -void VertexDecoder::Step_PosFloatMorph() const -{ - float *v = (float *)(decoded_ + decFmt.posoff); +void VertexDecoder::Step_PosFloatMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *v = (float *)(decoded + dec->decFmt.posoff); memset(v, 0, sizeof(float) * 3); + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { - const float_le *fv = (const float_le *)(ptr_ + onesize_*n + posoff); + const float_le *fv = (const float_le *)(ptr + dec->onesize_*n + dec->posoff); for (int j = 0; j < 3; j++) v[j] += fv[j] * gstate_c.morphWeights[n]; } } -void VertexDecoder::Step_PosS8MorphSkin() const { - float *v = (float *)(decoded_ + decFmt.posoff); +void VertexDecoder::Step_PosS8MorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *v = (float *)(decoded + dec->decFmt.posoff); float pos[3]{}; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { const float multiplier = 1.0f / 128.0f; - const s8 *sv = (const s8*)(ptr_ + onesize_ * n + posoff); + const s8 *sv = (const s8*)(ptr + dec->onesize_ * n + dec->posoff); for (int j = 0; j < 3; j++) pos[j] += (float)sv[j] * (multiplier * gstate_c.morphWeights[n]); } Vec3ByMatrix43(v, pos, skinMatrix); } -void VertexDecoder::Step_PosS16MorphSkin() const { - float *v = (float *)(decoded_ + decFmt.posoff); +void VertexDecoder::Step_PosS16MorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *v = (float *)(decoded + dec->decFmt.posoff); float pos[3]{}; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { const float multiplier = 1.0f / 32768.0f; - const s16_le *sv = (const s16_le *)(ptr_ + onesize_ * n + posoff); + const s16_le *sv = (const s16_le *)(ptr + dec->onesize_ * n + dec->posoff); for (int j = 0; j < 3; j++) pos[j] += (float)sv[j] * (multiplier * gstate_c.morphWeights[n]); } Vec3ByMatrix43(v, pos, skinMatrix); } -void VertexDecoder::Step_PosFloatMorphSkin() const { - float *v = (float *)(decoded_ + decFmt.posoff); +void VertexDecoder::Step_PosFloatMorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded) { + float *v = (float *)(decoded + dec->decFmt.posoff); float pos[3]{}; + const int morphcount = dec->morphcount; for (int n = 0; n < morphcount; n++) { - const float_le *fv = (const float_le *)(ptr_ + onesize_ * n + posoff); + const float_le *fv = (const float_le *)(ptr + dec->onesize_ * n + dec->posoff); for (int j = 0; j < 3; j++) pos[j] += fv[j] * gstate_c.morphWeights[n]; } @@ -1097,9 +1120,9 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, memset(&decFmt, 0, sizeof(decFmt)); if (morphcount > 1) { - DEBUG_LOG_REPORT_ONCE(vtypeM, G3D, "VTYPE with morph used: THRU=%i TC=%i COL=%i POS=%i NRM=%i WT=%i NW=%i IDX=%i MC=%i", (int)throughmode, tc, col, pos, nrm, weighttype, nweights, idx, morphcount); + DEBUG_LOG_REPORT_ONCE(vtypeM, Log::G3D, "VTYPE with morph used: THRU=%i TC=%i COL=%i POS=%i NRM=%i WT=%i NW=%i IDX=%i MC=%i", (int)throughmode, tc, col, pos, nrm, weighttype, nweights, idx, morphcount); } else { - DEBUG_LOG(G3D, "VTYPE: THRU=%i TC=%i COL=%i POS=%i NRM=%i WT=%i NW=%i IDX=%i MC=%i", (int)throughmode, tc, col, pos, nrm, weighttype, nweights, idx, morphcount); + DEBUG_LOG(Log::G3D, "VTYPE: THRU=%i TC=%i COL=%i POS=%i NRM=%i WT=%i NW=%i IDX=%i MC=%i", (int)throughmode, tc, col, pos, nrm, weighttype, nweights, idx, morphcount); } skinInDecode = weighttype != 0 && options.applySkinInDecode; @@ -1265,29 +1288,45 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, decOff += DecFmtSize(DecVtxFormat::PosFmt()); } - decFmt.stride = options.alignOutputToWord ? align(decOff, 4) : decOff; + decFmt.stride = align(decOff, 4); decFmt.ComputeID(); size = align(size, biggest); onesize_ = size; size *= morphcount; - DEBUG_LOG(G3D, "SVT : size = %i, aligned to biggest %i", size, biggest); + DEBUG_LOG(Log::G3D, "SVT : size = %i, aligned to biggest %i", size, biggest); if (reportNoPos) { char temp[256]{}; ToString(temp, true); - ERROR_LOG_REPORT(G3D, "Vertices without position found: (%08x) %s", fmt_, temp); + ERROR_LOG_REPORT(Log::G3D, "Vertices without position found: (%08x) %s", fmt_, temp); } _assert_msg_(decFmt.uvfmt == DEC_FLOAT_2 || decFmt.uvfmt == DEC_NONE, "Reader only supports float UV"); + // Only use the handwritten decoders if we have SSE or NEON. Don't want to use these on RISC-V, probably? +#if PPSSPP_ARCH(ARM_NEON) || PPSSPP_ARCH(SSE2) + // See GetVertTypeID + uint32_t fmtWithoutSkinFlag = (fmt_ & ~0x04000000); + if (fmtWithoutSkinFlag == (GE_VTYPE_TC_8BIT | GE_VTYPE_COL_5551 | GE_VTYPE_POS_16BIT)) { + // Can skip looking up in the JIT. + jitted_ = &VtxDec_Tu8_C5551_Ps16; + return; + } + // Fails to update alphaFull properly. + else if (!options.expand8BitNormalsToFloat && fmtWithoutSkinFlag == (GE_VTYPE_TC_16BIT | GE_VTYPE_NRM_8BIT | GE_VTYPE_COL_8888 | GE_VTYPE_POS_FLOAT)) { + jitted_ = &VtxDec_Tu16_C8888_Pfloat; + return; + } +#endif + // Attempt to JIT as well. But only do that if the main CPU JIT is enabled, in order to aid // debugging attempts - if the main JIT doesn't work, this one won't do any better, probably. if (jitCache) { jitted_ = jitCache->Compile(*this, &jittedSize_); if (!jitted_) { - WARN_LOG(G3D, "Vertex decoder JIT failed! fmt = %08x (%s)", fmt_, GetString(SHADER_STRING_SHORT_DESC).c_str()); + WARN_LOG(Log::G3D, "Vertex decoder JIT failed! fmt = %08x (%s)", fmt_, GetString(SHADER_STRING_SHORT_DESC).c_str()); } } } @@ -1303,6 +1342,10 @@ void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const UVScale int count = indexUpperBound - indexLowerBound + 1; int stride = decFmt.stride; +#ifdef _DEBUG + decodedCount += count; +#endif + // Check alignment before running the decoder, as we may crash if it's bad (as should the real PSP but doesn't always) if (((uintptr_t)verts & (biggest - 1)) != 0) { // Bad alignment. Not really sure what to do here... zero the verts to be safe? @@ -1314,18 +1357,18 @@ void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const UVScale // We've compiled the steps into optimized machine code, so just jump! jitted_(startPtr, decodedptr, count, uvScaleOffset); } else { - ptr_ = startPtr; - decoded_ = decodedptr; + const u8 *ptr = startPtr; + u8 *decoded = decodedptr; prescaleUV_ = uvScaleOffset; // Interpret the decode steps for (; count; count--) { - for (int i = 0; i < numSteps_; i++) { - ((*this).*steps_[i])(); + const int steps = numSteps_; + for (int i = 0; i < steps; i++) { + steps_[i](this, ptr, decoded); } - ptr_ += size; - decoded_ += stride; + ptr += size; + decoded += stride; } - if (jitted_ && validateJit) { CompareToJit(startPtr, decodedptr, indexUpperBound - indexLowerBound + 1, uvScaleOffset); } @@ -1348,7 +1391,7 @@ static bool DecodedVertsAreSimilar(const VertexReader &vtx1, const VertexReader vtx2.ReadNrm(vec2.AsArray()); float diff = LargestAbsDiff(vec1, vec2, 3); if (diff >= 1.0 / 512.0f) { - WARN_LOG(G3D, "Normal diff %f", diff); + WARN_LOG(Log::G3D, "Normal diff %f", diff); return false; } } @@ -1357,7 +1400,7 @@ static bool DecodedVertsAreSimilar(const VertexReader &vtx1, const VertexReader vtx2.ReadUV(vec2.AsArray()); float diff = LargestAbsDiff(vec1, vec2, 2); if (diff >= 1.0 / 512.0f) { - WARN_LOG(G3D, "UV diff %f", diff); + WARN_LOG(Log::G3D, "UV diff %f", diff); return false; } } @@ -1366,7 +1409,7 @@ static bool DecodedVertsAreSimilar(const VertexReader &vtx1, const VertexReader vtx2.ReadColor0(vec2.AsArray()); float diff = LargestAbsDiff(vec1, vec2, 4); if (diff >= 1.0 / 255.0f) { - WARN_LOG(G3D, "Color0 diff %f", diff); + WARN_LOG(Log::G3D, "Color0 diff %f", diff); return false; } } @@ -1375,7 +1418,7 @@ static bool DecodedVertsAreSimilar(const VertexReader &vtx1, const VertexReader vtx2.ReadColor1(vec2.AsArray()); float diff = LargestAbsDiff(vec1, vec2, 4); if (diff >= 1.0 / 255.0f) { - WARN_LOG(G3D, "Color1 diff %f", diff); + WARN_LOG(Log::G3D, "Color1 diff %f", diff); return false; } } @@ -1383,7 +1426,7 @@ static bool DecodedVertsAreSimilar(const VertexReader &vtx1, const VertexReader vtx2.ReadPos(vec2.AsArray()); float diff = LargestAbsDiff(vec1, vec2, 3); if (diff >= 1.0 / 512.0f) { - WARN_LOG(G3D, "Pos diff %f", diff); + WARN_LOG(Log::G3D, "Pos diff %f", diff); return false; } @@ -1403,7 +1446,7 @@ void VertexDecoder::CompareToJit(const u8 *startPtr, u8 *decodedptr, int count, if (!DecodedVertsAreSimilar(controlReader, jittedReader)) { char name[512]{}; ToString(name, true); - ERROR_LOG(G3D, "Encountered vertexjit mismatch at %d/%d for %s", i, count, name); + ERROR_LOG(Log::G3D, "Encountered vertexjit mismatch at %d/%d for %s", i, count, name); if (morphcount > 1) { printf("Morph:\n"); for (int j = 0; j < morphcount; ++j) { @@ -1458,7 +1501,7 @@ static const char * const colnames[8] = { "", "?", "?", "?", "565", "5551", "444 int VertexDecoder::ToString(char *output, bool spaces) const { char *start = output; - + output += sprintf(output, "[%08x] ", fmt_); output += sprintf(output, "P: %s ", posnames[pos]); if (nrm) output += sprintf(output, "N: %s ", nrmnames[nrm]); @@ -1485,6 +1528,10 @@ int VertexDecoder::ToString(char *output, bool spaces) const { } } +#ifdef _DEBUG + output += sprintf(output, " (%llu)", (long long)decodedCount); +#endif + return output - start; } diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 4a30c5bef6..7a40701e01 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -186,7 +186,7 @@ public: Uint8x4ToFloat4(color, *(const u32 *)(data_ + decFmt_.c0off)); break; case DEC_FLOAT_4: - memcpy(color, data_ + decFmt_.c0off, 16); + memcpy(color, data_ + decFmt_.c0off, 16); break; default: memset(color, 0, sizeof(float) * 4); @@ -225,7 +225,7 @@ public: } break; case DEC_FLOAT_4: - memcpy(color, data_ + decFmt_.c1off, 12); + memcpy(color, data_ + decFmt_.c1off, 12); break; default: memset(color, 0, sizeof(float) * 3); @@ -254,7 +254,7 @@ public: case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i] = s[i] * (1.f / 32768.f); break; case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i] = s[i] * (1.f / 32768.f); break; default: - ERROR_LOG_REPORT_ONCE(fmtw0, G3D, "Reader: Unsupported W0 Format %d", decFmt_.w0fmt); + ERROR_LOG_REPORT_ONCE(fmtw0, Log::G3D, "Reader: Unsupported W0 Format %d", decFmt_.w0fmt); memset(weights, 0, sizeof(float) * 8); break; } @@ -309,7 +309,7 @@ void PrintDecodedVertex(const VertexReader &vtx); class VertexDecoder; class VertexDecoderJitCache; -typedef void (VertexDecoder::*StepFunction)() const; +typedef void (*StepFunction)(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); typedef void (VertexDecoderJitCache::*JitStepFunction)(); struct JitLookup { @@ -326,7 +326,6 @@ struct VertexDecoderOptions { bool expandAllWeightsToFloat; bool expand8BitNormalsToFloat; bool applySkinInDecode; - bool alignOutputToWord; }; class VertexDecoder { @@ -344,89 +343,89 @@ public: std::string GetString(DebugShaderStringType stringType) const; - void Step_WeightsU8() const; - void Step_WeightsU16() const; - void Step_WeightsU8ToFloat() const; - void Step_WeightsU16ToFloat() const; - void Step_WeightsFloat() const; - void ComputeSkinMatrix(const float weights[8]) const; - void Step_WeightsU8Skin() const; - void Step_WeightsU16Skin() const; - void Step_WeightsFloatSkin() const; + static void Step_WeightsU8(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_WeightsU16(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_WeightsU8ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_WeightsU16ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_WeightsFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_TcU8ToFloat() const; - void Step_TcU16ToFloat() const; - void Step_TcFloat() const; + static void Step_WeightsU8Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_WeightsU16Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_WeightsFloatSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_TcU8Prescale() const; - void Step_TcU16Prescale() const; - void Step_TcU16DoublePrescale() const; - void Step_TcFloatPrescale() const; + static void Step_TcU8ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_TcU16DoubleToFloat() const; - void Step_TcU16ThroughToFloat() const; - void Step_TcU16ThroughDoubleToFloat() const; - void Step_TcFloatThrough() const; + static void Step_TcU8Prescale(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16Prescale(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16DoublePrescale(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcFloatPrescale(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_TcU8MorphToFloat() const; - void Step_TcU16MorphToFloat() const; - void Step_TcU16DoubleMorphToFloat() const; - void Step_TcFloatMorph() const; - void Step_TcU8PrescaleMorph() const; - void Step_TcU16PrescaleMorph() const; - void Step_TcU16DoublePrescaleMorph() const; - void Step_TcFloatPrescaleMorph() const; + static void Step_TcU16DoubleToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16ThroughToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16ThroughDoubleToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcFloatThrough(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_ColorInvalid() const; - void Step_Color4444() const; - void Step_Color565() const; - void Step_Color5551() const; - void Step_Color8888() const; + static void Step_TcU8MorphToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16MorphToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16DoubleMorphToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcFloatMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU8PrescaleMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16PrescaleMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcU16DoublePrescaleMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_TcFloatPrescaleMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_Color4444Morph() const; - void Step_Color565Morph() const; - void Step_Color5551Morph() const; - void Step_Color8888Morph() const; + static void Step_ColorInvalid(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_Color4444(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_Color565(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_Color5551(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_Color8888(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_NormalS8() const; - void Step_NormalS8ToFloat() const; - void Step_NormalS16() const; - void Step_NormalFloat() const; + static void Step_Color4444Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_Color565Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_Color5551Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_Color8888Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_NormalS8Skin() const; - void Step_NormalS16Skin() const; - void Step_NormalFloatSkin() const; + static void Step_NormalS8(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalS8ToFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalS16(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_NormalS8Morph() const; - void Step_NormalS16Morph() const; - void Step_NormalFloatMorph() const; + static void Step_NormalS8Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalS16Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalFloatSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_NormalS8MorphSkin() const; - void Step_NormalS16MorphSkin() const; - void Step_NormalFloatMorphSkin() const; + static void Step_NormalS8Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalS16Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalFloatMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_PosS8() const; - void Step_PosS16() const; - void Step_PosFloat() const; + static void Step_NormalS8MorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalS16MorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_NormalFloatMorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_PosS8Skin() const; - void Step_PosS16Skin() const; - void Step_PosFloatSkin() const; + static void Step_PosS8(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosS16(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosFloat(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_PosS8Morph() const; - void Step_PosS16Morph() const; - void Step_PosFloatMorph() const; + static void Step_PosS8Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosS16Skin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosFloatSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_PosS8MorphSkin() const; - void Step_PosS16MorphSkin() const; - void Step_PosFloatMorphSkin() const; + static void Step_PosS8Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosS16Morph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosFloatMorph(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); - void Step_PosInvalid() const; - void Step_PosS8Through() const; - void Step_PosS16Through() const; - void Step_PosFloatThrough() const; + static void Step_PosS8MorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosS16MorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosFloatMorphSkin(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + + static void Step_PosInvalid(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosS8Through(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosS16Through(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); + static void Step_PosFloatThrough(const VertexDecoder *dec, const u8 *ptr, u8 *decoded); // output must be big for safety. // Returns number of chars written. @@ -438,16 +437,14 @@ public: } // Mutable decoder state - mutable u8 *decoded_ = nullptr; - mutable const u8 *ptr_ = nullptr; mutable const UVScale *prescaleUV_ = nullptr; JittedVertexDecoder jitted_ = 0; int32_t jittedSize_ = 0; // "Immutable" state, set at startup - // The decoding steps. Never more than 5. - StepFunction steps_[5]; + // The decoding steps. Never more than 5 (weight, texcoord, color, normal, pos) + StepFunction steps_[5]{}; int numSteps_; u32 fmt_; @@ -476,6 +473,10 @@ public: u8 biggest; // in practice, alignment. +#ifdef _DEBUG + mutable u64 decodedCount = 0; +#endif + friend class VertexDecoderJitCache; private: diff --git a/GPU/Common/VertexDecoderHandwritten.cpp b/GPU/Common/VertexDecoderHandwritten.cpp new file mode 100644 index 0000000000..681f18c769 --- /dev/null +++ b/GPU/Common/VertexDecoderHandwritten.cpp @@ -0,0 +1,291 @@ +#include "Common/CommonTypes.h" +#include "Common/Data/Convert/ColorConv.h" +#include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/GPUState.h" + +#ifdef _M_SSE +#include +#include +#endif + +#if PPSSPP_ARCH(ARM_NEON) +#if defined(_MSC_VER) && PPSSPP_ARCH(ARM64) +#include +#else +#include +#endif +#endif + +// Candidates for hand-writing +// (found using our custom Very Sleepy). +// GPU::P:_f_N:_s8_C:_8888_T:_u16__(24b)_040001BE (5%+ of God of War execution) +// GPU::P:_f_N:_s8_C:_8888_T:_u16_W:_f_(1x)__(28b)_040007BE (1%+ of God of War execution) + +// Tekken 6: +// (found using the vertex counter that's active in _DEBUG) +// [04000111] P: s16 C: 565 T: u8 (10b) (736949) // Also in Midnight Club + +// Wipeout Pure: +// [0400013f] P: s16 N: s8 C: 8888 T: f (24b) (1495430) + +// Flatout: +// [04000122] P: s16 N: s8 T: u16 (14b) (3901754) +// [04000116] P: s16 C: 5551 T: u16 (12b) (2225841) + +// Test drive: +// [05000100] P: s16 (6b) (2827872) +// [050011ff] P: f N: f C: 8888 T: f I: u16 (36b) (3812112) + +// Burnout Dominator: +// [04000122] P: s16 N: s8 T: u16 (14b) (1710813) +// [04000116] P: s16 C: 5551 T: u16 (12b) (7688298) + +// This is the first GoW one. +void VtxDec_Tu16_C8888_Pfloat(const u8 *srcp, u8 *dstp, int count, const UVScale *uvScaleOffset) { + struct GOWVTX { + union { + struct { + u16 u; + u16 v; + }; + u32 packed_uv; + }; + u32 packed_normal; + u32 col; + float x; + float y; + float z; + }; + // NOTE: This might be different for different vertex formats. + struct OutVTX { + float u; + float v; + u32 packed_normal; + uint32_t col; + float x; + float y; + float z; + }; + const GOWVTX *src = (const GOWVTX *)srcp; + OutVTX *dst = (OutVTX *)dstp; + float uscale = uvScaleOffset->uScale * (1.0f / 32768.0f); + float vscale = uvScaleOffset->vScale * (1.0f / 32768); + float uoff = uvScaleOffset->uOff; + float voff = uvScaleOffset->vOff; + + u32 alpha = 0xFFFFFFFF; + +#if PPSSPP_ARCH(SSE2) + __m128 uvOff = _mm_setr_ps(uoff, voff, uoff, voff); + __m128 uvScale = _mm_setr_ps(uscale, vscale, uscale, vscale); + __m128i alphaMask = _mm_set1_epi32(0xFFFFFFFF); + for (int i = 0; i < count; i++) { + __m128i uv = _mm_set1_epi32(src[i].packed_uv); + __m128 fuv = _mm_cvtepi32_ps(_mm_unpacklo_epi16(uv, _mm_setzero_si128())); + __m128 finalUV = _mm_add_ps(_mm_mul_ps(fuv, uvScale), uvOff); + u32 normal = src[i].packed_normal; + __m128i colpos = _mm_loadu_si128((const __m128i *)&src[i].col); + _mm_store_sd((double *)&dst[i].u, _mm_castps_pd(finalUV)); + dst[i].packed_normal = normal; + _mm_storeu_si128((__m128i *)&dst[i].col, colpos); + alphaMask = _mm_and_si128(alphaMask, colpos); + } + alpha = _mm_cvtsi128_si32(alphaMask); + +#elif PPSSPP_ARCH(ARM_NEON) + float32x2_t uvScale = vmul_f32(vld1_f32(&uvScaleOffset->uScale), vdup_n_f32(1.0f / 32768.0f)); + float32x2_t uvOff = vld1_f32(&uvScaleOffset->uOff); + uint32x4_t alphaMask = vdupq_n_u32(0xFFFFFFFF); + for (int i = 0; i < count; i++) { + uint16x4_t uv = vld1_u16(&src[i].u); // TODO: We only need the first two lanes, maybe there's a better way? + uint32x2_t fuv = vget_low_u32(vmovl_u16(uv)); // Only using the first two lanes + float32x2_t finalUV = vadd_f32(vmul_f32(vcvt_f32_u32(fuv), uvScale), uvOff); + u32 normal = src[i].packed_normal; + uint32x4_t colpos = vld1q_u32((const u32 *)&src[i].col); + alphaMask = vandq_u32(alphaMask, colpos); + vst1_f32(&dst[i].u, finalUV); + dst[i].packed_normal = normal; + vst1q_u32(&dst[i].col, colpos); + } + alpha = vgetq_lane_u32(alphaMask, 0); +#else + for (int i = 0; i < count; i++) { + float u = src[i].u * uscale + uoff; + float v = src[i].v * vscale + voff; + uint32_t color = src[i].col; + alpha &= color; + float x = src[i].x; + float y = src[i].y; + float z = src[i].z; + dst[i].col = color; + dst[i].packed_normal = src[i].packed_normal; + dst[i].u = u; + dst[i].v = v; + dst[i].x = x; + dst[i].y = y; + dst[i].z = z; + } +#endif + gstate_c.vertexFullAlpha = (alpha >> 24) == 0xFF; +} + +void VtxDec_Tu8_C5551_Ps16(const u8 *srcp, u8 *dstp, int count, const UVScale *uvScaleOffset) { + struct GTAVTX { + union { + struct { + u8 u; + u8 v; + }; + u16 uv; + }; + u16 col; + s16 x; + s16 y; + s16 z; + }; + // NOTE: This might be different for different vertex formats. + struct OutVTX { + float u; + float v; + uint32_t col; + float x; + float y; + float z; + }; + const GTAVTX *src = (const GTAVTX *)srcp; + OutVTX *dst = (OutVTX *)dstp; + float uscale = uvScaleOffset->uScale * (1.0f / 128.0f); + float vscale = uvScaleOffset->vScale * (1.0f / 128.0f); + float uoff = uvScaleOffset->uOff; + float voff = uvScaleOffset->vOff; + + uint64_t alpha = 0xFFFFFFFFFFFFFFFFULL; + +#if PPSSPP_ARCH(SSE2) + __m128 uvOff = _mm_setr_ps(uoff, voff, uoff, voff); + __m128 uvScale = _mm_setr_ps(uscale, vscale, uscale, vscale); + __m128 posScale = _mm_set1_ps(1.0f / 32768.0f); + __m128i rmask = _mm_set1_epi32(0x001F); + __m128i gmask = _mm_set1_epi32(0x03E0); + __m128i bmask = _mm_set1_epi32(0x7c00); + __m128i amask = _mm_set1_epi32(0x8000); + __m128i lowbits = _mm_set1_epi32(0x00070707); + + // Two vertices at a time, we can share some calculations. + // It's OK to accidentally decode an extra vertex. + for (int i = 0; i < count; i += 2) { + __m128i pos0 = _mm_loadl_epi64((const __m128i *) & src[i].x); + __m128i pos1 = _mm_loadl_epi64((const __m128i *) & src[i + 1].x); + // Translate UV, combined. TODO: Can possibly shuffle UV and col together here + uint32_t uv0 = (uint32_t)src[i].uv | ((uint32_t)src[i + 1].uv << 16); + uint64_t col0 = (uint64_t)src[i].col | ((uint64_t)src[i + 1].col << 32); + __m128i pos0_32 = _mm_srai_epi32(_mm_unpacklo_epi16(pos0, pos0), 16); + __m128i pos1_32 = _mm_srai_epi32(_mm_unpacklo_epi16(pos1, pos1), 16); + __m128 pos0_ext = _mm_mul_ps(_mm_cvtepi32_ps(pos0_32), posScale); + __m128 pos1_ext = _mm_mul_ps(_mm_cvtepi32_ps(pos1_32), posScale); + + __m128i uv8 = _mm_set1_epi32(uv0); + __m128i uv16 = _mm_unpacklo_epi8(uv8, uv8); + __m128i uv32 = _mm_srli_epi32(_mm_unpacklo_epi16(uv16, uv16), 24); + __m128d uvf = _mm_castps_pd(_mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(uv32), uvScale), uvOff)); + alpha &= col0; + + // Combined RGBA + __m128i col = _mm_set1_epi64x(col0); + __m128i r = _mm_slli_epi32(_mm_and_si128(col, rmask), 8 - 5); + __m128i g = _mm_slli_epi32(_mm_and_si128(col, gmask), 16 - 10); + __m128i b = _mm_slli_epi32(_mm_and_si128(col, bmask), 24 - 15); + __m128i a = _mm_srai_epi32(_mm_slli_epi32(_mm_and_si128(col, amask), 16), 7); + col = _mm_or_si128(_mm_or_si128(r, g), b); + col = _mm_or_si128(col, _mm_and_si128(_mm_srli_epi32(col, 5), lowbits)); + col = _mm_or_si128(col, a); + + // TODO: Mix into fewer stores. + _mm_storeu_ps(&dst[i].x, pos0_ext); + _mm_storeu_ps(&dst[i + 1].x, pos1_ext); + _mm_storel_pd((double *)&dst[i].u, uvf); + _mm_storeh_pd((double *)&dst[i + 1].u, uvf); + dst[i].col = _mm_cvtsi128_si32(col); + dst[i + 1].col = _mm_cvtsi128_si32(_mm_shuffle_epi32(col, _MM_SHUFFLE(1, 1, 1, 1))); + } + + alpha = alpha & (alpha >> 32); + +#elif PPSSPP_ARCH(ARM_NEON) + + float32x4_t uvScaleOff = vld1q_f32(&uvScaleOffset->uScale); + float32x4_t uvScale = vmulq_f32(vcombine_f32(vget_low_f32(uvScaleOff), vget_low_f32(uvScaleOff)), vdupq_n_f32(1.0f / 128.0f)); + float32x4_t uvOffset = vcombine_f32(vget_high_f32(uvScaleOff), vget_high_f32(uvScaleOff)); + float32x4_t posScale = vdupq_n_f32(1.0f / 32768.0f); + uint32x2_t rmask = vdup_n_u32(0x001F); + uint32x2_t gmask = vdup_n_u32(0x03E0); + uint32x2_t bmask = vdup_n_u32(0x7c00); + uint32x2_t amask = vdup_n_u32(0x8000); + uint32x2_t lowbits = vdup_n_u32(0x00070707); + + // Two vertices at a time, we can share some calculations. + // It's OK to accidentally decode an extra vertex. + // Doing four vertices at a time might be even better, can share more of the pesky color format conversion. + for (int i = 0; i < count; i += 2) { + int16x4_t pos0 = vld1_s16(&src[i].x); + int16x4_t pos1 = vld1_s16(&src[i + 1].x); + // Translate UV, combined. TODO: Can possibly shuffle UV and col together here + uint32_t uv0 = (uint32_t)src[i].uv | ((uint32_t)src[i + 1].uv << 16); + uint64_t col0 = (uint64_t)src[i].col | ((uint64_t)src[i + 1].col << 32); + int32x4_t pos0_32 = vmovl_s16(pos0); + int32x4_t pos1_32 = vmovl_s16(pos1); + float32x4_t pos0_ext = vmulq_f32(vcvtq_f32_s32(pos0_32), posScale); + float32x4_t pos1_ext = vmulq_f32(vcvtq_f32_s32(pos1_32), posScale); + + uint64x1_t uv8_one = vdup_n_u64(uv0); + uint8x8_t uv8 = vreinterpret_u8_u64(uv8_one); + uint16x4_t uv16 = vget_low_u16(vmovl_u8(uv8)); + uint32x4_t uv32 = vmovl_u16(uv16); + float32x4_t uvf = vaddq_f32(vmulq_f32(vcvtq_f32_u32(uv32), uvScale), uvOffset); + + alpha &= col0; + + // Combined RGBA + uint32x2_t col = vreinterpret_u32_u64(vdup_n_u64(col0)); + uint32x2_t r = vshl_n_u32(vand_u32(col, rmask), 8 - 5); + uint32x2_t g = vshl_n_u32(vand_u32(col, gmask), 16 - 10); + uint32x2_t b = vshl_n_u32(vand_u32(col, bmask), 24 - 15); + int32x2_t a_shifted = vshr_n_s32(vreinterpret_s32_u32(vshl_n_u32(vand_u32(col, amask), 16)), 7); + uint32x2_t a = vreinterpret_u32_s32(a_shifted); + col = vorr_u32(vorr_u32(r, g), b); + col = vorr_u32(col, vand_u32(vshl_n_u32(col, 5), lowbits)); + col = vorr_u32(col, a); + + // TODO: Mix into fewer stores. + vst1q_f32(&dst[i].x, pos0_ext); + vst1q_f32(&dst[i + 1].x, pos1_ext); + vst1_f32(&dst[i].u, vget_low_f32(uvf)); + vst1_f32(&dst[i + 1].u, vget_high_f32(uvf)); + dst[i].col = vget_lane_u32(col, 0); + dst[i + 1].col = vget_lane_u32(col, 1); + } + + alpha = alpha & (alpha >> 32); + +#else + + for (int i = 0; i < count; i++) { + float u = src[i].u * uscale + uoff; + float v = src[i].v * vscale + voff; + alpha &= src[i].col; + uint32_t color = RGBA5551ToRGBA8888(src[i].col); + float x = src[i].x * (1.0f / 32768.0f); + float y = src[i].y * (1.0f / 32768.0f); + float z = src[i].z * (1.0f / 32768.0f); + dst[i].col = color; + dst[i].u = u; + dst[i].v = v; + dst[i].x = x; + dst[i].y = y; + dst[i].z = z; + } + +#endif + + gstate_c.vertexFullAlpha = (alpha >> 15) & 1; +} diff --git a/GPU/Common/VertexDecoderHandwritten.h b/GPU/Common/VertexDecoderHandwritten.h new file mode 100644 index 0000000000..fdf666cc85 --- /dev/null +++ b/GPU/Common/VertexDecoderHandwritten.h @@ -0,0 +1,7 @@ +#pragma once + +// These are useful on JIT-less platforms - they don't beat the jitted vertex decoders by much, but they +// will beat the function-call-stitched ones by a lot. + +void VtxDec_Tu16_C8888_Pfloat(const u8 *srcp, u8 *dstp, int count, const UVScale *uvScaleOffset); +void VtxDec_Tu8_C5551_Ps16(const u8 *srcp, u8 *dstp, int count, const UVScale *uvScaleOffset); diff --git a/GPU/Common/VertexDecoderRiscV.cpp b/GPU/Common/VertexDecoderRiscV.cpp index 82a7b3b5b8..0d232a74fb 100644 --- a/GPU/Common/VertexDecoderRiscV.cpp +++ b/GPU/Common/VertexDecoderRiscV.cpp @@ -317,7 +317,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int ResetCodePtr(GetOffset(start)); char temp[1024]{}; dec.ToString(temp, true); - ERROR_LOG(G3D, "Could not compile vertex decoder, failed at step %d: %s", i, temp); + ERROR_LOG(Log::G3D, "Could not compile vertex decoder, failed at step %d: %s", i, temp); return nullptr; } } @@ -350,12 +350,12 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int if (log) { char temp[1024]{}; dec.ToString(temp, true); - INFO_LOG(JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start)); + INFO_LOG(Log::JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start)); std::vector lines = DisassembleRV64(start, (int)(GetCodePtr() - start)); for (auto line : lines) { - INFO_LOG(JIT, "%s", line.c_str()); + INFO_LOG(Log::JIT, "%s", line.c_str()); } - INFO_LOG(JIT, "=========="); + INFO_LOG(Log::JIT, "=========="); } *jittedSize = (int)(GetCodePtr() - start); diff --git a/GPU/Common/VertexDecoderX86.cpp b/GPU/Common/VertexDecoderX86.cpp index f35e6c1ed8..1df3be8388 100644 --- a/GPU/Common/VertexDecoderX86.cpp +++ b/GPU/Common/VertexDecoderX86.cpp @@ -21,9 +21,11 @@ #include #include "Common/CPUDetect.h" +#include "Common/Data/Convert/ColorConv.h" #include "Core/Config.h" #include "GPU/GPUState.h" #include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/VertexDecoderHandwritten.h" // We start out by converting the active matrices into 4x4 which are easier to multiply with // using SSE / NEON and store them here. diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 674ff0cef2..84f9ab122a 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -24,6 +24,7 @@ #include "Common/GPU/ShaderWriter.h" #include "Common/GPU/thin3d.h" #include "Core/Config.h" +#include "Core/System.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "GPU/Common/ShaderId.h" @@ -151,9 +152,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (gl_extensions.ARB_cull_distance && id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) { extensions.push_back("#extension GL_ARB_cull_distance : enable"); } - if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { - extensions.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;"); - } } bool useSimpleStereo = id.Bit(VS_BIT_SIMPLE_STEREO); @@ -494,11 +492,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag *uniformMask |= DIRTY_PROJTHROUGHMATRIX; } else if (useHWTransform) { if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { - WRITE(p, "layout(shared) uniform ProjectionMatrix { uniform mat4 u_proj_lens[2]; };\n"); - } else { - WRITE(p, "uniform mat4 u_proj_lens;\n"); - } + WRITE(p, "uniform mat4 u_proj_lens;\n"); } WRITE(p, "uniform mat4 u_proj;\n"); *uniformMask |= DIRTY_PROJMATRIX; @@ -508,11 +502,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // When transforming by hardware, we need a great deal more uniforms... // TODO: Use 4x3 matrices where possible. Though probably doesn't matter much. WRITE(p, "uniform mat4 u_world;\n"); - if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { - WRITE(p, "layout(shared) uniform ViewMatrices { uniform mat4 u_view[2]; };\n"); - } else { - WRITE(p, "uniform mat4 u_view;\n"); - } + WRITE(p, "uniform mat4 u_view;\n"); *uniformMask |= DIRTY_WORLDMATRIX | DIRTY_VIEWMATRIX; if (doTextureTransform) { WRITE(p, "uniform mediump mat4 u_texmtx;\n"); @@ -926,24 +916,27 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(skinnednormal, 0.0), u_world).xyz);\n"); } - std::string matrixPostfix; - if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) { - matrixPostfix = "[gl_ViewID_OVR]"; + WRITE(p, " vec4 viewPos = vec4(mul(vec4(worldpos, 1.0), u_view).xyz, 1.0);\n"); + if (useSimpleStereo) { + float ipd = 0.065f; + float scale = 1.0f; + if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) { + scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter; + } + WRITE(p, " viewPos.x += %f * float(gl_ViewIndex * 2 - 1);\n", scale * ipd * 0.5); } - WRITE(p, " vec4 viewPos = vec4(mul(vec4(worldpos, 1.0), u_view%s).xyz, 1.0);\n", matrixPostfix.c_str()); - // Final view and projection transforms. if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) { if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj_lens%s, viewPos));\n", matrixPostfix.c_str()); + WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj_lens, viewPos));\n"); WRITE(p, " vec4 orgPos = depthRoundZVP(mul(u_proj, viewPos));\n"); } else { WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj, viewPos));\n"); } } else { if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - WRITE(p, " vec4 outPos = mul(u_proj_lens%s, viewPos);\n", matrixPostfix.c_str()); + WRITE(p, " vec4 outPos = mul(u_proj_lens, viewPos);\n"); WRITE(p, " vec4 orgPos = mul(u_proj, viewPos);\n"); } else { WRITE(p, " vec4 outPos = mul(u_proj, viewPos);\n"); @@ -1019,6 +1012,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } } + // NOTE: Can't change this without updating uniform buffer declarations (for D3D11 and VK, the one in ShaderUniforms.h). bool useIndexing = compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == GLSL_VULKAN; char iStr[4]; @@ -1069,7 +1063,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag p.C(" ldot = u_matspecular.a > 0.0 ? pow(max(ldot, 0.0), u_matspecular.a) : 1.0;\n"); p.C(" }\n"); p.F(" diffuse = (u_lightdiffuse%s * diffuseColor) * max(ldot, 0.0);\n", iStr); - p.C(" if (comp == 0x1u && ldot > 0.0) {\n"); // do specular + p.C(" if (comp == 0x1u && ldot >= 0.0) {\n"); // do specular. note - must allow for the >= case, since the u_matspecular.a <= 0.0 case relies on it. p.C(" if (u_matspecular.a > 0.0) {\n"); p.C(" ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); @@ -1313,7 +1307,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " }\n"); } - if (vertexRangeCulling && !gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { + if (vertexRangeCulling) { WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n"); WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n"); @@ -1367,12 +1361,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " %sgl_Position.y *= u_scaleY;\n", compat.vsOutPrefix); } - if (useSimpleStereo && useHWTransform) { - p.C(" float zFactor = 0.2 * float(gl_ViewIndex * 2 - 1);\n"); - p.C(" float zFocus = 0.0;\n"); - p.C(" gl_Position.x += (-gl_Position.z - zFocus) * zFactor;\n"); - } - if (needsZWHack) { // See comment in thin3d_vulkan.cpp. WRITE(p, " if (%sgl_Position.z == %sgl_Position.w) %sgl_Position.z *= 0.999999;\n", diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index 9fd4c64a48..f84b188d56 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -28,9 +28,20 @@ std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeS errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); std::string numberedCode = LineNumberString(code); if (SUCCEEDED(result)) { - WARN_LOG(G3D, "%s: %s", "warnings", errors.c_str()); + std::vector lines; + SplitString(errors, '\n', lines); + for (auto &line : lines) { + auto trimmed = StripSpaces(line); + // Ignore the useless warning about taking the power of negative numbers. + if (trimmed.find("pow(f, e) will not work for negative f") != std::string::npos) { + continue; + } + if (trimmed.size() > 1) { // ignore single nulls, not sure how they appear. + WARN_LOG(Log::G3D, "%.*s", (int)trimmed.length(), trimmed.data()); + } + } } else { - ERROR_LOG(G3D, "%s: %s\n\n%s", "errors", errors.c_str(), numberedCode.c_str()); + ERROR_LOG(Log::G3D, "%s: %s\n\n%s", "errors", errors.c_str(), numberedCode.c_str()); } OutputDebugStringA(errors.c_str()); OutputDebugStringA(numberedCode.c_str()); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index e1c588b76b..db0440c6c4 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -237,7 +237,7 @@ ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshade // Create declaration HRESULT hr = device_->CreateInputLayout(VertexElements, VertexElement - VertexElements, vshader->bytecode().data(), vshader->bytecode().size(), &inputLayout); if (FAILED(hr)) { - ERROR_LOG(G3D, "Failed to create input layout!"); + ERROR_LOG(Log::G3D, "Failed to create input layout!"); inputLayout = nullptr; } @@ -370,7 +370,7 @@ void DrawEngineD3D11::DoFlush() { gpuStats.numUncachedVertsDrawn += vertexCount; prim = IndexGenerator::GeneralPrim((GEPrimitiveType)drawInds_[0].prim); - VERBOSE_LOG(G3D, "Flush prim %i SW! %i verts in one go", prim, vertexCount); + VERBOSE_LOG(Log::G3D, "Flush prim %i SW! %i verts in one go", prim, vertexCount); u16 *inds = decIndex_; SoftwareTransformResult result{}; @@ -382,10 +382,15 @@ void DrawEngineD3D11::DoFlush() { params.texCache = textureCache_; params.allowClear = true; params.allowSeparateAlphaClear = false; // D3D11 doesn't support separate alpha clears - params.provokeFlatFirst = true; params.flippedY = false; params.usesHalfZ = true; + if (gstate.getShadeMode() == GE_SHADE_FLAT) { + // We need to rotate the index buffer to simulate a different provoking vertex. + // We do this before line expansion etc. + IndexBufferProvokingLastToFirst(prim, inds, vertexCount); + } + // We need correct viewport values in gstate_c already. if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) { ViewportAndScissor vpAndScissor; @@ -424,7 +429,7 @@ void DrawEngineD3D11::DoFlush() { ApplyDrawStateLate(result.setStencil, result.stencilValue); - if (result.action == SW_DRAW_PRIMITIVES) { + if (result.action == SW_DRAW_INDEXED) { D3D11VertexShader *vshader; D3D11FragmentShader *fshader; shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true); @@ -452,17 +457,13 @@ void DrawEngineD3D11::DoFlush() { pushVerts_->EndPush(context_); ID3D11Buffer *buf = pushVerts_->Buf(); context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset); - if (result.drawIndexed) { - UINT iOffset; - int iSize = sizeof(uint16_t) * result.drawNumTrans; - uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); - memcpy(iptr, inds, iSize); - pushInds_->EndPush(context_); - context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); - context_->DrawIndexed(result.drawNumTrans, 0, 0); - } else { - context_->Draw(result.drawNumTrans, 0); - } + UINT iOffset; + int iSize = sizeof(uint16_t) * result.drawNumTrans; + uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); + memcpy(iptr, inds, iSize); + pushInds_->EndPush(context_); + context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); + context_->DrawIndexed(result.drawNumTrans, 0, 0); } else if (result.action == SW_CLEAR) { u32 clearColor = result.color; float clearDepth = result.depth; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index bb07131b5f..2e425b1f44 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -71,7 +71,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Sanity check gstate if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) { - ERROR_LOG(G3D, "gstate has drifted out of sync!"); + ERROR_LOG(Log::G3D, "gstate has drifted out of sync!"); } // No need to flush before the tex scale/offset commands if we are baking @@ -141,7 +141,7 @@ void GPU_D3D11::BeginHostFrame() { if (gstate_c.useFlagsChanged) { // TODO: It'd be better to recompile them in the background, probably? // This most likely means that saw equal depth changed. - WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers"); + WARN_LOG(Log::G3D, "Shader use flags changed, clearing all shaders and depth buffers"); shaderManager_->ClearShaders(); framebufferManager_->ClearAllDepthBuffers(); drawEngine_.ClearInputLayoutMap(); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 465981e673..320d688031 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -274,8 +274,8 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { ID3D11Resource *texture = DxTex(entry); _assert_(texture == nullptr); - // The PSP only supports 8 mip levels, but we support 12 in the texture replacer (4k textures down to 1). - D3D11_SUBRESOURCE_DATA subresData[12]{}; + // The PSP only supports 8 mip levels, but we support more in the texture replacer. 20 will never run out. + D3D11_SUBRESOURCE_DATA subresData[20]{}; if (plan.depth == 1) { // We don't yet have mip generation, so clamp the number of levels to the ones we can load directly. @@ -333,7 +333,7 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { } if (!data) { - ERROR_LOG(G3D, "Ran out of RAM trying to allocate a temporary texture upload buffer (%dx%d)", mipWidth, mipHeight); + ERROR_LOG(Log::G3D, "Ran out of RAM trying to allocate a temporary texture upload buffer (%dx%d)", mipWidth, mipHeight); return; } diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 16143b882f..88c923b8ee 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -141,10 +141,10 @@ bool NotifyCommand(u32 pc) { auto info = gpuDebug->DissassembleOp(pc); if (lastStepTime >= 0.0) { - NOTICE_LOG(G3D, "Waiting at %08x, %s (%fms)", pc, info.desc.c_str(), (time_now_d() - lastStepTime) * 1000.0); + NOTICE_LOG(Log::G3D, "Waiting at %08x, %s (%fms)", pc, info.desc.c_str(), (time_now_d() - lastStepTime) * 1000.0); lastStepTime = -1.0; } else { - NOTICE_LOG(G3D, "Waiting at %08x, %s", pc, info.desc.c_str()); + NOTICE_LOG(Log::G3D, "Waiting at %08x, %s", pc, info.desc.c_str()); } GPUStepping::EnterStepping(); } @@ -157,10 +157,10 @@ void NotifyDraw() { return; if (breakNext == BreakNext::DRAW && !GPUStepping::IsStepping()) { if (lastStepTime >= 0.0) { - NOTICE_LOG(G3D, "Waiting at a draw (%fms)", (time_now_d() - lastStepTime) * 1000.0); + NOTICE_LOG(Log::G3D, "Waiting at a draw (%fms)", (time_now_d() - lastStepTime) * 1000.0); lastStepTime = -1.0; } else { - NOTICE_LOG(G3D, "Waiting at a draw"); + NOTICE_LOG(Log::G3D, "Waiting at a draw"); } GPUStepping::EnterStepping(); } diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index f66a9c3e92..b19919348f 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -355,7 +355,7 @@ bool DumpExecute::SubmitCmds(const void *p, u32 sz) { execListBuf = 0; } if (execListBuf == 0) { - ERROR_LOG(SYSTEM, "Unable to allocate for display list"); + ERROR_LOG(Log::System, "Unable to allocate for display list"); return false; } @@ -462,7 +462,7 @@ void DumpExecute::Registers(u32 ptr, u32 sz) { void DumpExecute::Vertices(u32 ptr, u32 sz) { u32 psp = mapping_.Map(ptr, sz, std::bind(&DumpExecute::SyncStall, this)); if (psp == 0) { - ERROR_LOG(SYSTEM, "Unable to allocate for vertices"); + ERROR_LOG(Log::System, "Unable to allocate for vertices"); return; } @@ -476,7 +476,7 @@ void DumpExecute::Vertices(u32 ptr, u32 sz) { void DumpExecute::Indices(u32 ptr, u32 sz) { u32 psp = mapping_.Map(ptr, sz, std::bind(&DumpExecute::SyncStall, this)); if (psp == 0) { - ERROR_LOG(SYSTEM, "Unable to allocate for indices"); + ERROR_LOG(Log::System, "Unable to allocate for indices"); return; } @@ -513,7 +513,7 @@ void DumpExecute::Clut(u32 ptr, u32 sz) { } else { u32 psp = mapping_.Map(ptr, sz, std::bind(&DumpExecute::SyncStall, this)); if (psp == 0) { - ERROR_LOG(SYSTEM, "Unable to allocate for clut"); + ERROR_LOG(Log::System, "Unable to allocate for clut"); return; } @@ -525,7 +525,7 @@ void DumpExecute::Clut(u32 ptr, u32 sz) { void DumpExecute::TransferSrc(u32 ptr, u32 sz) { u32 psp = mapping_.Map(ptr, sz, std::bind(&DumpExecute::SyncStall, this)); if (psp == 0) { - ERROR_LOG(SYSTEM, "Unable to allocate for transfer"); + ERROR_LOG(Log::System, "Unable to allocate for transfer"); return; } @@ -569,7 +569,7 @@ void DumpExecute::Memcpy(u32 ptr, u32 sz) { void DumpExecute::Texture(int level, u32 ptr, u32 sz) { u32 psp = mapping_.Map(ptr, sz, std::bind(&DumpExecute::SyncStall, this)); if (psp == 0) { - ERROR_LOG(SYSTEM, "Unable to allocate for texture"); + ERROR_LOG(Log::System, "Unable to allocate for texture"); return; } @@ -733,7 +733,7 @@ bool DumpExecute::Run() { break; default: - ERROR_LOG(SYSTEM, "Unsupported GE dump command: %d", (int)cmd.type); + ERROR_LOG(Log::System, "Unsupported GE dump command: %d", (int)cmd.type); return false; } } @@ -788,7 +788,7 @@ bool RunMountedReplay(const std::string &filename) { version = header.version; if (memcmp(header.magic, HEADER_MAGIC, sizeof(header.magic)) != 0 || header.version > VERSION || header.version < MIN_VERSION) { - ERROR_LOG(SYSTEM, "Invalid GE dump or unsupported version"); + ERROR_LOG(Log::System, "Invalid GE dump or unsupported version"); pspFileSystem.CloseFile(fp); return false; } @@ -817,7 +817,7 @@ bool RunMountedReplay(const std::string &filename) { pspFileSystem.CloseFile(fp); if (truncated) { - ERROR_LOG(SYSTEM, "Truncated GE dump"); + ERROR_LOG(Log::System, "Truncated GE dump"); return false; } diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index f37af0b557..88ee8353ea 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -197,7 +197,7 @@ static Path WriteRecording() { const Path filename = GenRecordingFilename(); - NOTICE_LOG(G3D, "Recording filename: %s", filename.c_str()); + NOTICE_LOG(Log::G3D, "Recording filename: %s", filename.c_str()); FILE *fp = File::OpenCFile(filename, "wb"); Header header{}; @@ -624,7 +624,7 @@ static void FinishRecording() { pushbuf.clear(); lastVRAM.clear(); - NOTICE_LOG(SYSTEM, "Recording finished"); + NOTICE_LOG(Log::System, "Recording finished"); active = false; flipLastAction = gpuStats.numFlips; flipFinishAt = -1; @@ -784,7 +784,7 @@ void NotifyDisplay(u32 framebuf, int stride, int fmt) { writePending = true; } if (!active && nextFrame && (gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) { - NOTICE_LOG(SYSTEM, "Recording starting on display..."); + NOTICE_LOG(Log::System, "Recording starting on display..."); BeginRecording(); } if (!active) { @@ -808,7 +808,7 @@ void NotifyDisplay(u32 framebuf, int stride, int fmt) { commands.push_back({ CommandType::DISPLAY, sz, ptr }); if (writePending) { - NOTICE_LOG(SYSTEM, "Recording complete on display"); + NOTICE_LOG(Log::System, "Recording complete on display"); FinishRecording(); } } @@ -817,7 +817,7 @@ void NotifyBeginFrame() { const bool noDisplayAction = flipLastAction + 4 < gpuStats.numFlips; // We do this only to catch things that don't call NotifyDisplay. if (active && HasDrawCommands() && (noDisplayAction || gpuStats.numFlips == flipFinishAt)) { - NOTICE_LOG(SYSTEM, "Recording complete on frame"); + NOTICE_LOG(Log::System, "Recording complete on frame"); CheckEdramTrans(); struct DisplayBufData { @@ -839,7 +839,7 @@ void NotifyBeginFrame() { FinishRecording(); } if (!active && nextFrame && (gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0 && noDisplayAction) { - NOTICE_LOG(SYSTEM, "Recording starting on frame..."); + NOTICE_LOG(Log::System, "Recording starting on frame..."); BeginRecording(); // If we began on a BeginFrame, end on a BeginFrame. flipFinishAt = gpuStats.numFlips + 1; diff --git a/GPU/Debugger/Stepping.cpp b/GPU/Debugger/Stepping.cpp index d0fe232de6..db6b657e73 100644 --- a/GPU/Debugger/Stepping.cpp +++ b/GPU/Debugger/Stepping.cpp @@ -128,7 +128,7 @@ static void RunPauseAction() { break; default: - ERROR_LOG(G3D, "Unsupported pause action, forgot to add it to the switch."); + ERROR_LOG(Log::G3D, "Unsupported pause action, forgot to add it to the switch."); } actionComplete = true; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 6fe9b3dd07..ce20f88859 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -211,7 +211,7 @@ IDirect3DVertexDeclaration9 *DrawEngineDX9::SetupDecFmtForDraw(const DecVtxForma IDirect3DVertexDeclaration9 *pHardwareVertexDecl = nullptr; HRESULT hr = device_->CreateVertexDeclaration( VertexElements, &pHardwareVertexDecl ); if (FAILED(hr)) { - ERROR_LOG(G3D, "Failed to create vertex declaration!"); + ERROR_LOG(Log::G3D, "Failed to create vertex declaration!"); pHardwareVertexDecl = nullptr; } @@ -322,7 +322,7 @@ void DrawEngineDX9::DoFlush() { gpuStats.numUncachedVertsDrawn += vertexCount; prim = IndexGenerator::GeneralPrim((GEPrimitiveType)drawInds_[0].prim); - VERBOSE_LOG(G3D, "Flush prim %i SW! %i verts in one go", prim, vertexCount); + VERBOSE_LOG(Log::G3D, "Flush prim %i SW! %i verts in one go", prim, vertexCount); u16 *inds = decIndex_; SoftwareTransformResult result{}; @@ -334,10 +334,16 @@ void DrawEngineDX9::DoFlush() { params.texCache = textureCache_; params.allowClear = true; params.allowSeparateAlphaClear = false; - params.provokeFlatFirst = true; params.flippedY = false; params.usesHalfZ = true; + if (gstate.getShadeMode() == GE_SHADE_FLAT) { + // We need to rotate the index buffer to simulate a different provoking vertex. + // We do this before line expansion etc. + int indexCount = RemainingIndices(inds); + IndexBufferProvokingLastToFirst(prim, inds, vertexCount); + } + // We need correct viewport values in gstate_c already. if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) { ViewportAndScissor vpAndScissor; @@ -382,7 +388,7 @@ void DrawEngineDX9::DoFlush() { VSShader *vshader = shaderManager_->ApplyShader(false, false, dec_, decOptions_.expandAllWeightsToFloat, true, pipelineState_); - if (result.action == SW_DRAW_PRIMITIVES) { + if (result.action == SW_DRAW_INDEXED) { if (result.setStencil) { dxstate.stencilFunc.set(D3DCMP_ALWAYS); dxstate.stencilRef.set(result.stencilValue); @@ -393,11 +399,7 @@ void DrawEngineDX9::DoFlush() { // Might help for text drawing. device_->SetVertexDeclaration(transformedVertexDecl_); - if (result.drawIndexed) { - device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, numDecodedVerts_, D3DPrimCount(d3d_prim[prim], result.drawNumTrans), inds, D3DFMT_INDEX16, result.drawBuffer, sizeof(TransformedVertex)); - } else { - device_->DrawPrimitiveUP(d3d_prim[prim], D3DPrimCount(d3d_prim[prim], result.drawNumTrans), result.drawBuffer, sizeof(TransformedVertex)); - } + device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, numDecodedVerts_, D3DPrimCount(d3d_prim[prim], result.drawNumTrans), inds, D3DFMT_INDEX16, result.drawBuffer, sizeof(TransformedVertex)); } else if (result.action == SW_CLEAR) { u32 clearColor = result.color; float clearDepth = result.depth; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index cd821ad71c..cf49fa1c0a 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -69,7 +69,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Sanity check gstate if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) { - ERROR_LOG(G3D, "gstate has drifted out of sync!"); + ERROR_LOG(Log::G3D, "gstate has drifted out of sync!"); } // No need to flush before the tex scale/offset commands if we are baking @@ -86,7 +86,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) if (g_Config.bHardwareTessellation) { // Disable hardware tessellation bacause DX9 is still unsupported. - ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation"); + ERROR_LOG(Log::G3D, "Hardware Tessellation is unsupported, falling back to software tessellation"); auto gr = GetI18NCategory(I18NCat::GRAPHICS); // TODO: Badly formulated g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("Turn off Hardware Tessellation - unsupported")); @@ -131,7 +131,7 @@ void GPU_DX9::BeginHostFrame() { if (gstate_c.useFlagsChanged) { // TODO: It'd be better to recompile them in the background, probably? // This most likely means that saw equal depth changed. - WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers"); + WARN_LOG(Log::G3D, "Shader use flags changed, clearing all shaders and depth buffers"); shaderManager_->ClearShaders(); framebufferManager_->ClearAllDepthBuffers(); gstate_c.useFlagsChanged = false; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 790e6f7609..bddc01ecf0 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -61,12 +61,12 @@ PSShader::PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code) : i if (!errorMessage.empty()) { if (success) { - ERROR_LOG(G3D, "Warnings in shader compilation!"); + ERROR_LOG(Log::G3D, "Warnings in shader compilation!"); } else { - ERROR_LOG(G3D, "Error in shader compilation!"); + ERROR_LOG(Log::G3D, "Error in shader compilation!"); } - ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str()); - ERROR_LOG(G3D, "Shader source:\n%s", LineNumberString(code).c_str()); + ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str()); + ERROR_LOG(Log::G3D, "Shader source:\n%s", LineNumberString(code).c_str()); OutputDebugStringUTF8("Messages:\n"); OutputDebugStringUTF8(errorMessage.c_str()); Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code); @@ -79,7 +79,7 @@ PSShader::PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code) : i shader = NULL; return; } else { - VERBOSE_LOG(G3D, "Compiled pixel shader:\n%s\n", (const char *)code); + VERBOSE_LOG(Log::G3D, "Compiled pixel shader:\n%s\n", (const char *)code); } } @@ -110,12 +110,12 @@ VSShader::VSShader(LPDIRECT3DDEVICE9 device, VShaderID id, const char *code, boo success = CompileVertexShaderD3D9(device, code, &shader, &errorMessage); if (!errorMessage.empty()) { if (success) { - ERROR_LOG(G3D, "Warnings in shader compilation!"); + ERROR_LOG(Log::G3D, "Warnings in shader compilation!"); } else { - ERROR_LOG(G3D, "Error in shader compilation!"); + ERROR_LOG(Log::G3D, "Error in shader compilation!"); } - ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str()); - ERROR_LOG(G3D, "Shader source:\n%s", code); + ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str()); + ERROR_LOG(Log::G3D, "Shader source:\n%s", code); OutputDebugStringUTF8("Messages:\n"); OutputDebugStringUTF8(errorMessage.c_str()); Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code); @@ -128,7 +128,7 @@ VSShader::VSShader(LPDIRECT3DDEVICE9 device, VShaderID id, const char *code, boo shader = NULL; return; } else { - VERBOSE_LOG(G3D, "Compiled vertex shader:\n%s\n", (const char *)code); + VERBOSE_LOG(Log::G3D, "Compiled vertex shader:\n%s\n", (const char *)code); } } @@ -596,9 +596,9 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat if (!vs || vs->Failed()) { if (!vs) { // TODO: Report this? - ERROR_LOG(G3D, "Shader generation failed, falling back to software transform"); + ERROR_LOG(Log::G3D, "Shader generation failed, falling back to software transform"); } else { - ERROR_LOG(G3D, "Shader compilation failed, falling back to software transform"); + ERROR_LOG(Log::G3D, "Shader compilation failed, falling back to software transform"); } if (!g_Config.bHideSlowWarnings) { auto gr = GetI18NCategory(I18NCat::GRAPHICS); diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 04a1aafad1..ac130dd4c3 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -79,7 +79,7 @@ TextureCacheDX9::TextureCacheDX9(Draw::DrawContext *draw, Draw2D *draw2D) result = device_->GetDeviceCaps(&pCaps); } if (FAILED(result)) { - WARN_LOG(G3D, "Failed to get the device caps!"); + WARN_LOG(Log::G3D, "Failed to get the device caps!"); maxAnisotropyLevel = 16; } else { maxAnisotropyLevel = pCaps.MaxAnisotropy; @@ -264,7 +264,7 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) { } if (FAILED(hr)) { - INFO_LOG(G3D, "Failed to create D3D texture: %dx%d", tw, th); + INFO_LOG(Log::G3D, "Failed to create D3D texture: %dx%d", tw, th); ReleaseTexture(entry, true); return; } @@ -284,7 +284,7 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) { result = ((LPDIRECT3DTEXTURE9)texture)->LockRect(dstLevel, &rect, NULL, lockFlag); if (FAILED(result)) { - ERROR_LOG(G3D, "Failed to lock D3D 2D texture at level %d: %dx%d", i, plan.w, plan.h); + ERROR_LOG(Log::G3D, "Failed to lock D3D 2D texture at level %d: %dx%d", i, plan.w, plan.h); return; } uint8_t *data = (uint8_t *)rect.pBits; @@ -297,7 +297,7 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) { D3DLOCKED_BOX box; HRESULT result = ((LPDIRECT3DVOLUMETEXTURE9)texture)->LockBox(0, &box, nullptr, D3DLOCK_DISCARD); if (FAILED(result)) { - ERROR_LOG(G3D, "Failed to lock D3D 2D texture: %dx%dx%d", plan.w, plan.h, plan.depth); + ERROR_LOG(Log::G3D, "Failed to lock D3D 2D texture: %dx%dx%d", plan.w, plan.h, plan.depth); return; } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 1fcfc119bd..e2161572d3 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -356,7 +356,6 @@ void DrawEngineGLES::DoFlush() { params.texCache = textureCache_; params.allowClear = true; // Clear in OpenGL respects scissor rects, so we'll use it. params.allowSeparateAlphaClear = true; - params.provokeFlatFirst = false; params.flippedY = framebufferManager_->UseBufferedRendering(); params.usesHalfZ = false; @@ -375,7 +374,7 @@ void DrawEngineGLES::DoFlush() { if (gl_extensions.IsGLES && !gl_extensions.GLES3) { constexpr int vertexCountLimit = 0x10000 / 3; if (vertexCount > vertexCountLimit) { - WARN_LOG_REPORT_ONCE(manyVerts, G3D, "Truncating vertex count from %d to %d", vertexCount, vertexCountLimit); + WARN_LOG_REPORT_ONCE(manyVerts, Log::G3D, "Truncating vertex count from %d to %d", vertexCount, vertexCountLimit); vertexCount = vertexCountLimit; } } @@ -415,18 +414,12 @@ void DrawEngineGLES::DoFlush() { goto bail; } - if (result.action == SW_DRAW_PRIMITIVES) { - if (result.drawIndexed) { - vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, numDecodedVerts_ * sizeof(TransformedVertex), 4, &vertexBuffer); - indexBufferOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(uint16_t) * result.drawNumTrans, 2, &indexBuffer); - render_->DrawIndexed( - softwareInputLayout_, vertexBuffer, vertexBufferOffset, indexBuffer, indexBufferOffset, - glprim[prim], result.drawNumTrans, GL_UNSIGNED_SHORT); - } else { - vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, result.drawNumTrans * sizeof(TransformedVertex), 4, &vertexBuffer); - render_->Draw( - softwareInputLayout_, vertexBuffer, vertexBufferOffset, glprim[prim], 0, result.drawNumTrans); - } + if (result.action == SW_DRAW_INDEXED) { + vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, numDecodedVerts_ * sizeof(TransformedVertex), 4, &vertexBuffer); + indexBufferOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(uint16_t) * result.drawNumTrans, 2, &indexBuffer); + render_->DrawIndexed( + softwareInputLayout_, vertexBuffer, vertexBufferOffset, indexBuffer, indexBufferOffset, + glprim[prim], result.drawNumTrans, GL_UNSIGNED_SHORT); } else if (result.action == SW_CLEAR) { u32 clearColor = result.color; float clearDepth = result.depth; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 510cd58e91..b70d429c1c 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -75,7 +75,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Sanity check gstate if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) { - ERROR_LOG(G3D, "gstate has drifted out of sync!"); + ERROR_LOG(Log::G3D, "gstate has drifted out of sync!"); } // No need to flush before the tex scale/offset commands if we are baking @@ -105,18 +105,18 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) gstate_c.useFlagsChanged = false; if (shaderManagerGL_->LoadCache(f)) - NOTICE_LOG(G3D, "Precompiling the shader cache from '%s'", shaderCachePath_.c_str()); + NOTICE_LOG(Log::G3D, "Precompiling the shader cache from '%s'", shaderCachePath_.c_str()); } } } else { - INFO_LOG(G3D, "Shader cache disabled. Not loading."); + INFO_LOG(Log::G3D, "Shader cache disabled. Not loading."); } } if (g_Config.bHardwareTessellation) { // Disable hardware tessellation if device is unsupported. if (!drawEngine_.SupportsHWTessellation()) { - ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation"); + ERROR_LOG(Log::G3D, "Hardware Tessellation is unsupported, falling back to software tessellation"); auto gr = GetI18NCategory(I18NCat::GRAPHICS); g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("Turn off Hardware Tessellation - unsupported")); } @@ -131,7 +131,7 @@ GPU_GLES::~GPU_GLES() { if (g_Config.bShaderCache) { shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_); } else { - INFO_LOG(G3D, "Shader cache disabled. Not saving."); + INFO_LOG(Log::G3D, "Shader cache disabled. Not saving."); } } fragmentTestCache_.Clear(); @@ -169,11 +169,9 @@ u32 GPU_GLES::CheckGPUFeatures() const { if ((gl_extensions.IsGLES && !gl_extensions.GLES3) || (!gl_extensions.IsGLES && !gl_extensions.VersionGEThan(1, 3))) features &= ~GPU_USE_LIGHT_UBERSHADER; - if (IsVREnabled()) { + if (IsVREnabled() || g_Config.bForceVR) { features |= GPU_USE_VIRTUAL_REALITY; - } - if (IsMultiviewSupported()) { - features |= GPU_USE_SINGLE_PASS_STEREO; + features &= ~GPU_USE_VS_RANGE_CULLING; } if (!gl_extensions.GLES3) { @@ -224,7 +222,7 @@ void GPU_GLES::BuildReportingInfo() { } void GPU_GLES::DeviceLost() { - INFO_LOG(G3D, "GPU_GLES: DeviceLost"); + INFO_LOG(Log::G3D, "GPU_GLES: DeviceLost"); // Simply drop all caches and textures. // FBOs appear to survive? Or no? @@ -263,7 +261,7 @@ void GPU_GLES::BeginHostFrame() { if (gstate_c.useFlagsChanged) { // TODO: It'd be better to recompile them in the background, probably? // This most likely means that saw equal depth changed. - WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers"); + WARN_LOG(Log::G3D, "Shader use flags changed, clearing all shaders and depth buffers"); shaderManager_->ClearShaders(); framebufferManager_->ClearAllDepthBuffers(); gstate_c.useFlagsChanged = false; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index dc36d8e114..b1fd36871a 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -412,7 +412,8 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin // Set HUD mode if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { if (GuessVRDrawingHUD(is2D, flatScreen)) { - render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDisplayScale * 480.0f / 272.0f); + float aspect = 480.0f / 272.0f * (IsImmersiveVRMode() ? 0.5f : 1.0f); + render_->SetUniformF1(&u_scaleX, g_Config.fHeadUpDisplayScale * aspect); render_->SetUniformF1(&u_scaleY, g_Config.fHeadUpDisplayScale); } else { render_->SetUniformF1(&u_scaleX, 1.0f); @@ -423,21 +424,18 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin // Update any dirty uniforms before we draw if (dirty & DIRTY_PROJMATRIX) { if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { - Matrix4x4 leftEyeMatrix, rightEyeMatrix; + Matrix4x4 vrProjection; if (flatScreen || is2D) { - memcpy(&leftEyeMatrix, gstate.projMatrix, 16 * sizeof(float)); - memcpy(&rightEyeMatrix, gstate.projMatrix, 16 * sizeof(float)); + memcpy(&vrProjection, gstate.projMatrix, 16 * sizeof(float)); } else { - UpdateVRProjection(gstate.projMatrix, leftEyeMatrix.m, rightEyeMatrix.m); + UpdateVRProjection(gstate.projMatrix, vrProjection.m); } UpdateVRParams(gstate.projMatrix); - FlipProjMatrix(leftEyeMatrix, useBufferedRendering); - FlipProjMatrix(rightEyeMatrix, useBufferedRendering); - ScaleProjMatrix(leftEyeMatrix, useBufferedRendering); - ScaleProjMatrix(rightEyeMatrix, useBufferedRendering); + FlipProjMatrix(vrProjection, useBufferedRendering); + ScaleProjMatrix(vrProjection, useBufferedRendering); - render_->SetUniformM4x4Stereo("u_proj_lens", &u_proj_lens, leftEyeMatrix.m, rightEyeMatrix.m); + render_->SetUniformM4x4(&u_proj_lens, vrProjection.m); } Matrix4x4 flippedMatrix; @@ -484,7 +482,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin } if (dirty & DIRTY_FOGCOLOR) { SetColorUniform3(render_, &u_fogcolor, gstate.fogcolor); - if (IsVREnabled()) { + if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) { SetVRCompat(VR_COMPAT_FOG_COLOR, gstate.fogcolor); } } @@ -752,7 +750,7 @@ Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) { std::string errorString; FragmentShaderFlags flags; if (!GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString)) { - ERROR_LOG_REPORT(G3D, "FS shader gen error: %s (%s: %08x:%08x)", errorString.c_str(), "GLES", FSID.d[0], FSID.d[1]); + ERROR_LOG_REPORT(Log::G3D, "FS shader gen error: %s (%s: %08x:%08x)", errorString.c_str(), "GLES", FSID.d[0], FSID.d[1]); return nullptr; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_)); @@ -770,7 +768,7 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { std::string errorString; VertexShaderFlags flags; if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &errorString)) { - ERROR_LOG_REPORT(G3D, "VS shader gen error: %s (%s: %08x:%08x)", errorString.c_str(), "GLES", VSID.d[0], VSID.d[1]); + ERROR_LOG_REPORT(Log::G3D, "VS shader gen error: %s (%s: %08x:%08x)", errorString.c_str(), "GLES", VSID.d[0], VSID.d[1]); return nullptr; } _assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_)); @@ -804,7 +802,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess // Vertex shader not in cache. Let's compile it. vs = CompileVertexShader(*VSID); if (!vs) { - ERROR_LOG(G3D, "Vertex shader generation failed, falling back to software transform"); + ERROR_LOG(Log::G3D, "Vertex shader generation failed, falling back to software transform"); if (!g_Config.bHideSlowWarnings) { auto gr = GetI18NCategory(I18NCat::GRAPHICS); g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("hardware transform error - falling back to software"), 2.5f); @@ -855,7 +853,7 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, // Could fail to generate, in which case we're kinda screwed. fs = CompileFragmentShader(FSID); if (!fs) { - ERROR_LOG(G3D, "Failed to generate fragment shader with ID %08x:%08x", FSID.d[0], FSID.d[1]); + ERROR_LOG(Log::G3D, "Failed to generate fragment shader with ID %08x:%08x", FSID.d[0], FSID.d[1]); // Still insert it so we don't end up spamming generation. } fsCache_.Insert(FSID, fs); @@ -1046,7 +1044,7 @@ bool ShaderManagerGLES::LoadCache(File::IOFile &f) { // Sanity check the file contents if (header.numFragmentShaders > 1000 || header.numVertexShaders > 1000 || header.numLinkedPrograms > 1000) { - ERROR_LOG(G3D, "Corrupt shader cache file header, aborting."); + ERROR_LOG(Log::G3D, "Corrupt shader cache file header, aborting."); return false; } @@ -1056,7 +1054,7 @@ bool ShaderManagerGLES::LoadCache(File::IOFile &f) { expectedSize += header.numFragmentShaders * sizeof(FShaderID); expectedSize += header.numLinkedPrograms * (sizeof(VShaderID) + sizeof(FShaderID)); if (sz != expectedSize) { - ERROR_LOG(G3D, "Shader cache file is wrong size: %lld instead of %lld", sz, expectedSize); + ERROR_LOG(Log::G3D, "Shader cache file is wrong size: %lld instead of %lld", sz, expectedSize); return false; } @@ -1099,7 +1097,7 @@ bool ShaderManagerGLES::LoadCache(File::IOFile &f) { if (!vsCache_.ContainsKey(id)) { if (id.Bit(VS_BIT_IS_THROUGH) && id.Bit(VS_BIT_USE_HW_TRANSFORM)) { // Clearly corrupt, bailing. - ERROR_LOG_REPORT(G3D, "Corrupt shader cache: Both IS_THROUGH and USE_HW_TRANSFORM set."); + ERROR_LOG_REPORT(Log::G3D, "Corrupt shader cache: Both IS_THROUGH and USE_HW_TRANSFORM set."); pending.Clear(); return false; } @@ -1108,14 +1106,13 @@ bool ShaderManagerGLES::LoadCache(File::IOFile &f) { if (!vs) { // Give up on using the cache, just bail. We can't safely create the fallback shaders here // without trying to deduce the vertType from the VSID. - ERROR_LOG(G3D, "Failed to compile a vertex shader loading from cache. Skipping rest of shader cache."); - delete vs; + ERROR_LOG(Log::G3D, "Failed to compile a vertex shader loading from cache. Skipping rest of shader cache."); pending.Clear(); return false; } vsCache_.Insert(id, vs); } else { - WARN_LOG(G3D, "Duplicate vertex shader found in GL shader cache, ignoring"); + WARN_LOG(Log::G3D, "Duplicate vertex shader found in GL shader cache, ignoring"); } } @@ -1126,14 +1123,13 @@ bool ShaderManagerGLES::LoadCache(File::IOFile &f) { if (!fs) { // Give up on using the cache - something went wrong. // We'll still keep the shaders we generated so far around. - ERROR_LOG(G3D, "Failed to compile a fragment shader loading from cache. Skipping rest of shader cache."); - delete fs; + ERROR_LOG(Log::G3D, "Failed to compile a fragment shader loading from cache. Skipping rest of shader cache."); pending.Clear(); return false; } fsCache_.Insert(id, fs); } else { - WARN_LOG(G3D, "Duplicate fragment shader found in GL shader cache, ignoring"); + WARN_LOG(Log::G3D, "Duplicate fragment shader found in GL shader cache, ignoring"); } } @@ -1155,7 +1151,7 @@ bool ShaderManagerGLES::LoadCache(File::IOFile &f) { // Okay, finally done. Time to report status. double finish = time_now_d(); - NOTICE_LOG(G3D, "Precompile: Compiled and linked %d programs (%d vertex, %d fragment) in %0.1f milliseconds", (int)pending.link.size(), (int)pending.vert.size(), (int)pending.frag.size(), 1000 * (finish - pending.start)); + NOTICE_LOG(Log::G3D, "Precompile: Compiled and linked %d programs (%d vertex, %d fragment) in %0.1f milliseconds", (int)pending.link.size(), (int)pending.vert.size(), (int)pending.frag.size(), 1000 * (finish - pending.start)); pending.Clear(); return true; @@ -1165,7 +1161,7 @@ void ShaderManagerGLES::SaveCache(const Path &filename, DrawEngineGLES *drawEngi if (linkedShaderCache_.empty()) { return; } - INFO_LOG(G3D, "Saving the shader cache to '%s'", filename.c_str()); + INFO_LOG(Log::G3D, "Saving the shader cache to '%s'", filename.c_str()); FILE *f = File::OpenCFile(filename, "wb"); if (!f) { // Can't save, give up for now. diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index cb045691fc..18be9d359f 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -102,7 +102,7 @@ bool FramebufferManagerGLES::ReadbackStencilbuffer(Draw::Framebuffer *fbo, int x using namespace Draw; if (!fbo) { - ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackStencilbufferSync: bad fbo"); + ERROR_LOG_REPORT_ONCE(vfbfbozero, Log::sceGe, "ReadbackStencilbufferSync: bad fbo"); return false; } diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 25fe23eea3..62b2ca3765 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -321,7 +321,7 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { data = (u8 *)AllocateAlignedMemory(dataSize, 16); if (!data) { - ERROR_LOG(G3D, "Ran out of RAM trying to allocate a temporary texture upload buffer (%dx%d)", mipWidth, mipHeight); + ERROR_LOG(Log::G3D, "Ran out of RAM trying to allocate a temporary texture upload buffer (%dx%d)", mipWidth, mipHeight); return; } @@ -409,7 +409,7 @@ bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, buffer.Allocate(w, h, GE_FORMAT_8888, false); renderManager->CopyImageToMemorySync(entry->textureName, level, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, (uint8_t *)buffer.GetData(), w, "GetCurrentTextureDebug"); } else { - ERROR_LOG(G3D, "Failed to get debug texture: texture is null"); + ERROR_LOG(Log::G3D, "Failed to get debug texture: texture is null"); } gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); framebufferManager_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug"); diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index 21ad2d3f0f..38af2f75ba 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -102,7 +102,7 @@ bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { #if !PPSSPP_PLATFORM(SWITCH) case GPUCORE_VULKAN: if (!ctx) { - ERROR_LOG(G3D, "Unable to init Vulkan GPU backend, no context"); + ERROR_LOG(Log::G3D, "Unable to init Vulkan GPU backend, no context"); break; } SetGPU(new GPU_Vulkan(ctx, draw)); diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 87c79f3462..147e31c724 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -371,6 +371,7 @@ + @@ -511,6 +512,7 @@ true + true diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 6b35f8f33a..c59e28ed7b 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -273,6 +273,9 @@ Common + + Common + @@ -542,6 +545,9 @@ Common + + Common + diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 08ad845e05..80dc8b91c0 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -363,13 +363,13 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointersize is below 16, it's the old struct without stack info. if (args.IsValid() && args->size >= 16 && args->numStacks >= 256) { - return hleLogError(G3D, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid stack depth %d", args->numStacks); + return hleLogError(Log::G3D, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid stack depth %d", args->numStacks); } int id = -1; @@ -384,10 +384,10 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointersignal == PSP_GE_SIGNAL_HANDLER_PAUSE) { - ERROR_LOG_REPORT(G3D, "sceGeBreak: can't break signal-pausing list"); + ERROR_LOG_REPORT(Log::G3D, "sceGeBreak: can't break signal-pausing list"); } else return SCE_KERNEL_ERROR_ALREADY; @@ -620,7 +620,7 @@ void GPUCommon::NotifySteppingEnter() { void GPUCommon::NotifySteppingExit() { if (coreCollectDebugStats) { if (timeSteppingStarted_ <= 0.0) { - ERROR_LOG(G3D, "Mismatched stepping enter/exit."); + ERROR_LOG(Log::G3D, "Mismatched stepping enter/exit."); } double total = time_now_d() - timeSteppingStarted_; _dbg_assert_msg_(total >= 0.0, "Time spent stepping became negative"); @@ -648,7 +648,7 @@ bool GPUCommon::InterpretList(DisplayList &list) { gstate_c.offsetAddr = list.offsetAddr; if (!Memory::IsValidAddress(list.pc)) { - ERROR_LOG_REPORT(G3D, "DL PC = %08x WTF!!!!", list.pc); + ERROR_LOG_REPORT(Log::G3D, "DL PC = %08x WTF!!!!", list.pc); return true; } @@ -712,7 +712,7 @@ bool GPUCommon::InterpretList(DisplayList &list) { void GPUCommon::PSPFrame() { immCount_ = 0; if (dumpNextFrame_) { - NOTICE_LOG(G3D, "DUMPING THIS FRAME"); + NOTICE_LOG(Log::G3D, "DUMPING THIS FRAME"); dumpThisFrame_ = true; dumpNextFrame_ = false; } else if (dumpThisFrame_) { @@ -746,7 +746,7 @@ void GPUCommon::SlowRunLoop(DisplayList &list) { prev = 0; } GeDisassembleOp(list.pc, op, prev, temp, 256); - NOTICE_LOG(G3D, "%08x: %s", op, temp); + NOTICE_LOG(Log::G3D, "%08x: %s", op, temp); } gstate.cmdmem[cmd] = op; @@ -839,13 +839,13 @@ void GPUCommon::ProcessDLQueue() { // Seems to be correct behaviour to process the list anyway? if (startingTicks < busyTicks) { - DEBUG_LOG(G3D, "Can't execute a list yet, still busy for %lld ticks", busyTicks - startingTicks); + DEBUG_LOG(Log::G3D, "Can't execute a list yet, still busy for %lld ticks", busyTicks - startingTicks); //return; } for (int listIndex = GetNextListIndex(); listIndex != -1; listIndex = GetNextListIndex()) { DisplayList &l = dls[listIndex]; - DEBUG_LOG(G3D, "Starting DL execution at %08x - stall = %08x", l.pc, l.stall); + DEBUG_LOG(Log::G3D, "Starting DL execution at %08x - stall = %08x", l.pc, l.stall); if (!InterpretList(l)) { return; } else { @@ -889,7 +889,7 @@ void GPUCommon::Execute_Origin(u32 op, u32 diff) { void GPUCommon::Execute_Jump(u32 op, u32 diff) { const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); if (!Memory::IsValidAddress(target)) { - ERROR_LOG(G3D, "JUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + ERROR_LOG(Log::G3D, "JUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); UpdateState(GPUSTATE_ERROR); return; } @@ -906,7 +906,7 @@ void GPUCommon::Execute_BJump(u32 op, u32 diff) { UpdatePC(currentList->pc, target - 4); currentList->pc = target - 4; // pc will be increased after we return, counteract that } else { - ERROR_LOG(G3D, "BJUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + ERROR_LOG(Log::G3D, "BJUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); UpdateState(GPUSTATE_ERROR); } } @@ -917,7 +917,7 @@ void GPUCommon::Execute_Call(u32 op, u32 diff) { const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); if (!Memory::IsValidAddress(target)) { - ERROR_LOG(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + ERROR_LOG(Log::G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); UpdateState(GPUSTATE_ERROR); return; } @@ -941,7 +941,7 @@ void GPUCommon::DoExecuteCall(u32 target) { } if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) { - ERROR_LOG(G3D, "CALL: Stack full!"); + ERROR_LOG(Log::G3D, "CALL: Stack full!"); // TODO: UpdateState(GPUSTATE_ERROR) ? } else { auto &stackEntry = currentList->stack[currentList->stackptr++]; @@ -955,7 +955,7 @@ void GPUCommon::DoExecuteCall(u32 target) { void GPUCommon::Execute_Ret(u32 op, u32 diff) { if (currentList->stackptr == 0) { - DEBUG_LOG(G3D, "RET: Stack empty!"); + DEBUG_LOG(Log::G3D, "RET: Stack empty!"); } else { auto &stackEntry = currentList->stack[--currentList->stackptr]; gstate_c.offsetAddr = stackEntry.offsetAddr; @@ -965,7 +965,7 @@ void GPUCommon::Execute_Ret(u32 op, u32 diff) { currentList->pc = target - 4; #ifdef _DEBUG if (!Memory::IsValidAddress(currentList->pc)) { - ERROR_LOG_REPORT(G3D, "Invalid DL PC %08x on return", currentList->pc); + ERROR_LOG_REPORT(Log::G3D, "Invalid DL PC %08x on return", currentList->pc); UpdateState(GPUSTATE_ERROR); } #endif @@ -998,12 +998,12 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { if (sceKernelGetCompiledSdkVersion() <= 0x02000010) currentList->state = PSP_GE_DL_STATE_PAUSED; currentList->signal = behaviour; - DEBUG_LOG(G3D, "Signal with wait. signal/end: %04x %04x", signal, enddata); + DEBUG_LOG(Log::G3D, "Signal with wait. signal/end: %04x %04x", signal, enddata); break; case PSP_GE_SIGNAL_HANDLER_CONTINUE: // Resume the list right away, then call the handler. currentList->signal = behaviour; - DEBUG_LOG(G3D, "Signal without wait. signal/end: %04x %04x", signal, enddata); + DEBUG_LOG(Log::G3D, "Signal without wait. signal/end: %04x %04x", signal, enddata); break; case PSP_GE_SIGNAL_HANDLER_PAUSE: // Pause the list instead of ending at the next FINISH. @@ -1012,7 +1012,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { // But right now, signal is always reset by interrupts, so that causes pause to not work. trigger = false; currentList->signal = behaviour; - DEBUG_LOG(G3D, "Signal with Pause. signal/end: %04x %04x", signal, enddata); + DEBUG_LOG(Log::G3D, "Signal with Pause. signal/end: %04x %04x", signal, enddata); break; case PSP_GE_SIGNAL_SYNC: // Acts as a memory barrier, never calls any user code. @@ -1021,7 +1021,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { // However, this is likely a bug in how GE signal interrupts are handled. trigger = false; currentList->signal = behaviour; - DEBUG_LOG(G3D, "Signal with Sync. signal/end: %04x %04x", signal, enddata); + DEBUG_LOG(Log::G3D, "Signal with Sync. signal/end: %04x %04x", signal, enddata); break; case PSP_GE_SIGNAL_JUMP: case PSP_GE_SIGNAL_RJUMP: @@ -1041,12 +1041,12 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { } if (!Memory::IsValidAddress(target)) { - ERROR_LOG_REPORT(G3D, "Signal with Jump (%s): bad address. signal/end: %04x %04x", targetType, signal, enddata); + ERROR_LOG_REPORT(Log::G3D, "Signal with Jump (%s): bad address. signal/end: %04x %04x", targetType, signal, enddata); UpdateState(GPUSTATE_ERROR); } else { UpdatePC(currentList->pc, target); currentList->pc = target; - DEBUG_LOG(G3D, "Signal with Jump (%s). signal/end: %04x %04x", targetType, signal, enddata); + DEBUG_LOG(Log::G3D, "Signal with Jump (%s). signal/end: %04x %04x", targetType, signal, enddata); } } break; @@ -1068,9 +1068,9 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { } if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) { - ERROR_LOG_REPORT(G3D, "Signal with Call (%s): stack full. signal/end: %04x %04x", targetType, signal, enddata); + ERROR_LOG_REPORT(Log::G3D, "Signal with Call (%s): stack full. signal/end: %04x %04x", targetType, signal, enddata); } else if (!Memory::IsValidAddress(target)) { - ERROR_LOG_REPORT(G3D, "Signal with Call (%s): bad address. signal/end: %04x %04x", targetType, signal, enddata); + ERROR_LOG_REPORT(Log::G3D, "Signal with Call (%s): bad address. signal/end: %04x %04x", targetType, signal, enddata); UpdateState(GPUSTATE_ERROR); } else { // TODO: This might save/restore other state... @@ -1080,7 +1080,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { stackEntry.baseAddr = gstate.base; UpdatePC(currentList->pc, target); currentList->pc = target; - DEBUG_LOG(G3D, "Signal with Call (%s). signal/end: %04x %04x", targetType, signal, enddata); + DEBUG_LOG(Log::G3D, "Signal with Call (%s). signal/end: %04x %04x", targetType, signal, enddata); } } break; @@ -1089,7 +1089,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { trigger = false; currentList->signal = behaviour; if (currentList->stackptr == 0) { - ERROR_LOG_REPORT(G3D, "Signal with Return: stack empty. signal/end: %04x %04x", signal, enddata); + ERROR_LOG_REPORT(Log::G3D, "Signal with Return: stack empty. signal/end: %04x %04x", signal, enddata); } else { // TODO: This might save/restore other state... auto &stackEntry = currentList->stack[--currentList->stackptr]; @@ -1097,12 +1097,12 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { gstate.base = stackEntry.baseAddr; UpdatePC(currentList->pc, stackEntry.pc); currentList->pc = stackEntry.pc; - DEBUG_LOG(G3D, "Signal with Return. signal/end: %04x %04x", signal, enddata); + DEBUG_LOG(Log::G3D, "Signal with Return. signal/end: %04x %04x", signal, enddata); } } break; default: - ERROR_LOG_REPORT(G3D, "UNKNOWN Signal UNIMPLEMENTED %i ! signal/end: %04x %04x", behaviour, signal, enddata); + ERROR_LOG_REPORT(Log::G3D, "UNKNOWN Signal UNIMPLEMENTED %i ! signal/end: %04x %04x", behaviour, signal, enddata); break; } // TODO: Technically, jump/call/ret should generate an interrupt, but before the pc change maybe? @@ -1155,7 +1155,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { } break; default: - DEBUG_LOG(G3D,"Ah, not finished: %06x", prev & 0xFFFFFF); + DEBUG_LOG(Log::G3D,"Ah, not finished: %06x", prev & 0xFFFFFF); break; } } @@ -1178,7 +1178,7 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { if (Memory::IsValidRange(gstate_c.vertexAddr, bytesRead)) { const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); if (!control_points) { - ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Invalid verts in bounding box check"); + ERROR_LOG_REPORT_ONCE(boundingbox, Log::G3D, "Invalid verts in bounding box check"); currentList->bboxResult = true; return; } @@ -1188,7 +1188,7 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { int indexShift = ((gstate.vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT) - 1; inds = Memory::GetPointerUnchecked(gstate_c.indexAddr); if (!inds || !Memory::IsValidRange(gstate_c.indexAddr, count << indexShift)) { - ERROR_LOG_REPORT_ONCE(boundingboxInds, G3D, "Invalid inds in bounding box check"); + ERROR_LOG_REPORT_ONCE(boundingboxInds, Log::G3D, "Invalid inds in bounding box check"); currentList->bboxResult = true; return; } @@ -1208,7 +1208,7 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { } AdvanceVerts(gstate.vertType, count, bytesRead); } else { - ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Bad bounding box data: %06x", count); + ERROR_LOG_REPORT_ONCE(boundingbox, Log::G3D, "Bad bounding box data: %06x", count); // Data seems invalid. Let's assume the box test passed. currentList->bboxResult = true; } @@ -1223,7 +1223,7 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { if (immCount_ >= MAX_IMMBUFFER_SIZE) { // Only print once for each overrun. if (immCount_ == MAX_IMMBUFFER_SIZE) { - ERROR_LOG_REPORT_ONCE(exceed_imm_buffer, G3D, "Exceeded immediate draw buffer size. gstate.imm_ap=%06x , prim=%d", gstate.imm_ap & 0xFFFFFF, (int)immPrim_); + ERROR_LOG_REPORT_ONCE(exceed_imm_buffer, Log::G3D, "Exceeded immediate draw buffer size. gstate.imm_ap=%06x , prim=%d", gstate.imm_ap & 0xFFFFFF, (int)immPrim_); } if (immCount_ < 0x7fffffff) // Paranoia :) immCount_++; @@ -1270,7 +1270,7 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { if (immCount_ == flushPrimCount[immPrim_ & 7]) FlushImm(); } else { - ERROR_LOG_REPORT_ONCE(imm_draw_prim, G3D, "Immediate draw: Unexpected primitive %d at count %d", prim, immCount_); + ERROR_LOG_REPORT_ONCE(imm_draw_prim, Log::G3D, "Immediate draw: Unexpected primitive %d at count %d", prim, immCount_); } } @@ -1307,7 +1307,7 @@ void GPUCommon::FlushImm() { bool prevDither = gstate.isDitherEnabled(); if ((immFlags_ & GE_IMM_CLIPMASK) != 0) { - WARN_LOG_REPORT_ONCE(geimmclipvalue, G3D, "Imm vertex used clip value, flags=%06x", immFlags_); + WARN_LOG_REPORT_ONCE(geimmclipvalue, Log::G3D, "Imm vertex used clip value, flags=%06x", immFlags_); } bool changed = texturing != prevTexturing || cullEnable != prevCullEnable || dither != prevDither; @@ -1341,7 +1341,7 @@ void GPUCommon::FlushImm() { void GPUCommon::Execute_Unknown(u32 op, u32 diff) { if ((op & 0xFFFFFF) != 0) - WARN_LOG_REPORT_ONCE(unknowncmd, G3D, "Unknown GE command : %08x ", op); + WARN_LOG_REPORT_ONCE(unknowncmd, Log::G3D, "Unknown GE command : %08x ", op); } void GPUCommon::FastLoadBoneMatrix(u32 target) { @@ -1666,7 +1666,7 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { int bpp = gstate.getTransferBpp(); - DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); + DEBUG_LOG(Log::G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); gpuStats.numBlockTransfers++; // For VRAM, we wrap around when outside valid memory (mirrors still work.) @@ -1675,11 +1675,12 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { if ((dstBasePtr & 0x04800000) == 0x04800000) dstBasePtr &= ~0x00800000; - // Use height less one to account for width, which can be greater or less than stride. + // Use height less one to account for width, which can be greater or less than stride, and then add it on for the last line. + // NOTE: The sizes are only used for validity checks and memory info tracking. const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; - const uint32_t srcSize = (height - 1) * (srcStride + width) * bpp; const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; - const uint32_t dstSize = (height - 1) * (dstStride + width) * bpp; + const uint32_t srcSize = ((height - 1) * srcStride) + width * bpp; + const uint32_t dstSize = ((height - 1) * dstStride) + width * bpp; bool srcDstOverlap = src + srcSize > dst && dst + dstSize > src; bool srcValid = Memory::IsValidRange(src, srcSize); @@ -1842,7 +1843,7 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { } else { // This seems to cause the GE to require a break/reset on a PSP. // TODO: Handle that and figure out which bytes are still copied? - ERROR_LOG_REPORT_ONCE(invalidtransfer, G3D, "Block transfer invalid: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); + ERROR_LOG_REPORT_ONCE(invalidtransfer, Log::G3D, "Block transfer invalid: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); } if (framebufferManager_) { diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp index 144fd8276b..8d835da5ff 100644 --- a/GPU/GPUCommonHW.cpp +++ b/GPU/GPUCommonHW.cpp @@ -367,7 +367,7 @@ GPUCommonHW::GPUCommonHW(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPU for (size_t i = 0; i < ARRAY_SIZE(commonCommandTable); i++) { const u8 cmd = commonCommandTable[i].cmd; if (dupeCheck.find(cmd) != dupeCheck.end()) { - ERROR_LOG(G3D, "Command table Dupe: %02x (%i)", (int)cmd, (int)cmd); + ERROR_LOG(Log::G3D, "Command table Dupe: %02x (%i)", (int)cmd, (int)cmd); } else { dupeCheck.insert(cmd); } @@ -381,7 +381,7 @@ GPUCommonHW::GPUCommonHW(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPU // Find commands missing from the table. for (int i = 0; i < 0xEF; i++) { if (dupeCheck.find((u8)i) == dupeCheck.end()) { - ERROR_LOG(G3D, "Command missing from table: %02x (%i)", i, i); + ERROR_LOG(Log::G3D, "Command missing from table: %02x (%i)", i, i); } } @@ -519,7 +519,7 @@ void GPUCommonHW::CheckFlushOp(int cmd, u32 diff) { const u8 cmdFlags = cmdInfo_[cmd].flags; if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) { if (dumpThisFrame_) { - NOTICE_LOG(G3D, "================ FLUSH ================"); + NOTICE_LOG(Log::G3D, "================ FLUSH ================"); } drawEngineCommon_->DispatchFlush(); } @@ -916,7 +916,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) { gstate_c.framebufFormat = gstate.FrameBufFormat(); if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG(Log::G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); return; } @@ -977,7 +977,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) { u32 indexAddr = gstate_c.indexAddr; u32 indexSize = (vertexType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT; if (!Memory::IsValidRange(indexAddr, count * indexSize)) { - ERROR_LOG(G3D, "Bad index address %08x (%d)!", indexAddr, count); + ERROR_LOG(Log::G3D, "Bad index address %08x (%d)!", indexAddr, count); return; } inds = Memory::GetPointerUnchecked(indexAddr); @@ -1263,7 +1263,7 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) { CheckDepthUsage(vfb); if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG_REPORT(Log::G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); return; } @@ -1271,14 +1271,14 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) { const void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(Log::G3D, "Bad index address %08x!", gstate_c.indexAddr); return; } indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); } if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); + DEBUG_LOG_REPORT(Log::G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } // Can't flush after setting gstate_c.submitType below since it'll be a mess - it must be done already. @@ -1335,7 +1335,7 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) { CheckDepthUsage(vfb); if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG_REPORT(Log::G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); return; } @@ -1343,14 +1343,14 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) { const void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(Log::G3D, "Bad index address %08x!", gstate_c.indexAddr); return; } indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); } if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); + DEBUG_LOG_REPORT(Log::G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } // Can't flush after setting gstate_c.submitType below since it'll be a mess - it must be done already. diff --git a/GPU/Math3D.h b/GPU/Math3D.h index b9af0a7e44..0fa5ed78af 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -912,6 +912,7 @@ float MATH3D_CALL vectorGetByIndex(__m128 v) { #if defined(_M_SSE) // x, y, and z should be broadcast. Should only be used through Vec3f version. +// Note that this will read an extra float from the matrix, so it better not be at the end of an allocation! inline __m128 MATH3D_CALL Vec3ByMatrix43Internal(__m128 x, __m128 y, __m128 z, const float m[12]) { __m128 col0 = _mm_loadu_ps(m); __m128 col1 = _mm_loadu_ps(m + 3); diff --git a/GPU/Software/DrawPixelX86.cpp b/GPU/Software/DrawPixelX86.cpp index f539d681d3..2c887f44f1 100644 --- a/GPU/Software/DrawPixelX86.cpp +++ b/GPU/Software/DrawPixelX86.cpp @@ -101,7 +101,7 @@ SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) { regCache_.ForceRelease(RegCache::GEN_ARG_ID); if (!success) { - ERROR_LOG_REPORT(G3D, "Could not compile pixel func: %s", DescribePixelFuncID(id).c_str()); + ERROR_LOG_REPORT(Log::G3D, "Could not compile pixel func: %s", DescribePixelFuncID(id).c_str()); regCache_.Reset(false); EndWrite(); diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index 60afbd39a9..dae2c93118 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -314,7 +314,7 @@ static inline u32 LookupColor(unsigned int index, unsigned int level, const Samp return samplerID.cached.clut32[index + clutSharingOffset]; default: - ERROR_LOG_REPORT(G3D, "Software: Unsupported palette format: %x", samplerID.ClutFmt()); + ERROR_LOG_REPORT(Log::G3D, "Software: Unsupported palette format: %x", samplerID.ClutFmt()); return 0; } } @@ -434,7 +434,7 @@ inline static Nearest4 SOFTRAST_CALL SampleNearest(const int u[N], const int v[N return res; default: - ERROR_LOG_REPORT(G3D, "Software: Unsupported texture format: %x", samplerID.TexFmt()); + ERROR_LOG_REPORT(Log::G3D, "Software: Unsupported texture format: %x", samplerID.TexFmt()); memset(res.v, 0, sizeof(res.v)); return res; } diff --git a/GPU/Software/SamplerX86.cpp b/GPU/Software/SamplerX86.cpp index 290f8587f4..3b3d432210 100644 --- a/GPU/Software/SamplerX86.cpp +++ b/GPU/Software/SamplerX86.cpp @@ -80,7 +80,7 @@ FetchFunc SamplerJitCache::CompileFetch(const SamplerID &id) { regCache_.Reset(false); EndWrite(); ResetCodePtr(GetOffset(start)); - ERROR_LOG(G3D, "Failed to compile fetch %s", DescribeSamplerID(id).c_str()); + ERROR_LOG(Log::G3D, "Failed to compile fetch %s", DescribeSamplerID(id).c_str()); return nullptr; } @@ -415,7 +415,7 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { regCache_.Reset(false); EndWrite(); ResetCodePtr(GetOffset(start)); - ERROR_LOG(G3D, "Failed to compile nearest %s", DescribeSamplerID(id).c_str()); + ERROR_LOG(Log::G3D, "Failed to compile nearest %s", DescribeSamplerID(id).c_str()); return nullptr; } @@ -486,7 +486,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { regCache_.Reset(false); EndWrite(); ResetCodePtr(GetOffset(nearest)); - ERROR_LOG(G3D, "Failed to compile linear nearest %s", DescribeSamplerID(id).c_str()); + ERROR_LOG(Log::G3D, "Failed to compile linear nearest %s", DescribeSamplerID(id).c_str()); return nullptr; } @@ -878,7 +878,7 @@ LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { regCache_.Reset(false); EndWrite(); ResetCodePtr(GetOffset(nearest ? nearest : linearResetPos)); - ERROR_LOG(G3D, "Failed to compile linear %s", DescribeSamplerID(id).c_str()); + ERROR_LOG(Log::G3D, "Failed to compile linear %s", DescribeSamplerID(id).c_str()); return nullptr; } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index d02049d740..fbaa0093fc 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -406,7 +406,7 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw) for (size_t i = 0; i < ARRAY_SIZE(softgpuCommandTable); i++) { const u8 cmd = softgpuCommandTable[i].cmd; if (dupeCheck.find(cmd) != dupeCheck.end()) { - ERROR_LOG(G3D, "Command table Dupe: %02x (%i)", (int)cmd, (int)cmd); + ERROR_LOG(Log::G3D, "Command table Dupe: %02x (%i)", (int)cmd, (int)cmd); } else { dupeCheck.insert(cmd); } @@ -420,7 +420,7 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Find commands missing from the table. for (int i = 0; i < 0xEF; i++) { if (dupeCheck.find((u8)i) == dupeCheck.end()) { - ERROR_LOG(G3D, "Command missing from table: %02x (%i)", i, i); + ERROR_LOG(Log::G3D, "Command missing from table: %02x (%i)", i, i); } } @@ -524,7 +524,7 @@ void SoftGPU::ConvertTextureDescFrom16(Draw::TextureDesc &desc, int srcwidth, in break; default: - ERROR_LOG_REPORT(G3D, "Software: Unexpected framebuffer format: %d", displayFormat_); + ERROR_LOG_REPORT(Log::G3D, "Software: Unexpected framebuffer format: %d", displayFormat_); break; } } @@ -848,7 +848,7 @@ void SoftGPU::Execute_Prim(u32 op, u32 diff) { FlushImm(); if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Software: Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG_REPORT(Log::G3D, "Software: Bad vertex address %08x!", gstate_c.vertexAddr); return; } @@ -856,7 +856,7 @@ void SoftGPU::Execute_Prim(u32 op, u32 diff) { const void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Software: Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(Log::G3D, "Software: Bad index address %08x!", gstate_c.indexAddr); return; } indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); @@ -886,7 +886,7 @@ void SoftGPU::Execute_Bezier(u32 op, u32 diff) { } if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG_REPORT(Log::G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); return; } @@ -894,14 +894,14 @@ void SoftGPU::Execute_Bezier(u32 op, u32 diff) { const void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(Log::G3D, "Bad index address %08x!", gstate_c.indexAddr); return; } indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); } if ((gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) || vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); + DEBUG_LOG_REPORT(Log::G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } Spline::BezierSurface surface; @@ -938,7 +938,7 @@ void SoftGPU::Execute_Spline(u32 op, u32 diff) { } if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG_REPORT(Log::G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); return; } @@ -946,14 +946,14 @@ void SoftGPU::Execute_Spline(u32 op, u32 diff) { const void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(Log::G3D, "Bad index address %08x!", gstate_c.indexAddr); return; } indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); } if ((gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) || vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); + DEBUG_LOG_REPORT(Log::G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType)); } Spline::SplineSurface surface; @@ -1007,7 +1007,7 @@ void SoftGPU::Execute_LoadClut(u32 op, u32 diff) { } } else if (clutAddr != 0) { // Some invalid addresses trigger a crash, others fill with zero. We always fill zero. - DEBUG_LOG(G3D, "Software: Invalid CLUT address, filling with garbage instead of crashing"); + DEBUG_LOG(Log::G3D, "Software: Invalid CLUT address, filling with garbage instead of crashing"); memset(clut, 0x00, clutTotalBytes); changed = true; } @@ -1236,7 +1236,7 @@ void SoftGPU::Execute_Call(u32 op, u32 diff) { const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); if (!Memory::IsValidAddress(target)) { - ERROR_LOG(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + ERROR_LOG(Log::G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); gpuState = GPUSTATE_ERROR; downcount = 0; return; @@ -1244,7 +1244,7 @@ void SoftGPU::Execute_Call(u32 op, u32 diff) { const u32 retval = currentList->pc + 4; if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) { - ERROR_LOG(G3D, "CALL: Stack full!"); + ERROR_LOG(Log::G3D, "CALL: Stack full!"); } else { auto &stackEntry = currentList->stack[currentList->stackptr++]; stackEntry.pc = retval; diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 62c3e22ffc..eac7c21f85 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -835,7 +835,7 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G } default: - ERROR_LOG(G3D, "Unexpected prim type: %d", prim_type); + ERROR_LOG(Log::G3D, "Unexpected prim type: %d", prim_type); break; } } @@ -950,11 +950,11 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vectorGetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) { + provokingVertexOk = true; + } + bool useHWTransform = CanUseHardwareTransform(prim) && provokingVertexOk; uint32_t ibOffset; uint32_t vbOffset; - + // The optimization to avoid indexing isn't really worth it on Vulkan since it means creating more pipelines. // This could be avoided with the new dynamic state extensions, but not available enough on mobile. const bool forceIndexed = draw_->GetDeviceCaps().verySlowShaderCompiler; @@ -390,6 +391,8 @@ void DrawEngineVulkan::DoFlush() { gpuStats.numUncachedVertsDrawn += vertexCount; prim = IndexGenerator::GeneralPrim((GEPrimitiveType)drawInds_[0].prim); + // At this point, the output is always an index triangle/line/point list, no strips/fans. + u16 *inds = decIndex_; SoftwareTransformResult result{}; SoftwareTransformParams params{}; @@ -402,7 +405,14 @@ void DrawEngineVulkan::DoFlush() { // do not respect scissor rects. params.allowClear = framebufferManager_->UseBufferedRendering(); params.allowSeparateAlphaClear = false; - params.provokeFlatFirst = true; + + if (gstate.getShadeMode() == GE_SHADE_FLAT) { + if (!renderManager->GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) { + // If we can't have the hardware do it, we need to rotate the index buffer to simulate a different provoking vertex. + // We do this before line expansion etc. + IndexBufferProvokingLastToFirst(prim, inds, vertexCount); + } + } params.flippedY = true; params.usesHalfZ = true; @@ -440,7 +450,7 @@ void DrawEngineVulkan::DoFlush() { // Only here, where we know whether to clear or to draw primitives, should we actually set the current framebuffer! Because that gives use the opportunity // to use a "pre-clear" render pass, for high efficiency on tilers. - if (result.action == SW_DRAW_PRIMITIVES) { + if (result.action == SW_DRAW_INDEXED) { if (textureNeedsApply) { gstate_c.pixelMapped = result.pixelMapped; textureCache_->ApplyTexture(); @@ -517,16 +527,10 @@ void DrawEngineVulkan::DoFlush() { PROFILE_THIS_SCOPE("renderman_q"); - if (result.drawIndexed) { - VkBuffer vbuf, ibuf; - vbOffset = (uint32_t)pushVertex_->Push(result.drawBuffer, numDecodedVerts_ * sizeof(TransformedVertex), 4, &vbuf); - ibOffset = (uint32_t)pushIndex_->Push(inds, sizeof(short) * result.drawNumTrans, 4, &ibuf); - renderManager->DrawIndexed(descSetIndex, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, result.drawNumTrans, 1); - } else { - VkBuffer vbuf; - vbOffset = (uint32_t)pushVertex_->Push(result.drawBuffer, result.drawNumTrans * sizeof(TransformedVertex), 4, &vbuf); - renderManager->Draw(descSetIndex, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, result.drawNumTrans); - } + VkBuffer vbuf, ibuf; + vbOffset = (uint32_t)pushVertex_->Push(result.drawBuffer, numDecodedVerts_ * sizeof(TransformedVertex), 4, &vbuf); + ibOffset = (uint32_t)pushIndex_->Push(inds, sizeof(short) * result.drawNumTrans, 4, &ibuf); + renderManager->DrawIndexed(descSetIndex, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, result.drawNumTrans, 1); } else if (result.action == SW_CLEAR) { // Note: we won't get here if the clear is alpha but not color, or color but not alpha. bool clearColor = gstate.isClearModeColorMask(); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 09f914c059..8ae8862735 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -81,7 +81,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Sanity check gstate if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) { - ERROR_LOG(G3D, "gstate has drifted out of sync!"); + ERROR_LOG(Log::G3D, "gstate has drifted out of sync!"); } BuildReportingInfo(); @@ -99,7 +99,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) void GPU_Vulkan::LoadCache(const Path &filename) { if (!g_Config.bShaderCache) { - WARN_LOG(G3D, "Shader cache disabled. Not loading."); + WARN_LOG(Log::G3D, "Shader cache disabled. Not loading."); return; } @@ -114,7 +114,7 @@ void GPU_Vulkan::LoadCache(const Path &filename) { // it can just memcpy the finished shader binaries out of the pipeline cache file. bool result = shaderManagerVulkan_->LoadCacheFlags(f, &drawEngine_); if (!result) { - WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache header."); + WARN_LOG(Log::G3D, "ShaderManagerVulkan failed to load cache header."); } if (result) { // Reload use flags in case LoadCacheFlags() changed them. @@ -124,7 +124,7 @@ void GPU_Vulkan::LoadCache(const Path &filename) { gstate_c.SetUseFlags(CheckGPUFeatures()); result = shaderManagerVulkan_->LoadCache(f); if (!result) { - WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache."); + WARN_LOG(Log::G3D, "ShaderManagerVulkan failed to load cache."); } } if (result) { @@ -134,23 +134,23 @@ void GPU_Vulkan::LoadCache(const Path &filename) { fclose(f); if (!result) { - WARN_LOG(G3D, "Incompatible Vulkan pipeline cache - rebuilding."); + WARN_LOG(Log::G3D, "Incompatible Vulkan pipeline cache - rebuilding."); // Bad cache file for this GPU/Driver/etc. Delete it. File::Delete(filename); } else { - INFO_LOG(G3D, "Loaded Vulkan pipeline cache."); + INFO_LOG(Log::G3D, "Loaded Vulkan pipeline cache."); } } void GPU_Vulkan::SaveCache(const Path &filename) { if (!g_Config.bShaderCache) { - INFO_LOG(G3D, "Shader cache disabled. Not saving."); + INFO_LOG(Log::G3D, "Shader cache disabled. Not saving."); return; } if (!draw_) { // Already got the lost message, we're in shutdown. - WARN_LOG(G3D, "Not saving shaders - shutting down from in-game."); + WARN_LOG(Log::G3D, "Not saving shaders - shutting down from in-game."); return; } @@ -160,7 +160,7 @@ void GPU_Vulkan::SaveCache(const Path &filename) { shaderManagerVulkan_->SaveCache(f, &drawEngine_); // WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true. pipelineManager_->SavePipelineCache(f, false, shaderManagerVulkan_, draw_); - INFO_LOG(G3D, "Saved Vulkan pipeline cache"); + INFO_LOG(Log::G3D, "Saved Vulkan pipeline cache"); fclose(f); } @@ -265,7 +265,7 @@ u32 GPU_Vulkan::CheckGPUFeatures() const { if ((fmt4444 & Draw::FMT_TEXTURE) && (fmt565 & Draw::FMT_TEXTURE) && (fmt1555 & Draw::FMT_TEXTURE)) { features |= GPU_USE_16BIT_FORMATS; } else { - INFO_LOG(G3D, "Deficient texture format support: 4444: %d 1555: %d 565: %d", fmt4444, fmt1555, fmt565); + INFO_LOG(Log::G3D, "Deficient texture format support: 4444: %d 1555: %d 565: %d", fmt4444, fmt1555, fmt565); } } @@ -306,7 +306,7 @@ void GPU_Vulkan::BeginHostFrame() { if (gstate_c.useFlagsChanged) { // TODO: It'd be better to recompile them in the background, probably? // This most likely means that saw equal depth changed. - WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers"); + WARN_LOG(Log::G3D, "Shader use flags changed, clearing all shaders and depth buffers"); // TODO: Not all shaders need to be recompiled. In fact, quite few? Of course, depends on // the use flag change.. This is a major frame rate hitch in the start of a race in Outrun. shaderManager_->ClearShaders(); @@ -316,7 +316,7 @@ void GPU_Vulkan::BeginHostFrame() { } if (dumpNextFrame_) { - NOTICE_LOG(G3D, "DUMPING THIS FRAME"); + NOTICE_LOG(Log::G3D, "DUMPING THIS FRAME"); dumpThisFrame_ = true; dumpNextFrame_ = false; } else if (dumpThisFrame_) { @@ -388,7 +388,7 @@ void GPU_Vulkan::FinishDeferred() { } void GPU_Vulkan::InitDeviceObjects() { - INFO_LOG(G3D, "GPU_Vulkan::InitDeviceObjects"); + INFO_LOG(Log::G3D, "GPU_Vulkan::InitDeviceObjects"); uint32_t hacks = 0; if (PSP_CoreParameter().compat.flags().MGS2AcidHack) @@ -406,7 +406,7 @@ void GPU_Vulkan::InitDeviceObjects() { } void GPU_Vulkan::DestroyDeviceObjects() { - INFO_LOG(G3D, "GPU_Vulkan::DestroyDeviceObjects"); + INFO_LOG(Log::G3D, "GPU_Vulkan::DestroyDeviceObjects"); // Need to turn off hacks when shutting down the GPU. Don't want them running in the menu. if (draw_) { VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 86f6e51f1a..9babb43e39 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -48,7 +48,7 @@ void PipelineManagerVulkan::Clear() { pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) { if (!value->pipeline) { // Something went wrong. - ERROR_LOG(G3D, "Null pipeline found in PipelineManagerVulkan::Clear - didn't wait for asyncs?"); + ERROR_LOG(Log::G3D, "Null pipeline found in PipelineManagerVulkan::Clear - didn't wait for asyncs?"); } else { value->pipeline->QueueForDeletion(vulkan_); } @@ -192,15 +192,15 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, _assert_(fs && vs); if (!fs || !fs->GetModule()) { - ERROR_LOG(G3D, "Fragment shader missing in CreateVulkanPipeline"); + ERROR_LOG(Log::G3D, "Fragment shader missing in CreateVulkanPipeline"); return nullptr; } if (!vs || !vs->GetModule()) { - ERROR_LOG(G3D, "Vertex shader missing in CreateVulkanPipeline"); + ERROR_LOG(Log::G3D, "Vertex shader missing in CreateVulkanPipeline"); return nullptr; } if (gs && !gs->GetModule()) { - ERROR_LOG(G3D, "Geometry shader missing in CreateVulkanPipeline"); + ERROR_LOG(Log::G3D, "Geometry shader missing in CreateVulkanPipeline"); return nullptr; } @@ -285,6 +285,11 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, rs.polygonMode = VK_POLYGON_MODE_FILL; rs.depthClampEnable = key.depthClampEnable; + if (renderManager->GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) { + ChainStruct(rs, &desc->rs_provoking); + desc->rs_provoking.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT; + } + desc->fragmentShaderSource = fs->GetShaderString(SHADER_STRING_SOURCE_CODE); desc->vertexShaderSource = vs->GetShaderString(SHADER_STRING_SOURCE_CODE); if (gs) { @@ -376,6 +381,9 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager * if (fs->Flags() & FragmentShaderFlags::USES_DISCARD) { pipelineFlags |= PipelineFlags::USES_DISCARD; } + if (fs->Flags() & FragmentShaderFlags::USES_FLAT_SHADING) { + pipelineFlags |= PipelineFlags::USES_FLAT_SHADING; + } if (vs->Flags() & VertexShaderFlags::MULTI_VIEW) { pipelineFlags |= PipelineFlags::USES_MULTIVIEW; } @@ -650,7 +658,7 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa size = (uint32_t)dataSize; fwrite(&size, sizeof(size), 1, file); fwrite(buffer.get(), 1, size, file); - NOTICE_LOG(G3D, "Saved Vulkan pipeline cache (%d bytes).", (int)size); + NOTICE_LOG(Log::G3D, "Saved Vulkan pipeline cache (%d bytes).", (int)size); } size_t seekPosOnFailure = ftell(file); @@ -702,20 +710,20 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa } if (failed) { - ERROR_LOG(G3D, "Failed to write pipeline cache, some shader was missing"); + ERROR_LOG(Log::G3D, "Failed to write pipeline cache, some shader was missing"); // Write a zero in the right place so it doesn't try to load the pipelines next time. size = 0; fseek(file, (long)seekPosOnFailure, SEEK_SET); writeFailed = fwrite(&size, sizeof(size), 1, file) != 1; if (writeFailed) { - ERROR_LOG(G3D, "Failed to write pipeline cache, disk full?"); + ERROR_LOG(Log::G3D, "Failed to write pipeline cache, disk full?"); } return; } if (writeFailed) { - ERROR_LOG(G3D, "Failed to write pipeline cache, disk full?"); + ERROR_LOG(Log::G3D, "Failed to write pipeline cache, disk full?"); } else { - NOTICE_LOG(G3D, "Saved Vulkan pipeline ID cache (%d unique pipelines/%d).", (int)keys.size(), (int)pipelines_.size()); + NOTICE_LOG(Log::G3D, "Saved Vulkan pipeline ID cache (%d unique pipelines/%d).", (int)keys.size(), (int)pipelines_.size()); } } @@ -725,11 +733,11 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa uint32_t size = 0; if (loadRawPipelineCache) { - NOTICE_LOG(G3D, "WARNING: Using the badly tested raw pipeline cache path!!!!"); + NOTICE_LOG(Log::G3D, "WARNING: Using the badly tested raw pipeline cache path!!!!"); // WARNING: Do not use this path until after reading and implementing https://zeux.io/2019/07/17/serializing-pipeline-cache/ ! bool success = fread(&size, sizeof(size), 1, file) == 1; if (!size || !success) { - WARN_LOG(G3D, "Zero-sized Vulkan pipeline cache."); + WARN_LOG(Log::G3D, "Zero-sized Vulkan pipeline cache."); return true; } auto buffer = std::make_unique(size); @@ -738,12 +746,12 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa VkPipelineCacheHeader *header = (VkPipelineCacheHeader *)buffer.get(); if (!success || header->version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) { // Bad header, don't do anything. - WARN_LOG(G3D, "Bad Vulkan pipeline cache header - ignoring"); + WARN_LOG(Log::G3D, "Bad Vulkan pipeline cache header - ignoring"); return false; } if (0 != memcmp(header->uuid, vulkan_->GetPhysicalDeviceProperties().properties.pipelineCacheUUID, VK_UUID_SIZE)) { // Wrong hardware/driver/etc. - WARN_LOG(G3D, "Bad Vulkan pipeline cache UUID - ignoring"); + WARN_LOG(Log::G3D, "Bad Vulkan pipeline cache UUID - ignoring"); return false; } @@ -761,14 +769,14 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa } else { vkMergePipelineCaches(vulkan_->GetDevice(), pipelineCache_, 1, &cache); } - NOTICE_LOG(G3D, "Loaded Vulkan binary pipeline cache (%d bytes).", (int)size); + NOTICE_LOG(Log::G3D, "Loaded Vulkan binary pipeline cache (%d bytes).", (int)size); // Note that after loading the cache, it's still a good idea to pre-create the various pipelines. } else { if (!pipelineCache_) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); if (res != VK_SUCCESS) { - WARN_LOG(G3D, "vkCreatePipelineCache failed (%08x), highly unexpected", (u32)res); + WARN_LOG(Log::G3D, "vkCreatePipelineCache failed (%08x), highly unexpected", (u32)res); return false; } } @@ -777,7 +785,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa // Read the number of pipelines. bool failed = fread(&size, sizeof(size), 1, file) != 1; - NOTICE_LOG(G3D, "Creating %d pipelines from cache (%dx MSAA)...", size, (1 << multiSampleLevel)); + NOTICE_LOG(Log::G3D, "Creating %d pipelines from cache (%dx MSAA)...", size, (1 << multiSampleLevel)); int pipelineCreateFailCount = 0; int shaderFailCount = 0; for (uint32_t i = 0; i < size; i++) { @@ -787,12 +795,12 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa StoredVulkanPipelineKey key; failed = failed || fread(&key, sizeof(key), 1, file) != 1; if (failed) { - ERROR_LOG(G3D, "Truncated Vulkan pipeline cache file, stopping."); + ERROR_LOG(Log::G3D, "Truncated Vulkan pipeline cache file, stopping."); break; } if (key.raster.topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST || key.raster.topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) { - WARN_LOG(G3D, "Bad raster key in cache, ignoring"); + WARN_LOG(Log::G3D, "Bad raster key in cache, ignoring"); continue; } @@ -802,7 +810,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa if (!vs || !fs || (!gs && key.gShaderID.Bit(GS_BIT_ENABLED))) { // We just ignore this one, it'll get created later if needed. // Probably some useFlags mismatch. - WARN_LOG(G3D, "Failed to find vs or fs in pipeline %d in cache, skipping pipeline", (int)i); + WARN_LOG(Log::G3D, "Failed to find vs or fs in pipeline %d in cache, skipping pipeline", (int)i); continue; } @@ -828,7 +836,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa rm->NudgeCompilerThread(); - NOTICE_LOG(G3D, "Recreated Vulkan pipeline cache (%d pipelines, %d failed).", (int)size, pipelineCreateFailCount); + NOTICE_LOG(Log::G3D, "Recreated Vulkan pipeline cache (%d pipelines, %d failed).", (int)size, pipelineCreateFailCount); // We just ignore any failures. return true; } diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 9a95259b33..4ee6e40a2b 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -75,6 +75,7 @@ struct VulkanPipeline { bool UsesDepthStencil() const { return (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) != 0; } bool UsesGeometryShader() const { return (pipelineFlags & PipelineFlags::USES_GEOMETRY_SHADER) != 0; } bool UsesDiscard() const { return (pipelineFlags & PipelineFlags::USES_DISCARD) != 0; } + bool UsesFlatShading() const { return (pipelineFlags & PipelineFlags::USES_FLAT_SHADING) != 0; } u32 GetVariantsBitmask() const; }; diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 1068e94f98..10a8371768 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -59,13 +59,13 @@ static Promise *CompileShaderModuleAsync(VulkanContext *vulkan, if (!errorMessage.empty()) { if (success) { - ERROR_LOG(G3D, "Warnings in shader compilation!"); + ERROR_LOG(Log::G3D, "Warnings in shader compilation!"); } else { - ERROR_LOG(G3D, "Error in shader compilation!"); + ERROR_LOG(Log::G3D, "Error in shader compilation!"); } std::string numberedSource = LineNumberString(code); - ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str()); - ERROR_LOG(G3D, "Shader source:\n%s", numberedSource.c_str()); + ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str()); + ERROR_LOG(Log::G3D, "Shader source:\n%s", numberedSource.c_str()); #if PPSSPP_PLATFORM(WINDOWS) OutputDebugStringA("Error messages:\n"); OutputDebugStringA(errorMessage.c_str()); @@ -116,7 +116,7 @@ VulkanFragmentShader::VulkanFragmentShader(VulkanContext *vulkan, FShaderID id, _assert_(!id.is_invalid()); source_ = code; module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, source_.c_str(), new std::string(FragmentShaderDesc(id))); - VERBOSE_LOG(G3D, "Compiled fragment shader:\n%s\n", (const char *)code); + VERBOSE_LOG(Log::G3D, "Compiled fragment shader:\n%s\n", (const char *)code); } VulkanFragmentShader::~VulkanFragmentShader() { @@ -148,7 +148,7 @@ VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, Vert _assert_(!id.is_invalid()); source_ = code; module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_VERTEX_BIT, source_.c_str(), new std::string(VertexShaderDesc(id))); - VERBOSE_LOG(G3D, "Compiled vertex shader:\n%s\n", (const char *)code); + VERBOSE_LOG(Log::G3D, "Compiled vertex shader:\n%s\n", (const char *)code); } VulkanVertexShader::~VulkanVertexShader() { @@ -180,7 +180,7 @@ VulkanGeometryShader::VulkanGeometryShader(VulkanContext *vulkan, GShaderID id, _assert_(!id.is_invalid()); source_ = code; module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_GEOMETRY_BIT, source_.c_str(), new std::string(GeometryShaderDesc(id).c_str())); - VERBOSE_LOG(G3D, "Compiled geometry shader:\n%s\n", (const char *)code); + VERBOSE_LOG(Log::G3D, "Compiled geometry shader:\n%s\n", (const char *)code); } VulkanGeometryShader::~VulkanGeometryShader() { @@ -520,11 +520,11 @@ bool ShaderManagerVulkan::LoadCacheFlags(FILE *f, DrawEngineVulkan *drawEngine) // We'll read it again later, this is just to check the flags. success = success && fseek(f, pos, SEEK_SET) == 0; if (!success || header.magic != CACHE_HEADER_MAGIC) { - WARN_LOG(G3D, "Shader cache magic mismatch"); + WARN_LOG(Log::G3D, "Shader cache magic mismatch"); return false; } if (header.version != CACHE_VERSION) { - WARN_LOG(G3D, "Shader cache version mismatch, %d, expected %d", header.version, CACHE_VERSION); + WARN_LOG(Log::G3D, "Shader cache version mismatch, %d, expected %d", header.version, CACHE_VERSION); return false; } @@ -543,7 +543,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { if (header.useFlags != gstate_c.GetUseFlags()) { // This can simply be a result of sawExactEqualDepth_ having been flipped to true in the previous run. // Let's just keep going. - WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.GetUseFlags()); + WARN_LOG(Log::G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.GetUseFlags()); } else { // We're compiling shaders now, so they haven't changed anymore. gstate_c.useFlagsChanged = false; @@ -555,7 +555,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { for (int i = 0; i < header.numVertexShaders; i++) { VShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated (in VertexShaders)"); + ERROR_LOG(Log::G3D, "Vulkan shader cache truncated (in VertexShaders)"); return false; } bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM); @@ -564,7 +564,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { uint64_t uniformMask = 0; VertexShaderFlags flags; if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString)) { - ERROR_LOG(G3D, "Failed to generate vertex shader during cache load"); + ERROR_LOG(Log::G3D, "Failed to generate vertex shader during cache load"); // We just ignore this one and carry on. failCount++; continue; @@ -581,14 +581,14 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { for (int i = 0; i < header.numFragmentShaders; i++) { FShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated (in FragmentShaders)"); + ERROR_LOG(Log::G3D, "Vulkan shader cache truncated (in FragmentShaders)"); return false; } std::string genErrorString; uint64_t uniformMask = 0; FragmentShaderFlags flags; if (!GenerateFragmentShader(id, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString)) { - ERROR_LOG(G3D, "Failed to generate fragment shader during cache load"); + ERROR_LOG(Log::G3D, "Failed to generate fragment shader during cache load"); // We just ignore this one and carry on. failCount++; continue; @@ -605,12 +605,12 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { for (int i = 0; i < header.numGeometryShaders; i++) { GShaderID id; if (fread(&id, sizeof(id), 1, f) != 1) { - ERROR_LOG(G3D, "Vulkan shader cache truncated (in GeometryShaders)"); + ERROR_LOG(Log::G3D, "Vulkan shader cache truncated (in GeometryShaders)"); return false; } std::string genErrorString; if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) { - ERROR_LOG(G3D, "Failed to generate geometry shader during cache load"); + ERROR_LOG(Log::G3D, "Failed to generate geometry shader during cache load"); // We just ignore this one and carry on. failCount++; continue; @@ -623,7 +623,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { } } - NOTICE_LOG(G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders (failed %d)", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders, failCount); + NOTICE_LOG(Log::G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders (failed %d)", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders, failCount); return true; } @@ -649,8 +649,8 @@ void ShaderManagerVulkan::SaveCache(FILE *f, DrawEngineVulkan *drawEngine) { writeFailed = writeFailed || fwrite(&id, sizeof(id), 1, f) != 1; }); if (writeFailed) { - ERROR_LOG(G3D, "Failed to write Vulkan shader cache, disk full?"); + ERROR_LOG(Log::G3D, "Failed to write Vulkan shader cache, disk full?"); } else { - NOTICE_LOG(G3D, "Saved %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders); + NOTICE_LOG(Log::G3D, "Saved %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders); } } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 08efbc62ed..a38a18fc11 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -486,7 +486,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { if (uploadCS_ != VK_NULL_HANDLE) { computeUpload = true; } else { - WARN_LOG(G3D, "Falling back to software scaling, hardware shader didn't compile"); + WARN_LOG(Log::G3D, "Falling back to software scaling, hardware shader didn't compile"); } } @@ -496,7 +496,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } if (plan.saveTexture) { - INFO_LOG(G3D, "About to save texture"); + INFO_LOG(Log::G3D, "About to save texture"); actualFmt = VULKAN_8888_FORMAT; } @@ -512,9 +512,12 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { snprintf(texName, sizeof(texName), "tex_%08x_%s_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format, gstate.getClutPaletteFormat()), gstate.isTextureSwizzled() ? "swz" : "lin"); entry->vkTex = new VulkanTexture(vulkan, texName); VulkanTexture *image = entry->vkTex; - bool allocSuccess = image->CreateDirect(cmdInit, plan.createW, plan.createH, plan.depth, plan.levelsToCreate, actualFmt, imageLayout, usage, mapping); + + VulkanBarrierBatch barrier; + bool allocSuccess = image->CreateDirect(plan.createW, plan.createH, plan.depth, plan.levelsToCreate, actualFmt, imageLayout, usage, &barrier, mapping); + barrier.Flush(cmdInit); if (!allocSuccess && !lowMemoryMode_) { - WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode"); + WARN_LOG_REPORT(Log::G3D, "Texture cache ran out of GPU memory; switching to low memory mode"); lowMemoryMode_ = true; decimationCounter_ = 0; Decimate(entry, true); @@ -537,11 +540,12 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { plan.scaleFactor = 1; actualFmt = dstFmt; - allocSuccess = image->CreateDirect(cmdInit, plan.createW, plan.createH, plan.depth, plan.levelsToCreate, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); + allocSuccess = image->CreateDirect(plan.createW, plan.createH, plan.depth, plan.levelsToCreate, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, &barrier, mapping); + barrier.Flush(cmdInit); } if (!allocSuccess) { - ERROR_LOG(G3D, "Failed to create texture (%dx%d)", plan.w, plan.h); + ERROR_LOG(Log::G3D, "Failed to create texture (%dx%d)", plan.w, plan.h); delete entry->vkTex; entry->vkTex = nullptr; } @@ -613,7 +617,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { data = pushBuffer->Allocate(uploadSize, pushAlignment, &texBuf, &bufferOffset); double replaceStart = time_now_d(); if (!plan.replaced->CopyLevelTo(plan.baseLevelSrc + i, (uint8_t *)data, uploadSize, byteStride)) { // If plan.doReplace, this shouldn't fail. - WARN_LOG(G3D, "Failed to copy replaced texture level"); + WARN_LOG(Log::G3D, "Failed to copy replaced texture level"); // TODO: Fill with some pattern? } replacementTimeThisFrame_ += time_now_d() - replaceStart; @@ -648,7 +652,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } // Format might be wrong in lowMemoryMode_, so don't save. if (plan.saveTexture && !lowMemoryMode_) { - INFO_LOG(G3D, "Calling NotifyTextureDecoded %08x", entry->addr); + INFO_LOG(Log::G3D, "Calling NotifyTextureDecoded %08x", entry->addr); // When hardware texture scaling is enabled, this saves the original. int w = dataScaled ? mipWidth : mipUnscaledWidth; diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index 0309c35c20..dcde43d286 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -32,12 +32,12 @@ VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits bool success = GLSLtoSPV(stage, code, GLSLVariant::VULKAN, spirv, error); if (!error->empty()) { if (success) { - ERROR_LOG(G3D, "Warnings in shader compilation!"); + ERROR_LOG(Log::G3D, "Warnings in shader compilation!"); } else { - ERROR_LOG(G3D, "Error in shader compilation!"); + ERROR_LOG(Log::G3D, "Error in shader compilation!"); } - ERROR_LOG(G3D, "Messages: %s", error->c_str()); - ERROR_LOG(G3D, "Shader source:\n%s", LineNumberString(code).c_str()); + ERROR_LOG(Log::G3D, "Messages: %s", error->c_str()); + ERROR_LOG(Log::G3D, "Shader source:\n%s", LineNumberString(code).c_str()); OutputDebugStringUTF8("Messages:\n"); OutputDebugStringUTF8(error->c_str()); OutputDebugStringUTF8(LineNumberString(code).c_str()); diff --git a/Qt/PPSSPP.desktop b/Qt/PPSSPP.desktop deleted file mode 100644 index 1752317072..0000000000 --- a/Qt/PPSSPP.desktop +++ /dev/null @@ -1,12 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Version=1.0 # The version of the desktop entry specification to which this file complies -Type=Application -Terminal=false -Name=PPSSPP -Exec=/usr/bin/invoker --type=d -s /opt/PPSSPP/bin/PPSSPPQt -Icon=/usr/share/icons/hicolor/114x114/apps/icon-114.png -X-Window-Icon= -X-HildonDesk-ShowInToolbar=true -X-Osso-Type=application/x-executable -StartupWMClass=PPSSPPQt diff --git a/Qt/PPSSPPQt.desktop b/Qt/PPSSPPQt.desktop new file mode 100644 index 0000000000..b6eab983f7 --- /dev/null +++ b/Qt/PPSSPPQt.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Terminal=false +Name=PPSSPP +Categories=Game; +Exec=PPSSPPQt %f +Icon=ppsspp.png diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index c20058af25..5122131e10 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -45,6 +45,8 @@ #include "Common/Thread/ThreadUtil.h" #include "Common/Data/Encoding/Utf8.h" #include "Common/StringUtils.h" +#include "Common/TimeUtil.h" + #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/HW/Camera.h" @@ -53,7 +55,7 @@ #include #include -// Audio +// AUDIO #define AUDIO_FREQ 44100 #define AUDIO_CHANNELS 2 #define AUDIO_SAMPLES 2048 @@ -92,23 +94,23 @@ static void InitSDLAudioDevice() { if (!g_Config.sAudioDevice.empty()) { audioDev = SDL_OpenAudioDevice(g_Config.sAudioDevice.c_str(), 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (audioDev <= 0) { - WARN_LOG(AUDIO, "Failed to open preferred audio device %s", g_Config.sAudioDevice.c_str()); + WARN_LOG(Log::Audio, "Failed to open preferred audio device %s", g_Config.sAudioDevice.c_str()); } } if (audioDev <= 0) { audioDev = SDL_OpenAudioDevice(nullptr, 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); } if (audioDev <= 0) { - ERROR_LOG(AUDIO, "Failed to open audio: %s", SDL_GetError()); + ERROR_LOG(Log::Audio, "Failed to open audio: %s", SDL_GetError()); } else { if (g_retFmt.samples != fmt.samples) // Notify, but still use it - ERROR_LOG(AUDIO, "Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); + ERROR_LOG(Log::Audio, "Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); if (g_retFmt.format != fmt.format || g_retFmt.channels != fmt.channels) { - ERROR_LOG(AUDIO, "Sound buffer format does not match requested format."); - ERROR_LOG(AUDIO, "Output audio freq: %d (requested: %d)", g_retFmt.freq, fmt.freq); - ERROR_LOG(AUDIO, "Output audio format: %d (requested: %d)", g_retFmt.format, fmt.format); - ERROR_LOG(AUDIO, "Output audio channels: %d (requested: %d)", g_retFmt.channels, fmt.channels); - ERROR_LOG(AUDIO, "Provided output format does not match requirement, turning audio off"); + ERROR_LOG(Log::Audio, "Sound buffer format does not match requested format."); + ERROR_LOG(Log::Audio, "Output audio freq: %d (requested: %d)", g_retFmt.freq, fmt.freq); + ERROR_LOG(Log::Audio, "Output audio format: %d (requested: %d)", g_retFmt.format, fmt.format); + ERROR_LOG(Log::Audio, "Output audio channels: %d (requested: %d)", g_retFmt.channels, fmt.channels); + ERROR_LOG(Log::Audio, "Provided output format does not match requirement, turning audio off"); SDL_CloseAudioDevice(audioDev); } SDL_PauseAudioDevice(audioDev, 0); @@ -185,7 +187,7 @@ std::vector System_GetPropertyStringVec(SystemProperty prop) { } } -int System_GetPropertyInt(SystemProperty prop) { +int64_t System_GetPropertyInt(SystemProperty prop) { switch (prop) { #if defined(SDL) case SYSPROP_AUDIO_SAMPLE_RATE: @@ -245,6 +247,8 @@ float System_GetPropertyFloat(SystemProperty prop) { bool System_GetPropertyBool(SystemProperty prop) { switch (prop) { + case SYSPROP_HAS_TEXT_CLIPBOARD: + return true; case SYSPROP_HAS_BACK_BUTTON: return true; case SYSPROP_HAS_IMAGE_BROWSER: @@ -316,7 +320,7 @@ bool MainUI::HandleCustomEvent(QEvent *e) { filter = "DB files (*.db)"; break; case BrowseFileType::SOUND_EFFECT: - filter = "WAVE files (*.wav)"; + filter = "WAVE files (*.wav *.mp3)"; break; case BrowseFileType::ZIP: filter = "ZIP files (*.zip)"; @@ -354,7 +358,7 @@ bool MainUI::HandleCustomEvent(QEvent *e) { return true; } -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { switch (type) { case SystemRequestType::EXIT_APP: qApp->exit(0); @@ -388,7 +392,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string } case SystemRequestType::BROWSE_FOR_IMAGE: // Fall back to file browser. - return System_MakeRequest(SystemRequestType::BROWSE_FOR_FILE, requestId, param1, param2, (int)BrowseFileType::IMAGE); + return System_MakeRequest(SystemRequestType::BROWSE_FOR_FILE, requestId, param1, param2, (int)BrowseFileType::IMAGE, 0); case SystemRequestType::BROWSE_FOR_FILE: g_requestId = requestId; g_param1 = param1; @@ -517,9 +521,9 @@ MainUI::MainUI(QWidget *parent) } MainUI::~MainUI() { - INFO_LOG(SYSTEM, "MainUI::Destructor"); + INFO_LOG(Log::System, "MainUI::Destructor"); if (emuThreadState != (int)EmuThreadState::DISABLED) { - INFO_LOG(SYSTEM, "EmuThreadStop"); + INFO_LOG(Log::System, "EmuThreadStop"); EmuThreadStop(); while (graphicsContext->ThreadFrame()) { // Need to keep eating frames to allow the EmuThread to exit correctly. @@ -684,7 +688,7 @@ bool MainUI::event(QEvent *e) { void MainUI::initializeGL() { if (g_Config.iGPUBackend != (int)GPUBackend::OPENGL) { - INFO_LOG(SYSTEM, "Only GL supported under Qt - switching."); + INFO_LOG(Log::System, "Only GL supported under Qt - switching."); g_Config.iGPUBackend = (int)GPUBackend::OPENGL; } @@ -706,12 +710,12 @@ void MainUI::initializeGL() { #endif if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) { // OpenGL uses a background thread to do the main processing and only renders on the gl thread. - INFO_LOG(SYSTEM, "Initializing GL graphics context"); + INFO_LOG(Log::System, "Initializing GL graphics context"); graphicsContext = new QtGLGraphicsContext(); - INFO_LOG(SYSTEM, "Using thread, starting emu thread"); + INFO_LOG(Log::System, "Using thread, starting emu thread"); EmuThreadStart(); } else { - INFO_LOG(SYSTEM, "Not using thread, backend=%d", (int)g_Config.iGPUBackend); + INFO_LOG(Log::System, "Not using thread, backend=%d", (int)g_Config.iGPUBackend); } graphicsContext->ThreadStart(); } @@ -799,6 +803,8 @@ Q_DECL_EXPORT #endif int main(int argc, char *argv[]) { + TimeInit(); + for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "--version")) { printf("%s\n", PPSSPP_GIT_VERSION); @@ -864,7 +870,7 @@ int main(int argc, char *argv[]) g_Config.iGPUBackend = (int)GPUBackend::OPENGL; int ret = mainInternal(a); - INFO_LOG(SYSTEM, "Left mainInternal here."); + INFO_LOG(Log::System, "Left mainInternal here."); #ifdef SDL if (audioDev > 0) { diff --git a/Qt/QtMain.h b/Qt/QtMain.h index 16bcc6d62d..af077c04bd 100644 --- a/Qt/QtMain.h +++ b/Qt/QtMain.h @@ -166,7 +166,7 @@ extern MainUI* emugl; #ifndef SDL -// Audio +// AUDIO class MainAudio : public QObject { Q_OBJECT public: diff --git a/Qt/macbundle.sh b/Qt/macbundle.sh index 989cde3d17..457e618d37 100644 --- a/Qt/macbundle.sh +++ b/Qt/macbundle.sh @@ -8,6 +8,11 @@ if [ ! -f "${PPSSPPQt}" ]; then exit 0 fi +GIT_VERSION_LINE=$(grep "PPSSPP_GIT_VERSION = " "$(dirname "${0}")/../git-version.cpp") + +echo "Running Qt macbundle.sh for $PPSSPP/Contents/Info.plist ($GIT_VERSION_LINE)" + +# Why don't we just put these in the template? plutil -replace NSPrincipalClass -string NSApplication ${PPSSPP}/Contents/Info.plist plutil -replace NSHighResolutionCapable -bool YES ${PPSSPP}/Contents/Info.plist @@ -15,7 +20,6 @@ plutil -replace NSLocationWhenInUseUsageDescription -string "Your location may b plutil -replace NSCameraUsageDescription -string "Your camera may be used to emulate Go!Cam, a camera accessory" ${PPSSPP}/Contents/Info.plist plutil -replace NSMicrophoneUsageDescription -string "Your microphone may be used to emulate Go!Cam/Talkman, a microphone accessory" ${PPSSPP}/Contents/Info.plist -GIT_VERSION_LINE=$(grep "PPSSPP_GIT_VERSION = " "$(dirname "${0}")/../git-version.cpp") SHORT_VERSION_MATCH='.*"v([0-9\.]+(-[0-9]+)?).*";' LONG_VERSION_MATCH='.*"v(.*)";' if [[ "${GIT_VERSION_LINE}" =~ ^${SHORT_VERSION_MATCH}$ ]]; then diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index 5897edcb62..e982aff696 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -350,7 +350,9 @@ void MainWindow::dumpNextAct() void MainWindow::consoleAct() { +#if PPSSPP_PLATFORM(WINDOWS) LogManager::GetInstance()->GetConsoleListener()->Show(LogManager::GetInstance()->GetConsoleListener()->Hidden()); +#endif } void MainWindow::raiseTopMost() diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index b9da7ee905..edda066b1c 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -9,9 +9,12 @@ #include #include +#include "ppsspp_config.h" #include "Common/System/System.h" #include "Common/System/NativeApp.h" -#include "ConsoleListener.h" +#if PPSSPP_PLATFORM(WINDOWS) +#include "Common/Log/ConsoleListener.h" +#endif #include "Core/Core.h" #include "Core/Config.h" #include "Core/System.h" diff --git a/README.md b/README.md index 4039c3dd04..42755c2e4e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ For documentation of all kinds (usage, reference, development), see the [documen For build instructions and other development tutorials, see [the wiki](https://github.com/hrydgard/ppsspp/wiki). -If you want to download regularly updated builds for Android, Windows x86 and x64, [visit Orphis' buildbot](https://buildbot.orphis.net/ppsspp/) +To download fresh development builds for Android, Windows and Mac, [go to the /devbuilds page](https://www.ppsspp.org/devbuilds) For game compatibility, see [community compatibility feedback](https://report.ppsspp.org/games). @@ -399,4 +399,4 @@ Credit goes to: [#18822]: https://github.com/hrydgard/ppsspp/issues/18822 "Avoid vertically merging the two main framebuffers, even if FramebufferAllowLargeVerticalOffset is on." [#18813]: https://github.com/hrydgard/ppsspp/issues/18813 "Mali: Turn off any depth writes in the shader if depth test == NEVER" [#18819]: https://github.com/hrydgard/ppsspp/issues/18819 "Temporarily disable MSAA on Adreno GPUs" -[#18823]: https://github.com/hrydgard/ppsspp/issues/18823 "Memory exception handler: Don't disassemble if ignoring the exception" \ No newline at end of file +[#18823]: https://github.com/hrydgard/ppsspp/issues/18823 "Memory exception handler: Don't disassemble if ignoring the exception" diff --git a/SDL/CocoaBarItems.mm b/SDL/CocoaBarItems.mm index 90703899f4..664095c8d5 100644 --- a/SDL/CocoaBarItems.mm +++ b/SDL/CocoaBarItems.mm @@ -548,7 +548,7 @@ TOGGLE_METHOD_INVERSE(BreakOnLoad, g_Config.bAutoRun) TOGGLE_METHOD(IgnoreIllegalRWs, g_Config.bIgnoreBadMemAccess) TOGGLE_METHOD(AutoFrameSkip, g_Config.bAutoFrameSkip, g_Config.UpdateAfterSettingAutoFrameSkip()) TOGGLE_METHOD(SoftwareRendering, g_Config.bSoftwareRendering) -TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_MakeRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, 0, g_Config.UseFullScreen() ? "1" : "0", "", 3)) +TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_MakeRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, 0, g_Config.UseFullScreen() ? "1" : "0", "", 3, 0)) // TOGGLE_METHOD(VSync, g_Config.bVSync) #undef TOGGLE_METHOD @@ -645,13 +645,11 @@ TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_MakeRequest(SystemRequest -(void)openSystemFileBrowser { int g = 0; - DarwinDirectoryPanelCallback callback = [g] (bool succ, Path thePathChosen) { + DarwinDirectoryPanelCallback panelCallback = [g] (bool succ, Path thePathChosen) { if (succ) System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, thePathChosen.c_str()); }; - - DarwinFileSystemServices services; - services.presentDirectoryPanel(callback, /* allowFiles = */ true, /* allowDirectorites = */ true); + DarwinFileSystemServices::presentDirectoryPanel(panelCallback, /* allowFiles = */ true, /* allowDirectorites = */ true); } -(void)openMemstickFolder { diff --git a/SDL/PPSSPPSDL.desktop b/SDL/PPSSPPSDL.desktop new file mode 100644 index 0000000000..b9dfdab959 --- /dev/null +++ b/SDL/PPSSPPSDL.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=PPSSPP +Exec=PPSSPPSDL +Icon=ppsspp +Type=Application +Keywords=Sony;PlayStation;Portable;PSP;handheld;console; +Categories=Game;Emulator; +MimeType=application/x-cd-image;application/x-iso9660-image;application/x-compressed-iso;application/zip; diff --git a/SDL/README.TXT b/SDL/README.TXT index 19b5c2bea2..d4115dca4a 100644 --- a/SDL/README.TXT +++ b/SDL/README.TXT @@ -14,3 +14,28 @@ Under the assets directory is the SDL2 game controller database: gamecontrollerd Hot plugging of control pads is also supported. If you control pad has a "Guide" or "Home" button then when pressed, this will trigger the emulator pause menu, thus allowing you to exit the emulator if you wish or load another game from your library. + +WSL notes +========= +Works fine on WSL2 with OpenGL, at least. For more notes, see https://www.ppsspp.org/docs/development/wsl/ . + +Running with valgrind +===================== + +Here's an example where we both use suppressions, and generate new ones (that you can then take from suppressions.log and simplify and copy to valgrind-wsl2.supp): + +> valgrind --suppressions=SDL/valgrind-wsl2.supp --gen-suppressions=all --log-file=suppressions.log build/PPSSPPSDL + +Running with ASAN +================= + +./b.sh --sanitize + +build/PPSSPPSDL.app/Contents/MacOS/PPSSPPSDL + +Running with UBSAN +================== + +./b.sh --sanitize --sanitizeub + +UBSAN_OPTIONS=print_stacktrack=true build/PPSSPPSDL.app/Contents/MacOS/PPSSPPSDL diff --git a/SDL/SDLGLGraphicsContext.cpp b/SDL/SDLGLGraphicsContext.cpp index 7c05a1ad93..db53a72507 100644 --- a/SDL/SDLGLGraphicsContext.cpp +++ b/SDL/SDLGLGraphicsContext.cpp @@ -299,6 +299,13 @@ void EGL_Close() { #endif // USING_EGL +bool SDLGLGraphicsContext::InitFromRenderThread(std::string *errorMessage) { + bool retval = GraphicsContext::InitFromRenderThread(errorMessage); + // HACK: Ensure that the swap interval is set after context creation (needed for kmsdrm) + SDL_GL_SetSwapInterval(1); + return retval; +} + // Returns 0 on success. int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int w, int h, int mode, std::string *error_message) { struct GLVersionPair { @@ -368,6 +375,7 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int w, int h, glContext = SDL_GL_CreateContext(window); if (glContext == nullptr) { + // OK, now we really have tried everything. NativeShutdown(); fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError()); SDL_Quit(); @@ -432,9 +440,10 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int w, int h, }); renderManager_->SetSwapIntervalFunction([&](int interval) { - INFO_LOG(G3D, "SDL SwapInterval: %d", interval); + INFO_LOG(Log::G3D, "SDL SwapInterval: %d", interval); SDL_GL_SetSwapInterval(interval); }); + window_ = window; return 0; } diff --git a/SDL/SDLGLGraphicsContext.h b/SDL/SDLGLGraphicsContext.h index a54e8b5121..c2d046a243 100644 --- a/SDL/SDLGLGraphicsContext.h +++ b/SDL/SDLGLGraphicsContext.h @@ -7,6 +7,8 @@ #include "SDL_syswm.h" #endif +#include + #include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/GPU/OpenGL/GLCommon.h" #include "Common/GraphicsContext.h" @@ -16,6 +18,8 @@ public: // Returns 0 on success. int Init(SDL_Window *&window, int x, int y, int w, int h, int mode, std::string *error_message); + bool InitFromRenderThread(std::string *errorMessage) override; + void Shutdown() override {} void ShutdownFromRenderThread() override; diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index d9d0644340..a0d206ee21 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -149,6 +149,26 @@ InputKeyCode SDLJoystick::getKeycodeForButton(SDL_GameControllerButton button) { return NKCODE_BUTTON_THUMBL; case SDL_CONTROLLER_BUTTON_RIGHTSTICK: return NKCODE_BUTTON_THUMBR; + + // Found these limits by checking out the SDL2 branch of the SDL repo, doing git blame, then `git tag --contains (commit)` etc. +#if SDL_VERSION_ATLEAST(2, 0, 16) + case SDL_CONTROLLER_BUTTON_MISC1: + return NKCODE_BUTTON_11; +#endif +#if SDL_VERSION_ATLEAST(2, 0, 28) + case SDL_CONTROLLER_BUTTON_PADDLE1: + return NKCODE_BUTTON_12; + case SDL_CONTROLLER_BUTTON_PADDLE2: + return NKCODE_BUTTON_13; + case SDL_CONTROLLER_BUTTON_PADDLE3: + return NKCODE_BUTTON_14; + case SDL_CONTROLLER_BUTTON_PADDLE4: + return NKCODE_BUTTON_15; +#endif +#if SDL_VERSION_ATLEAST(2, 0, 14) + case SDL_CONTROLLER_BUTTON_TOUCHPAD: + return NKCODE_BUTTON_16; +#endif case SDL_CONTROLLER_BUTTON_INVALID: default: return NKCODE_UNKNOWN; diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index cbd90ae514..53a2160440 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -152,24 +152,24 @@ static void InitSDLAudioDevice(const std::string &name = "") { if (!startDevice.empty()) { audioDev = SDL_OpenAudioDevice(startDevice.c_str(), 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (audioDev <= 0) { - WARN_LOG(AUDIO, "Failed to open audio device: %s", startDevice.c_str()); + WARN_LOG(Log::Audio, "Failed to open audio device: %s", startDevice.c_str()); } } if (audioDev <= 0) { - INFO_LOG(AUDIO, "SDL: Trying a different audio device"); + INFO_LOG(Log::Audio, "SDL: Trying a different audio device"); audioDev = SDL_OpenAudioDevice(nullptr, 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); } if (audioDev <= 0) { - ERROR_LOG(AUDIO, "Failed to open audio device: %s", SDL_GetError()); + ERROR_LOG(Log::Audio, "Failed to open audio device: %s", SDL_GetError()); } else { if (g_retFmt.samples != fmt.samples) // Notify, but still use it - ERROR_LOG(AUDIO, "Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); + ERROR_LOG(Log::Audio, "Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); if (g_retFmt.format != fmt.format || g_retFmt.channels != fmt.channels) { - ERROR_LOG(AUDIO, "Sound buffer format does not match requested format."); - ERROR_LOG(AUDIO, "Output audio freq: %d (requested: %d)", g_retFmt.freq, fmt.freq); - ERROR_LOG(AUDIO, "Output audio format: %d (requested: %d)", g_retFmt.format, fmt.format); - ERROR_LOG(AUDIO, "Output audio channels: %d (requested: %d)", g_retFmt.channels, fmt.channels); - ERROR_LOG(AUDIO, "Provided output format does not match requirement, turning audio off"); + ERROR_LOG(Log::Audio, "Sound buffer format does not match requested format."); + ERROR_LOG(Log::Audio, "Output audio freq: %d (requested: %d)", g_retFmt.freq, fmt.freq); + ERROR_LOG(Log::Audio, "Output audio format: %d (requested: %d)", g_retFmt.format, fmt.format); + ERROR_LOG(Log::Audio, "Output audio channels: %d (requested: %d)", g_retFmt.channels, fmt.channels); + ERROR_LOG(Log::Audio, "Provided output format does not match requirement, turning audio off"); SDL_CloseAudioDevice(audioDev); } SDL_PauseAudioDevice(audioDev, 0); @@ -223,7 +223,7 @@ void System_Vibrate(int length_ms) { // Ignore on PC } -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { switch (type) { case SystemRequestType::RESTART_APP: g_RestartRequested = true; @@ -273,9 +273,8 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string g_requestManager.PostSystemFailure(requestId); } }; - DarwinFileSystemServices services; BrowseFileType fileType = (BrowseFileType)param3; - services.presentDirectoryPanel(callback, /* allowFiles = */ true, /* allowDirectories = */ false, fileType); + DarwinFileSystemServices::presentDirectoryPanel(callback, /* allowFiles = */ true, /* allowDirectories = */ false, fileType); return true; } case SystemRequestType::BROWSE_FOR_FOLDER: @@ -287,8 +286,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string g_requestManager.PostSystemFailure(requestId); } }; - DarwinFileSystemServices services; - services.presentDirectoryPanel(callback, /* allowFiles = */ false, /* allowDirectories = */ true); + DarwinFileSystemServices::presentDirectoryPanel(callback, /* allowFiles = */ false, /* allowDirectories = */ true); return true; } #endif @@ -367,7 +365,7 @@ void System_LaunchUrl(LaunchUrlType urlType, const char *url) { webWifiCreate(&conf, NULL, url, uuid, 0); webWifiShow(&conf, NULL); #elif defined(MOBILE_DEVICE) - INFO_LOG(SYSTEM, "Would have gone to %s but LaunchBrowser is not implemented on this platform", url); + INFO_LOG(Log::System, "Would have gone to %s but LaunchBrowser is not implemented on this platform", url); #elif defined(_WIN32) std::wstring wurl = ConvertUTF8ToWString(url); ShellExecute(NULL, L"open", wurl.c_str(), NULL, NULL, SW_SHOWNORMAL); @@ -377,7 +375,7 @@ void System_LaunchUrl(LaunchUrlType urlType, const char *url) { std::string command = std::string("xdg-open ") + url; int err = system(command.c_str()); if (err) { - INFO_LOG(SYSTEM, "Would have gone to %s but xdg-utils seems not to be installed", url); + INFO_LOG(Log::System, "Would have gone to %s but xdg-utils seems not to be installed", url); } #endif break; @@ -385,7 +383,7 @@ void System_LaunchUrl(LaunchUrlType urlType, const char *url) { case LaunchUrlType::EMAIL_ADDRESS: { #if defined(MOBILE_DEVICE) - INFO_LOG(SYSTEM, "Would have opened your email client for %s but LaunchEmail is not implemented on this platform", url); + INFO_LOG(Log::System, "Would have opened your email client for %s but LaunchEmail is not implemented on this platform", url); #elif defined(_WIN32) std::wstring mailto = std::wstring(L"mailto:") + ConvertUTF8ToWString(url); ShellExecute(NULL, L"open", mailto.c_str(), NULL, NULL, SW_SHOWNORMAL); @@ -396,7 +394,7 @@ void System_LaunchUrl(LaunchUrlType urlType, const char *url) { std::string command = std::string("xdg-email ") + url; int err = system(command.c_str()); if (err) { - INFO_LOG(SYSTEM, "Would have gone to %s but xdg-utils seems not to be installed", url); + INFO_LOG(Log::System, "Would have gone to %s but xdg-utils seems not to be installed", url); } #endif break; @@ -492,7 +490,7 @@ std::vector System_GetPropertyStringVec(SystemProperty prop) { } } -int System_GetPropertyInt(SystemProperty prop) { +int64_t System_GetPropertyInt(SystemProperty prop) { switch (prop) { case SYSPROP_AUDIO_SAMPLE_RATE: return g_retFmt.freq; @@ -545,6 +543,7 @@ float System_GetPropertyFloat(SystemProperty prop) { bool System_GetPropertyBool(SystemProperty prop) { switch (prop) { + case SYSPROP_HAS_TEXT_CLIPBOARD: case SYSPROP_CAN_SHOW_FILE: #if PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(MAC) || (PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)) return true; @@ -1110,6 +1109,8 @@ int main(int argc, char *argv[]) { } } + TimeInit(); + #ifdef HAVE_LIBNX socketInitializeDefault(); nxlinkStdio(); @@ -1133,8 +1134,10 @@ int main(int argc, char *argv[]) { SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); #endif + bool vulkanMayBeAvailable = false; if (VulkanMayBeAvailable()) { printf("DEBUG: Vulkan might be available.\n"); + vulkanMayBeAvailable = true; } else { printf("DEBUG: Vulkan is not available, not using Vulkan.\n"); } @@ -1317,35 +1320,60 @@ int main(int argc, char *argv[]) { x = g_Config.iWindowX; if (g_Config.iWindowY != -1) y = g_Config.iWindowY; - if (g_Config.iWindowWidth > 0) + if (g_Config.iWindowWidth > 0 && set_xres <= 0) w = g_Config.iWindowWidth; - if (g_Config.iWindowHeight > 0) + if (g_Config.iWindowHeight > 0 && set_yres <= 0) h = g_Config.iWindowHeight; } GraphicsContext *graphicsContext = nullptr; SDL_Window *window = nullptr; + // Switch away from Vulkan if not available. + if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && !vulkanMayBeAvailable) { + g_Config.iGPUBackend = (int)GPUBackend::OPENGL; + } + std::string error_message; if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) { - SDLGLGraphicsContext *ctx = new SDLGLGraphicsContext(); - if (ctx->Init(window, x, y, w, h, mode, &error_message) != 0) { - printf("GL init error '%s'\n", error_message.c_str()); + SDLGLGraphicsContext *glctx = new SDLGLGraphicsContext(); + if (glctx->Init(window, x, y, w, h, mode, &error_message) != 0) { + // Let's try the fallback once per process run. + printf("GL init error '%s' - falling back to Vulkan\n", error_message.c_str()); + g_Config.iGPUBackend = (int)GPUBackend::VULKAN; + SetGPUBackend((GPUBackend)g_Config.iGPUBackend); + delete glctx; + + // NOTE : This should match the lines below in the Vulkan case. + SDLVulkanGraphicsContext *vkctx = new SDLVulkanGraphicsContext(); + if (!vkctx->Init(window, x, y, w, h, mode | SDL_WINDOW_VULKAN, &error_message)) { + printf("Vulkan fallback failed: %s\n", error_message.c_str()); + return 1; + } + graphicsContext = vkctx; + } else { + graphicsContext = glctx; } - graphicsContext = ctx; #if !PPSSPP_PLATFORM(SWITCH) } else if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { - SDLVulkanGraphicsContext *ctx = new SDLVulkanGraphicsContext(); - if (!ctx->Init(window, x, y, w, h, mode | SDL_WINDOW_VULKAN, &error_message)) { + SDLVulkanGraphicsContext *vkctx = new SDLVulkanGraphicsContext(); + if (!vkctx->Init(window, x, y, w, h, mode | SDL_WINDOW_VULKAN, &error_message)) { + // Let's try the fallback once per process run. + printf("Vulkan init error '%s' - falling back to GL\n", error_message.c_str()); g_Config.iGPUBackend = (int)GPUBackend::OPENGL; SetGPUBackend((GPUBackend)g_Config.iGPUBackend); - delete ctx; + delete vkctx; + + // NOTE : This should match the three lines above in the OpenGL case. SDLGLGraphicsContext *glctx = new SDLGLGraphicsContext(); - glctx->Init(window, x, y, w, h, mode, &error_message); + if (glctx->Init(window, x, y, w, h, mode, &error_message) != 0) { + printf("GL fallback failed: %s\n", error_message.c_str()); + return 1; + } graphicsContext = glctx; } else { - graphicsContext = ctx; + graphicsContext = vkctx; } #endif } @@ -1388,14 +1416,19 @@ int main(int argc, char *argv[]) { // Since we render from the main thread, there's nothing done here, but we call it to avoid confusion. if (!graphicsContext->InitFromRenderThread(&error_message)) { printf("Init from thread error: '%s'\n", error_message.c_str()); + return 1; } + // OK, we have a valid graphics backend selected. Let's clear the failures. + g_Config.sFailedGPUBackends.clear(); + #ifdef MOBILE_DEVICE SDL_ShowCursor(SDL_DISABLE); #endif - // Ensure that the swap interval is set after context creation (needed for kmsdrm) - SDL_GL_SetSwapInterval(1); + // Avoid the IME popup when holding keys. This doesn't affect all versions of SDL. + // TODO: Enable it in text input fields + SDL_StopTextInput(); InitSDLAudioDevice(); @@ -1420,10 +1453,12 @@ int main(int argc, char *argv[]) { bool waitOnExit = g_Config.iGPUBackend == (int)GPUBackend::OPENGL; if (!mainThreadIsRender) { - // We should only be a message pump + // Vulkan mode uses this. + // We should only be a message pump. This allows for lower latency + // input events, and so on. while (true) { SDL_Event event; - while (SDL_PollEvent(&event)) { + while (SDL_WaitEventTimeout(&event, 100)) { ProcessSDLEvent(window, event, &inputTracker); } if (g_QuitRequested || g_RestartRequested) @@ -1478,7 +1513,7 @@ int main(int argc, char *argv[]) { EmuThreadStop("shutdown"); // Skipping GL calls, the old context is gone. while (graphicsContext->ThreadFrame()) { - INFO_LOG(SYSTEM, "graphicsContext->ThreadFrame executed to clear buffers"); + INFO_LOG(Log::System, "graphicsContext->ThreadFrame executed to clear buffers"); } EmuThreadJoin(); graphicsContext->ThreadEnd(); diff --git a/SDL/SDLVulkanGraphicsContext.cpp b/SDL/SDLVulkanGraphicsContext.cpp index 9300afa8d6..a581818bdc 100644 --- a/SDL/SDLVulkanGraphicsContext.cpp +++ b/SDL/SDLVulkanGraphicsContext.cpp @@ -84,8 +84,7 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int w, in g_Config.sVulkanDevice = vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName; } - vulkan_->ChooseDevice(deviceNum); - if (vulkan_->CreateDevice() != VK_SUCCESS) { + if (vulkan_->CreateDevice(deviceNum) != VK_SUCCESS) { *error_message = vulkan_->InitError(); delete vulkan_; vulkan_ = nullptr; diff --git a/SDL/macbundle.sh b/SDL/macbundle.sh index b51e804ce3..8cf177908c 100755 --- a/SDL/macbundle.sh +++ b/SDL/macbundle.sh @@ -1,6 +1,6 @@ #!/bin/bash -echo "Hello from macbundle.sh" +echo "SDL macbundle.sh" PPSSPP="${1}" PPSSPP_SHORTNAME="${2}" diff --git a/SDL/valgrind-wsl2.supp b/SDL/valgrind-wsl2.supp new file mode 100644 index 0000000000..ed8e7a7a7b --- /dev/null +++ b/SDL/valgrind-wsl2.supp @@ -0,0 +1,117 @@ +{ + + Memcheck:Addr8 + ... + fun:_dl_catch_exception + fun:_dl_map_object_deps + fun:dl_open_worker_begin + fun:_dl_catch_exception + fun:dl_open_worker +} +{ + + Memcheck:Cond + ... + fun:DXCoreCreateAdapterFactory + ... + obj:/*/swrast_dri.so +} +{ + + Memcheck:Cond + ... + obj:/usr/lib/wsl/lib/libd3d12core.so +} +{ + + Memcheck:Addr1 + ... + obj:/usr/lib/wsl/lib/libd3d12core.so +} +{ + + Memcheck:Addr8 + ... + obj:/usr/lib/wsl/lib/libd3d12core.so +} +{ + + Memcheck:Addr16 + ... + obj:/usr/lib/wsl/lib/libd3d12.so +} +{ + + Memcheck:Addr8 + ... + obj:/usr/lib/wsl/lib/libd3d12.so +} +{ + + Memcheck:Addr4 + ... + obj:/usr/lib/wsl/lib/libd3d12core.so +} +{ + + Memcheck:Addr16 + ... + obj:/usr/lib/wsl/lib/libd3d12core.so +} +{ + + Memcheck:Addr4 + ... + obj:/usr/lib/wsl/lib/libd3d12.so +} +{ + + Memcheck:Addr2 + ... + obj:/usr/lib/wsl/lib/libd3d12core.so +} +{ + + Memcheck:Addr1 + ... + obj:/usr/lib/wsl/lib/libd3d12core.so +} +{ + + Memcheck:Addr2 + ... + obj:/usr/lib/wsl/lib/libd3d12.so +} +{ + + Memcheck:Addr8 + ... + obj:/usr/lib/wsl/drivers/nvmdig.inf_amd64_e08347d07a4d61e2/libnvwgf2umx.so +} +{ + + Memcheck:Addr4 + ... + obj:/usr/lib/wsl/drivers/nvmdig.inf_amd64_e08347d07a4d61e2/libnvwgf2umx.so +} +{ + + Memcheck:Cond + obj:/usr/lib/wsl/lib/libdxcore.so + ... + obj:/usr/lib/x86_64-linux-gnu/libvulkan.so.* +} +{ + + Memcheck:Cond + ... + obj:/usr/lib/wsl/drivers/nvmdig.inf_amd64_e08347d07a4d61e2/libnvwgf2umx.so +} +{ + + Memcheck:Addr8 + fun:memmove + ... + obj:/usr/lib/x86_64-linux-gnu/dri/swrast_dri.so + ... +} \ No newline at end of file diff --git a/Tools/langtool/Cargo.lock b/Tools/langtool/Cargo.lock index 625e0c8159..10f0ab4cb3 100644 --- a/Tools/langtool/Cargo.lock +++ b/Tools/langtool/Cargo.lock @@ -4,47 +4,48 @@ version = 3 [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys", @@ -52,9 +53,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -62,9 +63,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -74,9 +75,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", "proc-macro2", @@ -86,15 +87,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "heck" @@ -102,6 +103,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "langtool" version = "0.1.0" @@ -111,18 +118,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -135,9 +142,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.58" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -152,9 +159,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "windows-sys" @@ -167,13 +174,14 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -182,42 +190,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/UI/BackgroundAudio.cpp b/UI/BackgroundAudio.cpp index 742e0c4cc4..c49941084f 100644 --- a/UI/BackgroundAudio.cpp +++ b/UI/BackgroundAudio.cpp @@ -1,6 +1,8 @@ #include #include +#include "ext/minimp3/minimp3_ex.h" + #include "Common/File/VFS/VFS.h" #include "Common/UI/Root.h" @@ -36,7 +38,7 @@ struct WavData { int raw_data_size = 0; u8 at3_extradata[16]; - void Read(RIFFReader &riff); + bool Read(RIFFReader &riff); ~WavData() { free(raw_data); @@ -49,7 +51,7 @@ struct WavData { } }; -void WavData::Read(RIFFReader &file_) { +bool WavData::Read(RIFFReader &file_) { // If we have no loop start info, we'll just loop the entire audio. raw_offset_loop_start = 0; raw_offset_loop_end = 0; @@ -71,8 +73,8 @@ void WavData::Read(RIFFReader &file_) { codec = 0; break; default: - ERROR_LOG(SCEAUDIO, "Unexpected wave format %04x", format); - return; + ERROR_LOG(Log::sceAudio, "Unexpected wave format %04x", format); + return false; } num_channels = temp >> 16; @@ -93,11 +95,11 @@ void WavData::Read(RIFFReader &file_) { } } file_.Ascend(); - // INFO_LOG(AUDIO, "got fmt data: %i", samplesPerSec); + // INFO_LOG(Log::AUDIO, "got fmt data: %i", samplesPerSec); } else { - ERROR_LOG(AUDIO, "Error - no format chunk in wav"); + ERROR_LOG(Log::Audio, "Error - no format chunk in wav"); file_.Ascend(); - return; + return false; } if (file_.Descend('smpl')) { @@ -154,23 +156,24 @@ void WavData::Read(RIFFReader &file_) { if (num_channels == 1 || num_channels == 2) { file_.ReadData(raw_data, numBytes); } else { - ERROR_LOG(AUDIO, "Error - bad blockalign or channels"); + ERROR_LOG(Log::Audio, "Error - bad blockalign or channels"); free(raw_data); raw_data = nullptr; - return; + return false; } file_.Ascend(); } else { - ERROR_LOG(AUDIO, "Error - no data chunk in wav"); + ERROR_LOG(Log::Audio, "Error - no data chunk in wav"); file_.Ascend(); - return; + return false; } file_.Ascend(); } else { - ERROR_LOG(AUDIO, "Could not descend into RIFF file."); - return; + ERROR_LOG(Log::Audio, "Could not descend into RIFF file."); + return false; } sample_rate = samplesPerSec; + return true; } // Really simple looping in-memory AT3 player that also takes care of reading the file format. @@ -186,11 +189,18 @@ public: wave_.Read(file_); - decoder_ = new SimpleAudio(wave_.codec, wave_.sample_rate, wave_.num_channels); + uint8_t *extraData = nullptr; + size_t extraDataSize = 0; + size_t blockSize = 0; if (wave_.codec == PSP_CODEC_AT3) { - decoder_->SetExtraData(&wave_.at3_extradata[2], 14, wave_.raw_bytes_per_frame); + extraData = &wave_.at3_extradata[2]; + extraDataSize = 14; + blockSize = wave_.raw_bytes_per_frame; + } else if (wave_.codec == PSP_CODEC_AT3PLUS) { + blockSize = wave_.raw_bytes_per_frame; } - INFO_LOG(AUDIO, "read ATRAC, frames: %d, rate %d", wave_.numFrames, wave_.sample_rate); + decoder_ = CreateAudioDecoder((PSPAudioType)wave_.codec, wave_.sample_rate, wave_.num_channels, blockSize, extraData, extraDataSize); + INFO_LOG(Log::Audio, "read ATRAC, frames: %d, rate %d", wave_.numFrames, wave_.sample_rate); } ~AT3PlusReader() { @@ -207,10 +217,12 @@ public: return false; while (bgQueue.size() < (size_t)(len * 2)) { - int outBytes = 0; - decoder_->Decode(wave_.raw_data + raw_offset_, wave_.raw_bytes_per_frame, (uint8_t *)buffer_, &outBytes); - if (!outBytes) + int outSamples = 0; + int inbytesConsumed = 0; + bool result = decoder_->Decode(wave_.raw_data + raw_offset_, wave_.raw_bytes_per_frame, &inbytesConsumed, 2, (int16_t *)buffer_, &outSamples); + if (!result || !outSamples) return false; + int outBytes = outSamples * 2 * sizeof(int16_t); if (wave_.raw_offset_loop_end != 0 && raw_offset_ == wave_.raw_offset_loop_end) { // Only take the remaining bytes, but convert to stereo s16. @@ -253,7 +265,7 @@ private: int skip_next_samples_ = 0; FixedSizeQueue bgQueue; short *buffer_ = nullptr; - SimpleAudio *decoder_ = nullptr; + AudioDecoder *decoder_ = nullptr; }; BackgroundAudio g_BackgroundAudio; @@ -380,40 +392,67 @@ inline int16_t ConvertU8ToI16(uint8_t value) { } Sample *Sample::Load(const std::string &path) { - size_t bytes = 0; - uint8_t *data = g_VFS.ReadFile(path.c_str(), &bytes); - if (!data || bytes > 100000000) { - WARN_LOG(AUDIO, "Failed to load sample '%s'", path.c_str()); + size_t data_size = 0; + uint8_t *data = g_VFS.ReadFile(path.c_str(), &data_size); + if (!data || data_size > 100000000) { + WARN_LOG(Log::Audio, "Failed to load sample '%s'", path.c_str()); return nullptr; } - RIFFReader reader(data, (int)bytes); - - WavData wave; - wave.Read(reader); - - delete[] data; - - if (!wave.IsSimpleWAV()) { - ERROR_LOG(AUDIO, "Wave format not supported for mixer playback. Must be 8-bit or 16-bit raw mono or stereo. '%s'", path.c_str()); - return nullptr; - } - - int16_t *samples = new int16_t[wave.num_channels * wave.numFrames]; - if (wave.raw_bytes_per_frame == wave.num_channels * 2) { - // 16-bit - memcpy(samples, wave.raw_data, wave.numFrames * wave.raw_bytes_per_frame); - } else if (wave.raw_bytes_per_frame == wave.num_channels) { - // 8-bit. Convert. - for (int i = 0; i < wave.num_channels * wave.numFrames; i++) { - samples[i] = ConvertU8ToI16(wave.raw_data[i]); + const char *mp3_magic = "ID3\03"; + const char *wav_magic = "RIFF"; + if (!memcmp(data, wav_magic, 4)) { + RIFFReader reader(data, (int)data_size); + WavData wave; + if (!wave.Read(reader)) { + delete[] data; + return nullptr; } + // A wav file. + delete[] data; + + if (!wave.IsSimpleWAV()) { + ERROR_LOG(Log::Audio, "Wave format not supported for mixer playback. Must be 8-bit or 16-bit raw mono or stereo. '%s'", path.c_str()); + return nullptr; + } + + int16_t *samples = new int16_t[wave.num_channels * wave.numFrames]; + if (wave.raw_bytes_per_frame == wave.num_channels * 2) { + // 16-bit + memcpy(samples, wave.raw_data, wave.numFrames * wave.raw_bytes_per_frame); + } else if (wave.raw_bytes_per_frame == wave.num_channels) { + // 8-bit. Convert. + for (int i = 0; i < wave.num_channels * wave.numFrames; i++) { + samples[i] = ConvertU8ToI16(wave.raw_data[i]); + } + } + + // Protect against bad metadata. + int actualFrames = std::min(wave.numFrames, wave.raw_data_size / wave.raw_bytes_per_frame); + + return new Sample(samples, wave.num_channels, actualFrames, wave.sample_rate); } - // Protect against bad metadata. - int actualFrames = std::min(wave.numFrames, wave.raw_data_size / wave.raw_bytes_per_frame); + // Something else. + // Let's see if minimp3 can read it. + mp3dec_t mp3d; + mp3dec_init(&mp3d); + mp3dec_file_info_t mp3_info; + int retval = mp3dec_load_buf(&mp3d, data, data_size, &mp3_info, nullptr, nullptr); - return new Sample(samples, wave.num_channels, actualFrames, wave.sample_rate); + if (retval < 0 || mp3_info.samples == 0) { + ERROR_LOG(Log::Audio, "Couldn't load MP3 for sound effect from %s", path.c_str()); + return nullptr; + } + + // mp3_info contains the decoded data. + int16_t *sample_data = new int16_t[mp3_info.samples]; + memcpy(sample_data, mp3_info.buffer, mp3_info.samples * sizeof(int16_t)); + + Sample *sample = new Sample(sample_data, mp3_info.channels, (int)mp3_info.samples / mp3_info.channels, mp3_info.hz); + free(mp3_info.buffer); + delete[] data; + return sample; } static inline int16_t Clamp16(int32_t sample) { @@ -516,7 +555,7 @@ void SoundEffectMixer::LoadDefaultSample(UI::UISound sound) { } Sample *sample = Sample::Load(filename); if (!sample) { - ERROR_LOG(SYSTEM, "Failed to load the default sample for UI sound %d", (int)sound); + ERROR_LOG(Log::System, "Failed to load the default sample for UI sound %d", (int)sound); } std::lock_guard guard(mutex_); samples_[(size_t)sound] = std::unique_ptr(sample); diff --git a/UI/BackgroundAudio.h b/UI/BackgroundAudio.h index 3c869485dc..4f2952fd73 100644 --- a/UI/BackgroundAudio.h +++ b/UI/BackgroundAudio.h @@ -11,7 +11,7 @@ class AT3PlusReader; struct Sample { - // data must be new-ed. + // data must be new[]-ed. Sample(int16_t *data, int channels, int length, int rateInHz) : channels_(channels), data_(data), length_(length), rateInHz_(rateInHz) {} ~Sample() { delete[] data_; diff --git a/UI/ChatScreen.cpp b/UI/ChatScreen.cpp index 1a79eaee06..6cafc63a05 100644 --- a/UI/ChatScreen.cpp +++ b/UI/ChatScreen.cpp @@ -26,7 +26,7 @@ void ChatMenu::CreateContents(UI::ViewGroup *parent) { chatEdit_ = bottom->Add(new TextEdit("", n->T("Chat message"), n->T("Chat Here"), new LinearLayoutParams(1.0))); chatEdit_->OnEnter.Handle(this, &ChatMenu::OnSubmit); -#elif PPSSPP_PLATFORM(ANDROID) +#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) bottom->Add(new Button(n->T("Chat Here"),new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->OnClick.Handle(this, &ChatMenu::OnSubmit); bottom->Add(new Button(n->T("Send")))->OnClick.Handle(this, &ChatMenu::OnSubmit); #endif @@ -95,7 +95,7 @@ UI::EventReturn ChatMenu::OnSubmit(UI::EventParams &e) { chatEdit_->SetText(""); chatEdit_->SetFocus(); sendChat(chat); -#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) +#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) || PPSSPP_PLATFORM(IOS) auto n = GetI18NCategory(I18NCat::NETWORKING); System_InputBoxGetString(token_, n->T("Chat"), "", [](const std::string &value, int) { sendChat(value); diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index c95e732783..564fe3da21 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -97,15 +97,16 @@ void SingleControlMapper::Refresh() { Clear(); auto mc = GetI18NCategory(I18NCat::MAPPABLECONTROLS); - std::map keyImages; - keyImages["Circle"] = ImageID("I_CIRCLE"); - keyImages["Cross"] = ImageID("I_CROSS"); - keyImages["Square"] = ImageID("I_SQUARE"); - keyImages["Triangle"] = ImageID("I_TRIANGLE"); - keyImages["Start"] = ImageID("I_START"); - keyImages["Select"] = ImageID("I_SELECT"); - keyImages["L"] = ImageID("I_L"); - keyImages["R"] = ImageID("I_R"); + std::map keyImages = { + { "Circle", ImageID("I_CIRCLE") }, + { "Cross", ImageID("I_CROSS") }, + { "Square", ImageID("I_SQUARE") }, + { "Triangle", ImageID("I_TRIANGLE") }, + { "Start", ImageID("I_START") }, + { "Select", ImageID("I_SELECT") }, + { "L", ImageID("I_L") }, + { "R", ImageID("I_R") } + }; using namespace UI; @@ -234,6 +235,21 @@ UI::EventReturn SingleControlMapper::OnDelete(UI::EventParams ¶ms) { return UI::EVENT_DONE; } + +struct BindingCategory { + const char *catName; + int firstKey; +}; + +// Category name, first input from psp_button_names. +static const BindingCategory cats[] = { + {"Standard PSP controls", CTRL_UP}, + {"Control modifiers", VIRTKEY_ANALOG_ROTATE_CW}, + {"Emulator controls", VIRTKEY_FASTFORWARD}, + {"Extended PSP controls", VIRTKEY_AXIS_RIGHT_Y_MAX}, + {}, // sentinel +}; + void ControlMappingScreen::CreateViews() { using namespace UI; mappers_.clear(); @@ -278,25 +294,12 @@ void ControlMappingScreen::CreateViews() { size_t numMappableKeys = 0; const KeyMap::KeyMap_IntStrPair *mappableKeys = KeyMap::GetMappableKeys(&numMappableKeys); - struct Cat { - const char *catName; - int firstKey; - bool *open; - }; - // Category name, first input from psp_button_names. - static const Cat cats[] = { - {"Standard PSP controls", CTRL_UP, &categoryToggles_[0]}, - {"Control modifiers", VIRTKEY_ANALOG_ROTATE_CW, &categoryToggles_[1]}, - {"Emulator controls", VIRTKEY_FASTFORWARD, &categoryToggles_[2]}, - {"Extended PSP controls", VIRTKEY_AXIS_RIGHT_Y_MAX, &categoryToggles_[3]}, - }; - int curCat = -1; CollapsibleSection *curSection = nullptr; for (size_t i = 0; i < numMappableKeys; i++) { if (curCat < (int)ARRAY_SIZE(cats) && mappableKeys[i].key == cats[curCat + 1].firstKey) { if (curCat >= 0) { - curSection->SetOpenPtr(cats[curCat].open); + curSection->SetOpenPtr(&categoryToggles_[curCat]); } curCat++; curSection = rightColumn->Add(new CollapsibleSection(km->T(cats[curCat].catName))); @@ -309,8 +312,9 @@ void ControlMappingScreen::CreateViews() { mappers_.push_back(mapper); } if (curCat >= 0 && curSection) { - curSection->SetOpenPtr(cats[curCat].open); + curSection->SetOpenPtr(&categoryToggles_[curCat]); } + _dbg_assert_(curCat == ARRAY_SIZE(cats) - 2); // count the sentinel keyMapGeneration_ = KeyMap::g_controllerMapGeneration; } diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index d6d7c1421c..2cf3225600 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -53,7 +53,7 @@ bool CwCheatScreen::TryLoadCheatInfo() { if (!info->Ready(GameInfoFlags::PARAM_SFO)) { return false; } - gameID = info->paramSFO.GetValueString("DISC_ID"); + gameID = info->GetParamSFO().GetValueString("DISC_ID"); if ((info->id.empty() || !info->disc_total) && gamePath_.FilePathContainsNoCase("PSP/GAME/")) { gameID = g_paramSFO.GenerateFakeID(gamePath_); @@ -217,7 +217,7 @@ static char *GetLineNoNewline(char *temp, int sz, FILE *fp) { UI::EventReturn CwCheatScreen::OnImportBrowse(UI::EventParams ¶ms) { System_BrowseForFile(GetRequesterToken(), "Open cheat DB file", BrowseFileType::DB, [&](const std::string &value, int) { Path path(value); - INFO_LOG(SYSTEM, "Attempting to load cheats from: '%s'", path.ToVisualString().c_str()); + INFO_LOG(Log::System, "Attempting to load cheats from: '%s'", path.ToVisualString().c_str()); if (ImportCheats(path)) { g_Config.bReloadCheats = true; } else { @@ -242,7 +242,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { bool CwCheatScreen::ImportCheats(const Path & cheatFile) { if (gameID_.length() != 9 || !engine_) { - WARN_LOG(COMMON, "CWCHEAT: Incorrect ID(%s) - can't import cheats.", gameID_.c_str()); + WARN_LOG(Log::Common, "CWCHEAT: Incorrect ID(%s) - can't import cheats.", gameID_.c_str()); return false; } @@ -250,7 +250,7 @@ bool CwCheatScreen::ImportCheats(const Path & cheatFile) { FILE *in = File::OpenCFile(cheatFile, "rt"); if (!in) { - WARN_LOG(COMMON, "Unable to open %s\n", cheatFile.c_str()); + WARN_LOG(Log::Common, "Unable to open %s\n", cheatFile.c_str()); return false; } @@ -315,7 +315,7 @@ bool CwCheatScreen::ImportCheats(const Path & cheatFile) { } } - NOTICE_LOG(COMMON, "Imported %u lines from %s.\n", (int)newList.size(), cheatFile.c_str()); + NOTICE_LOG(Log::Common, "Imported %u lines from %s.\n", (int)newList.size(), cheatFile.c_str()); if (newList.size() != 0) { fputc('\n', append); } diff --git a/UI/DarwinFileSystemServices.h b/UI/DarwinFileSystemServices.h index 2b22d12acf..e992c7a4e0 100644 --- a/UI/DarwinFileSystemServices.h +++ b/UI/DarwinFileSystemServices.h @@ -20,19 +20,21 @@ typedef std::function DarwinDirectoryPanelCallback; class DarwinFileSystemServices { public: /// Present a panel to choose a file or directory. - void presentDirectoryPanel( - DarwinDirectoryPanelCallback, + static void presentDirectoryPanel( + DarwinDirectoryPanelCallback panelCallback, bool allowFiles = false, bool allowDirectories = true, BrowseFileType fileType = BrowseFileType::ANY); static Path appropriateMemoryStickDirectoryToUse(); static void setUserPreferredMemoryStickDirectory(Path); + + static void ClearDelegate(); private: static Path __defaultMemoryStickPath(); #if PPSSPP_PLATFORM(IOS) // iOS only, needed for UIDocumentPickerViewController - void *__pickerDelegate = NULL; + static void *__pickerDelegate; #endif // PPSSPP_PLATFORM(IOS) }; diff --git a/UI/DarwinFileSystemServices.mm b/UI/DarwinFileSystemServices.mm index 2afeabfa94..5f08c1c781 100644 --- a/UI/DarwinFileSystemServices.mm +++ b/UI/DarwinFileSystemServices.mm @@ -7,6 +7,7 @@ #include "ppsspp_config.h" #include "Core/Config.h" +#include "Common/Log.h" #include "DarwinFileSystemServices.h" #include #include @@ -16,26 +17,45 @@ #endif #if __has_include() +#include "../ios/ViewControllerCommon.h" #include @interface DocumentPickerDelegate : NSObject -@property DarwinDirectoryPanelCallback callback; +@property DarwinDirectoryPanelCallback panelCallback; @end +void *DarwinFileSystemServices::__pickerDelegate = nullptr; + +void DarwinFileSystemServices::ClearDelegate() { + // TODO: Figure out how to free the delegate. + // CFRelease((__bridge DocumentPickerDelegate *)__pickerDelegate); + __pickerDelegate = NULL; +} + @implementation DocumentPickerDelegate --(instancetype)initWithCallback: (DarwinDirectoryPanelCallback)callback { - if (self = [super init]) { - self.callback = callback; - } - - return self; +-(instancetype)initWithCallback: (DarwinDirectoryPanelCallback)panelCallback { + if (self = [super init]) { + self.panelCallback = panelCallback; + } + return self; } - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray *)urls { - if (urls.count >= 1) - self.callback(true, Path(urls[0].path.UTF8String)); - else - self.callback(false, Path()); + if (urls.count >= 1) + self.panelCallback(true, Path(urls[0].path.UTF8String)); + else + self.panelCallback(false, Path()); + + INFO_LOG(Log::System, "Callback processed, pre-emptively hide keyboard"); + [sharedViewController hideKeyboard]; + DarwinFileSystemServices::ClearDelegate(); +} + +- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller { + self.panelCallback(false, Path()); + + INFO_LOG(Log::System, "Picker cancelled, pre-emptively hide keyboard"); + [sharedViewController hideKeyboard]; } @end @@ -45,7 +65,7 @@ #endif // __has_include() void DarwinFileSystemServices::presentDirectoryPanel( - DarwinDirectoryPanelCallback callback, + DarwinDirectoryPanelCallback panelCallback, bool allowFiles, bool allowDirectories, BrowseFileType fileType) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -75,13 +95,17 @@ void DarwinFileSystemServices::presentDirectoryPanel( } // if (!allowFiles && allowDirectories) // panel.allowedFileTypes = @[(__bridge NSString *)kUTTypeFolder]; - - NSModalResponse modalResponse = [panel runModal]; - if (modalResponse == NSModalResponseOK && panel.URLs.firstObject) { - callback(true, Path(panel.URLs.firstObject.path.UTF8String)); - } else if (modalResponse == NSModalResponseCancel) { - callback(false, Path()); - } + NSModalResponse modalResponse = [panel runModal]; + if (modalResponse == NSModalResponseOK && panel.URLs.firstObject) { + INFO_LOG(Log::System, "Mac: Received OK response from modal"); + panelCallback(true, Path(panel.URLs.firstObject.path.UTF8String)); + } else if (modalResponse == NSModalResponseCancel) { + INFO_LOG(Log::System, "Mac: Received Cancel response from modal"); + panelCallback(false, Path()); + } else { + WARN_LOG(Log::System, "Mac: Received unknown responsde from modal"); + panelCallback(false, Path()); + } #elif PPSSPP_PLATFORM(IOS) UIViewController *rootViewController = UIApplication.sharedApplication .keyWindow @@ -104,7 +128,7 @@ void DarwinFileSystemServices::presentDirectoryPanel( UIDocumentPickerViewController *pickerVC = [[UIDocumentPickerViewController alloc] initWithDocumentTypes: types inMode: pickerMode]; // What if you wanted to go to heaven, but then God showed you the next few lines? // serious note: have to do this, because __pickerDelegate has to stay retained as a class property - __pickerDelegate = (void *)CFBridgingRetain([[DocumentPickerDelegate alloc] initWithCallback:callback]); + __pickerDelegate = (void *)CFBridgingRetain([[DocumentPickerDelegate alloc] initWithCallback:panelCallback]); pickerVC.delegate = (__bridge DocumentPickerDelegate *)__pickerDelegate; [rootViewController presentViewController:pickerVC animated:true completion:nil]; #endif @@ -144,4 +168,4 @@ void RestartMacApp() { [task launch]; exit(0); #endif -} \ No newline at end of file +} diff --git a/UI/DebugOverlay.cpp b/UI/DebugOverlay.cpp index 6a54cc882b..fec216f949 100644 --- a/UI/DebugOverlay.cpp +++ b/UI/DebugOverlay.cpp @@ -2,6 +2,7 @@ #include "Common/GPU/thin3d.h" #include "Common/System/System.h" #include "Common/Data/Text/I18n.h" +#include "Common/CPUDetect.h" #include "Core/MIPS/MIPS.h" #include "Core/HW/Display.h" #include "Core/FrameTiming.h" @@ -229,7 +230,7 @@ void DrawDebugOverlay(UIContext *ctx, const Bounds &bounds, DebugOverlay overlay case DebugOverlay::FRAME_TIMING: DrawFrameTiming(ctx, ctx->GetLayoutBounds()); break; - case DebugOverlay::AUDIO: + case DebugOverlay::Audio: DrawAudioDebugStats(ctx, ctx->GetLayoutBounds()); break; #if !PPSSPP_PLATFORM(UWP) && !PPSSPP_PLATFORM(SWITCH) @@ -324,7 +325,7 @@ void DrawCrashDump(UIContext *ctx, const Path &gamePath) { ctx->PushScissor(Bounds(x, y, columnWidth, height)); - // INFO_LOG(SYSTEM, "DrawCrashDump (%d %d %d %d)", x, y, columnWidth, height); + // INFO_LOG(Log::System, "DrawCrashDump (%d %d %d %d)", x, y, columnWidth, height); snprintf(statbuf, sizeof(statbuf), R"(%s %s (%s) @@ -434,21 +435,23 @@ void DrawFPS(UIContext *ctx, const Bounds &bounds) { float vps, fps, actual_fps; __DisplayGetFPS(&vps, &fps, &actual_fps); - char fpsbuf[256]{}; - if (g_Config.iShowStatusFlags == ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) { - snprintf(fpsbuf, sizeof(fpsbuf), "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / (59.94f / 100.0f)); + char fpsbuf[256]; + fpsbuf[0] = '\0'; + if ((g_Config.iShowStatusFlags & ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) == ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) { + snprintf(fpsbuf, sizeof(fpsbuf), "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / ((g_Config.iDisplayRefreshRate / 60.0f * 59.94f) / 100.0f)); } else { if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER) { snprintf(fpsbuf, sizeof(fpsbuf), "FPS: %0.1f", actual_fps); - } - if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER) { - snprintf(fpsbuf, sizeof(fpsbuf), "%s Speed: %0.1f%%", fpsbuf, vps / (59.94f / 100.0f)); + } else if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER) { + snprintf(fpsbuf, sizeof(fpsbuf), "Speed: %0.1f%%", vps / (59.94f / 100.0f)); } } #ifdef CAN_DISPLAY_CURRENT_BATTERY_CAPACITY if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT) { - snprintf(fpsbuf, sizeof(fpsbuf), "%s Battery: %d%%", fpsbuf, getCurrentBatteryCapacity()); + char temp[256]; + snprintf(temp, sizeof(temp), "%s Battery: %d%%", fpsbuf, getCurrentBatteryCapacity()); + snprintf(fpsbuf, sizeof(fpsbuf), "%s", temp); } #endif diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 983f599214..53300d3d74 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -46,7 +46,7 @@ #include "Common/Data/Text/Parsers.h" #include "Common/Profiler/Profiler.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Common/CPUDetect.h" #include "Common/StringUtils.h" @@ -56,6 +56,7 @@ #include "Core/System.h" #include "Core/Reporting.h" #include "Core/CoreParameter.h" +#include "Core/HLE/sceKernel.h" // GPI/GPO #include "Core/MIPS/MIPSTables.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" #include "Core/MIPS/JitCommon/JitCommon.h" @@ -68,6 +69,7 @@ #include "UI/MainScreen.h" #include "UI/ControlMappingScreen.h" #include "UI/GameSettingsScreen.h" +#include "UI/JitCompareScreen.h" #ifdef _WIN32 // Want to avoid including the full header here as it includes d3dx.h @@ -141,9 +143,14 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { items->Add(new Choice(dev->T("Reset limited logging")))->OnClick.Handle(this, &DevMenuScreen::OnResetLimitedLogging); + items->Add(new Choice(dev->T("GPI/GPO switches/LEDs")))->OnClick.Add([=](UI::EventParams &e) { + screenManager()->push(new GPIGPOScreen(dev->T("GPI/GPO switches/LEDs"))); + return UI::EVENT_DONE; + }); + items->Add(new Choice(dev->T("Create frame dump")))->OnClick.Add([](UI::EventParams &e) { GPURecord::RecordNextFrame([](const Path &dumpPath) { - NOTICE_LOG(SYSTEM, "Frame dump created at '%s'", dumpPath.c_str()); + NOTICE_LOG(Log::System, "Frame dump created at '%s'", dumpPath.c_str()); if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) { System_ShowFileInFolder(dumpPath); } else { @@ -213,6 +220,16 @@ void DevMenuScreen::dialogFinished(const Screen *dialog, DialogResult result) { // TriggerFinish(DR_OK); } +void GPIGPOScreen::CreatePopupContents(UI::ViewGroup *parent) { + using namespace UI; + auto dev = GetI18NCategory(I18NCat::DEVELOPER); + parent->Add(new CheckBox(&g_Config.bShowGPOLEDs, dev->T("Show GPO LEDs"))); + for (int i = 0; i < 8; i++) { + std::string name = ApplySafeSubstitutions(dev->T("GPI switch %1"), i); + parent->Add(new BitCheckBox(&g_GPIBits, 1 << i, name)); + } +} + void LogScreen::UpdateLog() { using namespace UI; RingbufferLogListener *ring = LogManager::GetInstance()->GetRingbufferListener(); @@ -268,7 +285,7 @@ UI::EventReturn LogScreen::OnSubmit(UI::EventParams &e) { // TODO: Can add all sorts of fun stuff here that we can't be bothered writing proper UI for, like various memdumps etc. - NOTICE_LOG(SYSTEM, "Submitted: %s", cmd.c_str()); + NOTICE_LOG(Log::System, "Submitted: %s", cmd.c_str()); UpdateLog(); cmdLine_->SetText(""); @@ -307,7 +324,7 @@ void LogConfigScreen::CreateViews() { GridLayout *grid = vert->Add(new GridLayoutList(gridsettings, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); for (int i = 0; i < LogManager::GetNumChannels(); i++) { - LogType type = (LogType)i; + Log type = (Log)i; LogChannel *chan = logMan->GetLogChannel(type); LinearLayout *row = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(cellSize - 50, WRAP_CONTENT)); row->SetSpacing(0); @@ -320,7 +337,7 @@ void LogConfigScreen::CreateViews() { UI::EventReturn LogConfigScreen::OnToggleAll(UI::EventParams &e) { LogManager *logMan = LogManager::GetInstance(); for (int i = 0; i < LogManager::GetNumChannels(); i++) { - LogChannel *chan = logMan->GetLogChannel((LogType)i); + LogChannel *chan = logMan->GetLogChannel((Log)i); chan->enabled = !chan->enabled; } return UI::EVENT_DONE; @@ -329,7 +346,7 @@ UI::EventReturn LogConfigScreen::OnToggleAll(UI::EventParams &e) { UI::EventReturn LogConfigScreen::OnEnableAll(UI::EventParams &e) { LogManager *logMan = LogManager::GetInstance(); for (int i = 0; i < LogManager::GetNumChannels(); i++) { - LogChannel *chan = logMan->GetLogChannel((LogType)i); + LogChannel *chan = logMan->GetLogChannel((Log)i); chan->enabled = true; } return UI::EVENT_DONE; @@ -338,7 +355,7 @@ UI::EventReturn LogConfigScreen::OnEnableAll(UI::EventParams &e) { UI::EventReturn LogConfigScreen::OnDisableAll(UI::EventParams &e) { LogManager *logMan = LogManager::GetInstance(); for (int i = 0; i < LogManager::GetNumChannels(); i++) { - LogChannel *chan = logMan->GetLogChannel((LogType)i); + LogChannel *chan = logMan->GetLogChannel((Log)i); chan->enabled = false; } return UI::EVENT_DONE; @@ -376,7 +393,7 @@ void LogLevelScreen::OnCompleted(DialogResult result) { LogManager *logMan = LogManager::GetInstance(); for (int i = 0; i < LogManager::GetNumChannels(); ++i) { - LogType type = (LogType)i; + Log type = (Log)i; LogChannel *chan = logMan->GetLogChannel(type); if (chan->enabled) chan->level = (LogLevel)(selected + 1); @@ -452,34 +469,6 @@ UI::EventReturn JitDebugScreen::OnDisableAll(UI::EventParams &e) { return UI::EVENT_DONE; } -const char *GetCompilerABI() { -#if PPSSPP_ARCH(ARMV7) - return "armeabi-v7a"; -#elif PPSSPP_ARCH(ARM) - return "armeabi"; -#elif PPSSPP_ARCH(ARM64) - return "arm64"; -#elif PPSSPP_ARCH(X86) - return "x86"; -#elif PPSSPP_ARCH(AMD64) - return "x86-64"; -#elif PPSSPP_ARCH(RISCV64) - //https://github.com/riscv/riscv-toolchain-conventions#cc-preprocessor-definitions - //https://github.com/riscv/riscv-c-api-doc/blob/master/riscv-c-api.md#abi-related-preprocessor-definitions - #if defined(__riscv_float_abi_single) - return "lp64f"; - #elif defined(__riscv_float_abi_double) - return "lp64d"; - #elif defined(__riscv_float_abi_quad) - return "lp64q"; - #elif defined(__riscv_float_abi_soft) - return "lp64"; - #endif -#else - return "other"; -#endif -} - void SystemInfoScreen::update() { TabbedUIDialogScreenWithGameBackground::update(); g_OSD.NudgeSidebar(); @@ -500,6 +489,11 @@ void SystemInfoScreen::CreateTabs() { systemInfo->Add(new InfoItem(si->T("System Name", "Name"), System_GetProperty(SYSPROP_NAME))); #if PPSSPP_PLATFORM(ANDROID) systemInfo->Add(new InfoItem(si->T("System Version"), StringFromInt(System_GetPropertyInt(SYSPROP_SYSTEMVERSION)))); +#elif PPSSPP_PLATFORM(WINDOWS) + std::string sysVersion = System_GetProperty(SYSPROP_SYSTEMBUILD); + if (!sysVersion.empty()) { + systemInfo->Add(new InfoItem(si->T("OS Build"), sysVersion)); + } #endif systemInfo->Add(new InfoItem(si->T("Lang/Region"), System_GetProperty(SYSPROP_LANGREGION))); std::string board = System_GetProperty(SYSPROP_BOARDNAME); @@ -704,6 +698,9 @@ void SystemInfoScreen::CreateTabs() { #ifdef JENKINS buildConfig->Add(new InfoItem(si->T("Built by"), "Jenkins")); #endif +#ifdef ANDROID_LEGACY + buildConfig->Add(new InfoItem("ANDROID_LEGACY", "")); +#endif #ifdef _DEBUG buildConfig->Add(new InfoItem("_DEBUG", "")); #else @@ -870,8 +867,14 @@ void SystemInfoScreen::CreateInternalsTab(UI::ViewGroup *internals) { g_OSD.Show(OSDType::MESSAGE_INFO, "Info"); return UI::EVENT_DONE; }); + // This one is clickable internals->Add(new Choice(si->T("Success")))->OnClick.Add([&](UI::EventParams &) { - g_OSD.Show(OSDType::MESSAGE_SUCCESS, "Success"); + g_OSD.Show(OSDType::MESSAGE_SUCCESS, "Success", 0.0f, "clickable"); + g_OSD.SetClickCallback("clickable", [](bool clicked, void *) { + if (clicked) { + System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.google.com/"); + } + }, nullptr); return UI::EVENT_DONE; }); internals->Add(new Choice(sy->T("RetroAchievements")))->OnClick.Add([&](UI::EventParams &) { @@ -926,356 +929,6 @@ void SystemInfoScreen::CreateInternalsTab(UI::ViewGroup *internals) { #endif } -void AddressPromptScreen::CreatePopupContents(UI::ViewGroup *parent) { - using namespace UI; - - auto dev = GetI18NCategory(I18NCat::DEVELOPER); - - addrView_ = new TextView(dev->T("Enter address"), ALIGN_HCENTER, false); - parent->Add(addrView_); - - ViewGroup *grid = new GridLayout(GridLayoutSettings(60, 40)); - parent->Add(grid); - - for (int i = 0; i < 16; ++i) { - char temp[16]; - snprintf(temp, 16, " %X ", i); - buttons_[i] = new Button(temp); - grid->Add(buttons_[i])->OnClick.Handle(this, &AddressPromptScreen::OnDigitButton); - } - - parent->Add(new Button(dev->T("Backspace")))->OnClick.Handle(this, &AddressPromptScreen::OnBackspace); -} - -void AddressPromptScreen::OnCompleted(DialogResult result) { - if (result == DR_OK) { - UI::EventParams e{}; - e.v = root_; - e.a = addr_; - OnChoice.Trigger(e); - } -} - -UI::EventReturn AddressPromptScreen::OnDigitButton(UI::EventParams &e) { - for (int i = 0; i < 16; ++i) { - if (buttons_[i] == e.v) { - AddDigit(i); - } - } - return UI::EVENT_DONE; -} - -UI::EventReturn AddressPromptScreen::OnBackspace(UI::EventParams &e) { - BackspaceDigit(); - return UI::EVENT_DONE; -} - -void AddressPromptScreen::AddDigit(int n) { - if ((addr_ & 0xF0000000) == 0) { - addr_ = addr_ * 16 + n; - } - UpdatePreviewDigits(); -} - -void AddressPromptScreen::BackspaceDigit() { - addr_ /= 16; - UpdatePreviewDigits(); -} - -void AddressPromptScreen::UpdatePreviewDigits() { - if (addr_ != 0) { - char temp[32]; - snprintf(temp, 32, "%8X", addr_); - addrView_->SetText(temp); - } else { - auto dev = GetI18NCategory(I18NCat::DEVELOPER); - addrView_->SetText(dev->T("Enter address")); - } -} - -bool AddressPromptScreen::key(const KeyInput &key) { - if (key.flags & KEY_DOWN) { - if (key.keyCode >= NKCODE_0 && key.keyCode <= NKCODE_9) { - AddDigit(key.keyCode - NKCODE_0); - } else if (key.keyCode >= NKCODE_A && key.keyCode <= NKCODE_F) { - AddDigit(10 + key.keyCode - NKCODE_A); - // NKCODE_DEL is backspace. - } else if (key.keyCode == NKCODE_DEL) { - BackspaceDigit(); - } else if (key.keyCode == NKCODE_ENTER) { - TriggerFinish(DR_OK); - } else { - return UIDialogScreen::key(key); - } - } else { - return UIDialogScreen::key(key); - } - return true; -} - -// Three panes: Block chooser, MIPS view, ARM/x86 view -void JitCompareScreen::CreateViews() { - auto di = GetI18NCategory(I18NCat::DIALOG); - auto dev = GetI18NCategory(I18NCat::DEVELOPER); - - using namespace UI; - - root_ = new LinearLayout(ORIENT_HORIZONTAL); - - ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); - LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); - - ScrollView *midColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.0f))); - LinearLayout *midColumn = midColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); - midColumn->SetTag("JitCompareLeftDisasm"); - leftDisasm_ = midColumn->Add(new LinearLayout(ORIENT_VERTICAL)); - leftDisasm_->SetSpacing(0.0f); - - ScrollView *rightColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.0f))); - rightColumnScroll->SetTag("JitCompareRightDisasm"); - LinearLayout *rightColumn = rightColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); - rightDisasm_ = rightColumn->Add(new LinearLayout(ORIENT_VERTICAL)); - rightDisasm_->SetSpacing(0.0f); - - leftColumn->Add(new Choice(dev->T("Current")))->OnClick.Handle(this, &JitCompareScreen::OnCurrentBlock); - leftColumn->Add(new Choice(dev->T("By Address")))->OnClick.Handle(this, &JitCompareScreen::OnSelectBlock); - leftColumn->Add(new Choice(dev->T("Prev")))->OnClick.Handle(this, &JitCompareScreen::OnPrevBlock); - leftColumn->Add(new Choice(dev->T("Next")))->OnClick.Handle(this, &JitCompareScreen::OnNextBlock); - leftColumn->Add(new Choice(dev->T("Random")))->OnClick.Handle(this, &JitCompareScreen::OnRandomBlock); - leftColumn->Add(new Choice(dev->T("FPU")))->OnClick.Handle(this, &JitCompareScreen::OnRandomFPUBlock); - leftColumn->Add(new Choice(dev->T("VFPU")))->OnClick.Handle(this, &JitCompareScreen::OnRandomVFPUBlock); - leftColumn->Add(new Choice(dev->T("Stats")))->OnClick.Handle(this, &JitCompareScreen::OnShowStats); - leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); - blockName_ = leftColumn->Add(new TextView(dev->T("No block"))); - blockAddr_ = leftColumn->Add(new TextEdit("", dev->T("Block address"), "", new LayoutParams(FILL_PARENT, WRAP_CONTENT))); - blockAddr_->OnTextChange.Handle(this, &JitCompareScreen::OnAddressChange); - blockStats_ = leftColumn->Add(new TextView("")); - - EventParams ignore{}; - OnCurrentBlock(ignore); -} - -void JitCompareScreen::UpdateDisasm() { - leftDisasm_->Clear(); - rightDisasm_->Clear(); - - using namespace UI; - - if (!MIPSComp::jit) { - return; - } - - JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface(); - - char temp[256]; - snprintf(temp, sizeof(temp), "%i/%i", currentBlock_, blockCacheDebug->GetNumBlocks()); - blockName_->SetText(temp); - - if (currentBlock_ < 0 || !blockCacheDebug || currentBlock_ >= blockCacheDebug->GetNumBlocks()) { - auto dev = GetI18NCategory(I18NCat::DEVELOPER); - leftDisasm_->Add(new TextView(dev->T("No block"))); - rightDisasm_->Add(new TextView(dev->T("No block"))); - blockStats_->SetText(""); - return; - } - - JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(currentBlock_); - - snprintf(temp, sizeof(temp), "%08x", debugInfo.originalAddress); - blockAddr_->SetText(temp); - - // Alright. First generate the MIPS disassembly. - - // TODO: Need a way to communicate branch continuing. - for (const auto &line : debugInfo.origDisasm) { - leftDisasm_->Add(new TextView(line))->SetFocusable(true); - } - - // TODO : When we have both target and IR, need a third column. - if (debugInfo.targetDisasm.size()) { - for (const auto &line : debugInfo.targetDisasm) { - rightDisasm_->Add(new TextView(line))->SetFocusable(true); - } - } else { - for (const auto &line : debugInfo.irDisasm) { - rightDisasm_->Add(new TextView(line))->SetFocusable(true); - } - } - - int numMips = leftDisasm_->GetNumSubviews(); - int numHost = rightDisasm_->GetNumSubviews(); - - snprintf(temp, sizeof(temp), "%d to %d : %d%%", numMips, numHost, 100 * numHost / numMips); - blockStats_->SetText(temp); -} - -UI::EventReturn JitCompareScreen::OnAddressChange(UI::EventParams &e) { - std::lock_guard guard(MIPSComp::jitLock); - if (!MIPSComp::jit) { - return UI::EVENT_DONE; - } - JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface(); - if (!blockCache) - return UI::EVENT_DONE; - u32 addr; - if (blockAddr_->GetText().size() > 8) - return UI::EVENT_DONE; - if (1 == sscanf(blockAddr_->GetText().c_str(), "%08x", &addr)) { - if (Memory::IsValidAddress(addr)) { - currentBlock_ = blockCache->GetBlockNumberFromStartAddress(addr); - UpdateDisasm(); - } - } - return UI::EVENT_DONE; -} - -UI::EventReturn JitCompareScreen::OnShowStats(UI::EventParams &e) { - std::lock_guard guard(MIPSComp::jitLock); - if (!MIPSComp::jit) { - return UI::EVENT_DONE; - } - - JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface(); - if (!blockCache) - return UI::EVENT_DONE; - - BlockCacheStats bcStats; - blockCache->ComputeStats(bcStats); - NOTICE_LOG(JIT, "Num blocks: %i", bcStats.numBlocks); - NOTICE_LOG(JIT, "Average Bloat: %0.2f%%", 100 * bcStats.avgBloat); - NOTICE_LOG(JIT, "Min Bloat: %0.2f%% (%08x)", 100 * bcStats.minBloat, bcStats.minBloatBlock); - NOTICE_LOG(JIT, "Max Bloat: %0.2f%% (%08x)", 100 * bcStats.maxBloat, bcStats.maxBloatBlock); - - int ctr = 0, sz = (int)bcStats.bloatMap.size(); - for (auto iter : bcStats.bloatMap) { - if (ctr < 10 || ctr > sz - 10) { - NOTICE_LOG(JIT, "%08x: %f", iter.second, iter.first); - } else if (ctr == 10) { - NOTICE_LOG(JIT, "..."); - } - ctr++; - } - return UI::EVENT_DONE; -} - - -UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) { - auto dev = GetI18NCategory(I18NCat::DEVELOPER); - - auto addressPrompt = new AddressPromptScreen(dev->T("Block address")); - addressPrompt->OnChoice.Handle(this, &JitCompareScreen::OnBlockAddress); - screenManager()->push(addressPrompt); - return UI::EVENT_DONE; -} - -UI::EventReturn JitCompareScreen::OnPrevBlock(UI::EventParams &e) { - currentBlock_--; - UpdateDisasm(); - return UI::EVENT_DONE; -} - -UI::EventReturn JitCompareScreen::OnNextBlock(UI::EventParams &e) { - currentBlock_++; - UpdateDisasm(); - return UI::EVENT_DONE; -} - -UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) { - std::lock_guard guard(MIPSComp::jitLock); - if (!MIPSComp::jit) { - return UI::EVENT_DONE; - } - - JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface(); - if (!blockCache) - return UI::EVENT_DONE; - - if (Memory::IsValidAddress(e.a)) { - currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a); - } else { - currentBlock_ = -1; - } - UpdateDisasm(); - return UI::EVENT_DONE; -} - -UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) { - std::lock_guard guard(MIPSComp::jitLock); - if (!MIPSComp::jit) { - return UI::EVENT_DONE; - } - - JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface(); - if (!blockCache) - return UI::EVENT_DONE; - - int numBlocks = blockCache->GetNumBlocks(); - if (numBlocks > 0) { - currentBlock_ = rand() % numBlocks; - } - UpdateDisasm(); - return UI::EVENT_DONE; -} - -UI::EventReturn JitCompareScreen::OnRandomVFPUBlock(UI::EventParams &e) { - OnRandomBlock(IS_VFPU); - return UI::EVENT_DONE; -} - -UI::EventReturn JitCompareScreen::OnRandomFPUBlock(UI::EventParams &e) { - OnRandomBlock(IS_FPU); - return UI::EVENT_DONE; -} - -void JitCompareScreen::OnRandomBlock(int flag) { - std::lock_guard guard(MIPSComp::jitLock); - if (!MIPSComp::jit) { - return; - } - JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface(); - if (!blockCache) - return; - - int numBlocks = blockCache->GetNumBlocks(); - if (numBlocks > 0) { - bool anyWanted = false; - int tries = 0; - while (!anyWanted && tries < numBlocks) { - currentBlock_ = rand() % numBlocks; - JitBlockDebugInfo b = blockCache->GetBlockDebugInfo(currentBlock_); - u32 mipsBytes = (u32)b.origDisasm.size() * 4; - for (u32 addr = b.originalAddress; addr < b.originalAddress + mipsBytes; addr += 4) { - MIPSOpcode opcode = Memory::Read_Instruction(addr); - if (MIPSGetInfo(opcode) & flag) { - char temp[256]; - MIPSDisAsm(opcode, addr, temp, sizeof(temp)); - // INFO_LOG(HLE, "Stopping at random instruction: %08x %s", addr, temp); - anyWanted = true; - break; - } - } - tries++; - } - - if (!anyWanted) - currentBlock_ = -1; - } - UpdateDisasm(); -} - -UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) { - std::lock_guard guard(MIPSComp::jitLock); - if (!MIPSComp::jit) { - return UI::EVENT_DONE; - } - JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache(); - if (!blockCache) - return UI::EVENT_DONE; - currentBlock_ = blockCache->GetBlockNumberFromAddress(currentMIPS->pc); - UpdateDisasm(); - return UI::EVENT_DONE; -} - int ShaderListScreen::ListShaders(DebugShaderType shaderType, UI::LinearLayout *view) { using namespace UI; std::vector shaderIds_ = gpu->DebugGetShaderIDs(shaderType); @@ -1357,6 +1010,16 @@ void ShaderViewScreen::CreateViews() { layout->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); } +bool ShaderViewScreen::key(const KeyInput &ki) { + if (ki.flags & KEY_CHAR) { + if (ki.unicodeChar == 'C' || ki.unicodeChar == 'c') { + System_CopyStringToClipboard(gpu->DebugGetShaderString(id_, type_, SHADER_STRING_SHORT_DESC)); + } + } + return UIDialogScreenWithBackground::key(ki); +} + + const std::string framedumpsBaseUrl = "http://framedump.ppsspp.org/repro/"; FrameDumpTestScreen::FrameDumpTestScreen() { @@ -1399,7 +1062,7 @@ void FrameDumpTestScreen::CreateViews() { UI::EventReturn FrameDumpTestScreen::OnLoadDump(UI::EventParams ¶ms) { std::string url = params.v->Tag(); - INFO_LOG(COMMON, "Trying to launch '%s'", url.c_str()); + INFO_LOG(Log::Common, "Trying to launch '%s'", url.c_str()); // Our disc streaming functionality detects the URL and takes over and handles loading framedumps well, // except for some reason the game ID. // TODO: Fix that since it can be important for compat settings. @@ -1431,7 +1094,7 @@ void FrameDumpTestScreen::update() { if (offset != std::string::npos) { trimmed = trimmed.substr(0, offset); if (endsWith(trimmed, ".ppdmp")) { - INFO_LOG(COMMON, "Found ppdmp: '%s'", trimmed.c_str()); + INFO_LOG(Log::Common, "Found ppdmp: '%s'", trimmed.c_str()); files_.push_back(trimmed); } } @@ -1451,7 +1114,7 @@ void TouchTestScreen::touch(const TouchInput &touch) { bool found = false; for (int i = 0; i < MAX_TOUCH_POINTS; i++) { if (touches_[i].id == touch.id) { - WARN_LOG(SYSTEM, "Double touch"); + WARN_LOG(Log::System, "Double touch"); touches_[i].x = touch.x; touches_[i].y = touch.y; found = true; @@ -1478,7 +1141,7 @@ void TouchTestScreen::touch(const TouchInput &touch) { } } if (!found) { - WARN_LOG(SYSTEM, "Move without touch down: %d", touch.id); + WARN_LOG(Log::System, "Move without touch down: %d", touch.id); } } if (touch.flags & TOUCH_UP) { @@ -1491,7 +1154,7 @@ void TouchTestScreen::touch(const TouchInput &touch) { } } if (!found) { - WARN_LOG(SYSTEM, "Touch release without touch down"); + WARN_LOG(Log::System, "Touch release without touch down"); } } } @@ -1505,6 +1168,7 @@ void TouchTestScreen::CreateViews() { root_ = new LinearLayout(ORIENT_VERTICAL); LinearLayout *theTwo = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)); + // TODO: This one should use DYNAMIC_ASCII. Though doesn't matter much. lastKeyEvents_ = theTwo->Add(new TextView("-", new LayoutParams(FILL_PARENT, WRAP_CONTENT))); root_->Add(theTwo); @@ -1612,7 +1276,7 @@ void TouchTestScreen::DrawForeground(UIContext &dc) { "g_dpi_scale_real: %0.3fx%0.3f\n" "delta: %0.2f ms fps: %0.3f\n%s", #if PPSSPP_PLATFORM(ANDROID) - System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES), + (int)System_GetPropertyInt(SYSPROP_DISPLAY_XRES), (int)System_GetPropertyInt(SYSPROP_DISPLAY_YRES), #endif g_display.dp_xres, g_display.dp_yres, g_display.pixel_xres, g_display.pixel_yres, g_display.dpi, g_display.dpi_scale_x, g_display.dpi_scale_y, @@ -1621,7 +1285,6 @@ void TouchTestScreen::DrawForeground(UIContext &dc) { extra_debug); // On Android, also add joystick debug data. - dc.DrawTextShadow(buffer, bounds.centerX(), bounds.y + 20.0f, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII); dc.Flush(); } @@ -1629,9 +1292,9 @@ void TouchTestScreen::DrawForeground(UIContext &dc) { void RecreateActivity() { const int SYSTEM_JELLYBEAN = 16; if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= SYSTEM_JELLYBEAN) { - INFO_LOG(SYSTEM, "Sending recreate"); + INFO_LOG(Log::System, "Sending recreate"); System_Notify(SystemNotification::FORCE_RECREATE_ACTIVITY); - INFO_LOG(SYSTEM, "Got back from recreate"); + INFO_LOG(Log::System, "Got back from recreate"); } else { auto gr = GetI18NCategory(I18NCat::GRAPHICS); System_Toast(gr->T_cstr("Must Restart", "You must restart PPSSPP for this change to take effect")); diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 0321aab1a3..ef9965ba4d 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -117,63 +117,13 @@ protected: void CreateInternalsTab(UI::ViewGroup *internals); }; -class AddressPromptScreen : public PopupScreen { +class GPIGPOScreen : public PopupScreen { public: - AddressPromptScreen(std::string_view title) : PopupScreen(title, "OK", "Cancel"), addrView_(NULL), addr_(0) { - memset(buttons_, 0, sizeof(buttons_)); - } - - const char *tag() const override { return "AddressPrompt"; } - - bool key(const KeyInput &key) override; - - UI::Event OnChoice; + GPIGPOScreen(std::string_view title) : PopupScreen(title, "OK") {} + const char *tag() const override { return "GPIGPO"; } protected: void CreatePopupContents(UI::ViewGroup *parent) override; - void OnCompleted(DialogResult result) override; - UI::EventReturn OnDigitButton(UI::EventParams &e); - UI::EventReturn OnBackspace(UI::EventParams &e); - -private: - void AddDigit(int n); - void BackspaceDigit(); - void UpdatePreviewDigits(); - - UI::TextView *addrView_; - UI::Button *buttons_[16]; - unsigned int addr_; -}; - -class JitCompareScreen : public UIDialogScreenWithBackground { -public: - void CreateViews() override; - - const char *tag() const override { return "JitCompare"; } - -private: - void UpdateDisasm(); - UI::EventReturn OnRandomBlock(UI::EventParams &e); - UI::EventReturn OnRandomFPUBlock(UI::EventParams &e); - UI::EventReturn OnRandomVFPUBlock(UI::EventParams &e); - void OnRandomBlock(int flag); - - UI::EventReturn OnCurrentBlock(UI::EventParams &e); - UI::EventReturn OnSelectBlock(UI::EventParams &e); - UI::EventReturn OnPrevBlock(UI::EventParams &e); - UI::EventReturn OnNextBlock(UI::EventParams &e); - UI::EventReturn OnBlockAddress(UI::EventParams &e); - UI::EventReturn OnAddressChange(UI::EventParams &e); - UI::EventReturn OnShowStats(UI::EventParams &e); - - int currentBlock_ = -1; - - UI::TextView *blockName_; - UI::TextEdit *blockAddr_; - UI::TextView *blockStats_; - - UI::LinearLayout *leftDisasm_; - UI::LinearLayout *rightDisasm_; }; class ShaderListScreen : public UIDialogScreenWithBackground { @@ -196,6 +146,7 @@ public: : id_(id), type_(type) {} void CreateViews() override; + bool key(const KeyInput &ki) override; const char *tag() const override { return "ShaderView"; } @@ -264,6 +215,5 @@ protected: }; void DrawProfile(UIContext &ui); -const char *GetCompilerABI(); void AddOverlayList(UI::ViewGroup *items, ScreenManager *screenManager); diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index b0e58d54f5..748547c2a0 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -35,13 +35,13 @@ static const char *ppsspp_app_id = "423397985041383434"; #ifdef ENABLE_DISCORD // No context argument? What? static void handleDiscordError(int errCode, const char *message) { - ERROR_LOG(SYSTEM, "Discord error code %d: '%s'", errCode, message); + ERROR_LOG(Log::System, "Discord error code %d: '%s'", errCode, message); } #endif Discord::~Discord() { if (initialized_) { - ERROR_LOG(SYSTEM, "Discord destructor running though g_Discord.Shutdown() has not been called."); + ERROR_LOG(Log::System, "Discord destructor running though g_Discord.Shutdown() has not been called."); } } @@ -57,7 +57,7 @@ void Discord::Init() { DiscordEventHandlers eventHandlers{}; eventHandlers.errored = &handleDiscordError; Discord_Initialize(ppsspp_app_id, &eventHandlers, 0, nullptr); - INFO_LOG(SYSTEM, "Discord connection initialized"); + INFO_LOG(Log::System, "Discord connection initialized"); #endif initialized_ = true; diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index a1920f9897..261bbe29b9 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -172,7 +172,7 @@ static std::string PostShaderTranslateName(std::string_view value) { const ShaderInfo *info = GetPostShaderInfo(value); if (info) { auto ps = GetI18NCategory(I18NCat::POSTSHADERS); - return std::string(ps->T(value, info ? info->name : value)); + return std::string(ps->T(value, info->name)); } else { return std::string(value); } @@ -274,6 +274,7 @@ void DisplayLayoutScreen::CreateViews() { rotation->SetEnabledFunc([] { return !g_Config.bSkipBufferEffects || g_Config.bSoftwareRendering; }); + rotation->SetHideTitle(true); rightColumn->Add(rotation); Choice *center = new Choice(di->T("Reset")); diff --git a/UI/DriverManagerScreen.cpp b/UI/DriverManagerScreen.cpp index 0e93ac3ebb..5b810f5304 100644 --- a/UI/DriverManagerScreen.cpp +++ b/UI/DriverManagerScreen.cpp @@ -191,7 +191,7 @@ UI::EventReturn DriverManagerScreen::OnCustomDriverChange(UI::EventParams &e) { screenManager()->push(new PromptScreen(gamePath_, di->T("Changing this setting requires PPSSPP to restart."), di->T("Restart"), di->T("Cancel"), [=](bool yes) { if (yes) { - INFO_LOG(G3D, "Switching driver to '%s'", e.s.c_str()); + INFO_LOG(Log::G3D, "Switching driver to '%s'", e.s.c_str()); g_Config.sCustomDriver = e.s; TriggerRestart("GameSettingsScreen::CustomDriverYes", false, gamePath_); } @@ -203,7 +203,7 @@ UI::EventReturn DriverManagerScreen::OnCustomDriverUninstall(UI::EventParams &e) if (e.s.empty()) { return UI::EVENT_DONE; } - INFO_LOG(G3D, "Uninstalling driver: %s", e.s.c_str()); + INFO_LOG(Log::G3D, "Uninstalling driver: %s", e.s.c_str()); Path folder = GetDriverPath() / e.s; File::DeleteDirRecursively(folder); @@ -230,7 +230,7 @@ UI::EventReturn DriverManagerScreen::OnCustomDriverInstall(UI::EventParams &e) { std::unique_ptr zipFileReader = std::unique_ptr(ZipFileReader::Create(zipPath, "", true)); if (!zipFileReader) { g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver", "couldn't open zip")); - ERROR_LOG(SYSTEM, "Failed to open file '%s' as zip", zipPath.c_str()); + ERROR_LOG(Log::System, "Failed to open file '%s' as zip", zipPath.c_str()); return; } @@ -251,7 +251,7 @@ UI::EventReturn DriverManagerScreen::OnCustomDriverInstall(UI::EventParams &e) { delete[] metaData; const Path newCustomDriver = GetDriverPath() / meta.name; - NOTICE_LOG(G3D, "Installing driver into '%s'", newCustomDriver.c_str()); + NOTICE_LOG(Log::G3D, "Installing driver into '%s'", newCustomDriver.c_str()); File::CreateFullPath(newCustomDriver); std::vector zipListing; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 0f79c36663..bb352c8b81 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -67,6 +67,7 @@ using namespace std::placeholders; #if !PPSSPP_PLATFORM(UWP) #include "GPU/Vulkan/DebugVisVulkan.h" #endif +#include "Core/MIPS/MIPS.h" #include "Core/HLE/sceCtrl.h" #include "Core/HLE/sceSas.h" #include "Core/Debugger/SymbolMap.h" @@ -254,7 +255,7 @@ void EmuScreen::bootGame(const Path &filename) { invalid_ = !PSP_IsInited(); if (invalid_) { errorMessage_ = error_string; - ERROR_LOG(BOOT, "isIniting bootGame error: %s", errorMessage_.c_str()); + ERROR_LOG(Log::Boot, "isIniting bootGame error: %s", errorMessage_.c_str()); return; } bootComplete(); @@ -283,7 +284,7 @@ void EmuScreen::bootGame(const Path &filename) { if (!File::Exists(filename / INDEX_FILENAME)) { g_OSD.Show(OSDType::MESSAGE_CENTERED_WARNING, sc->T("ExtractedIsoWarning", "Extracted ISOs often don't work.\nPlay the ISO file directly."), gamePath_.ToVisualString(), 7.0f); } else { - INFO_LOG(LOADER, "Extracted ISO loaded without warning - %s is present.", INDEX_FILENAME.c_str()); + INFO_LOG(Log::Loader, "Extracted ISO loaded without warning - %s is present.", INDEX_FILENAME.c_str()); } } @@ -348,7 +349,7 @@ void EmuScreen::bootGame(const Path &filename) { bootPending_ = false; invalid_ = true; errorMessage_ = error_string; - ERROR_LOG(BOOT, "InitStart bootGame error: %s", errorMessage_.c_str()); + ERROR_LOG(Log::Boot, "InitStart bootGame error: %s", errorMessage_.c_str()); } if (PSP_CoreParameter().compat.flags().RequireBufferedRendering && g_Config.bSkipBufferEffects) { @@ -356,7 +357,7 @@ void EmuScreen::bootGame(const Path &filename) { g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 10.0f); } - if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.iSkipGPUReadbackMode != (int)SkipGPUReadbackMode::NO_SKIP) { + if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.iSkipGPUReadbackMode != (int)SkipGPUReadbackMode::NO_SKIP && !PSP_CoreParameter().compat.flags().ForceEnableGPUReadback) { auto gr = GetI18NCategory(I18NCat::GRAPHICS); g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("BlockTransferRequired", "Warning: This game requires Skip GPU Readbacks be set to No."), 10.0f); } @@ -381,7 +382,7 @@ void EmuScreen::bootComplete() { System_Notify(SystemNotification::BOOT_DONE); System_Notify(SystemNotification::DISASSEMBLY); - NOTICE_LOG(BOOT, "Booted %s...", PSP_CoreParameter().fileToStart.c_str()); + NOTICE_LOG(Log::Boot, "Booted %s...", PSP_CoreParameter().fileToStart.c_str()); if (!Achievements::HardcoreModeActive()) { // Don't auto-load savestates in hardcore mode. autoLoad(); @@ -531,12 +532,17 @@ void EmuScreen::sendMessage(UIMessage message, const char *value) { std::string resetError; if (!PSP_InitStart(PSP_CoreParameter(), &resetError)) { - ERROR_LOG(LOADER, "Error resetting: %s", resetError.c_str()); + ERROR_LOG(Log::Loader, "Error resetting: %s", resetError.c_str()); stopRender_ = true; screenManager()->switchScreen(new MainScreen()); return; } } else if (message == UIMessage::REQUEST_GAME_BOOT) { + // TODO: Ignore or not if it's the same game that's already running? + if (gamePath_ == Path(value)) { + WARN_LOG(Log::Loader, "Game already running, ignoring"); + return; + } const char *ext = strrchr(value, '.'); if (ext != nullptr && !strcmp(ext, ".ppst")) { SaveState::Load(Path(value), -1, &AfterStateBoot); @@ -1270,7 +1276,7 @@ bool EmuScreen::checkPowerDown() { if (PSP_IsInited()) { PSP_Shutdown(); } - INFO_LOG(SYSTEM, "SELF-POWERDOWN!"); + INFO_LOG(Log::System, "SELF-POWERDOWN!"); screenManager()->switchScreen(new MainScreen()); bootPending_ = false; invalid_ = true; @@ -1279,17 +1285,25 @@ bool EmuScreen::checkPowerDown() { return false; } -bool EmuScreen::canBeBackground(bool isTop) const { - if (g_Config.bSkipBufferEffects) { - return isTop || (g_Config.bTransparentBackground && Core_ShouldRunBehind()); - } +ScreenRenderRole EmuScreen::renderRole(bool isTop) const { + auto CanBeBackground = [&]() -> bool { + if (g_Config.bSkipBufferEffects) { + return isTop || (g_Config.bTransparentBackground && Core_ShouldRunBehind()); + } - if (!g_Config.bTransparentBackground && !isTop) { - if (Core_ShouldRunBehind() || screenManager()->topScreen()->wantBrightBackground()) - return true; - return false; + if (!g_Config.bTransparentBackground && !isTop) { + if (Core_ShouldRunBehind() || screenManager()->topScreen()->wantBrightBackground()) + return true; + return false; + } + return true; + }; + + ScreenRenderRole role = ScreenRenderRole::MUST_BE_FIRST; + if (CanBeBackground()) { + role |= ScreenRenderRole::CAN_BE_BACKGROUND; } - return true; + return role; } void EmuScreen::darken() { @@ -1313,6 +1327,12 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { return flags; // shouldn't really happen but I've seen a suspicious stack trace.. } + // Sanity check +#ifdef _DEBUG + Draw::BackendState state = draw->GetCurrentBackendState(); + _dbg_assert_(!state.valid || state.passes == 0); +#endif + GamepadUpdateOpacity(); bool skipBufferEffects = g_Config.bSkipBufferEffects; @@ -1329,7 +1349,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { // We only bind it in FramebufferManager::CopyDisplayToOutput (unless non-buffered)... // We do, however, start the frame in other ways. - if ((skipBufferEffects && !g_Config.bSoftwareRendering) || Core_IsStepping()) { + if (skipBufferEffects && !g_Config.bSoftwareRendering) { // We need to clear here already so that drawing during the frame is done on a clean slate. if (Core_IsStepping() && gpuStats.numFlips != 0) { draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_BackBuffer"); @@ -1395,7 +1415,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { } else if (PSP_CoreParameter().frozen) { std::string errorString; if (CChunkFileReader::ERROR_NONE != SaveState::LoadFromRam(freezeState_, &errorString)) { - ERROR_LOG(SAVESTATE, "Failed to load freeze state (%s). Unfreezing.", errorString.c_str()); + ERROR_LOG(Log::SaveState, "Failed to load freeze state (%s). Unfreezing.", errorString.c_str()); PSP_CoreParameter().frozen = false; } } @@ -1431,13 +1451,11 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { } else { // If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output. // This won't work in non-buffered, but that's fine. - draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_Stepping"); - framebufferBound = true; - // Just to make sure. - if (PSP_IsInited()) { - _dbg_assert_(gpu); + if (!framebufferBound && PSP_IsInited()) { + // draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_Stepping"); gpu->CopyDisplayToOutput(true); } + framebufferBound = true; } break; } @@ -1449,6 +1467,10 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { break; } + if (framebufferBound && gpu) { + gpu->PresentedThisFrame(); + } + PSP_EndHostFrame(); // This place rougly matches how libretro handles it (after retro_frame). @@ -1507,6 +1529,8 @@ bool EmuScreen::hasVisibleUI() { return true; if (g_Config.bEnableCardboardVR || g_Config.bEnableNetworkChat) return true; + if (g_Config.bShowGPOLEDs) + return true; // Debug UI. if ((DebugOverlay)g_Config.iDebugOverlay != DebugOverlay::OFF || g_Config.bShowDeveloperMenu) return true; @@ -1557,6 +1581,26 @@ void EmuScreen::renderUI() { } #endif + if (g_Config.bShowGPOLEDs) { + // Draw a vertical strip of LEDs at the right side of the screen. + const float ledSize = 24.0f; + const float spacing = 4.0f; + const float height = 8 * ledSize + 7 * spacing; + const float x = ctx->GetBounds().w - spacing - ledSize; + const float y = (ctx->GetBounds().h - height) * 0.5f; + ctx->FillRect(UI::Drawable(0xFF000000), Bounds(x - spacing, y - spacing, ledSize + spacing * 2, height + spacing * 2)); + for (int i = 0; i < 8; i++) { + int bit = (g_GPOBits >> i) & 1; + uint32_t color = 0xFF30FF30; + if (!bit) { + color = darkenColor(darkenColor(color)); + } + Bounds ledBounds(x, y + (spacing + ledSize) * i, ledSize, ledSize); + ctx->FillRect(UI::Drawable(color), ledBounds); + } + ctx->Flush(); + } + if (coreState == CORE_RUNTIME_ERROR || coreState == CORE_STEPPING) { const MIPSExceptionInfo &info = Core_GetExceptionInfo(); if (info.type != MIPSExceptionType::NONE) { diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 50157a6002..77df9e3816 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -46,7 +46,7 @@ public: void dialogFinished(const Screen *dialog, DialogResult result) override; void sendMessage(UIMessage message, const char *value) override; void resized() override; - bool canBeBackground(bool isTop) const override; + ScreenRenderRole renderRole(bool isTop) const override; // Note: Unlike your average boring UIScreen, here we override the Unsync* functions // to get minimal latency and full control. We forward to UIScreen when needed. diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 326383dd1d..694a28bb13 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -473,9 +473,9 @@ void GPUDriverTestScreen::DiscardTest(UIContext &dc) { std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME); std::string vendor = screenManager()->getDrawContext()->GetInfoString(InfoField::VENDORSTRING); std::string driver = screenManager()->getDrawContext()->GetInfoString(InfoField::DRIVER); - dc.DrawText(apiName.c_str(), layoutBounds.centerX(), 20, 0xFFFFFFFF, ALIGN_CENTER); - dc.DrawText(vendor.c_str(), layoutBounds.centerX(), 60, 0xFFFFFFFF, ALIGN_CENTER); - dc.DrawText(driver.c_str(), layoutBounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER); + dc.DrawText(apiName, layoutBounds.centerX(), 20, 0xFFFFFFFF, ALIGN_CENTER); + dc.DrawText(vendor, layoutBounds.centerX(), 60, 0xFFFFFFFF, ALIGN_CENTER); + dc.DrawText(driver, layoutBounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER); dc.Flush(); float testW = 170.f; @@ -579,9 +579,9 @@ void GPUDriverTestScreen::ShaderTest(UIContext &dc) { std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME); std::string vendor = screenManager()->getDrawContext()->GetInfoString(InfoField::VENDORSTRING); std::string driver = screenManager()->getDrawContext()->GetInfoString(InfoField::DRIVER); - dc.DrawText(apiName.c_str(), layoutBounds.centerX(), 20, 0xFFFFFFFF, ALIGN_CENTER); - dc.DrawText(vendor.c_str(), layoutBounds.centerX(), 60, 0xFFFFFFFF, ALIGN_CENTER); - dc.DrawText(driver.c_str(), layoutBounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER); + dc.DrawText(apiName, layoutBounds.centerX(), 20, 0xFFFFFFFF, ALIGN_CENTER); + dc.DrawText(vendor, layoutBounds.centerX(), 60, 0xFFFFFFFF, ALIGN_CENTER); + dc.DrawText(driver, layoutBounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER); dc.Flush(); float y = layoutBounds.y + 150; @@ -616,7 +616,7 @@ void GPUDriverTestScreen::ShaderTest(UIContext &dc) { // Draw rectangle that should be flat shaded dc.BeginPipeline(flatShadingPipeline_, samplerNearest_); // There is a "provoking vertex" difference here between GL and Vulkan when using flat shading. One gets one color, one gets the other. - // Wherever possible we should reconfigure the GL provoking vertex to match Vulkan, probably. + // However, we now use the VK_EXT_provoking_vertex extension to make it match up (and match with the PSP). dc.DrawImageVGradient(ImageID("I_ICON"), 0xFFFFFFFF, 0xFF808080, bounds); dc.Flush(); diff --git a/UI/GPUDriverTestScreen.h b/UI/GPUDriverTestScreen.h index 5c8b67cfa4..6f27f855be 100644 --- a/UI/GPUDriverTestScreen.h +++ b/UI/GPUDriverTestScreen.h @@ -5,7 +5,7 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" -#include "Common/LogManager.h" +#include "Common/Log.h" #include "UI/MiscScreens.h" #include "Common/GPU/thin3d.h" diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 26bbccf1ae..00b4e13cdd 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -33,6 +33,7 @@ #include "Core/FileSystems/ISOFileSystem.h" #include "Core/FileSystems/DirectoryFileSystem.h" #include "Core/FileSystems/VirtualDiscFileSystem.h" +#include "Core/HLE/sceUtility.h" #include "Core/ELF/PBPReader.h" #include "Core/SaveState.h" #include "Core/System.h" @@ -52,6 +53,7 @@ void GameInfoTex::Clear() { texture->Release(); texture = nullptr; } + timeLoaded = 0.0; } GameInfo::GameInfo(const Path &gamePath) : filePath_(gamePath) { @@ -75,7 +77,7 @@ bool GameInfo::Delete() { { // Just delete the one file (TODO: handle two-disk games as well somehow). Path fileToRemove = filePath_; - INFO_LOG(SYSTEM, "Deleting file %s", fileToRemove.c_str()); + INFO_LOG(Log::System, "Deleting file %s", fileToRemove.c_str()); File::Delete(fileToRemove); g_Config.RemoveRecent(filePath_.ToString()); return true; @@ -85,9 +87,9 @@ bool GameInfo::Delete() { { // TODO: This could be handled by Core/Util/GameManager too somehow. Path directoryToRemove = ResolvePBPDirectory(filePath_); - INFO_LOG(SYSTEM, "Deleting directory %s", directoryToRemove.c_str()); + INFO_LOG(Log::System, "Deleting directory %s", directoryToRemove.c_str()); if (!File::DeleteDirRecursively(directoryToRemove)) { - ERROR_LOG(SYSTEM, "Failed to delete file"); + ERROR_LOG(Log::System, "Failed to delete file"); return false; } g_Config.CleanRecent(); @@ -103,7 +105,7 @@ bool GameInfo::Delete() { case IdentifiedFileType::PPSSPP_GE_DUMP: { const Path &fileToRemove = filePath_; - INFO_LOG(SYSTEM, "Deleting file %s", fileToRemove.c_str()); + INFO_LOG(Log::System, "Deleting file %s", fileToRemove.c_str()); File::Delete(fileToRemove); g_Config.RemoveRecent(filePath_.ToString()); return true; @@ -112,7 +114,7 @@ bool GameInfo::Delete() { case IdentifiedFileType::PPSSPP_SAVESTATE: { const Path &ppstPath = filePath_; - INFO_LOG(SYSTEM, "Deleting file %s", ppstPath.c_str()); + INFO_LOG(Log::System, "Deleting file %s", ppstPath.c_str()); File::Delete(ppstPath); const Path screenshotPath = filePath_.WithReplacedExtension(".ppst", ".jpg"); if (File::Exists(screenshotPath)) { @@ -122,12 +124,12 @@ bool GameInfo::Delete() { } default: - INFO_LOG(SYSTEM, "Don't know how to delete this type of file: %s", filePath_.c_str()); + INFO_LOG(Log::System, "Don't know how to delete this type of file: %s", filePath_.c_str()); return false; } } -u64 GameInfo::GetGameSizeOnDiskInBytes() { +u64 GameInfo::GetSizeOnDiskInBytes() { switch (fileType) { case IdentifiedFileType::PSP_PBP_DIRECTORY: case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: @@ -139,7 +141,7 @@ u64 GameInfo::GetGameSizeOnDiskInBytes() { } } -u64 GameInfo::GetGameSizeUncompressedInBytes() { +u64 GameInfo::GetSizeUncompressedInBytes() { switch (fileType) { case IdentifiedFileType::PSP_PBP_DIRECTORY: case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: @@ -160,6 +162,39 @@ u64 GameInfo::GetGameSizeUncompressedInBytes() { } } +std::string GetFileDateAsString(const Path &filename) { + tm time; + if (File::GetModifTime(filename, time)) { + char buf[256]; + switch (g_Config.iDateFormat) { + case PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD: + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &time); + break; + case PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY: + strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &time); + break; + case PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY: + strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", &time); + break; + default: // Should never happen + return ""; + } + return std::string(buf); + } + return ""; +} + +std::string GameInfo::GetMTime() const { + switch (fileType) { + case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: + return GetFileDateAsString(GetFilePath() / "PARAM.SFO"); + case IdentifiedFileType::PSP_PBP_DIRECTORY: + return GetFileDateAsString(GetFilePath() / "EBOOT.PBP"); + default: + return GetFileDateAsString(GetFilePath()); + } +} + // Not too meaningful if the object itself is a savedata directory... // Call this under lock. std::vector GameInfo::GetSaveDataDirectories() { @@ -182,7 +217,7 @@ std::vector GameInfo::GetSaveDataDirectories() { return directories; } -u64 GameInfo::GetSaveDataSizeInBytes() { +u64 GameInfo::GetGameSavedataSizeInBytes() { if (fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY || fileType == IdentifiedFileType::PPSSPP_SAVESTATE) { return 0; } @@ -357,7 +392,7 @@ void GameInfo::SetupTexture(Draw::DrawContext *thin3d, GameInfoTex &tex) { tex.texture = CreateTextureFromFileData(thin3d, (const uint8_t *)tex.data.data(), tex.data.size(), ImageFileType::DETECT, false, GetTitle().c_str()); tex.timeLoaded = time_now_d(); if (!tex.texture) { - ERROR_LOG(G3D, "Failed creating texture (%s) from %d-byte file", GetTitle().c_str(), tex.data.size()); + ERROR_LOG(Log::G3D, "Failed creating texture (%s) from %d-byte file", GetTitle().c_str(), (int)tex.data.size()); } } @@ -455,7 +490,7 @@ public: // Mark everything requested as done, so std::unique_lock lock(info_->lock); info_->MarkReadyNoLock(flags_); - ERROR_LOG(LOADER, "Failed getting game info."); + ERROR_LOG(Log::Loader, "Failed getting game info for %s", info_->GetFilePath().ToVisualString().c_str()); return; } @@ -465,6 +500,10 @@ public: info_->fileType = Identify_File(info_->GetFileLoader().get(), &errorString); } + if (!info_->Ready(GameInfoFlags::FILE_TYPE) && !(flags_ & GameInfoFlags::FILE_TYPE)) { + _dbg_assert_(false); + } + switch (info_->fileType) { case IdentifiedFileType::PSP_PBP: case IdentifiedFileType::PSP_PBP_DIRECTORY: @@ -482,7 +521,7 @@ public: if (pbp.IsELF()) { goto handleELF; } - ERROR_LOG(LOADER, "invalid pbp '%s'\n", pbpLoader->GetPath().c_str()); + ERROR_LOG(Log::Loader, "invalid pbp '%s'\n", pbpLoader->GetPath().c_str()); return; } @@ -575,7 +614,7 @@ handleELF: ReadLocalFileToString(screenshot_jpg, &info_->icon.data, &info_->lock); } else { // Read standard icon - VERBOSE_LOG(LOADER, "Loading unknown.png because there was an ELF"); + VERBOSE_LOG(Log::Loader, "Loading unknown.png because there was an ELF"); ReadVFSToString("unknown.png", &info_->icon.data, &info_->lock); } info_->icon.dataLoaded = true; @@ -622,7 +661,7 @@ handleELF: if (ReadLocalFileToString(screenshotPath, &info_->icon.data, &info_->lock)) { info_->icon.dataLoaded = true; } else { - ERROR_LOG(G3D, "Error loading screenshot data: '%s'", screenshotPath.c_str()); + ERROR_LOG(Log::G3D, "Error loading screenshot data: '%s'", screenshotPath.c_str()); } } break; @@ -724,7 +763,7 @@ handleELF: else if (File::Exists(screenshot_jpg)) info_->icon.dataLoaded = ReadLocalFileToString(screenshot_jpg, &info_->icon.data, &info_->lock); else { - DEBUG_LOG(LOADER, "Loading unknown.png because no icon was found"); + DEBUG_LOG(Log::Loader, "Loading unknown.png because no icon was found"); info_->icon.dataLoaded = ReadVFSToString("unknown.png", &info_->icon.data, &info_->lock); } } else { @@ -767,18 +806,30 @@ handleELF: if (flags_ & GameInfoFlags::SIZE) { std::lock_guard lock(info_->lock); - info_->gameSizeOnDisk = info_->GetGameSizeOnDiskInBytes(); - info_->saveDataSize = info_->GetSaveDataSizeInBytes(); - info_->installDataSize = info_->GetInstallDataSizeInBytes(); + info_->gameSizeOnDisk = info_->GetSizeOnDiskInBytes(); + switch (info_->fileType) { + case IdentifiedFileType::PSP_ISO: + case IdentifiedFileType::PSP_ISO_NP: + case IdentifiedFileType::PSP_DISC_DIRECTORY: + case IdentifiedFileType::PSP_PBP: + case IdentifiedFileType::PSP_PBP_DIRECTORY: + info_->saveDataSize = info_->GetGameSavedataSizeInBytes(); + info_->installDataSize = info_->GetInstallDataSizeInBytes(); + break; + default: + info_->saveDataSize = 0; + info_->installDataSize = 0; + break; + } } if (flags_ & GameInfoFlags::UNCOMPRESSED_SIZE) { - info_->gameSizeUncompressed = info_->GetGameSizeUncompressedInBytes(); + info_->gameSizeUncompressed = info_->GetSizeUncompressedInBytes(); } // Time to update the flags. std::unique_lock lock(info_->lock); info_->MarkReadyNoLock(flags_); - // INFO_LOG(SYSTEM, "Completed writing info for %s", info_->GetTitle().c_str()); + // INFO_LOG(Log::System, "Completed writing info for %s", info_->GetTitle().c_str()); } private: @@ -865,7 +916,7 @@ void GameInfoCache::PurgeType(IdentifiedFileType fileType) { } // TODO: Find a better way to wait here. if (info->pendingFlags != (GameInfoFlags)0) { - INFO_LOG(LOADER, "%s: pending flags %08x, retrying", info->GetTitle().c_str(), (int)info->pendingFlags); + INFO_LOG(Log::Loader, "%s: pending flags %08x, retrying", info->GetTitle().c_str(), (int)info->pendingFlags); retry = true; break; } @@ -882,6 +933,8 @@ void GameInfoCache::PurgeType(IdentifiedFileType fileType) { std::shared_ptr GameInfoCache::GetInfo(Draw::DrawContext *draw, const Path &gamePath, GameInfoFlags wantFlags) { const std::string &pathStr = gamePath.ToString(); + // _dbg_assert_(gamePath != GetSysDirectory(DIRECTORY_SAVEDATA)); + // This is always needed to determine the method to get the other info, so make sure it's computed first. wantFlags |= GameInfoFlags::FILE_TYPE; diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 589882a3dd..ea50e3fd68 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -96,12 +96,20 @@ public: std::shared_ptr GetFileLoader(); void DisposeFileLoader(); - u64 GetGameSizeUncompressedInBytes(); // NOTE: More expensive than GetGameSizeOnDiskInBytes(). - u64 GetGameSizeOnDiskInBytes(); - u64 GetSaveDataSizeInBytes(); + u64 GetSizeUncompressedInBytes(); // NOTE: More expensive than GetGameSizeOnDiskInBytes(). + u64 GetSizeOnDiskInBytes(); + u64 GetGameSavedataSizeInBytes(); // For games u64 GetInstallDataSizeInBytes(); + // For various kinds of savedata, mainly. + // NOTE: This one actually performs I/O directly, not cached. + std::string GetMTime() const; + void ParseParamSFO(); + const ParamSFOData &GetParamSFO() const { + _dbg_assert_(hasFlags & GameInfoFlags::PARAM_SFO); + return paramSFO; + } void FinishPendingTextureLoads(Draw::DrawContext *draw); std::vector GetSaveDataDirectories(); @@ -109,6 +117,10 @@ public: std::string GetTitle(); void SetTitle(const std::string &newTitle); + const Path &GetFilePath() const { + return filePath_; + } + bool Ready(GameInfoFlags flags) { std::unique_lock guard(lock); // Avoid the operator, we want to check all the bits. @@ -148,7 +160,6 @@ public: int disc_number = 0; int region = -1; IdentifiedFileType fileType; - ParamSFOData paramSFO; bool hasConfig = false; // Pre read the data, create a texture the next time (GL thread..) @@ -167,6 +178,7 @@ public: u64 installDataSize = 0; protected: + ParamSFOData paramSFO; // Note: this can change while loading, use GetTitle(). std::string title; @@ -178,6 +190,7 @@ protected: private: DISALLOW_COPY_AND_ASSIGN(GameInfo); + friend class GameInfoWorkItem; }; class GameInfoCache { @@ -193,6 +206,7 @@ public: // but filled in later asynchronously in the background. So keep calling this, // redrawing the UI often. Only set flags to GAMEINFO_WANTBG or WANTSND if you really want them // because they're big. bgTextures and sound may be discarded over time as well. + // NOTE: This never returns null, so you don't need to check for that. Do check Ready() flags though. std::shared_ptr GetInfo(Draw::DrawContext *draw, const Path &gamePath, GameInfoFlags wantFlags); void FlushBGs(); // Gets rid of all BG textures. Also gets rid of bg sounds. diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index dacd879545..6aa5d10f82 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -30,6 +30,7 @@ #include "Common/File/FileUtil.h" #include "Common/StringUtils.h" #include "Common/System/System.h" +#include "Common/System/OSD.h" #include "Common/System/Request.h" #include "Common/System/NativeApp.h" #include "Core/Config.h" @@ -37,6 +38,7 @@ #include "Core/System.h" #include "Core/Loaders.h" #include "Core/Util/GameDB.h" +#include "Core/HLE/Plugins.h" #include "UI/OnScreenDisplay.h" #include "UI/CwCheatScreen.h" #include "UI/EmuScreen.h" @@ -80,6 +82,9 @@ void GameScreen::update() { CRC32string = int2hexstr(crcvalue); tvCRC_->SetVisibility(UI::V_VISIBLE); tvCRC_->SetText(CRC32string); + if (tvCRCCopy_) { + tvCRCCopy_->SetVisibility(UI::V_VISIBLE); + } if (btnCalcCRC_) { btnCalcCRC_->SetVisibility(UI::V_GONE); } @@ -144,12 +149,42 @@ void GameScreen::CreateViews() { tvPlayTime_ = infoLayout->Add(new TextView("", ALIGN_LEFT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); tvPlayTime_->SetShadow(true); tvPlayTime_->SetVisibility(V_GONE); - tvCRC_ = infoLayout->Add(new TextView("", ALIGN_LEFT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + + LinearLayout *crcHoriz = infoLayout->Add(new LinearLayout(ORIENT_HORIZONTAL)); + tvCRC_ = crcHoriz->Add(new TextView("", ALIGN_LEFT, true, new LinearLayoutParams(0.0, G_VCENTER))); tvCRC_->SetShadow(true); - tvCRC_->SetVisibility(Reporting::HasCRC(gamePath_) ? V_VISIBLE : V_GONE); + Visibility crcVisibility = Reporting::HasCRC(gamePath_) ? V_VISIBLE : V_GONE; + tvCRC_->SetVisibility(crcVisibility); + if (System_GetPropertyBool(SYSPROP_HAS_TEXT_CLIPBOARD)) { + tvCRCCopy_ = crcHoriz->Add(new Button(di->T("Copy to clipboard"), new LinearLayoutParams(0.0, G_VCENTER))); + tvCRCCopy_->OnClick.Add([this](UI::EventParams &) { + u32 crc = Reporting::RetrieveCRC(gamePath_); + char buffer[16]; + snprintf(buffer, sizeof(buffer), "%08X", crc); + System_CopyStringToClipboard(buffer); + // Success indication. Not worth a translatable string. + g_OSD.Show(OSDType::MESSAGE_SUCCESS, buffer, 1.0f); + return UI::EVENT_DONE; + }); + tvCRCCopy_->SetVisibility(crcVisibility); + tvCRCCopy_->SetScale(0.82f); + } else { + tvCRCCopy_ = nullptr; + } + tvVerified_ = infoLayout->Add(new NoticeView(NoticeLevel::INFO, ga->T("Click \"Calculate CRC\" to verify ISO"), "", new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); tvVerified_->SetVisibility(UI::V_GONE); tvVerified_->SetSquishy(true); + + // Show plugin info, if any. Later might add checkboxes. + auto plugins = HLEPlugins::FindPlugins(info->id, g_Config.sLanguageIni); + if (!plugins.empty()) { + auto sy = GetI18NCategory(I18NCat::SYSTEM); + infoLayout->Add(new TextView(sy->T("Plugins"), ALIGN_LEFT, true)); + for (const auto &plugin : plugins) { + infoLayout->Add(new TextView(ApplySafeSubstitutions("* %1", plugin.name), ALIGN_LEFT, true)); + } + } } else { tvTitle_ = nullptr; tvID_ = nullptr; @@ -159,6 +194,7 @@ void GameScreen::CreateViews() { tvRegion_ = nullptr; tvPlayTime_ = nullptr; tvCRC_ = nullptr; + tvCRCCopy_ = nullptr; tvVerified_ = nullptr; } @@ -349,6 +385,9 @@ ScreenRenderFlags GameScreen::render(ScreenRenderMode mode) { std::string crc = StringFromFormat("%08X", crcVal); tvCRC_->SetText(ReplaceAll(rp->T("FeedbackCRCValue", "Disc CRC: %1"), "%1", crc)); tvCRC_->SetVisibility(UI::V_VISIBLE); + if (tvCRCCopy_) { + tvCRCCopy_->SetVisibility(UI::V_VISIBLE); + } // Let's check the CRC in the game database, looking up the ID and also matching the crc. std::vector dbInfos; @@ -360,7 +399,7 @@ ScreenRenderFlags GameScreen::render(ScreenRenderMode mode) { } } if (found) { - tvVerified_->SetText(ga->T("ISO OK according to the Redump project")); + tvVerified_->SetText(ga->T("ISO OK according to the ReDump project")); tvVerified_->SetLevel(NoticeLevel::SUCCESS); tvVerified_->SetVisibility(UI::V_VISIBLE); } else { @@ -370,7 +409,7 @@ ScreenRenderFlags GameScreen::render(ScreenRenderMode mode) { tvVerified_->SetVisibility(UI::V_GONE); } } else if (tvVerified_) { - // tvVerified_->SetText(ga->T("Game ID unknown - not in the Redump database")); + // tvVerified_->SetText(ga->T("Game ID unknown - not in the ReDump database")); // tvVerified_->SetVisibility(UI::V_VISIBLE); // tvVerified_->SetLevel(NoticeLevel::WARN); tvVerified_->SetVisibility(UI::V_GONE); @@ -395,7 +434,7 @@ ScreenRenderFlags GameScreen::render(ScreenRenderMode mode) { // tvVerified_->SetText(ga->T("File size incorrect, bad or modified ISO")); // tvVerified_->SetVisibility(UI::V_VISIBLE); // tvVerified_->SetLevel(NoticeLevel::ERROR); - // INFO_LOG(LOADER, "File size %d not matching game DB", (int)info->gameSizeUncompressed); + // INFO_LOG(Log::Loader, "File size %d not matching game DB", (int)info->gameSizeUncompressed); } else { tvVerified_->SetText(ga->T("Click \"Calculate CRC\" to verify ISO")); tvVerified_->SetVisibility(UI::V_VISIBLE); @@ -464,7 +503,7 @@ UI::EventReturn GameScreen::OnPlay(UI::EventParams &e) { UI::EventReturn GameScreen::OnGameSettings(UI::EventParams &e) { std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GameInfoFlags::PARAM_SFO); if (info && info->Ready(GameInfoFlags::PARAM_SFO)) { - std::string discID = info->paramSFO.GetValueString("DISC_ID"); + std::string discID = info->GetParamSFO().GetValueString("DISC_ID"); if ((discID.empty() || !info->disc_total) && gamePath_.FilePathContainsNoCase("PSP/GAME/")) discID = g_paramSFO.GenerateFakeID(gamePath_); screenManager()->push(new GameSettingsScreen(gamePath_, discID, true)); @@ -502,8 +541,11 @@ UI::EventReturn GameScreen::OnDeleteGame(UI::EventParams &e) { if (info->Ready(GameInfoFlags::PARAM_SFO)) { auto di = GetI18NCategory(I18NCat::DIALOG); auto ga = GetI18NCategory(I18NCat::GAME); + std::string prompt; + prompt = di->T("DeleteConfirmGame", "Do you really want to delete this game\nfrom your device? You can't undo this."); + prompt += "\n\n" + gamePath_.ToVisualString(g_Config.memStickDirectory.c_str()); screenManager()->push( - new PromptScreen(gamePath_, di->T("DeleteConfirmGame", "Do you really want to delete this game\nfrom your device? You can't undo this."), ga->T("ConfirmDelete"), di->T("Cancel"), + new PromptScreen(gamePath_, prompt, ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GameScreen::CallbackDeleteGame, this, std::placeholders::_1))); } return UI::EVENT_DONE; diff --git a/UI/GameScreen.h b/UI/GameScreen.h index b8fd92fe78..5638eb33c6 100644 --- a/UI/GameScreen.h +++ b/UI/GameScreen.h @@ -75,6 +75,7 @@ private: UI::TextView *tvPlayTime_ = nullptr; UI::TextView *tvCRC_ = nullptr; UI::TextView *tvID_ = nullptr; + UI::Button *tvCRCCopy_ = nullptr; NoticeView *tvVerified_ = nullptr; UI::Choice *btnGameSettings_ = nullptr; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 5d2ba62883..2545438e71 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -79,6 +79,9 @@ #include "GPU/GPUInterface.h" #include "GPU/Common/FramebufferManagerCommon.h" +#include "Core/Core.h" // for Core_IsStepping +#include "Core/MIPS/MIPSTracer.h" + #if PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) #include "UI/DarwinFileSystemServices.h" #endif @@ -163,7 +166,7 @@ static std::string TextureTranslateName(std::string_view value) { const TextureShaderInfo *info = GetTextureShaderInfo(value); if (info) { auto ts = GetI18NCategory(I18NCat::TEXTURESHADERS); - return std::string(ts->T(value, info ? info->name.c_str() : value)); + return std::string(ts->T(value, info->name.c_str())); } else { return std::string(value); } @@ -210,7 +213,7 @@ static std::string PostShaderTranslateName(std::string_view value) { const ShaderInfo *info = GetPostShaderInfo(value); if (info) { auto ps = GetI18NCategory(I18NCat::POSTSHADERS); - return std::string(ps->T(value, info ? info->name : value)); + return std::string(ps->T(value, info->name)); } else { return std::string(value); } @@ -254,7 +257,7 @@ void GameSettingsScreen::CreateTabs() { CreateSystemSettings(systemSettings); int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE); - if (deviceType == DEVICE_TYPE_VR) { + if ((deviceType == DEVICE_TYPE_VR) || g_Config.bForceVR) { LinearLayout *vrSettings = AddTab("GameSettingsVR", ms->T("VR")); CreateVRSettings(vrSettings); } @@ -392,7 +395,7 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) } #endif // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. - displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display Layout && Effects"))); + displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout & effects"))); displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { screenManager()->push(new DisplayLayoutScreen(gamePath_)); return UI::EVENT_DONE; @@ -476,7 +479,7 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) } if (GetGPUBackend() == GPUBackend::VULKAN) { - const bool usable = !draw->GetBugs().Has(Draw::Bugs::GEOMETRY_SHADERS_SLOW_OR_BROKEN); + const bool usable = draw->GetDeviceCaps().geometryShaderSupported && !draw->GetBugs().Has(Draw::Bugs::GEOMETRY_SHADERS_SLOW_OR_BROKEN); const bool vertexSupported = draw->GetDeviceCaps().clipDistanceSupported && draw->GetDeviceCaps().cullDistanceSupported; if (usable && !vertexSupported) { CheckBox *geometryCulling = graphicsSettings->Add(new CheckBox(&g_Config.bUseGeometryShader, gr->T("Geometry shader culling"))); @@ -587,6 +590,9 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) graphicsSettings->Add(new ItemHeader(gr->T("Camera"))); PopupMultiChoiceDynamic *cameraChoice = graphicsSettings->Add(new PopupMultiChoiceDynamic(&g_Config.sCameraDevice, gr->T("Camera Device"), cameraList, I18NCat::NONE, screenManager())); cameraChoice->OnChoice.Handle(this, &GameSettingsScreen::OnCameraDeviceChange); +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) + graphicsSettings->Add(new CheckBox(&g_Config.bCameraMirrorHorizontal, gr->T("Mirror camera image"))); +#endif } graphicsSettings->Add(new ItemHeader(gr->T("Hack Settings", "Hack Settings (these WILL cause glitches)"))); @@ -615,6 +621,22 @@ void GameSettingsScreen::CreateAudioSettings(UI::ViewGroup *audioSettings) { audioSettings->Add(new ItemHeader(ms->T("Audio"))); CheckBox *enableSound = audioSettings->Add(new CheckBox(&g_Config.bEnableSound,a->T("Enable Sound"))); + +#if PPSSPP_PLATFORM(IOS) + CheckBox *respectSilentMode = audioSettings->Add(new CheckBox(&g_Config.bAudioRespectSilentMode, a->T("Respect silent mode"))); + respectSilentMode->OnClick.Add([=](EventParams &e) { + System_Notify(SystemNotification::AUDIO_MODE_CHANGED); + return UI::EVENT_DONE; + }); + respectSilentMode->SetEnabledPtr(&g_Config.bEnableSound); + CheckBox *mixWithOthers = audioSettings->Add(new CheckBox(&g_Config.bAudioMixWithOthers, a->T("Mix audio with other apps"))); + mixWithOthers->OnClick.Add([=](EventParams &e) { + System_Notify(SystemNotification::AUDIO_MODE_CHANGED); + return UI::EVENT_DONE; + }); + mixWithOthers->SetEnabledPtr(&g_Config.bEnableSound); +#endif + PopupSliderChoice *volume = audioSettings->Add(new PopupSliderChoice(&g_Config.iGlobalVolume, VOLUME_OFF, VOLUME_FULL, VOLUME_FULL, a->T("Global volume"), screenManager())); volume->SetEnabledPtr(&g_Config.bEnableSound); volume->SetZeroLabel(a->T("Mute")); @@ -967,12 +989,16 @@ void GameSettingsScreen::CreateToolsSettings(UI::ViewGroup *tools) { tools->Add(new ItemHeader(ms->T("Tools"))); - auto retro = tools->Add(new Choice(sy->T("RetroAchievements"))); - retro->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn { - screenManager()->push(new RetroAchievementsSettingsScreen(gamePath_)); - return UI::EVENT_DONE; - }); - retro->SetIcon(ImageID("I_RETROACHIEVEMENTS_LOGO")); + const bool showRetroAchievements = true; + if (showRetroAchievements) { + auto retro = tools->Add(new Choice(sy->T("RetroAchievements"))); + retro->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn { + screenManager()->push(new RetroAchievementsSettingsScreen(gamePath_)); + return UI::EVENT_DONE; + }); + retro->SetIcon(ImageID("I_RETROACHIEVEMENTS_LOGO")); + } + // These were moved here so use the wrong translation objects, to avoid having to change all inis... This isn't a sustainable situation :P tools->Add(new Choice(sa->T("Savedata Manager")))->OnClick.Add([=](UI::EventParams &) { screenManager()->push(new SavedataScreen(gamePath_)); @@ -1025,6 +1051,19 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) { screenManager()->push(langScreen); return UI::EVENT_DONE; }); + +#if PPSSPP_PLATFORM(IOS) + static const char *indicator[] = { + "Swipe once to switch app (indicator auto-hides)", + "Swipe twice to switch app (indicator stays visible)" + }; + PopupMultiChoice *switchMode = systemSettings->Add(new PopupMultiChoice(&g_Config.iAppSwitchMode, sy->T("App switching mode"), indicator, 0, ARRAY_SIZE(indicator), I18NCat::SYSTEM, screenManager())); + switchMode->OnChoice.Add([](EventParams &e) { + System_Notify(SystemNotification::APP_SWITCH_MODE_CHANGED); + return UI::EVENT_DONE; + }); +#endif + systemSettings->Add(new CheckBox(&g_Config.bUISound, sy->T("UI Sound"))); const Path bgPng = GetSysDirectory(DIRECTORY_SYSTEM) / "background.png"; const Path bgJpg = GetSysDirectory(DIRECTORY_SYSTEM) / "background.jpg"; @@ -1201,6 +1240,10 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) { systemSettings->Add(new CheckBox(&g_Config.bCacheFullIsoInRam, sy->T("Cache ISO in RAM", "Cache full ISO in RAM")))->SetEnabled(!PSP_IsInited()); systemSettings->Add(new CheckBox(&g_Config.bCheckForNewVersion, sy->T("VersionCheck", "Check for new versions of PPSSPP"))); systemSettings->Add(new CheckBox(&g_Config.bScreenshotsAsPNG, sy->T("Screenshots as PNG"))); + // TODO: Make this setting available on Mac too. +#if PPSSPP_PLATFORM(WINDOWS) + systemSettings->Add(new CheckBox(&g_Config.bPauseOnLostFocus, sy->T("Pause when not focused"))); +#endif systemSettings->Add(new ItemHeader(sy->T("Cheats", "Cheats"))); CheckBox *enableCheats = systemSettings->Add(new CheckBox(&g_Config.bEnableCheats, sy->T("Enable Cheats"))); @@ -1208,6 +1251,7 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) { enableReportsCheckbox_->SetEnabled(Reporting::IsSupported()); return UI::EVENT_CONTINUE; }); + systemSettings->Add(new CheckBox(&g_Config.bEnablePlugins, sy->T("Enable plugins"))); systemSettings->Add(new ItemHeader(sy->T("PSP Settings"))); @@ -1225,8 +1269,8 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) { static const char *buttonPref[] = { "Use O to confirm", "Use X to confirm" }; systemSettings->Add(new PopupMultiChoice(&g_Config.iButtonPreference, sy->T("Confirmation Button"), buttonPref, 0, ARRAY_SIZE(buttonPref), I18NCat::SYSTEM, screenManager())); - systemSettings->Add(new ItemHeader(sy->T("Recording"))); #if defined(_WIN32) || (defined(USING_QT_UI) && !defined(MOBILE_DEVICE)) + systemSettings->Add(new ItemHeader(sy->T("Recording"))); systemSettings->Add(new CheckBox(&g_Config.bDumpFrames, sy->T("Record Display"))); systemSettings->Add(new CheckBox(&g_Config.bUseFFV1, sy->T("Use Lossless Video Codec (FFV1)"))); systemSettings->Add(new CheckBox(&g_Config.bDumpVideoOutput, sy->T("Use output buffer (with overlay) for recording"))); @@ -1239,35 +1283,30 @@ void GameSettingsScreen::CreateVRSettings(UI::ViewGroup *vrSettings) { using namespace UI; auto vr = GetI18NCategory(I18NCat::VR); + int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE); - vrSettings->Add(new ItemHeader(vr->T("Virtual reality"))); - vrSettings->Add(new CheckBox(&g_Config.bEnableVR, vr->T("Virtual reality"))); - vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("6DoF movement"))); - vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); - vrSettings->Add(new CheckBox(&g_Config.bForce72Hz, vr->T("Force 72Hz update"))); - if (IsPassthroughSupported()) { - vrSettings->Add(new CheckBox(&g_Config.bPassthrough, vr->T("Enable passthrough"))); + if (deviceType == DEVICE_TYPE_VR) { + vrSettings->Add(new ItemHeader(vr->T("Virtual reality"))); + vrSettings->Add(new CheckBox(&g_Config.bEnableVR, vr->T("Virtual reality"))); + vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("6DoF movement"))); + vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); + vrSettings->Add(new CheckBox(&g_Config.bEnableImmersiveVR, vr->T("Enable immersive mode"))); + if (IsPassthroughSupported()) { + vrSettings->Add(new CheckBox(&g_Config.bPassthrough, vr->T("Enable passthrough"))); + } + vrSettings->Add(new CheckBox(&g_Config.bForce72Hz, vr->T("Force 72Hz update"))); } vrSettings->Add(new ItemHeader(vr->T("VR camera"))); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 15.0f, 12.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); - vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvas3DDistance, 1.0f, 15.0f, 3.0f, vr->T("Distance to 3D scenes when VR disabled"), 1.0f, screenManager(), "")); + if (deviceType == DEVICE_TYPE_VR) { + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 15.0f, 12.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvas3DDistance, 1.0f, 15.0f, 3.0f, vr->T("Distance to 3D scenes when VR disabled"), 1.0f, screenManager(), "")); + } + vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fFieldOfViewPercentage, 100.0f, 200.0f, 100.0f, vr->T("Field of view scale"), 10.0f, screenManager(), vr->T("% of native FoV"))); vrSettings->Add(new CheckBox(&g_Config.bRescaleHUD, vr->T("Heads-up display detection"))); PopupSliderChoiceFloat* vrHudScale = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadUpDisplayScale, 0.0f, 1.5f, 0.3f, vr->T("Heads-up display scale"), 0.1f, screenManager(), "")); vrHudScale->SetEnabledPtr(&g_Config.bRescaleHUD); vrSettings->Add(new CheckBox(&g_Config.bManualForceVR, vr->T("Manual switching between flat screen and VR using SCREEN key"))); - - vrSettings->Add(new ItemHeader(vr->T("Experts only"))); - vrSettings->Add(new CheckBox(&g_Config.bHeadRotationEnabled, vr->T("Map HMD rotations on keys instead of VR camera"))); - PopupSliderChoiceFloat *vrHeadRotationScale = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadRotationScale, 0.1f, 10.0f, 5.0f, vr->T("Game camera rotation step per frame"), 0.1f, screenManager(), "°")); - vrHeadRotationScale->SetEnabledPtr(&g_Config.bHeadRotationEnabled); - CheckBox *vrHeadRotationSmoothing = vrSettings->Add(new CheckBox(&g_Config.bHeadRotationSmoothing, vr->T("Game camera uses rotation smoothing"))); - vrHeadRotationSmoothing->SetEnabledPtr(&g_Config.bHeadRotationEnabled); - vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys"))); - PopupSliderChoiceFloat *vrMotions = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMotionLength, 0.3f, 1.0f, 0.5f, vr->T("Motion needed to generate action"), 0.1f, screenManager(), vr->T("m"))); - vrMotions->SetEnabledPtr(&g_Config.bEnableMotions); - static const char *cameraPitchModes[] = { "Disabled", "Top view -> First person", "First person -> Top view" }; - vrSettings->Add(new PopupMultiChoice(&g_Config.iCameraPitch, vr->T("Camera type"), cameraPitchModes, 0, 3, I18NCat::NONE, screenManager())); } UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) { @@ -1276,10 +1315,10 @@ UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnScreenRotation(UI::EventParams &e) { - INFO_LOG(SYSTEM, "New display rotation: %d", g_Config.iScreenRotation); - INFO_LOG(SYSTEM, "Sending rotate"); + INFO_LOG(Log::System, "New display rotation: %d", g_Config.iScreenRotation); + INFO_LOG(Log::System, "Sending rotate"); System_Notify(SystemNotification::ROTATE_UPDATED); - INFO_LOG(SYSTEM, "Got back from rotate"); + INFO_LOG(Log::System, "Got back from rotate"); return UI::EVENT_DONE; } @@ -1510,7 +1549,7 @@ void GameSettingsScreen::CallbackMemstickFolder(bool yes) { File::Delete(Path(testWriteFile)); if (!File::WriteDataToFile(true, pendingMemstickFolder_.c_str(), pendingMemstickFolder_.size(), memstickDirFile)) { - WARN_LOG(SYSTEM, "Failed to write memstick folder to '%s'", memstickDirFile.c_str()); + WARN_LOG(Log::System, "Failed to write memstick folder to '%s'", memstickDirFile.c_str()); } else { // Save so the settings, at least, are transferred. g_Config.memStickDirectory = Path(pendingMemstickFolder_); @@ -1751,9 +1790,10 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new ItemHeader(sy->T("General"))); - bool canUseJit = true; + bool canUseJit = System_GetPropertyBool(SYSPROP_CAN_JIT); // iOS can now use JIT on all modes, apparently. // The bool may come in handy for future non-jit platforms though (UWP XB1?) + // In iOS App Store builds, we disable the JIT. static const char *cpuCores[] = {"Interpreter", "Dynarec/JIT (recommended)", "IR Interpreter", "JIT using IR"}; PopupMultiChoice *core = list->Add(new PopupMultiChoice(&g_Config.iCpuCore, sy->T("CPU Core"), cpuCores, 0, ARRAY_SIZE(cpuCores), I18NCat::SYSTEM, screenManager())); @@ -1766,7 +1806,7 @@ void DeveloperToolsScreen::CreateViews() { core->HideChoice(1); core->HideChoice(3); } - // TODO: Enable on more architectures. + // TODO: Enable "JIT using IR" on more architectures. #if !PPSSPP_ARCH(X86) && !PPSSPP_ARCH(AMD64) && !PPSSPP_ARCH(ARM64) core->HideChoice(3); #endif @@ -1782,6 +1822,8 @@ void DeveloperToolsScreen::CreateViews() { cpuTests->SetEnabled(TestsAvailable()); #endif + list->Add(new CheckBox(&g_Config.bUseNewAtrac, dev->T("Use experimental sceAtrac"))); + AddOverlayList(list, screenManager()); list->Add(new CheckBox(&g_Config.bEnableLogging, dev->T("Enable Logging")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoggingChanged); @@ -1825,6 +1867,11 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bShowOnScreenMessages, dev->T("Show on-screen messages"))); + list->Add(new Choice(dev->T("GPI/GPO switches/LEDs")))->OnClick.Add([=](UI::EventParams &e) { + screenManager()->push(new GPIGPOScreen(dev->T("GPI/GPO switches/LEDs"))); + return UI::EVENT_DONE; + }); + #if PPSSPP_PLATFORM(ANDROID) static const char *framerateModes[] = { "Default", "Request 60Hz", "Force 60Hz" }; PopupMultiChoice *framerateMode = list->Add(new PopupMultiChoice(&g_Config.iDisplayFramerateMode, gr->T("Framerate mode"), framerateModes, 0, ARRAY_SIZE(framerateModes), I18NCat::GRAPHICS, screenManager())); @@ -1840,6 +1887,63 @@ void DeveloperToolsScreen::CreateViews() { ffMode->SetEnabledFunc([]() { return !g_Config.bVSync; }); ffMode->HideChoice(1); // not used + auto displayRefreshRate = list->Add(new PopupSliderChoice(&g_Config.iDisplayRefreshRate, 60, 1000, 60, dev->T("Display refresh rate"), 1, screenManager())); + displayRefreshRate->SetFormat(dev->T("%d Hz")); + +#if !PPSSPP_PLATFORM(ANDROID) && !PPSSPP_PLATFORM(IOS) && !PPSSPP_PLATFORM(SWITCH) + list->Add(new ItemHeader(dev->T("MIPSTracer"))); + + MIPSTracerEnabled_ = mipsTracer.tracing_enabled; + CheckBox *MIPSLoggerEnabled = new CheckBox(&MIPSTracerEnabled_, dev->T("MIPSTracer enabled")); + list->Add(MIPSLoggerEnabled)->OnClick.Handle(this, &DeveloperToolsScreen::OnMIPSTracerEnabled); + MIPSLoggerEnabled->SetEnabledFunc([]() { + bool temp = g_Config.iCpuCore == static_cast(CPUCore::IR_INTERPRETER) && PSP_IsInited(); + return temp && Core_IsStepping() && coreState != CORE_POWERDOWN; + }); + + Choice *MIPSlogging_path = list->Add(new Choice(dev->T("Select the output logging file"))); + MIPSlogging_path->OnClick.Handle(this, &DeveloperToolsScreen::OnMIPSTracerPathChanged); + MIPSlogging_path->SetEnabledFunc([]() { + if (!PSP_IsInited()) + return false; + return true; + }); + + MIPSTracerPath_ = mipsTracer.get_logging_path(); + MIPSTracerPath = list->Add(new InfoItem(dev->T("Current log file"), MIPSTracerPath_)); + + PopupSliderChoice* storage_capacity = list->Add( + new PopupSliderChoice( + &mipsTracer.in_storage_capacity, 0x4'0000, 0x40'0000, 0x10'0000, dev->T("Storage capacity"), 0x10000, screenManager() + ) + ); + storage_capacity->SetFormat("0x%x asm opcodes"); + storage_capacity->OnChange.Add([&](UI::EventParams &) { + INFO_LOG(Log::JIT, "User changed the tracer's storage capacity to 0x%x", mipsTracer.in_storage_capacity); + return UI::EVENT_CONTINUE; + }); + + PopupSliderChoice* trace_max_size = list->Add( + new PopupSliderChoice( + &mipsTracer.in_max_trace_size, 0x1'0000, 0x40'0000, 0x10'0000, dev->T("Max allowed trace size"), 0x10000, screenManager() + ) + ); + trace_max_size->SetFormat("%d basic blocks"); + trace_max_size->OnChange.Add([&](UI::EventParams &) { + INFO_LOG(Log::JIT, "User changed the tracer's max trace size to %d", mipsTracer.in_max_trace_size); + return UI::EVENT_CONTINUE; + }); + + Button *FlushTrace = list->Add(new Button(dev->T("Flush the trace"))); + FlushTrace->OnClick.Handle(this, &DeveloperToolsScreen::OnMIPSTracerFlushTrace); + + Button *InvalidateJitCache = list->Add(new Button(dev->T("Clear the JIT cache"))); + InvalidateJitCache->OnClick.Handle(this, &DeveloperToolsScreen::OnMIPSTracerClearJitCache); + + Button *ClearMIPSTracer = list->Add(new Button(dev->T("Clear the MIPSTracer"))); + ClearMIPSTracer->OnClick.Handle(this, &DeveloperToolsScreen::OnMIPSTracerClearTracer); +#endif + Draw::DrawContext *draw = screenManager()->getDrawContext(); list->Add(new ItemHeader(dev->T("Ubershaders"))); @@ -1855,6 +1959,13 @@ void DeveloperToolsScreen::CreateViews() { list->Add(new CheckBox(&g_Config.bUberShaderFragment, dev->T("Fragment"))); } + // Experimental, allow some VR features without OpenXR + if (GetGPUBackend() == GPUBackend::OPENGL) { + auto vr = GetI18NCategory(I18NCat::VR); + list->Add(new ItemHeader(gr->T("Virtual reality"))); + list->Add(new CheckBox(&g_Config.bForceVR, vr->T("VR camera"))); + } + // Experimental, will move to main graphics settings later. bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; @@ -2004,7 +2115,7 @@ UI::EventReturn DeveloperToolsScreen::OnCopyStatesToRoot(UI::EventParams &e) { for (const File::FileInfo &file : files) { Path src = file.fullName; Path dst = root_dir / file.name; - INFO_LOG(SYSTEM, "Copying file '%s' to '%s'", src.c_str(), dst.c_str()); + INFO_LOG(Log::System, "Copying file '%s' to '%s'", src.c_str(), dst.c_str()); File::Copy(src, dst); } @@ -2022,6 +2133,51 @@ UI::EventReturn DeveloperToolsScreen::OnRemoteDebugger(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn DeveloperToolsScreen::OnMIPSTracerEnabled(UI::EventParams &e) { + if (MIPSTracerEnabled_) { + u32 capacity = mipsTracer.in_storage_capacity; + u32 trace_size = mipsTracer.in_max_trace_size; + + mipsTracer.initialize(capacity, trace_size); + mipsTracer.start_tracing(); + } + else { + mipsTracer.stop_tracing(); + } + return UI::EVENT_DONE; +} + +UI::EventReturn DeveloperToolsScreen::OnMIPSTracerPathChanged(UI::EventParams &e) { + auto dev = GetI18NCategory(I18NCat::DEVELOPER); + System_BrowseForFile(GetRequesterToken(), dev->T("Select the log file"), BrowseFileType::ANY, + [this](const std::string &value, int) { + mipsTracer.set_logging_path(value); + MIPSTracerPath_ = value; + MIPSTracerPath->SetRightText(MIPSTracerPath_); + }); + return UI::EVENT_DONE; +} + +UI::EventReturn DeveloperToolsScreen::OnMIPSTracerFlushTrace(UI::EventParams &e) { + bool success = mipsTracer.flush_to_file(); + if (!success) { + WARN_LOG(Log::JIT, "Error: cannot flush the trace to the specified file!"); + } + return UI::EVENT_DONE; +} + +UI::EventReturn DeveloperToolsScreen::OnMIPSTracerClearJitCache(UI::EventParams &e) { + INFO_LOG(Log::JIT, "Clearing the jit cache..."); + System_PostUIMessage(UIMessage::REQUEST_CLEAR_JIT); + return UI::EVENT_DONE; +} + +UI::EventReturn DeveloperToolsScreen::OnMIPSTracerClearTracer(UI::EventParams &e) { + INFO_LOG(Log::JIT, "Clearing the MIPSTracer..."); + mipsTracer.clear(); + return UI::EVENT_DONE; +} + void DeveloperToolsScreen::update() { UIDialogScreenWithBackground::update(); allowDebugger_ = !WebServerStopped(WebServerFlags::DEBUGGER); @@ -2171,7 +2327,7 @@ UI::EventReturn HostnameSelectScreen::OnDeleteAllClick(UI::EventParams &e) { UI::EventReturn HostnameSelectScreen::OnEditClick(UI::EventParams& e) { auto n = GetI18NCategory(I18NCat::NETWORKING); System_InputBoxGetString(GetRequesterToken(), n->T("proAdhocServer Address:"), addrView_->GetText(), [this](const std::string& value, int) { - addrView_->SetText(value); + addrView_->SetText(value); }); return UI::EVENT_DONE; } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 94be030025..87ad8eca44 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -150,6 +150,11 @@ private: UI::EventReturn OnJitAffectingSetting(UI::EventParams &e); UI::EventReturn OnJitDebugTools(UI::EventParams &e); UI::EventReturn OnRemoteDebugger(UI::EventParams &e); + UI::EventReturn OnMIPSTracerEnabled(UI::EventParams &e); + UI::EventReturn OnMIPSTracerPathChanged(UI::EventParams &e); + UI::EventReturn OnMIPSTracerFlushTrace(UI::EventParams &e); + UI::EventReturn OnMIPSTracerClearJitCache(UI::EventParams &e); + UI::EventReturn OnMIPSTracerClearTracer(UI::EventParams &e); UI::EventReturn OnGPUDriverTest(UI::EventParams &e); UI::EventReturn OnFramedumpTest(UI::EventParams &e); UI::EventReturn OnMemstickTest(UI::EventParams &e); @@ -164,6 +169,10 @@ private: MAYBE, }; HasIni hasTexturesIni_ = HasIni::MAYBE; + + bool MIPSTracerEnabled_ = false; + std::string MIPSTracerPath_ = ""; + UI::InfoItem* MIPSTracerPath = nullptr; }; class HostnameSelectScreen : public PopupScreen { diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index cdc7bf4a72..3c5b9ca8df 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -521,8 +521,8 @@ void PSPStick::ProcessTouch(float x, float y, bool down) { } } -PSPCustomStick::PSPCustomStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, float scale, UI::LayoutParams *layoutParams) - : PSPStick(bgImg, key, stickImg, stickDownImg, -1, scale, layoutParams) { +PSPCustomStick::PSPCustomStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, int stick, float scale, UI::LayoutParams *layoutParams) + : PSPStick(bgImg, key, stickImg, stickDownImg, stick, scale, layoutParams) { } void PSPCustomStick::Draw(UIContext &dc) { @@ -607,7 +607,7 @@ bool PSPCustomStick::Touch(const TouchInput &input) { void PSPCustomStick::ProcessTouch(float x, float y, bool down) { static const int buttons[] = {0, CTRL_LTRIGGER, CTRL_RTRIGGER, CTRL_SQUARE, CTRL_TRIANGLE, CTRL_CIRCLE, CTRL_CROSS, CTRL_UP, CTRL_DOWN, CTRL_LEFT, CTRL_RIGHT, CTRL_START, CTRL_SELECT}; - + static const int analogs[] = {VIRTKEY_AXIS_RIGHT_Y_MAX, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, VIRTKEY_AXIS_Y_MAX, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX}; u32 press = 0; u32 release = 0; @@ -621,6 +621,71 @@ void PSPCustomStick::ProcessTouch(float x, float y, bool down) { release |= buttons[config]; }; + auto analog = [&](float dx, float dy) { + if (g_Config.bRightAnalogDisableDiagonal) { + if (fabs(dx) > fabs(dy)) { + dy = 0.0f; + } else { + dx = 0.0f; + } + } + + auto assign = [&](int config, float value) { + if (config < ARRAY_SIZE(buttons) || config >= ARRAY_SIZE(buttons) + ARRAY_SIZE(analogs)) { + return; + } + switch(analogs[config - ARRAY_SIZE(buttons)]) { + case VIRTKEY_AXIS_Y_MAX: + __CtrlSetAnalogY(0, value); + break; + case VIRTKEY_AXIS_Y_MIN: + __CtrlSetAnalogY(0, value * -1.0f); + break; + case VIRTKEY_AXIS_X_MIN: + __CtrlSetAnalogX(0, value * -1.0f); + break; + case VIRTKEY_AXIS_X_MAX: + __CtrlSetAnalogX(0, value); + break; + case VIRTKEY_AXIS_RIGHT_Y_MAX: + __CtrlSetAnalogY(1, value); + break; + case VIRTKEY_AXIS_RIGHT_Y_MIN: + __CtrlSetAnalogY(1, value * -1.0f); + break; + case VIRTKEY_AXIS_RIGHT_X_MIN: + __CtrlSetAnalogX(1, value * -1.0f); + break; + case VIRTKEY_AXIS_RIGHT_X_MAX: + __CtrlSetAnalogX(1, value); + break; + } + }; + + // if/when we ever get iLeftAnalog settings, check stick_ for the config to use + // let 0.0f through during centering + if (dy >= 0.0f) { + // down + assign(g_Config.iRightAnalogUp, 0.0f); + assign(g_Config.iRightAnalogDown, dy); + } + if (dy <= 0.0f) { + // up + assign(g_Config.iRightAnalogDown, 0.0f); + assign(g_Config.iRightAnalogUp, dy * -1.0f); + } + if (dx <= 0.0f) { + // left + assign(g_Config.iRightAnalogRight, 0.0f); + assign(g_Config.iRightAnalogLeft, dx * -1.0f); + } + if (dx >= 0.0f) { + // right + assign(g_Config.iRightAnalogLeft, 0.0f); + assign(g_Config.iRightAnalogRight, dx); + } + }; + if (down && centerX_ >= 0.0f) { float inv_stick_size = 1.0f / (stick_size_ * scale_); @@ -636,6 +701,8 @@ void PSPCustomStick::ProcessTouch(float x, float y, bool down) { toggle(g_Config.iRightAnalogDown, dy > 0.5f, fabs(dx) <= fabs(dy)); toggle(g_Config.iRightAnalogPress, true); + analog(dx, dy); + posX_ = dx; posY_ = dy; @@ -646,6 +713,8 @@ void PSPCustomStick::ProcessTouch(float x, float y, bool down) { toggle(g_Config.iRightAnalogDown, false); toggle(g_Config.iRightAnalogPress, false); + analog(0.0f, 0.0f); + posX_ = 0.0f; posY_ = 0.0f; } @@ -712,16 +781,23 @@ void InitPadLayout(float xres, float yres, float globalScale) { bottom_key_spacing *= 0.8f; } +// On IOS, nudge the bottom button up a little to avoid the task switcher. +#if PPSSPP_PLATFORM(IOS) + const float bottom_button_Y = 80.0f; +#else + const float bottom_button_Y = 60.0f; +#endif + int start_key_X = halfW + bottom_key_spacing * scale; - int start_key_Y = yres - 60 * scale; + int start_key_Y = yres - bottom_button_Y * scale; initTouchPos(g_Config.touchStartKey, start_key_X, start_key_Y); int select_key_X = halfW; - int select_key_Y = yres - 60 * scale; + int select_key_Y = yres - bottom_button_Y * scale; initTouchPos(g_Config.touchSelectKey, select_key_X, select_key_Y); int fast_forward_key_X = halfW - bottom_key_spacing * scale; - int fast_forward_key_Y = yres - 60 * scale; + int fast_forward_key_Y = yres - bottom_button_Y * scale; initTouchPos(g_Config.touchFastForwardKey, fast_forward_key_X, fast_forward_key_Y); // L and R------------------------------------------------------------ @@ -806,6 +882,10 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause, bool showPau auto addCustomButton = [=](const ConfigCustomButton& cfg, const char *key, const ConfigTouchPos &touch) -> CustomButton * { using namespace CustomKeyData; if (touch.show) { + _dbg_assert_(cfg.shape < ARRAY_SIZE(customKeyShapes)); + _dbg_assert_(cfg.image < ARRAY_SIZE(customKeyImages)); + + // Note: cfg.shape and cfg.image are bounds-checked elsewhere. auto aux = root->Add(new CustomButton(cfg.key, key, cfg.toggle, cfg.repeat, controllMapper, g_Config.iTouchButtonStyle == 0 ? customKeyShapes[cfg.shape].i : customKeyShapes[cfg.shape].l, customKeyShapes[cfg.shape].i, customKeyImages[cfg.image].i, touch.scale, customKeyShapes[cfg.shape].d, buttonLayoutParams(touch))); @@ -859,12 +939,20 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause, bool showPau if (g_Config.touchRightAnalogStick.show) { if (g_Config.bRightAnalogCustom) - root->Add(new PSPCustomStick(stickBg, "Right analog stick", stickImage, ImageID("I_STICK"), g_Config.touchRightAnalogStick.scale, buttonLayoutParams(g_Config.touchRightAnalogStick))); + root->Add(new PSPCustomStick(stickBg, "Right analog stick", stickImage, ImageID("I_STICK"), 1, g_Config.touchRightAnalogStick.scale, buttonLayoutParams(g_Config.touchRightAnalogStick))); else root->Add(new PSPStick(stickBg, "Right analog stick", stickImage, ImageID("I_STICK"), 1, g_Config.touchRightAnalogStick.scale, buttonLayoutParams(g_Config.touchRightAnalogStick))); } + // Sanitize custom button images, while adding them. for (int i = 0; i < Config::CUSTOM_BUTTON_COUNT; i++) { + if (g_Config.CustomButton[i].shape >= ARRAY_SIZE(CustomKeyData::customKeyShapes)) { + g_Config.CustomButton[i].shape = 0; + } + if (g_Config.CustomButton[i].image >= ARRAY_SIZE(CustomKeyData::customKeyImages)) { + g_Config.CustomButton[i].image = 0; + } + char temp[64]; snprintf(temp, sizeof(temp), "Custom %d button", i + 1); addCustomButton(g_Config.CustomButton[i], temp, g_Config.touchCustom[i]); diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index d110a527d4..a66671d9ae 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -142,7 +142,7 @@ private: class PSPCustomStick : public PSPStick { public: - PSPCustomStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, float scale, UI::LayoutParams *layoutParams); + PSPCustomStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, int stick, float scale, UI::LayoutParams *layoutParams); bool Touch(const TouchInput &input) override; void Draw(UIContext &dc) override; @@ -252,6 +252,7 @@ namespace CustomKeyData { { ImageID("I_ARROW_UP"), 0.0f}, { ImageID("I_ARROW_DOWN"), 0.0f}, { ImageID("I_THREE_DOTS"), 0.0f}, + { ImageID("I_EMPTY"), 0.0f}, }; // Shape list diff --git a/UI/InstallZipScreen.cpp b/UI/InstallZipScreen.cpp index a85f898a61..30d4605619 100644 --- a/UI/InstallZipScreen.cpp +++ b/UI/InstallZipScreen.cpp @@ -20,10 +20,17 @@ #include "Common/UI/ViewGroup.h" #include "Common/StringUtils.h" +#include "Common/File/FileUtil.h" #include "Common/Data/Text/I18n.h" +#include "Common/Data/Text/Parsers.h" +#include "Core/Config.h" +#include "Core/System.h" #include "Core/Util/GameManager.h" +#include "Core/Loaders.h" #include "UI/InstallZipScreen.h" #include "UI/MainScreen.h" +#include "UI/OnScreenDisplay.h" +#include "UI/SavedataScreen.h" InstallZipScreen::InstallZipScreen(const Path &zipPath) : zipPath_(zipPath) { g_GameManager.ResetInstallError(); @@ -37,12 +44,14 @@ void InstallZipScreen::CreateViews() { auto di = GetI18NCategory(I18NCat::DIALOG); auto iz = GetI18NCategory(I18NCat::INSTALLZIP); + auto er = GetI18NCategory(I18NCat::ERRORS); + auto ga = GetI18NCategory(I18NCat::GAME); Margins actionMenuMargins(0, 100, 15, 0); root_ = new LinearLayout(ORIENT_HORIZONTAL); - ViewGroup *leftColumn = new AnchorLayout(new LinearLayoutParams(1.0f)); + ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f, Margins(12))); ViewGroup *rightColumnItems = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); root_->Add(leftColumn); root_->Add(rightColumnItems); @@ -50,59 +59,151 @@ void InstallZipScreen::CreateViews() { std::string shortFilename = zipPath_.GetFilename(); // TODO: Do in the background? - ZipFileInfo zipInfo; - ZipFileContents contents = DetectZipFileContents(zipPath_, &zipInfo); + struct zip *z = ZipOpenPath(zipPath_); - if (contents == ZipFileContents::ISO_FILE || contents == ZipFileContents::PSP_GAME_DIR) { - std::string_view question = iz->T("Install game from ZIP file?"); - leftColumn->Add(new TextView(question, ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); - leftColumn->Add(new TextView(shortFilename, ALIGN_LEFT, false, new AnchorLayoutParams(10, 60, NONE, NONE))); + bool showDeleteCheckbox = false; + returnToHomebrew_ = false; + installChoice_ = nullptr; + doneView_ = nullptr; + installChoice_ = nullptr; + existingSaveView_ = nullptr; + destFolders_.clear(); - doneView_ = leftColumn->Add(new TextView("", new AnchorLayoutParams(10, 120, NONE, NONE))); - progressBar_ = leftColumn->Add(new ProgressBar(new AnchorLayoutParams(10, 200, 200, NONE))); + std::vector destOptions; - installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install"))); - installChoice_->OnClick.Handle(this, &InstallZipScreen::OnInstall); - backChoice_ = rightColumnItems->Add(new Choice(di->T("Back"))); - rightColumnItems->Add(new CheckBox(&deleteZipFile_, iz->T("Delete ZIP file"))); + if (z) { + DetectZipFileContents(z, &zipFileInfo_); // Even if this fails, it sets zipInfo->contents. + if (zipFileInfo_.contents == ZipFileContents::ISO_FILE || zipFileInfo_.contents == ZipFileContents::PSP_GAME_DIR) { + std::string_view question = iz->T("Install game from ZIP file?"); - returnToHomebrew_ = true; - } else if (contents == ZipFileContents::TEXTURE_PACK) { - std::string_view question = iz->T("Install textures from ZIP file?"); - leftColumn->Add(new TextView(question, ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); - leftColumn->Add(new TextView(shortFilename, ALIGN_LEFT, false, new AnchorLayoutParams(10, 60, NONE, NONE))); + leftColumn->Add(new TextView(question)); + leftColumn->Add(new TextView(shortFilename)); + if (!zipFileInfo_.contentName.empty()) { + leftColumn->Add(new TextView(zipFileInfo_.contentName)); + } - doneView_ = leftColumn->Add(new TextView("", new AnchorLayoutParams(10, 120, NONE, NONE))); - progressBar_ = leftColumn->Add(new ProgressBar(new AnchorLayoutParams(10, 200, 200, NONE))); + doneView_ = leftColumn->Add(new TextView("")); - installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install"))); - installChoice_->OnClick.Handle(this, &InstallZipScreen::OnInstall); - backChoice_ = rightColumnItems->Add(new Choice(di->T("Back"))); - rightColumnItems->Add(new CheckBox(&deleteZipFile_, iz->T("Delete ZIP file"))); + if (zipFileInfo_.contents == ZipFileContents::ISO_FILE) { + const bool isInDownloads = File::IsProbablyInDownloadsFolder(zipPath_); + Path parent; + if (!isInDownloads && zipPath_.CanNavigateUp()) { + parent = zipPath_.NavigateUp(); + destFolders_.push_back(parent); + } + if (g_Config.currentDirectory.IsLocalType() && File::Exists(g_Config.currentDirectory) && g_Config.currentDirectory != parent) { + destFolders_.push_back(g_Config.currentDirectory); + } + destFolders_.push_back(g_Config.memStickDirectory); + } else { + destFolders_.push_back(GetSysDirectory(DIRECTORY_GAME)); + } - returnToHomebrew_ = false; + installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install"))); + installChoice_->OnClick.Handle(this, &InstallZipScreen::OnInstall); + returnToHomebrew_ = true; + showDeleteCheckbox = true; + } else if (zipFileInfo_.contents == ZipFileContents::TEXTURE_PACK) { + std::string_view question = iz->T("Install textures from ZIP file?"); + leftColumn->Add(new TextView(question)); + leftColumn->Add(new TextView(shortFilename)); + + doneView_ = leftColumn->Add(new TextView("")); + + installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install"))); + installChoice_->OnClick.Handle(this, &InstallZipScreen::OnInstall); + backChoice_ = rightColumnItems->Add(new Choice(di->T("Back"))); + + showDeleteCheckbox = true; + } else if (zipFileInfo_.contents == ZipFileContents::SAVE_DATA) { + std::string_view question = iz->T("Import savedata from ZIP file"); + leftColumn->Add(new TextView(question))->SetBig(true); + leftColumn->Add(new TextView(zipFileInfo_.gameTitle + ": " + zipFileInfo_.savedataDir)); + + Path savedataDir = GetSysDirectory(DIRECTORY_SAVEDATA); + bool overwrite = !CanExtractWithoutOverwrite(z, savedataDir, 50); + + destFolders_.push_back(savedataDir); + + if (overwrite) { + leftColumn->Add(new NoticeView(NoticeLevel::WARN, di->T("Confirm Overwrite"), "")); + } + + int columnWidth = 300; + + LinearLayout *compareColumns = leftColumn->Add(new LinearLayout(UI::ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + LinearLayout *leftCompare = new LinearLayout(UI::ORIENT_VERTICAL); + leftCompare->Add(new TextView(iz->T("Data to import"))); + compareColumns->Add(leftCompare); + leftCompare->Add(new SavedataView(*screenManager()->getUIContext(), Path(), IdentifiedFileType::PSP_SAVEDATA_DIRECTORY, + zipFileInfo_.gameTitle, zipFileInfo_.savedataTitle, zipFileInfo_.savedataDetails, NiceSizeFormat(zipFileInfo_.totalFileSize), zipFileInfo_.mTime, false, new LinearLayoutParams(columnWidth, WRAP_CONTENT))); + + // Check for potential overwrite at destination, and ask the user if it's OK to overwrite. + if (overwrite) { + savedataToOverwrite_ = savedataDir / zipFileInfo_.savedataDir; + std::shared_ptr ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savedataToOverwrite_, GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE); + + LinearLayout *rightCompare = new LinearLayout(UI::ORIENT_VERTICAL); + rightCompare->Add(new TextView(iz->T("Existing data"))); + + compareColumns->Add(rightCompare); + existingSaveView_ = rightCompare->Add(new SavedataView(*screenManager()->getUIContext(), ginfo.get(), IdentifiedFileType::PSP_SAVEDATA_DIRECTORY, false, new LinearLayoutParams(columnWidth, WRAP_CONTENT))); + if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) { + rightCompare->Add(new Button(ga->T("Show In Folder")))->OnClick.Add([=](UI::EventParams &) { + System_ShowFileInFolder(savedataToOverwrite_); + return UI::EVENT_DONE; + }); + } + } + + installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install"))); + installChoice_->OnClick.Handle(this, &InstallZipScreen::OnInstall); + + doneView_ = leftColumn->Add(new TextView("")); + showDeleteCheckbox = true; + } else { + leftColumn->Add(new TextView(iz->T("Zip file does not contain PSP software"), ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); + } } else { - leftColumn->Add(new TextView(iz->T("Zip file does not contain PSP software"), ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); - doneView_ = nullptr; - progressBar_ = nullptr; - installChoice_ = nullptr; - backChoice_ = rightColumnItems->Add(new Choice(di->T("Back"))); + leftColumn->Add(new TextView(er->T("Error reading file"), ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); + } + + if (destFolders_.size() > 1) { + leftColumn->Add(new TextView(iz->T("Install into folder"))); + for (int i = 0; i < (int)destFolders_.size(); i++) { + leftColumn->Add(new RadioButton(&destFolderChoice_, i, destFolders_[i].ToVisualString())); + } + } else if (destFolders_.size() == 1 && zipFileInfo_.contents != ZipFileContents::SAVE_DATA) { + leftColumn->Add(new TextView(StringFromFormat("%s %s", iz->T_cstr("Install into folder:"), destFolders_[0].ToVisualString().c_str()))); } // OK so that EmuScreen will handle it right. + backChoice_ = rightColumnItems->Add(new Choice(di->T("Back"))); backChoice_->OnClick.Handle(this, &UIScreen::OnOK); + + if (showDeleteCheckbox) { + rightColumnItems->Add(new CheckBox(&deleteZipFile_, iz->T("Delete ZIP file"))); + } } bool InstallZipScreen::key(const KeyInput &key) { // Ignore all key presses during download and installation to avoid user escape if (g_GameManager.GetState() == GameManagerState::IDLE) { - return UIScreen::key(key); + return UIDialogScreen::key(key); } return false; } UI::EventReturn InstallZipScreen::OnInstall(UI::EventParams ¶ms) { - if (g_GameManager.InstallGameOnThread(zipPath_, zipPath_, deleteZipFile_)) { + ZipFileTask task; + task.url = zipPath_; + task.fileName = zipPath_; + task.deleteAfter = deleteZipFile_; + task.zipFileInfo = zipFileInfo_; + if (!destFolders_.empty() && destFolderChoice_ < destFolders_.size()) { + task.destination = destFolders_[destFolderChoice_]; + } + if (g_GameManager.InstallZipOnThread(task)) { installStarted_ = true; if (installChoice_) { installChoice_->SetEnabled(false); @@ -116,17 +217,10 @@ void InstallZipScreen::update() { using namespace UI; if (g_GameManager.GetState() != GameManagerState::IDLE) { - if (progressBar_) { - progressBar_->SetVisibility(V_VISIBLE); - progressBar_->SetProgress(g_GameManager.GetCurrentInstallProgressPercentage()); - } if (backChoice_) { backChoice_->SetEnabled(false); } } else { - if (progressBar_) { - progressBar_->SetVisibility(V_GONE); - } if (backChoice_) { backChoice_->SetEnabled(true); } @@ -140,5 +234,10 @@ void InstallZipScreen::update() { MainScreen::showHomebrewTab = returnToHomebrew_; } } - UIScreen::update(); + + if (existingSaveView_) { + std::shared_ptr ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savedataToOverwrite_, GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE); + existingSaveView_->Update(ginfo.get()); + } + UIDialogScreenWithBackground::update(); } diff --git a/UI/InstallZipScreen.h b/UI/InstallZipScreen.h index b877595d57..68982187ac 100644 --- a/UI/InstallZipScreen.h +++ b/UI/InstallZipScreen.h @@ -19,11 +19,15 @@ #include +#include "Common/File/Path.h" + #include "Common/UI/View.h" #include "Common/UI/UIScreen.h" #include "UI/MiscScreens.h" +class SavedataView; + class InstallZipScreen : public UIDialogScreenWithBackground { public: InstallZipScreen(const Path &zipPath); @@ -40,9 +44,13 @@ private: UI::Choice *installChoice_ = nullptr; UI::Choice *backChoice_ = nullptr; - UI::ProgressBar *progressBar_ = nullptr; UI::TextView *doneView_ = nullptr; + SavedataView *existingSaveView_ = nullptr; + Path savedataToOverwrite_; Path zipPath_; + std::vector destFolders_; + int destFolderChoice_ = 0; + ZipFileInfo zipFileInfo_{}; bool returnToHomebrew_ = true; bool installStarted_ = false; bool deleteZipFile_ = false; diff --git a/UI/JitCompareScreen.cpp b/UI/JitCompareScreen.cpp new file mode 100644 index 0000000000..326bd55d9f --- /dev/null +++ b/UI/JitCompareScreen.cpp @@ -0,0 +1,559 @@ +#include + +#include "UI/JitCompareScreen.h" + +#include "Core/MemMap.h" +#include "Core/MIPS/MIPSTables.h" +#include "Core/MIPS/JitCommon/JitBlockCache.h" +#include "Core/MIPS/JitCommon/JitCommon.h" +#include "Core/MIPS/JitCommon/JitState.h" + +JitCompareScreen::JitCompareScreen() : UIDialogScreenWithBackground() { + JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface(); + // The only defaults that make sense. + if (blockCacheDebug->SupportsProfiling()) { + listSort_ = ListSort::TIME_SPENT; + } else { + listSort_ = ListSort::BLOCK_LENGTH_DESC; + } + FillBlockList(); +} + +void JitCompareScreen::Flip() { + using namespace UI; + // If we add more, let's convert to a for loop. + switch (viewMode_) { + case ViewMode::DISASM: + comparisonView_->SetVisibility(V_VISIBLE); + blockListView_->SetVisibility(V_GONE); + statsView_->SetVisibility(V_GONE); + break; + case ViewMode::BLOCK_LIST: + comparisonView_->SetVisibility(V_GONE); + blockListView_->SetVisibility(V_VISIBLE); + statsView_->SetVisibility(V_GONE); + break; + case ViewMode::STATS: + comparisonView_->SetVisibility(V_GONE); + blockListView_->SetVisibility(V_GONE); + statsView_->SetVisibility(V_VISIBLE); + break; + } +} + +// Three panes: Block chooser, MIPS view, ARM/x86 view +void JitCompareScreen::CreateViews() { + auto di = GetI18NCategory(I18NCat::DIALOG); + auto dev = GetI18NCategory(I18NCat::DEVELOPER); + + using namespace UI; + + root_ = new LinearLayout(ORIENT_HORIZONTAL); + + ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(200, FILL_PARENT))); + LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); + + comparisonView_ = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); + comparisonView_->SetVisibility(V_VISIBLE); + LinearLayout *blockTopBar = comparisonView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + blockTopBar->Add(new Button("", ImageID("I_ARROW_UP")))->OnClick.Add([this](UI::EventParams &e) { + viewMode_ = ViewMode::BLOCK_LIST; + Flip(); + return UI::EVENT_DONE; + }); + blockTopBar->Add(new Button("", ImageID("I_ARROW_LEFT")))->OnClick.Add([=](UI::EventParams &e) { + if (currentBlock_ >= 1) + currentBlock_--; + UpdateDisasm(); + return UI::EVENT_DONE; + }); + blockTopBar->Add(new Button("", ImageID("I_ARROW_RIGHT")))->OnClick.Add([=](UI::EventParams &e) { + if (currentBlock_ < blockList_.size() - 1) + currentBlock_++; + UpdateDisasm(); + return UI::EVENT_DONE; + }); + blockTopBar->Add(new Button(dev->T("Random")))->OnClick.Add([=](UI::EventParams &e) { + if (blockList_.empty()) { + return UI::EVENT_DONE; + } + currentBlock_ = rand() % blockList_.size(); + UpdateDisasm(); + return UI::EVENT_DONE; + }); + + blockAddr_ = blockTopBar->Add(new TextEdit("", dev->T("Block address"), "")); + blockAddr_->OnEnter.Handle(this, &JitCompareScreen::OnAddressChange); + blockName_ = blockTopBar->Add(new TextView(dev->T("No block"))); + blockStats_ = blockTopBar->Add(new TextView("")); + + LinearLayout *columns = comparisonView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f))); + + ScrollView *midColumnScroll = columns->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); + LinearLayout *midColumn = midColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); + midColumn->SetTag("JitCompareLeftDisasm"); + leftDisasm_ = midColumn->Add(new LinearLayout(ORIENT_VERTICAL)); + leftDisasm_->SetSpacing(0.0f); + + ScrollView *rightColumnScroll = columns->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); + rightColumnScroll->SetTag("JitCompareRightDisasm"); + LinearLayout *rightColumn = rightColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL)); + rightDisasm_ = rightColumn->Add(new LinearLayout(ORIENT_VERTICAL)); + rightDisasm_->SetSpacing(0.0f); + + blockListView_ = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); + blockListView_->SetVisibility(V_GONE); + + // Should match the ListSort enum + static ContextMenuItem sortMenu[] = { + { "Block number", "I_ARROW_UP" }, + { "Block length", "I_ARROW_DOWN" }, + { "Block length", "I_ARROW_UP" }, + { "Time spent", "I_ARROW_DOWN" }, + { "Executions", "I_ARROW_DOWN" }, + }; + int sortCount = ARRAY_SIZE(sortMenu); + if (MIPSComp::jit) { + JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface(); + if (!blockCacheDebug->SupportsProfiling()) { + sortCount -= 2; + } + } + + LinearLayout *listTopBar = blockListView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + Button *sortButton = new Button(dev->T("Sort...")); + listTopBar->Add(sortButton)->OnClick.Add([this, sortButton, sortCount](UI::EventParams &e) { + PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(sortMenu, sortCount, I18NCat::DEVELOPER, sortButton); + screenManager()->push(contextMenu); + contextMenu->OnChoice.Add([=](EventParams &e) -> UI::EventReturn { + if (e.a < (int)ListSort::MAX) { + listSort_ = (ListSort)e.a; + UpdateDisasm(); + } + return UI::EVENT_DONE; + }); + return UI::EVENT_DONE; + }); + + ScrollView *blockScroll = blockListView_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); + blockListContainer_ = blockScroll->Add(new LinearLayout(ORIENT_VERTICAL)); + + statsView_ = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); + statsView_->SetVisibility(V_GONE); + + LinearLayout *statsTopBar = statsView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + ScrollView *statsScroll = statsView_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); + statsContainer_ = statsScroll->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + + // leftColumn->Add(new Choice(dev->T("By Address")))->OnClick.Handle(this, &JitCompareScreen::OnSelectBlock); + leftColumn->Add(new Choice(dev->T("All")))->OnClick.Add([=](UI::EventParams &e) { + listType_ = ListType::ALL_BLOCKS; + viewMode_ = ViewMode::BLOCK_LIST; + UpdateDisasm(); + return UI::EVENT_DONE; + }); + leftColumn->Add(new Choice(dev->T("FPU")))->OnClick.Add([=](UI::EventParams &e) { + listType_ = ListType::FPU_BLOCKS; + viewMode_ = ViewMode::BLOCK_LIST; + UpdateDisasm(); + return UI::EVENT_DONE; + }); + leftColumn->Add(new Choice(dev->T("VFPU")))->OnClick.Add([=](UI::EventParams &e) { + listType_ = ListType::VFPU_BLOCKS; + viewMode_ = ViewMode::BLOCK_LIST; + UpdateDisasm(); + return UI::EVENT_DONE; + }); + + leftColumn->Add(new Choice(dev->T("Stats")))->OnClick.Handle(this, &JitCompareScreen::OnShowStats); + leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); + UpdateDisasm(); +} + +void JitCompareScreen::FillBlockList() { + JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface(); + blockList_.clear(); + int64_t sumTotalNanos = 0; + int64_t sumExecutions = 0; + bool profiling = blockCacheDebug->SupportsProfiling(); + for (int i = 0; i < blockCacheDebug->GetNumBlocks(); i++) { + if (!blockCacheDebug->IsValidBlock(i)) { + continue; + } + + switch (listType_) { + case ListType::ALL_BLOCKS: + blockList_.push_back(i); + break; + case ListType::FPU_BLOCKS: + case ListType::VFPU_BLOCKS: + { + const uint64_t flags = listType_ == ListType::FPU_BLOCKS ? IS_FPU : IS_VFPU; + // const uint64_t antiFlags = IS_SYSCALL; + const uint64_t antiFlags = 0; + JitBlockMeta meta = blockCacheDebug->GetBlockMeta(i); + if (meta.valid) { + for (u32 addr = meta.addr; addr < meta.addr + meta.sizeInBytes; addr += 4) { + MIPSOpcode opcode = Memory::Read_Instruction(addr); + MIPSInfo info = MIPSGetInfo(opcode); + if ((info & flags) && !(info & antiFlags)) { + blockList_.push_back(i); + break; + } + } + } + } + default: + break; + } + + if (profiling) { + JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(i); + sumTotalNanos += stats.totalNanos; + sumExecutions += stats.executions; + } + } + + sumTotalNanos_ = sumTotalNanos; + sumExecutions_ = sumExecutions; + + if (listSort_ == ListSort::BLOCK_NUM) { + // Already sorted, effectively. + return; + } + + std::sort(blockList_.begin(), blockList_.end(), [=](const int &a_index, const int &b_index) { + // First, check metadata sorts. + switch (listSort_) { + case ListSort::BLOCK_LENGTH_DESC: + { + JitBlockMeta a_meta = blockCacheDebug->GetBlockMeta(a_index); + JitBlockMeta b_meta = blockCacheDebug->GetBlockMeta(b_index); + return a_meta.sizeInBytes > b_meta.sizeInBytes; // reverse for descending + } + case ListSort::BLOCK_LENGTH_ASC: + { + JitBlockMeta a_meta = blockCacheDebug->GetBlockMeta(a_index); + JitBlockMeta b_meta = blockCacheDebug->GetBlockMeta(b_index); + return a_meta.sizeInBytes < b_meta.sizeInBytes; + } + default: + break; + } + JitBlockProfileStats a_stats = blockCacheDebug->GetBlockProfileStats(a_index); + JitBlockProfileStats b_stats = blockCacheDebug->GetBlockProfileStats(b_index); + switch (listSort_) { + case ListSort::EXECUTIONS: + return a_stats.executions > b_stats.executions; + case ListSort::TIME_SPENT: + return a_stats.totalNanos > b_stats.totalNanos; + default: + return false; + } + }); +} + +void JitCompareScreen::UpdateDisasm() { + leftDisasm_->Clear(); + rightDisasm_->Clear(); + + using namespace UI; + + if (!MIPSComp::jit) { + return; + } + + JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface(); + if (viewMode_ == ViewMode::DISASM && (currentBlock_ < 0 || currentBlock_ >= (int)blockList_.size())) { + viewMode_ = ViewMode::BLOCK_LIST; + } + + FillBlockList(); + Flip(); + + if (viewMode_ == ViewMode::DISASM) { + char temp[256]; + snprintf(temp, sizeof(temp), "%d/%d", currentBlock_, (int)blockList_.size()); + blockName_->SetText(temp); + + int blockNum = blockList_[currentBlock_]; + + if (!blockCacheDebug->IsValidBlock(blockNum)) { + auto dev = GetI18NCategory(I18NCat::DEVELOPER); + leftDisasm_->Add(new TextView(dev->T("No block"))); + rightDisasm_->Add(new TextView(dev->T("No block"))); + blockStats_->SetText(""); + return; + } + + JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(blockNum); + snprintf(temp, sizeof(temp), "%08x", debugInfo.originalAddress); + blockAddr_->SetText(temp); + + // Alright. First generate the MIPS disassembly. + + // TODO: Need a way to communicate branch continuing. + for (const auto &line : debugInfo.origDisasm) { + leftDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true); + } + + // TODO : When we have both target and IR, need a third column. + if (debugInfo.targetDisasm.size()) { + for (const auto &line : debugInfo.targetDisasm) { + rightDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true); + } + } else { + for (const auto &line : debugInfo.irDisasm) { + rightDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true); + } + } + + int numMips = leftDisasm_->GetNumSubviews(); + int numHost = rightDisasm_->GetNumSubviews(); + double bloat = 100.0 * numHost / numMips; + if (blockCacheDebug->SupportsProfiling()) { + JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(blockNum); + int execs = (int)stats.executions; + double us = (double)stats.totalNanos / 1000000.0; + double percentage = 100.0 * (double)stats.totalNanos / (double)sumTotalNanos_; + snprintf(temp, sizeof(temp), "%d runs, %0.2f ms, %0.2f%%, bloat: %0.1f%%", execs, us, percentage, bloat); + } else { + snprintf(temp, sizeof(temp), "bloat: %0.1f%%", bloat); + } + blockStats_->SetText(temp); + } else if (viewMode_ == ViewMode::BLOCK_LIST) { + blockListContainer_->Clear(); + bool profiling = blockCacheDebug->SupportsProfiling(); + for (int i = 0; i < std::min(100, (int)blockList_.size()); i++) { + int blockNum = blockList_[i]; + JitBlockMeta meta = blockCacheDebug->GetBlockMeta(blockNum); + char temp[512], small[512]; + if (profiling) { + JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(blockNum); + int execs = (int)stats.executions; + double us = (double)stats.totalNanos / 1000000.0; + double percentage = 100.0 * (double)stats.totalNanos / (double)sumTotalNanos_; + snprintf(temp, sizeof(temp), "%08x: %d instrs (%d runs, %0.2f ms, %0.2f%%)", meta.addr, meta.sizeInBytes / 4, execs, us, percentage); + } else { + snprintf(temp, sizeof(temp), "%08x: %d instrs", meta.addr, meta.sizeInBytes / 4); + } + snprintf(small, sizeof(small), "Small text"); + Choice *blockChoice = blockListContainer_->Add(new Choice(temp, small)); + blockChoice->OnClick.Handle(this, &JitCompareScreen::OnBlockClick); + } + } else { // viewMode_ == ViewMode::STATS + statsContainer_->Clear(); + + BlockCacheStats bcStats; + blockCacheDebug->ComputeStats(bcStats); + + char stats[1024]; + snprintf(stats, sizeof(stats), + "Num blocks: %d\n" + "Average Bloat: %0.2f%%\n" + "Min Bloat: %0.2f%% (%08x)\n" + "Max Bloat: %0.2f%% (%08x)\n", + blockCacheDebug->GetNumBlocks(), + 100.0 * bcStats.avgBloat, + 100.0 * bcStats.minBloat, bcStats.minBloatBlock, + 100.0 * bcStats.maxBloat, bcStats.maxBloatBlock); + + statsContainer_->Add(new TextView(stats)); + } +} + +UI::EventReturn JitCompareScreen::OnBlockClick(UI::EventParams &e) { + int blockIndex = blockListContainer_->IndexOfSubview(e.v); + if (blockIndex >= 0) { + viewMode_ = ViewMode::DISASM; + currentBlock_ = blockIndex; + UpdateDisasm(); + } + return UI::EVENT_DONE; +} + +UI::EventReturn JitCompareScreen::OnAddressChange(UI::EventParams &e) { + std::lock_guard guard(MIPSComp::jitLock); + if (!MIPSComp::jit) { + return UI::EVENT_DONE; + } + JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface(); + if (!blockCache) + return UI::EVENT_DONE; + u32 addr; + if (blockAddr_->GetText().size() > 8) + return UI::EVENT_DONE; + if (1 == sscanf(blockAddr_->GetText().c_str(), "%08x", &addr)) { + if (Memory::IsValidAddress(addr)) { + currentBlock_ = blockCache->GetBlockNumberFromStartAddress(addr); + UpdateDisasm(); + } + } + return UI::EVENT_DONE; +} + +UI::EventReturn JitCompareScreen::OnShowStats(UI::EventParams &e) { + std::lock_guard guard(MIPSComp::jitLock); + if (!MIPSComp::jit) { + return UI::EVENT_DONE; + } + + viewMode_ = ViewMode::STATS; + UpdateDisasm(); + return UI::EVENT_DONE; +} + + +UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) { + auto dev = GetI18NCategory(I18NCat::DEVELOPER); + + auto addressPrompt = new AddressPromptScreen(dev->T("Block address")); + addressPrompt->OnChoice.Handle(this, &JitCompareScreen::OnBlockAddress); + screenManager()->push(addressPrompt); + return UI::EVENT_DONE; +} + +UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) { + std::lock_guard guard(MIPSComp::jitLock); + if (!MIPSComp::jit) { + return UI::EVENT_DONE; + } + + JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface(); + if (!blockCache) + return UI::EVENT_DONE; + + if (Memory::IsValidAddress(e.a)) { + currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a); + } else { + currentBlock_ = -1; + } + UpdateDisasm(); + return UI::EVENT_DONE; +} + +/* +void JitCompareScreen::OnRandomBlock(int flag) { + std::lock_guard guard(MIPSComp::jitLock); + if (!MIPSComp::jit) { + return; + } + JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface(); + if (!blockCache) + return; + + int numBlocks = blockCache->GetNumBlocks(); + if (numBlocks > 0) { + bool anyWanted = false; + int tries = 0; + while (!anyWanted && tries < numBlocks) { + currentBlock_ = rand() % numBlocks; + if (blockCache->IsValidBlock(currentBlock_)) { + JitBlockDebugInfo b = blockCache->GetBlockDebugInfo(currentBlock_); + u32 mipsBytes = (u32)b.origDisasm.size() * 4; + for (u32 addr = b.originalAddress; addr < b.originalAddress + mipsBytes; addr += 4) { + MIPSOpcode opcode = Memory::Read_Instruction(addr); + if (MIPSGetInfo(opcode) & flag) { + char temp[256]; + MIPSDisAsm(opcode, addr, temp, sizeof(temp)); + // INFO_LOG(Log::HLE, "Stopping at random instruction: %08x %s", addr, temp); + anyWanted = true; + break; + } + } + } + tries++; + } + + if (!anyWanted) + currentBlock_ = -1; + } + UpdateDisasm(); +}*/ + +void AddressPromptScreen::CreatePopupContents(UI::ViewGroup *parent) { + using namespace UI; + + auto dev = GetI18NCategory(I18NCat::DEVELOPER); + + addrView_ = new TextView(dev->T("Enter address"), ALIGN_HCENTER, false); + parent->Add(addrView_); + + ViewGroup *grid = new GridLayout(GridLayoutSettings(60, 40)); + parent->Add(grid); + + for (int i = 0; i < 16; ++i) { + char temp[16]; + snprintf(temp, 16, " %X ", i); + buttons_[i] = new Button(temp); + grid->Add(buttons_[i])->OnClick.Handle(this, &AddressPromptScreen::OnDigitButton); + } + + parent->Add(new Button(dev->T("Backspace")))->OnClick.Handle(this, &AddressPromptScreen::OnBackspace); +} + +void AddressPromptScreen::OnCompleted(DialogResult result) { + if (result == DR_OK) { + UI::EventParams e{}; + e.v = root_; + e.a = addr_; + OnChoice.Trigger(e); + } +} + +UI::EventReturn AddressPromptScreen::OnDigitButton(UI::EventParams &e) { + for (int i = 0; i < 16; ++i) { + if (buttons_[i] == e.v) { + AddDigit(i); + } + } + return UI::EVENT_DONE; +} + +UI::EventReturn AddressPromptScreen::OnBackspace(UI::EventParams &e) { + BackspaceDigit(); + return UI::EVENT_DONE; +} + +void AddressPromptScreen::AddDigit(int n) { + if ((addr_ & 0xF0000000) == 0) { + addr_ = addr_ * 16 + n; + } + UpdatePreviewDigits(); +} + +void AddressPromptScreen::BackspaceDigit() { + addr_ /= 16; + UpdatePreviewDigits(); +} + +void AddressPromptScreen::UpdatePreviewDigits() { + if (addr_ != 0) { + char temp[32]; + snprintf(temp, 32, "%8X", addr_); + addrView_->SetText(temp); + } else { + auto dev = GetI18NCategory(I18NCat::DEVELOPER); + addrView_->SetText(dev->T("Enter address")); + } +} + +bool AddressPromptScreen::key(const KeyInput &key) { + if (key.flags & KEY_DOWN) { + if (key.keyCode >= NKCODE_0 && key.keyCode <= NKCODE_9) { + AddDigit(key.keyCode - NKCODE_0); + } else if (key.keyCode >= NKCODE_A && key.keyCode <= NKCODE_F) { + AddDigit(10 + key.keyCode - NKCODE_A); + // NKCODE_DEL is backspace. + } else if (key.keyCode == NKCODE_DEL) { + BackspaceDigit(); + } else if (key.keyCode == NKCODE_ENTER) { + TriggerFinish(DR_OK); + } else { + return UIDialogScreen::key(key); + } + } else { + return UIDialogScreen::key(key); + } + return true; +} diff --git a/UI/JitCompareScreen.h b/UI/JitCompareScreen.h new file mode 100644 index 0000000000..8a3828f1e4 --- /dev/null +++ b/UI/JitCompareScreen.h @@ -0,0 +1,92 @@ +#pragma once +#include "Common/UI/UIScreen.h" +#include "UI/MiscScreens.h" + +class JitCompareScreen : public UIDialogScreenWithBackground { +public: + JitCompareScreen(); + void CreateViews() override; + + const char *tag() const override { return "JitCompare"; } + +private: + void Flip(); + void UpdateDisasm(); + + // Uses the current ListType + void FillBlockList(); + + UI::LinearLayout *comparisonView_; + UI::LinearLayout *leftDisasm_; + UI::LinearLayout *rightDisasm_; + + UI::LinearLayout *blockListView_; + UI::LinearLayout *blockListContainer_; + + UI::LinearLayout *statsView_; + UI::LinearLayout *statsContainer_; + + UI::EventReturn OnSelectBlock(UI::EventParams &e); + UI::EventReturn OnBlockAddress(UI::EventParams &e); + UI::EventReturn OnAddressChange(UI::EventParams &e); + UI::EventReturn OnShowStats(UI::EventParams &e); + UI::EventReturn OnBlockClick(UI::EventParams &e); + + // To switch, change the below things and call RecreateViews(); + enum class ViewMode { + BLOCK_LIST, + DISASM, + STATS, + }; + enum class ListType { + ALL_BLOCKS, + FPU_BLOCKS, + VFPU_BLOCKS, + }; + enum class ListSort { + BLOCK_NUM, + BLOCK_LENGTH_DESC, + BLOCK_LENGTH_ASC, + TIME_SPENT, + EXECUTIONS, + MAX + }; + ViewMode viewMode_ = ViewMode::BLOCK_LIST; + ListType listType_ = ListType::ALL_BLOCKS; + ListSort listSort_ = ListSort::TIME_SPENT; + + int currentBlock_ = -1; // For DISASM mode + int64_t sumTotalNanos_ = 0; + int64_t sumExecutions_ = 0; + std::vector blockList_; // for BLOCK_LIST mode + + UI::TextView *blockName_; + UI::TextEdit *blockAddr_; + UI::TextView *blockStats_; +}; + +class AddressPromptScreen : public PopupScreen { +public: + AddressPromptScreen(std::string_view title) : PopupScreen(title, "OK", "Cancel") {} + + const char *tag() const override { return "AddressPrompt"; } + + bool key(const KeyInput &key) override; + + UI::Event OnChoice; + +protected: + void CreatePopupContents(UI::ViewGroup *parent) override; + void OnCompleted(DialogResult result) override; + UI::EventReturn OnDigitButton(UI::EventParams &e); + UI::EventReturn OnBackspace(UI::EventParams &e); + +private: + void AddDigit(int n); + void BackspaceDigit(); + void UpdatePreviewDigits(); + + UI::TextView *addrView_ = nullptr; + UI::Button *buttons_[16]{}; + unsigned int addr_ = 0; +}; diff --git a/UI/JoystickHistoryView.cpp b/UI/JoystickHistoryView.cpp index 3aa1828f9c..f82bae8e07 100644 --- a/UI/JoystickHistoryView.cpp +++ b/UI/JoystickHistoryView.cpp @@ -15,7 +15,7 @@ void JoystickHistoryView::Draw(UIContext &dc) { float minRadius = std::min(bounds_.w, bounds_.h) * 0.5f - image->w; dc.Begin(); Bounds textBounds(bounds_.x, bounds_.centerY() + minRadius + 5.0, bounds_.w, bounds_.h / 2 - minRadius - 5.0); - dc.DrawTextShadowRect(title_.c_str(), textBounds, 0xFFFFFFFF, ALIGN_TOP | ALIGN_HCENTER | FLAG_WRAP_TEXT); + dc.DrawTextShadowRect(title_, textBounds, 0xFFFFFFFF, ALIGN_TOP | ALIGN_HCENTER | FLAG_WRAP_TEXT); dc.Flush(); dc.BeginNoTex(); dc.Draw()->RectOutline(bounds_.centerX() - minRadius, bounds_.centerY() - minRadius, minRadius * 2.0f, minRadius * 2.0f, 0x80FFFFFF); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index f0e2005bfe..2730803e47 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -333,7 +333,7 @@ void GameButton::Draw(UIContext &dc) { dc.PushScissor(bounds_); const std::string currentTitle = ginfo->GetTitle(); dc.SetFontScale(0.6f, 0.6f); - dc.DrawText(title_.c_str(), bounds_.x + 4.0f, bounds_.centerY(), style.fgColor, ALIGN_VCENTER | ALIGN_LEFT); + dc.DrawText(title_, bounds_.x + 4.0f, bounds_.centerY(), style.fgColor, ALIGN_VCENTER | ALIGN_LEFT); dc.SetFontScale(1.0f, 1.0f); title_ = currentTitle; dc.Draw()->Flush(); @@ -348,15 +348,15 @@ void GameButton::Draw(UIContext &dc) { title_ = ReplaceAll(title_, "\n", " "); } - dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, title_.c_str(), &tw, &th, 0); + dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, title_, &tw, &th, 0); int availableWidth = bounds_.w - 150; if (g_Config.bShowIDOnGameIcon) { float vw, vh; - dc.MeasureText(dc.GetFontStyle(), 0.7f, 0.7f, ginfo->id_version.c_str(), &vw, &vh, 0); + dc.MeasureText(dc.GetFontStyle(), 0.7f, 0.7f, ginfo->id_version, &vw, &vh, 0); availableWidth -= vw + 20; dc.SetFontScale(0.7f, 0.7f); - dc.DrawText(ginfo->id_version.c_str(), bounds_.x + availableWidth + 160, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.DrawText(ginfo->id_version, bounds_.x + availableWidth + 160, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); dc.SetFontScale(1.0f, 1.0f); } float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f; @@ -369,7 +369,7 @@ void GameButton::Draw(UIContext &dc) { tb.w = availableWidth; dc.PushScissor(tb); } - dc.DrawText(title_.c_str(), bounds_.x + tx, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.DrawText(title_, bounds_.x + tx, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); if (availableWidth < tw) { dc.PopScissor(); } @@ -378,7 +378,7 @@ void GameButton::Draw(UIContext &dc) { } else if (!texture) { dc.Draw()->Flush(); dc.PushScissor(bounds_); - dc.DrawText(title_.c_str(), bounds_.x + 4, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.DrawText(title_, bounds_.x + 4, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); dc.Draw()->Flush(); dc.PopScissor(); } else { @@ -416,8 +416,8 @@ void GameButton::Draw(UIContext &dc) { } if (gridStyle_ && g_Config.bShowIDOnGameIcon) { dc.SetFontScale(0.5f*g_Config.fGameGridScale, 0.5f*g_Config.fGameGridScale); - dc.DrawText(ginfo->id_version.c_str(), x+5, y+1, 0xFF000000, ALIGN_TOPLEFT); - dc.DrawText(ginfo->id_version.c_str(), x+4, y, dc.theme->infoStyle.fgColor, ALIGN_TOPLEFT); + dc.DrawText(ginfo->id_version, x+5, y+1, 0xFF000000, ALIGN_TOPLEFT); + dc.DrawText(ginfo->id_version, x+4, y, dc.theme->infoStyle.fgColor, ALIGN_TOPLEFT); dc.SetFontScale(1.0f, 1.0f); } if (overlayColor) { @@ -467,7 +467,7 @@ void DirButton::Draw(UIContext &dc) { dc.FillRect(style.background, bounds_); - std::string text(GetText()); + std::string_view text(GetText()); ImageID image = ImageID("I_FOLDER"); if (text == "..") { @@ -475,7 +475,7 @@ void DirButton::Draw(UIContext &dc) { } float tw, th; - dc.MeasureText(dc.GetFontStyle(), gridStyle_ ? g_Config.fGameGridScale : 1.0, gridStyle_ ? g_Config.fGameGridScale : 1.0, text.c_str(), &tw, &th, 0); + dc.MeasureText(dc.GetFontStyle(), gridStyle_ ? g_Config.fGameGridScale : 1.0, gridStyle_ ? g_Config.fGameGridScale : 1.0, text, &tw, &th, 0); bool compact = bounds_.w < 180 * (gridStyle_ ? g_Config.fGameGridScale : 1.0); @@ -486,7 +486,7 @@ void DirButton::Draw(UIContext &dc) { // No icon, except "up" dc.PushScissor(bounds_); if (image == ImageID("I_FOLDER")) { - dc.DrawText(text.c_str(), bounds_.x + 5, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.DrawText(text, bounds_.x + 5, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); } else { dc.Draw()->DrawImage(image, bounds_.centerX(), bounds_.centerY(), gridStyle_ ? g_Config.fGameGridScale : 1.0, style.fgColor, ALIGN_CENTER); } @@ -498,7 +498,7 @@ void DirButton::Draw(UIContext &dc) { scissor = true; } dc.Draw()->DrawImage(image, bounds_.x + 72, bounds_.centerY(), 0.88f*(gridStyle_ ? g_Config.fGameGridScale : 1.0), style.fgColor, ALIGN_CENTER); - dc.DrawText(text.c_str(), bounds_.x + 150, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.DrawText(text, bounds_.x + 150, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); if (scissor) { dc.PopScissor(); @@ -510,10 +510,21 @@ void DirButton::Draw(UIContext &dc) { } GameBrowser::GameBrowser(int token, const Path &path, BrowseFlags browseFlags, bool *gridStyle, ScreenManager *screenManager, std::string_view lastText, std::string_view lastLink, UI::LayoutParams *layoutParams) - : LinearLayout(UI::ORIENT_VERTICAL, layoutParams), path_(path), gridStyle_(gridStyle), browseFlags_(browseFlags), lastText_(lastText), lastLink_(lastLink), screenManager_(screenManager), token_(token) { + : LinearLayout(UI::ORIENT_VERTICAL, layoutParams), gridStyle_(gridStyle), browseFlags_(browseFlags), lastText_(lastText), lastLink_(lastLink), screenManager_(screenManager), token_(token) { using namespace UI; path_.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION)); - path_.SetRootAlias("ms:", GetSysDirectory(DIRECTORY_MEMSTICK_ROOT).ToVisualString() + "/"); + Path memstickRoot = GetSysDirectory(DIRECTORY_MEMSTICK_ROOT); + if (memstickRoot == GetSysDirectory(DIRECTORY_PSP)) { + path_.SetRootAlias("ms:/PSP/", memstickRoot); + } else { + path_.SetRootAlias("ms:/", memstickRoot); + } + if (System_GetPropertyBool(SYSPROP_LIMITED_FILE_BROWSING) && + (path.Type() == PathType::NATIVE || path.Type() == PathType::CONTENT_URI)) { + // Note: We don't restrict if the path is HTTPS, otherwise remote disc streaming breaks! + path_.RestrictToRoot(GetSysDirectory(DIRECTORY_MEMSTICK_ROOT)); + } + path_.SetPath(path); Refresh(); } @@ -648,7 +659,7 @@ Path GameBrowser::HomePath() { if (!homePath_.empty()) { return homePath_; } -#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) || defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP) +#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) || defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS) return g_Config.memStickDirectory; #else return Path(getenv("HOME")); @@ -684,8 +695,12 @@ bool GameBrowser::HasSpecialFiles(std::vector &filenames) { void GameBrowser::Update() { LinearLayout::Update(); - if (listingPending_ && path_.IsListingReady()) { + if (refreshPending_) { + path_.Refresh(); + } + if ((listingPending_ && path_.IsListingReady()) || refreshPending_) { Refresh(); + refreshPending_ = false; } if (searchPending_) { ApplySearchFilter(); @@ -769,7 +784,11 @@ void GameBrowser::Refresh() { if (System_GetPropertyBool(SYSPROP_HAS_ADDITIONAL_STORAGE)) { topBar->Add(new Choice(ImageID("I_SDCARD"), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Handle(this, &GameBrowser::StorageClick); } -#if PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(MAC) +#if PPSSPP_PLATFORM(IOS_APP_STORE) + // Don't show a browse button, not meaningful to browse outside the documents folder it seems, + // as we can't list things like document folders of another app, as far as I can tell. + // However, we do show a Load.. button for picking individual files, that seems to work. +#elif PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(MAC) // on Darwin, we don't show the 'Browse' text alongside the image // we show just the image, because we don't need to emphasize the button on Darwin topBar->Add(new Choice(ImageID("I_FOLDER_OPEN"), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Handle(this, &GameBrowser::BrowseClick); @@ -845,6 +864,8 @@ void GameBrowser::Refresh() { listingPending_ = !path_.IsListingReady(); + // TODO: If listing failed, show a special error message. + std::vector filenames; if (HasSpecialFiles(filenames)) { for (size_t i = 0; i < filenames.size(); i++) { @@ -1116,12 +1137,19 @@ void MainScreen::CreateViews() { ScrollView *scrollHomebrew = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); scrollHomebrew->SetTag("MainScreenHomebrew"); +#if PPSSPP_PLATFORM(IOS) + std::string_view getGamesUri = "https://www.ppsspp.org/getgames_ios"; + std::string_view getHomebrewUri = "https://www.ppsspp.org/gethomebrew_ios"; +#else + std::string_view getGamesUri = "https://www.ppsspp.org/getgames"; + std::string_view getHomebrewUri = "https://www.ppsspp.org/gethomebrew"; +#endif GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD, &g_Config.bGridView2, screenManager(), - mm->T("How to get games"), "https://www.ppsspp.org/getgames", + mm->T("How to get games"), getGamesUri, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); GameBrowser *tabHomebrew = new GameBrowser(GetRequesterToken(), GetSysDirectory(DIRECTORY_GAME), BrowseFlags::HOMEBREW_STORE, &g_Config.bGridView3, screenManager(), - mm->T("How to get homebrew & demos", "How to get homebrew && demos"), "https://www.ppsspp.org/gethomebrew", + mm->T("How to get homebrew & demos", "How to get homebrew && demos"), getHomebrewUri, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); scrollAllGames_->Add(tabAllGames); @@ -1264,7 +1292,6 @@ void MainScreen::CreateViews() { if (!vertical) { rightColumnChoices->Add(new Choice(mm->T("www.ppsspp.org")))->OnClick.Handle(this, &MainScreen::OnPPSSPPOrg); - if (!System_GetPropertyBool(SYSPROP_APP_GOLD) && (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) != DEVICE_TYPE_VR)) { Choice *gold = rightColumnChoices->Add(new Choice(mm->T("Buy PPSSPP Gold"))); gold->OnClick.Handle(this, &MainScreen::OnSupport); @@ -1273,7 +1300,10 @@ void MainScreen::CreateViews() { } rightColumnChoices->Add(new Spacer(25.0)); +#if !PPSSPP_PLATFORM(IOS_APP_STORE) + // Officially, iOS apps should not have exit buttons. Remove it to maximize app store review chances. rightColumnChoices->Add(new Choice(mm->T("Exit")))->OnClick.Handle(this, &MainScreen::OnExit); +#endif if (vertical) { root_ = new LinearLayout(ORIENT_VERTICAL); @@ -1514,6 +1544,7 @@ UI::EventReturn MainScreen::OnGameHighlight(UI::EventParams &e) { } UI::EventReturn MainScreen::OnGameSelectedInstant(UI::EventParams &e) { + // TODO: This is really not necessary here in all cases. g_Config.Save("MainScreen::OnGameSelectedInstant"); ScreenManager *screen = screenManager(); LaunchFile(screen, Path(e.s)); @@ -1531,7 +1562,9 @@ UI::EventReturn MainScreen::OnCredits(UI::EventParams &e) { } UI::EventReturn MainScreen::OnSupport(UI::EventParams &e) { -#ifdef __ANDROID__ +#if PPSSPP_PLATFORM(IOS_APP_STORE) + System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://apps.apple.com/us/app/ppsspp-gold-psp-emulator/id6502287918"); +#elif PPSSPP_PLATFORM(ANDROID) System_LaunchUrl(LaunchUrlType::BROWSER_URL, "market://details?id=org.ppsspp.ppssppgold"); #else System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/buygold"); @@ -1587,6 +1620,12 @@ void MainScreen::dialogFinished(const Screen *dialog, DialogResult result) { g_BackgroundAudio.SetGame(Path()); } } + if (tag == "InstallZip") { + INFO_LOG(Log::System, "InstallZip finished, refreshing"); + if (gameBrowsers_.size() >= 2) { + gameBrowsers_[1]->RequestRefresh(); + } + } } void UmdReplaceScreen::CreateViews() { diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 26cbf2d463..026f967410 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -55,6 +55,9 @@ public: void ApplySearchFilter(const std::string &filter); void Draw(UIContext &dc) override; void Update() override; + void RequestRefresh() { + refreshPending_ = true; + } void SetHomePath(const Path &path) { homePath_ = path; @@ -106,6 +109,7 @@ private: Path focusGamePath_; bool listingPending_ = false; bool searchPending_ = false; + bool refreshPending_ = false; float lastScale_ = 1.0f; bool lastLayoutWasGrid_ = true; ScreenManager *screenManager_; diff --git a/UI/MemStickScreen.cpp b/UI/MemStickScreen.cpp index e1ce789268..173206695d 100644 --- a/UI/MemStickScreen.cpp +++ b/UI/MemStickScreen.cpp @@ -77,7 +77,7 @@ MemStickScreen::MemStickScreen(bool initialSetup) if (System_GetPropertyBool(SYSPROP_ANDROID_SCOPED_STORAGE)) { choice_ = CHOICE_BROWSE_FOLDER; } else { - WARN_LOG_REPORT(SYSTEM, "Scoped storage not enabled - shouldn't be in MemStickScreen at initial setup"); + WARN_LOG_REPORT(Log::System, "Scoped storage not enabled - shouldn't be in MemStickScreen at initial setup"); choice_ = CHOICE_STORAGE_ROOT; // Shouldn't really be here in initial setup. } @@ -268,7 +268,7 @@ void MemStickScreen::CreateViews() { rightColumnItems->Add(new UI::Choice(iz->T("WhatsThis", "What's this?")))->OnClick.Handle(this, &MemStickScreen::OnHelp); } - INFO_LOG(SYSTEM, "MemStickScreen: initialSetup=%d", (int)initialSetup_); + INFO_LOG(Log::System, "MemStickScreen: initialSetup=%d", (int)initialSetup_); } UI::EventReturn MemStickScreen::OnHelp(UI::EventParams ¶ms) { @@ -302,7 +302,7 @@ UI::EventReturn MemStickScreen::OnConfirmClick(UI::EventParams ¶ms) { } UI::EventReturn MemStickScreen::SetFolderManually(UI::EventParams ¶ms) { - // The old way, from before scoped storage. + // The old way, from before scoped storage. Write in the full path. #if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) auto sy = GetI18NCategory(I18NCat::SYSTEM); System_InputBoxGetString(GetRequesterToken(), sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](const std::string &value, int) { @@ -342,10 +342,10 @@ UI::EventReturn MemStickScreen::SetFolderManually(UI::EventParams ¶ms) { std::string oldNewPath = newPath; FixPathCase(Path(""), newPath, FixPathCaseBehavior::FPC_FILE_MUST_EXIST); if (oldNewPath != newPath) { - NOTICE_LOG(IO, "Fixed path case: %s -> %s", oldNewPath.c_str(), newPath.c_str()); + NOTICE_LOG(Log::IO, "Fixed path case: %s -> %s", oldNewPath.c_str(), newPath.c_str()); pendingMemStickFolder = Path(newPath); } else { - NOTICE_LOG(IO, "Failed to fix case of path %s (result: %s)", newPath.c_str(), oldNewPath.c_str()); + NOTICE_LOG(Log::IO, "Failed to fix case of path %s (result: %s)", newPath.c_str(), oldNewPath.c_str()); } } @@ -380,7 +380,7 @@ UI::EventReturn MemStickScreen::UseInternalStorage(UI::EventParams ¶ms) { TriggerFinish(DialogResult::DR_OK); } else { // This can't really happen?? Not worth making an error message. - ERROR_LOG_REPORT(SYSTEM, "Could not switch memstick path in setup (internal)"); + ERROR_LOG_REPORT(Log::System, "Could not switch memstick path in setup (internal)"); } // Don't have a confirmation dialog that would otherwise do it for us, need to just switch directly to the main screen. screenManager()->switchScreen(new MainScreen()); @@ -404,7 +404,7 @@ UI::EventReturn MemStickScreen::UseStorageRoot(UI::EventParams ¶ms) { TriggerFinish(DialogResult::DR_OK); } else { // This can't really happen?? Not worth making an error message. - ERROR_LOG_REPORT(SYSTEM, "Could not switch memstick path in setup"); + ERROR_LOG_REPORT(Log::System, "Could not switch memstick path in setup"); } } else if (pendingMemStickFolder != g_Config.memStickDirectory) { // Always ask for confirmation when called from the UI. Likely there's already some data. @@ -420,7 +420,7 @@ UI::EventReturn MemStickScreen::Browse(UI::EventParams ¶ms) { auto mm = GetI18NCategory(I18NCat::MAINMENU); System_BrowseForFolder(GetRequesterToken(), mm->T("Choose folder"), g_Config.memStickDirectory, [=](const std::string &value, int) { Path pendingMemStickFolder = Path(value); - INFO_LOG(SYSTEM, "Got folder: '%s'", pendingMemStickFolder.c_str()); + INFO_LOG(Log::System, "Got folder: '%s'", pendingMemStickFolder.c_str()); // Browse finished. Let's pop up the confirmation dialog. if (!pendingMemStickFolder.empty() && pendingMemStickFolder == g_Config.memStickDirectory && File::IsDirectory(pendingMemStickFolder)) { auto iz = GetI18NCategory(I18NCat::MEMSTICK); @@ -439,7 +439,7 @@ UI::EventReturn MemStickScreen::Browse(UI::EventParams ¶ms) { void MemStickScreen::dialogFinished(const Screen *dialog, DialogResult result) { if (result == DialogResult::DR_OK) { - INFO_LOG(SYSTEM, "Confirmation screen done - moving on."); + INFO_LOG(Log::System, "Confirmation screen done - moving on."); // There's a screen manager bug if we call TriggerFinish directly. // Can't be bothered right now, so we pick this up in update(). done_ = true; @@ -456,7 +456,7 @@ void MemStickScreen::update() { } ConfirmMemstickMoveScreen::ConfirmMemstickMoveScreen(Path newMemstickFolder, bool initialSetup) - : newMemstickFolder_(newMemstickFolder), initialSetup_(initialSetup) { + : newMemstickFolder_(newMemstickFolder), initialSetup_(initialSetup), progressReporter_() { existingFilesInNewFolder_ = FolderSeemsToBeUsed(newMemstickFolder); if (initialSetup_) { moveData_ = false; @@ -465,7 +465,7 @@ ConfirmMemstickMoveScreen::ConfirmMemstickMoveScreen(Path newMemstickFolder, boo ConfirmMemstickMoveScreen::~ConfirmMemstickMoveScreen() { if (moveDataTask_) { - INFO_LOG(SYSTEM, "Move Data task still running, blocking on it"); + INFO_LOG(Log::System, "Move Data task still running, blocking on it"); moveDataTask_->BlockUntilReady(); delete moveDataTask_; } @@ -553,12 +553,12 @@ void ConfirmMemstickMoveScreen::update() { if (result) { if (result->success) { progressReporter_.SetProgress(iz->T("Done!")); - INFO_LOG(SYSTEM, "Move data task finished successfully!"); + INFO_LOG(Log::System, "Move data task finished successfully!"); // Succeeded! FinishFolderMove(); } else { progressReporter_.SetProgress(iz->T("Failed to move some files!")); - INFO_LOG(SYSTEM, "Move data task failed!"); + INFO_LOG(Log::System, "Move data task failed!"); // What do we do here? We might be in the middle of a move... Bad. RecreateViews(); } diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index a038f5e6f5..900d7ad778 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -553,7 +553,9 @@ UI::EventReturn PromptScreen::OnNo(UI::EventParams &e) { } void PromptScreen::TriggerFinish(DialogResult result) { - callback_(result == DR_OK || result == DR_YES); + if (callback_) { + callback_(result == DR_OK || result == DR_YES); + } UIDialogScreenWithBackground::TriggerFinish(result); } @@ -976,7 +978,7 @@ void CreditsScreen::DrawForeground(UIContext &dc) { "", "", cr->T("tools", "Free tools used:"), -#ifdef __ANDROID__ +#if PPSSPP_PLATFORM(ANDROID) "Android SDK + NDK", #endif #if defined(USING_QT_UI) @@ -988,6 +990,17 @@ void CreditsScreen::DrawForeground(UIContext &dc) { "CMake", "freetype2", "zlib", + "rcheevos", + "SPIRV-Cross", + "armips", + "Basis Universal", + "cityhash", + "zstd", + "glew", + "libchdr", + "minimp3", + "xxhash", + "naett-http", "PSP SDK", "", "", @@ -1009,7 +1022,6 @@ void CreditsScreen::DrawForeground(UIContext &dc) { cr->T("info5", "PSP is a trademark by Sony, Inc."), }; - // TODO: This is kinda ugly, done on every frame... char temp[256]; if (System_GetPropertyBool(SYSPROP_APP_GOLD)) { @@ -1029,15 +1041,13 @@ void CreditsScreen::DrawForeground(UIContext &dc) { float t = (float)(time_now_d() - startTime_) * 60.0; float y = bounds.y2() - fmodf(t, (float)totalHeight); - std::string line; for (int i = 0; i < numItems; i++) { float alpha = linearInOut(y+32, 64, bounds.y2() - 192, 64); uint32_t textColor = colorAlpha(dc.theme->infoStyle.fgColor, alpha); if (alpha > 0.0f) { dc.SetFontScale(ease(alpha), ease(alpha)); - line = credits[i]; - dc.DrawText(line.c_str(), bounds.centerX(), y, textColor, ALIGN_HCENTER); + dc.DrawText(credits[i], bounds.centerX(), y, textColor, ALIGN_HCENTER); dc.SetFontScale(1.0f, 1.0f); } y += itemHeight; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 692201f107..377ca7ddb4 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -78,7 +78,7 @@ #include "Common/File/FileUtil.h" #include "Common/TimeUtil.h" #include "Common/StringUtils.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Common/MemArena.h" #include "Common/GraphicsContext.h" #include "Common/OSVersion.h" @@ -284,7 +284,7 @@ void PostLoadConfig() { static void CheckFailedGPUBackends() { #ifdef _DEBUG // If you're in debug mode, you probably don't want a fallback. If you're in release mode, use IGNORE below. - NOTICE_LOG(LOADER, "Not checking for failed graphics backends in debug mode"); + NOTICE_LOG(Log::Loader, "Not checking for failed graphics backends in debug mode"); return; #endif @@ -317,14 +317,14 @@ static void CheckFailedGPUBackends() { if (g_Config.sFailedGPUBackends == "IGNORE") return; else if (!g_Config.sFailedGPUBackends.empty()) - ERROR_LOG(LOADER, "Failed graphics backends: %s", g_Config.sFailedGPUBackends.c_str()); + ERROR_LOG(Log::Loader, "Failed graphics backends: %s", g_Config.sFailedGPUBackends.c_str()); // Okay, let's not try a backend in the failed list. g_Config.iGPUBackend = g_Config.NextValidBackend(); if (lastBackend != g_Config.iGPUBackend) { std::string param = GPUBackendToString((GPUBackend)lastBackend) + " -> " + GPUBackendToString((GPUBackend)g_Config.iGPUBackend); System_GraphicsBackendFailedAlert(param); - WARN_LOG(LOADER, "Failed graphics backend switched from %s (%d to %d)", param.c_str(), lastBackend, g_Config.iGPUBackend); + WARN_LOG(Log::Loader, "Failed graphics backend switched from %s (%d to %d)", param.c_str(), lastBackend, g_Config.iGPUBackend); } // And then let's - for now - add the current to the failed list. if (g_Config.sFailedGPUBackends.empty()) { @@ -431,24 +431,24 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch Path memstickDirFile = g_Config.internalDataDirectory / "memstick_dir.txt"; if (File::Exists(memstickDirFile)) { - INFO_LOG(SYSTEM, "Reading '%s' to find memstick dir.", memstickDirFile.c_str()); + INFO_LOG(Log::System, "Reading '%s' to find memstick dir.", memstickDirFile.c_str()); std::string memstickDir; if (File::ReadTextFileToString(memstickDirFile, &memstickDir)) { Path memstickPath(memstickDir); if (!memstickPath.empty() && File::Exists(memstickPath)) { g_Config.memStickDirectory = memstickPath; - INFO_LOG(SYSTEM, "Memstick Directory from memstick_dir.txt: '%s'", g_Config.memStickDirectory.c_str()); + INFO_LOG(Log::System, "Memstick Directory from memstick_dir.txt: '%s'", g_Config.memStickDirectory.c_str()); } else { - ERROR_LOG(SYSTEM, "Couldn't read directory '%s' specified by memstick_dir.txt.", memstickDir.c_str()); + ERROR_LOG(Log::System, "Couldn't read directory '%s' specified by memstick_dir.txt.", memstickDir.c_str()); if (System_GetPropertyBool(SYSPROP_ANDROID_SCOPED_STORAGE)) { // Ask the user to configure a memstick directory. - INFO_LOG(SYSTEM, "Asking the user."); + INFO_LOG(Log::System, "Asking the user."); g_Config.memStickDirectory.clear(); } } } } else { - INFO_LOG(SYSTEM, "No memstick directory file found (tried to open '%s')", memstickDirFile.c_str()); + INFO_LOG(Log::System, "No memstick directory file found (tried to open '%s')", memstickDirFile.c_str()); } // Attempt to create directories after reading the path. @@ -458,7 +458,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch #elif PPSSPP_PLATFORM(UWP) && !defined(__LIBRETRO__) Path memstickDirFile = g_Config.internalDataDirectory / "memstick_dir.txt"; if (File::Exists(memstickDirFile)) { - INFO_LOG(SYSTEM, "Reading '%s' to find memstick dir.", memstickDirFile.c_str()); + INFO_LOG(Log::System, "Reading '%s' to find memstick dir.", memstickDirFile.c_str()); std::string memstickDir; if (File::ReadTextFileToString(memstickDirFile, &memstickDir)) { Path memstickPath(memstickDir); @@ -466,15 +466,15 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch g_Config.memStickDirectory = memstickPath; g_Config.SetSearchPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.Reload(); - INFO_LOG(SYSTEM, "Memstick Directory from memstick_dir.txt: '%s'", g_Config.memStickDirectory.c_str()); + INFO_LOG(Log::System, "Memstick Directory from memstick_dir.txt: '%s'", g_Config.memStickDirectory.c_str()); } else { - ERROR_LOG(SYSTEM, "Couldn't read directory '%s' specified by memstick_dir.txt.", memstickDir.c_str()); + ERROR_LOG(Log::System, "Couldn't read directory '%s' specified by memstick_dir.txt.", memstickDir.c_str()); g_Config.memStickDirectory.clear(); } } } else { - INFO_LOG(SYSTEM, "No memstick directory file found (tried to open '%s')", memstickDirFile.c_str()); + INFO_LOG(Log::System, "No memstick directory file found (tried to open '%s')", memstickDirFile.c_str()); } #elif PPSSPP_PLATFORM(IOS) g_Config.defaultCurrentDirectory = g_Config.internalDataDirectory; @@ -618,21 +618,21 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch // don't already have one. if (!gotBootFilename) { gotBootFilename = true; - INFO_LOG(SYSTEM, "Boot filename found in args: '%s'", argv[i]); + INFO_LOG(Log::System, "Boot filename found in args: '%s'", argv[i]); bool okToLoad = true; bool okToCheck = true; if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) { PermissionStatus status = System_GetPermissionStatus(SYSTEM_PERMISSION_STORAGE); if (status == PERMISSION_STATUS_DENIED) { - ERROR_LOG(IO, "Storage permission denied. Launching without argument."); + ERROR_LOG(Log::IO, "Storage permission denied. Launching without argument."); okToLoad = false; okToCheck = false; } else if (status != PERMISSION_STATUS_GRANTED) { - ERROR_LOG(IO, "Storage permission not granted. Launching without argument check."); + ERROR_LOG(Log::IO, "Storage permission not granted. Launching without argument check."); okToCheck = false; } else { - INFO_LOG(IO, "Storage permission granted."); + INFO_LOG(Log::IO, "Storage permission granted."); } } if (okToLoad) { @@ -640,7 +640,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch // Handle file:/// URIs, since you get those when creating shortcuts on some Android systems. if (startsWith(str, "file:///")) { str = UriDecode(str.substr(7)); - INFO_LOG(IO, "Decoding '%s' to '%s'", argv[i], str.c_str()); + INFO_LOG(Log::IO, "Decoding '%s' to '%s'", argv[i], str.c_str()); } boot_filename = Path(str); @@ -659,7 +659,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } } } else { - fprintf(stderr, "Can only boot one file"); + fprintf(stderr, "Syntax error: Can only boot one file.\nNote: Many command line args need a =, like --appendconfig=FILENAME.ini.\n"); #if defined(_WIN32) || defined(__ANDROID__) // Ignore and proceed. #else @@ -749,10 +749,10 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } } - DEBUG_LOG(SYSTEM, "ScreenManager!"); + DEBUG_LOG(Log::System, "ScreenManager!"); g_screenManager = new ScreenManager(); if (g_Config.memStickDirectory.empty()) { - INFO_LOG(SYSTEM, "No memstick directory! Asking for one to be configured."); + INFO_LOG(Log::System, "No memstick directory! Asking for one to be configured."); g_screenManager->switchScreen(new LogoScreen(AfterLogoScreen::MEMSTICK_SCREEN_INITIAL_SETUP)); } else if (gotoGameSettings) { g_screenManager->switchScreen(new LogoScreen(AfterLogoScreen::TO_GAME_SETTINGS)); @@ -800,7 +800,7 @@ void CallbackPostRender(UIContext *dc, void *userdata); bool CreateGlobalPipelines(); bool NativeInitGraphics(GraphicsContext *graphicsContext) { - INFO_LOG(SYSTEM, "NativeInitGraphics"); + INFO_LOG(Log::System, "NativeInitGraphics"); _assert_msg_(g_screenManager, "No screenmanager, bad init order. Backend = %d", g_Config.iGPUBackend); @@ -813,7 +813,7 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { _assert_(g_draw); if (!CreateGlobalPipelines()) { - ERROR_LOG(G3D, "Failed to create global pipelines"); + ERROR_LOG(Log::G3D, "Failed to create global pipelines"); return false; } @@ -848,7 +848,7 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { if (IsWin7OrHigher()) { winCamera = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::VIDEO); winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr }); - winMic = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::AUDIO); + winMic = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::Audio); winMic->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr }); } #endif @@ -861,7 +861,7 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { gpu->DeviceRestore(g_draw); } - INFO_LOG(SYSTEM, "NativeInitGraphics completed"); + INFO_LOG(Log::System, "NativeInitGraphics completed"); return true; } @@ -875,7 +875,7 @@ bool CreateGlobalPipelines() { ShaderModule *fs_texture_color_2d = g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D); if (!vs_color_2d || !fs_color_2d || !vs_texture_color_2d || !fs_texture_color_2d) { - ERROR_LOG(G3D, "Failed to get shader preset"); + ERROR_LOG(Log::G3D, "Failed to get shader preset"); return false; } @@ -917,7 +917,7 @@ bool CreateGlobalPipelines() { } void NativeShutdownGraphics() { - INFO_LOG(SYSTEM, "NativeShutdownGraphics"); + INFO_LOG(Log::System, "NativeShutdownGraphics"); if (g_screenManager) { g_screenManager->deviceLost(); @@ -965,10 +965,10 @@ void NativeShutdownGraphics() { texColorPipeline = nullptr; } - INFO_LOG(SYSTEM, "NativeShutdownGraphics done"); + INFO_LOG(Log::System, "NativeShutdownGraphics done"); } -static void TakeScreenshot() { +static void TakeScreenshot(Draw::DrawContext *draw) { Path path = GetSysDirectory(DIRECTORY_SCREENSHOT); if (!File::Exists(path)) { File::CreateDir(path); @@ -991,9 +991,19 @@ static void TakeScreenshot() { i++; } - bool success = TakeGameScreenshot(filename, g_Config.bScreenshotsAsPNG ? ScreenshotFormat::PNG : ScreenshotFormat::JPG, SCREENSHOT_OUTPUT); + bool success = TakeGameScreenshot(draw, filename, g_Config.bScreenshotsAsPNG ? ScreenshotFormat::PNG : ScreenshotFormat::JPG, SCREENSHOT_OUTPUT); if (success) { - g_OSD.Show(OSDType::MESSAGE_FILE_LINK, filename.ToString()); + g_OSD.Show(OSDType::MESSAGE_FILE_LINK, filename.ToString(), 0.0f, "screenshot_link"); + if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) { + g_OSD.SetClickCallback("screenshot_link", [](bool clicked, void *data) -> void { + Path *path = reinterpret_cast(data); + if (clicked) { + System_ShowFileInFolder(*path); + } else { + delete path; + } + }, new Path(filename)); + } } else { auto err = GetI18NCategory(I18NCat::ERRORS); g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Could not save screenshot file")); @@ -1002,7 +1012,7 @@ static void TakeScreenshot() { void CallbackPostRender(UIContext *dc, void *userdata) { if (g_TakeScreenshot) { - TakeScreenshot(); + TakeScreenshot(dc->GetDrawContext()); g_TakeScreenshot = false; } } @@ -1098,7 +1108,7 @@ void NativeFrame(GraphicsContext *graphicsContext) { for (const auto &item : toProcess) { if (HandleGlobalMessage(item.message, item.value)) { // TODO: Add a to-string thingy. - INFO_LOG(SYSTEM, "Handled global message: %d / %s", (int)item.message, item.value.c_str()); + INFO_LOG(Log::System, "Handled global message: %d / %s", (int)item.message, item.value.c_str()); } g_screenManager->sendMessage(item.message, item.value.c_str()); } @@ -1147,7 +1157,7 @@ void NativeFrame(GraphicsContext *graphicsContext) { g_draw->Present(presentMode, interval); if (resized) { - INFO_LOG(G3D, "Resized flag set - recalculating bounds"); + INFO_LOG(Log::G3D, "Resized flag set - recalculating bounds"); resized = false; if (uiContext) { @@ -1174,7 +1184,7 @@ void NativeFrame(GraphicsContext *graphicsContext) { System_PostUIMessage(UIMessage::GPU_DISPLAY_RESIZED); #endif } else { - // INFO_LOG(G3D, "Polling graphics context"); + // INFO_LOG(Log::G3D, "Polling graphics context"); graphicsContext->Poll(); } @@ -1244,7 +1254,7 @@ bool HandleGlobalMessage(UIMessage message, const std::string &value) { // and then getting permission), it will get out of sync. So we save and restore g_Config.iGPUBackend. // Ideally we should simply reinitialize graphics to the mode from the config, but there are potential issues. int gpuBackend = g_Config.iGPUBackend; - INFO_LOG(IO, "Reloading config after storage permission grant."); + INFO_LOG(Log::IO, "Reloading config after storage permission grant."); g_Config.Reload(); PostLoadConfig(); g_Config.iGPUBackend = gpuBackend; @@ -1261,16 +1271,16 @@ bool HandleGlobalMessage(UIMessage message, const std::string &value) { bool NativeIsAtTopLevel() { // This might need some synchronization? if (!g_screenManager) { - ERROR_LOG(SYSTEM, "No screen manager active"); + ERROR_LOG(Log::System, "No screen manager active"); return false; } Screen *currentScreen = g_screenManager->topScreen(); if (currentScreen) { bool top = currentScreen->isTopLevel(); - INFO_LOG(SYSTEM, "Screen toplevel: %i", (int)top); + INFO_LOG(Log::System, "Screen toplevel: %i", (int)top); return currentScreen->isTopLevel(); } else { - ERROR_LOG(SYSTEM, "No current screen"); + ERROR_LOG(Log::System, "No current screen"); return false; } } @@ -1312,7 +1322,7 @@ bool NativeKey(const KeyInput &key) { double now = time_now_d(); // VR actions - if (IsVREnabled() && !UpdateVRKeys(key)) { + if ((IsVREnabled() || g_Config.bForceVR) && !UpdateVRKeys(key)) { return false; } @@ -1324,7 +1334,7 @@ bool NativeKey(const KeyInput &key) { } #endif - // INFO_LOG(SYSTEM, "Key code: %i flags: %i", key.keyCode, key.flags); + // INFO_LOG(Log::System, "Key code: %i flags: %i", key.keyCode, key.flags); #if !defined(MOBILE_DEVICE) if (g_Config.bPauseExitsEmulator) { std::vector pspKeys; @@ -1362,7 +1372,7 @@ bool NativeKey(const KeyInput &key) { void NativeAxis(const AxisInput *axes, size_t count) { // VR actions - if (IsVREnabled() && !UpdateVRAxis(axes, count)) { + if ((IsVREnabled() || g_Config.bForceVR) && !UpdateVRAxis(axes, count)) { return; } @@ -1395,7 +1405,7 @@ static void SendMouseDeltaAxis() { HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_X] = mx; HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_Y] = my; - //NOTICE_LOG(SYSTEM, "delta: %0.2f %0.2f mx/my: %0.2f %0.2f dpi: %f sens: %f ", + //NOTICE_LOG(Log::System, "delta: %0.2f %0.2f mx/my: %0.2f %0.2f dpi: %f sens: %f ", // g_mouseDeltaX, g_mouseDeltaY, mx, my, g_display.dpi_scale_x, g_Config.fMouseSensitivity); if (GetUIState() == UISTATE_INGAME || g_Config.bMapMouse) { @@ -1455,7 +1465,7 @@ void System_PostUIMessage(UIMessage message, const std::string &value) { void NativeResized() { // NativeResized can come from any thread so we just set a flag, then process it later. - VERBOSE_LOG(G3D, "NativeResized - setting flag"); + VERBOSE_LOG(Log::G3D, "NativeResized - setting flag"); resized = true; } @@ -1486,13 +1496,13 @@ void NativeShutdown() { g_Config.Save("NativeShutdown"); - INFO_LOG(SYSTEM, "NativeShutdown called"); + INFO_LOG(Log::System, "NativeShutdown called"); g_i18nrepo.LogMissingKeys(); ShutdownWebServer(); -#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) +#if PPSSPP_PLATFORM(ANDROID) System_ExitApp(); #endif @@ -1534,7 +1544,7 @@ static Path GetSecretPath(const char *nameOfSecret) { bool NativeSaveSecret(const char *nameOfSecret, const std::string &data) { Path path = GetSecretPath(nameOfSecret); if (!File::WriteDataToFile(false, data.data(), data.size(), path)) { - WARN_LOG(SYSTEM, "Failed to write secret '%s' to path '%s'", nameOfSecret, path.c_str()); + WARN_LOG(Log::System, "Failed to write secret '%s' to path '%s'", nameOfSecret, path.c_str()); return false; } return true; diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index 73773584e2..c02e5bcbe0 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -164,7 +164,7 @@ static void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLeve UI::Drawable backgroundDark = UI::Drawable(colorAlpha(darkenColor(GetNoticeBackgroundColor(level)), alpha)); dc.FillRect(backgroundDark, bottomTextBounds); dc.SetFontScale(extraTextScale, extraTextScale); - dc.DrawTextRect(details.c_str(), bottomTextBounds, foreGround, (align & FLAG_DYNAMIC_ASCII) | ALIGN_LEFT); + dc.DrawTextRect(details, bottomTextBounds, foreGround, (align & FLAG_DYNAMIC_ASCII) | ALIGN_LEFT); } dc.SetFontScale(1.0f, 1.0f); } @@ -379,7 +379,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) { edges[(size_t)pos].maxWidth = std::max(edges[(size_t)pos].maxWidth, measuredEntry.w); } - std::vector dismissZones; + std::vector clickZones; // Now, perform layout for all 8 edges. for (size_t i = 0; i < (size_t)ScreenEdgePosition::VALUE_COUNT; i++) { @@ -471,7 +471,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) { case OSDType::MESSAGE_FILE_LINK: case OSDType::ACHIEVEMENT_UNLOCKED: // Save the location of the popup, for easy dismissal. - dismissZones.push_back(ClickZone{ (int)j, b }); + clickZones.push_back(ClickZone{ (int)j, b }); break; default: break; @@ -486,7 +486,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) { } std::lock_guard lock(clickMutex_); - clickZones_ = dismissZones; + clickZones_ = clickZones; } std::string OnScreenMessagesView::DescribeText() const { @@ -508,7 +508,7 @@ bool OnScreenMessagesView::Dismiss(float x, float y) { double now = time_now_d(); for (auto &zone : clickZones_) { if (zone.bounds.Contains(x, y)) { - g_OSD.DismissEntry(zone.index, now); + g_OSD.ClickEntry(zone.index, now); dismissed = true; } } diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 2b384e44bb..a5d2e078e8 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -258,7 +258,7 @@ void GamePauseScreen::update() { UIScreen::update(); if (finishNextFrame_) { - TriggerFinish(DR_CANCEL); + TriggerFinish(finishNextFrameResult_); finishNextFrame_ = false; } @@ -412,7 +412,7 @@ void GamePauseScreen::CreateViews() { rightColumnItems->Add(new Choice(pa->T("Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings); rightColumnItems->Add(new Choice(pa->T("Create Game Config")))->OnClick.Handle(this, &GamePauseScreen::OnCreateConfig); } - UI::Choice *displayEditor_ = rightColumnItems->Add(new Choice(gr->T("Display Layout && Effects"))); + UI::Choice *displayEditor_ = rightColumnItems->Add(new Choice(gr->T("Display layout & effects"))); displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { screenManager()->push(new DisplayLayoutScreen(gamePath_)); return UI::EVENT_DONE; @@ -494,10 +494,26 @@ UI::EventReturn GamePauseScreen::OnScreenshotClicked(UI::EventParams &e) { } UI::EventReturn GamePauseScreen::OnExitToMenu(UI::EventParams &e) { - if (g_Config.bPauseMenuExitsEmulator) { - System_ExitApp(); + // If RAIntegration has dirty info, ask for confirmation. + if (Achievements::RAIntegrationDirty()) { + auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS); + auto di = GetI18NCategory(I18NCat::DIALOG); + screenManager()->push(new PromptScreen(gamePath_, ac->T("You have unsaved RAIntegration changes. Exit?"), di->T("Yes"), di->T("No"), [=](bool result) { + if (result) { + if (g_Config.bPauseMenuExitsEmulator) { + System_ExitApp(); + } else { + finishNextFrameResult_ = DR_OK; // exit game + finishNextFrame_ = true; + } + } + })); } else { - TriggerFinish(DR_OK); + if (g_Config.bPauseMenuExitsEmulator) { + System_ExitApp(); + } else { + TriggerFinish(DR_OK); + } } return UI::EVENT_DONE; } diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 64f2c6cf8e..3e039338a2 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -24,6 +24,7 @@ #include "Common/UI/UIScreen.h" #include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" +#include "UI/Screen.h" enum class PauseScreenMode { MAIN, @@ -65,6 +66,7 @@ private: // hack bool finishNextFrame_ = false; + DialogResult finishNextFrameResult_ = DR_CANCEL; PauseScreenMode mode_ = PauseScreenMode::MAIN; UI::Button *playButton_ = nullptr; diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index ccfb4e6d83..611f0bb58a 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -44,6 +44,7 @@ #include "Core/System.h" #include "Core/WebServer.h" #include "UI/RemoteISOScreen.h" +#include "UI/OnScreenDisplay.h" using namespace UI; @@ -118,7 +119,7 @@ bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort std::lock_guard guard(statusLock_); statusMessage_ = formatted; - INFO_LOG(SYSTEM, "Remote: %s", formatted.c_str()); + INFO_LOG(Log::System, "Remote: %s", formatted.c_str()); }; http.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION)); @@ -176,7 +177,7 @@ bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort resultHost = host; resultPort = port; SetStatus("Connected to [URL]", host, port); - NOTICE_LOG(SYSTEM, "RemoteISO found: %s : %d", host.c_str(), port); + NOTICE_LOG(Log::System, "RemoteISO found: %s : %d", host.c_str(), port); return true; } @@ -253,10 +254,11 @@ bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort } static bool LoadGameList(const Path &url, std::vector &games) { - PathBrowser browser(url); + PathBrowser browser; + browser.SetPath(url); std::vector files; browser.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION)); - browser.SetRootAlias("ms:", GetSysDirectory(DIRECTORY_MEMSTICK_ROOT).ToVisualString() + "/"); + browser.SetRootAlias("ms:", GetSysDirectory(DIRECTORY_MEMSTICK_ROOT)); browser.GetListing(files, "iso:cso:chd:pbp:elf:prx:ppdmp:", &scanCancelled); if (scanCancelled) { return false; @@ -270,10 +272,22 @@ static bool LoadGameList(const Path &url, std::vector &games) { return !games.empty(); } -RemoteISOScreen::RemoteISOScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename) {} +RemoteISOScreen::RemoteISOScreen(const Path &filename) : TabbedUIDialogScreenWithGameBackground(filename) {} + + +void RemoteISOScreen::CreateTabs() { + auto ri = GetI18NCategory(I18NCat::REMOTEISO); + + UI::LinearLayout *connect = AddTab("Connect", ri->T("Connect")); + connect->SetSpacing(5.0f); + CreateConnectTab(connect); + + UI::LinearLayout *settings = AddTab("Settings", ri->T("Settings")); + CreateSettingsTab(settings); +} void RemoteISOScreen::update() { - UIDialogScreenWithBackground::update(); + TabbedUIDialogScreenWithGameBackground::update(); if (!WebServerStopped(WebServerFlags::DISCS)) { auto result = IsServerAllowed(g_Config.iRemoteISOPort); @@ -295,21 +309,28 @@ void RemoteISOScreen::update() { serverRunning_ = nowRunning; } -void RemoteISOScreen::CreateViews() { +void RemoteISOScreen::CreateConnectTab(UI::ViewGroup *tab) { auto di = GetI18NCategory(I18NCat::DIALOG); auto ri = GetI18NCategory(I18NCat::REMOTEISO); Margins actionMenuMargins(0, 20, 15, 0); Margins contentMargins(0, 20, 5, 5); + ViewGroup *leftColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 0.4f, contentMargins)); LinearLayout *leftColumnItems = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(WRAP_CONTENT, FILL_PARENT)); ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL); + if (serverRunning_) { + leftColumnItems->Add(new NoticeView(NoticeLevel::SUCCESS, ri->T("Currently sharing"), "", new LinearLayoutParams(Margins(12, 5, 0, 5)))); + } else { + leftColumnItems->Add(new NoticeView(NoticeLevel::INFO, ri->T("Not currently sharing"), "", new LinearLayoutParams(Margins(12, 5, 0, 5)))); + } + if ((RemoteISOShareType)g_Config.iRemoteISOShareType == RemoteISOShareType::RECENT) { leftColumnItems->Add(new TextView(ri->T("RemoteISODesc", "Games in your recent list will be shared"), new LinearLayoutParams(Margins(12, 5, 0, 5)))); } else { - leftColumnItems->Add(new TextView(std::string(ri->T("Share Games(Server)")) + " " + Path(g_Config.sRemoteISOSharedDir).ToVisualString(), new LinearLayoutParams(Margins(12, 5, 0, 5)))); + leftColumnItems->Add(new TextView(std::string(ri->T("Share Games (Server)")) + ": " + Path(g_Config.sRemoteISOSharedDir).ToVisualString(), new LinearLayoutParams(Margins(12, 5, 0, 5)))); } leftColumnItems->Add(new TextView(ri->T("RemoteISOWifi", "Note: Connect both devices to the same wifi"), new LinearLayoutParams(Margins(12, 5, 0, 5)))); firewallWarning_ = leftColumnItems->Add(new TextView(ri->T("RemoteISOWinFirewall", "WARNING: Windows Firewall is blocking sharing"), new LinearLayoutParams(Margins(12, 5, 0, 5)))); @@ -329,18 +350,73 @@ void RemoteISOScreen::CreateViews() { rightColumnItems->Add(new Choice(ri->T("Share Games (Server)")))->OnClick.Handle(this, &RemoteISOScreen::HandleStartServer); browseChoice->SetEnabled(true); } - Choice *settingsChoice = new Choice(ri->T("Settings")); - rightColumnItems->Add(settingsChoice)->OnClick.Handle(this, &RemoteISOScreen::HandleSettings); - LinearLayout *beforeBack = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT)); + LinearLayout *beforeBack = new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, FILL_PARENT)); beforeBack->Add(leftColumn); beforeBack->Add(rightColumn); - root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - root_->Add(beforeBack); - root_->Add(new Choice(di->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &UIScreen::OnBack); leftColumn->Add(leftColumnItems); rightColumn->Add(rightColumnItems); + tab->Add(beforeBack); +} + +void RemoteISOScreen::CreateSettingsTab(UI::ViewGroup *remoteisoSettings) { + serverRunning_ = !WebServerStopped(WebServerFlags::DISCS); + + auto ri = GetI18NCategory(I18NCat::REMOTEISO); + + remoteisoSettings->Add(new ItemHeader(ri->T("Remote disc streaming"))); + remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteShareOnStartup, ri->T("Share on PPSSPP startup"))); + remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteISOManual, ri->T("Manual Mode Client", "Manually configure client"))); + remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteTab, ri->T("Show Remote tab on main screen"))); + + if (System_GetPropertyBool(SYSPROP_HAS_FOLDER_BROWSER)) { + static const char *shareTypes[] = { "Recent files", "Choose directory" }; + remoteisoSettings->Add(new PopupMultiChoice(&g_Config.iRemoteISOShareType, ri->T("Files to share"), shareTypes, 0, ARRAY_SIZE(shareTypes), I18NCat::REMOTEISO, screenManager())); + FolderChooserChoice *folderChooser = remoteisoSettings->Add(new FolderChooserChoice(GetRequesterToken(), &g_Config.sRemoteISOSharedDir, ri->T("Files to share"))); + folderChooser->SetEnabledFunc([=]() { + return g_Config.iRemoteISOShareType == (int)RemoteISOShareType::LOCAL_FOLDER; + }); + } else { + // Can't pick a folder, only allow sharing recent stuff. + g_Config.iRemoteISOShareType = (int)RemoteISOShareType::RECENT; + } + + UI::Choice *remoteServer = new PopupTextInputChoice(GetRequesterToken(), &g_Config.sLastRemoteISOServer, ri->T("Remote Server"), "", 255, screenManager()); + remoteisoSettings->Add(remoteServer); + remoteServer->SetEnabledPtr(&g_Config.bRemoteISOManual); + + PopupSliderChoice *remotePort = remoteisoSettings->Add(new PopupSliderChoice(&g_Config.iLastRemoteISOPort, 0, 65535, 0, ri->T("Remote Port"), 100, screenManager())); + remotePort->SetEnabledPtr(&g_Config.bRemoteISOManual); + + UI::Choice *remoteSubdir; + { + PopupTextInputChoice *remoteSubdirInput = new PopupTextInputChoice(GetRequesterToken(), &g_Config.sRemoteISOSubdir, ri->T("Remote Subdirectory"), "", 255, screenManager()); + remoteSubdirInput->OnChange.Handle(this, &RemoteISOScreen::OnChangeRemoteISOSubdir); + remoteSubdir = remoteSubdirInput; + } + remoteisoSettings->Add(remoteSubdir); + remoteSubdir->SetEnabledPtr(&g_Config.bRemoteISOManual); + + PopupSliderChoice *portChoice = new PopupSliderChoice(&g_Config.iRemoteISOPort, 0, 65535, 0, ri->T("Local Server Port", "Local Server Port"), 100, screenManager()); + remoteisoSettings->Add(portChoice); + portChoice->SetDisabledPtr(&serverRunning_); +} + +static void CleanupRemoteISOSubdir() { + // Replace spaces and force forward slashes. + // TODO: Maybe we should uri escape this after? + ReplaceAll(g_Config.sRemoteISOSubdir, " ", "%20"); + ReplaceAll(g_Config.sRemoteISOSubdir, "\\", "/"); + // Make sure it begins with /. + if (g_Config.sRemoteISOSubdir.empty() || g_Config.sRemoteISOSubdir[0] != '/') + g_Config.sRemoteISOSubdir = "/" + g_Config.sRemoteISOSubdir; +} + + +UI::EventReturn RemoteISOScreen::OnChangeRemoteISOSubdir(UI::EventParams &e) { + CleanupRemoteISOSubdir(); + return UI::EVENT_DONE; } UI::EventReturn RemoteISOScreen::HandleStartServer(UI::EventParams &e) { @@ -367,11 +443,6 @@ UI::EventReturn RemoteISOScreen::HandleBrowse(UI::EventParams &e) { return EVENT_DONE; } -UI::EventReturn RemoteISOScreen::HandleSettings(UI::EventParams &e) { - screenManager()->push(new RemoteISOSettingsScreen()); - return EVENT_DONE; -} - RemoteISOConnectScreen::RemoteISOConnectScreen() { scanCancelled = false; scanAborted = false; @@ -569,84 +640,3 @@ void RemoteISOBrowseScreen::CreateViews() { upgradeBar_ = 0; } - -RemoteISOSettingsScreen::RemoteISOSettingsScreen() { - serverRunning_ = !WebServerStopped(WebServerFlags::DISCS); -} - -void RemoteISOSettingsScreen::update() { - UIDialogScreenWithBackground::update(); - - bool nowRunning = !WebServerStopped(WebServerFlags::DISCS); - if (serverRunning_ != nowRunning) { - RecreateViews(); - } - serverRunning_ = nowRunning; -} - -void RemoteISOSettingsScreen::CreateViews() { - auto ri = GetI18NCategory(I18NCat::REMOTEISO); - - ViewGroup *remoteisoSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT)); - remoteisoSettingsScroll->SetTag("RemoteISOSettings"); - LinearLayout *remoteisoSettings = new LinearLayoutList(ORIENT_VERTICAL); - remoteisoSettings->SetSpacing(0); - remoteisoSettingsScroll->Add(remoteisoSettings); - - remoteisoSettings->Add(new ItemHeader(ri->T("Remote disc streaming"))); - remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteShareOnStartup, ri->T("Share on PPSSPP startup"))); - remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteISOManual, ri->T("Manual Mode Client", "Manually configure client"))); - remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteTab, ri->T("Show Remote tab on main screen"))); - - if (System_GetPropertyBool(SYSPROP_HAS_FOLDER_BROWSER)) { - static const char *shareTypes[] = { "Recent files", "Choose directory" }; - remoteisoSettings->Add(new PopupMultiChoice(&g_Config.iRemoteISOShareType, ri->T("Files to share"), shareTypes, 0, ARRAY_SIZE(shareTypes), I18NCat::REMOTEISO, screenManager())); - FolderChooserChoice *folderChooser = remoteisoSettings->Add(new FolderChooserChoice(GetRequesterToken(), &g_Config.sRemoteISOSharedDir, ri->T("Files to share"))); - folderChooser->SetEnabledFunc([=]() { - return g_Config.iRemoteISOShareType == (int)RemoteISOShareType::LOCAL_FOLDER; - }); - } else { - // Can't pick a folder, only allow sharing recent stuff. - g_Config.iRemoteISOShareType = (int)RemoteISOShareType::RECENT; - } - - UI::Choice *remoteServer = new PopupTextInputChoice(GetRequesterToken(), &g_Config.sLastRemoteISOServer, ri->T("Remote Server"), "", 255, screenManager()); - remoteisoSettings->Add(remoteServer); - remoteServer->SetEnabledPtr(&g_Config.bRemoteISOManual); - - PopupSliderChoice *remotePort = remoteisoSettings->Add(new PopupSliderChoice(&g_Config.iLastRemoteISOPort, 0, 65535, 0, ri->T("Remote Port"), 100, screenManager())); - remotePort->SetEnabledPtr(&g_Config.bRemoteISOManual); - - UI::Choice *remoteSubdir; - { - PopupTextInputChoice *remoteSubdirInput = new PopupTextInputChoice(GetRequesterToken(), &g_Config.sRemoteISOSubdir, ri->T("Remote Subdirectory"), "", 255, screenManager()); - remoteSubdirInput->OnChange.Handle(this, &RemoteISOSettingsScreen::OnChangeRemoteISOSubdir); - remoteSubdir = remoteSubdirInput; - } - remoteisoSettings->Add(remoteSubdir); - remoteSubdir->SetEnabledPtr(&g_Config.bRemoteISOManual); - - PopupSliderChoice *portChoice = new PopupSliderChoice(&g_Config.iRemoteISOPort, 0, 65535, 0, ri->T("Local Server Port", "Local Server Port"), 100, screenManager()); - remoteisoSettings->Add(portChoice); - portChoice->SetDisabledPtr(&serverRunning_); - remoteisoSettings->Add(new Spacer(25.0)); - - root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); - root_->Add(remoteisoSettingsScroll); - AddStandardBack(root_); -} - -static void CleanupRemoteISOSubdir() { - // Replace spaces and force forward slashes. - // TODO: Maybe we should uri escape this after? - ReplaceAll(g_Config.sRemoteISOSubdir, " ", "%20"); - ReplaceAll(g_Config.sRemoteISOSubdir, "\\", "/"); - // Make sure it begins with /. - if (g_Config.sRemoteISOSubdir.empty() || g_Config.sRemoteISOSubdir[0] != '/') - g_Config.sRemoteISOSubdir = "/" + g_Config.sRemoteISOSubdir; -} - -UI::EventReturn RemoteISOSettingsScreen::OnChangeRemoteISOSubdir(UI::EventParams &e) { - CleanupRemoteISOSubdir(); - return UI::EVENT_DONE; -} diff --git a/UI/RemoteISOScreen.h b/UI/RemoteISOScreen.h index 6452c9419e..1913950f17 100644 --- a/UI/RemoteISOScreen.h +++ b/UI/RemoteISOScreen.h @@ -24,21 +24,27 @@ #include "Common/UI/ViewGroup.h" #include "UI/MiscScreens.h" #include "UI/MainScreen.h" +#include "UI/TabbedDialogScreen.h" -class RemoteISOScreen : public UIDialogScreenWithGameBackground { +class RemoteISOScreen : public TabbedUIDialogScreenWithGameBackground { public: RemoteISOScreen(const Path &filename); const char *tag() const override { return "RemoteISO"; } + void CreateTabs() override; protected: + UI::EventReturn OnChangeRemoteISOSubdir(UI::EventParams &e); + + void CreateConnectTab(UI::ViewGroup *viewGroup); + void CreateSettingsTab(UI::ViewGroup *viewGroup); + bool ShowSearchControls() const override { return false; } + void update() override; - void CreateViews() override; UI::EventReturn HandleStartServer(UI::EventParams &e); UI::EventReturn HandleStopServer(UI::EventParams &e); UI::EventReturn HandleBrowse(UI::EventParams &e); - UI::EventReturn HandleSettings(UI::EventParams &e); UI::TextView *firewallWarning_ = nullptr; bool serverRunning_ = false; @@ -97,20 +103,5 @@ protected: std::vector games_; }; -class RemoteISOSettingsScreen : public UIDialogScreenWithBackground { -public: - RemoteISOSettingsScreen(); - - const char *tag() const override { return "RemoteISOSettings"; } - -protected: - void update() override; - void CreateViews() override; - - UI::EventReturn OnChangeRemoteISOSubdir(UI::EventParams &e); - - bool serverRunning_ = false; -}; - std::string RemoteSubdir(); std::string FormatRemoteISOUrl(const char *host, int port, const char *subdir); diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index 361540bce7..8458507c99 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -160,26 +160,26 @@ void CompatRatingChoice::SetupChoices() { AddChoice(4, rp->T("Nothing")); } -ReportScreen::ReportScreen(const Path &gamePath) - : UIDialogScreenWithGameBackground(gamePath) { +ReportScreen::ReportScreen(const Path &gamePath) // unused gamePath, after removing the background + : UIDialogScreen(), gamePath_(gamePath) { enableReporting_ = Reporting::IsEnabled(); ratingEnabled_ = enableReporting_; } ScreenRenderFlags ReportScreen::render(ScreenRenderMode mode) { - ScreenRenderFlags flags = UIScreen::render(mode); + _dbg_assert_(mode & ScreenRenderMode::FIRST); + _dbg_assert_(mode & ScreenRenderMode::TOP); if (mode & ScreenRenderMode::TOP) { - // We do this after render because we need it to be within the frame (so the screenshot works). // We could do it mid frame, but then we have to reapply viewport/scissor. - if (!tookScreenshot_) { + if (!tookScreenshot_ && !g_Config.bSkipBufferEffects) { Path path = GetSysDirectory(DIRECTORY_SCREENSHOT); if (!File::Exists(path)) { File::CreateDir(path); } screenshotFilename_ = path / ".reporting.jpg"; - if (TakeGameScreenshot(screenshotFilename_, ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, nullptr, nullptr, 4)) { + if (TakeGameScreenshot(screenManager()->getDrawContext(), screenshotFilename_, ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, nullptr, nullptr, 4)) { // Redo the views already, now with a screenshot included. RecreateViews(); } else { @@ -189,6 +189,11 @@ ScreenRenderFlags ReportScreen::render(ScreenRenderMode mode) { tookScreenshot_ = true; } } + + // We take the screenshot first, then we start rendering. + // We are the only screen visible so this avoid starting and then trying to resume a backbuffer render pass. + ScreenRenderFlags flags = UIScreen::render(mode); + return flags; } @@ -200,12 +205,12 @@ void ReportScreen::update() { screenshot_->SetVisibility(V_GONE); } } - UIDialogScreenWithGameBackground::update(); + UIDialogScreen::update(); UpdateCRCInfo(); } void ReportScreen::resized() { - UIDialogScreenWithGameBackground::resized(); + UIDialogScreen::resized(); RecreateViews(); } @@ -407,7 +412,7 @@ EventReturn ReportScreen::HandleShowCRC(EventParams &e) { } ReportFinishScreen::ReportFinishScreen(const Path &gamePath, ReportingOverallScore score) - : UIDialogScreenWithGameBackground(gamePath), score_(score) { + : UIDialogScreen(), gamePath_(gamePath), score_(score) { } void ReportFinishScreen::CreateViews() { @@ -468,7 +473,7 @@ void ReportFinishScreen::update() { } } - UIDialogScreenWithGameBackground::update(); + UIDialogScreen::update(); } void ReportFinishScreen::ShowSuggestions() { diff --git a/UI/ReportScreen.h b/UI/ReportScreen.h index c287042dea..8967cac82e 100644 --- a/UI/ReportScreen.h +++ b/UI/ReportScreen.h @@ -33,12 +33,15 @@ enum class ReportingOverallScore : int { INVALID = -1, }; -class ReportScreen : public UIDialogScreenWithGameBackground { +class ReportScreen : public UIDialogScreen { public: ReportScreen(const Path &gamePath); const char *tag() const override { return "Report"; } + // For the screenshotting functionality to work. + ScreenRenderRole renderRole(bool isTop) const override { return ScreenRenderRole::MUST_BE_FIRST | ScreenRenderRole::CAN_BE_BACKGROUND; } + protected: ScreenRenderFlags render(ScreenRenderMode mode) override; void update() override; @@ -60,6 +63,7 @@ protected: UI::TextView *overallDescription_ = nullptr; UI::TextView *crcInfo_ = nullptr; UI::Choice *showCrcButton_ = nullptr; + Path gamePath_; Path screenshotFilename_; ReportingOverallScore overall_ = ReportingOverallScore::INVALID; @@ -73,7 +77,7 @@ protected: bool showCRC_ = false; }; -class ReportFinishScreen : public UIDialogScreenWithGameBackground { +class ReportFinishScreen : public UIDialogScreen { public: ReportFinishScreen(const Path &gamePath, ReportingOverallScore score); @@ -88,6 +92,7 @@ protected: UI::TextView *resultNotice_ = nullptr; UI::LinearLayout *resultItems_ = nullptr; + Path gamePath_; ReportingOverallScore score_; bool setStatus_ = false; }; diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 71535bc81a..d7022ef567 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -13,8 +13,8 @@ #include "UI/BackgroundAudio.h" #include "UI/OnScreenDisplay.h" -static inline const char *DeNull(const char *ptr) { - return ptr ? ptr : ""; +static inline std::string_view DeNull(const char *ptr) { + return ptr ? std::string_view(ptr) : ""; } // Compound view, creating a FileChooserChoice inside. @@ -46,7 +46,7 @@ AudioFileChooser::AudioFileChooser(RequesterToken token, std::string *value, std g_BackgroundAudio.SFX().UpdateSample(sound, sample); } else { auto au = GetI18NCategory(I18NCat::AUDIO); - g_OSD.Show(OSDType::MESSAGE_ERROR, au->T("Audio file format not supported. Must be WAV.")); + g_OSD.Show(OSDType::MESSAGE_ERROR, au->T("Audio file format not supported. Must be WAV or MP3.")); value->clear(); } return UI::EVENT_DONE; @@ -113,7 +113,7 @@ void RetroAchievementsListScreen::CreateAchievementsTab(UI::ViewGroup *achieveme if (!bucket.num_achievements) { continue; } - std::string title = StringFromFormat("%s (%d)", ac->T(AchievementBucketTitle(bucket.bucket_type)), bucket.num_achievements); + std::string title = StringFromFormat("%s (%d)", ac->T_cstr(AchievementBucketTitle(bucket.bucket_type)), bucket.num_achievements); CollapsibleSection *section = achievements->Add(new CollapsibleSection(title)); section->SetSpacing(2.0f); for (uint32_t j = 0; j < bucket.num_achievements; j++) { @@ -298,7 +298,8 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup) }); } else if (System_GetPropertyBool(SYSPROP_HAS_LOGIN_DIALOG)) { viewGroup->Add(new Choice(di->T("Log in")))->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn { - System_AskUsernamePassword(GetRequesterToken(), StringFromFormat("RetroAchievements: %s", di->T("Log in")), [](const std::string &value, int) { + std::string title = StringFromFormat("RetroAchievements: %s", di->T_cstr("Log in")); + System_AskUsernamePassword(GetRequesterToken(), title, [](const std::string &value, int) { std::vector parts; SplitString(value, '\n', parts); if (parts.size() == 2 && !parts[0].empty() && !parts[1].empty()) { @@ -337,7 +338,7 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup) RecreateViews(); return UI::EVENT_DONE; }); - viewGroup->Add(new CheckBox(&g_Config.bAchievementsChallengeMode, ac->T("Hardcore Mode (no savestates)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); + viewGroup->Add(new CheckBox(&g_Config.bAchievementsHardcoreMode, ac->T("Hardcore Mode (no savestates)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); viewGroup->Add(new CheckBox(&g_Config.bAchievementsSoundEffects, ac->T("Sound Effects")))->SetEnabledPtr(&g_Config.bAchievementsEnable); // not yet implemented viewGroup->Add(new ItemHeader(di->T("Links"))); @@ -361,7 +362,7 @@ void RetroAchievementsSettingsScreen::CreateCustomizeTab(UI::ViewGroup *viewGrou viewGroup->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsUnlockAudioFile, ac->T("Achievement unlocked"), UISound::ACHIEVEMENT_UNLOCKED)); viewGroup->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsLeaderboardSubmitAudioFile, ac->T("Leaderboard score submission"), UISound::LEADERBOARD_SUBMITTED)); } - PopupSliderChoice *volume = viewGroup->Add(new PopupSliderChoice(&g_Config.iAchievementSoundVolume, VOLUME_OFF, VOLUME_FULL, VOLUME_FULL, a->T("Achievement sound volume"), screenManager())); + PopupSliderChoice *volume = viewGroup->Add(new PopupSliderChoice(&g_Config.iAchievementSoundVolume, VOLUME_OFF, VOLUME_FULL, VOLUME_FULL, ac->T("Achievement sound volume"), screenManager())); volume->SetEnabledPtr(&g_Config.bEnableSound); volume->SetZeroLabel(a->T("Mute")); @@ -382,6 +383,9 @@ void RetroAchievementsSettingsScreen::CreateDeveloperToolsTab(UI::ViewGroup *vie using namespace UI; viewGroup->Add(new ItemHeader(di->T("Settings"))); +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION + viewGroup->Add(new CheckBox(&g_Config.bAchievementsEnableRAIntegration, ac->T("Enable RAIntegration (for achievement development)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); +#endif viewGroup->Add(new CheckBox(&g_Config.bAchievementsEncoreMode, ac->T("Encore Mode")))->SetEnabledPtr(&g_Config.bAchievementsEnable); viewGroup->Add(new CheckBox(&g_Config.bAchievementsUnofficial, ac->T("Unofficial achievements")))->SetEnabledPtr(&g_Config.bAchievementsEnable); viewGroup->Add(new CheckBox(&g_Config.bAchievementsLogBadMemReads, ac->T("Log bad memory accesses")))->SetEnabledPtr(&g_Config.bAchievementsEnable); @@ -407,7 +411,7 @@ void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achi } } -void MeasureGameAchievementSummary(const UIContext &dc, float *w, float *h) { +static void MeasureGameAchievementSummary(const UIContext &dc, float *w, float *h) { std::string description = Achievements::GetGameAchievementSummary(); float tw, th; @@ -418,12 +422,12 @@ void MeasureGameAchievementSummary(const UIContext &dc, float *w, float *h) { *w += 8.0f; } -void MeasureLeaderboardSummary(const UIContext &dc, const rc_client_leaderboard_t *leaderboard, float *w, float *h) { +static void MeasureLeaderboardSummary(const UIContext &dc, const rc_client_leaderboard_t *leaderboard, float *w, float *h) { *w = 0.0f; *h = 72.0f; } -void MeasureLeaderboardEntry(const UIContext &dc, const rc_client_leaderboard_entry_t *entry, float *w, float *h) { +static void MeasureLeaderboardEntry(const UIContext &dc, const rc_client_leaderboard_entry_t *entry, float *w, float *h) { *w = 0.0f; *h = 72.0f; } @@ -534,7 +538,7 @@ void RenderAchievement(UIContext &dc, const rc_client_achievement_t *achievement dc.PopScissor(); } -void RenderGameAchievementSummary(UIContext &dc, const Bounds &bounds, float alpha) { +static void RenderGameAchievementSummary(UIContext &dc, const Bounds &bounds, float alpha) { using namespace UI; UI::Drawable background = dc.theme->itemStyle.background; @@ -557,7 +561,7 @@ void RenderGameAchievementSummary(UIContext &dc, const Bounds &bounds, float alp std::string description = Achievements::GetGameAchievementSummary(); dc.SetFontScale(0.66f, 0.66f); - dc.DrawTextRect(description.c_str(), bounds.Inset(iconSpace + 5.0f, 38.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT); + dc.DrawTextRect(description, bounds.Inset(iconSpace + 5.0f, 38.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT); dc.SetFontScale(1.0f, 1.0f); dc.Flush(); @@ -576,7 +580,7 @@ void RenderGameAchievementSummary(UIContext &dc, const Bounds &bounds, float alp dc.RebindTexture(); } -void RenderLeaderboardSummary(UIContext &dc, const rc_client_leaderboard_t *leaderboard, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s, bool hasFocus) { +static void RenderLeaderboardSummary(UIContext &dc, const rc_client_leaderboard_t *leaderboard, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s, bool hasFocus) { using namespace UI; UI::Drawable background = dc.theme->itemStyle.background; if (hasFocus) { @@ -619,7 +623,7 @@ void RenderLeaderboardSummary(UIContext &dc, const rc_client_leaderboard_t *lead dc.RebindTexture(); } -void RenderLeaderboardEntry(UIContext &dc, const rc_client_leaderboard_entry_t *entry, const Bounds &bounds, float alpha, bool hasFocus, bool isCurrentUser) { +static void RenderLeaderboardEntry(UIContext &dc, const rc_client_leaderboard_entry_t *entry, const Bounds &bounds, float alpha, bool hasFocus, bool isCurrentUser) { using namespace UI; UI::Drawable background = dc.theme->itemStyle.background; if (hasFocus) { diff --git a/UI/RetroAchievementScreens.h b/UI/RetroAchievementScreens.h index b3fe0826e2..bfef98a868 100644 --- a/UI/RetroAchievementScreens.h +++ b/UI/RetroAchievementScreens.h @@ -92,12 +92,6 @@ enum class AchievementRenderStyle { void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, float *w, float *h); void RenderAchievement(UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s, bool hasFocus); -void MeasureGameAchievementSummary(const UIContext &dc, float *w, float *h); -void RenderGameAchievementSummary(UIContext &dc, const Bounds &bounds, float alpha); - -void MeasureLeaderboardEntry(const UIContext &dc, const rc_client_leaderboard_entry_t *entry, float *w, float *h); -void RenderLeaderboardEntry(UIContext &dc, const rc_client_leaderboard_entry_t *entry, const Bounds &bounds, float alpha); - class AchievementView : public UI::ClickableItem { public: AchievementView(const rc_client_achievement_t *achievement, UI::LayoutParams *layoutParams = nullptr) : UI::ClickableItem(layoutParams), achievement_(achievement) { diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 8567205013..4c8162d4f1 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -23,6 +23,7 @@ #include "Common/Data/Encoding/Utf8.h" #include "Common/Data/Text/I18n.h" #include "Common/Math/curves.h" +#include "Common/Data/Text/Parsers.h" #include "Common/System/NativeApp.h" #include "Common/System/Request.h" #include "Common/Data/Encoding/Utf8.h" @@ -46,85 +47,117 @@ class SavedataButton; -std::string GetFileDateAsString(const Path &filename) { - tm time; - if (File::GetModifTime(filename, time)) { - char buf[256]; - switch (g_Config.iDateFormat) { - case PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD: - strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &time); - break; - case PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY: - strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &time); - break; - case PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY: - strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", &time); - break; - default: // Should never happen - return ""; +SavedataView::SavedataView(UIContext &dc, const Path &savePath, IdentifiedFileType type, std::string_view title, std::string_view savedataTitle, std::string_view savedataDetail, std::string_view fileSize, std::string_view mtime, bool showIcon, UI::LayoutParams *layoutParams) + : LinearLayout(UI::ORIENT_VERTICAL, layoutParams) +{ + using namespace UI; + + const Style &textStyle = dc.theme->popupStyle; + LinearLayout *toprow = new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT)); + Add(toprow); + toprow->SetSpacing(0.0); + + savedataTitle_ = nullptr; + fileSize_ = nullptr; + mTime_ = nullptr; + detail_ = nullptr; + if (type == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { + if (showIcon) { + toprow->Add(new GameIconView(savePath, 2.0f, new LinearLayoutParams(Margins(5, 5)))); } - return std::string(buf); + LinearLayout *topright = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f)); + topright->SetSpacing(1.0f); + savedataTitle_ = topright->Add(new TextView(savedataTitle, ALIGN_LEFT | FLAG_WRAP_TEXT, false)); + savedataTitle_->SetTextColor(textStyle.fgColor); + fileSize_ = topright->Add(new TextView(fileSize, 0, true)); + fileSize_->SetTextColor(textStyle.fgColor); + mTime_ = topright->Add(new TextView(mtime, 0, true)); + mTime_->SetTextColor(textStyle.fgColor); + toprow->Add(topright); + Add(new Spacer(3.0)); + detail_ = Add(new TextView(ReplaceAll(savedataDetail, "\r", ""), ALIGN_LEFT | FLAG_WRAP_TEXT, true, new LinearLayoutParams(Margins(10, 0)))); + detail_->SetTextColor(textStyle.fgColor); + Add(new Spacer(3.0)); + } else { + _dbg_assert_(type == IdentifiedFileType::PPSSPP_SAVESTATE); + Path image_path = savePath.WithReplacedExtension(".ppst", ".jpg"); + if (File::Exists(image_path)) { + toprow->Add(new AsyncImageFileView(image_path, IS_KEEP_ASPECT, new LinearLayoutParams(480, 272, Margins(10, 0)))); + } else { + auto sa = GetI18NCategory(I18NCat::SAVEDATA); + toprow->Add(new TextView(sa->T("No screenshot"), new LinearLayoutParams(Margins(10, 5))))->SetTextColor(textStyle.fgColor); + } + mTime_ = Add(new TextView(mtime, 0, true, new LinearLayoutParams(Margins(10, 5)))); + mTime_->SetTextColor(textStyle.fgColor); } - return ""; } -static std::string TrimString(const std::string &str) { - size_t pos = str.find_last_not_of(" \r\n\t"); - if (pos != str.npos) { - return str.substr(0, pos + 1); +void SavedataView::Update(GameInfo *ginfo) { + if (!ginfo->Ready(GameInfoFlags::PARAM_SFO | GameInfoFlags::SIZE)) { + return; + } + _dbg_assert_(savedataTitle_); + if (savedataTitle_) { + savedataTitle_->SetText(ginfo->GetParamSFO().GetValueString("SAVEDATA_TITLE")); + } + if (detail_) { + detail_->SetText(ginfo->GetParamSFO().GetValueString("SAVEDATA_DETAIL")); + } + if (fileSize_) { + fileSize_->SetText(NiceSizeFormat(ginfo->gameSizeOnDisk)); + } + if (mTime_) { + mTime_->SetText(ginfo->GetMTime()); + } +} + +SavedataView::SavedataView(UIContext &dc, GameInfo *ginfo, IdentifiedFileType type, bool showIcon, UI::LayoutParams *layoutParams) + : SavedataView(dc, + ginfo->GetFilePath(), + type, + "", + "", + "", + "", + "", + showIcon, + layoutParams) { + if (ginfo) { + Update(ginfo); } - return str; } class SavedataPopupScreen : public PopupScreen { public: - SavedataPopupScreen(std::string savePath, std::string title) : PopupScreen(TrimString(title)), savePath_(savePath) { } + SavedataPopupScreen(Path savePath, std::string_view title) : PopupScreen(StripSpaces(title)), savePath_(savePath) { } const char *tag() const override { return "SavedataPopup"; } + void update() override { + PopupScreen::update(); + std::shared_ptr ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savePath_, GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE); + if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) { + // Hm, this is no good. But hopefully the previous screen loaded it. + return; + } + if (savedataView_) { + savedataView_->Update(ginfo.get()); + } + } void CreatePopupContents(UI::ViewGroup *parent) override { using namespace UI; UIContext &dc = *screenManager()->getUIContext(); - const Style &textStyle = dc.theme->popupStyle; std::shared_ptr ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savePath_, GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE); - if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) - return; + if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) { + // This is OK, handled in Update. Though most likely, the previous screen loaded it. + } ScrollView *contentScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f, UI::Margins(0, 3))); - LinearLayout *content = new LinearLayout(ORIENT_VERTICAL); parent->Add(contentScroll); - contentScroll->Add(content); - LinearLayout *toprow = new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT)); - content->Add(toprow); - toprow->SetSpacing(0.0); - if (ginfo->fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { - std::string savedata_detail = ginfo->paramSFO.GetValueString("SAVEDATA_DETAIL"); - std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE"); - - if (ginfo->icon.texture) { - toprow->Add(new GameIconView(savePath_, 2.0f, new LinearLayoutParams(Margins(5, 5)))); - } - LinearLayout *topright = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f)); - topright->SetSpacing(1.0f); - topright->Add(new TextView(savedata_title, ALIGN_LEFT | FLAG_WRAP_TEXT, false))->SetTextColor(textStyle.fgColor); - topright->Add(new TextView(StringFromFormat("%lld kB", ginfo->gameSizeOnDisk / 1024), 0, true))->SetTextColor(textStyle.fgColor); - topright->Add(new TextView(GetFileDateAsString(savePath_ / "PARAM.SFO"), 0, true))->SetTextColor(textStyle.fgColor); - toprow->Add(topright); - content->Add(new Spacer(3.0)); - content->Add(new TextView(ReplaceAll(savedata_detail, "\r", ""), ALIGN_LEFT | FLAG_WRAP_TEXT, true, new LinearLayoutParams(Margins(10, 0))))->SetTextColor(textStyle.fgColor); - content->Add(new Spacer(3.0)); - } else { - Path image_path = savePath_.WithReplacedExtension(".ppst", ".jpg"); - if (File::Exists(image_path)) { - toprow->Add(new AsyncImageFileView(image_path, IS_KEEP_ASPECT, new LinearLayoutParams(480, 272, Margins(10, 0)))); - } else { - auto sa = GetI18NCategory(I18NCat::SAVEDATA); - toprow->Add(new TextView(sa->T("No screenshot"), new LinearLayoutParams(Margins(10, 5))))->SetTextColor(textStyle.fgColor); - } - content->Add(new TextView(GetFileDateAsString(savePath_), 0, true, new LinearLayoutParams(Margins(10, 5))))->SetTextColor(textStyle.fgColor); - } + // TODO: If the game info wasn't already loaded, we'll get a bogus fileType here. + savedataView_ = contentScroll->Add(new SavedataView(dc, ginfo.get(), ginfo->fileType, true)); auto di = GetI18NCategory(I18NCat::DIALOG); LinearLayout *buttons = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); @@ -141,6 +174,7 @@ protected: private: UI::EventReturn OnDeleteButtonClick(UI::EventParams &e); + SavedataView *savedataView_ = nullptr; Path savePath_; }; @@ -192,45 +226,6 @@ void SortedLinearLayout::Update() { UI::LinearLayout::Update(); } -class SavedataButton : public UI::Clickable { -public: - SavedataButton(const Path &gamePath, UI::LayoutParams *layoutParams = 0) - : UI::Clickable(layoutParams), savePath_(gamePath) { - SetTag(gamePath.ToString()); - } - - void Draw(UIContext &dc) override; - bool UpdateText(); - std::string DescribeText() const override; - void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { - w = 500; - h = 74; - } - - const Path &GamePath() const { return savePath_; } - - uint64_t GetTotalSize() const { - return totalSize_; - } - int64_t GetDateSeconds() const { - return dateSeconds_; - } - - void UpdateTotalSize(); - void UpdateDateSeconds(); - -private: - void UpdateText(const std::shared_ptr &ginfo); - - Path savePath_; - std::string title_; - std::string subtitle_; - uint64_t totalSize_ = 0; - int64_t dateSeconds_ = 0; - bool hasTotalSize_ = false; - bool hasDateSeconds_ = false; -}; - void SavedataButton::UpdateTotalSize() { if (hasTotalSize_) return; @@ -267,9 +262,8 @@ UI::EventReturn SavedataPopupScreen::OnDeleteButtonClick(UI::EventParams &e) { return UI::EVENT_DONE; } -static std::string CleanSaveString(const std::string &str) { - std::string s = ReplaceAll(str, "&", "&&"); - s = ReplaceAll(s, "\n", " "); +static std::string CleanSaveString(std::string_view str) { + std::string s = ReplaceAll(str, "\n", " "); s = ReplaceAll(s, "\r", " "); return s; } @@ -289,8 +283,9 @@ void SavedataButton::UpdateText(const std::shared_ptr &ginfo) { title_ = CleanSaveString(currentTitle); } if (subtitle_.empty() && ginfo->gameSizeOnDisk > 0) { - std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE"); - subtitle_ = CleanSaveString(savedata_title) + StringFromFormat(" (%lld kB)", ginfo->gameSizeOnDisk / 1024); + std::string date = ginfo->GetMTime(); + std::string savedata_title = ginfo->GetParamSFO().GetValueString("SAVEDATA_TITLE"); + subtitle_ = CleanSaveString(savedata_title) + " (" + NiceSizeFormat(ginfo->gameSizeOnDisk) + ", " + date.c_str() + ")"; } } @@ -687,7 +682,7 @@ UI::EventReturn SavedataScreen::OnSavedataButtonClick(UI::EventParams &e) { if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) { return UI::EVENT_DONE; } - SavedataPopupScreen *popupScreen = new SavedataPopupScreen(e.s, ginfo->GetTitle()); + SavedataPopupScreen *popupScreen = new SavedataPopupScreen(Path(e.s), ginfo->GetTitle()); if (e.v) { popupScreen->SetPopupOrigin(e.v); } diff --git a/UI/SavedataScreen.h b/UI/SavedataScreen.h index b1dc6565e4..5980f370c8 100644 --- a/UI/SavedataScreen.h +++ b/UI/SavedataScreen.h @@ -105,3 +105,57 @@ private: int textureWidth_ = 0; int textureHeight_ = 0; }; + +class SavedataButton : public UI::Clickable { +public: + SavedataButton(const Path &gamePath, UI::LayoutParams *layoutParams = 0) + : UI::Clickable(layoutParams), savePath_(gamePath) { + SetTag(gamePath.ToString()); + } + + void Draw(UIContext &dc) override; + bool UpdateText(); + std::string DescribeText() const override; + void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { + w = 500; + h = 74; + } + + const Path &GamePath() const { return savePath_; } + + uint64_t GetTotalSize() const { + return totalSize_; + } + int64_t GetDateSeconds() const { + return dateSeconds_; + } + + void UpdateTotalSize(); + void UpdateDateSeconds(); + +private: + void UpdateText(const std::shared_ptr &ginfo); + + Path savePath_; + std::string title_; + std::string subtitle_; + uint64_t totalSize_ = 0; + int64_t dateSeconds_ = 0; + bool hasTotalSize_ = false; + bool hasDateSeconds_ = false; +}; + +// View used for the detailed popup, and also in the import savedata comparison. +// It doesn't do its own data loading for that reason. +class SavedataView : public UI::LinearLayout { +public: + SavedataView(UIContext &dc, GameInfo *ginfo, IdentifiedFileType type, bool showIcon, UI::LayoutParams *layoutParams = nullptr); + SavedataView(UIContext &dc, const Path &savePath, IdentifiedFileType type, std::string_view title, std::string_view savedataTitle, std::string_view savedataDetail, std::string_view fileSize, std::string_view mtime, bool showIcon, UI::LayoutParams *layoutParams = nullptr); + + void Update(GameInfo *ginfo); +private: + UI::TextView *savedataTitle_ = nullptr; + UI::TextView *detail_ = nullptr; + UI::TextView *mTime_ = nullptr; + UI::TextView *fileSize_ = nullptr; +}; diff --git a/UI/Store.cpp b/UI/Store.cpp index 9dd2efc254..9c9dbc281b 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -233,8 +233,6 @@ void HttpImageFileView::Draw(UIContext &dc) { } } - - // This is the entry in a list. Does not have install buttons and so on. class ProductItemView : public UI::StickyChoice { public: @@ -290,7 +288,7 @@ void ProductView::CreateViews() { if (!entry_.iconURL.empty()) { Add(new HttpImageFileView(&g_DownloadManager, ResolveUrl(StoreBaseUrl(), entry_.iconURL), IS_FIXED))->SetFixedSize(144, 88); } - Add(new TextView(entry_.name)); + Add(new TextView(entry_.name))->SetBig(true); Add(new TextView(entry_.author)); auto st = GetI18NCategory(I18NCat::STORE); @@ -315,7 +313,7 @@ void ProductView::CreateViews() { g_GameManager.UninstallGameOnThread(entry_.file); return UI::EVENT_DONE; }); - Add(new TextView(st->T("Installed"))); + // Add(new TextView(st->T("Installed"))); // Not really needed } cancelButton_ = Add(new Button(di->T("Cancel"))); @@ -333,6 +331,37 @@ void ProductView::CreateViews() { float size = entry_.size / (1024.f * 1024.f); Add(new TextView(StringFromFormat("%s: %.2f %s", st->T_cstr("Size"), size, st->T_cstr("MB")))); + + if (!entry_.license.empty()) { + LinearLayout *horiz = Add(new LinearLayout(ORIENT_HORIZONTAL)); + horiz->Add(new TextView(StringFromFormat("%s: %s", st->T_cstr("License"), entry_.license.c_str()), new LinearLayoutParams(0.0, G_VCENTER))); + horiz->Add(new Button(di->T("More information..."), new LinearLayoutParams(0.0, G_VCENTER)))->OnClick.Add([this](UI::EventParams) { + std::string url = StringFromFormat("https://www.ppsspp.org/docs/reference/homebrew-store-distribution/#%s", entry_.file.c_str()); + System_LaunchUrl(LaunchUrlType::BROWSER_URL, url.c_str()); + return UI::EVENT_DONE; + }); + } + if (!entry_.websiteURL.empty()) { + // Display in a few different ways depending on the URL + size_t slashes = std::count(entry_.websiteURL.begin(), entry_.websiteURL.end(), '/'); + std::string buttonText; + if (slashes == 2) { + // Just strip https and show the URL. + std::string_view name = StripPrefix("https://", entry_.websiteURL); + name = StripPrefix("http://", name); + if (name.size() < entry_.websiteURL.size()) { + buttonText = name; + } + } + if (buttonText.empty()) { + // Fall back + buttonText = st->T("Website"); + } + Add(new Button(buttonText))->OnClick.Add([this](UI::EventParams) { + System_LaunchUrl(LaunchUrlType::BROWSER_URL, entry_.websiteURL.c_str()); + return UI::EVENT_DONE; + }); + } } void ProductView::Update() { @@ -372,7 +401,7 @@ UI::EventReturn ProductView::OnInstall(UI::EventParams &e) { if (cancelButton_) { cancelButton_->SetVisibility(UI::V_VISIBLE); } - INFO_LOG(SYSTEM, "Triggering install of '%s'", fileUrl.c_str()); + INFO_LOG(Log::System, "Triggering install of '%s'", fileUrl.c_str()); g_GameManager.DownloadAndInstall(fileUrl); return UI::EVENT_DONE; } @@ -430,7 +459,7 @@ void StoreScreen::update() { RecreateViews(); } else { // Failed to contact store. Don't do anything. - ERROR_LOG(IO, "Download failed : error code %d", resultCode_); + ERROR_LOG(Log::IO, "Download failed : error code %d", resultCode_); connectionError_ = true; loading_ = false; RecreateViews(); @@ -445,7 +474,7 @@ void StoreScreen::ParseListing(const std::string &json) { using namespace json; JsonReader reader(json.c_str(), json.size()); if (!reader.ok() || !reader.root()) { - ERROR_LOG(IO, "Error parsing JSON from store"); + ERROR_LOG(Log::IO, "Error parsing JSON from store"); connectionError_ = true; RecreateViews(); return; @@ -456,14 +485,22 @@ void StoreScreen::ParseListing(const std::string &json) { entries_.clear(); for (const JsonNode *pgame : entries->value) { JsonGet game = pgame->value; - StoreEntry e; + StoreEntry e{}; e.type = ENTRY_PBPZIP; e.name = GetTranslatedString(game, "name"); e.description = GetTranslatedString(game, "description", ""); - e.author = game.getStringOr("author", "?"); + e.author = ReplaceAll(game.getStringOr("author", "?"), "&&", "&"); // Can't remove && in the JSON source data due to old app versions e.size = game.getInt("size"); e.downloadURL = game.getStringOr("download-url", ""); e.iconURL = game.getStringOr("icon-url", ""); + e.contentRating = game.getInt("content-rating", 0); + e.websiteURL = game.getStringOr("website-url", ""); + e.license = game.getStringOr("license", ""); +#if PPSSPP_PLATFORM(IOS_APP_STORE) + if (e.contentRating >= 100) { + continue; + } +#endif e.hidden = false; // NOTE: Handling of the "hidden" flag is broken in old versions of PPSSPP. Do not use. const char *file = game.getStringOr("file", nullptr); if (!file) @@ -483,9 +520,9 @@ void StoreScreen::CreateViews() { auto mm = GetI18NCategory(I18NCat::MAINMENU); // Top bar - LinearLayout *topBar = root_->Add(new LinearLayout(ORIENT_HORIZONTAL)); - topBar->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); - titleText_ = new TextView(mm->T("PPSSPP Homebrew Store")); + LinearLayout *topBar = root_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, 64.0f))); + topBar->Add(new Choice(di->T("Back"), new LinearLayoutParams(WRAP_CONTENT, FILL_PARENT)))->OnClick.Handle(this, &UIScreen::OnBack); + titleText_ = new TextView(mm->T("PPSSPP Homebrew Store"), ALIGN_VCENTER, false, new LinearLayoutParams(WRAP_CONTENT, FILL_PARENT)); topBar->Add(titleText_); UI::Drawable solid(0xFFbd9939); topBar->SetBG(solid); diff --git a/UI/Store.h b/UI/Store.h index 1782037b9b..1e51b6bd5f 100644 --- a/UI/Store.h +++ b/UI/Store.h @@ -50,10 +50,13 @@ struct StoreEntry { std::string description; std::string author; std::string iconURL; - std::string file; // This is the folder name of the installed one too, and hence a "unique-ish" identifier. + std::string file; // This is the folder name of the installed one too, and hence a "unique-ish" identifier. Also used as a-link on the license website, if !license.empty(). std::string category; std::string downloadURL; // Only set for games that are not hosted on store.ppsspp.org + std::string websiteURL; + std::string license; bool hidden; + int contentRating; // 100 means to hide it on iOS. No other values defined yet. u64 size; }; diff --git a/UI/Theme.cpp b/UI/Theme.cpp index 91c7d10dbf..b8704ced91 100644 --- a/UI/Theme.cpp +++ b/UI/Theme.cpp @@ -25,7 +25,7 @@ #include "Common/File/VFS/VFS.h" #include "Common/Data/Format/IniFile.h" #include "Common/File/DirListing.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Core/Config.h" @@ -167,9 +167,9 @@ static void LoadAtlasMetadata(Atlas &metadata, const char *filename, bool requir bool load_success = atlas_data != nullptr && metadata.Load(atlas_data, atlas_data_size); if (!load_success) { if (required) - ERROR_LOG(G3D, "Failed to load %s - graphics will be broken", filename); + ERROR_LOG(Log::G3D, "Failed to load %s - graphics will be broken", filename); else - WARN_LOG(G3D, "Failed to load %s", filename); + WARN_LOG(Log::G3D, "Failed to load %s", filename); // Stumble along with broken visuals instead of dying... } delete[] atlas_data; @@ -197,11 +197,11 @@ void UpdateTheme(UIContext *ctx) { #if defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP) || defined(USING_QT_UI) ui_theme.uiFont = UI::FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 22); ui_theme.uiFontSmall = UI::FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 17); - ui_theme.uiFontSmaller = UI::FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 13); + ui_theme.uiFontBig = UI::FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 28); #else ui_theme.uiFont = UI::FontStyle(FontID("UBUNTU24"), "", 20); ui_theme.uiFontSmall = UI::FontStyle(FontID("UBUNTU24"), "", 15); - ui_theme.uiFontSmaller = UI::FontStyle(FontID("UBUNTU24"), "", 12); + ui_theme.uiFontBig = UI::FontStyle(FontID("UBUNTU24"), "", 26); #endif ui_theme.checkOn = ImageID("I_CHECKEDBOX"); diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 0f66931b2e..47190891d6 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -370,8 +370,8 @@ public: int mode_ = 0; }; -static Point ClampTo(const Point &p, const Bounds &b) { - return Point(clamp_value(p.x, b.x, b.x + b.w), clamp_value(p.y, b.y, b.y + b.h)); +static Point2D ClampTo(const Point2D &p, const Bounds &b) { + return Point2D(clamp_value(p.x, b.x, b.x + b.w), clamp_value(p.y, b.y, b.y + b.h)); } bool ControlLayoutView::Touch(const TouchInput &touch) { @@ -393,7 +393,7 @@ bool ControlLayoutView::Touch(const TouchInput &touch) { //validRange.y += controlBounds.h * 0.5f; //validRange.h -= controlBounds.h; - Point newPos; + Point2D newPos; newPos.x = startObjectX_ + (touch.x - startDragX_); newPos.y = startObjectY_ + (touch.y - startDragY_); if (g_Config.bTouchSnapToGrid) { @@ -514,6 +514,8 @@ void ControlLayoutView::CreateViews() { auto addDragCustomKey = [&](ConfigTouchPos &pos, const char *key, const ConfigCustomButton& cfg) { DragDropButton *b = nullptr; if (pos.show) { + + b = new DragDropButton(pos, key, g_Config.iTouchButtonStyle == 0 ? customKeyShapes[cfg.shape].i : customKeyShapes[cfg.shape].l, customKeyImages[cfg.image].i, bounds); b->FlipImageH(customKeyShapes[cfg.shape].f); b->SetAngle(customKeyImages[cfg.image].r, customKeyShapes[cfg.shape].r); @@ -523,6 +525,14 @@ void ControlLayoutView::CreateViews() { }; for (int i = 0; i < Config::CUSTOM_BUTTON_COUNT; i++) { + // Similar to GamepadEmu, we sanitize the images for valid values. + if (g_Config.CustomButton[i].shape >= ARRAY_SIZE(CustomKeyData::customKeyShapes)) { + g_Config.CustomButton[i].shape = 0; + } + if (g_Config.CustomButton[i].image >= ARRAY_SIZE(CustomKeyData::customKeyImages)) { + g_Config.CustomButton[i].image = 0; + } + char temp[64]; snprintf(temp, sizeof(temp), "Custom %d button", i); addDragCustomKey(g_Config.touchCustom[i], temp, g_Config.CustomButton[i]); @@ -573,7 +583,7 @@ UI::EventReturn TouchControlLayoutScreen::OnVisibility(UI::EventParams &e) { } UI::EventReturn TouchControlLayoutScreen::OnReset(UI::EventParams &e) { - INFO_LOG(G3D, "Resetting touch control layout"); + INFO_LOG(Log::G3D, "Resetting touch control layout"); g_Config.ResetControlLayout(); const Bounds &bounds = screenManager()->getUIContext()->GetBounds(); InitPadLayout(bounds.w, bounds.h); diff --git a/UI/TouchControlVisibilityScreen.cpp b/UI/TouchControlVisibilityScreen.cpp index d96951fbfb..34b8c620b5 100644 --- a/UI/TouchControlVisibilityScreen.cpp +++ b/UI/TouchControlVisibilityScreen.cpp @@ -151,8 +151,8 @@ void RightAnalogMappingScreen::CreateViews() { LinearLayout *vert = rightPanel->Add(new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT))); vert->SetSpacing(0); - static const char *rightAnalogButton[] = {"None", "L", "R", "Square", "Triangle", "Circle", "Cross", "D-pad up", "D-pad down", "D-pad left", "D-pad right", "Start", "Select"}; - + static const char *rightAnalogButton[] = {"None", "L", "R", "Square", "Triangle", "Circle", "Cross", "D-pad up", "D-pad down", "D-pad left", "D-pad right", "Start", "Select", "RightAn.Up", "RightAn.Down", "RightAn.Left", "RightAn.Right", "An.Up", "An.Down", "An.Left", "An.Right"}; + vert->Add(new ItemHeader(co->T("Analog Style"))); vert->Add(new CheckBox(&g_Config.touchRightAnalogStick.show, co->T("Visible"))); vert->Add(new CheckBox(&g_Config.bRightAnalogCustom, co->T("Use custom right analog"))); @@ -163,7 +163,7 @@ void RightAnalogMappingScreen::CreateViews() { PopupMultiChoice *rightAnalogDown = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogDown, mc->T("RightAn.Down"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), I18NCat::MAPPABLECONTROLS, screenManager())); PopupMultiChoice *rightAnalogLeft = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogLeft, mc->T("RightAn.Left"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), I18NCat::MAPPABLECONTROLS, screenManager())); PopupMultiChoice *rightAnalogRight = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogRight, mc->T("RightAn.Right"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), I18NCat::MAPPABLECONTROLS, screenManager())); - PopupMultiChoice *rightAnalogPress = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogPress, co->T("Keep this button pressed when right analog is pressed"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), I18NCat::MAPPABLECONTROLS, screenManager())); + PopupMultiChoice *rightAnalogPress = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogPress, co->T("Keep this button pressed when right analog is pressed"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton) - 8, I18NCat::MAPPABLECONTROLS, screenManager())); rightAnalogUp->SetEnabledPtr(&g_Config.bRightAnalogCustom); rightAnalogDown->SetEnabledPtr(&g_Config.bRightAnalogCustom); rightAnalogLeft->SetEnabledPtr(&g_Config.bRightAnalogCustom); diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index aff7187e61..e1fcc93938 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -51,6 +51,7 @@ + @@ -90,6 +91,7 @@ + @@ -221,7 +223,7 @@ Level3 - _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) + RC_CLIENT_SUPPORTS_RAINTEGRATION;_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext true false @@ -242,7 +244,7 @@ Level3 - _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) + RC_CLIENT_SUPPORTS_RAINTEGRATION;_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext true false @@ -312,7 +314,7 @@ MaxSpeed true true - USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) + RC_CLIENT_SUPPORTS_RAINTEGRATION;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext false Size @@ -339,7 +341,7 @@ MaxSpeed true true - USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) + RC_CLIENT_SUPPORTS_RAINTEGRATION;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext false true diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 24c3cc6cf0..ba5da5148c 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -95,6 +95,9 @@ Screens + + Screens + @@ -190,6 +193,9 @@ Screens + + Screens + diff --git a/UWP/App.cpp b/UWP/App.cpp index 6383d59516..937021eff8 100644 --- a/UWP/App.cpp +++ b/UWP/App.cpp @@ -15,7 +15,7 @@ #include "Common/Input/InputState.h" #include "Common/System/NativeApp.h" #include "Common/System/System.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Core/System.h" #include "Core/Config.h" #include "Core/Core.h" diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index 8d594111a6..195b61c8b4 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -188,7 +188,8 @@ - + + @@ -197,7 +198,7 @@ - + @@ -240,6 +241,17 @@ + + + + + + + + + + + @@ -254,6 +266,8 @@ + + @@ -329,7 +343,8 @@ - + + @@ -337,7 +352,7 @@ - + @@ -379,6 +394,15 @@ + + + + + + + + + @@ -396,6 +420,7 @@ + @@ -420,6 +445,10 @@ {c249f016-7f82-45cf-bb6e-0642a988c4d3} + + + + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index 262e1e7af3..f38724008a 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -97,6 +97,12 @@ {403c3154-5e8a-4da1-ba82-8f69bef25e14} + + {7b5c3ddc-225d-48d5-a829-9a1e71e304be} + + + {47e3b9c8-3a5f-4c78-b62b-3fa65bf23594} + @@ -105,12 +111,13 @@ - + + - + @@ -456,6 +463,36 @@ ext\naett + + ext\minimp3 + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + @@ -472,13 +509,14 @@ - + + - + @@ -865,6 +903,45 @@ Math + + ext\minimp3 + + + ext\minimp3 + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + + + ext\at3_standalone + @@ -905,4 +982,12 @@ ext\basis_universal - \ No newline at end of file + + + ext\at3_standalone + + + ext\at3_standalone + + + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 207fa9ad79..0a64ea0a29 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -174,6 +174,8 @@ + + @@ -261,6 +263,7 @@ + @@ -302,6 +305,7 @@ + @@ -424,6 +428,8 @@ + + @@ -508,6 +514,7 @@ + @@ -577,6 +584,7 @@ + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index 82bf9b68af..0434c2142b 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -258,6 +258,9 @@ HW + + HW + HW @@ -552,6 +555,9 @@ MIPS + + MIPS + Dialog @@ -1196,6 +1202,12 @@ Util + + HLE + + + HLE + @@ -1306,6 +1318,9 @@ HW + + HW + HW @@ -1612,6 +1627,9 @@ MIPS + + MIPS + Dialog @@ -1876,6 +1894,12 @@ Util + + HLE + + + HLE + diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj index ffc2d6f0c0..9e22d246ef 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj @@ -136,6 +136,7 @@ + @@ -203,6 +204,7 @@ + @@ -257,4 +259,4 @@ - \ No newline at end of file + diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters index 314574f863..804554a2c5 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters @@ -22,6 +22,7 @@ + @@ -86,6 +87,7 @@ + @@ -130,4 +132,4 @@ - \ No newline at end of file + diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index f90e96ae50..140d0948fd 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -18,13 +18,12 @@ #include "Common/DirectXHelper.h" #include "Common/File/FileUtil.h" #include "Common/Log.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Common/TimeUtil.h" #include "Common/StringUtils.h" #include "Common/System/Display.h" #include "Common/System/NativeApp.h" #include "Common/System/Request.h" -#include "Common/OSVersion.h" #include "Core/System.h" #include "Core/Loaders.h" @@ -65,6 +64,8 @@ PPSSPP_UWPMain::PPSSPP_UWPMain(App ^app, const std::shared_ptrRegisterDeviceNotify(this); @@ -312,7 +313,9 @@ std::string System_GetProperty(SystemProperty prop) { static bool hasCheckedGPUDriverVersion = false; switch (prop) { case SYSPROP_NAME: - return GetWindowsVersion(); + return GetSystemName(); + case SYSPROP_SYSTEMBUILD: + return GetWindowsBuild(); case SYSPROP_LANGREGION: return GetLangRegion(); case SYSPROP_CLIPBOARD_TEXT: @@ -354,7 +357,7 @@ std::vector System_GetPropertyStringVec(SystemProperty prop) { } } -int System_GetPropertyInt(SystemProperty prop) { +int64_t System_GetPropertyInt(SystemProperty prop) { switch (prop) { case SYSPROP_AUDIO_SAMPLE_RATE: return winAudioBackend ? winAudioBackend->GetSampleRate() : -1; @@ -406,6 +409,7 @@ void System_Toast(std::string_view str) {} bool System_GetPropertyBool(SystemProperty prop) { switch (prop) { + case SYSPROP_HAS_TEXT_CLIPBOARD: case SYSPROP_HAS_OPEN_DIRECTORY: { return !IsXBox(); @@ -460,7 +464,7 @@ void System_Notify(SystemNotification notification) { } } -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { switch (type) { case SystemRequestType::EXIT_APP: @@ -478,7 +482,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ExecuteTask(error, Windows::ApplicationModel::Core::CoreApplication::RequestRestartAsync(nullptr)); if (error != Windows::ApplicationModel::Core::AppRestartFailureReason::RestartPending) { // Shutdown - System_MakeRequest(SystemRequestType::EXIT_APP, requestId, param1, param2, param3); + System_MakeRequest(SystemRequestType::EXIT_APP, requestId, param1, param2, param3, param4); } return true; } @@ -514,13 +518,13 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string supportedExtensions = { ".db" }; break; case BrowseFileType::SOUND_EFFECT: - supportedExtensions = { ".wav" }; + supportedExtensions = { ".wav", ".mp3" }; break; case BrowseFileType::ANY: // 'ChooseFile' will added '*' by default when there are no extensions assigned break; default: - ERROR_LOG(FILESYS, "Unexpected BrowseFileType: %d", param3); + ERROR_LOG(Log::FileSystem, "Unexpected BrowseFileType: %d", param3); return false; } @@ -548,21 +552,23 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string }); return true; } - case SystemRequestType::NOTIFY_UI_STATE: + case SystemRequestType::NOTIFY_UI_EVENT: { - if (!param1.empty()) { - if (!strcmp(param1.c_str(), "menu")) { - CloseLaunchItem(); - } - else if (!strcmp(param1.c_str(), "popup_closed")) { - DeactivateTextEditInput(); - } - else if (!strcmp(param1.c_str(), "text_gotfocus")) { - ActivateTextEditInput(true); - } - else if (!strcmp(param1.c_str(), "text_lostfocus")) { - DeactivateTextEditInput(true); - } + switch ((UIEventNotification)param3) { + case UIEventNotification::MENU_RETURN: + CloseLaunchItem(); + break; + case UIEventNotification::POPUP_CLOSED: + DeactivateTextEditInput(); + break; + case UIEventNotification::TEXT_GOTFOCUS: + ActivateTextEditInput(true); + break; + case UIEventNotification::TEXT_LOSTFOCUS: + DeactivateTextEditInput(true); + break; + default: + break; } return true; } @@ -650,7 +656,7 @@ std::string GetCPUBrandString() { } catch (const std::exception & e) { const char* what = e.what(); - INFO_LOG(SYSTEM, "%s", what); + INFO_LOG(Log::System, "%s", what); } if (cpu_id != nullptr) { @@ -672,7 +678,7 @@ std::string GetCPUBrandString() { } catch (const std::exception & e) { const char* what = e.what(); - INFO_LOG(SYSTEM, "%s", what); + INFO_LOG(Log::System, "%s", what); } } diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index f3b4c5a085..40838af5ed 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -127,6 +127,7 @@ + @@ -166,6 +167,7 @@ + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index 18fe8834c3..b7bb978d11 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -38,6 +38,7 @@ + @@ -77,5 +78,6 @@ + \ No newline at end of file diff --git a/UWP/UWPHelpers/InputHelpers.cpp b/UWP/UWPHelpers/InputHelpers.cpp index c865ff1b77..441b731094 100644 --- a/UWP/UWPHelpers/InputHelpers.cpp +++ b/UWP/UWPHelpers/InputHelpers.cpp @@ -21,6 +21,7 @@ #include "UWPUtil.h" #include "NKCodeFromWindowsSystem.h" #include "Common/Log.h" +#include "Common/OSVersion.h" #include #include @@ -121,13 +122,13 @@ void ActivateTextEditInput(bool byFocus) { if (!isInputPaneVisible() && (isDPadActive() || !IsXBox())) { if (ShowInputPane()) { - DEBUG_LOG(COMMON, "Input pane: TryShow accepted"); + DEBUG_LOG(Log::Common, "Input pane: TryShow accepted"); } else { - DEBUG_LOG(COMMON, "Input pane: (TryShow is not accepted or not supported)"); + DEBUG_LOG(Log::Common, "Input pane: (TryShow is not accepted or not supported)"); } } - DEBUG_LOG(COMMON, "Text edit active"); + DEBUG_LOG(Log::Common, "Text edit active"); textEditActive = true; })); } @@ -140,14 +141,14 @@ void DeactivateTextEditInput(bool byFocus) { { if (isInputPaneVisible()) { if (HideInputPane()) { - DEBUG_LOG(COMMON, "Input pane: TryHide accepted"); + DEBUG_LOG(Log::Common, "Input pane: TryHide accepted"); } else { - DEBUG_LOG(COMMON, "Input pane: TryHide is not accepted, or not supported"); + DEBUG_LOG(Log::Common, "Input pane: TryHide is not accepted, or not supported"); } } if (isTextEditActive()) { - DEBUG_LOG(COMMON, "Text edit inactive"); + DEBUG_LOG(Log::Common, "Text edit inactive"); textEditActive = false; } })); @@ -238,4 +239,40 @@ bool IsMobile() { auto deviceInfo = Windows::System::Profile::AnalyticsInfo::VersionInfo; return deviceInfo->DeviceFamily == "Windows.Mobile"; } + +void GetVersionInfo(uint32_t& major, uint32_t& minor, uint32_t& build, uint32_t& revision) { + Platform::String^ deviceFamilyVersion = Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamilyVersion; + uint64_t version = std::stoull(deviceFamilyVersion->Data()); + + major = static_cast((version & 0xFFFF000000000000L) >> 48); + minor = static_cast((version & 0x0000FFFF00000000L) >> 32); + build = static_cast((version & 0x00000000FFFF0000L) >> 16); + revision = static_cast(version & 0x000000000000FFFFL); +} + +std::string GetSystemName() { + std::string osName = "Microsoft Windows 10"; + + if (IsXBox()) { + osName = "Xbox OS"; + } + else { + uint32_t major = 0, minor = 0, build = 0, revision = 0; + GetVersionInfo(major, minor, build, revision); + + if (build >= 22000) { + osName = "Microsoft Windows 11"; + } + } + return osName + " " + GetWindowsSystemArchitecture(); +} + +std::string GetWindowsBuild() { + uint32_t major = 0, minor = 0, build = 0, revision = 0; + GetVersionInfo(major, minor, build, revision); + + char buffer[50]; + sprintf_s(buffer, sizeof(buffer), "%u.%u.%u (rev. %u)", major, minor, build, revision); + return std::string(buffer); +} #pragma endregion diff --git a/UWP/UWPHelpers/InputHelpers.h b/UWP/UWPHelpers/InputHelpers.h index d5656e81fc..7bcfb4931c 100644 --- a/UWP/UWPHelpers/InputHelpers.h +++ b/UWP/UWPHelpers/InputHelpers.h @@ -47,3 +47,10 @@ bool IsCtrlOnHold(); std::string GetLangRegion(); bool IsXBox(); bool IsMobile(); + +// Get major, minor, build, revision +void GetVersionInfo(uint32_t& major, uint32_t& minor, uint32_t& build, uint32_t& revision); + +// Get formatted windows info as string (for preview) +std::string GetSystemName(); +std::string GetWindowsBuild(); diff --git a/UWP/UWPHelpers/LaunchItem.cpp b/UWP/UWPHelpers/LaunchItem.cpp index 4f06c173d3..e46bb5e219 100644 --- a/UWP/UWPHelpers/LaunchItem.cpp +++ b/UWP/UWPHelpers/LaunchItem.cpp @@ -60,7 +60,7 @@ public: if (arg->Name == "cmd") { auto command = FromPlatformString(arg->Value); - DEBUG_LOG(FILESYS, "Launch command %s", command.c_str()); + DEBUG_LOG(Log::FileSystem, "Launch command %s", command.c_str()); std::regex rgx("\"(.+[^\\/]+)\""); std::smatch match; @@ -73,12 +73,12 @@ public: catch (...) { launchPath = match[0]; } - DEBUG_LOG(FILESYS, "Launch target %s", launchPath.c_str()); + DEBUG_LOG(Log::FileSystem, "Launch target %s", launchPath.c_str()); } } else if (arg->Name == "launchOnExit") { launchOnExit = FromPlatformString(arg->Value); - DEBUG_LOG(FILESYS, "On exit URI %s", launchOnExit.c_str()); + DEBUG_LOG(Log::FileSystem, "On exit URI %s", launchOnExit.c_str()); } } } @@ -126,12 +126,12 @@ public: if (!launchOnExit.empty()) { if (callLaunchOnExit) { - DEBUG_LOG(FILESYS, "Calling back %s", launchOnExit.c_str()); + DEBUG_LOG(Log::FileSystem, "Calling back %s", launchOnExit.c_str()); auto uri = ref new Windows::Foundation::Uri(ToPlatformString(launchOnExit)); Windows::System::Launcher::LaunchUriAsync(uri); } else { - DEBUG_LOG(FILESYS, "Ignoring callback %s, due to callLaunchOnExit is false", launchOnExit.c_str()); + DEBUG_LOG(Log::FileSystem, "Ignoring callback %s, due to callLaunchOnExit is false", launchOnExit.c_str()); } } launchOnExit = std::string(); diff --git a/UWP/UWPHelpers/StorageAsync.h b/UWP/UWPHelpers/StorageAsync.h index 3f57a2457a..b55066d303 100644 --- a/UWP/UWPHelpers/StorageAsync.h +++ b/UWP/UWPHelpers/StorageAsync.h @@ -31,7 +31,7 @@ T TaskHandler(std::function()> wtask, T def) } catch (Platform::Exception^ exception_) { - ERROR_LOG(FILESYS, FromPlatformString(exception_->Message).c_str()); + ERROR_LOG(Log::FileSystem, FromPlatformString(exception_->Message).c_str()); } done = true; }); diff --git a/UWP/XAudioSoundStream.cpp b/UWP/XAudioSoundStream.cpp index 1e3ee6d0bb..070402598d 100644 --- a/UWP/XAudioSoundStream.cpp +++ b/UWP/XAudioSoundStream.cpp @@ -163,7 +163,7 @@ void XAudioBackend::PollLoop() { xaudioBuffer.AudioBytes = numBytesRendered; if FAILED(xaudioVoice->SubmitSourceBuffer(&xaudioBuffer, NULL)) { - WARN_LOG(AUDIO, "XAudioBackend: Failed writing bytes"); + WARN_LOG(Log::Audio, "XAudioBackend: Failed writing bytes"); } cursor_ += numBytesRendered; if (cursor_ >= BUFSIZE) { diff --git a/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj index a2aec08ba8..d56b5db6a2 100644 --- a/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj +++ b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj @@ -67,7 +67,7 @@ true pch.h _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) - ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ext/miniupnp-build;../../ext/miniupnp/miniupnpc/include;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) Console @@ -89,7 +89,7 @@ true pch.h _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ext/miniupnp-build;../../ext/miniupnp/miniupnpc/include;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) Console @@ -111,7 +111,7 @@ true pch.h _CRT_SECURE_NO_WARNINGS;NOMINMAX;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - ../../ext/miniupnpc;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) + ../../ext/miniupnp-build;../../ext/miniupnp/miniupnpc/include;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) Console @@ -127,35 +127,21 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + Create @@ -163,6 +149,18 @@ + + + + + + + + + + + + diff --git a/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj.filters b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj.filters index 929654b098..0c80d42138 100644 --- a/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj.filters +++ b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj.filters @@ -1,96 +1,52 @@  - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - + src - - - + src - - + + src - - + + src - - + + src - - + + src - - + + src - - + + src - - + + src - - + + src - - + + src - - + + src - - + + src - - + + src - - + + src - + @@ -105,4 +61,36 @@ scripts + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + \ No newline at end of file diff --git a/Windows/CaptureDevice.cpp b/Windows/CaptureDevice.cpp index 7b61fa6fa0..93376078c8 100644 --- a/Windows/CaptureDevice.cpp +++ b/Windows/CaptureDevice.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include + #include "Common/Thread/ThreadUtil.h" #include "CaptureDevice.h" #include "BufferLock.h" @@ -114,12 +115,14 @@ HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride); ReaderCallback::ReaderCallback(WindowsCaptureDevice *_device) : device(_device) {} ReaderCallback::~ReaderCallback() { +#ifdef USE_FFMPEG if (img_convert_ctx) { sws_freeContext(img_convert_ctx); } if (resample_ctx) { swr_free(&resample_ctx); } +#endif } HRESULT ReaderCallback::QueryInterface(REFIID riid, void** ppv) @@ -178,6 +181,7 @@ HRESULT ReaderCallback::OnReadSample( else srcPadding = device->deviceParam.default_stride - lStride; +#ifdef USE_FFMPEG if (SUCCEEDED(hr)) { // Convert image to RGB24 if (lStride > 0) { @@ -196,6 +200,25 @@ HRESULT ReaderCallback::OnReadSample( av_free(invertedSrcImg); } + // Mirror the image in-place if needed. + if (g_Config.bCameraMirrorHorizontal) { + for (int y = 0; y < dstH; y++) { + uint8_t *line = device->imageRGB + y * device->imgRGBLineSizes[0]; + for (int x = 0; x < dstW / 2; x++) { + const int invX = dstW - 1 - x; + const uint8_t r = line[x * 3 + 0]; + const uint8_t g = line[x * 3 + 1]; + const uint8_t b = line[x * 3 + 2]; + line[x * 3 + 0] = line[invX * 3 + 0]; + line[x * 3 + 1] = line[invX * 3 + 1]; + line[x * 3 + 2] = line[invX * 3 + 2]; + line[invX * 3 + 0] = r; + line[invX * 3 + 1] = g; + line[invX * 3 + 2] = b; + } + } + } + // Compress image to jpeg from RGB24. jpge::compress_image_to_jpeg_file_in_memory( device->imageJpeg, imgJpegSize, @@ -204,6 +227,7 @@ HRESULT ReaderCallback::OnReadSample( 3, device->imageRGB); } +#endif Camera::pushCameraImage(imgJpegSize, device->imageJpeg); } // Request the next frame. @@ -220,7 +244,7 @@ HRESULT ReaderCallback::OnReadSample( delete videoBuffer; break; } - case CAPTUREDEVIDE_TYPE::AUDIO: { + case CAPTUREDEVIDE_TYPE::Audio: { BYTE *sampleBuf = nullptr; DWORD length = 0; u32 sizeAfterResample = 0; @@ -278,12 +302,14 @@ void ReaderCallback::imgConvert( unsigned char *dst, unsigned int &dstW, unsigned int &dstH, int dstLineSizes[4], unsigned char *src, const unsigned int &srcW, const unsigned int &srcH, const GUID &srcFormat, const int &srcPadding) { +#ifdef USE_FFMPEG int srcLineSizes[4] = { 0, 0, 0, 0 }; unsigned char *pSrc[4]; unsigned char *pDst[4]; AVPixelFormat srcAVFormat = getAVVideoFormatbyMFVideoFormat(srcFormat); + av_image_fill_linesizes(srcLineSizes, srcAVFormat, srcW); // Is this correct? @@ -322,9 +348,11 @@ void ReaderCallback::imgConvert( dstLineSizes ); } +#endif } void ReaderCallback::imgInvert(unsigned char *dst, unsigned char *src, const int &srcW, const int &srcH, const GUID &srcFormat, const int &srcStride) { +#ifdef USE_FFMPEG AVPixelFormat srcAvFormat = getAVVideoFormatbyMFVideoFormat(srcFormat); int dstLineSizes[4] = { 0, 0, 0, 0 }; @@ -338,6 +366,7 @@ void ReaderCallback::imgInvert(unsigned char *dst, unsigned char *src, const int imgInvertYUY2(dst, dstLineSizes[0], src, srcStride, srcH); else if (srcFormat == MFVideoFormat_NV12) imgInvertNV12(dst, dstLineSizes[0], src, srcStride, srcH);; +#endif } void ReaderCallback::imgInvertRGBA(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h) { @@ -392,6 +421,7 @@ void ReaderCallback::imgInvertNV12(unsigned char *dst, int &dstStride, unsigned } u32 ReaderCallback::doResample(u8 **dst, u32 &dstSampleRate, u32 &dstChannels, u32 *dstSize, u8 *src, const u32 &srcSampleRate, const u32 &srcChannels, const GUID &srcFormat, const u32& srcSize, const u32& srcBitsPerSample) { +#ifdef USE_FFMPEG AVSampleFormat srcAVFormat = getAVAudioFormatbyMFAudioFormat(srcFormat, srcBitsPerSample); int outSamplesCount = 0; if (resample_ctx == nullptr) { @@ -427,6 +457,9 @@ u32 ReaderCallback::doResample(u8 **dst, u32 &dstSampleRate, u32 &dstChannels, u if (outSamplesCount < 0) return 0; return av_samples_get_buffer_size(nullptr, dstChannels, outSamplesCount, AV_SAMPLE_FMT_S16, 0); +#else + return 0; +#endif } WindowsCaptureDevice::WindowsCaptureDevice(CAPTUREDEVIDE_TYPE _type) : @@ -440,7 +473,7 @@ WindowsCaptureDevice::WindowsCaptureDevice(CAPTUREDEVIDE_TYPE _type) : case CAPTUREDEVIDE_TYPE::VIDEO: targetMediaParam = defaultVideoParam; break; - case CAPTUREDEVIDE_TYPE::AUDIO: + case CAPTUREDEVIDE_TYPE::Audio: targetMediaParam = defaultAudioParam; break; } @@ -450,15 +483,17 @@ WindowsCaptureDevice::WindowsCaptureDevice(CAPTUREDEVIDE_TYPE _type) : } WindowsCaptureDevice::~WindowsCaptureDevice() { +#ifdef USE_FFMPEG switch (type) { case CAPTUREDEVIDE_TYPE::VIDEO: av_freep(&imageRGB); av_freep(&imageJpeg); break; - case CAPTUREDEVIDE_TYPE::AUDIO: + case CAPTUREDEVIDE_TYPE::Audio: av_freep(&resampleBuf); break; } +#endif } void WindowsCaptureDevice::CheckDevices() { @@ -555,6 +590,7 @@ bool WindowsCaptureDevice::start(void *startParam) { targetMediaParam.height = resolution->at(1); delete resolution; } +#ifdef USE_FFMPEG av_freep(&imageRGB); av_freep(&imageJpeg); @@ -562,6 +598,7 @@ bool WindowsCaptureDevice::start(void *startParam) { imgJpegSize = av_image_get_buffer_size(AV_PIX_FMT_YUVJ411P, targetMediaParam.width, targetMediaParam.height, 1); imageJpeg = (unsigned char*)av_malloc(imgJpegSize); av_image_fill_linesizes(imgRGBLineSizes, AV_PIX_FMT_RGB24, targetMediaParam.width); +#endif for (DWORD i = 0; ; i++) { hr = m_pReader->GetNativeMediaType( @@ -600,7 +637,7 @@ bool WindowsCaptureDevice::start(void *startParam) { break; } - case CAPTUREDEVIDE_TYPE::AUDIO: { + case CAPTUREDEVIDE_TYPE::Audio: { if (startParam) { std::vector *micParam = static_cast*>(startParam); targetMediaParam.sampleRate = micParam->at(0); @@ -786,7 +823,7 @@ HRESULT WindowsCaptureDevice::setDeviceParam(IMFMediaType *pType) { hr = GetDefaultStride(pType, &deviceParam.default_stride); break; - case CAPTUREDEVIDE_TYPE::AUDIO: + case CAPTUREDEVIDE_TYPE::Audio: hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); if (FAILED(hr)) break; @@ -875,7 +912,7 @@ void WindowsCaptureDevice::messageHandler() { if (type == CAPTUREDEVIDE_TYPE::VIDEO) { SetCurrentThreadName("Camera"); - } else if (type == CAPTUREDEVIDE_TYPE::AUDIO) { + } else if (type == CAPTUREDEVIDE_TYPE::Audio) { SetCurrentThreadName("Microphone"); } @@ -932,7 +969,7 @@ HRESULT WindowsCaptureDevice::enumDevices() { ); break; - case CAPTUREDEVIDE_TYPE::AUDIO: + case CAPTUREDEVIDE_TYPE::Audio: hr = pAttributes->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID diff --git a/Windows/CaptureDevice.h b/Windows/CaptureDevice.h index d0ed3b4b5f..0107f3d774 100644 --- a/Windows/CaptureDevice.h +++ b/Windows/CaptureDevice.h @@ -50,7 +50,7 @@ struct AudioFormatTransform { enum class CAPTUREDEVIDE_TYPE { VIDEO, - AUDIO + Audio }; enum class CAPTUREDEVIDE_STATE { diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index 05b36f12aa..d72e0a90b3 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -676,9 +676,10 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) Show(false); return TRUE; case WM_ACTIVATE: - if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) - { + if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) { g_activeWindow = WINDOW_CPUDEBUGGER; + } else { + g_activeWindow = WINDOW_OTHER; } break; diff --git a/Windows/Debugger/Debugger_MemoryDlg.cpp b/Windows/Debugger/Debugger_MemoryDlg.cpp index 670713e1c3..7c320212ab 100644 --- a/Windows/Debugger/Debugger_MemoryDlg.cpp +++ b/Windows/Debugger/Debugger_MemoryDlg.cpp @@ -13,7 +13,7 @@ #include "Debugger_MemoryDlg.h" #include "CtrlMemView.h" #include "DebuggerShared.h" -#include "LogManager.h" +#include "Common/Log.h" #include "winnt.h" #include #include diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index 052253fbde..d560bd74da 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -116,7 +116,7 @@ static void EmuThreadStop() { static void EmuThreadJoin() { emuThread.join(); - INFO_LOG(SYSTEM, "EmuThreadJoin - joined"); + INFO_LOG(Log::System, "EmuThreadJoin - joined"); } bool CreateGraphicsBackend(std::string *error_message, GraphicsContext **ctx) { @@ -240,7 +240,7 @@ void MainThreadFunc() { std::string full_error = StringFromFormat("%.*s\n\n%s", (int)genericError.size(), genericError.data(), error_string.c_str()); std::wstring title = ConvertUTF8ToWString(err->T("GenericGraphicsError", "Graphics Error")); bool yes = IDYES == MessageBox(0, ConvertUTF8ToWString(full_error).c_str(), title.c_str(), MB_ICONERROR | MB_YESNO); - ERROR_LOG(BOOT, "%s", full_error.c_str()); + ERROR_LOG(Log::Boot, "%s", full_error.c_str()); if (yes) { // Change the config to the alternative and restart. @@ -268,10 +268,10 @@ void MainThreadFunc() { NativeResized(); } - DEBUG_LOG(BOOT, "Done."); + DEBUG_LOG(Log::Boot, "Done."); if (coreState == CORE_POWERDOWN) { - INFO_LOG(BOOT, "Exit before core loop."); + INFO_LOG(Log::Boot, "Exit before core loop."); goto shutdown; } diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index e33e882e6f..12ab35ea97 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -1073,6 +1073,8 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case WM_ACTIVATE: if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) { g_activeWindow = WINDOW_GEDEBUGGER; + } else { + g_activeWindow = WINDOW_OTHER; } break; diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index 3056d9fee3..eb21c5512b 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -116,7 +116,7 @@ void SimpleGLWindow::SetupGL() { pfd.cDepthBits = 16; pfd.iLayerType = PFD_MAIN_PLANE; -#define ENFORCE(x, msg) { if (!(x)) { ERROR_LOG(COMMON, "SimpleGLWindow: %s (%08x)", msg, (uint32_t)GetLastError()); return; } } +#define ENFORCE(x, msg) { if (!(x)) { ERROR_LOG(Log::Common, "SimpleGLWindow: %s (%08x)", msg, (uint32_t)GetLastError()); return; } } ENFORCE(hDC_ = GetDC(hWnd_), "Unable to create DC."); ENFORCE(pixelFormat = ChoosePixelFormat(hDC_, &pfd), "Unable to match pixel format."); diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index ea416aa0b3..f508037f49 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -286,11 +286,11 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) { } if (prim_type >= 7) { - ERROR_LOG(G3D, "Unsupported prim type: %x", op); + ERROR_LOG(Log::G3D, "Unsupported prim type: %x", op); return; } if (!gpuDebug) { - ERROR_LOG(G3D, "Invalid debugging environment, shutting down?"); + ERROR_LOG(Log::G3D, "Invalid debugging environment, shutting down?"); return; } which &= previewsEnabled_; @@ -303,7 +303,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) { static std::vector indices; if (!gpuDebug->GetCurrentSimpleVertices(count, vertices, indices)) { - ERROR_LOG(G3D, "Vertex preview not yet supported"); + ERROR_LOG(Log::G3D, "Vertex preview not yet supported"); return; } diff --git a/Windows/GPU/D3D9Context.cpp b/Windows/GPU/D3D9Context.cpp index 11ce38367a..e23eb562e0 100644 --- a/Windows/GPU/D3D9Context.cpp +++ b/Windows/GPU/D3D9Context.cpp @@ -35,7 +35,7 @@ bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { hD3D9_ = LoadLibrary(TEXT("d3d9.dll")); if (!hD3D9_) { - ERROR_LOG(G3D, "Missing d3d9.dll"); + ERROR_LOG(Log::G3D, "Missing d3d9.dll"); *error_message = "D3D9.dll missing - try reinstalling DirectX."; return false; } diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index e799a2e330..b61d26ad89 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -49,7 +49,7 @@ void WindowsGLContext::Poll() { resumeRequested = true; DWORD result = WaitForSingleObject(resumeEvent, INFINITE); if (result == WAIT_TIMEOUT) { - ERROR_LOG(G3D, "Wait for resume timed out. Resuming rendering"); + ERROR_LOG(Log::G3D, "Wait for resume timed out. Resuming rendering"); } pauseRequested = false; } @@ -66,7 +66,7 @@ void WindowsGLContext::Pause() { pauseRequested = true; DWORD result = WaitForSingleObject(pauseEvent, INFINITE); if (result == WAIT_TIMEOUT) { - ERROR_LOG(G3D, "Wait for pause timed out"); + ERROR_LOG(Log::G3D, "Wait for pause timed out"); } // OK, we now know the rendering thread is paused. } @@ -80,7 +80,7 @@ void WindowsGLContext::Resume() { } if (!resumeRequested) { - ERROR_LOG(G3D, "Not waiting to get resumed"); + ERROR_LOG(Log::G3D, "Not waiting to get resumed"); } else { SetEvent(resumeEvent); } @@ -156,18 +156,18 @@ void DebugCallbackARB(GLenum source, GLenum type, GLuint id, GLenum severity, case GL_DEBUG_TYPE_ERROR_ARB: case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: - ERROR_LOG(G3D, "GL: %s", finalMessage); + ERROR_LOG(Log::G3D, "GL: %s", finalMessage); break; case GL_DEBUG_TYPE_PORTABILITY_ARB: case GL_DEBUG_TYPE_PERFORMANCE_ARB: - NOTICE_LOG(G3D, "GL: %s", finalMessage); + NOTICE_LOG(Log::G3D, "GL: %s", finalMessage); break; case GL_DEBUG_TYPE_OTHER_ARB: default: // These are just performance warnings. - VERBOSE_LOG(G3D, "GL: %s", finalMessage); + VERBOSE_LOG(Log::G3D, "GL: %s", finalMessage); break; } } @@ -383,21 +383,21 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) { glGetError(); glDebugMessageCallback((GLDEBUGPROC)&DebugCallbackARB, nullptr); if (glGetError()) { - ERROR_LOG(G3D, "Failed to register a debug log callback"); + ERROR_LOG(Log::G3D, "Failed to register a debug log callback"); } glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); if (glGetError()) { - ERROR_LOG(G3D, "Failed to enable synchronous debug output"); + ERROR_LOG(Log::G3D, "Failed to enable synchronous debug output"); } } else if (glewIsSupported("GL_ARB_debug_output")) { glGetError(); glDebugMessageCallbackARB((GLDEBUGPROCARB)&DebugCallbackARB, 0); // print debug output to stderr if (glGetError()) { - ERROR_LOG(G3D, "Failed to register a debug log callback"); + ERROR_LOG(Log::G3D, "Failed to register a debug log callback"); } glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); if (glGetError()) { - ERROR_LOG(G3D, "Failed to enable synchronous debug output"); + ERROR_LOG(Log::G3D, "Failed to enable synchronous debug output"); } // For extra verbosity uncomment this (MEDIUM and HIGH are on by default): diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 13ee5f1bf1..cec6f494ca 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -118,8 +118,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m g_Config.sVulkanDevice = vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName; } - vulkan_->ChooseDevice(deviceNum); - if (vulkan_->CreateDevice() != VK_SUCCESS) { + if (vulkan_->CreateDevice(deviceNum) != VK_SUCCESS) { *error_message = vulkan_->InitError(); delete vulkan_; vulkan_ = nullptr; diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 2cdafcaccf..09857e31d2 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "Common/System/Display.h" #include "Common/System/NativeApp.h" @@ -71,8 +72,8 @@ #include "Windows/resource.h" #include "Windows/MainWindow.h" -#include "Common/LogManager.h" -#include "Common/ConsoleListener.h" +#include "Common/Log/LogManager.h" +#include "Common/Log/ConsoleListener.h" #include "Windows/W32Util/DialogManager.h" #include "Windows/W32Util/ShellUtil.h" #include "Windows/W32Util/Misc.h" @@ -136,6 +137,7 @@ namespace MainWindow static bool inResizeMove = false; static bool hasFocus = true; static bool g_isFullscreen = false; + static bool g_keepScreenBright = false; static bool disasmMapLoadPending = false; static bool memoryMapLoadPending = false; @@ -160,6 +162,10 @@ namespace MainWindow return hwndDisplay; } + void SetKeepScreenBright(bool keepBright) { + g_keepScreenBright = keepBright; + } + void Init(HINSTANCE hInstance) { // Register classes - Main Window WNDCLASSEX wcex; @@ -286,7 +292,7 @@ namespace MainWindow PSP_CoreParameter().pixelHeight = height; } - DEBUG_LOG(SYSTEM, "Pixel width/height: %dx%d", PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); + DEBUG_LOG(Log::System, "Pixel width/height: %dx%d", PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); if (UpdateScreenScale(width, height)) { System_PostUIMessage(UIMessage::GPU_DISPLAY_RESIZED); @@ -483,6 +489,10 @@ namespace MainWindow SetWindowLong(hwndMain, GWL_EXSTYLE, WS_EX_APPWINDOW); + + const DWM_WINDOW_CORNER_PREFERENCE pref = DWMWCP_DONOTROUND; + DwmSetWindowAttribute(hwndMain, DWMWA_WINDOW_CORNER_PREFERENCE, &pref, sizeof(pref)); + RECT rcClient; GetClientRect(hwndMain, &rcClient); @@ -599,12 +609,6 @@ namespace MainWindow static bool firstErase = true; switch (message) { - case WM_ACTIVATE: - if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) { - g_activeWindow = WINDOW_MAINWINDOW; - } - break; - case WM_SIZE: break; @@ -761,7 +765,7 @@ namespace MainWindow switch (message) { case WM_CREATE: - if (!DoesVersionMatchWindows(6, 0, 0, 0, true)) { + if (!IsVistaOrHigher()) { // Remove the D3D11 choice on versions below XP RemoveMenu(GetMenu(hWnd), ID_OPTIONS_DIRECT3D11, MF_BYCOMMAND); } @@ -770,6 +774,13 @@ namespace MainWindow } break; + case WM_USER_RUN_CALLBACK: + { + auto callback = reinterpret_cast(wParam); + void *userdata = reinterpret_cast(lParam); + callback(hWnd, userdata); + break; + } case WM_USER_GET_BASE_POINTER: Reporting::NotifyDebugger(); switch (lParam) { @@ -829,9 +840,11 @@ namespace MainWindow } g_activeWindow = WINDOW_MAINWINDOW; pause = false; + } else { + g_activeWindow = WINDOW_OTHER; } if (!noFocusPause && g_Config.bPauseOnLostFocus && GetUIState() == UISTATE_INGAME) { - if (pause != Core_IsStepping()) { // != is xor for bools + if (pause != Core_IsStepping()) { if (disasmWindow) SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0); else @@ -1000,19 +1013,19 @@ namespace MainWindow return DefWindowProc(hWnd, message, wParam, lParam); HDROP hdrop = (HDROP)wParam; - int count = DragQueryFile(hdrop,0xFFFFFFFF,0,0); + int count = DragQueryFile(hdrop, 0xFFFFFFFF, 0, 0); if (count != 1) { - MessageBox(hwndMain,L"You can only load one file at a time",L"Error",MB_ICONINFORMATION); - } - else - { - TCHAR filename[512]; - if (DragQueryFile(hdrop, 0, filename, 512) != 0) { + // TODO: Translate? Or just not bother? + MessageBox(hwndMain, L"You can only load one file at a time", L"Error", MB_ICONINFORMATION); + } else { + TCHAR filename[1024]; + if (DragQueryFile(hdrop, 0, filename, ARRAY_SIZE(filename)) != 0) { const std::string utf8_filename = ReplaceAll(ConvertWStringToUTF8(filename), "\\", "/"); System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, utf8_filename); Core_EnableStepping(false); } } + DragFinish(hdrop); } break; @@ -1075,20 +1088,32 @@ namespace MainWindow trapMouse = true; break; - // Turn off the screensaver. + // Turn off the screensaver if in-game. // Note that if there's a screensaver password, this simple method // doesn't work on Vista or higher. case WM_SYSCOMMAND: - { + // Disable Alt key for menu if it's been mapped. + if (wParam == SC_KEYMENU && (lParam >> 16) <= 0) { + if (KeyMap::IsKeyMapped(DEVICE_ID_KEYBOARD, NKCODE_ALT_LEFT) || KeyMap::IsKeyMapped(DEVICE_ID_KEYBOARD, NKCODE_ALT_RIGHT)) { + return 0; + } + } + if (g_keepScreenBright) { switch (wParam) { case SC_SCREENSAVE: return 0; case SC_MONITORPOWER: - return 0; + if (lParam == 1 || lParam == 2) { + return 0; + } else { + break; + } + default: + // fall down to DefWindowProc + break; } - return DefWindowProc(hWnd, message, wParam, lParam); } - break; + return DefWindowProc(hWnd, message, wParam, lParam); case WM_SETTINGCHANGE: { if (g_darkModeSupported && IsColorSchemeChangeMessage(lParam)) @@ -1139,4 +1164,8 @@ namespace MainWindow return g_isFullscreen; } + void RunCallbackInWndProc(void (*callback)(void *, void *), void *userdata) { + PostMessage(hwndMain, WM_USER_RUN_CALLBACK, reinterpret_cast(callback), reinterpret_cast(userdata)); + } + } // namespace diff --git a/Windows/MainWindow.h b/Windows/MainWindow.h index c4ed9f81fd..5bed554c71 100644 --- a/Windows/MainWindow.h +++ b/Windows/MainWindow.h @@ -18,7 +18,8 @@ namespace MainWindow WM_USER_WINDOW_TITLE_CHANGED = WM_USER + 103, WM_USER_TOGGLE_FULLSCREEN = WM_USER + 105, WM_USER_RESTART_EMUTHREAD = WM_USER + 106, - WM_USER_SWITCHUMD_UPDATED = WM_USER + 107 + WM_USER_SWITCHUMD_UPDATED = WM_USER + 107, + WM_USER_RUN_CALLBACK = WM_USER + 108, }; enum { @@ -79,6 +80,8 @@ namespace MainWindow void ToggleDebugConsoleVisibility(); void SetInternalResolution(int res = -1); void SetWindowSize(int zoom); + void RunCallbackInWndProc(void (*callback)(void *window, void *userdata), void *userdata); + void SetKeepScreenBright(bool keepBright); } #endif diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 22ab1e0e86..c3237c56da 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -19,8 +19,8 @@ #include "Common/System/Request.h" #include "Common/File/FileUtil.h" #include "Common/Log.h" -#include "Common/LogManager.h" -#include "Common/ConsoleListener.h" +#include "Common/Log/LogManager.h" +#include "Common/Log/ConsoleListener.h" #include "Common/OSVersion.h" #include "Common/GPU/Vulkan/VulkanLoader.h" #include "Common/StringUtils.h" @@ -53,6 +53,10 @@ #include "Core/Core.h" #include "Core/RetroAchievements.h" +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION +#include "ext/rcheevos/include/rc_client_raintegration.h" +#endif + extern bool g_TakeScreenshot; namespace MainWindow { @@ -103,7 +107,6 @@ namespace MainWindow { EnableMenuItem(menu, ID_DEBUG_LOADSYMFILE, menuEnable); EnableMenuItem(menu, ID_DEBUG_SAVESYMFILE, menuEnable); EnableMenuItem(menu, ID_DEBUG_RESETSYMBOLTABLE, menuEnable); - EnableMenuItem(menu, ID_DEBUG_TAKESCREENSHOT, menuEnable); EnableMenuItem(menu, ID_DEBUG_SHOWDEBUGSTATISTICS, menuInGameEnable); EnableMenuItem(menu, ID_DEBUG_EXTRACTFILE, menuEnable); EnableMenuItem(menu, ID_DEBUG_MEMORYBASE, menuInGameEnable); @@ -233,6 +236,7 @@ namespace MainWindow { TranslateMenuItem(menu, ID_DEBUG_TAKESCREENSHOT, g_Config.bSystemControls ? L"\tF12" : L""); TranslateMenuItem(menu, ID_DEBUG_DUMPNEXTFRAME); TranslateMenuItem(menu, ID_DEBUG_SHOWDEBUGSTATISTICS); + TranslateMenuItem(menu, ID_DEBUG_RESTARTGRAPHICS); TranslateMenuItem(menu, ID_DEBUG_DISASSEMBLY, g_Config.bSystemControls ? L"\tCtrl+D" : L""); TranslateMenuItem(menu, ID_DEBUG_GEDEBUGGER, g_Config.bSystemControls ? L"\tCtrl+G" : L""); TranslateMenuItem(menu, ID_DEBUG_EXTRACTFILE); @@ -946,7 +950,12 @@ namespace MainWindow { break; default: - MessageBox(hWnd, L"Unimplemented", L"Sorry", 0); +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION + if (rc_client_raintegration_activate_menu_item(Achievements::GetClient(), LOWORD(wParam))) { + break; + } +#endif + MessageBox(hWnd, L"Unhandled menu item", L"Sorry", 0); break; } } diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 01128f75fb..031296a483 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -231,7 +231,7 @@ - _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USE_FFMPEG;RC_CLIENT_SUPPORTS_RAINTEGRATION;_CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) false Sync Use @@ -249,7 +249,7 @@ stdcpp17 - winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) + dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) ../ffmpeg/Windows/x86/lib true Windows @@ -271,7 +271,7 @@ false - _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USE_FFMPEG;RC_CLIENT_SUPPORTS_RAINTEGRATION;_CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Sync Use Level3 @@ -289,7 +289,7 @@ stdcpp17 - winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) + dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) ../ffmpeg/Windows/x86_64/lib true $(OutDir)$(ProjectName).pdb @@ -307,7 +307,7 @@ false - _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USE_FFMPEG;_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Sync Use Level3 @@ -325,7 +325,7 @@ stdcpp17 - winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies) + dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies) ../ffmpeg/Windows/aarch64/lib true $(OutDir)$(ProjectName).pdb @@ -343,7 +343,7 @@ false - _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USE_FFMPEG;_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) Use Level3 ProgramDatabase @@ -359,7 +359,7 @@ stdcpp17 - winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies) + dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies) ../ffmpeg/Windows/arm/lib true $(OutDir)$(ProjectName).pdb @@ -378,7 +378,7 @@ AnySuitable true Speed - USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USE_FFMPEG;RC_CLIENT_SUPPORTS_RAINTEGRATION;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -397,7 +397,7 @@ stdcpp17 - winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) + dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) ../ffmpeg/Windows/x86/lib;%(AdditionalLibraryDirectories) $(OutDir)$(TargetName)$(TargetExt) true @@ -428,7 +428,7 @@ true Speed false - USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USE_FFMPEG;RC_CLIENT_SUPPORTS_RAINTEGRATION;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -446,7 +446,7 @@ stdcpp17 - winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) + dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) ../ffmpeg/Windows/x86_64/lib;%(AdditionalLibraryDirectories) true Windows @@ -471,7 +471,7 @@ true Speed false - USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USE_FFMPEG;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -489,7 +489,7 @@ stdcpp17 - winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies) + dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies) ../ffmpeg/Windows/aarch64/lib;%(AdditionalLibraryDirectories) true Windows @@ -513,7 +513,7 @@ true Speed false - USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + USE_FFMPEG;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -530,7 +530,7 @@ stdcpp17 - winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies) + dwmapi.lib;winhttp.lib;uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies) ../ffmpeg/Windows/arm/lib;%(AdditionalLibraryDirectories) true Windows @@ -1334,6 +1334,7 @@ true true + true @@ -1683,6 +1684,7 @@ true + true true diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 1c228494e9..b1b0525a34 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -580,6 +580,9 @@ Other Platforms\Mac + + Other Platforms\iOS + @@ -815,6 +818,9 @@ Other Platforms\Mac + + Other Platforms\iOS + diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index 81f833681e..a8e7ceea01 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -196,7 +196,7 @@ namespace WindowsRawInput { dev[2].dwFlags = 0; if (!RegisterRawInputDevices(dev, 3, sizeof(RAWINPUTDEVICE))) { - WARN_LOG(SYSTEM, "Unable to register raw input devices: %s", GetLastErrorMsg().c_str()); + WARN_LOG(Log::System, "Unable to register raw input devices: %s", GetLastErrorMsg().c_str()); } } diff --git a/Windows/TouchInputHandler.cpp b/Windows/TouchInputHandler.cpp index 56b91c5275..ff359a01db 100644 --- a/Windows/TouchInputHandler.cpp +++ b/Windows/TouchInputHandler.cpp @@ -90,7 +90,7 @@ void TouchInputHandler::handleTouchEvent(HWND hWnd, UINT message, WPARAM wParam, } closeTouch(touchInputData); } else { - WARN_LOG(SYSTEM, "Failed to read input data: %s", GetLastErrorMsg().c_str()); + WARN_LOG(Log::System, "Failed to read input data: %s", GetLastErrorMsg().c_str()); } delete [] inputs; } diff --git a/Windows/W32Util/ShellUtil.cpp b/Windows/W32Util/ShellUtil.cpp index 32c5d3b272..c0f3af4a49 100644 --- a/Windows/W32Util/ShellUtil.cpp +++ b/Windows/W32Util/ShellUtil.cpp @@ -6,6 +6,8 @@ #include #include "Common/Data/Encoding/Utf8.h" +#include "Common/File/FileUtil.h" +#include "Common/Data/Format/PNGLoad.h" #include "ShellUtil.h" #include @@ -188,7 +190,7 @@ namespace W32Util { // http://msdn.microsoft.com/en-us/library/aa969393.aspx -HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathLink, LPCWSTR lpszDesc) { +static HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszIcon, int iconIndex) { HRESULT hres; IShellLink *psl = nullptr; hres = CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -205,7 +207,9 @@ HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathL psl->SetPath(lpszPathObj); psl->SetArguments(lpszArguments); psl->SetDescription(lpszDesc); - // psl->SetIconLocation(..) + if (lpszIcon) { + psl->SetIconLocation(lpszIcon, iconIndex); + } // Query IShellLink for the IPersistFile interface, used for saving the // shortcut in persistent storage. @@ -223,7 +227,7 @@ HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathL return hres; } -bool CreateDesktopShortcut(std::string_view argumentPath, std::string_view gameTitleStr) { +bool CreateDesktopShortcut(std::string_view argumentPath, std::string_view gameTitleStr, const Path &icoFile) { // Get the desktop folder wchar_t *pathbuf = new wchar_t[4096]; SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, pathbuf); @@ -264,7 +268,12 @@ bool CreateDesktopShortcut(std::string_view argumentPath, std::string_view gameT sanitizedArgument = "\"" + sanitizedArgument + "\""; - CreateLink(moduleFilename.c_str(), ConvertUTF8ToWString(sanitizedArgument).c_str(), pathbuf, ConvertUTF8ToWString(gameTitle).c_str()); + std::wstring icon; + if (!icoFile.empty()) { + icon = icoFile.ToWString(); + } + + CreateLink(moduleFilename.c_str(), ConvertUTF8ToWString(sanitizedArgument).c_str(), pathbuf, ConvertUTF8ToWString(gameTitle).c_str(), icon.empty() ? nullptr : icon.c_str(), 0); // TODO: Also extract the game icon and convert to .ico, put it somewhere under Memstick, and set it. @@ -272,4 +281,56 @@ bool CreateDesktopShortcut(std::string_view argumentPath, std::string_view gameT return false; } +// Function to create an icon file from PNG image data (these icons require Windows Vista). +// The Old New Thing comes to the rescue again! ChatGPT failed miserably. +// https://devblogs.microsoft.com/oldnewthing/20101018-00/?p=12513 +// https://devblogs.microsoft.com/oldnewthing/20101022-00/?p=12473 +bool CreateICOFromPNGData(const uint8_t *imageData, size_t imageDataSize, const Path &icoPath) { + if (imageDataSize <= sizeof(PNGHeaderPeek)) { + return false; + } + // Parse the PNG + PNGHeaderPeek pngHeader; + memcpy(&pngHeader, imageData, sizeof(PNGHeaderPeek)); + if (pngHeader.Width() > 256 || pngHeader.Height() > 256) { + // Reject the png as an icon. + return false; + } + + struct IconHeader { + uint16_t reservedZero; + uint16_t type; // should be 1 + uint16_t imageCount; + }; + IconHeader hdr{ 0, 1, 1 }; + struct IconDirectoryEntry { + BYTE bWidth; + BYTE bHeight; + BYTE bColorCount; + BYTE bReserved; + WORD wPlanes; + WORD wBitCount; + DWORD dwBytesInRes; + DWORD dwImageOffset; + }; + IconDirectoryEntry entry{}; + entry.bWidth = pngHeader.Width(); + entry.bHeight = pngHeader.Height(); + entry.bColorCount = 0; + entry.dwBytesInRes = (DWORD)imageDataSize; + entry.wPlanes = 1; + entry.wBitCount = 32; + entry.dwImageOffset = sizeof(hdr) + sizeof(entry); + + FILE *file = File::OpenCFile(icoPath, "wb"); + if (!file) { + return false; + } + fwrite(&hdr, sizeof(hdr), 1, file); + fwrite(&entry, sizeof(entry), 1, file); + fwrite(imageData, 1, imageDataSize, file); + fclose(file); + return true; +} + } // namespace diff --git a/Windows/W32Util/ShellUtil.h b/Windows/W32Util/ShellUtil.h index fb0247e7f3..8201ae691b 100644 --- a/Windows/W32Util/ShellUtil.h +++ b/Windows/W32Util/ShellUtil.h @@ -5,18 +5,22 @@ #include #include +class Path; + namespace W32Util { - // Can't make initialPath a string_view, need the null so might as well require it. - std::string BrowseForFolder(HWND parent, std::string_view title, std::string_view initialPath); - std::string BrowseForFolder(HWND parent, const wchar_t *title, std::string_view initialPath); - bool BrowseForFileName (bool _bLoad, HWND _hParent, const wchar_t*_pTitle, - const wchar_t *_pInitialFolder,const wchar_t *_pFilter,const wchar_t*_pExtension, - std::string& _strFileName); - std::vector BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const wchar_t*_pTitle, - const wchar_t*_pInitialFolder,const wchar_t*_pFilter,const wchar_t*_pExtension); +// Can't make initialPath a string_view, need the null so might as well require it. +std::string BrowseForFolder(HWND parent, std::string_view title, std::string_view initialPath); +std::string BrowseForFolder(HWND parent, const wchar_t *title, std::string_view initialPath); +bool BrowseForFileName(bool _bLoad, HWND _hParent, const wchar_t*_pTitle, + const wchar_t *_pInitialFolder, const wchar_t *_pFilter, const wchar_t*_pExtension, + std::string& _strFileName); +std::vector BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const wchar_t*_pTitle, + const wchar_t*_pInitialFolder, const wchar_t*_pFilter, const wchar_t*_pExtension); - std::string UserDocumentsPath(); +std::string UserDocumentsPath(); - bool CreateDesktopShortcut(std::string_view argumentPath, std::string_view gameTitle); -} // namespace +bool CreateDesktopShortcut(std::string_view argumentPath, std::string_view gameTitle, const Path &icoFile); +bool CreateICOFromPNGData(const uint8_t *imageData, size_t imageDataSize, const Path &icoPath); + +} // namespace diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp index 2844934eb5..034bdafd74 100644 --- a/Windows/WASAPIStream.cpp +++ b/Windows/WASAPIStream.cpp @@ -54,7 +54,7 @@ public: } if (currentDevice_) { - INFO_LOG(SCEAUDIO, "Switching to WASAPI audio device: '%s'", GetDeviceName(currentDevice_).c_str()); + INFO_LOG(Log::sceAudio, "Switching to WASAPI audio device: '%s'", GetDeviceName(currentDevice_).c_str()); } deviceChanged_ = false; @@ -112,7 +112,7 @@ public: } deviceChanged_ = true; - INFO_LOG(SCEAUDIO, "New default eRender/eConsole WASAPI audio device detected: '%s'", GetDeviceName(pwstrDeviceId).c_str()); + INFO_LOG(Log::sceAudio, "New default eRender/eConsole WASAPI audio device detected: '%s'", GetDeviceName(pwstrDeviceId).c_str()); return S_OK; } @@ -132,7 +132,7 @@ public: } HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) override { - INFO_LOG(SCEAUDIO, "Changed audio device property " + INFO_LOG(Log::sceAudio, "Changed audio device property " "{%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}#%d", (uint32_t)key.fmtid.Data1, key.fmtid.Data2, key.fmtid.Data3, key.fmtid.Data4[0], key.fmtid.Data4[1], @@ -368,14 +368,14 @@ bool WASAPIAudioThread::DetectFormat() { } else { wchar_t guid[256]{}; StringFromGUID2(closest->SubFormat, guid, 256); - ERROR_LOG_REPORT_ONCE(badfallbackclosest, SCEAUDIO, "WASAPI fallback and closest unsupported (fmt=%04x/%s)", closest->Format.wFormatTag, guid); + ERROR_LOG_REPORT_ONCE(badfallbackclosest, Log::sceAudio, "WASAPI fallback and closest unsupported (fmt=%04x/%s)", closest->Format.wFormatTag, guid); CoTaskMemFree(closest); return false; } } else { CoTaskMemFree(closest); if (hr != AUDCLNT_E_DEVICE_INVALIDATED && hr != AUDCLNT_E_SERVICE_NOT_RUNNING) - ERROR_LOG_REPORT_ONCE(badfallback, SCEAUDIO, "WASAPI fallback format was unsupported (%08x)", hr); + ERROR_LOG_REPORT_ONCE(badfallback, Log::sceAudio, "WASAPI fallback format was unsupported (%08x)", hr); return false; } } @@ -397,7 +397,7 @@ bool WASAPIAudioThread::ValidateFormat(const WAVEFORMATEXTENSIBLE *fmt) { } else { wchar_t guid[256]{}; StringFromGUID2(fmt->SubFormat, guid, 256); - ERROR_LOG_REPORT_ONCE(unexpectedformat, SCEAUDIO, "Got unexpected WASAPI 0xFFFE stream format (%S), expected float!", guid); + ERROR_LOG_REPORT_ONCE(unexpectedformat, Log::sceAudio, "Got unexpected WASAPI 0xFFFE stream format (%S), expected float!", guid); if (fmt->Format.wBitsPerSample == 16 && fmt->Format.nChannels == 2) { format_ = Format::PCM16; } @@ -406,7 +406,7 @@ bool WASAPIAudioThread::ValidateFormat(const WAVEFORMATEXTENSIBLE *fmt) { if (fmt->Format.nChannels >= 1) format_ = Format::IEEE_FLOAT; } else { - ERROR_LOG_REPORT_ONCE(unexpectedformat2, SCEAUDIO, "Got unexpected non-extensible WASAPI stream format, expected extensible float!"); + ERROR_LOG_REPORT_ONCE(unexpectedformat2, Log::sceAudio, "Got unexpected non-extensible WASAPI stream format, expected extensible float!"); if (fmt->Format.wBitsPerSample == 16 && fmt->Format.nChannels == 2) { format_ = Format::PCM16; } @@ -453,7 +453,7 @@ void WASAPIAudioThread::Run() { return; if (!ActivateDefaultDevice()) { - ERROR_LOG(SCEAUDIO, "WASAPI: Could not activate default device"); + ERROR_LOG(Log::sceAudio, "WASAPI: Could not activate default device"); return; } @@ -467,17 +467,17 @@ void WASAPIAudioThread::Run() { } if (!InitAudioDevice()) { - ERROR_LOG(SCEAUDIO, "WASAPI: Could not init audio device"); + ERROR_LOG(Log::sceAudio, "WASAPI: Could not init audio device"); return; } if (!PrepareFormat()) { - ERROR_LOG(SCEAUDIO, "WASAPI: Could not find a suitable audio output format"); + ERROR_LOG(Log::sceAudio, "WASAPI: Could not find a suitable audio output format"); return; } hresult = audioInterface_->Start(); if (FAILED(hresult)) { - ERROR_LOG(SCEAUDIO, "WASAPI: Failed to start audio stream"); + ERROR_LOG(Log::sceAudio, "WASAPI: Failed to start audio stream"); return; } @@ -542,23 +542,23 @@ void WASAPIAudioThread::Run() { ShutdownAudioDevice(); if (!ActivateDefaultDevice()) { - ERROR_LOG(SCEAUDIO, "WASAPI: Could not activate default device"); + ERROR_LOG(Log::sceAudio, "WASAPI: Could not activate default device"); // TODO: Return to the old device here? return; } notificationClient_->SetCurrentDevice(device_); if (!InitAudioDevice()) { - ERROR_LOG(SCEAUDIO, "WASAPI: Could not init audio device"); + ERROR_LOG(Log::sceAudio, "WASAPI: Could not init audio device"); return; } if (!PrepareFormat()) { - ERROR_LOG(SCEAUDIO, "WASAPI: Could not find a suitable audio output format"); + ERROR_LOG(Log::sceAudio, "WASAPI: Could not find a suitable audio output format"); return; } hresult = audioInterface_->Start(); if (FAILED(hresult)) { - ERROR_LOG(SCEAUDIO, "WASAPI: Failed to start audio stream"); + ERROR_LOG(Log::sceAudio, "WASAPI: Failed to start audio stream"); return; } } @@ -569,7 +569,7 @@ void WASAPIAudioThread::Run() { hresult = audioInterface_->Stop(); if (FAILED(hresult)) { - ERROR_LOG(SCEAUDIO, "WASAPI: Failed to stop audio stream"); + ERROR_LOG(Log::sceAudio, "WASAPI: Failed to stop audio stream"); } } diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 2e3e8809e7..7216a8a10f 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -82,7 +82,7 @@ void WindowsInputManager::PollControllers() { #ifndef _M_ARM size_t newCount = DinputDevice::getNumPads(); if (newCount > numDinputDevices_) { - INFO_LOG(SYSTEM, "New controller device detected"); + INFO_LOG(Log::System, "New controller device detected"); for (size_t i = numDinputDevices_; i < newCount; i++) { input.push_back(std::make_unique(static_cast(i))); } diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index 7ad79255ef..e6a19b4c42 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -144,7 +144,7 @@ static const struct { int from; InputKeyCode to; } xinput_ctrl_map[] = { XinputDevice::XinputDevice() { if (LoadXInputDLL() != 0) { - WARN_LOG(SCECTRL, "Failed to load XInput! DLL missing"); + WARN_LOG(Log::sceCtrl, "Failed to load XInput! DLL missing"); } for (size_t i = 0; i < ARRAY_SIZE(check_delay); ++i) { diff --git a/Windows/main.cpp b/Windows/main.cpp index 2e0eed488f..cfd7d987e9 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -55,8 +55,8 @@ #include "Windows/WindowsAudio.h" #include "ext/disarm.h" -#include "Common/LogManager.h" -#include "Common/ConsoleListener.h" +#include "Common/Log/LogManager.h" +#include "Common/Log/ConsoleListener.h" #include "Common/StringUtils.h" #include "Commctrl.h" @@ -106,6 +106,7 @@ CVFPUDlg *vfpudlg = nullptr; static std::string langRegion; static std::string osName; +static std::string osVersion; static std::string gpuDriverVersion; static std::string restartArgs; @@ -203,6 +204,8 @@ std::string System_GetProperty(SystemProperty prop) { switch (prop) { case SYSPROP_NAME: return osName; + case SYSPROP_SYSTEMBUILD: + return osVersion; case SYSPROP_LANGREGION: return langRegion; case SYSPROP_CLIPBOARD_TEXT: @@ -269,23 +272,23 @@ extern WindowsAudioBackend *winAudioBackend; #ifdef _WIN32 #if PPSSPP_PLATFORM(UWP) -static int ScreenDPI() { - return 96; // TODO UWP +static float ScreenDPI() { + return 96.0f; // TODO UWP } #else -static int ScreenDPI() { +static float ScreenDPI() { HDC screenDC = GetDC(nullptr); int dotsPerInch = GetDeviceCaps(screenDC, LOGPIXELSY); ReleaseDC(nullptr, screenDC); - return dotsPerInch ? dotsPerInch : 96; + return dotsPerInch ? (float)dotsPerInch : 96.0f; } #endif #endif -static int ScreenRefreshRateHz() { - static int rate = 0; +static float ScreenRefreshRateHz() { + static float rate = 0.0f; static double lastCheck = 0.0; - double now = time_now_d(); + const double now = time_now_d(); if (!rate || lastCheck < now - 10.0) { lastCheck = now; DEVMODE lpDevMode{}; @@ -295,20 +298,22 @@ static int ScreenRefreshRateHz() { // TODO: Use QueryDisplayConfig instead (Win7+) so we can get fractional refresh rates correctly. if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &lpDevMode) == 0) { - rate = 60; // default value + rate = 60.0f; // default value } else { if (lpDevMode.dmFields & DM_DISPLAYFREQUENCY) { - rate = lpDevMode.dmDisplayFrequency > 60 ? lpDevMode.dmDisplayFrequency : 60; + rate = (float)(lpDevMode.dmDisplayFrequency > 60 ? lpDevMode.dmDisplayFrequency : 60); } else { - rate = 60; + rate = 60.0f; } } } return rate; } -int System_GetPropertyInt(SystemProperty prop) { +int64_t System_GetPropertyInt(SystemProperty prop) { switch (prop) { + case SYSPROP_MAIN_WINDOW_HANDLE: + return (int64_t)MainWindow::GetHWND(); case SYSPROP_AUDIO_SAMPLE_RATE: return winAudioBackend ? winAudioBackend->GetSampleRate() : -1; case SYSPROP_DEVICE_TYPE: @@ -338,9 +343,9 @@ int System_GetPropertyInt(SystemProperty prop) { float System_GetPropertyFloat(SystemProperty prop) { switch (prop) { case SYSPROP_DISPLAY_REFRESH_RATE: - return (float)ScreenRefreshRateHz(); + return ScreenRefreshRateHz(); case SYSPROP_DISPLAY_DPI: - return (float)ScreenDPI(); + return ScreenDPI(); case SYSPROP_DISPLAY_SAFE_INSET_LEFT: case SYSPROP_DISPLAY_SAFE_INSET_RIGHT: case SYSPROP_DISPLAY_SAFE_INSET_TOP: @@ -353,6 +358,7 @@ float System_GetPropertyFloat(SystemProperty prop) { bool System_GetPropertyBool(SystemProperty prop) { switch (prop) { + case SYSPROP_HAS_TEXT_CLIPBOARD: case SYSPROP_HAS_DEBUGGER: case SYSPROP_HAS_FILE_BROWSER: case SYSPROP_HAS_FOLDER_BROWSER: @@ -478,7 +484,7 @@ void System_Notify(SystemNotification notification) { } } -std::wstring MakeFilter(std::wstring filter) { +static std::wstring MakeFilter(std::wstring filter) { for (size_t i = 0; i < filter.length(); i++) { if (filter[i] == '|') filter[i] = '\0'; @@ -486,7 +492,7 @@ std::wstring MakeFilter(std::wstring filter) { return filter; } -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { switch (type) { case SystemRequestType::EXIT_APP: if (!NativeIsRestarting()) { @@ -526,6 +532,11 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_WINDOW_TITLE_CHANGED, 0, 0); return true; } + case SystemRequestType::SET_KEEP_SCREEN_BRIGHT: + { + MainWindow::SetKeepScreenBright(param3 != 0); + return true; + } case SystemRequestType::INPUT_TEXT_MODAL: std::thread([=] { std::string out; @@ -576,7 +587,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string filter = MakeFilter(L"Cheat db files (*.db)|*.db|All files (*.*)|*.*||"); break; case BrowseFileType::SOUND_EFFECT: - filter = MakeFilter(L"WAVE files (*.wav)|*.wav|All files (*.*)|*.*||"); + filter = MakeFilter(L"Sound effect files (*.wav *.mp3)|*.wav;*.mp3|All files (*.*)|*.*||"); break; case BrowseFileType::ANY: filter = MakeFilter(L"All files (*.*)|*.*||"); @@ -633,7 +644,34 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string return true; } case SystemRequestType::CREATE_GAME_SHORTCUT: - return W32Util::CreateDesktopShortcut(param1, param2); + { + // Get the game info to get our hands on the icon png + Path gamePath(param1); + std::shared_ptr info = g_gameInfoCache->GetInfo(nullptr, gamePath, GameInfoFlags::ICON); + Path icoPath; + if (info->icon.dataLoaded) { + // Write the icon png out as a .ICO file so the shortcut can point to it + + // Savestate seems like a good enough place to put ico files. + Path iconFolder = GetSysDirectory(PSPDirectories::DIRECTORY_SAVESTATE); + + icoPath = iconFolder / (info->id + ".ico"); + if (!File::Exists(icoPath)) { + if (!W32Util::CreateICOFromPNGData((const uint8_t *)info->icon.data.data(), info->icon.data.size(), icoPath)) { + ERROR_LOG(Log::System, "ICO creation failed"); + icoPath.clear(); + } + } + } + return W32Util::CreateDesktopShortcut(param1, param2, icoPath); + } + case SystemRequestType::RUN_CALLBACK_IN_WNDPROC: + { + auto func = reinterpret_cast(param3); + void *userdata = reinterpret_cast(param4); + MainWindow::RunCallbackInWndProc(func, userdata); + return true; + } default: return false; } @@ -642,7 +680,8 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string void System_AskForPermission(SystemPermission permission) {} PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } -void EnableCrashingOnCrashes() { +// Don't swallow exceptions. +static void EnableCrashingOnCrashes() { typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); const DWORD EXCEPTION_SWALLOWING = 0x1; @@ -705,7 +744,7 @@ static bool DetectVulkanInExternalProcess() { if (W32Util::ExecuteAndGetReturnCode(moduleFilename.c_str(), cmdline, workingDirectory.c_str(), &exitCode)) { return exitCode == EXIT_CODE_VULKAN_WORKS; } else { - ERROR_LOG(G3D, "Failed to detect Vulkan in external process somehow"); + ERROR_LOG(Log::G3D, "Failed to detect Vulkan in external process somehow"); return false; } } @@ -773,7 +812,7 @@ static void InitMemstickDirectory() { if (!File::Exists(g_Config.memStickDirectory)) { if (!File::CreateDir(g_Config.memStickDirectory)) g_Config.memStickDirectory = myDocsPath; - INFO_LOG(COMMON, "Memstick directory not present, creating at '%s'", g_Config.memStickDirectory.c_str()); + INFO_LOG(Log::Common, "Memstick directory not present, creating at '%s'", g_Config.memStickDirectory.c_str()); } Path testFile = g_Config.memStickDirectory / "_writable_test.$$$"; @@ -852,6 +891,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin SetCurrentThreadName("Main"); + TimeInit(); + WinMainInit(); #ifndef _DEBUG @@ -867,13 +908,19 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin langRegion = GetDefaultLangRegion(); osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture(); + // OS Build + uint32_t outMajor = 0, outMinor = 0, outBuild = 0; + if (GetVersionFromKernel32(outMajor, outMinor, outBuild)) { + // Builds with (service pack) don't show OS Build for now + osVersion = std::to_string(outMajor) + "." + std::to_string(outMinor) + "." + std::to_string(outBuild); + } + std::string configFilename = ""; const std::wstring configOption = L"--config="; std::string controlsConfigFilename = ""; const std::wstring controlsOption = L"--controlconfig="; - for (size_t i = 1; i < wideArgs.size(); ++i) { if (wideArgs[i][0] == L'\0') continue; @@ -960,7 +1007,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin #ifndef _DEBUG // See #11719 - too many Vulkan drivers crash on basic init. - if (g_Config.IsBackendEnabled(GPUBackend::VULKAN, false)) { + if (g_Config.IsBackendEnabled(GPUBackend::VULKAN)) { VulkanSetAvailable(DetectVulkanInExternalProcess()); } #endif @@ -975,15 +1022,12 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin // - By default in Debug, the console should be shown by default. // - The -l switch is expected to show the log console, REGARDLESS of config settings. // - It should be possible to log to a file without showing the console. - LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console"); + LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120); if (debugLogLevel) { LogManager::GetInstance()->SetAllLogLevels(LogLevel::LDEBUG); } - // This still seems to improve performance noticeably. - timeBeginPeriod(1); - ContextMenuInit(_hInstance); MainWindow::Init(_hInstance); MainWindow::Show(_hInstance); diff --git a/Windows/main.h b/Windows/main.h index 44cdbd621a..610197d208 100644 --- a/Windows/main.h +++ b/Windows/main.h @@ -37,4 +37,4 @@ extern CGEDebugger* geDebuggerWindow; extern int g_activeWindow; -enum { WINDOW_MAINWINDOW, WINDOW_CPUDEBUGGER, WINDOW_GEDEBUGGER }; +enum { WINDOW_MAINWINDOW, WINDOW_CPUDEBUGGER, WINDOW_GEDEBUGGER, WINDOW_OTHER }; diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 7282a68d9d..c146f12261 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -591,7 +591,7 @@ BEGIN POPUP "Game Settings", ID_OPTIONS_MENU BEGIN MENUITEM "Keep PPSSPP On Top", ID_OPTIONS_TOPMOST - MENUITEM "Pause When Not Focused", ID_OPTIONS_PAUSE_FOCUS + MENUITEM "Pause when not focused", ID_OPTIONS_PAUSE_FOCUS MENUITEM "Ignore Windows Key", ID_OPTIONS_IGNOREWINKEY MENUITEM "Language...", ID_OPTIONS_LANGUAGE MENUITEM "Control Mapping...", ID_OPTIONS_CONTROLS @@ -664,7 +664,7 @@ BEGIN MENUITEM "Linear", ID_OPTIONS_LINEARFILTERING MENUITEM "Auto Max Quality", ID_OPTIONS_AUTOMAXQUALITYFILTERING MENUITEM "", 0, MFT_SEPARATOR - MENUITEM "Smart 2D Texture Filtering", ID_OPTIONS_SMART2DTEXTUREFILTERING + MENUITEM "Smart 2D texture filtering", ID_OPTIONS_SMART2DTEXTUREFILTERING END POPUP "Screen Scaling Filter", ID_OPTIONS_SCREENFILTER_MENU BEGIN diff --git a/Windows/resource.h b/Windows/resource.h index 9a4c943a54..d7fce4a416 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -61,7 +61,7 @@ #define IDD_GEDBG_TAB_MATRICES 255 #define IDD_GEDBG_STEPCOUNT 256 #define IDD_CPUWATCH 257 -#define IDD_EDITSYMBOLS 258 +#define IDD_EDITSYMBOLS 258 #define IDC_STOPGO 1001 #define IDC_ADDRESS 1002 @@ -123,12 +123,12 @@ #define IDC_SHOWOFFSETS 1200 #define IDC_GEDBG_PRIMCOUNTER 1201 #define IDC_BUTTON_SEARCH 1204 -#define IDC_EDITSYMBOLS_SCAN 1205 -#define IDC_EDITSYMBOLS_REMOVE 1206 -#define IDC_EDITSYMBOLS_ADDRESS 1207 -#define IDC_EDITSYMBOLS_SIZE 1208 -#define IDC_EDITSYMBOLS_OK 1209 -#define IDC_EDITSYMBOLS_CANCEL 1210 +#define IDC_EDITSYMBOLS_SCAN 1205 +#define IDC_EDITSYMBOLS_REMOVE 1206 +#define IDC_EDITSYMBOLS_ADDRESS 1207 +#define IDC_EDITSYMBOLS_SIZE 1208 +#define IDC_EDITSYMBOLS_OK 1209 +#define IDC_EDITSYMBOLS_CANCEL 1210 #define ID_FILE_EXIT 40000 #define ID_DEBUG_SAVEMAPFILE 40001 @@ -354,7 +354,7 @@ #define IDC_DISASM_FMT_INT 40233 #define IDC_DISASM_FMT_FLOAT 40234 #define IDC_DISASM_FMT_STR 40235 -#define ID_DISASM_EDITSYMBOLS 40236 +#define ID_DISASM_EDITSYMBOLS 40236 // Dummy option to let the buffered rendering hotkey cycle through all the options. diff --git a/android/VRManifest.xml b/android/VRManifest.xml index dc1a3aa1eb..737fedf2fc 100644 --- a/android/VRManifest.xml +++ b/android/VRManifest.xml @@ -4,6 +4,7 @@ + = 14000000) { // Start using automatic Android version numbers from version 1.4. @@ -63,7 +74,7 @@ android { new File("versioncode.txt").write(androidGitVersion.code().toString()) minSdk 9 - targetSdk 33 + targetSdk 35 if (project.hasProperty("ANDROID_VERSION_CODE") && project.hasProperty("ANDROID_VERSION_NAME")) { versionCode ANDROID_VERSION_CODE versionName ANDROID_VERSION_NAME @@ -112,6 +123,9 @@ android { vr { manifest.srcFile 'VRManifest.xml' } + legacy { + res.srcDirs = ['legacy/res'] + } } productFlavors { normal { @@ -150,6 +164,25 @@ android { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64' } } + legacy { + applicationId 'org.ppsspp.ppsspplegacy' + dimension "variant" + targetSdkVersion 29 // This is the point of legacy. + externalNativeBuild { + cmake { + // Available arguments listed at https://developer.android.com/ndk/guides/cmake.html + arguments '-DANDROID=true', + '-DANDROID_PLATFORM=android-16', + '-DANDROID_TOOLCHAIN=clang', + '-DANDROID_CPP_FEATURES=', + '-DANDROID_STL=c++_static', + '-DANDROID_LEGACY=TRUE' + } + } + ndk { + abiFilters 'armeabi-v7a', 'arm64-v8a' + } + } vr { applicationId 'org.ppsspp.ppssppvr' dimension "variant" @@ -163,7 +196,8 @@ android { '-DANDROID_CPP_FEATURES=', '-DANDROID_STL=c++_static', '-DANDROID_ARM_NEON=TRUE', - '-DOPENXR=TRUE' + '-DOPENXR=TRUE', + '-DANDROID_LEGACY=TRUE' } } ndk { @@ -171,15 +205,20 @@ android { } } } + // TODO: This is deprecated and needs a replacement. See https://stackoverflow.com/questions/67330818/android-gradle-plugin7-0-0-alpha15-removed-variantfilter-property-how-to-rest + // Though, not really that important. variantFilter { variant -> def needed = variant.name in [ - 'normalDebug', // for debugging - 'normalOptimized', // for testing - 'normalRelease', // for Google Play releases - 'goldRelease', // for Google Play releases - 'vrDebug', // for VR debugging - 'vrOptimized', // for VR testing - 'vrRelease', // for VR releases + 'normalDebug', // for debugging + 'normalOptimized', // for testing/user build + 'normalRelease', // for Google Play releases + 'goldRelease', // for Google Play releases + 'vrDebug', // for VR debugging + 'vrOptimized', // for VR testing + 'vrRelease', // for VR releases + 'legacyDebug', // for legacy debugging + 'legacyOptimized', // for legacy testing/user build + 'legacyRelease', // for buildbot releases ] variant.setIgnore(!needed) } diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 315e51f581..8e45dc5eb4 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -109,6 +109,20 @@ SPIRV_CROSS_FILES := \ NAETT_FILES := \ ${SRC}/ext/naett/naett.c +MINIMP3_FILES := \ + ${SRC}/ext/minimp3/minimp3.cpp + +AT3_STANDALONE_FILES := \ + ${SRC}/ext/at3_standalone/atrac.cpp \ + ${SRC}/ext/at3_standalone/atrac3.cpp \ + ${SRC}/ext/at3_standalone/atrac3plus.cpp \ + ${SRC}/ext/at3_standalone/atrac3plusdec.cpp \ + ${SRC}/ext/at3_standalone/atrac3plusdsp.cpp \ + ${SRC}/ext/at3_standalone/get_bits.cpp \ + ${SRC}/ext/at3_standalone/compat.cpp \ + ${SRC}/ext/at3_standalone/fft.cpp \ + ${SRC}/ext/at3_standalone/mem.cpp + RCHEEVOS_FILES := \ ${SRC}/ext/rcheevos/src/rapi/rc_api_common.c \ ${SRC}/ext/rcheevos/src/rapi/rc_api_editor.c \ @@ -217,6 +231,8 @@ EXEC_AND_LIB_FILES := \ $(SPIRV_CROSS_FILES) \ $(RCHEEVOS_FILES) \ $(NAETT_FILES) \ + $(MINIMP3_FILES) \ + $(AT3_STANDALONE_FILES) \ $(EXT_FILES) \ $(NATIVE_FILES) \ $(SRC)/Common/Buffer.cpp \ @@ -310,7 +326,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/ExceptionHandlerSetup.cpp \ $(SRC)/Common/FakeCPUDetect.cpp \ $(SRC)/Common/Log.cpp \ - $(SRC)/Common/LogManager.cpp \ + $(SRC)/Common/Log/LogManager.cpp \ $(SRC)/Common/LogReporting.cpp \ $(SRC)/Common/MemArenaAndroid.cpp \ $(SRC)/Common/MemArenaDarwin.cpp \ @@ -431,6 +447,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/MIPS/MIPSVFPUFallbacks.cpp.arm \ $(SRC)/Core/MIPS/MIPSCodeUtils.cpp.arm \ $(SRC)/Core/MIPS/MIPSDebugInterface.cpp \ + $(SRC)/Core/MIPS/MIPSTracer.cpp \ $(SRC)/Core/MIPS/IR/IRAnalysis.cpp \ $(SRC)/Core/MIPS/IR/IRFrontend.cpp \ $(SRC)/Core/MIPS/IR/IRJit.cpp \ @@ -465,6 +482,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/Common/ReinterpretFramebuffer.cpp \ $(SRC)/GPU/Common/DepthBufferCommon.cpp \ $(SRC)/GPU/Common/VertexDecoderCommon.cpp.arm \ + $(SRC)/GPU/Common/VertexDecoderHandwritten.cpp.arm \ $(SRC)/GPU/Common/TextureCacheCommon.cpp.arm \ $(SRC)/GPU/Common/TextureScalerCommon.cpp.arm \ $(SRC)/GPU/Common/ShaderCommon.cpp \ @@ -509,6 +527,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/ELF/PrxDecrypter.cpp \ $(SRC)/Core/ELF/ParamSFO.cpp \ $(SRC)/Core/HW/SimpleAudioDec.cpp \ + $(SRC)/Core/HW/Atrac3Standalone.cpp \ $(SRC)/Core/HW/AsyncIOManager.cpp \ $(SRC)/Core/HW/BufferQueue.cpp \ $(SRC)/Core/HW/Camera.cpp \ @@ -594,6 +613,8 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/HLE/Plugins.cpp \ $(SRC)/Core/HLE/sceAdler.cpp \ $(SRC)/Core/HLE/sceAtrac.cpp \ + $(SRC)/Core/HLE/AtracCtx.cpp \ + $(SRC)/Core/HLE/AtracCtx2.cpp \ $(SRC)/Core/HLE/__sceAudio.cpp.arm \ $(SRC)/Core/HLE/sceAudio.cpp.arm \ $(SRC)/Core/HLE/sceAudiocodec.cpp.arm \ @@ -835,6 +856,7 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/TouchControlVisibilityScreen.cpp \ $(SRC)/UI/CwCheatScreen.cpp \ $(SRC)/UI/InstallZipScreen.cpp \ + $(SRC)/UI/JitCompareScreen.cpp \ $(SRC)/UI/OnScreenDisplay.cpp \ $(SRC)/UI/ProfilerDraw.cpp \ $(SRC)/UI/NativeApp.cpp \ diff --git a/android/jni/AndroidAudio.cpp b/android/jni/AndroidAudio.cpp index e7d699068a..4d80779177 100644 --- a/android/jni/AndroidAudio.cpp +++ b/android/jni/AndroidAudio.cpp @@ -45,42 +45,42 @@ AndroidAudioState *AndroidAudio_Init(AndroidAudioCallback callback, int optimalF bool AndroidAudio_Recording_SetSampleRate(AndroidAudioState *state, int sampleRate) { if (!state) { - ERROR_LOG(AUDIO, "AndroidAudioState not initialized, cannot set recording sample rate"); + ERROR_LOG(Log::Audio, "AndroidAudioState not initialized, cannot set recording sample rate"); return false; } state->input_sample_rate = sampleRate; - INFO_LOG(AUDIO, "AndroidAudio_Recording_SetSampleRate=%d", sampleRate); + INFO_LOG(Log::Audio, "AndroidAudio_Recording_SetSampleRate=%d", sampleRate); return true; } bool AndroidAudio_Recording_Start(AndroidAudioState *state) { if (!state) { - ERROR_LOG(AUDIO, "AndroidAudioState not initialized, cannot start recording!"); + ERROR_LOG(Log::Audio, "AndroidAudioState not initialized, cannot start recording!"); return false; } state->input_enable = 1; if (!state->ctx) { - ERROR_LOG(AUDIO, "OpenSLContext not initialized, cannot start recording!"); + ERROR_LOG(Log::Audio, "OpenSLContext not initialized, cannot start recording!"); return false; } state->ctx->AudioRecord_Start(state->input_sample_rate); - INFO_LOG(AUDIO, "AndroidAudio_Recording_Start"); + INFO_LOG(Log::Audio, "AndroidAudio_Recording_Start"); return true; } bool AndroidAudio_Recording_Stop(AndroidAudioState *state) { if (!state) { - ERROR_LOG(AUDIO, "AndroidAudioState not initialized, cannot stop recording!"); + ERROR_LOG(Log::Audio, "AndroidAudioState not initialized, cannot stop recording!"); return false; } if (!state->ctx) { - ERROR_LOG(AUDIO, "OpenSLContext not initialized, cannot stop recording!"); + ERROR_LOG(Log::Audio, "OpenSLContext not initialized, cannot stop recording!"); return false; } state->input_enable = 0; state->input_sample_rate = 0; state->ctx->AudioRecord_Stop(); - INFO_LOG(AUDIO, "AndroidAudio_Recording_Stop"); + INFO_LOG(Log::Audio, "AndroidAudio_Recording_Stop"); return true; } @@ -93,13 +93,13 @@ bool AndroidAudio_Recording_State(AndroidAudioState *state) { bool AndroidAudio_Resume(AndroidAudioState *state) { if (!state) { - ERROR_LOG(AUDIO, "Audio was shutdown, cannot resume!"); + ERROR_LOG(Log::Audio, "Audio was shutdown, cannot resume!"); return false; } if (!state->ctx) { - INFO_LOG(AUDIO, "Calling OpenSLWrap_Init_T..."); + INFO_LOG(Log::Audio, "Calling OpenSLWrap_Init_T..."); state->ctx = new OpenSLContext(state->callback, state->frames_per_buffer, state->sample_rate); - INFO_LOG(AUDIO, "Returned from OpenSLWrap_Init_T"); + INFO_LOG(Log::Audio, "Returned from OpenSLWrap_Init_T"); bool init_retval = state->ctx->Init(); if (!init_retval) { delete state->ctx; @@ -115,14 +115,14 @@ bool AndroidAudio_Resume(AndroidAudioState *state) { bool AndroidAudio_Pause(AndroidAudioState *state) { if (!state) { - ERROR_LOG(AUDIO, "Audio was shutdown, cannot pause!"); + ERROR_LOG(Log::Audio, "Audio was shutdown, cannot pause!"); return false; } if (state->ctx) { - INFO_LOG(AUDIO, "Calling OpenSLWrap_Shutdown_T..."); + INFO_LOG(Log::Audio, "Calling OpenSLWrap_Shutdown_T..."); delete state->ctx; state->ctx = nullptr; - INFO_LOG(AUDIO, "Returned from OpenSLWrap_Shutdown_T ..."); + INFO_LOG(Log::Audio, "Returned from OpenSLWrap_Shutdown_T ..."); return true; } return false; @@ -130,15 +130,15 @@ bool AndroidAudio_Pause(AndroidAudioState *state) { bool AndroidAudio_Shutdown(AndroidAudioState *state) { if (!state) { - ERROR_LOG(AUDIO, "Audio already shutdown!"); + ERROR_LOG(Log::Audio, "Audio already shutdown!"); return false; } if (state->ctx) { - ERROR_LOG(AUDIO, "Should not shut down when playing! Something is wrong!"); + ERROR_LOG(Log::Audio, "Should not shut down when playing! Something is wrong!"); return false; } delete state; - INFO_LOG(AUDIO, "OpenSLWrap completely unloaded."); + INFO_LOG(Log::Audio, "OpenSLWrap completely unloaded."); return true; } diff --git a/android/jni/AndroidJavaGLContext.cpp b/android/jni/AndroidJavaGLContext.cpp index 84010df9c4..12e4862592 100644 --- a/android/jni/AndroidJavaGLContext.cpp +++ b/android/jni/AndroidJavaGLContext.cpp @@ -11,9 +11,9 @@ AndroidJavaEGLGraphicsContext::AndroidJavaEGLGraphicsContext() { } bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { - INFO_LOG(G3D, "AndroidJavaEGLGraphicsContext::InitFromRenderThread"); + INFO_LOG(Log::G3D, "AndroidJavaEGLGraphicsContext::InitFromRenderThread"); if (!CheckGLExtensions()) { - ERROR_LOG(G3D, "CheckGLExtensions failed - not gonna attempt starting up."); + ERROR_LOG(Log::G3D, "CheckGLExtensions failed - not gonna attempt starting up."); state_ = GraphicsContextState::FAILED_INIT; return false; } @@ -37,7 +37,7 @@ bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int } void AndroidJavaEGLGraphicsContext::ShutdownFromRenderThread() { - INFO_LOG(G3D, "AndroidJavaEGLGraphicsContext::Shutdown"); + INFO_LOG(Log::G3D, "AndroidJavaEGLGraphicsContext::Shutdown"); renderManager_ = nullptr; // owned by draw_. delete draw_; draw_ = nullptr; diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index a700ab3141..e021194f55 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -42,19 +42,19 @@ AndroidVulkanContext::~AndroidVulkanContext() { } bool AndroidVulkanContext::InitAPI() { - INFO_LOG(G3D, "AndroidVulkanContext::Init"); + INFO_LOG(Log::G3D, "AndroidVulkanContext::Init"); init_glslang(); g_LogOptions.breakOnError = true; g_LogOptions.breakOnWarning = true; g_LogOptions.msgBoxOnError = false; - INFO_LOG(G3D, "Creating Vulkan context"); + INFO_LOG(Log::G3D, "Creating Vulkan context"); Version gitVer(PPSSPP_GIT_VERSION); std::string errorStr; if (!VulkanLoad(&errorStr)) { - ERROR_LOG(G3D, "Failed to load Vulkan driver library: %s", errorStr.c_str()); + ERROR_LOG(Log::G3D, "Failed to load Vulkan driver library: %s", errorStr.c_str()); state_ = GraphicsContextState::FAILED_INIT; return false; } @@ -68,54 +68,28 @@ bool AndroidVulkanContext::InitAPI() { info.app_name = "PPSSPP"; info.app_ver = gitVer.ToInteger(); info.flags = FlagsFromConfig(); - VkResult res = g_Vulkan->CreateInstance(info); - if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "Failed to create vulkan context: %s", g_Vulkan->InitError().c_str()); - VulkanSetAvailable(false); + if (!g_Vulkan->CreateInstanceAndDevice(info)) { delete g_Vulkan; g_Vulkan = nullptr; state_ = GraphicsContextState::FAILED_INIT; return false; } - int physicalDevice = g_Vulkan->GetBestPhysicalDevice(); - if (physicalDevice < 0) { - ERROR_LOG(G3D, "No usable Vulkan device found."); - g_Vulkan->DestroyInstance(); - delete g_Vulkan; - g_Vulkan = nullptr; - state_ = GraphicsContextState::FAILED_INIT; - return false; - } - - g_Vulkan->ChooseDevice(physicalDevice); - - INFO_LOG(G3D, "Creating Vulkan device (flags: %08x)", info.flags); - if (g_Vulkan->CreateDevice() != VK_SUCCESS) { - INFO_LOG(G3D, "Failed to create vulkan device: %s", g_Vulkan->InitError().c_str()); - System_Toast("No Vulkan driver found. Using OpenGL instead."); - g_Vulkan->DestroyInstance(); - delete g_Vulkan; - g_Vulkan = nullptr; - state_ = GraphicsContextState::FAILED_INIT; - return false; - } - - INFO_LOG(G3D, "Vulkan device created!"); + INFO_LOG(Log::G3D, "Vulkan device created!"); state_ = GraphicsContextState::INITIALIZED; return true; } bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { - INFO_LOG(G3D, "AndroidVulkanContext::InitFromRenderThread: desiredwidth=%d desiredheight=%d", desiredBackbufferSizeX, desiredBackbufferSizeY); + INFO_LOG(Log::G3D, "AndroidVulkanContext::InitFromRenderThread: desiredwidth=%d desiredheight=%d", desiredBackbufferSizeX, desiredBackbufferSizeY); if (!g_Vulkan) { - ERROR_LOG(G3D, "AndroidVulkanContext::InitFromRenderThread: No Vulkan context"); + ERROR_LOG(Log::G3D, "AndroidVulkanContext::InitFromRenderThread: No Vulkan context"); return false; } VkResult res = g_Vulkan->InitSurface(WINDOWSYSTEM_ANDROID, (void *)wnd, nullptr); if (res != VK_SUCCESS) { - ERROR_LOG(G3D, "g_Vulkan->InitSurface failed: '%s'", VulkanResultToString(res)); + ERROR_LOG(Log::G3D, "g_Vulkan->InitSurface failed: '%s'", VulkanResultToString(res)); return false; } @@ -138,7 +112,7 @@ bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredB success = false; } - INFO_LOG(G3D, "AndroidVulkanContext::Init completed, %s", success ? "successfully" : "but failed"); + INFO_LOG(Log::G3D, "AndroidVulkanContext::Init completed, %s", success ? "successfully" : "but failed"); if (!success) { g_Vulkan->DestroySwapchain(); g_Vulkan->DestroySurface(); @@ -149,7 +123,7 @@ bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredB } void AndroidVulkanContext::ShutdownFromRenderThread() { - INFO_LOG(G3D, "AndroidVulkanContext::Shutdown"); + INFO_LOG(Log::G3D, "AndroidVulkanContext::Shutdown"); draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); delete draw_; draw_ = nullptr; @@ -157,20 +131,20 @@ void AndroidVulkanContext::ShutdownFromRenderThread() { g_Vulkan->PerformPendingDeletes(); g_Vulkan->DestroySwapchain(); g_Vulkan->DestroySurface(); - INFO_LOG(G3D, "Done with ShutdownFromRenderThread"); + INFO_LOG(Log::G3D, "Done with ShutdownFromRenderThread"); } void AndroidVulkanContext::Shutdown() { - INFO_LOG(G3D, "Calling NativeShutdownGraphics"); + INFO_LOG(Log::G3D, "Calling NativeShutdownGraphics"); g_Vulkan->DestroyDevice(); g_Vulkan->DestroyInstance(); // We keep the g_Vulkan context around to avoid invalidating a ton of pointers around the app. finalize_glslang(); - INFO_LOG(G3D, "AndroidVulkanContext::Shutdown completed"); + INFO_LOG(Log::G3D, "AndroidVulkanContext::Shutdown completed"); } void AndroidVulkanContext::Resize() { - INFO_LOG(G3D, "AndroidVulkanContext::Resize begin (oldsize: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + INFO_LOG(Log::G3D, "AndroidVulkanContext::Resize begin (oldsize: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); g_Vulkan->DestroySwapchain(); @@ -181,5 +155,5 @@ void AndroidVulkanContext::Resize() { g_Vulkan->ReinitSurface(); g_Vulkan->InitSwapchain(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - INFO_LOG(G3D, "AndroidVulkanContext::Resize end (final size: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + INFO_LOG(Log::G3D, "AndroidVulkanContext::Resize end (final size: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); } diff --git a/android/jni/Arm64EmitterTest.cpp b/android/jni/Arm64EmitterTest.cpp index 3a04f6fb18..e49658cfda 100644 --- a/android/jni/Arm64EmitterTest.cpp +++ b/android/jni/Arm64EmitterTest.cpp @@ -66,11 +66,11 @@ void Arm64EmitterTest() { return; for (int i = 0; i < 6; i++) { - INFO_LOG(SYSTEM, "---------------------------"); + INFO_LOG(Log::System, "---------------------------"); } - INFO_LOG(SYSTEM, "---------------------------"); - INFO_LOG(SYSTEM, "Running ARM64 emitter test!"); - INFO_LOG(SYSTEM, "---------------------------"); + INFO_LOG(Log::System, "---------------------------"); + INFO_LOG(Log::System, "Running ARM64 emitter test!"); + INFO_LOG(Log::System, "---------------------------"); TestCode gen; gen.ReserveCodeSpace(0x1000); @@ -78,15 +78,15 @@ void Arm64EmitterTest() { gen.Generate(); u32 retval = CallPtr(gen.testCodePtr); - INFO_LOG(SYSTEM, "Returned %d", retval); - // INFO_LOG(SYSTEM, "ARM emitter test 1 passed if %f == 3.0! retval = %08x", abc[32 + 31], retval); + INFO_LOG(Log::System, "Returned %d", retval); + // INFO_LOG(Log::System, "ARM emitter test 1 passed if %f == 3.0! retval = %08x", abc[32 + 31], retval); /* - INFO_LOG(SYSTEM, "x: %08x %08x %08x %08x", x[0], x[1], x[2], x[3]); - INFO_LOG(SYSTEM, "y: %08x %08x %08x %08x", y[0], y[1], y[2], y[3]); - INFO_LOG(SYSTEM, "z: %08x %08x %08x %08x", z[0], z[1], z[2], z[3]); - INFO_LOG(SYSTEM, "c: %f %f %f %f", c[0], c[1], c[2], c[3]);*/ + INFO_LOG(Log::System, "x: %08x %08x %08x %08x", x[0], x[1], x[2], x[3]); + INFO_LOG(Log::System, "y: %08x %08x %08x %08x", y[0], y[1], y[2], y[3]); + INFO_LOG(Log::System, "z: %08x %08x %08x %08x", z[0], z[1], z[2], z[3]); + INFO_LOG(Log::System, "c: %f %f %f %f", c[0], c[1], c[2], c[3]);*/ for (int i = 0; i < 6; i++) { - INFO_LOG(SYSTEM, "--------------------------"); + INFO_LOG(Log::System, "--------------------------"); } // DisassembleArm(codeStart, gen.GetCodePtr()-codeStart); } diff --git a/android/jni/ArmEmitterTest.cpp b/android/jni/ArmEmitterTest.cpp index 5af9643f07..fe9d06b725 100644 --- a/android/jni/ArmEmitterTest.cpp +++ b/android/jni/ArmEmitterTest.cpp @@ -69,7 +69,7 @@ void TestCode::Generate() VST1(I_32, D6, R3, 2); PLD(R1, 32); u32 word = *(u32 *)(GetCodePtr() - 4); - INFO_LOG(SYSTEM, "Instruction Word: %08x", word); + INFO_LOG(Log::System, "Instruction Word: %08x", word); // This works! @@ -121,11 +121,11 @@ void ArmEmitterTest() return; for (int i = 0; i < 6; i++) { - INFO_LOG(SYSTEM, "--------------------------"); + INFO_LOG(Log::System, "--------------------------"); } - INFO_LOG(SYSTEM, "--------------------------"); - INFO_LOG(SYSTEM, "Running ARM emitter test!"); - INFO_LOG(SYSTEM, "--------------------------"); + INFO_LOG(Log::System, "--------------------------"); + INFO_LOG(Log::System, "Running ARM emitter test!"); + INFO_LOG(Log::System, "--------------------------"); TestCode gen; gen.ReserveCodeSpace(0x1000); @@ -133,13 +133,13 @@ void ArmEmitterTest() gen.Generate(); u32 retval = CallPtr(gen.testCodePtr); - // INFO_LOG(SYSTEM, "ARM emitter test 1 passed if %f == 3.0! retval = %08x", abc[32 + 31], retval); - INFO_LOG(SYSTEM, "x: %08x %08x %08x %08x", x[0], x[1], x[2], x[3]); - INFO_LOG(SYSTEM, "y: %08x %08x %08x %08x", y[0], y[1], y[2], y[3]); - INFO_LOG(SYSTEM, "z: %08x %08x %08x %08x", z[0], z[1], z[2], z[3]); - INFO_LOG(SYSTEM, "c: %f %f %f %f", c[0], c[1], c[2], c[3]); + // INFO_LOG(Log::System, "ARM emitter test 1 passed if %f == 3.0! retval = %08x", abc[32 + 31], retval); + INFO_LOG(Log::System, "x: %08x %08x %08x %08x", x[0], x[1], x[2], x[3]); + INFO_LOG(Log::System, "y: %08x %08x %08x %08x", y[0], y[1], y[2], y[3]); + INFO_LOG(Log::System, "z: %08x %08x %08x %08x", z[0], z[1], z[2], z[3]); + INFO_LOG(Log::System, "c: %f %f %f %f", c[0], c[1], c[2], c[3]); for (int i = 0; i < 6; i++) { - INFO_LOG(SYSTEM, "--------------------------"); + INFO_LOG(Log::System, "--------------------------"); } // DisassembleArm(codeStart, gen.GetCodePtr()-codeStart); } diff --git a/android/jni/OpenSLContext.cpp b/android/jni/OpenSLContext.cpp index c5ebffbe6a..32d951b854 100644 --- a/android/jni/OpenSLContext.cpp +++ b/android/jni/OpenSLContext.cpp @@ -45,7 +45,7 @@ void OpenSLContext::bqPlayerCallbackWrap(SLAndroidSimpleBufferQueueItf bq, void void OpenSLContext::BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq) { if (bq != bqPlayerBufferQueue) { - ERROR_LOG(AUDIO, "OpenSL: Wrong bq!"); + ERROR_LOG(Log::Audio, "OpenSL: Wrong bq!"); return; } @@ -64,7 +64,7 @@ void OpenSLContext::BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq) { // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, // which for this code example would indicate a programming error if (result != SL_RESULT_SUCCESS) { - ERROR_LOG(AUDIO, "OpenSL: Failed to enqueue! %i %i", renderedFrames, sizeInBytes); + ERROR_LOG(Log::Audio, "OpenSL: Failed to enqueue! %i %i", renderedFrames, sizeInBytes); } curBuffer += 1; // Switch buffer @@ -131,7 +131,7 @@ bool OpenSLContext::Init() { result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, sizeof(ids)/sizeof(ids[0]), ids, req); if (result != SL_RESULT_SUCCESS) { - ERROR_LOG(AUDIO, "OpenSL: CreateAudioPlayer failed: %d", (int)result); + ERROR_LOG(Log::Audio, "OpenSL: CreateAudioPlayer failed: %d", (int)result); (*outputMixObject)->Destroy(outputMixObject); outputMixObject = nullptr; @@ -269,13 +269,13 @@ bool OpenSLContext::AudioRecord_Stop() { // shut down the native audio system OpenSLContext::~OpenSLContext() { if (bqPlayerPlay) { - INFO_LOG(AUDIO, "OpenSL: Shutdown - stopping playback"); + INFO_LOG(Log::Audio, "OpenSL: Shutdown - stopping playback"); SLresult result; result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED); CheckResult(result, "SetPlayState(stopped) failed"); } - INFO_LOG(AUDIO, "OpenSL: Shutdown - deleting player object"); + INFO_LOG(Log::Audio, "OpenSL: Shutdown - deleting player object"); if (bqPlayerObject) { (*bqPlayerObject)->Destroy(bqPlayerObject); @@ -285,7 +285,7 @@ OpenSLContext::~OpenSLContext() { bqPlayerVolume = nullptr; } - INFO_LOG(AUDIO, "OpenSL: Shutdown - deleting mix object"); + INFO_LOG(Log::Audio, "OpenSL: Shutdown - deleting mix object"); if (outputMixObject) { (*outputMixObject)->Destroy(outputMixObject); @@ -293,7 +293,7 @@ OpenSLContext::~OpenSLContext() { } AudioRecord_Stop(); - INFO_LOG(AUDIO, "OpenSL: Shutdown - deleting engine object"); + INFO_LOG(Log::Audio, "OpenSL: Shutdown - deleting engine object"); if (engineObject) { (*engineObject)->Destroy(engineObject); @@ -305,12 +305,12 @@ OpenSLContext::~OpenSLContext() { delete[] buffer[i]; buffer[i] = nullptr; } - INFO_LOG(AUDIO, "OpenSL: Shutdown - finished"); + INFO_LOG(Log::Audio, "OpenSL: Shutdown - finished"); } bool OpenSLContext::CheckResult(SLresult result, const char *str) { if (result != SL_RESULT_SUCCESS) { - ERROR_LOG(AUDIO, "OpenSL failure (%s): %d", str, result); + ERROR_LOG(Log::Audio, "OpenSL failure (%s): %d", str, result); SetErrorString(str); return false; } else { @@ -320,7 +320,7 @@ bool OpenSLContext::CheckResult(SLresult result, const char *str) { bool OpenSLContext::CheckResultStatic(SLresult result, const char *str) { if (result != SL_RESULT_SUCCESS) { - ERROR_LOG(AUDIO, "OpenSL failure (%s): %d", str, result); + ERROR_LOG(Log::Audio, "OpenSL failure (%s): %d", str, result); return false; } else { return true; diff --git a/android/jni/TestRunner.cpp b/android/jni/TestRunner.cpp index 691cf2e3cd..2be5918de2 100644 --- a/android/jni/TestRunner.cpp +++ b/android/jni/TestRunner.cpp @@ -66,6 +66,8 @@ bool TestsAvailable() { // Hack to easily run the tests on Windows from the submodule if (File::IsDirectory(Path("../pspautotests"))) { testDirectory = Path(".."); + } else if (File::IsDirectory(Path("pspautotests"))) { + testDirectory = Path("."); } return File::Exists(testDirectory / "pspautotests" / "tests"); } @@ -80,6 +82,8 @@ bool RunTests() { // Hack to easily run the tests on Windows from the submodule if (File::IsDirectory(Path("../pspautotests"))) { baseDirectory = Path(".."); + } else if (File::IsDirectory(Path("pspautotests"))) { + baseDirectory = Path("."); } #endif @@ -113,11 +117,11 @@ bool RunTests() { coreParam.fileToStart = baseDirectory / "pspautotests" / "tests" / (testName + ".prx"); Path expectedFile = baseDirectory / "pspautotests" / "tests" / (testName + ".expected"); - INFO_LOG(SYSTEM, "Preparing to execute '%s'", testName.c_str()); + INFO_LOG(Log::System, "Preparing to execute '%s'", testName.c_str()); std::string error_string; output.clear(); if (!PSP_Init(coreParam, &error_string)) { - ERROR_LOG(SYSTEM, "Failed to init unittest %s : %s", testsToRun[i], error_string.c_str()); + ERROR_LOG(Log::System, "Failed to init unittest %s : %s", testsToRun[i], error_string.c_str()); PSP_CoreParameter().pixelWidth = g_display.pixel_xres; PSP_CoreParameter().pixelHeight = g_display.pixel_yres; return false; @@ -126,7 +130,7 @@ bool RunTests() { PSP_BeginHostFrame(); // Run the emu until the test exits - INFO_LOG(SYSTEM, "Test: Entering runloop."); + INFO_LOG(Log::System, "Test: Entering runloop."); while (true) { int blockTicks = (int)usToCycles(1000000 / 10); while (coreState == CORE_RUNNING) { @@ -137,7 +141,7 @@ bool RunTests() { // set back to running for the next frame coreState = CORE_RUNNING; } else if (coreState == CORE_POWERDOWN) { - INFO_LOG(SYSTEM, "Finished running test %s", testName.c_str()); + INFO_LOG(Log::System, "Finished running test %s", testName.c_str()); break; } } @@ -145,7 +149,7 @@ bool RunTests() { std::string expect_results; if (!File::ReadTextFileToString(expectedFile, &expect_results)) { - ERROR_LOG(SYSTEM, "Error opening expectedFile %s", expectedFile.c_str()); + ERROR_LOG(Log::System, "Error opening expectedFile %s", expectedFile.c_str()); break; } @@ -162,9 +166,9 @@ bool RunTests() { e = TrimNewlines(e); o = TrimNewlines(o); if (e != o) { - ERROR_LOG(SYSTEM, "DIFF on line %i!", line); - ERROR_LOG(SYSTEM, "O: %s", o.c_str()); - ERROR_LOG(SYSTEM, "E: %s", e.c_str()); + ERROR_LOG(Log::System, "DIFF on line %i!", line); + ERROR_LOG(Log::System, "O: %s", o.c_str()); + ERROR_LOG(Log::System, "E: %s", e.c_str()); } if (expected.eof()) { break; diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 6dcb3d79a5..1011e599c5 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -112,6 +112,7 @@ enum class EmuThreadState { STOPPED, }; +// OpenGL emu thread static std::thread emuThread; static std::atomic emuThreadState((int)EmuThreadState::DISABLED); @@ -255,7 +256,7 @@ void Android_AttachThreadToJNI() { JNIEnv *env; int status = gJvm->GetEnv((void **)&env, JNI_VERSION_1_6); if (status < 0) { - DEBUG_LOG(SYSTEM, "Attaching thread '%s' (not already attached) to JNI.", GetCurrentThreadName()); + DEBUG_LOG(Log::System, "Attaching thread '%s' (not already attached) to JNI.", GetCurrentThreadName()); JavaVMAttachArgs args{}; args.version = JNI_VERSION_1_6; args.name = GetCurrentThreadName(); @@ -263,23 +264,23 @@ void Android_AttachThreadToJNI() { if (status < 0) { // bad, but what can we do other than report.. - ERROR_LOG_REPORT_ONCE(threadAttachFail, SYSTEM, "Failed to attach thread %s to JNI.", GetCurrentThreadName()); + ERROR_LOG_REPORT_ONCE(threadAttachFail, Log::System, "Failed to attach thread %s to JNI.", GetCurrentThreadName()); } } else { - WARN_LOG(SYSTEM, "Thread %s was already attached to JNI.", GetCurrentThreadName()); + WARN_LOG(Log::System, "Thread %s was already attached to JNI.", GetCurrentThreadName()); } } void Android_DetachThreadFromJNI() { if (gJvm->DetachCurrentThread() == JNI_OK) { - DEBUG_LOG(SYSTEM, "Detached thread from JNI: '%s'", GetCurrentThreadName()); + DEBUG_LOG(Log::System, "Detached thread from JNI: '%s'", GetCurrentThreadName()); } else { - WARN_LOG(SYSTEM, "Failed to detach thread '%s' from JNI - never attached?", GetCurrentThreadName()); + WARN_LOG(Log::System, "Failed to detach thread '%s' from JNI - never attached?", GetCurrentThreadName()); } } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) { - INFO_LOG(SYSTEM, "JNI_OnLoad"); + INFO_LOG(Log::System, "JNI_OnLoad"); gJvm = pjvm; // cache the JavaVM pointer auto env = getEnv(); //replace with one of your classes in the line below @@ -293,6 +294,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) { "(Ljava/lang/String;)Ljava/lang/Class;"); RegisterAttachDetach(&Android_AttachThreadToJNI, &Android_DetachThreadFromJNI); + + TimeInit(); return JNI_VERSION_1_6; } @@ -308,17 +311,17 @@ static void EmuThreadFunc() { args.name = "EmuThread"; gJvm->AttachCurrentThread(&env, &args); - INFO_LOG(SYSTEM, "Entering emu thread"); + INFO_LOG(Log::System, "Entering emu thread"); // Wait for render loop to get started. - INFO_LOG(SYSTEM, "Runloop: Waiting for displayInit..."); + INFO_LOG(Log::System, "Runloop: Waiting for displayInit..."); while (!graphicsContext || graphicsContext->GetState() == GraphicsContextState::PENDING) { sleep_ms(5); } // Check the state of the graphics context before we try to feed it into NativeInitGraphics. if (graphicsContext->GetState() != GraphicsContextState::INITIALIZED) { - ERROR_LOG(G3D, "Failed to initialize the graphics context! %d", (int)graphicsContext->GetState()); + ERROR_LOG(Log::G3D, "Failed to initialize the graphics context! %d", (int)graphicsContext->GetState()); emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; gJvm->DetachCurrentThread(); return; @@ -331,7 +334,7 @@ static void EmuThreadFunc() { return; } - INFO_LOG(SYSTEM, "Graphics initialized. Entering loop."); + INFO_LOG(Log::System, "Graphics initialized. Entering loop."); // There's no real requirement that NativeInit happen on this thread. // We just call the update/render loop here. @@ -344,7 +347,7 @@ static void EmuThreadFunc() { std::lock_guard guard(frameCommandLock); if (!nativeActivity) { - ERROR_LOG(SYSTEM, "No activity, clearing commands"); + ERROR_LOG(Log::System, "No activity, clearing commands"); while (!frameCommands.empty()) frameCommands.pop(); return; @@ -353,7 +356,7 @@ static void EmuThreadFunc() { ProcessFrameCommands(env); } - INFO_LOG(SYSTEM, "QUIT_REQUESTED found, left EmuThreadFunc loop. Setting state to STOPPED."); + INFO_LOG(Log::System, "QUIT_REQUESTED found, left EmuThreadFunc loop. Setting state to STOPPED."); emuThreadState = (int)EmuThreadState::STOPPED; NativeShutdownGraphics(); @@ -362,11 +365,11 @@ static void EmuThreadFunc() { graphicsContext->StopThread(); gJvm->DetachCurrentThread(); - INFO_LOG(SYSTEM, "Leaving emu thread"); + INFO_LOG(Log::System, "Leaving emu thread"); } static void EmuThreadStart() { - INFO_LOG(SYSTEM, "EmuThreadStart"); + INFO_LOG(Log::System, "EmuThreadStart"); emuThreadState = (int)EmuThreadState::START_REQUESTED; emuThread = std::thread(&EmuThreadFunc); } @@ -375,14 +378,14 @@ static void EmuThreadStart() { // as long as emuThreadState isn't STOPPED and/or there are still things queued up. // Only after that, call EmuThreadJoin. static void EmuThreadStop(const char *caller) { - INFO_LOG(SYSTEM, "EmuThreadStop - stopping (%s)...", caller); + INFO_LOG(Log::System, "EmuThreadStop - stopping (%s)...", caller); emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; } static void EmuThreadJoin() { emuThread.join(); emuThread = std::thread(); - INFO_LOG(SYSTEM, "EmuThreadJoin - joined"); + INFO_LOG(Log::System, "EmuThreadJoin - joined"); } static void PushCommand(std::string cmd, std::string param) { @@ -441,7 +444,7 @@ std::vector System_GetPropertyStringVec(SystemProperty prop) { } } -int System_GetPropertyInt(SystemProperty prop) { +int64_t System_GetPropertyInt(SystemProperty prop) { switch (prop) { case SYSPROP_SYSTEMVERSION: return androidVersion; @@ -496,6 +499,8 @@ bool System_GetPropertyBool(SystemProperty prop) { case SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE: return sustainedPerfSupported; // 7.0 introduced sustained performance mode as an optional feature. case SYSPROP_HAS_TEXT_INPUT_DIALOG: + return androidVersion >= 11; // honeycomb + case SYSPROP_HAS_TEXT_CLIPBOARD: return true; case SYSPROP_HAS_OPEN_DIRECTORY: return false; // We have this implemented but it may or may not work depending on if a file explorer is installed. @@ -547,6 +552,8 @@ bool System_GetPropertyBool(SystemProperty prop) { return deviceType != DEVICE_TYPE_VR; case SYSPROP_HAS_ACCELEROMETER: return deviceType == DEVICE_TYPE_MOBILE; + case SYSPROP_CAN_CREATE_SHORTCUT: + return false; // We can't create shortcuts directly from game code, but we can from the Android UI. #ifndef HTTPS_NOT_AVAILABLE case SYSPROP_SUPPORTS_HTTPS: return !g_Config.bDisableHTTPS; @@ -628,7 +635,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_audioConfig static std::string QueryConfig(std::string query) { char temp[128]; if (query == "screenRotation") { - INFO_LOG(G3D, "g_Config.screenRotation = %d", g_Config.iScreenRotation); + INFO_LOG(Log::G3D, "g_Config.screenRotation = %d", g_Config.iScreenRotation); snprintf(temp, sizeof(temp), "%d", g_Config.iScreenRotation); return std::string(temp); } else if (query == "immersiveMode") { @@ -789,6 +796,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init std::vector temp; args.push_back(app_name.c_str()); if (!shortcut_param.empty()) { + EARLY_LOG("NativeInit shortcut param %s", shortcut_param.c_str()); parse_args(temp, shortcut_param); for (const auto &arg : temp) { args.push_back(arg.c_str()); @@ -797,7 +805,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init NativeInit((int)args.size(), &args[0], user_data_path.c_str(), externalStorageDir.c_str(), cacheDir.c_str()); - // In debug mode, don't allow creating software Vulkan devices (reject by VulkaMaybeAvailable). + // In debug mode, don't allow creating software Vulkan devices (reject by VulkanMaybeAvailable). // Needed for #16931. #ifdef NDEBUG if (!VulkanMayBeAvailable()) { @@ -812,20 +820,20 @@ retry: switch (g_Config.iGPUBackend) { case (int)GPUBackend::OPENGL: useCPUThread = true; - INFO_LOG(SYSTEM, "NativeApp.init() -- creating OpenGL context (JavaGL)"); + INFO_LOG(Log::System, "NativeApp.init() -- creating OpenGL context (JavaGL)"); graphicsContext = new AndroidJavaEGLGraphicsContext(); - INFO_LOG(SYSTEM, "NativeApp.init() - launching emu thread"); + INFO_LOG(Log::System, "NativeApp.init() - launching emu thread"); EmuThreadStart(); break; case (int)GPUBackend::VULKAN: { - INFO_LOG(SYSTEM, "NativeApp.init() -- creating Vulkan context"); + INFO_LOG(Log::System, "NativeApp.init() -- creating Vulkan context"); useCPUThread = false; // The Vulkan render manager manages its own thread. // We create and destroy the Vulkan graphics context in the app main thread though. AndroidVulkanContext *ctx = new AndroidVulkanContext(); if (!ctx->InitAPI()) { - INFO_LOG(SYSTEM, "Failed to initialize Vulkan, switching to OpenGL"); + INFO_LOG(Log::System, "Failed to initialize Vulkan, switching to OpenGL"); g_Config.iGPUBackend = (int)GPUBackend::OPENGL; SetGPUBackend(GPUBackend::OPENGL); goto retry; @@ -835,7 +843,7 @@ retry: break; } default: - ERROR_LOG(SYSTEM, "NativeApp.init(): iGPUBackend %d not supported. Switching to OpenGL.", (int)g_Config.iGPUBackend); + ERROR_LOG(Log::System, "NativeApp.init(): iGPUBackend %d not supported. Switching to OpenGL.", (int)g_Config.iGPUBackend); g_Config.iGPUBackend = (int)GPUBackend::OPENGL; goto retry; } @@ -865,11 +873,11 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_audioInit(JNIEnv *, jclass) { sampleRate = 44100; } - INFO_LOG(AUDIO, "NativeApp.audioInit() -- Using OpenSL audio! frames/buffer: %i optimal sr: %i actual sr: %i", optimalFramesPerBuffer, optimalSampleRate, sampleRate); + INFO_LOG(Log::Audio, "NativeApp.audioInit() -- Using OpenSL audio! frames/buffer: %i optimal sr: %i actual sr: %i", optimalFramesPerBuffer, optimalSampleRate, sampleRate); if (!g_audioState) { g_audioState = AndroidAudio_Init(&NativeMix, framesPerBuffer, sampleRate); } else { - ERROR_LOG(AUDIO, "Audio state already initialized"); + ERROR_LOG(Log::Audio, "Audio state already initialized"); } } @@ -878,7 +886,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_audioShutdown(JNIEnv *, jclass) AndroidAudio_Shutdown(g_audioState); g_audioState = nullptr; } else { - ERROR_LOG(AUDIO, "Audio state already shutdown!"); + ERROR_LOG(Log::Audio, "Audio state already shutdown!"); } } @@ -903,19 +911,19 @@ bool System_AudioRecordingState() { } extern "C" void Java_org_ppsspp_ppsspp_NativeApp_resume(JNIEnv *, jclass) { - INFO_LOG(SYSTEM, "NativeApp.resume() - resuming audio"); + INFO_LOG(Log::System, "NativeApp.resume() - resuming audio"); AndroidAudio_Resume(g_audioState); System_PostUIMessage(UIMessage::APP_RESUMED); } extern "C" void Java_org_ppsspp_ppsspp_NativeApp_pause(JNIEnv *, jclass) { - INFO_LOG(SYSTEM, "NativeApp.pause() - pausing audio"); + INFO_LOG(Log::System, "NativeApp.pause() - pausing audio"); AndroidAudio_Pause(g_audioState); } extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { - INFO_LOG(SYSTEM, "NativeApp.shutdown() -- begin"); + INFO_LOG(Log::System, "NativeApp.shutdown() -- begin"); if (renderer_inited && useCPUThread && graphicsContext) { // Only used in Java EGL path. @@ -924,19 +932,19 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { // which locks renderLock already, and only gets out once we call ThreadFrame() // in a loop before, to empty the queue. EmuThreadStop("shutdown"); - INFO_LOG(SYSTEM, "BeginAndroidShutdown"); + INFO_LOG(Log::System, "BeginAndroidShutdown"); graphicsContext->BeginAndroidShutdown(); // Now, it could be that we had some frames queued up. Get through them. // We're on the render thread, so this is synchronous. do { - INFO_LOG(SYSTEM, "Executing graphicsContext->ThreadFrame to clear buffers"); + INFO_LOG(Log::System, "Executing graphicsContext->ThreadFrame to clear buffers"); } while (graphicsContext->ThreadFrame()); graphicsContext->ThreadEnd(); - INFO_LOG(SYSTEM, "ThreadEnd called."); + INFO_LOG(Log::System, "ThreadEnd called."); graphicsContext->ShutdownFromRenderThread(); - INFO_LOG(SYSTEM, "Graphics context now shut down from NativeApp_shutdown"); + INFO_LOG(Log::System, "Graphics context now shut down from NativeApp_shutdown"); - INFO_LOG(SYSTEM, "Joining emuthread"); + INFO_LOG(Log::System, "Joining emuthread"); EmuThreadJoin(); } @@ -944,13 +952,13 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { std::lock_guard guard(renderLock); if (graphicsContext) { - INFO_LOG(G3D, "Shutting down renderer"); + INFO_LOG(Log::G3D, "Shutting down renderer"); graphicsContext->Shutdown(); delete graphicsContext; graphicsContext = nullptr; renderer_inited = false; } else { - INFO_LOG(G3D, "Not shutting down renderer - not initialized"); + INFO_LOG(Log::G3D, "Not shutting down renderer - not initialized"); } NativeShutdown(); @@ -962,7 +970,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { while (frameCommands.size()) frameCommands.pop(); } - INFO_LOG(SYSTEM, "NativeApp.shutdown() -- end"); + INFO_LOG(Log::System, "NativeApp.shutdown() -- end"); } // JavaEGL. This doesn't get called on the Vulkan path. @@ -970,7 +978,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) { extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) { _assert_(useCPUThread); - INFO_LOG(G3D, "NativeApp.displayInit()"); + INFO_LOG(Log::G3D, "NativeApp.displayInit()"); bool firstStart = !renderer_inited; // We should be running on the render thread here. @@ -980,21 +988,21 @@ extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, // but the only mechanism for handling lost devices seems to be that onSurfaceCreated is called again, // which ends up calling displayInit. - INFO_LOG(G3D, "NativeApp.displayInit() restoring"); + INFO_LOG(Log::G3D, "NativeApp.displayInit() restoring"); EmuThreadStop("displayInit"); graphicsContext->BeginAndroidShutdown(); - INFO_LOG(G3D, "BeginAndroidShutdown. Looping until emu thread done..."); + INFO_LOG(Log::G3D, "BeginAndroidShutdown. Looping until emu thread done..."); // Skipping GL calls here because the old context is lost. while (graphicsContext->ThreadFrame()) { continue; } - INFO_LOG(G3D, "Joining emu thread"); + INFO_LOG(Log::G3D, "Joining emu thread"); EmuThreadJoin(); graphicsContext->ThreadEnd(); graphicsContext->ShutdownFromRenderThread(); - INFO_LOG(G3D, "Shut down both threads. Now let's bring it up again!"); + INFO_LOG(Log::G3D, "Shut down both threads. Now let's bring it up again!"); if (!graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0)) { System_Toast("Graphics initialization failed. Quitting."); @@ -1009,9 +1017,9 @@ extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, graphicsContext->ThreadStart(); - INFO_LOG(G3D, "Restored."); + INFO_LOG(Log::G3D, "Restored."); } else { - INFO_LOG(G3D, "NativeApp.displayInit() first time"); + INFO_LOG(Log::G3D, "NativeApp.displayInit() first time"); if (!graphicsContext || !graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0)) { System_Toast("Graphics initialization failed. Quitting."); return false; @@ -1046,12 +1054,12 @@ static void recalculateDpi() { g_display.pixel_in_dps_x = (float)g_display.pixel_xres / g_display.dp_xres; g_display.pixel_in_dps_y = (float)g_display.pixel_yres / g_display.dp_yres; - INFO_LOG(G3D, "RecalcDPI: display_xres=%d display_yres=%d pixel_xres=%d pixel_yres=%d", display_xres, display_yres, g_display.pixel_xres, g_display.pixel_yres); - INFO_LOG(G3D, "RecalcDPI: g_dpi=%f g_dpi_scale_x=%f g_dpi_scale_y=%f dp_xres=%d dp_yres=%d", g_display.dpi, g_display.dpi_scale_x, g_display.dpi_scale_y, g_display.dp_xres, g_display.dp_yres); + INFO_LOG(Log::G3D, "RecalcDPI: display_xres=%d display_yres=%d pixel_xres=%d pixel_yres=%d", display_xres, display_yres, g_display.pixel_xres, g_display.pixel_yres); + INFO_LOG(Log::G3D, "RecalcDPI: g_dpi=%f g_dpi_scale_x=%f g_dpi_scale_y=%f dp_xres=%d dp_yres=%d", g_display.dpi, g_display.dpi_scale_x, g_display.dpi_scale_y, g_display.dp_xres, g_display.dp_yres); } extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint bufw, jint bufh, jint format) { - INFO_LOG(SYSTEM, "NativeApp.backbufferResize(%d x %d)", bufw, bufh); + INFO_LOG(Log::System, "NativeApp.backbufferResize(%d x %d)", bufw, bufh); bool new_size = g_display.pixel_xres != bufw || g_display.pixel_yres != bufh; int old_w = g_display.pixel_xres; @@ -1068,10 +1076,10 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv recalculateDpi(); if (new_size) { - INFO_LOG(G3D, "Size change detected (previously %d,%d) - calling NativeResized()", old_w, old_h); + INFO_LOG(Log::G3D, "Size change detected (previously %d,%d) - calling NativeResized()", old_w, old_h); NativeResized(); } else { - INFO_LOG(G3D, "NativeApp::backbufferResize: Size didn't change."); + INFO_LOG(Log::G3D, "NativeApp::backbufferResize: Size didn't change."); } } @@ -1097,7 +1105,7 @@ void System_Notify(SystemNotification notification) { } } -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { switch (type) { case SystemRequestType::EXIT_APP: PushCommand("finish", ""); @@ -1108,6 +1116,9 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string case SystemRequestType::RECREATE_ACTIVITY: PushCommand("recreate", param1); return true; + case SystemRequestType::COPY_TO_CLIPBOARD: + PushCommand("copy_to_clipboard", param1); + return true; case SystemRequestType::INPUT_TEXT_MODAL: { std::string serialized = StringFromFormat("%d:@:%s:@:%s", requestId, param1.c_str(), param2.c_str()); @@ -1153,8 +1164,8 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string case SystemRequestType::SHARE_TEXT: PushCommand("share_text", param1); return true; - case SystemRequestType::NOTIFY_UI_STATE: - PushCommand("uistate", param1); + case SystemRequestType::SET_KEEP_SCREEN_BRIGHT: + PushCommand("set_keep_screen_bright", param3 ? "on" : "off"); return true; case SystemRequestType::SHOW_FILE_IN_FOLDER: PushCommand("show_folder", param1); @@ -1166,7 +1177,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendRequestResult(JNIEnv *env, jclass, jint jrequestID, jboolean result, jstring jvalue, jint jintValue) { std::string value = jvalue ? GetJavaString(env, jvalue) : "(no value)"; - INFO_LOG(SYSTEM, "Received result of request %d from Java: %d: %d '%s'", jrequestID, (int)result, jintValue, value.c_str()); + INFO_LOG(Log::System, "Received result of request %d from Java: %d: %d '%s'", jrequestID, (int)result, jintValue, value.c_str()); if (result) { g_requestManager.PostSystemSuccess(jrequestID, value.c_str()); } else { @@ -1319,9 +1330,9 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_accelerometer(JNIEnv *, NativeAccelerometer(x, y, z); } -extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessageFromJava(JNIEnv *env, jclass, jstring message, jstring param) { - std::string msg = GetJavaString(env, message); - std::string prm = GetJavaString(env, param); +extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessageFromJava(JNIEnv *env, jclass, jstring jmessage, jstring jparam) { + std::string msg = GetJavaString(env, jmessage); + std::string prm = GetJavaString(env, jparam); // A bit ugly, see InputDeviceState.java. static InputDeviceID nextInputDeviceID = DEVICE_ID_ANY; @@ -1330,23 +1341,23 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessageFromJava(JNI if (msg == "moga") { mogaVersion = prm; } else if (msg == "permission_pending") { - INFO_LOG(SYSTEM, "STORAGE PERMISSION: PENDING"); + INFO_LOG(Log::System, "STORAGE PERMISSION: PENDING"); // TODO: Add support for other permissions permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_PENDING; // Don't need to send along, nothing else is listening. } else if (msg == "permission_denied") { - INFO_LOG(SYSTEM, "STORAGE PERMISSION: DENIED"); + INFO_LOG(Log::System, "STORAGE PERMISSION: DENIED"); permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_DENIED; // Don't need to send along, nothing else is listening. } else if (msg == "permission_granted") { - INFO_LOG(SYSTEM, "STORAGE PERMISSION: GRANTED"); + INFO_LOG(Log::System, "STORAGE PERMISSION: GRANTED"); permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_GRANTED; // Send along. System_PostUIMessage(UIMessage::PERMISSION_GRANTED, prm); } else if (msg == "sustained_perf_supported") { sustainedPerfSupported = true; } else if (msg == "safe_insets") { - // INFO_LOG(SYSTEM, "Got insets: %s", prm.c_str()); + // INFO_LOG(Log::System, "Got insets: %s", prm.c_str()); // We don't bother with supporting exact rectangular regions. Safe insets are good enough. int left, right, top, bottom; if (4 == sscanf(prm.c_str(), "%d:%d:%d:%d", &left, &right, &top, &bottom)) { @@ -1364,8 +1375,15 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessageFromJava(JNI System_PostUIMessage(UIMessage::POWER_SAVING, prm); } else if (msg == "exception") { g_OSD.Show(OSDType::MESSAGE_ERROR, std::string("Java Exception"), prm, 10.0f); + } else if (msg == "shortcutParam") { + if (prm.empty()) { + WARN_LOG(Log::System, "shortcutParam empty"); + return; + } + INFO_LOG(Log::System, "shortcutParam received: %s", prm.c_str()); + System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, StripQuotes(prm)); } else { - ERROR_LOG(SYSTEM, "Got unexpected message from Java, ignoring: %s / %s", msg.c_str(), prm.c_str()); + ERROR_LOG(Log::System, "Got unexpected message from Java, ignoring: %s / %s", msg.c_str(), prm.c_str()); } } @@ -1373,7 +1391,7 @@ void correctRatio(int &sz_x, int &sz_y, float scale) { float x = (float)sz_x; float y = (float)sz_y; float ratio = x / y; - INFO_LOG(G3D, "CorrectRatio: Considering size: %0.2f/%0.2f=%0.2f for scale %f", x, y, ratio, scale); + INFO_LOG(Log::G3D, "CorrectRatio: Considering size: %0.2f/%0.2f=%0.2f for scale %f", x, y, ratio, scale); float targetRatio; // Try to get the longest dimension to match scale*PSP resolution. @@ -1388,7 +1406,7 @@ void correctRatio(int &sz_x, int &sz_y, float scale) { } float correction = targetRatio / ratio; - INFO_LOG(G3D, "Target ratio: %0.2f ratio: %0.2f correction: %0.2f", targetRatio, ratio, correction); + INFO_LOG(Log::G3D, "Target ratio: %0.2f ratio: %0.2f correction: %0.2f", targetRatio, ratio, correction); if (ratio < targetRatio) { y *= correction; } else { @@ -1397,7 +1415,7 @@ void correctRatio(int &sz_x, int &sz_y, float scale) { sz_x = x; sz_y = y; - INFO_LOG(G3D, "Corrected ratio: %dx%d", sz_x, sz_y); + INFO_LOG(Log::G3D, "Corrected ratio: %dx%d", sz_x, sz_y); } void getDesiredBackbufferSize(int &sz_x, int &sz_y) { @@ -1429,7 +1447,7 @@ void getDesiredBackbufferSize(int &sz_x, int &sz_y) { } extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) { - INFO_LOG(G3D, "NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate); + INFO_LOG(Log::G3D, "NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate); if (IsVREnabled()) { int width, height; @@ -1529,7 +1547,7 @@ static void ProcessFrameCommands(JNIEnv *env) { frameCmd = frameCommands.front(); frameCommands.pop(); - INFO_LOG(SYSTEM, "frameCommand '%s' '%s'", frameCmd.command.c_str(), frameCmd.params.c_str()); + INFO_LOG(Log::System, "frameCommand '%s' '%s'", frameCmd.command.c_str(), frameCmd.params.c_str()); jstring cmd = env->NewStringUTF(frameCmd.command.c_str()); jstring param = env->NewStringUTF(frameCmd.params.c_str()); @@ -1539,7 +1557,7 @@ static void ProcessFrameCommands(JNIEnv *env) { } } -std::thread g_vulkanRenderLoopThread; +std::thread g_renderLoopThread; static void VulkanEmuThread(ANativeWindow *wnd); @@ -1549,12 +1567,12 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runVulkanRenderLoo _assert_(!useCPUThread); if (!graphicsContext) { - ERROR_LOG(G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context."); + ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context."); return false; } - if (g_vulkanRenderLoopThread.joinable()) { - ERROR_LOG(G3D, "runVulkanRenderLoop: Already running"); + if (g_renderLoopThread.joinable()) { + ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Already running"); return false; } @@ -1562,25 +1580,25 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runVulkanRenderLoo if (!wnd) { // This shouldn't ever happen. - ERROR_LOG(G3D, "Error: Surface is null."); + ERROR_LOG(Log::G3D, "Error: Surface is null."); renderLoopRunning = false; return false; } - g_vulkanRenderLoopThread = std::thread(VulkanEmuThread, wnd); + g_renderLoopThread = std::thread(VulkanEmuThread, wnd); return true; } extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeActivity_requestExitVulkanRenderLoop(JNIEnv * env, jobject obj) { if (!renderLoopRunning) { - ERROR_LOG(SYSTEM, "Render loop already exited"); + ERROR_LOG(Log::System, "Render loop already exited"); return; } - _assert_(g_vulkanRenderLoopThread.joinable()); + _assert_(g_renderLoopThread.joinable()); exitRenderLoop = true; - g_vulkanRenderLoopThread.join(); - _assert_(!g_vulkanRenderLoopThread.joinable()); - g_vulkanRenderLoopThread = std::thread(); + g_renderLoopThread.join(); + _assert_(!g_renderLoopThread.joinable()); + g_renderLoopThread = std::thread(); } // TODO: Merge with the Win32 EmuThread and so on, and the Java EmuThread? @@ -1591,14 +1609,14 @@ static void VulkanEmuThread(ANativeWindow *wnd) { JNIEnv *env = getEnv(); if (!graphicsContext) { - ERROR_LOG(G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context."); + ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context."); renderLoopRunning = false; exitRenderLoop = false; return; } if (exitRenderLoop) { - WARN_LOG(G3D, "runVulkanRenderLoop: ExitRenderLoop requested at start, skipping the whole thing."); + WARN_LOG(Log::G3D, "runVulkanRenderLoop: ExitRenderLoop requested at start, skipping the whole thing."); renderLoopRunning = false; exitRenderLoop = false; return; @@ -1607,14 +1625,14 @@ static void VulkanEmuThread(ANativeWindow *wnd) { // This is up here to prevent race conditions, in case we pause during init. renderLoopRunning = true; - WARN_LOG(G3D, "runVulkanRenderLoop. display_xres=%d display_yres=%d desiredBackbufferSizeX=%d desiredBackbufferSizeY=%d", + WARN_LOG(Log::G3D, "runVulkanRenderLoop. display_xres=%d display_yres=%d desiredBackbufferSizeX=%d desiredBackbufferSizeY=%d", display_xres, display_yres, desiredBackbufferSizeX, desiredBackbufferSizeY); if (!graphicsContext->InitFromRenderThread(wnd, desiredBackbufferSizeX, desiredBackbufferSizeY, backbuffer_format, androidVersion)) { // On Android, if we get here, really no point in continuing. // The UI is supposed to render on any device both on OpenGL and Vulkan. If either of those don't work // on a device, we blacklist it. Hopefully we should have already failed in InitAPI anyway and reverted to GL back then. - ERROR_LOG(G3D, "Failed to initialize graphics context."); + ERROR_LOG(Log::G3D, "Failed to initialize graphics context."); System_Toast("Failed to initialize graphics context."); delete graphicsContext; @@ -1625,7 +1643,7 @@ static void VulkanEmuThread(ANativeWindow *wnd) { if (!exitRenderLoop) { if (!NativeInitGraphics(graphicsContext)) { - ERROR_LOG(G3D, "Failed to initialize graphics."); + ERROR_LOG(Log::G3D, "Failed to initialize graphics."); // Gonna be in a weird state here.. } graphicsContext->ThreadStart(); @@ -1641,9 +1659,9 @@ static void VulkanEmuThread(ANativeWindow *wnd) { ProcessFrameCommands(env); } } - INFO_LOG(G3D, "Leaving Vulkan main loop."); + INFO_LOG(Log::G3D, "Leaving Vulkan main loop."); } else { - INFO_LOG(G3D, "Not entering main loop."); + INFO_LOG(Log::G3D, "Not entering main loop."); } NativeShutdownGraphics(); @@ -1652,20 +1670,20 @@ static void VulkanEmuThread(ANativeWindow *wnd) { graphicsContext->ThreadEnd(); // Shut the graphics context down to the same state it was in when we entered the render thread. - INFO_LOG(G3D, "Shutting down graphics context..."); + INFO_LOG(Log::G3D, "Shutting down graphics context..."); graphicsContext->ShutdownFromRenderThread(); renderLoopRunning = false; exitRenderLoop = false; - WARN_LOG(G3D, "Render loop function exited."); + WARN_LOG(Log::G3D, "Render loop function exited."); } // NOTE: This is defunct and not working, due to how the Android storage functions currently require // a PpssppActivity specifically and we don't have one here. -extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv *env, jclass, jstring jpath) { +extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv * env, jclass, jstring jpath) { bool teardownThreadManager = false; if (!g_threadManager.IsInitialized()) { - INFO_LOG(SYSTEM, "No thread manager - initializing one"); + INFO_LOG(Log::System, "No thread manager - initializing one"); // Need a thread manager. teardownThreadManager = true; g_threadManager.Init(1, 1); @@ -1673,7 +1691,7 @@ extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv Path path = Path(GetJavaString(env, jpath)); - INFO_LOG(SYSTEM, "queryGameName(%s)", path.c_str()); + INFO_LOG(Log::System, "queryGameName(%s)", path.c_str()); std::string result = ""; @@ -1681,11 +1699,11 @@ extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv std::shared_ptr info = cache->GetInfo(nullptr, path, GameInfoFlags::PARAM_SFO); // Wait until it's done: this is synchronous, unfortunately. if (info) { - INFO_LOG(SYSTEM, "GetInfo successful, waiting"); + INFO_LOG(Log::System, "GetInfo successful, waiting"); while (!info->Ready(GameInfoFlags::PARAM_SFO)) { sleep_ms(1); } - INFO_LOG(SYSTEM, "Done waiting"); + INFO_LOG(Log::System, "Done waiting"); if (info->fileType != IdentifiedFileType::UNKNOWN) { result = info->GetTitle(); @@ -1695,12 +1713,12 @@ extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv result = result.substr(strlen("The ")); } - INFO_LOG(SYSTEM, "queryGameName: Got '%s'", result.c_str()); + INFO_LOG(Log::System, "queryGameName: Got '%s'", result.c_str()); } else { - INFO_LOG(SYSTEM, "queryGameName: Filetype unknown"); + INFO_LOG(Log::System, "queryGameName: Filetype unknown"); } } else { - INFO_LOG(SYSTEM, "No info from cache"); + INFO_LOG(Log::System, "No info from cache"); } delete cache; @@ -1710,3 +1728,58 @@ extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv return env->NewStringUTF(result.c_str()); } + + +extern "C" +JNIEXPORT jbyteArray JNICALL +Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameIcon(JNIEnv * env, jclass clazz, jstring jpath) { + bool teardownThreadManager = false; + if (!g_threadManager.IsInitialized()) { + INFO_LOG(Log::System, "No thread manager - initializing one"); + // Need a thread manager. + teardownThreadManager = true; + g_threadManager.Init(1, 1); + } + // TODO: implement requestIcon() + + Path path = Path(GetJavaString(env, jpath)); + + INFO_LOG(Log::System, "queryGameIcon(%s)", path.c_str()); + + jbyteArray result = nullptr; + + GameInfoCache *cache = new GameInfoCache(); + std::shared_ptr info = cache->GetInfo(nullptr, path, GameInfoFlags::ICON); + // Wait until it's done: this is synchronous, unfortunately. + if (info) { + INFO_LOG(Log::System, "GetInfo successful, waiting"); + int attempts = 1000; + while (!info->Ready(GameInfoFlags::ICON)) { + sleep_ms(1); + attempts--; + if (!attempts) { + break; + } + } + INFO_LOG(Log::System, "Done waiting"); + if (info->Ready(GameInfoFlags::ICON)) { + if (!info->icon.data.empty()) { + INFO_LOG(Log::System, "requestIcon: Got icon"); + result = env->NewByteArray(info->icon.data.size()); + env->SetByteArrayRegion(result, 0, info->icon.data.size(), (const jbyte *)info->icon.data.data()); + } + } else { + INFO_LOG(Log::System, "requestIcon: Filetype unknown"); + } + } else { + INFO_LOG(Log::System, "No info from cache"); + } + + delete cache; + + if (teardownThreadManager) { + g_threadManager.Teardown(); + } + + return result; +} diff --git a/android/jni/app-android.h b/android/jni/app-android.h index d2d7957dcb..15328af1af 100644 --- a/android/jni/app-android.h +++ b/android/jni/app-android.h @@ -5,7 +5,7 @@ #include #include -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Common/File/DirListing.h" #include "Common/File/Path.h" #include "Common/File/AndroidStorage.h" diff --git a/android/legacy/conv_color.sh b/android/legacy/conv_color.sh new file mode 100644 index 0000000000..ce58dc458b --- /dev/null +++ b/android/legacy/conv_color.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Wirtten by ChatGPT + +# Define the base directory to start the search +BASE_DIR="$1" + +# Check if the base directory is provided and exists +if [ -z "$BASE_DIR" ]; then + echo "Usage: $0 /path/to/directory" + exit 1 +fi + +if [ ! -d "$BASE_DIR" ]; then + echo "Directory $BASE_DIR does not exist." + exit 1 +fi + +# Function to process images +process_image() { + local image_path="$1" + + # Define output path (can be modified to save to a different location) + local output_path="$1" # ${image_path%.*}_tinted.${image_path##*.}" + + # Apply the tint and darkening + convert "$image_path" \ + -modulate 80,50,55 \ + "$output_path" + + echo "Processed $image_path -> $output_path" +} + +export -f process_image + +# Find and process image files +find "$BASE_DIR" -type f \( -iname '*.png' \) -exec bash -c 'process_image "$0"' {} \; + +echo "Image processing completed." diff --git a/android/legacy/icon_color.md b/android/legacy/icon_color.md new file mode 100644 index 0000000000..436de9a89e --- /dev/null +++ b/android/legacy/icon_color.md @@ -0,0 +1,3 @@ +# How to create legacy icons from regular icons + +convert ic_launcher.png -modulate 80,50,55 ic_launcher.png diff --git a/android/legacy/res/drawable-hdpi/ic_launcher.png b/android/legacy/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000..7a36832d0f Binary files /dev/null and b/android/legacy/res/drawable-hdpi/ic_launcher.png differ diff --git a/android/legacy/res/drawable-mdpi/ic_launcher.png b/android/legacy/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000..ed83506c1b Binary files /dev/null and b/android/legacy/res/drawable-mdpi/ic_launcher.png differ diff --git a/android/legacy/res/drawable-xhdpi/ic_launcher.png b/android/legacy/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..4b7484924c Binary files /dev/null and b/android/legacy/res/drawable-xhdpi/ic_launcher.png differ diff --git a/android/legacy/res/drawable-xhdpi/tv_banner.png b/android/legacy/res/drawable-xhdpi/tv_banner.png new file mode 100644 index 0000000000..2a8093f438 Binary files /dev/null and b/android/legacy/res/drawable-xhdpi/tv_banner.png differ diff --git a/android/legacy/res/drawable-xxhdpi/ic_launcher.png b/android/legacy/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..895bba7f68 Binary files /dev/null and b/android/legacy/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/android/legacy/res/mipmap-anydpi-v26/ic_launcher.xml b/android/legacy/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000000..036d09bc5f --- /dev/null +++ b/android/legacy/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/legacy/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/legacy/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000000..036d09bc5f --- /dev/null +++ b/android/legacy/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/legacy/res/mipmap-hdpi/ic_launcher.png b/android/legacy/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..99313828b3 Binary files /dev/null and b/android/legacy/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/legacy/res/mipmap-hdpi/ic_launcher_foreground.png b/android/legacy/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..514ef73f78 Binary files /dev/null and b/android/legacy/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/android/legacy/res/mipmap-hdpi/ic_launcher_round.png b/android/legacy/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000..99313828b3 Binary files /dev/null and b/android/legacy/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/android/legacy/res/mipmap-mdpi/ic_launcher.png b/android/legacy/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..0f426364dc Binary files /dev/null and b/android/legacy/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/legacy/res/mipmap-mdpi/ic_launcher_foreground.png b/android/legacy/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..23bd8ab817 Binary files /dev/null and b/android/legacy/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/android/legacy/res/mipmap-mdpi/ic_launcher_round.png b/android/legacy/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000..fe5d77dd22 Binary files /dev/null and b/android/legacy/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/android/legacy/res/mipmap-xhdpi/ic_launcher.png b/android/legacy/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..a1aef39a73 Binary files /dev/null and b/android/legacy/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/legacy/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/legacy/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..c608cb1658 Binary files /dev/null and b/android/legacy/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/android/legacy/res/mipmap-xhdpi/ic_launcher_round.png b/android/legacy/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..a1aef39a73 Binary files /dev/null and b/android/legacy/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/android/legacy/res/mipmap-xxhdpi/ic_launcher.png b/android/legacy/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..57ff24d6c9 Binary files /dev/null and b/android/legacy/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/legacy/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/legacy/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..ed7bf5c088 Binary files /dev/null and b/android/legacy/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/legacy/res/mipmap-xxhdpi/ic_launcher_round.png b/android/legacy/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..57ff24d6c9 Binary files /dev/null and b/android/legacy/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/android/legacy/res/values/ic_launcher_background.xml b/android/legacy/res/values/ic_launcher_background.xml new file mode 100644 index 0000000000..8458956d4e --- /dev/null +++ b/android/legacy/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #404040 + diff --git a/android/legacy/res/values/strings.xml b/android/legacy/res/values/strings.xml new file mode 100644 index 0000000000..c3157e242c --- /dev/null +++ b/android/legacy/res/values/strings.xml @@ -0,0 +1,4 @@ + + + PPSSPP Legacy + diff --git a/android/res/drawable-xhdpi/ouya_icon.png b/android/res/drawable-xhdpi/ouya_icon.png deleted file mode 100644 index 8daf84f84b..0000000000 Binary files a/android/res/drawable-xhdpi/ouya_icon.png and /dev/null differ diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 9f68f904d1..b5f4e8cd77 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -7,6 +7,8 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.UiModeManager; +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -443,6 +445,7 @@ public abstract class NativeActivity extends Activity { String languageRegion = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry(); String shortcut = overrideShortcutParam == null ? shortcutParam : overrideShortcutParam; overrideShortcutParam = null; + shortcutParam = null; NativeApp.audioConfig(optimalFramesPerBuffer, optimalSampleRate); NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, extStorageDir, externalFilesDir, nativeLibDir, additionalStorageDirs, cacheDir, shortcut, Build.VERSION.SDK_INT, Build.BOARD); @@ -594,6 +597,7 @@ public abstract class NativeActivity extends Activity { // whether to start at 1x or 2x. sizeManager.updateDisplayMeasurements(); + boolean wasInitialized = initialized; if (!initialized) { Initialize(); initialized = true; @@ -661,6 +665,13 @@ public abstract class NativeActivity extends Activity { Log.i(TAG, "setcontentview after"); startRenderLoopThread(); } + + if (shortcutParam != null && shortcutParam.length() > 0) { + Log.i(TAG, "Got shortcutParam in onCreate on secondary run: " + shortcutParam); + // Make sure we only send it once. + NativeApp.sendMessageFromJava("shortcutParam", shortcutParam); + shortcutParam = null; + } } @Override @@ -1422,7 +1433,10 @@ public abstract class NativeActivity extends Activity { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); if (command.equals("browse_file_audio")) { - intent.setType("audio/x-wav"); + // Trickery for multiple mime types. + String [] mimeTypes = {"audio/x-wav", "audio/x-mpeg3", "audio/mpeg"}; + intent.setType("*/*"); + intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); } else if (command.equals("browse_file_zip")) { intent.setType("application/zip"); } else { @@ -1619,10 +1633,10 @@ public abstract class NativeActivity extends Activity { } else if (params.equals("stopRecording")) { NativeApp.audioRecording_Stop(); } - } else if (command.equals("uistate")) { + } else if (command.equals("set_keep_screen_bright")) { Window window = this.getWindow(); - if (params.equals("ingame")) { - // Keep the screen bright - very annoying if it goes dark when tilting away + if (params.equals("on")) { + // Keep the screen bright - very annoying if it goes dark when using tilt or a joystick window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); updateSustainedPerformanceMode(); } else { @@ -1654,10 +1668,23 @@ public abstract class NativeActivity extends Activity { NativeApp.reportException(e, params); return false; } + } else if (command.equals("copy_to_clipboard")) { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + copyStringToClipboard(params); + } + } else { + Log.w(TAG, "Unknown string command " + command); } return false; } + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void copyStringToClipboard(String text) { + ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("Copied Text", text); + clipboard.setPrimaryClip(clip); + } + @SuppressLint("NewApi") @Override public void recreate() { diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java index d661c887d8..397731140a 100644 --- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java +++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java @@ -99,7 +99,9 @@ public class PpssppActivity extends NativeActivity { if (data != null) { String path = data.toString(); Log.i(TAG, "Found Shortcut Parameter in data: " + path); - super.setShortcutParam("\"" + path.replace("\\", "\\\\").replace("\"", "\\\"") + "\""); + String escaped = "\"" + path.replace("\\", "\\\\").replace("\"", "\\\"") + "\""; + Log.i(TAG, "Escaped: " + escaped); + super.setShortcutParam(escaped); // Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show(); } else { String param = getIntent().getStringExtra(SHORTCUT_EXTRA_KEY); diff --git a/android/src/org/ppsspp/ppsspp/ShortcutActivity.java b/android/src/org/ppsspp/ppsspp/ShortcutActivity.java index d21c3bddca..f7717f823a 100644 --- a/android/src/org/ppsspp/ppsspp/ShortcutActivity.java +++ b/android/src/org/ppsspp/ppsspp/ShortcutActivity.java @@ -4,6 +4,8 @@ import android.app.Activity; import android.app.AlertDialog; import android.content.Intent; import android.content.Intent.ShortcutIconResource; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -75,6 +77,7 @@ public class ShortcutActivity extends Activity { } public static native String queryGameName(String path); + public static native byte[] queryGameIcon(String path); // Create shortcut as response for ACTION_CREATE_SHORTCUT intent. private void respondToShortcutRequest(Uri uri) { @@ -99,13 +102,13 @@ public class ShortcutActivity extends Activity { if (path.startsWith("content://")) { String [] segments = path.split("/"); try { - pathStr = java.net.URLDecoder.decode(segments[segments.length - 1], StandardCharsets.UTF_8.name()); + pathStr = java.net.URLDecoder.decode(segments[segments.length - 1], "UTF-8"); } catch (Exception e) { Log.i(TAG, "Exception getting name: " + e); } } else if (path.startsWith("file:///")) { try { - pathStr = java.net.URLDecoder.decode(path.substring(7), StandardCharsets.UTF_8.name()); + pathStr = java.net.URLDecoder.decode(path.substring(7), "UTF-8"); } catch (Exception e) { Log.i(TAG, "Exception getting name: " + e); } @@ -116,16 +119,19 @@ public class ShortcutActivity extends Activity { String[] pathSegments = pathStr.split("/"); name = pathSegments[pathSegments.length - 1]; - /* - // No longer working for various reasons. - PpssppActivity.CheckABIAndLoadLibrary(); - String name = queryGameName(path); - if (name.equals("")) { + String gameName = queryGameName(path); + byte [] iconData = null; + if (gameName.equals("")) { Log.i(TAG, "Failed to retrieve game name - ignoring."); - showBadGameMessage(); - return; - }*/ + // This probably happened because PPSSPP isn't running so the GameInfoCache isn't working. + // Let's just continue with our fallback name until we can fix that. + // showBadGameMessage(); + // return; + } else { + name = gameName; + iconData = queryGameIcon(path); + } Log.i(TAG, "Game name: " + name + " : Creating shortcut to " + uri.toString()); @@ -134,9 +140,23 @@ public class ShortcutActivity extends Activity { Intent responseIntent = new Intent(); responseIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); responseIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name); - ShortcutIconResource iconResource = ShortcutIconResource.fromContext(this, R.drawable.ic_launcher); - responseIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); + boolean setIcon = false; + if (iconData != null) { + // Try to create a PNG from the iconData. + Bitmap bmp = BitmapFactory.decodeByteArray(iconData, 0, iconData.length); + if (bmp != null) { + // Scale it to a square. + Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp, 144, 144, true); + responseIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, scaledBitmap); + } + setIcon = true; + } + if (!setIcon) { + // Fall back to the PPSSPP icon. + ShortcutIconResource iconResource = ShortcutIconResource.fromContext(this, R.drawable.ic_launcher); + responseIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); + } setResult(RESULT_OK, responseIntent); // Must call finish for result to be returned immediately diff --git a/android/src/org/ppsspp/ppsspp/TextRenderer.java b/android/src/org/ppsspp/ppsspp/TextRenderer.java index 60b18912c5..6bc2102d09 100644 --- a/android/src/org/ppsspp/ppsspp/TextRenderer.java +++ b/android/src/org/ppsspp/ppsspp/TextRenderer.java @@ -2,17 +2,21 @@ package org.ppsspp.ppsspp; import android.content.Context; import android.graphics.*; +import android.provider.Settings; import android.util.Log; +import android.view.accessibility.AccessibilityManager; public class TextRenderer { - private static Paint p; + private static Paint textPaint; private static Paint bg; private static Typeface robotoCondensed; private static final String TAG = "TextRenderer"; + private static boolean highContrastFontsEnabled = false; + static { - p = new Paint(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); - p.setColor(Color.WHITE); + textPaint = new Paint(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); + textPaint.setColor(Color.WHITE); bg = new Paint(); bg.setColor(0); } @@ -21,24 +25,25 @@ public class TextRenderer { robotoCondensed = Typeface.createFromAsset(ctx.getAssets(), "Roboto-Condensed.ttf"); if (robotoCondensed != null) { Log.i(TAG, "Successfully loaded Roboto Condensed"); - p.setTypeface(robotoCondensed); + textPaint.setTypeface(robotoCondensed); } else { Log.e(TAG, "Failed to load Roboto Condensed"); } + highContrastFontsEnabled = Settings.Secure.getInt(ctx.getContentResolver(), "high_text_contrast_enabled", 0) == 1; } private static Point measureLine(String string, double textSize) { int w; if (string.length() > 0) { - p.setTextSize((float) textSize); - w = (int) p.measureText(string); + textPaint.setTextSize((float) textSize); + w = (int) textPaint.measureText(string); // Round width up to even already here to avoid annoyances from odd-width 16-bit textures // which OpenGL does not like - each line must be 4-byte aligned w = (w + 5) & ~1; } else { w = 1; } - int h = (int) (p.descent() - p.ascent() + 2.0f); + int h = (int) (textPaint.descent() - textPaint.ascent() + 2.0f); Point p = new Point(); p.x = w; p.y = h; @@ -53,7 +58,7 @@ public class TextRenderer { Point sz = measureLine(line, textSize); total.x = Math.max(sz.x, total.x); } - total.y = (int) (p.descent() - p.ascent()) * lines.length + 2; + total.y = (int) (textPaint.descent() - textPaint.ascent()) * lines.length + 2; // Returning a 0 size can create problems when the caller // uses the measurement to create a texture. // Also, clamp to a reasonable maximum size. @@ -85,10 +90,26 @@ public class TextRenderer { String lines[] = string.replaceAll("\\r", "").split("\n"); float y = 1.0f; + + Path path = new Path(); + for (String line : lines) { - if (line.length() > 0) - canvas.drawText(line, 1, -p.ascent() + y, p); - y += p.descent() - p.ascent(); + if (line.length() > 0) { + if (highContrastFontsEnabled) { + // This is a workaround for avoiding "High Contrast Fonts" screwing up our + // single-channel font rendering. + // Unfortunately, emoji do not render on this path. + if (path == null) { + path = new Path(); + } + textPaint.getTextPath(line, 0, line.length(), 1, -textPaint.ascent() + y, path); + canvas.drawPath(path, textPaint); + } else { + // Standard text rendering, including emoji. Fine if high contrast fonts are not enabled. + canvas.drawText(line, 1, -textPaint.ascent() + y, textPaint); + } + } + y += textPaint.descent() - textPaint.ascent(); } int[] pixels = new int[w * h]; diff --git a/assets/compat.ini b/assets/compat.ini index 430416357f..bf5aa82d1e 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -264,6 +264,10 @@ ULJM06365 = true # ULJM05036 = true # ULUS10044 = true +[DrawSyncInstant] +# Bizarre timing issue in Sakura-sou no Pet na Kanojo, see issue #15224. Note that an instant DrawSync is not logical. +NPJH50745 = true + [FakeMipmapChange] # This hacks separates each mipmap to independent textures to display wrong-size mipmaps. # For example this requires games like Tactics Ogre(Japanese) to display multi bytes fonts stored in mipmaps. @@ -814,6 +818,10 @@ NPJH50019 = true ULJS19039 = true ULJS00188 = true +# Twisted Metal sound effects break without this +UCES00018 = true +UCUS98601 = true + [GoWFramerateHack60] # Replaces ForceMax60FPS for GOW games, should provide smoother experience # Also works around softlock in GOW:GOS , see #8299 @@ -850,10 +858,10 @@ UCUS98705 = true UCED00971 = true UCUS98713 = true -[GoWFramerateHack30] -# As the 60 fps version, but makes GOW games run on a potato, -# Doesn't suffer from softlock #8299 -# disabled by default since most people wouldn't need it +[FramerateHack30] +# Note that this hack is not universal, will not work for games simply added to the list +# 30 fps hacks for games that run well are disabled by default since it's only an option for users with very weak hardware +# GOW in 30 fps doesn't suffer from softlock #8299, so the hack is actually simpler # GOW : Ghost of Sparta # UCUS98737 = true # UCAS40323 = true @@ -887,6 +895,15 @@ UCUS98713 = true # UCED00971 = true # UCUS98713 = true +# Brian Lara 2007: Pressure Play +# workaround for incorrect fps/game speed +ULES00814 = true +ULES00815 = true + +# Blitz: Overtime +# workaround for incorrect fps/game speed +ULUS10200 = true + [ForceMax60FPS] # Some games are very heavy and render as fast as they can. They benefit greatly from # capping the framerate at 60fps. @@ -1262,6 +1279,16 @@ ULJS19050 = true NPJH50907 = true [AllowLargeFBTextureOffsets] +# Final Fantasy - Type 0, see #18879 +ULJM05900 = true +ULJM05901 = true +NPJH50443 = true +NPJH50444 = true +ULJM06217 = true +ULJM06218 = true +UCAS40346 = true +UCAS40347 = true + # Quickfix for Clone Wars, see #12949 ULES01284 = true ULES01285 = true @@ -1337,6 +1364,11 @@ UCET00278 = true UCUS98670 = true UCUS98646 = true +[UseFFMPEGFindStreamInfo] +# The Warriors: Works around regression (#8991) by reverting to the old behavior +ULUS10213 = true +ULES00483 = true + [ForceLowerResolutionForEffectsOn] # The water effect of DiRT 2 and Outrun doesn't work in higher resolutions. @@ -1730,6 +1762,13 @@ ULKS46254 = true ULJS19057 = true NPJH50263 = true +# Tales of the World: Radiant Mythology 2 - #19196 +ULJS00175 = true +UCAS40244 = true +UCKS45110 = true +ULJS19044 = true +NPJH50852 = true + [AllowDelayedReadbacks] # NOTE: This only affects Vulkan currently. # Added for easy experimentation. Many games using readbacks do not work well delaying them, though. diff --git a/assets/compatvr.ini b/assets/compatvr.ini index 84fac0d978..e05251c5a5 100644 --- a/assets/compatvr.ini +++ b/assets/compatvr.ini @@ -110,6 +110,17 @@ ULES00035 = 3 ULUS10014 = 3 +[ProjectionHack] +# Forces ignoring of projection matrix pivot point. + +# Gran Turismo: The Real Driving Simulator +NPJG00027 = true +UCAS40265 = true +UCES01245 = true +UCJS10100 = true +UCUS98632 = true + + [Skyplane] # Workaround to remove the background skyplane and add clearing framebuffer with a fog color. diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index 2d7ed44700..7dc26921a5 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -9,107 +9,109 @@ [Achievements] %1: Attempt failed = %1: المحاولة فشلت %1: Attempt started = %1: بدأت المحاولة -%1 achievements, %2 points = %1انجازات , %2 نقاط +%1 achievements, %2 points = %1انجازات, %2 نقاط Account = الحساب -Achievement progress = تقدم الانجازات -Achievement sound volume = Achievement sound volume -Achievement unlocked = الانجازات المكتملة -Achievements = الانجازات -Achievements are disabled = الانجازات معطلة -Achievements enabled = الانجازات مفعلة +Achievement progress = تقدم الإنجازات +Achievement sound volume = صوت الإنجازات +Achievement unlocked = الإنجازات المكتملة +Achievements = الإنجازات +Achievements are disabled = الإنجازات معطلة +Achievements enabled = الإنجازات مفعلة Achievements with active challenges = انجازات مع تحديات نشطة Allow Save State in Hardcore Mode (but not Load State) = السماح بحالة الحفظ في الوضع المشدد (حالة التحميل غير مسموحة) -Almost completed achievements = انجازات شبه مكتملة +Almost completed achievements = الإنجازات شبه مكتملة Around me = حولي -Can't log in to RetroAchievements right now = غير قادر على تسجيل الدخول في الانجازات الرجعية حاليا +Can't log in to RetroAchievements right now = حاليا RetroAchievements لا يمكنك تسجيل الدخول في Challenge indicator = مؤشر التحدي -Contacting RetroAchievements server... = ...الاتصال بسرفر الانجازات الرجعية +Contacting RetroAchievements server... = . . .RetroAchivements يتم الإتصال بسيرفر Customize = تخصيص -Earned = لقد فتحت 1% من اصل 2% من الانجازات, و تحصلت على 3% من اصل 4% من النقاط -Encore Mode = وضع الظهور -Failed logging in to RetroAchievements = فشل تسجيل الدخول الى الانجازات الرجعية -Failed to connect to RetroAchievements. Achievements will not unlock. = فشل الاتصال بالانجازات الرجعية. لن يتم تسجيل الانجازات. -Failed to identify game. Achievements will not unlock. = فشل في تحديد اللعبة. لن يتم تسجيل الانجازات. +Earned = حصلت +Encore Mode = وضع الإعادة +Failed logging in to RetroAchievements = RetroAchievements فشل تسجيل الدخول في +Failed to connect to RetroAchievements. Achievements will not unlock. = . لن يتم فتح الانجازات RetroAchievements فشل الإتصال في +Failed to identify game. Achievements will not unlock. = فشلت في تحديد اللعبة. لن يتم فتح الإنجازات. Hardcore Mode (no savestates) = الوضع المشدد (لا لحالات الحفظ) Hardcore Mode = الوضع المشدد -How to use RetroAchievements = كيف تستعمل الانجازات الرجعية -In Encore mode - listings may be wrong below = في الوضع المشدد - قد تكون القوائم خاطئة ادناه +How to use RetroAchievements = RetroAchievements كيف تستعمل +In Encore mode - listings may be wrong below = في وضع الإعادة - قد تكون القوائم خاطئة ادناه Leaderboard attempt started or failed = بدأت محاولة قائمة المتصدرين او فشلت Leaderboard result submitted = تم تقديم نتائج قائمة المتصدرين Leaderboard score submission = تقديم نتيجة قائمة المتصدرين -Leaderboard submission is enabled = تم تفعيل تقديم قائمة المتصدرين +Leaderboard submission is enabled = تم تفعيل تقديم قائمة المتصدرين Leaderboard tracker = مقتفي قائمة المتصدرين Leaderboards = قوائم المتصدرين -Links = Links -Locked achievements = انجازات مقفلة +Links = الروابط +Locked achievements = إنجازات مقفلة Log bad memory accesses = تسجيل الوصول الى الذاكرة السيئة Mastered %1 = %تم اتقان 1 -Notifications = الاشعارات -Recently unlocked achievements = الانجازات المتحصل عليها حديثا -Reconnected to RetroAchievements. = تم اعادة الاتصال بالانجازات الرجعية -Register on www.retroachievements.org = www.retroachievements.org قم بتسجيل حساب على -RetroAchievements are not available for this game = ان الانجازات الرجعية غير متوفرة لهاذه اللعبة -RetroAchievements website = موقع الانجازات الرجعية -Rich Presence = الحضور الغني +Notifications = الإشعارات +Recently unlocked achievements = الإنجازات التي تم فتحها مؤخرا +Reconnected to RetroAchievements. = RetroAchievements يتم إعادة الإتصال في +Register on www.retroachievements.org = www.retroachievements.org سجل في +RetroAchievements are not available for this game = RetroAchievements الإنجازات غير متوفرة لهذه اللعبة +RetroAchievements website = RetroAchievements موقع +Rich Presence = حالة ديسكورد Save state loaded without achievement data = تم تنشيط حالة الحفظ بدون بيانات الانجازات Save states not available in Hardcore Mode = حالة الحفظ غير متاحة في الوضع المشدد (الصعب) Sound Effects = مؤثرات صوتية Statistics = الاحصاءات Submitted %1 for %2 = تم تقديم 1% من اصل 2% من -Syncing achievements data... = ...مزامنة بيانات الانجازات -Test Mode = وضع الاختبار -This feature is not available in Hardcore Mode = هاته الخاصية غير متواجدة في الوضع المشدد -This game has no achievements = لا تحتوي هاذه اللعبة على اية انجازات +Syncing achievements data... = ...مزامنة بيانات الإنجازات +Test Mode = وضع الإختبار +This feature is not available in Hardcore Mode = هذه الخاصية غير متواجدة في الوضع المشدد +This game has no achievements = لا تحتوي هذه اللعبة على اية انجازات Top players = افضل اللاعبين -Unlocked achievements = الانجازات المفتوحة -Unofficial achievements = الانجازات الغير رسمية -Unsupported achievements = الانجازات الغير مدعومة +Unlocked achievements = الإنجازات المفتوحة +Unofficial achievements = الإنجازات الغير رسمية +Unsupported achievements = الإنجازات الغير مدعومة [Audio] Alternate speed volume = حجم السرعة البديل Audio backend = ‎(إعادة التشغيل مطلوبة) الخلفية الصوتية -Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio Error = الاخطاء الصوتية +Audio file format not supported. Must be WAV or MP3. = .WAV or MP3 صيغة ملف الصوت غير مدعومة. يجب ان تكون AudioBufferingForBluetooth = ‎معادلة مصادقة البلوتوث (بطئ) -Auto = Auto -Device = Device -Disabled = Disabled +Auto = تلقائي +Device = جهاز +Disabled = غير مفعل DSound (compatible) = ‎DSound (متكامل) Enable Sound = ‎تفعيل الصوت Global volume = ‎الصوت العام Microphone = Microphone -Microphone Device = Microphone device -Mute = Mute -Reverb volume = Reverb volume -Use new audio devices automatically = Use new audio devices automatically -Use global volume = Use global volume +Microphone Device = جهاز المايكروفون +Mix audio with other apps = Mix audio with other apps +Mute = كتم +Respect silent mode = Respect silent mode +Reverb volume = تردد الصوت +Use new audio devices automatically = استعمل اجهزة الصوت الجديده تلقائيا +Use global volume = استعمل الصوت العالمي WASAPI (fast) = ‎WASAPI (سريع) [Controls] -Analog Binding = Analog Binding -Analog Limiter = ‎محدد التناظري -Analog Settings = اعدادات التناظر -Analog Stick = ‎عصا تناظرية -Analog Style = النمط التناظري -Analog trigger threshold = Analog trigger threshold -AnalogLimiter Tip = ‎وضع حد اقصى للتناظر +Analog Binding = ربط الانالوج +Analog Limiter = ‎محدد الانالوج +Analog Settings = اعدادات الانالوج +Analog Stick = ‎عصا الانالوج +Analog Style = النمط الانالوج +Analog trigger threshold = حساسية ضغطة الانالوج +AnalogLimiter Tip = ‎وضع حد اقصى للانالوج Auto = ‎تلقائي -Auto-centering analog stick = ‎تنصيف العصا التناظرية تلقائياً +Auto-centering analog stick = ‎توسيط عصا الانالوج تلقائياً Auto-hide buttons after delay = ‎إخفاء الأزرار تلقائياً بعد ثواني -Auto-rotation speed = Auto-rotation speed -Binds = Binds -Button Binding = Button Binding +Auto-rotation speed = سرعة التدوير التلقائي +Binds = ربط +Button Binding = ربط الزر Button Opacity = ‎شفافية الأزرار Button style = ‎شكل الأزرار Calibrate Analog Stick = معايرة عصا التحكم Calibrate = ‎معايرة -Calibrated = معايرة +Calibrated = تمت معايرته Calibration = ‎المعايرة -Circular deadzone = منطقة ميتة دائرية +Circular deadzone = منطقة الحساسيه الدائرية Circular stick input = ادخال العصا الدائرية Classic = ‎كلاسيكي Confine Mouse = ‎حجز مؤشر الماوس في حدود نافذة البرنامج -Control Mapping = ‎تخطيط التحكم +Control Mapping = ‎تعديل ازرار التحكم Custom Key Setting = اعدادات مفاتيح مخصصة Customize = تخصيص Customize Touch Controls = ‎تعديل نسق إعدادات اللمس... @@ -120,7 +122,7 @@ Disable diagonal input = تعطيل الادخال القطري Double tap = نقر مزدوج Enable analog stick gesture = تفعيل حركة عصا التحكم Enable gesture control = تفعيل تحكم الحركات -Enable standard shortcut keys = تفعيل ازرار الاختصارات المعتادة +Enable standard shortcut keys = تفعيل ازرار الاختصارات الإعتيادية frames = الاطارات Gesture = حركة Gesture mapping = تخطيط الحركات @@ -180,8 +182,8 @@ X = X Y = Y [CwCheats] -Cheats = ‎الشفرات -Edit Cheat File = ‎عدل ملف الشفرة +Cheats = ‎الغش +Edit Cheat File = ‎عدل ملف الغش Import Cheats = ‎إستورد من cheat.db Import from %s = ‎إستورد من %s Refresh interval = ‎معدل التحديث @@ -197,22 +199,22 @@ Backend = ‎&خلفية التصيير(إعادة تشغيل PPSSPP) Bicubic = &Bicubic Break = Break Break on Load = Break on load -Buy Gold = ‎إشتري النسخة الإحترافية & -Control Mapping... = ‎&تخطيط التحكم... +Buy Gold = ‎إشتري النسخة الذهبية +Control Mapping... = ‎تخطيط التحكم... Copy PSP memory base address = Copy PSP memory base &address -Debugging = ‎&تصحيح -Deposterize = ‎&تحديد الحجم -Direct3D9 = Direct3D &9 -Direct3D11 = Direct3D &11 -Disassembly = ‎&التفكيك... +Debugging = ‎Debugging +Deposterize = ‎تحديد الحجم +Direct3D9 = Direct3D9 +Direct3D11 = Direct3D11 +Disassembly = التفكيك Discord = ديسكورد Display Layout && Effects = ‎أظهر مُعدل النسق... Display Rotation = ‎تدوير العرض Dump Next Frame to Log = ‎تصحيح الفريم التالي إلي سجل -Emulation = ‎&محاكاة -Enable Cheats = ‎تفعيل &الشفرات -Enable Sound = ‎تفعيل &الصوت -Exit = ‎&خروج +Emulation = ‎محاكاة +Enable Cheats = ‎تفعيل الغش +Enable Sound = ‎تفعيل الصوت +Exit = خروج Extract File... = ‎&إستخراج ملف... File = ‎&ملف Frame Skipping = ‎&تخطي الإطار @@ -241,6 +243,7 @@ Log Console = ‎&سجل الكونسول Memory View... = ‎عرض الرام... More Settings... = ‎&إعدادات إضافية... Nearest = ‎&الأقرب +Pause when not focused = ‎&إيقاف مؤقت حينما لا يكون مفعلاً Recent = &Recent Restart Graphics = إعادة تشغيل الرسومات Skip Buffer Effects = ‎&تخطي تأثيرات الصقل (غير مصقول, أسرع) @@ -252,7 +255,6 @@ Open Memory Stick = فتح شريحة الذاكرة Open New Instance = Open new instance OpenGL = &OpenGL Pause = ‎&إيقاف مؤقت -Pause When Not Focused = ‎&إيقاف مؤقت حينما لا يكون مفعلاً Portrait = ‎لوحة Portrait reversed = ‎لوحة معكوسة PPSSPP Forums = ‎PPSSPP &منتديات @@ -315,6 +317,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -327,7 +331,7 @@ Log View = ‎أظهر السجل Logging Channels = ‎قنوات التسجيل Multi-threaded rendering = Multi-threaded rendering Next = ‎التالي -No block = ‎لا بوك +No block = بدون منع Off = Off Prev = ‎السابق Random = ‎عشوائي @@ -341,6 +345,7 @@ Run CPU Tests = ‎شغل فحوص المعالج Save new textures = ‎حفظ الرسم الجديد Shader Viewer = ‎مستعرض الرسوميات Show Developer Menu = ‎أظهر قائمة المطور +Show GPO LEDs = Show GPO LEDs Show on-screen messages = إظهار الرسائل على الشاشة Stats = ‎الحالات System Information = ‎معلومات النظام @@ -376,6 +381,7 @@ ConfirmLoad = ‎تحميل هذه البيانات? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = ‎مسح Delete all = ‎مسح الكل @@ -402,7 +408,7 @@ Grid = Grid Inactive = غير نشط Installing... = جاري التحميل InternalError = حدث عطل داخلي -Links = الروابط +Links = الروابط Load = ‎تحميل Load completed = ‎التحميل إكتمل. Loading = ‎تحميل\nمن فضلك إنتظر... @@ -411,7 +417,7 @@ Log in = تسجيل الدخول Log out = تسجيل الخروج Logged in! = تم تسحيل الدخول Logging in... = جاري تسجيل الدخول... -More information... = المزيد من المعلومات +More information... = المزيد من المعلومات Move = ‎تحريك Move Down = تحريك للأسفل Move Up = تحريك للأعلى @@ -520,12 +526,12 @@ Calculate CRC = Calculate CRC Click "Calculate CRC" to verify ISO = Click "Calculate CRC" to verify ISO ConfirmDelete = ‎مسح CRC checksum does not match, bad or modified ISO = CRC checksum does not match, bad or modified ISO -Create Game Config = ‎أنشي إعدادت للعبة +Create Game Config = ‎أنشاء إعدادت للعبة Create Shortcut = ‎إصنع إختصار Delete Game = ‎إمسح اللعبة Delete Game Config = ‎مسح إعدادات اللعبة Delete Save Data = ‎مسح بيانات الحفظ -Europe = ‎أروبا +Europe = ‎أوروبا File size incorrect, bad or modified ISO = File size incorrect, bad or modified ISO Game = ‎اللعبة Game ID unknown - not in the ReDump database = Game ID unknown - not in the ReDump database @@ -536,14 +542,14 @@ InstallData = ‎تثبيت البيانات ISO OK according to the ReDump project = ISO OK according to the ReDump project Japan = ‎اليابان Korea = كوريا -MB = ‎ميجا +MB = بايت‎ميجا One moment please... = ‎دقيقة واحدة من فضلك... Play = ‎إبدء اللعب Remove From Recent = ‎مسح من "الحالي" SaveData = ‎بيانات الحفظ Setting Background = ‎إعدادات الخلفية Show In Folder = ‎أظهر في المجلد -Time Played: %1h %2m %3s = Time Played: %1h %2m %3s +Time Played: %1h %2m %3s = %1س %2د %3ث : وقت اللعب Uncompressed = تم فك الضغط USA = ‎أمريكا Use UI background = ‎إستخدم خلفية الواجهة @@ -607,7 +613,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = ‎أظهر مُعدل النسق +Display layout & effects = ‎أظهر مُعدل النسق Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -640,6 +646,7 @@ LowCurves Tip = ‎فقط يستخدم من بعض الألعاب, يتحكم ب Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = ‎تكبير يدوي Medium = ‎متوسط +Mirror camera image = Mirror camera image Mode = ‎الوضع Must Restart = ‎يجب عليك إعادة تشغيل البرنامج لكي تُطبق التغييرات. Native device resolution = ‎حجم الجهاز الأساسي @@ -702,9 +709,12 @@ Window Size = ‎حجم النافذة xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = ‎مسح الملف المضغوط +Existing data = Existing data Install = ‎تثبيت Install game from ZIP file? = ‎تثبيت اللعبة من الملف المضغوط ? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = فشل في التثبيت Installed! = ‎مثبت! @@ -734,19 +744,19 @@ You can press ESC to cancel. = ‎يمكنك ضغط علي زر الخروج ل [MainMenu] Browse = ‎تصفح... -Buy PPSSPP Gold = Buy PPSSPP Gold -Choose folder = Choose folder +Buy PPSSPP Gold = الذهبي PPSSPP اشتر +Choose folder = اختر المجلد Credits = ‎الحقوق PPSSPP Homebrew Store = ‎PPSSPP Homebrew Store Exit = ‎خروج Game Settings = ‎الإعدادات Games = ‎الألعاب Give PPSSPP permission to access storage = ‎الأذون للوصول إلي مساحة التخزين PPSSPP أعطي الـ -Homebrew & Demos = Homebrew && Demos -How to get games = ‎كيف يمكنني الحصول علي الألعاب? -How to get homebrew & demos = How can I get homebrew && demos? -Load = ‎تحميل... -Loading... = Loading... +Homebrew & Demos = Homebrew & Demos +How to get games = ‎كيف يمكنني الحصول على الألعاب +How to get homebrew & demos = How can I get homebrew & demos? +Load = ‎تحميل +Loading... = ...تحميل PinPath = ‎تثبيت PPSSPP can't load games or save right now = ‎لا يمكنه تحميل الألعاب الأن أو الحفظ الأن PPSSPP Recent = ‎الحالي @@ -760,9 +770,9 @@ www.ppsspp.org = www.ppsspp.org [MainSettings] Audio = ‎الصوت Controls = ‎التحكم -Graphics = ‎الجرافك +Graphics = ‎الجرافكس Networking = ‎الشبكة -Search = Search +Search = البحث System = ‎النظام Tools = ‎الأدوات @@ -804,7 +814,7 @@ Mute toggle = Mute toggle Next Slot = Next slot None = None Note = Note -OpenChat = فتح المحادثة +OpenChat = فتح المحادثة Pause = ‎توقف مؤقت Previous Slot = Previous Slot R = R @@ -822,16 +832,16 @@ Rotate Analog (CCW) = Rotate analog (CCW) Rotate Analog (CW) = Rotate analog (CW) Save State = Save state Screen = ‎الشاشة -Screenshot = Screenshot +Screenshot = تصوير الشاشة Select = ‎تحديد SpeedToggle = ‎تفعيل السرعة Square = ‎مربع Start = ‎بدء -Swipe Down = Swipe Down -Swipe Left = Swipe Left -Swipe Right = Swipe Right -Swipe Up = Swipe Up -tap to customize = tap to customize +Swipe Down = اسحب تحت +Swipe Left = اسحب يسار +Swipe Right = اسحب يمين +Swipe Up = اسحب فوق +tap to customize = اضغط للتخصيص Texture Dumping = Texture dumping Texture Replacement = Texture replacement Toggle Fullscreen = ‎تفعيل وضع الشاشة الكاملة @@ -851,17 +861,17 @@ Already contains PSP data = Already contains PSP data Cancelled - try again = Cancelled - try again Checking... = Checking... Create or Choose a PSP folder = Create or Choose a PSP folder -Current = Current +Current = الحالي DataCanBeShared = Data can be shared between PPSSPP regular/Gold DataCannotBeShared = Data CANNOT be shared between PPSSPP regular/Gold! DataWillBeLostOnUninstall = Warning! Data will be lost when you uninstall PPSSPP! DataWillStay = Data will stay even if you uninstall PPSSPP. -Deleting... = Deleting... -Done! = Done! -EasyUSBAccess = Easy USB access +Deleting... = ...يتم الحذف +Done! = !تم +EasyUSBAccess = USBالوصول السهل للـ Failed to move some files! = فشل في نقل بعض الملفات Failed to save config = فشل في حفظ الإعدادات -Free space = المساحة المتوفرة +Free space = المساحة المتوفرة Manually specify PSP folder = Manually specify PSP folder MemoryStickDescription = Choose where to keep PSP data (Memory Stick) Move Data = نقل البيانات @@ -876,7 +886,7 @@ USBAccessThroughGold = USB access through Android/data/org.ppsspp.ppssppgold/fil Use App Private Data = Use App Private Data Use PSP folder at root of storage = Use PSP folder at root of storage Welcome to PPSSPP! = Welcome to PPSSPP! -WhatsThis = What's this? +WhatsThis = ?ما هذا [Networking] AdHoc Server = Ad hoc server @@ -888,46 +898,46 @@ Change proAdhocServer Address = Change PRO ad hoc server IP address (localhost = ChangeMacSaveConfirm = Generate a new MAC address? ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. Chat = محادثة -Chat Button Position = Chat button position +Chat Button Position = مكان زر المحادثة Chat Here = تحدث هنا -Chat message = Chat message -Chat Screen Position = Chat screen position -Disconnected from AdhocServer = Disconnected from ad hoc server +Chat message = رسائل الشات +Chat Screen Position = مكان شاشة الشات +Disconnected from AdhocServer = AdhocServer تم قطع الاتصال في سيرفرات DNS Error Resolving = DNS error resolving Enable built-in PRO Adhoc Server = Enable built-in PRO ad hoc server -Enable network chat = Enable network chat -Enable networking = Enable networking/WLAN -Enable UPnP = Enable UPnP (need a few seconds to detect) -EnableQuickChat = Enable quick chat -Enter a new PSP nickname = Enter a new PSP nickname -Enter Quick Chat 1 = Enter quick chat 1 -Enter Quick Chat 2 = Enter quick chat 2 -Enter Quick Chat 3 = Enter quick chat 3 -Enter Quick Chat 4 = Enter quick chat 4 -Enter Quick Chat 5 = Enter quick chat 5 -Error = Error +Enable network chat = تفعيل الشات عبر الشبكه +Enable networking = networking/WLAN تفعيل +Enable UPnP = (يحتاج لبعض الوقت للكشف) UPnP تفعيل +EnableQuickChat = تفعيل الشات السريع +Enter a new PSP nickname = اختيار اسم البي اس بي الجديد +Enter Quick Chat 1 = الدخول الى الشات السريع 1 +Enter Quick Chat 2 = الدخول الى الشات السريع 2 +Enter Quick Chat 3 = الدخول الى الشات السريع 3 +Enter Quick Chat 4 = الدخول الى الشات السريع 4 +Enter Quick Chat 5 = الدخول الى الشات السريع 5 +Error = فشل Failed to Bind Localhost IP = Failed to bind localhost IP Failed to Bind Port = Failed to bind port Failed to connect to Adhoc Server = Failed to connect to ad hoc server Forced First Connect = Forced first connect (faster connect) GM: Data from Unknown Port = GM: Data from Unknown Port -Hostname = Hostname +Hostname = اسم المستضيف Invalid IP or hostname = Invalid IP or hostname Minimum Timeout = Minimum timeout (override in ms, 0 = default) Misc = Miscellaneous (default = PSP compatibility) -Network connected = Network connected +Network connected = متصل بالشبكة Network initialized = ‎الشبكة تُطلق Please change your Port Offset = Please change your port offset Port offset = Port offset (0 = PSP compatibility) Open PPSSPP Multiplayer Wiki Page = Open PPSSPP Multiplayer Wiki Page proAdhocServer Address: = Ad hoc server address: -Quick Chat 1 = Quick chat 1 -Quick Chat 2 = Quick chat 2 -Quick Chat 3 = Quick chat 3 -Quick Chat 4 = Quick chat 4 -Quick Chat 5 = Quick chat 5 -QuickChat = Quick chat -Randomize = Randomize +Quick Chat 1 = الشات السريع 1 +Quick Chat 2 = الشات السريع 2 +Quick Chat 3 = الشات السريع 3 +Quick Chat 4 = الشات السريع 4 +Quick Chat 5 = الشات السريع 5 +QuickChat = الشات السريع +Randomize = عشوائي Send = إرسال Send Discord Presence information = Send Discord "Rich Presence" information Unable to find UPnP device = Unable to find UPnP device @@ -940,11 +950,11 @@ WLAN Channel = WLAN channel You're in Offline Mode, go to lobby or online hall = You're in offline mode, go to lobby or online hall [PSPSettings] -Auto = Auto +Auto = تلقائي Chinese (simplified) = صينية(مبسطة) Chinese (traditional) = صينية(التقليدية) Dutch = هُولَندي -English = إنجليزية +English = إنجليزية French = فرنسية Game language = لغة اللعبة German = إلماني @@ -968,8 +978,8 @@ Rewind = ‎إرجاع Save State = ‎حفظ الحالة Settings = ‎الإعدادات Switch UMD = ‎تبديل الـ UMD -Undo last load = Undo last load -Undo last save = Undo last save +Undo last load = تراجع عن اخر تحميل +Undo last save = تراجع عن اخر حفظ [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) @@ -977,38 +987,38 @@ Undo last save = Undo last save 5xBR = 5xBR pixel art upscaler 5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = ‎AA-لون -Amount = Amount +Amount = عدد Animation speed (0 -> disable) = Animation speed (0 -> disable) Aspect = Aspect -Black border = Black border -Bloom = Bloom -BloomNoBlur = Bloom (no blur) -Brightness = Brightness +Black border = حواف سوداء +Bloom = وهج +BloomNoBlur = وهج (بدون تغبيش) +Brightness = الاضائة Cartoon = ‎كرتوني CatmullRom = Bicubic (Catmull-Rom) Upscaler -ColorCorrection = Color correction -ColorPreservation = Color preservation +ColorCorrection = تصحيح الالوان +ColorPreservation = حفظ الالوان Contrast = Contrast CRT = ‎CRT خطوط الفحص -FakeReflections = FakeReflections +FakeReflections = انعكاسات وهميه FXAA = ‎FXAA منعم الحواف Gamma = Gamma -GreenLevel = Green level -Intensity = Intensity +GreenLevel = مستوى الاخضر +Intensity = الشدة LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = ‎الألوان الحقيقية -NaturalA = Natural Colors (no blur) +NaturalA = الوان حقيقية (بدون تغبيش) Off = ‎مغلق -Power = Power -PSPColor = PSP color -RedBlue = Red/Blue glasses +Power = طاقة +PSPColor = PSPلون الـ +RedBlue = نظارات الاحمر و الازرق Saturation = Saturation -Scanlines = Scanlines (CRT) +Scanlines = خطوط (CRT فلتر) Sharpen = ‎تنعيم الحواف SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) -Strength = Strength +Strength = قوة Tex4xBRZ = 4xBRZ TexMMPX = MMPX UpscaleBicubic = UpscaleBicubic @@ -1018,7 +1028,7 @@ Vignette = Vignette [PSPCredits] all the forum mods = all the forum mods -build server = build server +build server = بناء سيرفر Buy Gold = ‎إشتري النسخة الذهبية check = ‎تفحص أيضا برنامج Dolphin, أفضل محاكي جهاز الوي ومكعب الألعاب موجود حالياً: CheckOutPPSSPP = Check out PPSSPP, the awesome PSP emulator: https://www.ppsspp.org/ @@ -1030,13 +1040,13 @@ info2 = ‎من فضلك تحقق أنك تملك الحقوق لأي لعبة info3 = you play by owning the UMD or by buying the digital info4 = download from the PSN store on your real PSP. info5 = PSP is a trademark by Sony, Inc. -iOS builds = iOS builds +iOS builds = IOSنسخ الـ license = ‎برنامج مجاني تحت رخصة GPL 2.0+ list = ‎قائمة التكامل, المنتديات, ومعلومات التطوير PPSSPP Forums = ‎PPSSPP منتديات Privacy Policy = Privacy policy Share PPSSPP = ‎مشاركة PPSSPP -specialthanks = ‎الشكر الجزيل إلي: +specialthanks = ‎شكر خاص : specialthanksKeithGalocy = at NVIDIA (hardware, advice) specialthanksMaxim = for his amazing Atrac3+ decoder work testing = testing @@ -1046,20 +1056,24 @@ tools = ‎الأدوات المجانية المستعملة: # Add translators or contributors who translated PPSSPP into your language here. # Add translators1-6 for up to 6 lines of translator credits. # Leave extra lines blank. 4 contributors per line seems to look best. -translators1 = ‎عمر أنور عجلان +translators1 = ‎ِAlucard_xi translators2 = omar.aglan91@gmail.com translators3 =ma1feesm -translators4 = +translators4 =عمر أنور عجلان translators5 = translators6 = Twitter @PPSSPP_emu = Twitter @PPSSPP_emu -website = ‎تحقق من الموقع الألكتروني: +website = ‎الموقع الألكتروني written = ‎مكتوب في لغة C++ من أجل السرعة والمتانة [RemoteISO] Browse Games = ‎تصفح الألعاب +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = ‎منفذ السرفر المحلي Manual Mode Client = ‎الوضع اليدوي للعميل +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = ‎منفذ السرفر البعيد Remote Server = ‎السرفر البعيد @@ -1121,9 +1135,9 @@ Unselected Overall Description = ‎هل هذه اللعبة تمت لعبتها View Feedback = ‎أظهر كل المراجاعات [Savedata] -Date = التاريخ +Date = التاريخ Filename = إسم الملف -No screenshot = ‎لا لقطة شاشة +No screenshot = ‎لا تصور الشاشة None yet. Things will appear here after you save. = ‎ليس بعد. الأشياء سوف تظهر هنا بعد الحفظ. Nothing matching '%1' was found. = Nothing matching '%1' was found. Save Data = ‎حفظ البيانات @@ -1140,7 +1154,7 @@ Failed to load state = Failed to load state Failed to save state = Failed to save state fixed = ‎السرعة: الجانبي GLToolsWarning = WARNING: GLTools detected, may cause problems. -In menu = In menu +In menu = في القائمه Loaded State = ‎الحالة تم تحميلها Loaded. Game may refuse to save over different savedata. = Loaded. Game may refuse to save over different savedata. Loaded. Game may refuse to save over newer savedata. = Loaded. Game may refuse to save over newer savedata. @@ -1162,7 +1176,7 @@ Untitled PSP game = Untitled PSP game [Search] Clear filter = Clear filter -Filter = Filter +Filter = فلتر Filtering settings by '%1' = Filtering settings by '%1' Find settings = Find settings No settings matched '%1' = No settings matched '%1' @@ -1173,10 +1187,12 @@ Connection Error = ‎خطأ في الإتصال Install = ‎تثبيت Installed = ‎مثبتة بالفعل Launch Game = ‎إبدء اللعبة +License = License Loading... = ‎تحميل... MB = ‎ميجا Size = ‎الحجم Uninstall = ‎إلغاء التثبيت +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1232,7 +1248,7 @@ OS Information = OS information Pixel resolution = Pixel resolution PPSSPP build = PPSSPP build Present modes = Present modes -Refresh rate = Refresh rate +Refresh rate = معدل التحديث Release = Release RW/RX exclusive = RW/RX exclusive Sample rate = Sample rate @@ -1255,6 +1271,7 @@ Vulkan Features = Vulkan features (broken) = ‎(متضرر) 12HR = ‎12 ساعة 24HR = ‎24 ساعة +App switching mode = App switching mode Auto = ‎تلقائي Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1265,6 +1282,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = ‎أنوية المعالج Dynarec/JIT (recommended) = Dynarec/JIT (مُستَحسَن) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1285,11 +1303,11 @@ Confirmation Button = ‎زر التأكيد Date Format = ‎صيغة التاريخ Day Light Saving = ‎التوقيت الصيفي DDMMYYYY = ‎يوم شهر سنة -Decrease size = Decrease size +Decrease size = تقليص الحجم Developer Tools = ‎ادوات المطور Display Extra Info = إظهار معلومات أكثر Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = ‎المحاكاة Enable Cheats = ‎فعل الشفرات @@ -1313,7 +1331,7 @@ Memory Stick Folder = Memory Stick folder Memory Stick inserted = ‎تم إدخال الذاكرة MHz, 0:default = ميجا هرتز, 0 = ‎الإفتراضي MMDDYYYY = ‎شهر يوم سنة -Moving background = Moving background +Moving background = خلفية متحركة Newest Save = Newest save No animation = No animation Not a PSP game = ‎PSP ليست لعبة @@ -1321,6 +1339,8 @@ Off = ‎مغلق Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = ‎&إيقاف مؤقت حينما لا يكون مفعلاً +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = ‎PSP موديل PSP Settings = ‎PSP إعدادات @@ -1329,7 +1349,7 @@ PSP-2000/3000 = PSP-2000/3000 Recent games = الألعاب السابقة Record Audio = ‎تسجيل الصوت Record Display = ‎سجل الفيديو -Recording = جاري التسجيل +Recording = جاري التسجيل Reset Recording on Save/Load State = Reset recording on Save/Load state Restore Default Settings = ‎إلي الإفتراضي PPSSPP's إعادة إعدادات RetroAchievements = RetroAchievements @@ -1353,6 +1373,8 @@ Slot 4 = فتحة 4 Slot 5 = فتحة 5 Storage full = ‎الذاكرة ممتلئة Sustained performance mode = ‎وضع الأداء المتواصل +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = السمه Time Format = ‎صيغة الوقت Transparent UI background = Transparent UI background @@ -1394,26 +1416,23 @@ List: = List: Progress: %1% = Progress: %1% Screen representation = Screen representation [Upgrade] -Details = Details +Details = معلومات Dismiss = ‎إلغاء Download = ‎تحميل New version of PPSSPP available = ‎تتوفر نسخة جديدة من البرنامج [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = وضع الكاميرا Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = الواقع الإفتراضي VR camera = كاميرا الواقع الإفتراضي diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index e4ecf6f161..06978c6210 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Audio backend (restart req.) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = Səs Açıq Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest +Pause when not focused = &Pause When Not Focused Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Open &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &Forums @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Run CPU tests Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = System information @@ -368,6 +373,7 @@ ConfirmLoad = Load this data? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Sil Delete all = Delete all @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = Mode Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution @@ -694,9 +701,12 @@ Window Size = Window size xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Delete ZIP file +Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! @@ -734,9 +744,9 @@ Exit = Çıxış Game Settings = Settings Games = Games Give PPSSPP permission to access storage = Give PPSSPP permission to access storage -Homebrew & Demos = Homebrew && Demos +Homebrew & Demos = Homebrew & Demos How to get games = How can I get games? -How to get homebrew & demos = How can I get homebrew && demos? +How to get homebrew & demos = How can I get homebrew & demos? Load = Yüklə... Loading... = Loading... PinPath = Pin @@ -1050,8 +1060,12 @@ written = Written in C++ for speed and portability [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Connection error Install = Install Installed = Installed Launch Game = Launch game +License = License Loading... = Loading... MB = MB Size = Size Uninstall = Uninstall +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (tövsiyə) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Developer tools Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulation Enable Cheats = Enable cheats @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pause when not focused +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = PSP settings @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Time format Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Download New version of PPSSPP available = New version of PPSSPP available [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index 914df34303..33887122d0 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Audio backend (restart req.) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = Включи звук Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Log Console Memory View... = Памет изглед... More Settings... = Още настройки... Nearest = &Най-близко +Pause when not focused = Пауза, когато не фокусиран Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Отвори от мемори стик Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = Пауза, когато не фокусиран Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &форум @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Run CPU tests Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Покажи developer меню +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = Системна информация @@ -368,6 +373,7 @@ ConfirmLoad = Зареди тези данни? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Изтрий Delete all = Delete all @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = Режим Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution @@ -694,9 +701,12 @@ Window Size = Размер на прозореца xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Изтрий ZIP архива +Existing data = Existing data Install = Инсталирай Install game from ZIP file? = Инсталирай игра от ZIP архив? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Инсталирано! @@ -734,9 +744,9 @@ Exit = Изход Game Settings = Настройки Games = Директории Give PPSSPP permission to access storage = Give PPSSPP permission to access storage -Homebrew & Demos = Homebrew && Demos +Homebrew & Demos = Homebrew & Demos How to get games = Как да се сдобия с игри? -How to get homebrew & demos = Как да се сдобия с homebrew && demos? +How to get homebrew & demos = Как да се сдобия с Homebrew & Demos? Load = Зареди игра Loading... = Loading... PinPath = Pin @@ -1050,8 +1060,12 @@ written = Написано в C++ за бързина и съвместимос [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Грешка при свързването Install = Инсталирай Installed = Вече е инсталирано Launch Game = Launch game +License = License Loading... = Зареждане... MB = MB Size = Големина Uninstall = Деинсталирай +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12ч. 24HR = 24ч. +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (препоръчително) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Инсрументи на разработчик Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Емулация Enable Cheats = Включи чиитове @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Пауза, когато не фокусиран +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP серия PSP Settings = PSP настройки @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Час Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Свали New version of PPSSPP available = Налична е нова версия на PPSSPP [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 1fa83baf27..aeede7096d 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternar velocitat del soroll Audio backend = Motor d'àudio (requereix reiniciar) Audio Error = Error d'àudio -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Memòria intermèdia en Bluetooth (lent) Auto = Automàtic Device = Dispositiu @@ -71,7 +71,9 @@ Enable Sound = Activar el so Global volume = Volum global Microphone = Micròfon Microphone Device = Dispositiu de micròfon +Mix audio with other apps = Mix audio with other apps Mute = Silenciar +Respect silent mode = Respect silent mode Reverb volume = Volum de reverberació Use new audio devices automatically = Canviar a dispositiu d'àudio nou Use global volume = Utilitzar volumen global @@ -233,6 +235,7 @@ Log Console = Consola de re&gistres Memory View... = Visor de &memòria... More Settings... = Més &paràmetres... Nearest = &El més proper +Pause when not focused = &Pausar quan es canviï de finestra Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Renderitzat sense memòria intermèdia (més ràpid) @@ -244,7 +247,6 @@ Open Memory Stick = Obrir «&Memory Stick» Open New Instance = Obrir nova instància OpenGL = &OpenGL Pause = &Pausar -Pause When Not Focused = &Pausar quan es canviï de finestra Portrait = Vertical Portrait reversed = Vertical invertit PPSSPP Forums = &Fòrums de PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Amidar el rendiment +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Proves de CPU Save new textures = Desa les noves textures Shader Viewer = Visualitzador de shader Show Developer Menu = Mostra el menú de desenvolupament +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Estadístiques System Information = Informació del sistema @@ -368,6 +373,7 @@ ConfirmLoad = Vols carregar les dades? ConnectingAP = Connectant al punt d'accés.\nPer favor espera... ConnectingPleaseWait = Connectant.\nPer favor espera... ConnectionName = Nom de la connexió +Copy to clipboard = Copy to clipboard Corrupted Data = Dades corruptes Delete = Eliminar Delete all = Eliminar tot @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Desactivat -Display Layout && Effects = Editor de l'àrea de pantalla +Display layout & effects = Editor de l'àrea de pantalla Display Resolution (HW scaler) = Resolució de pantalla (escalat per maquinari) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Augmenta/redueix significativament el renderitzat de corbes Béz Lower resolution for effects (reduces artifacts) = Efectes en baixa resolució\n(redueix errors gràfics per escalat) Manual Scaling = Escalat manual Medium = Intermèdia +Mirror camera image = Mirror camera image Mode = Mode Must Restart = Heu de reiniciar PPSSPP per aplicar aquest canvi. Native device resolution = Resolució nativa del dispositiu @@ -694,9 +701,12 @@ Window Size = Mida de la finestra xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Delete ZIP file +Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! @@ -1050,8 +1060,12 @@ written = Written in C++ for speed and portability [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Error de connexió Install = Instal·lar Installed = Ja instal·lat Launch Game = Iniciar joc +License = License Loading... = Carregant... MB = MB Size = Mida Uninstall = Desinstal·lar +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = Nucli de CPU Dynarec/JIT (recommended) = Dynarec/JIT (recomanat) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Developer tools Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulation Enable Cheats = Activar trucs @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Pausar quan es canviï de finestra +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = PSP settings @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Time format Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Descarregar New version of PPSSPP available = Nova versió de PPSSPP disponible [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index 7cd0790da1..0855779b33 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Zvukové jádro (vyžaduje restart) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = Povolit zvuk Global volume = Celková hlasitost Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Konzole záznamu Memory View... = &Zobrazení paměti... More Settings... = D&alší nastavení... Nearest = &Nejbližší +Pause when not focused = &Pozastavit pokud okno není zaměřeno Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Přeskočit efekty vyrovnávací paměti @@ -244,7 +247,6 @@ Open Memory Stick = Otevřít &paměťovou kartu Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pozastavit -Pause When Not Focused = &Pozastavit pokud okno není zaměřeno Portrait = Na výšku Portrait reversed = Na výšku obráceně PPSSPP Forums = &Fóra PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Profilovač snímku +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Spustit zkoušky CPU Save new textures = Save new textures Shader Viewer = Prohlížeč shaderů Show Developer Menu = Zobrazit nabídku pro vývojáře +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Statistiky System Information = Informace o systému @@ -368,6 +373,7 @@ ConfirmLoad = Načíst tyto data? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Smazat Delete all = Smazat vše @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Zobrazit editor rozvržení +Display layout & effects = Zobrazit editor rozvržení Display Resolution (HW scaler) = Rozlišení obrazovky (Hardwarové zvětšení) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Nižší rozlišení efektů (snižuje artefakty) Manual Scaling = Ruční zvětšení Medium = Střední +Mirror camera image = Mirror camera image Mode = Režim Must Restart = Aby došlo k použití těchto změn, je nutné PPSSPP restartovat. Native device resolution = Původní rozlišení zařízení @@ -694,9 +701,12 @@ Window Size = Velikost okna xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Smazat soubor ZIP +Existing data = Existing data Install = Nainstalovat Install game from ZIP file? = Instalovat hru ze souboru ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Instalováno! @@ -1050,8 +1060,12 @@ written = Vytvořeno v jazyce C++ pro rychlost a přenosnost [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Chyba připojení Install = Nainstalovat Installed = Již instalováno Launch Game = Spustit hru +License = License Loading... = Načítání... MB = MB Size = Velikost Uninstall = Odinstalovat +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (rozbité) 12HR = 12HOD 24HR = 24HOD +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Nástroje pro vývojáře Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulace Enable Cheats = Povolit Cheaty @@ -1313,6 +1331,8 @@ Off = Vypnuto Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Pozastavit pokud okno není zaměřeno +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Model PSP PSP Settings = Nastavení PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Úložiště je plné Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Formát času Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Stáhnout New version of PPSSPP available = Je dostupná nová verze PPSSPP [VR] +% of native FoV = % výchozího FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Poměr zorného pole Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 37d51b8609..711ca6dce7 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Lyd backend Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-venlig buffer (langsommere) Auto = Automatisk Device = Device @@ -71,7 +71,9 @@ Enable Sound = Aktiver lyd Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Log konsol Memory View... = Hukommelseso&versigt... More Settings... = &Flere indstillinger... Nearest = &Nærmest +Pause when not focused = P&ause når ikke i fokus Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effekter @@ -244,7 +247,6 @@ Open Memory Stick = Åben h&ukommelsesstick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = P&ause når ikke i fokus Portrait = Portræt Portrait reversed = Omvendt portræt PPSSPP Forums = PPSSPP &forum @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Kør CPU test Save new textures = Gem nye textures Shader Viewer = Shader viewer Show Developer Menu = Vis udviklermenu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = System information @@ -368,6 +373,7 @@ ConfirmLoad = Hent dette data? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Slet Delete all = Slet alt @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Skærmopløsning (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Bruges kun af nogle spil, kontrollerer glathed af kurver Lower resolution for effects (reduces artifacts) = Lavere opløsning for effekter (reducerer artefakter) Manual Scaling = Manuel scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = Tilstand Must Restart = Du må genstarte PPSSPP for at aktivere denne ændring. Native device resolution = Standard enheds opløsning @@ -694,9 +701,12 @@ Window Size = Vinduesstørrelse xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Slet ZIP fil +Existing data = Existing data Install = Installer Install game from ZIP file? = Installer spil fra ZIP fil? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installeret! @@ -1050,8 +1060,12 @@ written = Skrevet i C++ for hastighed og portabilitet [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Forbindelsesfejl Install = Installer Installed = Allerede installeret Launch Game = Start spil +License = License Loading... = Henter... MB = MB Size = Størrelse Uninstall = Afinstaller +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (ødelagt) 12HR = 12 timer 24HR = 24 timer +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI Dump startet. @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (anbefalede) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Udvikler værktøjer Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulation Enable Cheats = Tillad snyd @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = P&ause når ikke i fokus +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = PSP indstillinger @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Tidsformat Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Download New version of PPSSPP available = Ny version af PPSSPP tilgængelig [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index b9349fbed5..39d4248417 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Lautstärke für wechselnde Geschwindigkeit/Turbo Audio backend = Ton-Backend (Neustart erforderlich) Audio Error = Audio Fehler -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-freundliche Pufferung (langsamer) Auto = Automatisch Device = Gerät @@ -71,7 +71,9 @@ Enable Sound = Ton einschalten Global volume = Lautstärke Microphone = Mikrofon Microphone Device = Mikrofon Gerät +Mix audio with other apps = Mix audio with other apps Mute = Stumm +Respect silent mode = Respect silent mode Reverb volume = Hall Lautstärke Use new audio devices automatically = Neues Tonausgabegerät anschalten Use global volume = Benutze globale Lautstärke @@ -233,6 +235,7 @@ Log Console = Logkonsole Memory View... = Speicheransicht... More Settings... = Mehr Einstellungen... Nearest = Nächster Nachbar +Pause when not focused = Pausieren im Hintergrund Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = Überspringe Puffereffekte @@ -244,7 +247,6 @@ Open Memory Stick = Öffne Memory Stick Open New Instance = Öffne neue Instanz OpenGL = OpenGL Pause = Pause -Pause When Not Focused = Pausieren im Hintergrund Portrait = Hochformat Portrait reversed = Hochformat umgedreht PPSSPP Forums = PPSSPP Forum @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame Profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU Treibertest GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = CPU Test starten Save new textures = Speichere neue Texturen Shader Viewer = Shader-Anzeige Show Developer Menu = Zeige Entwicklermenü +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Statistiken System Information = Systeminformationen @@ -368,6 +373,7 @@ ConfirmLoad = Wollen Sie diese Daten laden? ConnectingAP = Verbinde zu dem Access Point.\nBitte warten... ConnectingPleaseWait = Verbinde.\nBitte warten... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Löschen Delete all = Alle löschen @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Deaktiviert -Display Layout && Effects = Bildschirmlayout Editor +Display layout & effects = Bildschirmlayout Editor Display Resolution (HW scaler) = Bildschirmauflösung (HW Skalierung) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Diese Option regelt die Qualität von Bezierkurven und Splines Lower resolution for effects (reduces artifacts) = Niedrigere Auflösung für Effekte (reduziert Artifakte) Manual Scaling = Manuelle Skalierung Medium = Mittel +Mirror camera image = Mirror camera image Mode = Modus Must Restart = Sie müssen PPSSPP neustarten, damit die Änderungen wirksam werden. Native device resolution = Native Auflösung @@ -694,9 +701,12 @@ Window Size = Fenstergröße xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = ZIP Datei löschen +Existing data = Existing data Install = Installieren Install game from ZIP file? = Spiel aus ZIP Datei installieren? +Install in folder = Install in folder Install textures from ZIP file? = Texturen von ZIP Datei installieren? Installation failed = Installation failed Installed! = Installiert! @@ -734,9 +744,9 @@ Exit = Beenden Game Settings = Einstellungen Games = Spiele Give PPSSPP permission to access storage = PPSSPP Speicherzugriff erlauben -Homebrew & Demos = Homebrew && Demos +Homebrew & Demos = Homebrew & Demos How to get games = Woher bekomme ich Spiele? -How to get homebrew & demos = Woher bekomme ich Homebrew && Demos? +How to get homebrew & demos = Woher bekomme ich Homebrew & Demos? Load = Laden... Loading... = Lädt... PinPath = Anheften @@ -1050,8 +1060,12 @@ written = Programmiert in C++ für Geschwindigkeit und Portabilität [RemoteISO] Browse Games = Spiele durchsuchen +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Lokaler Serverport Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote Disc streaming Remote Port = Remote Port Remote Server = Remote Server @@ -1165,10 +1179,12 @@ Connection Error = Verbindungsfehler Install = Installieren Installed = Bereits installiert Launch Game = Spiel starten +License = License Loading... = Lade... MB = MB Size = Größe Uninstall = Deinstallieren +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan Besonderheiten (broken) = (kaputt) 12HR = 12 Std 24HR = 24 Std +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Spielstand automatisch laden AVI Dump started. = AVI Dump gestartet. @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU Kern Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Verkleinern Developer Tools = Entwicklerwerkzeuge Display Extra Info = Zeige weitere Infos Display Games on a grid = Zeige "Spiele" als Grid -Display Homebrew on a grid = Zeige "Homebrew && Demos" als Grid +Display Homebrew on a grid = Zeige "Homebrew & Demos" als Grid Display Recent on a grid = Zeige "Zuletzt gespielt" als Grid Emulation = Emulation Enable Cheats = Cheats aktivieren @@ -1313,6 +1331,8 @@ Off = Aus Oldest Save = Ältester Spielstand Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pausieren im Hintergrund +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP Modell PSP Settings = PSP Einstellungen @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Speicherplatz voll Sustained performance mode = Anhaltener Hochleistungsmodus +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Zeitformat Transparent UI background = Menü Hintergrund transparent @@ -1392,20 +1414,17 @@ Download = Herunterladen New version of PPSSPP available = Neue PPSSPP Version verfügbar [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Kameratyp Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR Kamera diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 10cdbb919a..68e840afe3 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Audio backend (restart req.) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = Padenni suarana Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Konsol log Memory View... = Pempakitan &Memory... More Settings... = &More Settings... Nearest = &Nearest +Pause when not focused = &Pause When Not Focused Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Bukka' &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Paus -Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &Forumna @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Pajalanni tes CPU Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = Pempakitan to sistem dipake @@ -368,6 +373,7 @@ ConfirmLoad = Bukka'mi te' data? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Hapusi Delete all = Delete all @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = Mode Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution @@ -694,9 +701,12 @@ Window Size = Window size xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Delete ZIP file +Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! @@ -736,7 +746,7 @@ Games = Paningoan Give PPSSPP permission to access storage = Give PPSSPP permission to access storage Homebrew & Demos = Homebrew Sola Demo How to get games = Matumbaki' nampa' paningoan? -How to get homebrew & demos = Matumbaki' nampa' homebrew && demo? +How to get homebrew & demos = Matumbaki' nampa' homebrew & demo? Load = Bukka'... Loading... = Loading... PinPath = Pin @@ -1050,8 +1060,12 @@ written = Pake C++ digaraka yamo na malassi [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Connection error Install = Install Installed = Installed Launch Game = Launch game +License = License Loading... = Loading... MB = MB Size = Size Uninstall = Uninstall +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12jang 24HR = 24jang +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Pakakasa'na to panggaraga Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Pang-emulasi Enable Cheats = Pajalanni to Cheat @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pause when not focused +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = Pangngaturan PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Matumbai to wattu? Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Download New version of PPSSPP available = New version of PPSSPP available [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 8d1d501402..857adc1436 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -18,7 +18,7 @@ # The hotkeys are only supported currently in the DesktopUI section, however. # # Example 1: &File. This will make it so when you press ALT + F on Windows, it'll open the File menu. -# Example 2: Homebrew && Demos. This would show one real ampersand in the menu. +# Example 2: Homebrew & Demos. This would show one real ampersand in the menu. # # Happy translating. @@ -84,8 +84,8 @@ Unofficial achievements = Unofficial achievements [Audio] Alternate speed volume = Alternate speed volume Audio backend = Audio backend (restart req.) -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. Audio Error = Audio Error +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -95,7 +95,9 @@ Enable Sound = Enable sound Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -257,6 +259,7 @@ Log Console = &Log console Memory View... = Memory &view... More Settings... = &More settings... Nearest = &Nearest +Pause when not focused = &Pause when not focused Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects Off = &Off @@ -267,7 +270,6 @@ Open Memory Stick = Open &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = &Pause when not focused Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &forums @@ -333,6 +335,8 @@ FPU = FPU Framedump tests = Framedump tests Frame Profiler = Frame profiler Frame timing = Frame timing +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU Profile = GPU profile @@ -359,6 +363,7 @@ Run CPU Tests = Run CPU tests Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = System information @@ -392,6 +397,7 @@ ConfirmLoad = Load this data? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Delete Delete all = Delete all @@ -605,6 +611,7 @@ Copy to texture = Copy to texture Current GPU Driver = Current GPU Driver Default GPU driver = Default GPU driver Disable culling = Disable culling +Display layout & effects = Display layout & effects Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. @@ -626,7 +633,6 @@ Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Disabled -Display Layout && Effects = Display layout && effects Display Resolution (HW scaler) = Display resolution (HW scaler) Enable Cardboard VR = Enable Cardboard VR FPS = FPS @@ -656,6 +662,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = Mode Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution @@ -718,9 +725,12 @@ Window Size = Window size xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Delete ZIP file +Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! @@ -758,9 +768,9 @@ Exit = Exit Game Settings = Settings Games = Games Give PPSSPP permission to access storage = Give PPSSPP permission to access storage -Homebrew & Demos = Homebrew && Demos +Homebrew & Demos = Homebrew & Demos How to get games = How can I get games? -How to get homebrew & demos = How can I get homebrew && demos? +How to get homebrew & demos = How can I get homebrew & demos? Load = Load... Loading... = Loading... PinPath = Pin @@ -1074,8 +1084,12 @@ Spanish = Spanish [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manually configure client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1181,10 +1195,12 @@ Connection Error = Connection error Install = Install Installed = Installed Launch Game = Launch game +License = License Loading... = Loading... MB = MB Size = Size Uninstall = Uninstall +Website = Website [SysInfo] %d (%d per core, %d cores) = %d (%d per core, %d cores) @@ -1263,6 +1279,7 @@ Display Color Formats = Display Color Formats (broken) = (broken) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1290,10 +1307,11 @@ Decrease size = Decrease size Developer Tools = Developer tools Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulation Enable Cheats = Enable cheats +Enable plugins = Enable plugins Enable Compatibility Server Reports = Enable compatibility server reports Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state. Error in the file system. = Failed to load state. Error in the file system. @@ -1327,6 +1345,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pause when not focused +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = PSP settings @@ -1358,6 +1378,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Time Format = Time format Transparent UI background = Transparent UI background UI = UI @@ -1417,20 +1439,17 @@ Progress: %1% = Progress: %1% Screen representation = Screen representation [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update Heads-up display scale = Heads-up display scale Heads-up display detection = Heads-up display detection -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Camera type = Camera type -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 133ed6f33a..301dcfb9ac 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternar velocidad de sonido Audio backend = Motor de audio (requiere reiniciar) Audio Error = Error de audio -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Búfer compatible con bluetooth (lento) Auto = Automático Device = Dispositivo @@ -71,7 +71,9 @@ Enable Sound = Activar sonido Global volume = Volumen global Microphone = Micrófono Microphone Device = Dispositivo de entrada +Mix audio with other apps = Mix audio with other apps Mute = Silenciar +Respect silent mode = Respect silent mode Reverb volume = Volumen de reverberación Use new audio devices automatically = Cambiar a dispositivo de audio nuevo Use global volume = Usar volumen global @@ -233,6 +235,7 @@ Log Console = Consola de re&gistros... Memory View... = Visor de &memoria... More Settings... = Más &opciones... Nearest = &Cercano +Pause when not focused = &Pausar al cambiar de ventana Recent = &Reciente Restart Graphics = Restart Graphics Skip Buffer Effects = &Saltar efectos del búfer (rápido) @@ -244,7 +247,6 @@ Open Memory Stick = Abrir "&Memory Stick" Open New Instance = Abrir nueva ins&tancia OpenGL = &OpenGL Pause = &Pausar -Pause When Not Focused = &Pausar al cambiar de ventana Portrait = &Vertical Portrait reversed = Vertical &invertido PPSSPP Forums = &Foro de PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame Profiler = Medir rendimiento Frame timing = Frame timing Framedump tests = Tests de volcado de cuadros +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = Test de controlador GPU GPU log profiler = log de perfiles GPU @@ -333,6 +337,7 @@ Run CPU Tests = Pruebas de CPU Save new textures = Guardar texturas nuevas Shader Viewer = Visor de shader Show Developer Menu = Mostrar menú de desarrollo +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Mostrar mensajes en pantalla Stats = Estadísticas System Information = Información del sistema @@ -368,6 +373,7 @@ ConfirmLoad = ¿Deseas cargar estos datos guardados? ConnectingAP = Conectando al punto de acceso.\nPor favor espera... ConnectingPleaseWait = Conectando.\nPor favor espera... ConnectionName = Nombre de la conexión +Copy to clipboard = Copy to clipboard Corrupted Data = Datos corruptos Delete = Borrar Delete all = Borrar todo @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Desactivado -Display Layout && Effects = Editar pantalla y Shaders +Display layout & effects = Editar pantalla y Shaders Display Resolution (HW scaler) = Resolución de pantalla (escalado por hardware) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Aumenta/reduce significativamente el renderizado de curvas Bézi Lower resolution for effects (reduces artifacts) = Efectos en baja resolución\n(reduce errores gráficos por escalado) Manual Scaling = Escalado manual Medium = Intermedia +Mirror camera image = Mirror camera image Mode = Modo Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa del dispositivo @@ -694,9 +701,12 @@ Window Size = Tamaño de ventana xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Borrar archivo ZIP +Existing data = Existing data Install = Instalar Install game from ZIP file? = ¿Instalar juego desde archivo ZIP? +Install in folder = Install in folder Install textures from ZIP file? = ¿Instalar texturas desde archivo ZIP? Installation failed = Installation failed Installed! = ¡Instalado! @@ -1051,8 +1061,12 @@ written = Escrito en lenguaje C++ para una mejor portabilidad y velocidad [RemoteISO] Browse Games = Buscar juegos +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Puerto del servidor local Manual Mode Client = Cliente en modo manual +Not currently sharing = Not currently sharing Remote disc streaming = Streaming de disco remoto Remote Port = Puerto remoto Remote Server = Servidor remoto @@ -1166,10 +1180,12 @@ Connection Error = Error de conexión Install = Instalar Installed = Ya instalado Launch Game = Iniciar juego +License = Licencia Loading... = Cargando... MB = MB Size = Tamaño Uninstall = Desinstalar +Website = Sitio web [SysInfo] %0.2f Hz = %0.2f Hz @@ -1248,6 +1264,7 @@ Vulkan Features = Funciones Vulkan (broken) = (roto) 12HR = 12 horas 24HR = 24 horas +App switching mode = App switching mode Auto = Automático Auto Load Savestate = Carga automática de estados de guardado AVI Dump started. = Grabación iniciada. @@ -1258,6 +1275,7 @@ Color Saturation = Saturación de color Color Tint = Matiz de color CPU Core = Núcleo de CPU Dynarec/JIT (recommended) = Dynarec/JIT (recomendada) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: el estado es de otro juego. Failed to load state for load undo. Error in the file system. = Falló la reversión del estado debido a un error del archivo. Floating symbols = Símbolos flotantes @@ -1314,6 +1332,8 @@ Off = No Oldest Save = Partida guardada más antigua Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = ¡La ruta no existe! +Pause when not focused = &Pausar al cambiar de ventana +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Modelo de PSP PSP Settings = Ajustes de PSP @@ -1346,6 +1366,8 @@ Slot 4 = Ranura 4 Slot 5 = Ranura 5 Storage full = No queda espacio Sustained performance mode = Modo de rendimiento sostenido +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Tema Time Format = Formato de hora Transparent UI background = Fondo transparente @@ -1394,20 +1416,17 @@ Download = Descargar New version of PPSSPP available = Nueva versión de PPSSPP disponible [VR] +% of native FoV = % de campo de visión nativo 6DoF movement = Movimiento 6DoF -Camera type = Camera type Distance to 2D menus and scenes = Distancia de los menús y escenas 2D Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Escala de campo de visión Force 72Hz update = Forzar actualizar a 72Hz -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Escala de la barra de estado Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Asignar los movimientos del mando a las teclas -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Movimiento necesario para generar acción Stereoscopic vision (Experimental) = Visión Estereoscópica (Experimental) Virtual reality = Realidad Virtual VR camera = Cámara VR diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index 9aea80aa77..930c6dbb25 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -1,128 +1,130 @@ [Achievements] %1 achievements, %2 points = %1 logros, %2 puntos -%1: Attempt started = %1: intento para el leaderboard iniciado -%1: Attempt failed = %1: intento para el leaderboard fallido +%1: Attempt started = %1: Intento iniciado +%1: Attempt failed = %1: Intento fallido Account = Cuenta -Achievement progress = Achievement progress -Achievement sound volume = Achievement sound volume +Achievement progress = Progreso en los logros +Achievement sound volume = Volumen de sonido de los logros Achievement unlocked = Logro Desbloqueado Achievements = Logros Achievements are disabled = Los logros están desactivados -Achievements enabled = Achievements enabled -Achievements with active challenges = Achievements with active challenges -Allow Save State in Hardcore Mode (but not Load State) = Allow Save State in Hardcore Mode (but not Load State) +Achievements enabled = Los logros están Activados +Achievements with active challenges = Logros con desafios activos +Allow Save State in Hardcore Mode (but not Load State) = Permitir Save State en Modo Hardcore (pero no Estado de carga) Almost completed achievements = Almost completed achievements Around me = Around me -Can't log in to RetroAchievements right now = No se pudo iniciar sesión a RetroAchievements -Challenge indicator = Challenge indicator +Can't log in to RetroAchievements right now = No se pudo iniciar sesión en RetroAchievements en este momentó +Challenge indicator = Indicador de desafios Contacting RetroAchievements server... = Contactando al servidor de RetroAchievements... Customize = Customizar Earned = Has obtenido %1 de %2 logros y %3 de %4 puntos Encore Mode = Modo Encore -Failed logging in to RetroAchievements = Failed logging in to RetroAchievements -Failed to connect to RetroAchievements. Achievements will not unlock. = Failed to connect to RetroAchievements. Achievements will not unlock. -Failed to identify game. Achievements will not unlock. = Failed to identify game. Achievements will not unlock. -Hardcore Mode (no savestates) = Modo Desafío (Sin estados) -Hardcore Mode = Modo Desafío +Failed logging in to RetroAchievements = Fallo el Inicio de sesión en RetroAchievement +Failed to connect to RetroAchievements. Achievements will not unlock. = Fallo la conección a RetroAchievements. Los logros no se desbloquearán. +Failed to identify game. Achievements will not unlock. = Fallo al identificar juego. Los logros no se desbloquearán. +Hardcore Mode (no savestates) = Modo Hardcore (Sin salvar estados) +Hardcore Mode = Modo Hardcore How to use RetroAchievements = Como usar RetroAchievements -In Encore mode - listings may be wrong below = En el modo Encore - las listas de abajo pueden estar equivocadas -Leaderboard attempt started or failed = Leaderboard attempt started or failed -Leaderboard result submitted = Leaderboard result submitted -Leaderboard score submission = Subir puntos al leaderboard -Leaderboard submission is enabled = Se ha activado la subida de puntos al leaderboard -Leaderboard tracker = Leaderboard tracker -Leaderboards = Leaderboards +In Encore mode - listings may be wrong below = En el modo Encore - las listas de abajo pueden estár equivocadas +Leaderboard attempt started or failed = Intento de Tabla de clasificación iniciado o fallido +Leaderboard result submitted = Resultado de Tabla de clasificaciónes enviado +Leaderboard score submission = Subir puntos a la Tabla de clasificación +Leaderboard submission is enabled = Se ha activado la subida de puntos a la Tabla de clasificaciónes +Leaderboard tracker = Seguimiento a la Tabla de clasificación +Leaderboards = Tabla de clasificaciónes Links = Links Locked achievements = Logros bloqueados Log bad memory accesses = Registrar malos accesos a la memoría Mastered %1 = Completaste %1 -Notifications = Notifications -Recently unlocked achievements = Recently unlocked achievements -Reconnected to RetroAchievements. = Reconnected to RetroAchievements. +Notifications = Notificaciones +Recently unlocked achievements = Logros recientemente desbloqueados +Reconnected to RetroAchievements. = Reconectado a RetroAchievements. Register on www.retroachievements.org = Registrate en www.retroachievements.org -RetroAchievements are not available for this game = RetroAchievements no está disponible para este juego +RetroAchievements are not available for this game = RetroAchievements no están disponibles para este juego RetroAchievements website = Página web de RetroAchievements -Rich Presence = Rich Presence -Save state loaded without achievement data = Estado guardado sin información de los logros -Save states not available in Hardcore Mode = Los estados no están disponibles en el modo desafío +Rich Presence = Mamón con presencia 😎 +Save state loaded without achievement data = Estado de guardado sin información de los logros +Save states not available in Hardcore Mode = Los estados de salvado no están disponibles en el modo Hardcore Sound Effects = Efectos de sonido Statistics = Estadísticas -Submitted %1 for %2 = Se subió %1 para %2 +Submitted %1 for %2 = Se envió %1 para %2 Syncing achievements data... = Sincronizando información de logros... Test Mode = Modo prueba -This feature is not available in Hardcore Mode = Esta opción no está disponible en el modo desafío +This feature is not available in Hardcore Mode = Esta opción no está disponible en el modo Hardcore This game has no achievements = Este juego no tiene logros Top players = Top players Unlocked achievements = Logros desbloqueados Unofficial achievements = Logros no oficiales -Unsupported achievements = Unsupported achievements +Unsupported achievements = Logros sin soporte [Audio] Alternate speed volume = Alternar velocidad de volumen Audio backend = Motor de audio (req. reiniciar) -Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. -AudioBufferingForBluetooth = Búfer amigable con Bluetooth (enlentece) +Audio Error = Error de Audio +Audio file format not supported. Must be WAV or MP3. = Formato de audio no soportado. Debe ser WAV o MP3. +AudioBufferingForBluetooth = AudioBuffering por Bluetooth (enlentece) Auto = Automático Device = Dispositivo Disabled = Deshabilitado DSound (compatible) = DirectSound (compatible) -Enable Sound = Activar sonido +Enable Sound = Habilitar sonido Global volume = Volumen global Microphone = Micrófono -Microphone Device = Dispositivo de entrada +Microphone Device = Dispositivo de entrada de sonido (Micrófono) +Mix audio with other apps = Mix audio with other apps Mute = Silenciar -Reverb volume = Reverb volume -Use new audio devices automatically = Cambiar al nuevo dispositivo de audio +Respect silent mode = Respect silent mode +Reverb volume = Efecto de profundidad espacial de sonido añadiendo reverberación al volumen +Use new audio devices automatically = Usar/cambiar a nuevos dispositivos de audio automaticamente Use global volume = Usar volumen global WASAPI (fast) = WASAPI (rápido) [Controls] Analog Binding = Asignar análogo -Analog Settings = Config. del análogo +Analog Settings = Configuraciones del análogo Analog Style = Estilo del análogo -Analog trigger threshold = Analog trigger threshold -Auto-rotation speed = Vel. de rotación auto. del análogo +Analog trigger threshold = Umbral de disparo analógico +Auto-rotation speed = Velacidad de rotación automatíca del análogo Analog Limiter = Limitador del análogo -Analog Stick = Analog stick +Analog Stick = Stick Analogíco AnalogLimiter Tip = Cuando se presiona el botón del limitador del análogo Auto = Automática Auto-centering analog stick = Auto-centrado del análogo -Auto-hide buttons after delay = Ocultar botones después de (en segundos) +Auto-hide buttons after delay = Ocultar botones con un retraso de(en X segundos) Binds = Asignaciones -Button Binding = Vincular botones +Button Binding = Vincular botones / Asignar botones Button Opacity = Transparencia de botones Button style = Estilo de botones Calibrate Analog Stick = Calibrar análogo Calibrate = Calibrar Calibrated = Calibrado Calibration = Calibración -Circular deadzone = Circular deadzone +Circular deadzone = Circular deadzone o Zona Inactiva circular Circular stick input = Entrada del stick circular Classic = Clásico Confine Mouse = Fijar el ratón al área de la ventana/pantalla -Control Mapping = Asignar botones +Control Mapping = Asignar botones / Mapeo de botones Custom Key Setting = Configurar teclas personalizadas Customize = Personalizar Customize Touch Controls = Editar pantalla táctil D-PAD = Cruceta Deadzone radius = Radio de zona inactiva Disable D-Pad diagonals (4-way touch) = Desactivar diagonales de la cruceta -Disable diagonal input = Deshabilitar mov. diagonal +Disable diagonal input = Deshabilitar movimiento diagonál Double tap = Doble toque -Enable analog stick gesture = Enable analog stick gesture -Enable gesture control = Habilitar gestos +Enable analog stick gesture = Habilitar gestos con stick analógico +Enable gesture control = Habilitar control de gestos Enable standard shortcut keys = Habilitar teclas de atajo frames = frames Gesture = Gestos -Gesture mapping = Configurac. de gestos +Gesture mapping = Configuracion de gestos Glowing borders = Bordes brillantes HapticFeedback = Vibración háptica Hide touch analog stick background circle = Ocultar círculo del análogo -Icon = Icon -Ignore gamepads when not focused = Ignorar pads con pantalla inactiva +Icon = Icono +Ignore gamepads when not focused = Ignorar pads con pantalla inactiva (sin enfoque) Ignore Windows Key = Ignorar tecla de Windows -Invert Axes = Invertir ejes +Invert Axes = Invertir Ejes Invert Tilt along X axis = Invertir inclinación del eje X Invert Tilt along Y axis = Invertir inclinación del eje Y Keep this button pressed when right analog is pressed = Pulsa esta tecla cuando se usa el análogo derecho @@ -135,24 +137,24 @@ Low end radius = Radio inferior Mouse = Ajustes de ratón Mouse sensitivity = Sensibilidad del ratón Mouse smoothing = Suavidad del ratón -Mouse wheel button-release delay = Mouse wheel button-release delay +Mouse wheel button-release delay = Retardo de liberación del botón de la rueda del mouse MouseControl Tip = Puedes controlar el ratón en la pantalla de controles presionando el icono 'M'. -None (Disabled) = Desactivado -Off = Off +None (Disabled) = Ninguno (Desactivado) +Off = Apagado OnScreen = Controles en pantalla Portrait = Retrato Portrait Reversed = Retrato invertido PSP Action Buttons = Botones de acción PSP -Rapid fire interval = Rapid fire interval +Rapid fire interval = Intervalo de disparo rápido Raw input = Raw input -Repeat mode = Repeat mode -Reset to defaults = Restaurar config. +Repeat mode = Modo de repetición +Reset to defaults = Restaurar configiguracion (Por defecto) Screen Rotation = Rotación de pantalla Sensitivity (scale) = Sensibilidad (escala) Sensitivity = Sensibilidad Shape = Forma Show Touch Pause Menu Button = Mostrar botón del menú -Sticky D-Pad (easier sweeping movements) = Sticky D-Pad (easier sweeping movements) +Sticky D-Pad (easier sweeping movements) = Sticky D-Pad (movimientos de barrido más fáciles) Swipe = Deslizar hacia Swipe sensitivity = Sensibilidad del deslizado Swipe smoothing = Fluidez del deslizado @@ -172,10 +174,10 @@ X = X Y = Y [CwCheats] -Cheats = trucos +Cheats = Trucos Edit Cheat File = Editar archivo de trucos Import Cheats = Importar archivo cheat.db -Import from %s = Import from %s +Import from %s = Importar desde %s Refresh interval = Frecuencia de actualización [DesktopUI] @@ -188,22 +190,22 @@ Auto Max Quality = Máx. calidad automática Backend = Motor &gráfico (requiere reiniciar) Bicubic = &Bicúbico Break = Romper -Break on Load = Romper en carga +Break on Load = Romper en &carga Buy Gold = Comprar versión &Gold Control Mapping... = Asignar &botones... -Copy PSP memory base address = Copy PSP memory base &address +Copy PSP memory base address = Copiar &direccion Base de la Memoria PSP Debugging = &Depuración Deposterize = &Deposterizar Direct3D9 = &Direct3D 9 Direct3D11 = Direct3D &11 Disassembly = &Desensamblador... Discord = Discord -Display Layout && Effects = Editar pantalla y Shaders... +Display Layout && Effects = Editar pantalla y &Shaders... Display Rotation = Rotación de pantalla Dump Next Frame to Log = &Volcar siguiente cuadro a registro Emulation = &Emulación Enable Cheats = Activar &trucos -Enable Sound = Activar s&onido +Enable Sound = Activar &sonido Exit = &Salir Extract File... = E&xtraer archivo... File = &Archivo @@ -233,18 +235,18 @@ Log Console = Consola de re&gistros... Memory View... = Visor de &memoria... More Settings... = Más &opciones... Nearest = &Cercano -Recent = &Recent -Restart Graphics = Restart Graphics +Pause when not focused = &Pausar al cambiar de ventana +Recent = &Resiente +Restart Graphics = Reiniciar Graficos Skip Buffer Effects = &Saltar efectos por búfer (rápido) Off = &No Open Chat = Abrir ventana de chat Open Directory... = &Abrir carpeta... Open from MS:/PSP/GAME... = A&brir desde ms0:/PSP/GAME... Open Memory Stick = Abrir &Memory Stick -Open New Instance = Open new instance +Open New Instance = Abrir nueva instancia OpenGL = &OpenGL Pause = &Pausar -Pause When Not Focused = &Pausar al cambiar de ventana Portrait = Retrato Portrait reversed = Retrato inverso PPSSPP Forums = &Foro de PPSSPP @@ -287,11 +289,11 @@ Backspace = Borrar Block address = Bloquear dirección By Address = Por dirección Copy savestates to memstick root = Copiar estados de guardado a la ruta inicial de Memory Stick -Create frame dump = Create frame dump +Create frame dump = Crear frame dump Create/Open textures.ini file for current game = Crear/Abrir archivo textures.ini para el juego actual Current = Actual Debug overlay = Debug overlay -Debug stats = Debug stats +Debug stats = Estadisticas debug Dev Tools = Herramientas de\ndesarrollador DevMenu = Menú Depuración Disabled JIT functionality = Apagar funcionalidad de JIT @@ -307,17 +309,19 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Pruebas de volcado de frames Frame Profiler = Perfilado de frame -GPU Allocator Viewer = GPU Allocator Viewer +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs +GPU Allocator Viewer = Visor de asignador de GPU GPU Driver Test = Probar controlador GPU -GPU log profiler = GPU log profiler +GPU log profiler = Perfilador de registros de GPU GPU Profile = Perfil de GPU Jit Compare = Comparar JIT -JIT debug tools = Herr. de depuración de JIT +JIT debug tools = Herramientas de depuración de JIT Log Dropped Frame Statistics = Registrar estadísticas de frames caídos Log Level = Nivel de registro Log View = Ver el registro Logging Channels = Canales de registro -Multi-threaded rendering = Multi-threaded rendering +Multi-threaded rendering = Renderización Multi-threaded Next = Siguiente No block = No bloquear Off = Off @@ -333,6 +337,7 @@ Run CPU Tests = Ejecutando pruebas de CPU Save new textures = Guardar nuevas texturas Shader Viewer = Visor de shader Show Developer Menu = Mostrar menú de desarrollador +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Mostrar mensajes en pantalla Stats = Estadísticas System Information = Información del sistema @@ -348,7 +353,7 @@ VFPU = VFPU [Dialog] %d ms = %d ms -%d seconds = %d seconds +%d seconds = %d segundos * PSP res = * PSP res Active = Activo Back = Atrás @@ -368,6 +373,7 @@ ConfirmLoad = ¿Deseas cargar estos datos guardados? ConnectingAP = Conectando a un punto de acceso.\nEspere un momento... ConnectingPleaseWait = Conectando \nEspere un momento... ConnectionName = Nombre de conexión +Copy to clipboard = Copy to clipboard Corrupted Data = Datos dañados Delete = Borrar Delete all = Borrar todos @@ -379,20 +385,20 @@ DeleteConfirmGameConfig = ADVERTENCIA:\nLos archivos de preferencias de este jue DeleteFailed = Los archivos no se pudieron borrar. Deleting = Borrando\nPor favor espere... Disable All = Apagar todo -Disabled = Disabled -Dumps = Volcados +Disabled = Deshabilitado +Dumps = Volcados/dumpeos Edit = Editar Enable All = Activar todo -Enabled = Enabled +Enabled = Habilitado Enter = Confirmar -Failed to connect to server, check your internet connection. = Failed to connect to server, check your internet connection. -Failed to log in, check your username and password. = Failed to log in, check your username and password. +Failed to connect to server, check your internet connection. = No se pudo conectar al servidor, verifique su conexión a Internet. +Failed to log in, check your username and password. = No se pudo iniciar sesión, verifique su nombre de usuario y contraseña. Filter = Filtrar Finish = Terminar GE Frame Dumps = Volcados de cuadros GE Grid = Cuadrícula Inactive = Inactivo -Installing... = Installing... +Installing... = Instalando... InternalError = Ha ocurrido una falla interna. Links = Links Load = Abrir @@ -403,7 +409,7 @@ Log in = Log in Log out = Log out Logged in! = Logged in! Logging in... = Logging in... -More information... = More information... +More information... = Más información... Move = Mover Move Down = Move Down Move Up = Move Up @@ -416,9 +422,9 @@ OK = OK Old savedata detected = Se han detectado datos del juego antiguos. Options = Opciones Password = Password -Remove = Remove +Remove = Remover Reset = Reiniciar -Resize = Tamaño +Resize = Redimencionar Tamaño Restart = Reiniciar Retry = Reintentar Save = Guardar @@ -509,25 +515,25 @@ ZIP file detected (Require WINRAR) = Se ha detectado un archivo ZIP.\nUtiliza co [Game] Asia = Asia Calculate CRC = Calcular valor CRC -Click "Calculate CRC" to verify ISO = Click "Calculate CRC" to verify ISO +Click "Calculate CRC" to verify ISO = Click en "Calcular CRC" para verificar ISO ConfirmDelete = Borrar -CRC checksum does not match, bad or modified ISO = CRC checksum does not match, bad or modified ISO +CRC checksum does not match, bad or modified ISO = La suma de comprobación CRC no coincide, la ISO es mala o está modificada Create Game Config = Crear config. del juego Create Shortcut = Crear acceso directo Delete Game = Borrar juego Delete Game Config = Borrar config. del juego Delete Save Data = Borrar datos Europe = Europa -File size incorrect, bad or modified ISO = File size incorrect, bad or modified ISO +File size incorrect, bad or modified ISO = Tamaño de archivo incorrecto, ISO incorrecto o modificado Game = Juego -Game ID unknown - not in the ReDump database = Game ID unknown - not in the ReDump database +Game ID unknown - not in the ReDump database = ID del juego desconocida: no está en la base de datos de ReDump Game Settings = Ajustes de juego Homebrew = Homebrew Hong Kong = Hong Kong InstallData = Instalación de datos -ISO OK according to the ReDump project = ISO OK according to the ReDump project +ISO OK according to the ReDump project = La ISO está bien según el proyecto ReDump Japan = Japón -Korea = Corea +Korea = Korea MB = MB One moment please... = Espera un momento... Play = Jugar @@ -535,8 +541,8 @@ Remove From Recent = Borrar de recientes SaveData = Datos Setting Background = Configurar fondo Show In Folder = Mostrar en carpeta -Time Played: %1h %2m %3s = Time Played: %1h %2m %3s -Uncompressed = Uncompressed +Time Played: %1h %2m %3s = Tiempo Jugado: %1h %2m %3s +Uncompressed = Sin comprimir USA = América Use UI background = Usar fondo como interfaz @@ -562,7 +568,7 @@ Use UI background = Usar fondo como interfaz 9x PSP = PSP ×9 10x PSP = PSP ×10 16x = ×16 -AdrenoTools driver manager = AdrenoTools driver manager +AdrenoTools driver manager = Administrador de controladores AdrenoTools(masculino) Aggressive = Agresivo Alternative Speed = Velocidad alternativa (en %, 0 = ilimitada) Alternative Speed 2 = Velocidad alternativa 2 (en %, 0 = ilimitada) @@ -587,7 +593,7 @@ Cardboard Screen X Shift = Desplazamiento X (en % del espacio en blanco) Cardboard Screen Y Shift = Desplazamiento Y (en % del espacio en blanco) Cardboard VR Settings = Configurar Google Cardboard VR Cheats = Trucos -Copy to texture = Copy to texture +Copy to texture = Copiar a la textura Current GPU Driver = Current GPU Driver Debugging = Depuración Default GPU driver = Default GPU driver @@ -599,9 +605,9 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Apagado -Display Layout && Effects = Editar pantalla y Shaders +Display layout & effects = Editar pantalla y Shaders Display Resolution (HW scaler) = Resolución de pantalla (escalado por HW) -Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 +Driver requires Android API version %1, current is %2 = El controlador requiere la versión de API de Android %1, la actual es %2 Drivers = Drivers Enable Cardboard VR = Activar Cardboard VR FPS = FPS @@ -610,7 +616,7 @@ Frame Skipping = Salto de cuadros Frame Skipping Type = Tipo de salto de cuadros FullScreen = Pantalla completa Geometry shader culling = Geometry shader culling -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +GPUReadbackRequired = Warning: Este juego requiere que "Omitir lecturas de GPU" esté desactivado. Hack Settings = Ajustes de hacks (puede causar glitches) Hardware Tessellation = Teselado por Hardware Hardware Transform = Transformación por Hardware @@ -624,7 +630,7 @@ Install custom driver... = Install custom driver... Integer scale factor = Integer scale factor Internal Resolution = Resolución interna Lazy texture caching = Caché de texturas diferido (rápido) -Lazy texture caching Tip = Faster, but can cause text problems in a few games +Lazy texture caching Tip = Más rápido, pero puede causar problemas de texto en algunos juegos. Linear = Lineal Low = Baja LowCurves = Calidad de curvas bézier/Spline @@ -632,6 +638,7 @@ LowCurves Tip = Controla la calidad de las curvas renderizadas, pero solo se uti Lower resolution for effects (reduces artifacts) = Efectos en baja resolución\n(reduce errores gráficos por escalado) Manual Scaling = Escalado manual Medium = Media +Mirror camera image = Mirror camera image Mode = Modo Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa del dispositivo @@ -670,7 +677,7 @@ Software Rendering = Renderizado por software (experimental) Software Skinning = Skineado por software SoftwareSkinning Tip = Combina dibujados de modelo de skineado en la CPU. Acelera muchos juegos pero ralentiza otros. Speed = Velocidad -Speed Hacks = Speed Hacks (puede causar glitches) +Speed Hacks = Hacks de Velocidad (pueden causar glitches) Stereo display shader = Stereo display shader Stereo rendering = Stereo rendering Stretch = Estirar @@ -694,23 +701,26 @@ Window Size = Tamaño de ventana xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Borrar archivo ZIP +Existing data = Existing data Install = Instalar Install game from ZIP file? = ¿Instalar juego desde un archivo ZIP? +Install in folder = Install in folder Install textures from ZIP file? = ¿Instalar texturas desde un archivo ZIP? -Installation failed = Installation failed +Installation failed = Instalación fallida Installed! = ¡Instalado! Texture pack doesn't support install = El paquete de texturas no es compatible con la instalación. Zip archive corrupt = El archivo ZIP está dañado. Zip file does not contain PSP software = El archivo ZIP no contiene software de PSP. [KeyMapping] -Allow combo mappings = Allow combo mappings +Allow combo mappings = Permitir combo mappings Autoconfigure = Autoconfigurar Autoconfigure for device = Autoconfigurar para dispositivo Bind All = Ocultar todo Clear All = Borrar todo -Combo mappings are not enabled = Combo mappings are not enabled +Combo mappings are not enabled = Las asignaciones combinadas o combo mappings no están habilitadas Control modifiers = Control modifiers Default All = Restaurar Emulator controls = Emulator controls @@ -746,7 +756,7 @@ SavesAreTemporary = PPSSPP está guardando en almacenamiento temporal SavesAreTemporaryGuidance = Extraer PPSSPP en cualquier parte para guardar para siempre SavesAreTemporaryIgnore = Ignorar advertencias UnpinPath = Desanclar -UseBrowseOrLoad = Use Browse to choose a folder, or Load to choose a file. +UseBrowseOrLoad = Utilice Examinar para elegir una carpeta o Cargar para elegir un archivo. www.ppsspp.org = www.ppsspp.org [MainSettings] @@ -754,7 +764,7 @@ Audio = Audio Controls = Controles Graphics = Gráficos Networking = Juego en red -Search = Search +Search = Buscar System = Sistema Tools = Herramientas @@ -840,7 +850,7 @@ Wlan = WLAN [MemStick] Already contains PSP data = Actualmente contiene datos de PSP -Cancelled - try again = Cancelled - try again +Cancelled - try again = Cancelado - inténtalo de nuevo Checking... = Checking... Create or Choose a PSP folder = Seleccionar o crear carpeta PSP Current = Actual @@ -848,7 +858,7 @@ DataCanBeShared = Datos pueden moverse entre PPSSPP regular/Gold DataCannotBeShared = ¡Datos NO pueden moverse entre PPSSPP regular/Gold! DataWillBeLostOnUninstall = ADVERTENCIA: ¡Datos pueden borrarse al desinstalar PPSSPP! DataWillStay = Datos pueden mantenerse incluso si desinstalas PPSSPP. -Deleting... = Deleting... +Deleting... = Eliminando... Done! = ¡Hecho! EasyUSBAccess = Acceso USB fácil Failed to move some files! = ¡Falló al mover algunos archivos! @@ -877,8 +887,8 @@ AM: Data from Unknown Port = AM: Datos de puerto desconocido Auto = Auto Change Mac Address = Cambiar dirección MAC Change proAdhocServer Address = Cambiar dirección IP de\nservidor PRO Adhoc (localhost = multiples instancias) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +ChangeMacSaveConfirm = ¿Generar una nueva dirección MAC? +ChangeMacSaveWarning = Algunos juegos verifican la dirección MAC al cargar datos guardados, por lo que esto puede dañar los guardados antiguos. Chat = Chat Chat Button Position = Posición del botón de chat Chat Here = Escribe aquí @@ -907,7 +917,7 @@ Hostname = Hostname Invalid IP or hostname = IP o nombre de host no válido Minimum Timeout = Tiempo de espera mínimo (en ms, 0 = por defecto) Misc = Otros ajustes (por defecto = compatibilidad con PSP) -Network connected = Network connected +Network connected = Red conectada Network initialized = Juego en red iniciado Please change your Port Offset = Por favor cambia el offset del puerto. Port offset = Variar puerto de red (0 = compatibilidad con PSP) @@ -921,12 +931,12 @@ Quick Chat 5 = Chat rápido 5 QuickChat = Chat rápido Randomize = Randomize Send = Enviar -Send Discord Presence information = Enviar información al Discord "Rich Presence" +Send Discord Presence information = Enviar información al Discord "Rich Presence / Mamón con presencia 😎" Unable to find UPnP device = No se encuentra el dispositivo UPnP UPnP (port-forwarding) = UPnP (redirección de puertos) UPnP need to be reinitialized = La función de UPnP debe reinicializarse. UPnP use original port = Usar puerto UPnP de PSP (activado = más compatible con PSP ) -UseOriginalPort Tip = May not work for all devices or games, see wiki. +UseOriginalPort Tip = Puede que no funcione para todos los dispositivos o juegos, consulte la wiki. Validating address... = Validando dirección ... WLAN Channel = Canal WLAN You're in Offline Mode, go to lobby or online hall = Estás en modo fuera de línea, ve al lobby o sala en línea @@ -961,7 +971,7 @@ Save State = Guardar estado Settings = Ajustes generales Switch UMD = Cambiar UMD Undo last load = Deshacer carga de estado -Undo last save = Deshacer guard. de estado +Undo last save = Deshacer guardado de estado [PostShaders] (duplicated setting, previous slider will be used) = (configuraciones duplicadas, se usará la anterior) @@ -970,8 +980,8 @@ Undo last save = Deshacer guard. de estado 5xBR-lv2 = 5×BR-lv2 AAColor = AA + Color Amount = Cantidad -Animation speed (0 -> disable) = Animation speed (0 -> disable) -Aspect = Aspect +Animation speed (0 -> disable) = Velocidad de animación (0 -> desactivar) +Aspect = Aspecto Black border = Borde negro Bloom = Resplandor BloomNoBlur = Bloom (no blur) @@ -982,7 +992,7 @@ ColorCorrection = Corrección de color ColorPreservation = Color preservation Contrast = Contraste CRT = Pantalla de tubo (CRT) -FakeReflections = FakeReflections +FakeReflections = Reflexiones falsas FXAA = Antialiasing por FXAA Gamma = Gamma GreenLevel = Green level @@ -1052,8 +1062,12 @@ written = Escrito en lenguaje C++ para una mejor portabilidad y velocidad [RemoteISO] Browse Games = Buscar juegos +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Puerto del servidor local Manual Mode Client = Clíente modo manual +Not currently sharing = Not currently sharing Remote disc streaming = Streaming de disco remoto Remote Port = Puerto remoto Remote Server = Servidor remoto @@ -1067,14 +1081,14 @@ RemoteISOWinFirewall = ADVERTENCIA: cortafuegos de Windows está bloqueando el a Settings = Opciones Share Games (Server) = Compartir juegos (servidor) Share on PPSSPP startup = Compartir al empezar PSSPP -Show Remote tab on main screen = Show Remote tab on main screen +Show Remote tab on main screen = Mostrar pestaña Remota en la pantalla principal Stop Sharing = Parar Stopping.. = Deteniendo... [Reporting] Bad = Mal -FeedbackCRCCalculating = Disc CRC: Calculating... -FeedbackCRCValue = Disc CRC: %1 +FeedbackCRCCalculating = Disco CRC: Calculando... +FeedbackCRCValue = Disco CRC: %1 FeedbackDelayInfo = Tus datos se están enviando al fondo. FeedbackDesc = ¿Cómo va el juego? ¡Que lo sepa la comunidad! FeedbackDisabled = El servidor de reportes debe activarse. @@ -1100,7 +1114,7 @@ Perfect Description = Perfecta emulación para este juego. Plays = Jugable Plays Description = Perfecta jugabilidad pero puede tener glitches. ReportButton = Informar de error -Show disc CRC = Show disc CRC +Show disc CRC = Mostrar CRC del disco Speed = Velocidad Submit Feedback = Enviar comentario SuggestionConfig = Ver reportes en la web para una buena configuración. @@ -1129,7 +1143,7 @@ Size = Tamaño [Screen] Cardboard VR OFF = Cardboard VR apagado Chainfire3DWarning = ADVERTENCIA: Chainfire3D detectado, puede causar problemas. -ExtractedISOWarning = Extracted ISOs often don't work.\nPlay the ISO file directly. +ExtractedISOWarning = Los ISO extraídos a menudo no funcionan.\nReproduzca el archivo ISO directamente. Failed to load state = Error al abrir el estado. Failed to save state = Error al guardar el estado. fixed = Velocidad: fija @@ -1155,22 +1169,24 @@ State load undone = Se ha revertido la carga del estado. Untitled PSP game = Juego de PSP sin título. [Search] -Clear filter = Clear filter -Filter = Filter -Filtering settings by '%1' = Filtering settings by '%1' -Find settings = Find settings -No settings matched '%1' = No settings matched '%1' -Search term = Search term +Clear filter = Limpiar filtro +Filter = Filtrar +Filtering settings by '%1' = Configuraciones de filtracion por '%1' +Find settings = Encontrar configiguracion +No settings matched '%1' = Ninguna configuración coincide '%1' +Search term = Buscar termino [Store] Connection Error = Error de conexión Install = Instalar Installed = Ya instalado Launch Game = Lanzar juego +License = Licencia Loading... = Cargando... MB = MB Size = Tamaño Uninstall = Desinstalar +Website = Sitio web [SysInfo] %0.2f Hz = %0.2f Hz @@ -1181,12 +1197,12 @@ Uninstall = Desinstalar 3D API = API 3D ABI = Arquitectura API Version = Versión del API -Audio Information = Info de audio +Audio Information = información de audio Board = Placa Build Config = Info. de la compilación Build Configuration = Info. de la compilación Built by = Compilado por -Compressed texture formats = Compressed texture formats +Compressed texture formats = Formatos de textura comprimidos Core Context = Contexto de núcleo Cores = Núcleos CPU Extensions = Extensiones de CPU @@ -1198,7 +1214,7 @@ Debugger Present = Depurador presente Depth buffer format = Depth buffer format Device Info = Info de dispositivo Directories = Directorios -Display Color Formats = Display Color Formats +Display Color Formats = Formatos de color de Display/Pantalla Display Information = Info de tamaño DPI = DPI Driver bugs = Driver bugs @@ -1249,6 +1265,7 @@ Vulkan Features = Funciones Vulkan (broken) = (dañado) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Automático Auto Load Savestate = Carga automática de estados de guardado AVI Dump started. = Grabación iniciada. @@ -1259,10 +1276,11 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = Núcleo de CPU Dynarec/JIT (recommended) = Dynarec/JIT (recomendado) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: el estado es de otro juego. Failed to load state for load undo. Error in the file system. = Falló la reversión del estado debido a un error del archivo. Floating symbols = Símbolos flotantes -Game crashed = Game crashed +Game crashed = El juego crasheo JIT using IR = JIT using IR Language = Idioma Loaded plugin: %1 = Loaded plugin: %1 @@ -1313,8 +1331,10 @@ No animation = Sin animación Not a PSP game = No es un juego de PSP Off = No Oldest Save = Antiguos datos de guardado -Only JPG and PNG images are supported = Only JPG and PNG images are supported +Only JPG and PNG images are supported = Sólo se admiten imágenes JPG y PNG Path does not exist! = La ruta no existe. +Pause when not focused = &Pausar al cambiar de ventana +Plugins = Plugins PSP Memory Stick = Memory Stick de PSP PSP Model = Modelo de PSP PSP Settings = Ajustes de PSP @@ -1333,13 +1353,13 @@ Save path in My Documents = Guardar ruta en "C:/Users/(tu usuario)/Documents" Savestate Slot = Ranura de estado guardado Savestate slot backups = Copias de seguridad de estado guardado Screenshots as PNG = Capturas en PNG -Set Memory Stick folder = Set Memory Stick folder +Set Memory Stick folder = Establecer carpeta de Memory Stick Set UI background... = Colocar fondo de interfaz... Show ID = Mostrar ID Show Memory Stick folder = Show Memory Stick folder Show region flag = Mostrar bandera de región Simulate UMD delays = Simular retraso del UMD -Simulate UMD slow reading speed = Simulate UMD slow reading speed +Simulate UMD slow reading speed = Simular velocidad de lectura lenta de UMD Slot 1 = Ranura 1 Slot 2 = Ranura 2 Slot 3 = Ranura 3 @@ -1347,6 +1367,8 @@ Slot 4 = Ranura 4 Slot 5 = Ranura 5 Storage full = Almacenamiento lleno Sustained performance mode = Modo de rendimiento sostenido +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Formato de hora Transparent UI background = Transparent UI background @@ -1373,20 +1395,20 @@ Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ [Themes] -Dark = Dark -Default = Default +Dark = Oscuro +Default = Por defecto [UI Elements] -%1 button = %1 button +%1 button = %1 botón %1 checkbox = %1 checkbox -%1 choice = %1 choice -%1 heading = %1 heading +%1 choice = %1 elección +%1 heading = %1 Encabezado o título %1 radio button = %1 radio button -%1 text field = %1 text field -Choices: = Choices: -List: = List: -Progress: %1% = Progress: %1% -Screen representation = Screen representation +%1 text field = %1 campo de texto +Choices: = Elecciones: +List: = Lista: +Progress: %1% = Progreso: %1% +Screen representation = Representación en pantalla [Upgrade] Details = Detalles Dismiss = Cancelar @@ -1394,21 +1416,18 @@ Download = Descargar New version of PPSSPP available = Nueva versión de PPSSPP disponible [VR] -6DoF movement = 6DoF movement -Camera type = Camera type -Distance to 2D menus and scenes = Distance to 2D menus and scenes -Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only -Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing -Heads-up display detection = Heads-up display detection -Heads-up display scale = Heads-up display scale -Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action -Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) -Virtual reality = Virtual reality -VR camera = VR camera -VR controllers = VR controllers +% of native FoV = % of native FoV +6DoF movement = movimiento 6DoF +Distance to 2D menus and scenes = Distancia a menús y escenas 2D +Distance to 3D scenes when VR disabled = Distancia a escenas 3D cuando la realidad virtual está desactivada +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale +Force 72Hz update = Forzar actualización de 72 Hz +Heads-up display detection = Detección de pantalla frontal +Heads-up display scale = Escala de visualización frontal +Manual switching between flat screen and VR using SCREEN key = Cambio manual entre pantalla plana y VR usando la tecla PANTALLA +Stereoscopic vision (Experimental) = Visión estereoscópica (Experimental) +Virtual reality = Realidad virtual +VR camera = Cámara de realidad virtual +VR controllers = Controladores de realidad virtual diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index 6492fdca1c..b6baa43a7c 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -58,10 +58,10 @@ Unofficial achievements = Unofficial achievements Unsupported achievements = Unsupported achievements [Audio] -Alternate speed volume = حجم سرعت متناوب -Audio backend = ‎صدا (نیاز به ریستارت) API +Alternate speed volume = حجم سرعت جایگزین +Audio backend = رابط صدا (نیاز به راه‌اندازی دوباره دارد) Audio Error = خطای صدا -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = قالب فایل صوتی پشتیبانی نمی‌شود. باید WAV یا MP3 باشد. AudioBufferingForBluetooth = ‎بافر مناسب هندزفری بلوتوث (کند تر) Auto = ‎اتوماتیک Device = سیستم @@ -71,43 +71,45 @@ Enable Sound = ‎فعال کردن صدا Global volume = ‎بلندی صدا Microphone = میکروفن Microphone Device = میکروفن دستگاه -Mute = بی صدا +Mix audio with other apps = میکس صدا با برنامه‌های دیگر +Mute = بی‌صدا +Respect silent mode = احترام به حالت بی‌صدا Reverb volume = حجم صدا -Use new audio devices automatically = از دستگاه های صوتی جدید استفاده کنید +Use new audio devices automatically = استفاده از دستگاه‌های صوتی جدید به صورت خودکار Use global volume = استفاده از صدای عمومی WASAPI (fast) = ‎WASAPI (سریع) [Controls] -Analog Binding =ا تصال آنالوگ -Analog Limiter = ‎محدود کننده آنالوگ -Analog Settings = تنظیمات انالوگ +Analog Binding =اتصال آنالوگ +Analog Limiter = ‎محدودکننده آنالوگ +Analog Settings = تنظیمات آنالوگ Analog Stick = ‎دسته آنالوگ -Analog Style = Analog Style +Analog Style = حالت آنالوگ Analog trigger threshold = Analog trigger threshold AnalogLimiter Tip = ‎هنگامی که دکمه محدود کننده آنالوگ فشرده شود -Auto = ‎اتوماتیک +Auto = خودکار Auto-centering analog stick = ‎تنظیم مرکز آنالوگ به صورت خودکار -Auto-hide buttons after delay = ‎مخفی کردن دکمه ها به صورت خودکار (به ثانیه) -Auto-rotation speed = Auto-rotation speed -Binds = Binds -Button Binding = اتصال دکمه ها -Button Opacity = ‎شفافیت دکمه ها -Button style = ‎تم دکمه ها +Auto-hide buttons after delay = تاخیر مخفی کردن دکمه‌ها به صورت خودکار (به ثانیه) +Auto-rotation speed = سرعت چرخش خودکار +Binds = اتصالات +Button Binding = اتصال دکمه‌ها +Button Opacity = ‎شفافیت دکمه‌ها +Button style = طرح دکمه‌ها Calibrate Analog Stick = دسته آنالوگ را کالیبراسیون کنید Calibrate = ‎کالیبره کردن -Calibrated = کالیبراسیون شد +Calibrated = کالیبره شد Calibration = ‎کالیبره کردن -Circular deadzone = Circular شعاع کم پایان -Circular stick input = ورودی دایره ای -Classic = ‎کلاسیک +Circular deadzone = Circular deadzone +Circular stick input = Circular stick input +Classic = کلاسیک Confine Mouse = ‎محدود کردن موس به ناحیه درون پنجره Control Mapping = ‎تنظیمات کنترلر Custom Key Setting = شخصی سازی تنظیمات کلید -Customize = شخصی سازی -Customize Touch Controls = ‎...ویرایش چیدمان دکمه های تاچ +Customize = شخصی‌سازی +Customize Touch Controls = ‎...ویرایش چیدمان دکمه‌های تاچ D-PAD = D-Pad -Deadzone radius = ‎شعاع ناحیه غیر فعال -Disable D-Pad diagonals (4-way touch) = ‎غیر فعال کردن جهت های قطری (تاچ ۴ جهته) +Deadzone radius = ‎شعاع ناحیه غیرفعال +Disable D-Pad diagonals (4-way touch) = ‎غیرفعال کردن D-Pad قطری (لمس ۴ جهته) Disable diagonal input = Disable diagonal input Double tap = Double tap Enable analog stick gesture = Enable analog stick gesture @@ -116,54 +118,54 @@ Enable standard shortcut keys = Enable standard shortcut keys frames = frames Gesture = Gesture Gesture mapping = Gesture mapping -Glowing borders = Glowing borders +Glowing borders = حاشیه‌های درخشان HapticFeedback = ‎لرزش -Hide touch analog stick background circle = مخفی کردن لمسی لمسی انالوگ استیک زمینه -Icon = ایکون -Ignore gamepads when not focused = ‎هنگامی که پنجره فعال نباشد گیم پد کار نکند -Ignore Windows Key = ‎غیر فعال کردن کلید ویندوز +Hide touch analog stick background circle = مخفی کردن دایرهٔ پس‌زمینهٔ دکمهٔ انالوگ +Icon = نقشک +Ignore gamepads when not focused = ‎هنگامی که پنجره فعال نیست دسته کار نکند +Ignore Windows Key = ‎غیرفعال کردن کلید ویندوز Invert Axes = ‎معکوس کردن محورها -Invert Tilt along X axis = ‎X معکوس کردن شتاب سنج در جهت -Invert Tilt along Y axis = ‎Y معکوس کردن شتاب سنج در جهت +Invert Tilt along X axis = ‎X معکوس کردن شتاب‌سنج در جهت +Invert Tilt along Y axis = ‎Y معکوس کردن شتاب‌سنج در جهت Keep this button pressed when right analog is pressed = Keep this button pressed when right analog is pressed Keyboard = ‎تنظیمات کیبورد -L/R Trigger Buttons = ‎L/R دکمه های +L/R Trigger Buttons = ‎L/R دکمه‌های Landscape = ‎افقی -Landscape Auto = چشم انداز خودکار +Landscape Auto = افقی خودکار Landscape Reversed = ‎افقی وارونه Low end radius = شعاع کم پایان Mouse = ‎تنظیمات موس Mouse sensitivity = ‎حساسیت موس Mouse smoothing = ‎روان کردن حرکت موس Mouse wheel button-release delay = Mouse wheel button-release delay -MouseControl Tip = ‎در قسمت تنظیمات کنترلر میتوانید از دکمه های موس استفاده کنید M با انتخاب آیکون +MouseControl Tip = ‎در قسمت تنظیمات کنترلر میتوانید از دکمه‌های موس استفاده کنید M با انتخاب آیکون None (Disabled) = ‎هیچ کدام (غیر فعال) Off = ‎خاموش -OnScreen = ‎نمایش کنترل های لمسی +OnScreen = ‎نمایش کنترل‌های لمسی Portrait = ‎عمودی Portrait Reversed = ‎عمودی وارونه -PSP Action Buttons = ‎اکشن دکمه های +PSP Action Buttons = ‎اکشن دکمه‌های Rapid fire interval = Rapid fire interval -Raw input = ورودی راو +Raw input = ورودی خام Repeat mode = حالت تکرار -Reset to defaults = ریست کردن پیشفرض +Reset to defaults = بازنشانی به پیش‌گزیده‌ها Screen Rotation = ‎چرخش صفحه Sensitivity (scale) = Sensitivity (scale) Sensitivity = ‎حساسیت -Shape = اشیا -Show Touch Pause Menu Button = ‎نمایش دکمه توقف بازی +Shape = شکل +Show Touch Pause Menu Button = نمایش دکمهٔ توقف بازی Sticky D-Pad (easier sweeping movements) = Sticky D-Pad (easier sweeping movements) Swipe = حساسیت -Swipe sensitivity = حساسیت کش رفتن +Swipe sensitivity = حساسیت کشیدن Swipe smoothing = ضربه تند وشدید زدن -Thin borders = ‎نوار نازک +Thin borders = حاشیه نازک Tilt control setup = ‎تنظیمات شتاب سنج Tilt Input Type = ‎...استفاده از شتاب سنج به عنوان Tilt Sensitivity along X axis = ‎X حساسیت شتاب سنج در جهت Tilt Sensitivity along Y axis = ‎Y حساسیت شتاب سنج در جهت To Calibrate = دستگاه را در زاویه دلخواه نگه دارید و " ‎کالیبره کردن" را فشار دهید. Toggle mode = حالت تعویض -Touch Control Visibility = ‎نشان دادن دکمه های تاچ +Touch Control Visibility = نشان دادن دکمه‌های لمسی Use custom right analog = استفاده شخصی سازی شده انالوگ سمت راست Use Mouse Control = ‎استفاده از موس Visibility = ‎نمایش @@ -172,57 +174,57 @@ X = X Y = Y [CwCheats] -Cheats = ‎کد های تقلب -Edit Cheat File = ‎ویرایش فایل کد ها +Cheats = ‎کد‌های تقلب +Edit Cheat File = ‎ویرایش فایل کد‌ها Import Cheats = ‎cheat.db وارد کردن از -Import from %s = Import from %s -Refresh interval = بازیابی نرخ +Import from %s = وارد کردن از %s +Refresh interval = دورهٔ تازه‌سازی [DesktopUI] # If your language does not show well with the default font, you can use Font to specify a different one. # Just add it to your language's ini file and uncomment it (remove the # by Font). #Font = Trebuchet MS -About PPSSPP... = ‎...PPSSPP درباره -Auto = ‎اتوماتیک -Auto Max Quality = Auto Max &Quality -Backend = ‎Rendering &Backend (ریستارت میشود PPSSPP) +About PPSSPP... = ‎...PPSSPP دربارهٔ +Auto = خودکار +Auto Max Quality = حداکثر کیفیت خودکار +Backend = رابط گرافیکی (ریستارت میشود PPSSPP) Bicubic = &Bicubic Break = بازگشت Break on Load = بازگشت و بارگیری -Buy Gold = ‎خرید نسخه طلایی +Buy Gold = ‎خرید نسخهٔ طلایی Control Mapping... = ‎...تنظیمات کنترلر Copy PSP memory base address = Copy PSP memory base &address Debugging = ‎دیباگ Deposterize = &Deposterize -Direct3D9 = &Direct3D9 +Direct3D9 = Direct3D &9 Direct3D11 = Direct3D &11 Disassembly = ‎...جداسازی قطعات -Discord = Discord -Display Layout && Effects = ‎ویرایشگر چیدمان صفحه +Discord = دیسکورد +Display Layout && Effects = چیدمان صفحه Display Rotation = ‎چرخش صفحه -Dump Next Frame to Log = ‎تخلیه فریم بعدی به فایل لاگ +Dump Next Frame to Log = نسخه‌برداری از فریم بعدی به فایل لاگ Emulation = ‎شبیه سازی Enable Cheats = ‎(فعال سازی کدهای تقلب (نیاز به راه اندازی دوباره Enable Sound = ‎فعال سازی صدا Exit = ‎خروج Extract File... = ‎...استخراج فایل File = ‎فایل -Frame Skipping = ‎ردکردن فریم +Frame Skipping = ‎رد کردن فریم Frame Skipping Type = رد کردن فریم خودکار تایپ Fullscreen = ‎تمام صفحه Game Settings = ‎تنظیمات بازی GE Debugger... = GE Debugge&r... -GitHub = گیت هاب +GitHub = گیت‌هاب Hardware Transform = ‎&استفاده از سخت افزار در پردازش Help = ‎راهنما -Hybrid = ‎Hybrid (ترکیبی) +Hybrid = ‎Hybrid Hybrid + Bicubic = Hybrid + Bicubic Ignore Illegal Reads/Writes = ‎نادیده گرفتن نوشتن/خواندن غیر مجاز Ignore Windows Key = ‎نادیده گرفتن کلید ویندوز -Keep PPSSPP On Top = ‎روی سایر پنجره ها باشد PPSSPP +Keep PPSSPP On Top = ‎روی سایر پنجره‌ها باشد PPSSPP Landscape = ‎افقی Landscape reversed = ‎افقی وارونه -Language... = زبان..... +Language... = زبان... Linear = ‎خطی Load = ‎... بارگیری Load .sym File... = Lo&ad .sym File... @@ -233,6 +235,7 @@ Log Console = ‎کنسول لاگ Memory View... = ‎...نمایش مموری More Settings... = ‎...تنظیمات بیشتر Nearest = ‎نزدیک ترین +Pause when not focused = ‎هنگامی که پنجره فعال نباشد بازی متوقف شود Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = ‎رد کردن اثرات بافر (سریع تر) @@ -244,10 +247,9 @@ Open Memory Stick = ‎بازکردن مموری استیک Open New Instance = باز کردن نمونه جدید OpenGL = &OpenGL Pause = ‎مکث -Pause When Not Focused = ‎هنگامی که پنجره فعال نباشد بازی متوقف شود Portrait = ‎عمودی Portrait reversed = ‎عمودی وارونه -PPSSPP Forums = ‎PPSSPP انجمن های +PPSSPP Forums = ‎PPSSPP انجمن‌های Record = ‎ضبط کردن Record Audio = ‎ضبط صدا Record Display = ‎ضبط صفحه @@ -270,13 +272,13 @@ Smart 2D texture filtering = Smart 2D texture filtering Stop = ‎توقف Switch UMD = ‎تغییر دیسک Take Screenshot = ‎گرفتن اسکرین شات -Texture Filtering = ‎فیلتر تکسچر -Texture Scaling = ‎تغییر سایز تکسچر +Texture Filtering = ‎فیلتر بافت +Texture Scaling = ‎تغییر سایز بافت Use Lossless Video Codec (FFV1) = ‎(FFV1) استفاده از کدک بدون دستکاری Use output buffer for video = Use output buffer for video VSync = VS&ync -Vulkan = والکمن -Window Size = ‎سایز پنجره +Vulkan = ولکان +Window Size = اندازهٔ پنجره www.ppsspp.org = ‎بزنید www.&ppsspp.org سری به xBRZ = &xBRZ @@ -288,18 +290,18 @@ Block address = Block address By Address = By address Copy savestates to memstick root = Copy save states to Memory Stick root Create frame dump = Create frame dump -Create/Open textures.ini file for current game = ساختن یا باز کردن تکسچر ini برای بازی شما +Create/Open textures.ini file for current game = ساختن یا باز کردن بافت ini برای بازی شما Current = جاری کردن Debug overlay = Debug overlay Debug stats = Debug stats Dev Tools = ابزارهای توسعه -DevMenu = منوتوسعه دهنده -Disabled JIT functionality = قابلیت جت غیر فعال +DevMenu = منوی توسعه دهنده +Disabled JIT functionality = قابلیت JIT غیر فعال Draw Frametimes Graph = Draw frametimes graph Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot Dump next frame to log = ‎ریختن فریم بعدی به فایل لاگ Enable driver bug workarounds = Enable driver bug workarounds -Enable Logging = ‎روشن کردن لاگ باگ ها +Enable Logging = ‎روشن کردن لاگ باگ‌ها Enter address = وارد کردن ادرس Fast-forward mode = Fast-forward mode FPU = FPU @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = تست کردن جی پی یو سخت افزار GPU log profiler = GPU log profiler @@ -316,14 +320,14 @@ JIT debug tools = ابزار دیباگ کردن JIT Log Dropped Frame Statistics = ورود آمار کادر کاهش یافته است Log Level = سطح خطا Log View = مشاهده خطا -Logging Channels = رکورد خطا چنل ها +Logging Channels = رکورد خطا چنل‌ها Multi-threaded rendering = Multi-threaded rendering Next = بعدی No block = بدون بلوک Off = Off Prev = قبلی Random = شانسی -Replace textures = جایگزین کردن تکسچر +Replace textures = جایگزین کردن بافت Reset = ریست Reset limited logging = Reset limited logging RestoreDefaultSettings = ‎آیا شما می خواهید که تمامی تنظیمات به حالت اولیه خود باز گردند؟\n.تنظیمات کنترلر هیچ تغییری نمی کنند\n\n\n.تنظیمات دیگر قابل بازیابی نخواهند بود\n.پس از تایید شبیه ساز را دوباره راه اندازی کنید @@ -333,6 +337,7 @@ Run CPU Tests = ‎CPU اجرای تست Save new textures = ذخیره بافت جدید Shader Viewer = Shader viewer Show Developer Menu = نمایش منو توسعه دهنده +Show GPO LEDs = Show GPO LEDs Show on-screen messages = نمایش پیام اسکرین Stats = Stats System Information = ‎اطلاعات سیستم @@ -347,33 +352,34 @@ Vertex = Vertex VFPU = VFPU [Dialog] -%d ms = %d ms -%d seconds = %d seconds +%d ms = %d میلی‌ثانیه +%d seconds = %d ثانیه * PSP res = * PSP res Active = Active -Back = ‎برگشت -Bottom Center = Bottom center -Bottom Left = Bottom left -Bottom Right = Bottom right +Back = ‎بازگشت +Bottom Center = پایین وسط +Bottom Left = پایین چپ +Bottom Right = پایین راست Cancel = ‎انصراف Center = وسط -Center Left = Center left -Center Right = Center right -Changing this setting requires PPSSPP to restart. = تغییر دستور گرافیک گرافیک نیاز به PPSSPP برای راه اندازی مجدد دارد. راه اندازی مجدد حالا؟ +Center Left = وسط چپ +Center Right = وسط راست +Changing this setting requires PPSSPP to restart. = تغییر رابط گرافیکی نیاز به راه‌اندازی مجدد PPSSPP دارد. الان راه‌اندازی مجدد شود؟ Channel: = کانال: Choose PPSSPP save folder = انتخاب پوشه برای PPSSSPP -Confirm Overwrite = ‎آیا می خواهید که دیتا ها را بازنویسی کنید؟ -Confirm Save = ‎آیا می خواهید که این دیتا را ذخیره نمایید؟ -ConfirmLoad = ‎بارگیری این دیتا؟ +Confirm Overwrite = ‎آیا می خواهید که داده‌ها را بازنویسی کنید؟ +Confirm Save = ‎آیا می خواهید که این داده را ذخیره نمایید؟ +ConfirmLoad = ‎بارگیری این داده؟ ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = نام اتصال -Corrupted Data = داده های خراب شده +Copy to clipboard = Copy to clipboard +Corrupted Data = داده‌ها خراب شده Delete = ‎حذف Delete all = حذف همه Delete completed = ‎.حذف شد -DeleteConfirm = ‎این دیتای ذخیره شده حذف خواهد شد.\nآیا از حذف آن مطمئن هستید؟ -DeleteConfirmAll = ‎آیا شما می خواهید که همه ی\nدیتاهای ذخیره این بازی را حذف نمایید؟ +DeleteConfirm = ‎این دادهٔ ذخیره شده حذف خواهد شد.\nآیا از حذف آن مطمئن هستید؟ +DeleteConfirmAll = ‎آیا شما می خواهید که همه ی\nداده‌های ذخیره این بازی را حذف نمایید؟ DeleteConfirmGame = ‎آیا شما می خواهید این بازی را\n.از دستگاه خود حذف کنید؟ نمی توانید آن را برگردانید DeleteConfirmGameConfig = آیا واقعا میخواهید تنظیمات این بازی را حذف کنید؟ DeleteFailed = Unable to delete data. @@ -383,39 +389,39 @@ Disabled = Disabled Dumps = Dumps Edit = ویرایش Enable All = فعال کردن همه؟ -Enabled = Enabled +Enabled = فعال Enter = ‎ورود -Failed to connect to server, check your internet connection. = Failed to connect to server, check your internet connection. -Failed to log in, check your username and password. = Failed to log in, check your username and password. +Failed to connect to server, check your internet connection. = اتصال به سرور شکست خورد، اتصال اینترنت خود را بررسی کنید. +Failed to log in, check your username and password. = ورود شکست خورد، نام کاربری و رمز عبور خود را بررسی کنید. Filter = فیلتر Finish = ‎پایان GE Frame Dumps = GE Frame Dumps Grid = چهارچوب Inactive = Inactive -Installing... = Installing... +Installing... = درحال نصب... InternalError = خطای داخلی رخ داده است. -Links = Links -Load = ‎بارگیری -Load completed = ‎.بارگیری نکمیل شد -Loading = ‎درحال بارگیری\n...منتظر بمانید -LoadingFailed = Unable to load data. -Log in = Log in -Log out = Log out -Logged in! = Logged in! -Logging in... = Logging in... -More information... = More information... +Links = پیوندها +Load = بارگیری +Load completed = ‎.بارگیری تکمیل شد +Loading = درحال بارگیری\n...منتظر بمانید +LoadingFailed = بارگیری ناموفق بود. +Log in = ورود +Log out = خروج +Logged in! = وارد شدید! +Logging in... = وارد شدن... +More information... = اطلاعات بیشتر... Move = حرکت Move Down = حرکت به پایین Move Up = حرکت به بالا Network Connection = Network Connection -NEW DATA = ‎دیتای جدید +NEW DATA = ‎دادهٔ جدید No = ‎خیر None = None ObtainingIP = Obtaining IP address.\nPlease wait... OK = ‎تایید Old savedata detected = Old savedata detected Options = تنظیمات -Password = Password +Password = رمز عبور Remove = حذف Reset = بازیابی Resize = اندازه گیری @@ -428,7 +434,7 @@ SavingFailed = Unable to save data. Search = جستجو seconds, 0:off = ‎تعداد فریم، 0 : ثانیه Select = ‎انتخاب -Settings = Settings +Settings = تنظیمات Shift = ‎تغییر Skip = رد کردن Snap = Snap @@ -436,7 +442,7 @@ Space = فاصله SSID = SSID Submit = تایید کردن Supported = حمایت میشود -There is no data = ‎.دیتایی وجود ندارد +There is no data = ‎.داده‌ای وجود ندارد Toggle All = تغییر وضعیت همه Toggle List = تغییر وضعیت لیست Top Center = Top center @@ -483,17 +489,17 @@ MsgErrorSavedataNoData = Warning: no save data was found. MsgErrorSavedataNoMS = Memory Stick not inserted. No EBOOT.PBP, misidentified game = ‎.در بازی ناموجود است EBOOT.PBP فایل Not a valid disc image. = Not a valid disc image. -OpenGLDriverError = OpenGL driver error -PPSSPP doesn't support UMD Music. = PPSSPP doesn't support UMD Music. -PPSSPP doesn't support UMD Video. = PPSSPP doesn't support UMD Video. -PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP plays PSP games, not PlayStation 1 or 2 games. +OpenGLDriverError = خطای راه‌انداز OpenGL +PPSSPP doesn't support UMD Music. = PPSSPP از موسیقی UMD پشتیبانی نمی‌کند. +PPSSPP doesn't support UMD Video. = PPSSPP از ویدیوی UMD پشتیبانی نمی‌کند. +PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP بازی‌های PSP را اجرا می‌کند، نه پلی‌استیشن ۱ یا ۲. PPSSPPDoesNotSupportInternet = PPSSPP currently does not support connecting to the Internet for DLC, PSN, or game updates. -PS1 EBOOTs are not supported by PPSSPP. = ‎.پشتیبانی نمی شوند PS1 ایبوت های PPSSPP در نرم افزار -PSX game image detected. = ‎.است PSX را امتحان کنید؟ این یک بازی MODE2 آیا می خواهید بازی های +PS1 EBOOTs are not supported by PPSSPP. = ‎.پشتیبانی نمی شوند PS1 ایبوت‌های PPSSPP در نرم افزار +PSX game image detected. = ‎.است PSX را امتحان کنید؟ این یک بازی MODE2 آیا می خواهید بازی‌های RAR file detected (Require UnRAR) = ‎\n.فشرده سازی شده است RAR این فایل با فرمت\n.آن را از حالت فشرده خارج کنید UnRAR لطفا با نرم افزار RAR file detected (Require WINRAR) = ‎\n.فشرده سازی شده است RAR این فایل با فرمت\n.آن را از حالت فشرده خارج کنید WinRAR لطفا با نرم افزار -Running slow: try frameskip, sound is choppy when slow = Running slow: try frameskip, sound is choppy when slow -Running slow: Try turning off Software Rendering = Running slow: try turning off "software rendering" +Running slow: try frameskip, sound is choppy when slow = اجرای آهسته: رد کردن فریم را امتحان کنید. صدا در این حالت متلاطم است +Running slow: Try turning off Software Rendering = اجرای آهسته: خاموش کردن «رندر نرم‌افزاری» را امتحان کنید Save encryption failed. This save won't work on real PSP = Save encryption failed. This save won't work on real PSP textures.ini filenames may not be cross-platform = "textures.ini" filenames may not be cross-platform. This is a saved state, not a game. = This is a saved state, not a game. @@ -515,16 +521,16 @@ CRC checksum does not match, bad or modified ISO = CRC checksum does not match, Create Game Config = ایجاد کانفیگ بازی Create Shortcut = ‎ساخت میانبر Delete Game = حذف بازی -Delete Game Config = حذف تنظیمات دستی -Delete Save Data = حذف دیتای بازی؟ +Delete Game Config = حذف تنظیمات بازی؟ +Delete Save Data = حذف دادهٔ بازی؟ Europe = اروپا File size incorrect, bad or modified ISO = File size incorrect, bad or modified ISO Game = ‎بازی Game ID unknown - not in the ReDump database = Game ID unknown - not in the ReDump database Game Settings = ‎تنظیمات بازی Homebrew = صفحه اصلی -Hong Kong = هونگ کونگ -InstallData = تصب دیتا؟ +Hong Kong = هنگ کنگ +InstallData = تصب داده؟ ISO OK according to the ReDump project = ISO OK according to the ReDump project Japan = ژاپن Korea = کره @@ -532,7 +538,7 @@ MB = مگابایت One moment please... = One moment please... Play = ‎بازی کردن Remove From Recent = Remove from "Recent" -SaveData = ‎دیتای ذخیره +SaveData = ‎دادهٔ ذخیره Setting Background = تنظیمات پس زمینا Show In Folder = نمایش پوشه Time Played: %1h %2m %3s = Time Played: %1h %2m %3s @@ -565,42 +571,42 @@ Use UI background = استفاده به عنوان پس زمینه؟ AdrenoTools driver manager = AdrenoTools driver manager Aggressive = ‎شدید Alternative Speed = ‎سرعت ثانویه -Alternative Speed 2 = Alternative speed 2 (in %, 0 = unlimited) +Alternative Speed 2 = ‎سرعت ثانویه ۲ (in %, 0 = نامحدود) Anisotropic Filtering = ‎Anisotropic فیلتر Antialiasing (MSAA) = Antialiasing (MSAA) -Aspect Ratio = Aspect Ratio -Auto = ‎اتوماتیک -Auto (1:1) = Auto (1:1) +Aspect Ratio = نسبت ابعاد +Auto = خودکار +Auto (1:1) = خودکار (1:1) Auto FrameSkip = ‎پرش فریم خودکار Auto Max Quality = خودکار حداکثر کیفیت Auto Scaling = ‎تنظیم سایز خودکار -Backend = ‎گرافیکی API +Backend = رابط گرافیکی Balanced = ‎متعادل Bicubic = Bicubic Both = ‎سرعت + فریم بر ثانیه Buffer graphics commands (faster, input lag) = دستورات گرافیک بافر (سریعتر، تاخیر ورودی) BufferedRenderingRequired = ‎تنظیم باشد "buffered" هشدار: برای این بازی "حالت رندرینگ" باید روی -Camera = Camera -Camera Device = Camera device +Camera = دوربین +Camera Device = دستگاه دوربین Cardboard Screen Size = Screen size (in % of the viewport) Cardboard Screen X Shift = X shift (in % of the blank space) Cardboard Screen Y Shift = Y shift (in % of the blank space) Cardboard VR Settings = ‎Google Cardboard VR تنظیمات عینک -Cheats = Cheats +Cheats = کدهای تقلب Copy to texture = Copy to texture Current GPU Driver = Current GPU Driver Debugging = ‎دیباگ کردن Default GPU driver = Default GPU driver DefaultCPUClockRequired = ‎باید روی پیش فرض تنظیم باشد CPU هشدار: برای این بازی سرعت Deposterize = Deposterize -Deposterize Tip = ‎مشکل نواری شدن در تکسچر های تغییر سایز یافته را رفع می کند +Deposterize Tip = ‎مشکل نواری شدن در بافت‌های تغییر سایز یافته را رفع می کند Device = Device Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = ‎ویرایشگر چیدمان صفحه -Display Resolution (HW scaler) = ‎رزولوشن صفحه +Display layout & effects = چیدمان صفحه +Display Resolution (HW scaler) = رزولوشن صفحه Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers Enable Cardboard VR = Enable Cardboard VR @@ -611,27 +617,28 @@ Frame Skipping Type = رد کردن فریز تایپ FullScreen = ‎تمام صفحه Geometry shader culling = Geometry shader culling GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. -Hack Settings = ‎تنظیمات هک ها (میتواند باعث باگ شود) +Hack Settings = ‎تنظیمات هک‌ها (میتواند باعث باگ شود) Hardware Tessellation = Hardware tessellation -Hardware Transform = ‎استفاده از سخت افزار در پردازش +Hardware Transform = ‎استفاده از سخت‌افزار در پردازش hardware transform error - falling back to software = ‎خطا در پردازش سخت افزاری، سوییچ به نرم افزار -HardwareTessellation Tip = ‎استفاده از سخت افزار در رسم منحنی ها. کیفیت ثابت میماند +HardwareTessellation Tip = ‎استفاده از سخت افزار در رسم منحنی‌ها. کیفیت ثابت میماند High = ‎زیاد Hybrid = ‎Hybrid (ترکیبی) Hybrid + Bicubic = Hybrid + Bicubic -Ignore camera notch when centering = Ignore camera notch when centering +Ignore camera notch when centering = نادیده گرفتن حفرهٔ دوربین هنگام وسط بردن Install custom driver... = Install custom driver... Integer scale factor = Integer scale factor Internal Resolution = ‎رزولوشن داخلی -Lazy texture caching = ‎کش کردن تکسچر های ماندگار (افزایش سرعت) +Lazy texture caching = ‎کش کردن بافت‌های ماندگار (افزایش سرعت) Lazy texture caching Tip = Faster, but can cause text problems in a few games Linear = ‎خطی Low = ‎کم -LowCurves = ‎Spline/Bezier کیفیت منحنی های -LowCurves Tip = ‎فقط در تعدادی بازی استفاده میشود، کیفیت منحنی ها را کنترل میکند -Lower resolution for effects (reduces artifacts) = ‎کاهش رزولوشن افکت ها (کاهش باگ گرافیکی) +LowCurves = ‎Spline/Bezier کیفیت منحنی‌های +LowCurves Tip = ‎فقط در تعدادی بازی استفاده میشود، کیفیت منحنی‌ها را کنترل میکند +Lower resolution for effects (reduces artifacts) = ‎کاهش رزولوشن افکت‌ها (کاهش باگ گرافیکی) Manual Scaling = ‎تغییر سایز دستی Medium = ‎متوسط +Mirror camera image = Mirror camera image Mode = ‎حالت Must Restart = ‎برای اعمال این تنظیم باید برنامه را ریستارت کنید Native device resolution = ‎رزولوشن دستگاه @@ -640,10 +647,10 @@ No (default) = No (default) No buffer = بدون بافر Render all frames = Render all frames Same as Rendering resolution = ‎خودکار (مانند رزولوشن رندرینگ) -Show Battery % = Show Battery % -Show Speed = Show Speed -Skip = Skip -Skip Buffer Effects = ‎رد کردن اثر بافر (سریع تر) +Show Battery % = نمایش درصد باتری +Show Speed = نمایش سرعت +Skip = رد کردن +Skip Buffer Effects = ‎رد کردن اثر بافر (سریع‌تر) None = ‎هیچ Number of Frames = Number of frames Off = ‎خاموش @@ -658,7 +665,7 @@ Render duplicate frames to 60hz = Render duplicate frames to 60 Hz RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates Rendering Mode = ‎حالت رندرینگ Rendering Resolution = ‎رزولوشن رندرینگ -RenderingMode NonBuffered Tip = ‎سریع تر، اما در بعضی بازی ها ممکن است چیزی نشان ندهد +RenderingMode NonBuffered Tip = ‎سریع تر، اما در بعضی بازی‌ها ممکن است چیزی نشان ندهد Rotation = ‎چرخش Safe = ‎امن Screen Scaling Filter = ‎فیلتر تغییر ساز صفحه @@ -668,16 +675,16 @@ Skip GPU Readbacks = Skip GPU Readbacks Smart 2D texture filtering = Smart 2D texture filtering Software Rendering = ‎(رندر نرم افزاری (آزمایشی Software Skinning = Software skinning -SoftwareSkinning Tip = ‎در اکثر بازی ها سریع تر ،CPU دار در skin ترکیب رسم مدل های +SoftwareSkinning Tip = ‎در اکثر بازی‌ها سریع تر ،CPU دار در skin ترکیب رسم مدل‌های Speed = ‎سرعت Speed Hacks = Speed Hacks ‎(میتواند باعث باگ شود) Stereo display shader = Stereo display shader Stereo rendering = Stereo rendering Stretch = ‎کشیدن -Texture Filter = ‎فیلتر تکسچر -Texture Filtering = ‎فیلتر کردن تکسچر +Texture Filter = ‎فیلتر بافت +Texture Filtering = ‎فیلتر کردن بافت Texture replacement pack activated = Texture replacement pack activated -Texture Scaling = ‎تغییر سایز تکسچر ها +Texture Scaling = ‎تغییر سایز بافت‌ها Texture Shader = Texture shader The chosen ZIP file doesn't contain a valid driver = The chosen ZIP file doesn't contain a valid driver Turn off Hardware Tessellation - unsupported = Turn off "hardware tessellation": unsupported @@ -687,16 +694,19 @@ Up to 2 = Up to 2 Upscale Level = ‎میزان افزایش سایز Upscale Type = ‎نوع افزایش سایز UpscaleLevel Tip = ‎زیاد کار میکشد CPU از -Use all displays = ‎استفاده از همه نمایشگر ها +Use all displays = ‎استفاده از همه نمایشگر‌ها VSync = VSync Vulkan = والکمن Window Size = ‎سایز پنجره xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Delete ZIP file +Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! @@ -726,22 +736,22 @@ You can press ESC to cancel. = You can press Esc to cancel. [MainMenu] Browse = ‎...جستجو -Buy PPSSPP Gold = Buy PPSSPP Gold +Buy PPSSPP Gold = خرید PPSSPP Gold Choose folder = Choose folder Credits = ‎درباره PPSSPP Homebrew Store = PPSSPP Homebrew Store Exit = ‎خروج Game Settings = ‎تنظیمات بازی -Games = ‎بازی ها +Games = ‎بازی‌ها Give PPSSPP permission to access storage = ‎داده شود PPSSPP اجازه دسترسی به حافظه به Homebrew & Demos = ‎Homebrew و Demos بازی How to get games = ‎چگونه بازی دریافت کنیم؟ -How to get homebrew & demos = ‎دریافت کنیم؟ homebrew و demos چگونه بازی های -Load = ‎...بار گذاری -Loading... = Loading... +How to get homebrew & demos = ‎دریافت کنیم؟ homebrew و demo چگونه بازی‌های +Load = ‎بارگذاری +Loading... = بارگذاری... PinPath = Pin PPSSPP can't load games or save right now = PPSSPP can't load games or save right now -Recent = ‎آخرین بازی ها +Recent = ‎آخرین بازی‌ها SavesAreTemporary = PPSSPP is saving in temporary storage SavesAreTemporaryGuidance = Extract PPSSPP somewhere to save permanently SavesAreTemporaryIgnore = Ignore warning @@ -751,12 +761,12 @@ www.ppsspp.org = ‎وبسایت شبیه ساز [MainSettings] Audio = ‎صدا -Controls = ‎کنترل ها +Controls = ‎کنترل‌ها Graphics = ‎گرافیک Networking = ‎شبکه -Search = Search +Search = جستجو System = ‎سیستم -Tools = ‎ابزار ها +Tools = ‎ابزار‌ها [MappableControls] Alt speed 1 = Alt speed 1 @@ -839,117 +849,117 @@ Vol - = Vol - Wlan = WLAN [MemStick] -Already contains PSP data = Already contains PSP data -Cancelled - try again = Cancelled - try again -Checking... = Checking... -Create or Choose a PSP folder = Create or Choose a PSP folder -Current = Current -DataCanBeShared = Data can be shared between PPSSPP regular/Gold -DataCannotBeShared = Data CANNOT be shared between PPSSPP regular/Gold! -DataWillBeLostOnUninstall = Warning! Data will be lost when you uninstall PPSSPP! -DataWillStay = Data will stay even if you uninstall PPSSPP. -Deleting... = Deleting... -Done! = Done! -EasyUSBAccess = Easy USB access +Already contains PSP data = در حال حاضر حاوی داده های PSP است. +Cancelled - try again = لغو شد - تلاش مجدد +Checking... = بررسی... +Create or Choose a PSP folder = ایجاد یا انتخاب پوشهٔ PSP +Current = فعلی +DataCanBeShared = می‌توان داده‌ها را بین PPSSPP معمولی و طلایی به اشتراک گذاشت. +DataCannotBeShared = نمی‌توان داده‌ها را بین PPSSPP معمولی و طلایی به اشتراک گذاشت! +DataWillBeLostOnUninstall = هشدار! وقتی PPSSPP را حذف کنید داده‌هایتان از بین خواهند رفت! +DataWillStay = حتی اگر PPSSPP را حذف کنید داده‌هایتان باقی می‌ماند. +Deleting... = درحال حذف... +Done! = انجام شد! +EasyUSBAccess = دسترسی راحت به USB Failed to move some files! = Failed to move some files! -Failed to save config = Failed to save config -Free space = Free space -Manually specify PSP folder = Manually specify PSP folder -MemoryStickDescription = Choose where to keep PSP data (Memory Stick) -Move Data = Move Data -Selected PSP Data Folder = Selected PSP Data Folder -No data will be changed = No data will be changed -PPSSPP will restart after the change = PPSSPP will restart after the change -Skip for now = Skip for now -Starting move... = Starting move... -That folder doesn't work as a memstick folder. = That folder doesn't work as a memstick folder. -USBAccessThrough = USB access through Android/data/org.ppsspp.ppsspp/files -USBAccessThroughGold = USB access through Android/data/org.ppsspp.ppssppgold/files -Use App Private Data = Use App Private Data -Use PSP folder at root of storage = Use PSP folder at root of storage -Welcome to PPSSPP! = Welcome to PPSSPP! -WhatsThis = What's this? +Failed to save config = ذخیرهٔ پیکربندی شکست خورد +Free space = فضای خالی +Manually specify PSP folder = به طور دستی پوشه PSP را مشخص کنید +MemoryStickDescription = محل نگهداری داده‌های PSP را انتخاب کنید (کارت حافظه) +Move Data = انتقال داده +Selected PSP Data Folder = پوشهٔ داده‌ٔ PSP انتخاب شد. +No data will be changed = هیچ داده‌ای تغییر نخواهد کرد +PPSSPP will restart after the change = بعد از تغییر PPSSPP بازراه‌اندازی خواهد شد +Skip for now = فعلا رد شوید +Starting move... = شروع کردن جابه‌جایی... +That folder doesn't work as a memstick folder. = این پوشه به عنوان پوشهٔ memstick کار نمی کند. +USBAccessThrough = دسترسی USB از مسیر Android/data/org.ppsspp.ppsspp/files +USBAccessThroughGold = دسترسی USB از مسیر Android/data/org.ppsspp.ppssppgold/files +Use App Private Data = استفاده از داده‌های خصوصی برنامه +Use PSP folder at root of storage = استفاده از پوشهٔ PSP در ریشهٔ فضای ذخیره +Welcome to PPSSPP! = به PPSSPP خوش آمدید! +WhatsThis = این چیست؟ [Networking] -AdHoc Server = Ad hoc server -AdhocServer Failed to Bind Port = Ad hoc server failed to bind port +AdHoc Server = سرور ادهاک +AdhocServer Failed to Bind Port = اتصال به سرور ادهاک ناموفق بود AM: Data from Unknown Port = AM: Data from Unknown Port -Auto = Auto -Change Mac Address = Change MAC address -Change proAdhocServer Address = Change PRO ad hoc server IP address (localhost = multiple instances) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. -Chat = Chat -Chat Button Position = Chat button position -Chat Here = Chat here -Chat message = Chat message -Chat Screen Position = Chat screen position -Disconnected from AdhocServer = Disconnected from ad hoc server -DNS Error Resolving = DNS error resolving -Enable built-in PRO Adhoc Server = Enable built-in PRO ad hoc server -Enable network chat = Enable network chat -Enable networking = Enable networking/WLAN -Enable UPnP = Enable UPnP (need a few seconds to detect) -EnableQuickChat = Enable quick chat -Enter a new PSP nickname = Enter a new PSP nickname -Enter Quick Chat 1 = Enter quick chat 1 -Enter Quick Chat 2 = Enter quick chat 2 -Enter Quick Chat 3 = Enter quick chat 3 -Enter Quick Chat 4 = Enter quick chat 4 -Enter Quick Chat 5 = Enter quick chat 5 -Error = Error -Failed to Bind Localhost IP = Failed to bind localhost IP -Failed to Bind Port = Failed to bind port -Failed to connect to Adhoc Server = Failed to connect to ad hoc server -Forced First Connect = Forced first connect (faster connect) +Auto = خودکار +Change Mac Address = تغییر آدرس مک +Change proAdhocServer Address = ویرایش آدرس IP سرور ادهاک (localhost = چند نمونه) +ChangeMacSaveConfirm = ایجاد آدرس مک جدید؟ +ChangeMacSaveWarning = برخی بازی‌ها هنگام بارگذاری داده‌های ذخیره آدرس مک را بررسی می‌کنند. بنابراین این کار ممکن است ذخیره‌های قبلی را خراب کند. +Chat = گپ +Chat Button Position = موقعیت دکمهٔ گپ +Chat Here = اینجا گپ بزنید +Chat message = پیام‌های گپ +Chat Screen Position = موقعیت صفحهٔ گپ +Disconnected from AdhocServer = از سرور ادهاک جدا شدید. +DNS Error Resolving = خطا در دریافت DNS +Enable built-in PRO Adhoc Server = فعال کردن سرور ادهاک داخلی +Enable network chat = فعال کردن گپ درون شبکه +Enable networking = فعال کردن شبکه/WLAN +Enable UPnP = فعال کردن UPnP (شناسایی چند ثانیه طول می‌کشد) +EnableQuickChat = فعال کردن گپ سریع +Enter a new PSP nickname = یک نام مستعار PSP وارد کنید +Enter Quick Chat 1 = گپ سریع ۱ را وارد کنید +Enter Quick Chat 2 = گپ سریع ۲ را وارد کنید +Enter Quick Chat 3 = گپ سریع ۳ را وارد کنید +Enter Quick Chat 4 = گپ سریع ۴ را وارد کنید +Enter Quick Chat 5 = گپ سریع ۵ را وارد کنید +Error = خطا +Failed to Bind Localhost IP = اتصال به IP localhost شکست خورد +Failed to Bind Port = اتصال به درگاه شکست خورد +Failed to connect to Adhoc Server = اتصال به سرور ادهاک شکست خورد +Forced First Connect = اتصال اول اجباری (اتصال سریع تر) GM: Data from Unknown Port = GM: Data from Unknown Port -Hostname = Hostname -Invalid IP or hostname = Invalid IP or hostname +Hostname = نام میزبان +Invalid IP or hostname = IP یا نام میزبان نامعتبر Minimum Timeout = Minimum timeout (override in ms, 0 = default) -Misc = Miscellaneous (default = PSP compatibility) -Network connected = Network connected -Network initialized = Network initialized -Please change your Port Offset = Please change your port offset +Misc = متفرقه (پیش‌فرض = سازگاری با PSP) +Network connected = شبکه متصل شد +Network initialized = شبکه راه‌اندازی شد +Please change your Port Offset = لطفا port offset را تغییر دهید Port offset = Port offset(0 = PSP compatibility) -Open PPSSPP Multiplayer Wiki Page = Open PPSSPP Multiplayer Wiki Page -proAdhocServer Address: = Ad hoc server address: -Quick Chat 1 = Quick chat 1 -Quick Chat 2 = Quick chat 2 -Quick Chat 3 = Quick chat 3 -Quick Chat 4 = Quick chat 4 -Quick Chat 5 = Quick chat 5 -QuickChat = Quick chat -Randomize = Randomize -Send = Send -Send Discord Presence information = Send Discord "Rich Presence" information -Unable to find UPnP device = Unable to find UPnP device -UPnP (port-forwarding) = UPnP (port forwarding) -UPnP need to be reinitialized = UPnP need to be reinitialized -UPnP use original port = UPnP use original port (enabled = PSP compatibility) -UseOriginalPort Tip = May not work for all devices or games, see wiki. -Validating address... = Validating address... -WLAN Channel = WLAN channel -You're in Offline Mode, go to lobby or online hall = You're in offline mode, go to lobby or online hall +Open PPSSPP Multiplayer Wiki Page = باز کردن ویکی چندنفره PPSSPP +proAdhocServer Address: = آدرس سرور ادهاک: +Quick Chat 1 = گپ سریع ۱ +Quick Chat 2 = گپ سریع ۲ +Quick Chat 3 = گپ سریع ۳ +Quick Chat 4 = گپ سریع ۴ +Quick Chat 5 = گپ سریع ۵ +QuickChat = گپ سریع +Randomize = تصادفی‌سازی +Send = ارسال +Send Discord Presence information = ارسال اطلاعات "Rich Presence" به دیسکورد +Unable to find UPnP device = پیدا کردن دستگاه UPnP ممکن نیست +UPnP (port-forwarding) = UPnP (هدایت درگاه) +UPnP need to be reinitialized = UPnP باید بازراه‌اندازی شود +UPnP use original port = استفاده از درگاه اصلی UPnP (فعال = سازگاری با PSP) +UseOriginalPort Tip = ممکن است برای همه دستگاه ها یا بازی ها کار نکند، ویکی را ببینید. +Validating address... = اعتبارسنجی نشانی... +WLAN Channel = کانال WLAN +You're in Offline Mode, go to lobby or online hall = شما در حالت آفلاین هستید، به لابی یا سالن آنلاین بروید. [PSPSettings] -Auto = Auto -Chinese (simplified) = Chinese (simplified) -Chinese (traditional) = Chinese (traditional) -Dutch = Dutch -English = English -French = French -Game language = Game language -German = German -Italian = Italian -Japanese = Japanese -Korean = Korean -Games often don't support all languages = Games often don't support all languages -Portuguese = Portuguese -Russian = Russian -Spanish = Spanish +Auto = خودکار +Chinese (simplified) = چینی (ساده شده) +Chinese (traditional) = چینی (سنتی) +Dutch = هلندی +English = انگلیسی +French = فرانسوی +Game language = زبان بازی +German = آلمانی +Italian = ایتالیایی +Japanese = ژاپنی +Korean = کره‌ای +Games often don't support all languages = بازی‌ها اغلب از همهٔ زبان‌ها پشتیبانی نمی‌کنند +Portuguese = پرتغالی +Russian = روسی +Spanish = اسپانیایی [Pause] -Cheats = ‎کد تقلب +Cheats = ‎کدهای تقلب Continue = ‎ادامه بازی Create Game Config = ‎ساختن تنظیمات بازی Delete Game Config = ‎حذف تنظیمات بازی @@ -965,8 +975,8 @@ Undo last save = بازگشت تنظیمات سیو شده [PostShaders] (duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) -4xHqGLSL = 4xHQ پیکسل هنر -5xBR = 5xBR هنر پیکسل بالابری +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler 5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Amount @@ -989,69 +999,73 @@ GreenLevel = سطح سبز Intensity = Intensity LCDPersistence = LCD Persistence MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler -Natural = رنگ های طبیعی -NaturalA = رنگ های طبیعی <بدون بلور> +Natural = رنگ‌های طبیعی +NaturalA = رنگ‌های طبیعی <بدون بلور> Off = خاموش Power = پاور PSPColor = رنگ پی اس پی RedBlue = قرمز یا ابی شیشه ای -Saturation = اشباه -Scanlines = اشباه (CRT) -Sharpen = تیز کردن +Saturation = اشباع +Scanlines = اشباع (CRT) +Sharpen = تیزی SideBySide = Side by side (SBS) SSAA(Gauss) = نمونه برداری فوق العاده AA (گوس) Strength = Strength Tex4xBRZ = 4xBRZ TexMMPX = MMPX UpscaleBicubic = UpscaleBicubic -UpscaleSpline36 = اسپلین 36 تا اسکلهر -VideoSmoothingAA = صاف کردن ویدئو AA +UpscaleSpline36 = Spline36 Upscaler +VideoSmoothingAA = صاف‌کردن ویدئو AA Vignette = شکل [PSPCredits] -all the forum mods = all the forum mods +all the forum mods = همهٔ ناظران انجمن build server = build server -Buy Gold = ‎نسخه طلایی نرم افزار +Buy Gold = ‎نسخهٔ طلایی نرم‌افزار check = ‎.موجود Wii/GC و سری هم به شبیه ساز دلفین بزنید، بهترین شبیه ساز -CheckOutPPSSPP = Check out PPSSPP, the awesome PSP emulator: https://www.ppsspp.org/ -contributors = ‎:همکاران +CheckOutPPSSPP = PPSSPP را بررسی کنید، یک شبیه‌ساز PSP عالی: https://www.ppsspp.org/ +contributors = ‎:مشارکت‌کنندگان created = ‎PPSSPP سازنده نرم افزار -Discord = Discord +Discord = دیسکورد info1 = ‎.فقط برای اهداف آموزشی ساخته شده است PPSSPP info2 = ‎لطفا کپی رایت هر بازی را رعایت کنید info3 = ‎و مطمئن شوید که شما صاحب اصلی آن بازی هستید info4 = ‎.واقعی خود دارا هستید PSP دانلود و بر روی PSN و یا آن را از فروشگاه -info5 = ‎.یک محصول کنسول بازی و دستگاهی تجاری از سوی شرکت سونی است PSP +info5 = ‎.یک نام تجاری متعلق به شرکت سونی است PSP iOS builds = iOS builds -license = ‎GPL 2.0+ نرم افزار رایگان تحت -list = ‎...لیست بازی های سازگار ، انجمن ها و اطلاعات دیگر -PPSSPP Forums = ‎PPSSPP انجمن های -Privacy Policy = Privacy policy +license = ‎GPL 2.0+ نرم‌افزار آزاد تحت +list = ‎...لیست بازی‌های سازگار ، انجمن‌ها و اطلاعات دیگر +PPSSPP Forums = ‎PPSSPP انجمن‌های +Privacy Policy = سیاست محرمانگی Share PPSSPP = Share PPSSPP specialthanks = ‎:تشکر ویژه -specialthanksKeithGalocy = at NVIDIA (hardware, advice) -specialthanksMaxim = for his amazing Atrac3+ decoder work +specialthanksKeithGalocy = در انویدیا (سخت‌افزار, توصیه) +specialthanksMaxim = برای کار شگفت‌انگیزش Atrac3+ decoder testing = testing -this translation by = ‎Ninja coder:ترجمه شده توسط +this translation by = :ترجمه شده توسط title = ‎PSP یک شبیه ساز سریع و پرتابل از -tools = ‎:ابزار های رایگان استفاده شده +tools = ‎:ابزار‌های آزاد استفاده شده # Add translators or contributors who translated PPSSPP into your language here. # Add translators1-6 for up to 6 lines of translator credits. # Leave extra lines blank. 4 contributors per line seems to look best. -translators1 = Leopard20 -translators2 = ‎آراس رضایی -translators3 = mail: id.arasrezaei@yahoo.com -translators4 = web: www.tempworld.ir +translators1 = آراس رضایی, Ninja coder, Leopard20, محمدمهدی واحدی +translators2 = +translators3 = +translators4 = translators5 = translators6 = -Twitter @PPSSPP_emu = Twitter @PPSSPP_emu +Twitter @PPSSPP_emu = توییتر @PPSSPP_emu website = ‎:سری به وبسایت بزنید written = ‎نوشته شده است C++ برای سریع و پرتابل بودن، نرم افزار با زبان برنامه نویسی [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1113,9 +1127,9 @@ Unselected Overall Description = How well does this game emulate? View Feedback = View all feedbacks [Savedata] -Date = Date -Filename = Filename -No screenshot = No screenshot +Date = تاریخ +Filename = نام فایل +No screenshot = بدون نماگرفت None yet. Things will appear here after you save. = None yet. Things will appear here after you save. Nothing matching '%1' was found. = Nothing matching '%1' was found. Save Data = Save data @@ -1138,7 +1152,7 @@ Loaded. Game may refuse to save over different savedata. = Loaded. Game may refu Loaded. Game may refuse to save over newer savedata. = Loaded. Game may refuse to save over newer savedata. Loaded. Save in game, restart, and load for less bugs. = Loaded. Save in game, restart, and load for less bugs. LoadStateDoesntExist = ‎!خطا در بارگیری: هیچ ذخیره ی سریعی پیدا نشد -LoadStateWrongVersion = ‎!است PPSSPP خطا در بارگیری: ذخیره موجود برای ورژن های پایین تر +LoadStateWrongVersion = ‎!است PPSSPP خطا در بارگیری: ذخیره موجود برای ورژن‌های پایین تر norewind = No rewind save states available. Playing = Playing PressESC = ‎.را برای منوی سریع فشار دهید ESC دکمه @@ -1150,25 +1164,27 @@ saveNewTextures_true = Textures will now be saved to your storage. SpeedCustom2 = Speed: alternate 2 standard = ‎سرعت: استاندارد State load undone = State load undone -Untitled PSP game = Untitled PSP game +Untitled PSP game = بازی PSP بی‌نام [Search] -Clear filter = Clear filter -Filter = Filter -Filtering settings by '%1' = Filtering settings by '%1' -Find settings = Find settings -No settings matched '%1' = No settings matched '%1' -Search term = Search term +Clear filter = حذف فیلتر +Filter = فیلتر +Filtering settings by '%1' = فیلتر کردن تنظیمات با '%1' +Find settings = یافتن تنظیمات +No settings matched '%1' = هیچ تنظیماتی با '%1' مطابقت ندارد +Search term = عبارت جستجو [Store] -Connection Error = Connection error -Install = Install -Installed = Installed -Launch Game = Launch game -Loading... = Loading... +Connection Error = خطای اتصال +Install = نصب +Installed = نصب شده +Launch Game = اجرای بازی +License = License +Loading... = بارگیری... MB = MB -Size = Size -Uninstall = Uninstall +Size = حجم +Uninstall = حذف نصب +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = ‎12 ساعت 24HR = ‎24 ساعت +App switching mode = App switching mode Auto = ‎خودکار Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = ‎CPU هسته Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1269,9 +1287,9 @@ Memory Stick size = Memory Stick size Change Nickname = ‎تغییر نام ChangingMemstickPath = Save games, save states, and other data will not be copied to this folder.\n\nChange the Memory Stick folder? ChangingMemstickPathInvalid = That path couldn't be used to save Memory Stick files. -Cheats = ‎(کد های تقلب (به انجمن ها سری بزنید +Cheats = ‎(کد‌های تقلب (به انجمن‌ها سری بزنید Clear Recent = Clear "Recent" -Clear Recent Games List = ‎پاک کردن لیست آخرین بازی ها +Clear Recent Games List = ‎پاک کردن لیست آخرین بازی‌ها Clear UI background = ‎پاک کردن تصویر پس زمینه برنامه Confirmation Button = ‎دکمه تایید Date Format = ‎فرمت تاریخ @@ -1281,14 +1299,14 @@ Decrease size = Decrease size Developer Tools = ‎تنظیمات توسعه دهندگان Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = ‎شبیه سازی Enable Cheats = ‎فعال کردن کدهای تقلب -Enable Compatibility Server Reports = ‎فعال کردن گزارش های سازگاری سرور +Enable Compatibility Server Reports = ‎فعال کردن گزارش‌های سازگاری سرور Failed to load state. Error in the file system. = Failed to load state. Error in the file system. Failed to save state. Error in the file system. = Failed to save state. Error in the file system. -Fast (lag on slow storage) = ‎سریع (در حافظه های کند باعث لگ میشود) +Fast (lag on slow storage) = ‎سریع (در حافظه‌های کند باعث لگ میشود) Fast Memory = ‎(مموری سریع (ناپایدار Force real clock sync (slower, less lag) = ‎واقعی (کندتر، لگ کمتر) CPU اجبار به همگام سازی سرعت Games list settings = لیست تنظیمات بازی @@ -1313,6 +1331,8 @@ Off = ‎خاموش Oldest Save = قدیمی ترین ذخیره Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = مسیر فایل پیدا نشد +Pause when not focused = ‎هنگامی که پنجره فعال نباشد بازی متوقف شود +Plugins = Plugins PSP Memory Stick = حافظه psp PSP Model = ‎PSP مدل PSP Settings = ‎PSP تنظیمات @@ -1327,7 +1347,7 @@ Restore Default Settings = ‎به حالت اولیه PPSSPP بازگشت تن RetroAchievements = RetroAchievements Rewind Snapshot Interval = ‎تعداد فریم ذخیره شده برای به عقب رفتن (مصرف زیاد رم) Save path in installed.txt = Save path in installed.txt -Save path in My Documents = ذخیره در داکیومنت ها +Save path in My Documents = ذخیره در داکیومنت‌ها Savestate Slot = Savestate slot Savestate slot backups = پشتیبان گیری از داده Screenshots as PNG = ‎باشد PNG اسکرین شات با فرمت @@ -1345,12 +1365,14 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = ‎حاقظه پر است Sustained performance mode = حالت عملکرد پایدار +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = تم برنامه Time Format = ‎فرمت زمان -Transparent UI background = بدون پس زمینه شفاف +Transparent UI background = پس‌زمینه شفاف UI = ‎زبان برنامه -UI background animation = پس زمینه زنده -UI Sound = پس زمینه صدا +UI background animation = پس‌زمینه زنده +UI Sound = صدای رابط کاربری undo %c = backup %c USB = USB Use Lossless Video Codec (FFV1) = Use lossless video codec (FFV1) @@ -1371,7 +1393,7 @@ Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ [Themes] -Dark = Dark +Dark = تیره Default = پیشفرض [UI Elements] @@ -1386,26 +1408,23 @@ List: = List: Progress: %1% = Progress: %1% Screen representation = Screen representation [Upgrade] -Details = ریزه کاری -Dismiss = رها کردن -Download = دانلود -New version of PPSSPP available = ورژن جدیدی از ppsspp موجود است +Details = جزئیات +Dismiss = رد کردن +Download = بارگیری +New version of PPSSPP available = نسخهٔ جدیدی از PPSSPP موجود است [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 9b6871daf4..022382b574 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Vaihtoehtoisen nopeuden äänenvoimakkuus Audio backend = Äänen taustajärjestelmä (uudelleenkäynnistä) Audio Error = Äänivirhe -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-ystävällinen puskuri (hitaampi) Auto = Automaattinen Device = Laite @@ -71,7 +71,9 @@ Enable Sound = Ota äänet käyttöön Global volume = Yleinen äänenvoimakkuus Microphone = Mikrofoni Microphone Device = Mikrofonin laite +Mix audio with other apps = Mix audio with other apps Mute = Mykistä +Respect silent mode = Respect silent mode Reverb volume = Kaikuefektin voimakkuus Use new audio devices automatically = Käytä uusia äänilaitteita automaattisesti Use global volume = Käytä yleistä äänenvoimakkuutta @@ -233,6 +235,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest +Pause when not focused = &Pause When Not Focused Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Open &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP:n &foorumit @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Suorita suoritin testi Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = System information @@ -368,6 +373,7 @@ ConfirmLoad = Load this data? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Poista Delete all = Poista kaikki @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Poista taustapintojen hylkääminen Disabled = Poistettu käytöstä -Display Layout && Effects = Näyttöasettelu ja -efektit +Display layout & effects = Näyttöasettelu ja -efektit Display Resolution (HW scaler) = Näyttöresoluutio (Laitteiston skaalaaja) Driver requires Android API version %1, current is %2 = Ajurin vaatima Android API -versio on %1, nykyinen versio on %2 Drivers = Ajurit @@ -632,6 +638,7 @@ LowCurves Tip = Käytetään vain joissakin peleissä, ohjaa käyrien sileyttä Lower resolution for effects (reduces artifacts) = Alempi resoluutio efekteille (vähentää häiriöitä) Manual Scaling = Manuaalinen skaalaus Medium = Keskitaso +Mirror camera image = Mirror camera image Mode = Mode Must Restart = Sinun täytyy käynnistää PPSSPP uudelleen, jotta tämä muutos astuisi voimaan. Native device resolution = Laiteen alkuperäinen resoluutio @@ -694,9 +701,12 @@ Window Size = Ikkunan koko xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Poista ZIP-tiedosto +Existing data = Existing data Install = Asenna Install game from ZIP file? = Asenna peli ZIP-tiedostosta? +Install in folder = Install in folder Install textures from ZIP file? = Asenna tekstuureja ZIP-tiedostosta? Installation failed = Installation failed Installed! = Asenettu! @@ -1050,8 +1060,12 @@ written = Kirjoitettu C++:ssa nopeutta ja siirrettävyyttä varten [RemoteISO] Browse Games = Selaa pelejä +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Paikallisen palvelimen portti Manual Mode Client = Käsikäyttötilan asiakas +Not currently sharing = Not currently sharing Remote disc streaming = Etälevyjen suoratoisto Remote Port = Etäportti Remote Server = Etäpavelin @@ -1133,7 +1147,6 @@ Failed to save state = Tilatallennuksen tallennus epäonnistui. fixed = Nopeus: vaihtoehtoinen GLToolsWarning = WARNING: GLTools detected, may cause problems. In menu = In menu -Load savestate failed = Tilatallennuksen lataaminen epäonnistui. Loaded State = Tilatallennus ladattu. Loaded. Game may refuse to save over different savedata. = Ladattu. Peli saattaa kieltäytyä tallentamasta toiselle tallennustiedolle. Loaded. Game may refuse to save over newer savedata. = Ladattu. Peli saattaa kieltäytyä tallentamasta uudelle tallennustiedolle. @@ -1145,7 +1158,6 @@ Playing = Playing PressESC = Press ESC to open the pause menu. replaceTextures_false = Textures no longer are being replaced. replaceTextures_true = Texture replacement is enabled. -Save State Failed = Tilatallennuksen tallentaminen epäonnistui! Saved State = Tilatallennus tallennettu. saveNewTextures_false = Tekstuurien tallennus oli pois käytöstä. saveNewTextures_true = Tekstuurit tallennetaan nyt tallennustilaasi. @@ -1167,10 +1179,12 @@ Connection Error = Yhteysvirhe Install = Asenna Installed = Jo asennettu Launch Game = Käynnistä peli +License = License Loading... = Ladataan... MB = Mt Size = Koko Uninstall = Poista asennus +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1249,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (rikki) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Automaattinen Auto Load Savestate = Lataa tilatallennus automaattisesti AVI Dump started. = AVI-tallennus aloitettu. @@ -1259,6 +1274,7 @@ Color Saturation = Värisaturaatio Color Tint = Värin sävy CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Virhe: "kumoa tilatallennuksen" tila on eri pelistä Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Leijuvat symbolit @@ -1315,6 +1331,8 @@ Off = Pois Oldest Save = Vanhin tallennus Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Polkua ei ole olemassa! +Pause when not focused = Pause when not focused +Plugins = Plugins PSP Memory Stick = PSP-muistikortti PSP Model = PSP-malli PSP Settings = PSP-asetukset @@ -1347,6 +1365,8 @@ Slot 4 = Lohko 4 Slot 5 = Lohko 5 Storage full = Tallennustila täynnä Sustained performance mode = Jatkuva suorituskykytila +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Teema Time Format = Ajan muoto Transparent UI background = Läpinäkyvä käyttöliittymän tausta @@ -1394,20 +1414,17 @@ Download = Lataa New version of PPSSPP available = Uusi PPSSPP-versio saatavilla [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF-liike (kuusi vapausastetta) -Camera type = Kameratyyppi Distance to 2D menus and scenes = Etäisyys 2D-valikkoihin ja kohtauksiin Distance to 3D scenes when VR disabled = Etäisyys 3D-kohtauksiin, kun VR on poistettu käytöstä -Experts only = Vain asiantuntijoille +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Pakota 72Hz päivitys -Game camera rotation step per frame = Pelikameran kiertovaihe per kuva -Game camera uses rotation smoothing = Pelikamera käyttää kiertotason tasoitusta Heads-up display detection = Heads-up-näytön havaitseminen Heads-up display scale = Heads-up-näytön skaalaus Manual switching between flat screen and VR using SCREEN key = Manuaalinen vaihto tasaisen näytön ja VR:n välillä käyttäen SCREEN-painiketta -Map controller movements to keys = Kartuta ohjaimen liikkeet näppäimiin -Map HMD rotations on keys instead of VR camera = Kartuta HMD-kierrokset näppäimiin sen sijaan, että käytettäisiin VR-kameraa -Motion needed to generate action = Liike tarvitaan toiminnan tuottamiseen Stereoscopic vision (Experimental) = Stereoskooppinen näkemys (kokeellinen) Virtual reality = Virtuaalitodellisuus VR camera = VR-kamera diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index ace8ccda22..0b9ed664f2 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Volume en vitesse alternative Audio backend = Back-end du son (redémarrage requis) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Mémoire tampon adaptée au Bluetooth (+ lent) Auto = Automatique Device = Périphérique de sortie @@ -71,7 +71,9 @@ Enable Sound = Activer le son Global volume = Volume global Microphone = Micro Microphone Device = Micro +Mix audio with other apps = Mix audio with other apps Mute = Muet +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Basculer sur le nouveau périphérique de sortie Use global volume = Utiliser le volume global @@ -233,6 +235,7 @@ Log Console = &Journal de débogage Memory View... = &Visionneur de mémoire More Settings... = &Plus de paramètres... Nearest = Le plus &proche +Pause when not focused = Mettre en pa&use si pas au premier plan Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Pas d'effets en mémoire tampon (hack de vitesse) @@ -244,7 +247,6 @@ Open Memory Stick = Ouvrir la &Memory Stick Open New Instance = Ouvrir une nouvelle instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = Mettre en pa&use si pas au premier plan Portrait = Portrait Portrait reversed = Portrait inversé PPSSPP Forums = Visiter le &forum de PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Profileur d'image +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = Test du pilote du GPU GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Exécuter des tests CPU Save new textures = Sauvegarder les nouvelles textures Shader Viewer = Visionneur de shader Show Developer Menu = Montrer le menu développeur "MenuDev" +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Afficher les messages à l'écran Stats = Statistiques System Information = Informations système @@ -368,6 +373,7 @@ ConfirmLoad = Charger ces données ? ConnectingAP = Connexion au point d'accès\nVeuillez patienter... ConnectingPleaseWait = Connexion en cours\nVeuillez patienter... ConnectionName = Nom de la connexion +Copy to clipboard = Copy to clipboard Corrupted Data = Données corrompues Delete = Supprimer Delete all = Tout supprimer @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Désactivé -Display Layout && Effects = Éditeur d'affichage +Display layout & effects = Éditeur d'affichage Display Resolution (HW scaler) = Définition d'affichage (mise à l'échelle matérielle) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Seulement utilisé par certains jeux, contrôle le lissage des c Lower resolution for effects (reduces artifacts) = Réduire définition des effets (réduit artéfacts) Manual Scaling = Mise à l'échelle man. Medium = Moyenne +Mirror camera image = Mirror camera image Mode = Mode Must Restart = Vous devez redémarrer PPSSPP pour que cette modification prenne effet. Native device resolution = Définition native de l'appareil @@ -694,9 +701,12 @@ Window Size = Taille de la fenêtre xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Supprimer le fichier ZIP +Existing data = Existing data Install = Installer Install game from ZIP file? = Installer le jeu depuis le fichier ZIP ? +Install in folder = Install in folder Install textures from ZIP file? = Installer les textures depuis le fichier ZIP ? Installation failed = Installation failed Installed! = Installé ! @@ -734,7 +744,7 @@ Exit = Quitter Game Settings = Paramètres Games = Jeux Give PPSSPP permission to access storage = Autoriser PPSSPP à accéder au stockage -Homebrew & Demos = Homebrews && Démos +Homebrew & Demos = Homebrews & Démos How to get games = Comment obtenir des jeux ? How to get homebrew & demos = Comment obtenir des homebrews et des démos ? Load = Charger... @@ -1041,8 +1051,12 @@ written = Écrit en C++ pour la vitesse et la portabilité [RemoteISO] Browse Games = Parcourir les jeux +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Port local du serveur Manual Mode Client = Configurer le client manuellement +Not currently sharing = Not currently sharing Remote disc streaming = Streaming de disque distant Remote Port = Port distant Remote Server = Serveur distant @@ -1156,10 +1170,12 @@ Connection Error = Erreur de connexion Install = Installer Installed = Déjà installé Launch Game = Lancer le jeu +License = License Loading... = Chargement... MB = Mo Size = Taille Uninstall = Désinstaller +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1238,6 +1254,7 @@ Vulkan Features = Fonctionnalités Vulkan (broken) = (cassé) 12HR = 12h 24HR = 24h +App switching mode = App switching mode Auto = Automatique Auto Load Savestate = Charger un état automatiquement AVI Dump started. = Dump AVI démarré @@ -1248,6 +1265,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = Méthode CPU Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1304,6 +1322,8 @@ Off = Désactivé Oldest Save = Le plus ancien état Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Mettre en pa&use si pas au premier plan +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Modèle de PSP PSP Settings = Paramètres de la PSP @@ -1336,6 +1356,8 @@ Slot 4 = Emplacement 4 Slot 5 = Emplacement 5 Storage full = Espace de stockage plein. Sustained performance mode = Mode performance prolongée +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Format de l'heure Transparent UI background = Transparent UI background @@ -1383,20 +1405,17 @@ Download = Télécharger New version of PPSSPP available = Nouvelle version de PPSSPP disponible [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index ffee7a0fec..69786c57af 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Motor de audio (require reiniciar) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Automático Device = Device @@ -71,7 +71,9 @@ Enable Sound = Activar son Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = Consola de re&xistros... Memory View... = Visor de &memoria... More Settings... = Máis &opcións... Nearest = &Cercano +Pause when not focused = &Pausar ó cambiar de ventá Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Abrir &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pausar -Pause When Not Focused = &Pausar ó cambiar de ventá Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = &Foro de PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Probas de CPU Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Mostrar menú de desenrolo +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = Información do sistema @@ -368,6 +373,7 @@ ConfirmLoad = Desexas cargar estes datos gardados? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Borrar Delete all = Borrar todo @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Resolución de pantalla (escalado por hardware) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Media +Mirror camera image = Mirror camera image Mode = Modo Must Restart = Debes reiniciar PPSSPP para aplicar este cambio. Native device resolution = Resolución nativa do dispositivo @@ -694,9 +701,12 @@ Window Size = Tamaño de ventana xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Borrar arquivo ZIP +Existing data = Existing data Install = Instalar Install game from ZIP file? = Instalar xogo dende un arquivo ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = ¡Instalado! @@ -1050,8 +1060,12 @@ written = Escrito en linguaxe C++ para unha mellor portabilidade e velocidade [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Erro de conexión Install = Instalar Installed = Xa instalado Launch Game = Launch game +License = License Loading... = Cargando... MB = MB Size = Tamaño Uninstall = Desinstalar +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12 hrs 24HR = 24 hrs +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recomendado) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Ferramentas de desenrolo Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulación Enable Cheats = Activar trucos @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Pausar ó cambiar de ventá +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Modelo de PSP PSP Settings = Axustes de PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Formato de hora Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Descargar New version of PPSSPP available = Nova versión de PPSSPP dispoñible [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index e388809975..f47244b991 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Backend ήχου (Απ. Επανεκκίνηση) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Buffer φιλικό για Bluetooth (αργό) Auto = Αυτόματο Device = Συσκευή @@ -71,7 +71,9 @@ Enable Sound = Ενεργοποίηση Ήχου Global volume = Γενική ένταση Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Σίγαση +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Ενεργοποίηση νέας συσκευής ήχου Use global volume = Χρήση γενικής έντασης @@ -233,6 +235,7 @@ Log Console = Κονσόλα Καταγραφέα Memory View... = Προβολή Μνήμης... More Settings... = Περισσότερες Ρυθμίσεις... Nearest = Κοντινότερο +Pause when not focused = Παύση σε κατάσταση παρασκηνίου Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Παράκαμψη εφέ buffer (γρηγορότερο) @@ -244,7 +247,6 @@ Open Memory Stick = Άνοιγμα Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Πάυση -Pause When Not Focused = Παύση σε κατάσταση παρασκηνίου Portrait = Κατακόρυφο προσανατολισμός Portrait reversed = Αντεστραμένος κατακόρυφος προσανατολισμός PPSSPP Forums = PPSSPP &Forum @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Profiler πλαισίου +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Εκκίνηση τέστ CPU Save new textures = Αποθήκευση νέων υφών Shader Viewer = Προβολέας Shader Show Developer Menu = Εμφάνιση μενού προγραμματιστών +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Στατιστικά System Information = Πληροφορίες Συστήματος @@ -368,6 +373,7 @@ ConfirmLoad = ΦΟΡΤΩΣΗ ΔΕΔΟΜΕΝΩΝ; ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = ΔΙΑΓΡΑΦΗ Delete all = ΔΙΑΓΡΑΦΗ ΟΛΩΝ @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Απενεργοποιημένο -Display Layout && Effects = Επεξεργασία διάταξης οθόνης +Display layout & effects = Επεξεργασία διάταξης οθόνης Display Resolution (HW scaler) = Ανάλυση οθόνης (Κλιμακοτής hardware) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Αυτή η επιλογή θα βελτιώσει/μειώσε Lower resolution for effects (reduces artifacts) = Χαμηλότερη ανάλυση για εφέ (λιγότερα προβλήματα) Manual Scaling = Χειροκίνητη Κλιμάκωση Medium = Μέτρια +Mirror camera image = Mirror camera image Mode = Τρόπος Must Restart = Πρέπει να επανεκκινήσετε το PPSSPP για να εφαρμοστούν οι αλλαγές. Native device resolution = Χρήση ανάλυσης συσκευής @@ -694,9 +701,12 @@ Window Size = Μέγεθος Παραθύρου xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Διαγραφή αρχείου ZIP +Existing data = Existing data Install = Εγκατάσταση Install game from ZIP file? = Εγκατάσταση παιχνιδιού από το αρχείο ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Εγκαταστάθηκε! @@ -734,7 +744,7 @@ Exit = Έξοδος Game Settings = Ρυθμίσεις Παιχνιδιού Games = Παιχνίδια Give PPSSPP permission to access storage = Αδειοδότηση PPSSPP για πρόσβαση σε χώρο αποθήκευσης -Homebrew & Demos = Προγράμματα && Demos +Homebrew & Demos = Προγράμματα & Demos How to get games = Πώς να πάρετε τα παιχνίδια How to get homebrew & demos = Πώς να κατεβάσετε homebrew & demos Load = Φόρτωση @@ -1050,8 +1060,12 @@ written = Γραμμένο σε C++ για ταχύτητα και φορητό [RemoteISO] Browse Games = Περιήγηση παιχνιδιών +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Τοπική θύρα διακομιστή Manual Mode Client = Λειτουργία πελάτη Manual +Not currently sharing = Not currently sharing Remote disc streaming = Απομακρυσμένη ροή του δίσκου Remote Port = Απομακρυσμένη θύρα Remote Server = Απομακρυσμένος διακομιστής @@ -1165,10 +1179,12 @@ Connection Error = Σφάλμα σύνδεσης Install = Εγκατάσταση Installed = Ήδη εγκατεστημένο Launch Game = Έναρξη παιχνιδιού +License = License Loading... = Φόρτωση... MB = MB Size = Μέγεθος Uninstall = Απεγκατάσταση +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Δυνατότητες Vulkan (broken) = (εσφαλμένο) 12HR = 12ωρο 24HR = 24ωρο +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = Καταγραφή AVI ξεκίνησε. @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = Πυρήνες CPU Dynarec/JIT (recommended) = Δυναμικός Αναμεταγλωττιστής/JIT (συνιστάται) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Εργαλεία Προγραμματιστών Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Εξομοίωση Enable Cheats = Ενεργοποίηση Κωδικών @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Παλαιότερο αρχείο αποθήκευσης Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Παύση σε κατάσταση παρασκηνίου +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Μοντέλο PSP PSP Settings = Ρυθμίσεις PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Μνήμη πλήρης Sustained performance mode = Διατηρημένη λειτουργία απόδοσης +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Μορφή Ώρας Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Κατέβασμα New version of PPSSPP available = Νέα διαθέσιμη έκδοση PPSSPP [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 2335b3b7a2..223f03c1fc 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Audio backend (restart req.) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = אפשר שמע Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &התחבר לקונסולה Memory View... = הצג &זיכרון... More Settings... = &More Settings... Nearest = &Nearest +Pause when not focused = &Pause When Not Focused Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = פתח &זיכרון Open New Instance = Open new instance OpenGL = &OpenGL Pause = &השהה -Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &Forums @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = הרץ בדיקות מעבד Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = מידע על המערכת @@ -368,6 +373,7 @@ ConfirmLoad = ?ולא םינותנ ןועטל הצור ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = קחמ Delete all = Delete all @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = מצב Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution @@ -694,9 +701,12 @@ Window Size = Window size xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Delete ZIP file +Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! @@ -1050,8 +1060,12 @@ written = למהירות וניידות C++ נכתב ב [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Connection error Install = Install Installed = Installed Launch Game = Launch game +License = License Loading... = Loading... MB = MB Size = Size Uninstall = Uninstall +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = PM/FM 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = כלי פיתוח Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = סימולציה Enable Cheats = אפשר צ'יטים @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pause when not focused +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = הגדרות PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = תבנית זמן Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Download New version of PPSSPP available = New version of PPSSPP available [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index dd15a264f3..771d8a2d20 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Audio backend (restart req.) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = עמש רשפא Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest +Pause when not focused = &Pause When Not Focused Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Open &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &Forums @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = דבעמ תוקידב ץרה Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = תכרעמה לע עדימ @@ -368,6 +373,7 @@ ConfirmLoad = ?ולא םינותנ ןועטל הצור ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = קחמ Delete all = Delete all @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = בצמ Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution @@ -694,9 +701,12 @@ Window Size = Window size xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Delete ZIP file +Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! @@ -1050,8 +1060,12 @@ written = ב בתכנ ++C תודיינו תוריהמל [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Connection error Install = Install Installed = Installed Launch Game = Launch game +License = License Loading... = Loading... MB = MB Size = Size Uninstall = Uninstall +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = PM/FM 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = חותיפ ילכ Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = היצלומיס Enable Cheats = םיטי'צ רשפא @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pause when not focused +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = PSP תורדגה @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = ןמז תינבת Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Download New version of PPSSPP available = New version of PPSSPP available [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 704196ffb7..d899733a4e 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Naizmjenična brzina zvuka Audio backend = Poslužitelj zvuka (ponovo pokrenuti) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-prijateljski poliranje (sporije) Auto = Automatski Device = Uređaj @@ -71,7 +71,9 @@ Enable Sound = Uključi zvuk Global volume = Opća glasnoća Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Priguši +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Promijeni trenutni uređaj Use global volume = Koristi opću glasnoću @@ -233,6 +235,7 @@ Log Console = &Konzola log-a Memory View... = Pregled &memorije... More Settings... = &Više postavki... Nearest = &Najbliže +Pause when not focused = &Pauziraj kad nije fokusirano Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Preskoči bufferane efekte @@ -244,7 +247,6 @@ Open Memory Stick = Otvori &Memorijsku Karticu Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pauza -Pause When Not Focused = &Pauziraj kad nije fokusirano Portrait = Portret Portrait reversed = Obrnuti portret PPSSPP Forums = PPSSPP &forumi @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = Testiranje GPU drivera GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Pokreni CPU testove Save new textures = Spremi nove teksture Shader Viewer = Pregled sjenčanja Show Developer Menu = Prikaži developer izbornik +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = System informacija @@ -368,6 +373,7 @@ ConfirmLoad = Učitaj ovu datu? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Izbriši Delete all = Izbriši sve @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Isključeno -Display Layout && Effects = Prikaz layout uređivača +Display layout & effects = Prikaz layout uređivača Display Resolution (HW scaler) = Prikaz rezolucije (HW mjeritelj) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Jedino korišteno od strane nekoliko igara, kontrolira uglađeno Lower resolution for effects (reduces artifacts) = Snizi rezoluciju za efekte (smanjuje artefakte) Manual Scaling = Ručno mjerenje Medium = Srednje +Mirror camera image = Mirror camera image Mode = Način Must Restart = Morate ponovno pokrenuti PPSSPP da bi se efekat primjenio. Native device resolution = Urođena rezolucija uređaja @@ -694,9 +701,12 @@ Window Size = Veličina prozora xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Izbriši ZIP datoteku +Existing data = Existing data Install = Instaliraj Install game from ZIP file? = Instaliraj igru iz ZIP datoteke? +Install in folder = Install in folder Install textures from ZIP file? = Instaliraj teksture iz ZIP datoteke? Installation failed = Installation failed Installed! = Instalirano! @@ -734,9 +744,9 @@ Exit = Izlaz Game Settings = Postavke Games = Igre Give PPSSPP permission to access storage = Dopusti PPSSPP dozvolu za pristup datotekama -Homebrew & Demos = Homebrew && Demos +Homebrew & Demos = Homebrew & Demos How to get games = Kako mogu nabaviti igre? -How to get homebrew & demos = Kako mogu nabaviti homebrew && demos? +How to get homebrew & demos = Kako mogu nabaviti Homebrew & Demos? Load = Učitaj... Loading... = Loading... PinPath = Prikvači mapu @@ -1050,8 +1060,12 @@ written = Napisan u C++ za brzinu i za pokretnost [RemoteISO] Browse Games = Pretraži igre +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Ručno konfiguriraj klijent +Not currently sharing = Not currently sharing Remote disc streaming = Daljinsko dijeljenje diska Remote Port = porta Daljinskog Remote Server = Daljinski server @@ -1165,10 +1179,12 @@ Connection Error = Pogreška u spajanju Install = Instaliraj Installed = Već instalirano Launch Game = Pokreni igru +License = License Loading... = Učitavanje... MB = MB Size = Veličina Uninstall = Deinstaliraj +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan svojstva (broken) = (broken) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto učitaj savestate AVI Dump started. = AVI dump započelo @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU jezgra Dynarec/JIT (recommended) = Dynarec/JIT (preporučeno) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1313,6 +1331,8 @@ Off = Isključeno Oldest Save = Najstariji save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Pauziraj kad nije fokusirano +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = PSP opcije @@ -1345,6 +1365,8 @@ Slot 4 = Mjesto 4 Slot 5 = Mjesto 5 Storage full = Prostor pun Sustained performance mode = Način održive performanse +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Format vremena Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Instaliraj New version of PPSSPP available = Nova verzija PPSSPP-a je dostupna [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 3e78a74914..f9573aeee5 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternatív sebesség hangereje Audio backend = Audió backend (újraindítás szükséges) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-barát buffer (lassabb) Auto = Auto Device = Eszköz @@ -71,7 +71,9 @@ Enable Sound = Hang engedélyezése Global volume = Globális hangerő Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Némítás +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Új eszköz észlelésekor átváltás rá Use global volume = Globális hangerő használata @@ -233,6 +235,7 @@ Log Console = &Napló ablak Memory View... = Memória &nézet… More Settings... = &Egyéb beállítások… Nearest = Leg&közelebbi +Pause when not focused = &Szüneteltetés, ha nincs fókuszban Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = Bufferelt effektek kihagyá&sa (nem bufferelt, gyorsabb) @@ -244,7 +247,6 @@ Open Memory Stick = Memory &Stick megnyitása Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Szünet -Pause When Not Focused = &Szüneteltetés, ha nincs fókuszban Portrait = Álló Portrait reversed = Fordított álló PPSSPP Forums = PPSSPP &fórum @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Képkocka profilozó +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver teszt GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = CPU tesztek futtatása Save new textures = Új textúrák mentése Shader Viewer = Shader megjelenítő Show Developer Menu = Fejlesztői menü megjelenítése +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Statisztikák System Information = Rendszer információ @@ -368,6 +373,7 @@ ConfirmLoad = Betöltöd ezt a mentést? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Töröl Delete all = Mindet töröl @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Letiltva -Display Layout && Effects = Elrendezés szerkesztő +Display layout & effects = Elrendezés szerkesztő Display Resolution (HW scaler) = Megjelenítési felbontás (HW skálázó) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Csak néhány játék használja, a görbék simaságát szabál Lower resolution for effects (reduces artifacts) = Effektek alacsonyabb felbontásssal (gyengíti a látványt) Manual Scaling = Kézi skálázás Medium = Közepes +Mirror camera image = Mirror camera image Mode = Renderelési üzemmód Must Restart = A beállítások érvénybeléptetéséhez újra kell indítani a PPSSPP-t. Native device resolution = Natív készülék felbontás @@ -694,9 +701,12 @@ Window Size = Ablak méret xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = ZIP fájl törlése +Existing data = Existing data Install = Telepítés Install game from ZIP file? = Játék telepítése ZIP fájlból? +Install in folder = Install in folder Install textures from ZIP file? = Textúrák telepítése ZIP fájlból? Installation failed = Installation failed Installed! = Telepítve! @@ -1050,8 +1060,12 @@ written = C++ban írva a sebességért és portolhatóságért [RemoteISO] Browse Games = Játékok tallózása +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Lokális szerver port Manual Mode Client = Kliens kézi konfigurálása +Not currently sharing = Not currently sharing Remote disc streaming = Távoli lemez streamelése Remote Port = Távoli port Remote Server = Távoli szerver @@ -1165,10 +1179,12 @@ Connection Error = Kapcsolódási hiba Install = Telepítés Installed = Már telepítve Launch Game = Játék indítása +License = License Loading... = Töltés... MB = MB Size = Méret Uninstall = Eltávolítás +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan funkciók (broken) = (nem működik) 12HR = 12ó 24HR = 24ó +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Állapotmentés automatikus betöltése AVI Dump started. = AVI írás indítva @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU mag Dynarec/JIT (recommended) = Dynarec/JIT (ajánlott) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1313,6 +1331,8 @@ Off = Ki Oldest Save = Legrégebbi mentés Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Szüneteltetés, ha nincs fókuszban +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP modell PSP Settings = PSP beállítások @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Tárhely megtelt Sustained performance mode = Fentartott teljesítmény mód +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Idő formátuma Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Letöltés New version of PPSSPP available = Elérhető a PPSSPP egy újabb verziója [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 4de64678f7..257a7da6fb 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Kecepatan volume alternatif Audio backend = Penyangga audio (perlu mulai ulang) Audio Error = Kesalahan audio -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Penyangga bluetooth (lambat) Auto = Otomatis Device = Perangkat @@ -71,7 +71,9 @@ Enable Sound = Aktifkan suara Global volume = Volume global Microphone = Mikrofon Microphone Device = Mikrofon perangkat +Mix audio with other apps = Mix audio with other apps Mute = Tidak bersuara +Respect silent mode = Respect silent mode Reverb volume = Volume gema Use new audio devices automatically = Gunakan perangkat audio baru secara otomatis Use global volume = Gunakan volume global @@ -233,6 +235,7 @@ Log Console = Konso&l pencatat Memory View... = Tampilan memori... More Settings... = Pengaturan lainnya... Nearest = Terdekat +Pause when not focused = Jeda ketika tidak fokus Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = Lewati efek penyangga (tak-tersangga, lebih cepat) @@ -244,7 +247,6 @@ Open Memory Stick = Buka &Memory Stick Open New Instance = Buka perumpamaan baru OpenGL = &OpenGL Pause = Jeda -Pause When Not Focused = Jeda ketika tidak fokus Portrait = Tegak Portrait reversed = Tegak terbalik PPSSPP Forums = &Forum PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Tes pembuangan laju bingkai Frame Profiler = Profil laju bingkai +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = Tes driver GPU GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Jalankan pengujian CPU Save new textures = Simpan tekstur baru Shader Viewer = Penampil shader Show Developer Menu = Tampilkan menu pengembang +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Tampilkan obrolan di layar Stats = Statistik System Information = Informasi sistem @@ -368,6 +373,7 @@ ConfirmLoad = Muat data ini? ConnectingAP = Menghubungkan ke titik akses.\nHarap tunggu... ConnectingPleaseWait = Menghubungkan.\nHarap tunggu... ConnectionName = Nama koneksi +Copy to clipboard = Copy to clipboard Corrupted Data = Data rusak Delete = Hapus Delete all = Hapus semua @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Nonaktif -Display Layout && Effects = Penyesuaian tata letak tampilan +Display layout & effects = Penyesuaian tata letak tampilan Display Resolution (HW scaler) = Resolusi tampilan (penskala HW) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Hanya digunakan oleh beberapa permainan, mengontrol kualitas kur Lower resolution for effects (reduces artifacts) = Resolusi efek lebih rendah (mengurangi artefak) Manual Scaling = Penskala manual Medium = Menengah +Mirror camera image = Mirror camera image Mode = Mode Must Restart = Anda harus memulai ulang PPSSPP agar perubahan ini berfungsi. Native device resolution = Resolusi asli @@ -694,9 +701,12 @@ Window Size = Ukuran Window xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Hapus berkas ZIP +Existing data = Existing data Install = Pasang Install game from ZIP file? = Pasang permainan dari berkas ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Pasang tekstur dari file ZIP? Installation failed = Installation failed Installed! = Terpasang! @@ -734,9 +744,9 @@ Exit = Keluar Game Settings = Pengaturan Games = Permainan Give PPSSPP permission to access storage = Berikan PPSSPP izin untuk mengakses penyimpanan -Homebrew & Demos = Paket Permainan && Demos +Homebrew & Demos = Paket Permainan & Demos How to get games = Bagaimana caranya mendapatkan permainan? -How to get homebrew & demos = Bagaimana caranya mendapatkan Paket Permainan && Demos? +How to get homebrew & demos = Bagaimana caranya mendapatkan Paket Permainan & Demos? Load = Memuat Loading... = Memuat... PinPath = Sematkan @@ -1050,8 +1060,12 @@ written = Ditulis dalam bahasa C++ demi kecepatan dan portabilitas [RemoteISO] Browse Games = Telusuri permainan +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Port pelayan lokal Manual Mode Client = Mode klien manual +Not currently sharing = Not currently sharing Remote disc streaming = Pengendali disk streaming jarak jauh Remote Port = Pengendali port jarak jauh Remote Server = Pengandali server jarak jauh @@ -1165,10 +1179,12 @@ Connection Error = Kesalahan pada koneksi Install = Pasang Installed = Sudah terpasang Launch Game = Jalankan permainan +License = License Loading... = Memuat... MB = MB Size = Ukuran Uninstall = Mencopot pemasangan +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Fitur-fitur Vulkan (broken) = (rusak) 12HR = 12 jam 24HR = 24 jam +App switching mode = App switching mode Auto = Otomatis Auto Load Savestate = Muat otomatis simpanan status AVI Dump started. = Pembuangan AVI dimulai. @@ -1257,6 +1274,7 @@ Color Saturation = Saturasi warna Color Tint = Pewarnaan CPU Core = Inti CPU Dynarec/JIT (recommended) = Dynarec/JIT (direkomendasikan) +Enable plugins = Enable plugins Error: load undo state is from a different game = Kesalahan: memuat status yang berasal dari permainan yang berbeda Failed to load state for load undo. Error in the file system. = Gagal memuat status untuk membatalkan pemuatan. Kesalahan dalam sistem berkas. Floating symbols = Simbol mengambang @@ -1313,6 +1331,8 @@ Off = Mati Oldest Save = Simpanan lawas Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Tidak ada jalur! +Pause when not focused = Jeda ketika tidak fokus +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Model PSP PSP Settings = Pengaturan PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Penyimpanan penuh Sustained performance mode = Mode kinerja berkelanjutan +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Tema Time Format = Format waktu Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Unduh New version of PPSSPP available = Versi baru PPSSPP tersedia [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 6f49e7b32f..00ccce1fc7 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -61,7 +61,7 @@ Unofficial achievements = Obiettivi non ufficiali Alternate speed volume = Volume a velocità alternativa Audio backend = Renderer Audio (riavvio necessario) Audio Error = Errore Audio -Audio file format not supported. Must be WAV. = Formato audio non supportato. Deve essere WAV. +Audio file format not supported. Must be WAV or MP3. = Formato audio non supportato. Deve essere WAV o MP3. AudioBufferingForBluetooth = Buffer compatibile con Bluetooth (più lento) Auto = Automatico Device = Dispositivo @@ -71,7 +71,9 @@ Enable Sound = Attiva il Sonoro Global volume = Volume Globale Microphone = Microfono Microphone Device = Periferica Microfono +Mix audio with other apps = Mix audio with other apps Mute = Muto +Respect silent mode = Respect silent mode Reverb volume = Riverb. volume Use new audio devices automatically = Usa nuovi dispositivi audio automaticamente. Use global volume = Usa volume globale @@ -233,6 +235,7 @@ Log Console = Log Console Memory View... = Visualizzazione Memoria... More Settings... = Altre Impostazioni... Nearest = Pixel perfect +Pause when not focused = Pausa quando non attivo Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = Salta effetti di buffer (niente buffer, più velocità) @@ -244,7 +247,6 @@ Open Memory Stick = Apri Memory Stick Open New Instance = Apri nuova istanza OpenGL = OpenGL Pause = Pausa -Pause When Not Focused = Pausa quando non attivo Portrait = Ritratto Portrait reversed = Ritratto invertito PPSSPP Forums = Forum PPSSPP @@ -307,6 +309,8 @@ Fragment = Frammento Frame timing = Frame timing Framedump tests = Test del framedump Frame Profiler = Profilatore di Frame +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = Visualizzatore dell'Allocatore GPU GPU Driver Test = Test dei driver GPU GPU log profiler = Profilatore dei registri GPU @@ -333,6 +337,7 @@ Run CPU Tests = Fai Test CPU Save new textures = Salva nuove texture Shader Viewer = Visualizzatore shader Show Developer Menu = Mostra Menu Sviluppatore +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Mostra i messaggi on-screen Stats = Statistiche System Information = Informazioni Sistema @@ -368,6 +373,7 @@ ConfirmLoad = Caricare questi dati? ConnectingAP = Connessione in corso dal punto di accesso.\nAttendere, prego... ConnectingPleaseWait = Connessione in corso.\nAttendere, prego... ConnectionName = Nome connessione +Copy to clipboard = Copy to clipboard Corrupted Data = Dati corrotti Delete = Elimina Delete all = Elimina tutto @@ -600,7 +606,7 @@ Direct3D 11 = Direct3D 11 #Disable slower effects (speedup) = Disattiva gli effetti più lenti (veloce) Disable culling = Disable culling Disabled = Disabilitato -Display Layout && Effects = Editor Display +Display layout & effects = Editor Display Display Resolution (HW scaler) = Risoluzione Display (scaler HW) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -633,6 +639,7 @@ LowCurves Tip = Usato solo in alcuni giochi, controlla la fluidità delle curve Lower resolution for effects (reduces artifacts) = Bassa risoluzione degli effetti (riduce gli artefatti) Manual Scaling = Scaling manuale Medium = Media +Mirror camera image = Mirror camera image Mode = Modalità Must Restart = Sarà necessario riavviare PPSSPP per attivare le modifiche. Native device resolution = Risoluzione nativa della periferica @@ -695,9 +702,12 @@ Window Size = Dimensioni Finestra xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Elimina file ZIP +Existing data = Existing data Install = Installa Install game from ZIP file? = Installare il gioco dal file ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Installare le texture dal file ZIP? Installation failed = Installation failed Installed! = Installato! @@ -734,7 +744,7 @@ Exit = Esci Game Settings = Impostazioni Games = Giochi Give PPSSPP permission to access storage = Da' a PPSSPP il permesso di accedere alla memoria di massa -Homebrew & Demos = Homebrew && Demo +Homebrew & Demos = Homebrew & Demo How to get games = Come ottenere giochi? How to get homebrew & demos = Come ottenere homebrew o demo? Load = Carica... @@ -1051,8 +1061,12 @@ WhatsThis = Cos'è questo? [RemoteISO] Browse Games = Cerca i giochi +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Porta locale del server Manual Mode Client = Client in modalità manuale +Not currently sharing = Not currently sharing Remote disc streaming = Streaming del disco remoto Remote Port = Porta in remoto Remote Server = Server in remoto @@ -1166,10 +1180,12 @@ Connection Error = Errore di connessione Install = Installa Installed = Già installato Launch Game = Avvia il gioco +License = License Loading... = Caricamento... MB = MB Size = Dimensioni Uninstall = Disinstalla +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1248,6 +1264,7 @@ Vulkan Features = Funzionalità Vulkan (broken) = (rotto) 12HR = 12 ore 24HR = 24 ore +App switching mode = App switching mode Auto = Automatico Auto Load Savestate = Carica automaticam. uno stato AVI Dump started. = Dump AVI avviato @@ -1258,6 +1275,7 @@ Color Saturation = Saturazione colore Color Tint = Tonalità colore CPU Core = Core CPU Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Errore: lo stato annullato proviene da un gioco diverso. Failed to load state for load undo. Error in the file system. = Impossibile caricare lo stato da un caricamento annullato. Errore nel file system. Floating symbols = Simboli fluttuanti @@ -1282,7 +1300,7 @@ Decrease size = Riduci dimensioni Developer Tools = Strumenti Sviluppatore Display Extra Info = Mostra altre informazioni Display Games on a grid = Mostra "Giochi" a icona -Display Homebrew on a grid = Mostra "Homebrew && Demo" a icona +Display Homebrew on a grid = Mostra "Homebrew & Demo" a icona Display Recent on a grid = Mostra "Recenti" a icona Emulation = Emulazione Enable Cheats = Attiva i Trucchi @@ -1296,12 +1314,16 @@ Moving background = Spostamento dello sfondo No animation = Nessuna animazione Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Il percorso non esiste! +Pause when not focused = Pausa quando non attivo +Plugins = Plugins PSP Memory Stick = Memory Stick PSP Recent games = Giochi recenti Recording = Recording RetroAchievements = RetroAchievements Set Memory Stick folder = Imposta la cartella della Memory Stick Show Memory Stick folder = Mostra cartella Memory Stick +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Tema Transparent UI background = Sfondo trasparente dell'interfaccia UI = Interfaccia @@ -1394,20 +1416,17 @@ Download = Scarica New version of PPSSPP available = È disponibile una nuova versione di PPSSPP [VR] +% of native FoV = % del FoV nativo 6DoF movement = Movimento 6DoF -Camera type = Tipo di telecamera Distance to 2D menus and scenes = Distanza dai menu e dalle scene 2D Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Solo per esperti +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Scalatura "Field of view" Force 72Hz update = Forza aggiornamento a 72Hz -Game camera rotation step per frame = Passo di rotazione della telecamera di gioco per fotogramma -Game camera uses rotation smoothing = La telecamera di gioco utilizza la rotazione fluida Heads-up display detection = Rilevamento del display heads-up Heads-up display scale = Scalatura con display heads-up Manual switching between flat screen and VR using SCREEN key = Commutazione manuale tra schermo piatto e VR con il tasto SCREEN -Map controller movements to keys = Mappare i movimenti del controller sui tasti -Map HMD rotations on keys instead of VR camera = Mappare le rotazioni dell'HMD sui tasti invece che sulla telecamera VR -Motion needed to generate action = Movimento necessario per generare un'azione Stereoscopic vision (Experimental) = Visione stereoscopica (Sperimentale) Virtual reality = Virtual reality VR camera = Telecamera VR diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 8841fc1dac..0cef653fc7 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -1,23 +1,23 @@ [Achievements] +%1 achievements, %2 points = %1つの実績、 %2ポイント %1: Attempt failed = %1: Attempt failed %1: Attempt started = %1: Attempt started -%1 achievements, %2 points = %1つの実績、 %2ポイント Account = アカウント Achievement progress = 実績進捗 -Achievement sound volume = Achievement sound volume +Achievement sound volume = Achievement音量 Achievement unlocked = 実績解除 Achievements = 実績 Achievements are disabled = 実績は無効化されています Achievements enabled = 実績を有効化 Achievements with active challenges = Achievements with active challenges -Allow Save State in Hardcore Mode (but not Load State) = Allow Save State in Hardcore Mode (but not Load State) +Allow Save State in Hardcore Mode (but not Load State) = ハードコアモードでセーブステートを許可する(ステートロードはしません) Almost completed achievements = もう少しで達成する実績 -Around me = 自分の近く +Around me = 自分付近 Can't log in to RetroAchievements right now = 現在RetroAchievementsにログインできません。 Challenge indicator = チャレンジ目標 Contacting RetroAchievements server... = RetroAchievementsのサーバーに接続しています... Customize = カスタマイズ -Earned = %2個中%1つの実績を解除し、%4ポイント中%3ポイントを得ています +Earned = %2個中%1個の実績を解除し、%4ポイント中%3ポイントを手に入れました Encore Mode = Encoreモード Failed logging in to RetroAchievements = RetroAchievementsのログインに失敗しました Failed to connect to RetroAchievements. Achievements will not unlock. = RetroAchievementsへの接続に失敗しました。実績はアンロックされません。 @@ -27,8 +27,8 @@ Hardcore Mode = チャレンジモード How to use RetroAchievements = RetroAchievementsの使い方 In Encore mode - listings may be wrong below = In Encore mode - listings may be wrong below Leaderboard attempt started or failed = Leaderboard attempt started or failed -Leaderboard result submitted = リーダーボードの結果を投稿した -Leaderboard score submission = リーダーボードの結果投稿 +Leaderboard result submitted = リーダーボードへ結果を投稿した +Leaderboard score submission = リーダーボードへの結果投稿 Leaderboard submission is enabled = リーダーボードへの投稿が有効 Leaderboard tracker = リーダーボードトラッカー Leaderboards = リーダーボード @@ -53,15 +53,15 @@ Test Mode = テストモード This feature is not available in Hardcore Mode = この機能はチャレンジモードでは使用できません This game has no achievements = このゲームは実績機能がありません Top players = トッププレイヤー -Unlocked achievements = 達成していない実績 +Unlocked achievements = 達成した実績 Unofficial achievements = 非公式な実績 Unsupported achievements = サポートしていない実績 [Audio] Alternate speed volume = カスタム速度時のボリューム -Audio backend = オーディオのバックエンド (再起動が必要) +Audio backend = オーディオバックエンド (再起動が必要) Audio Error = オーディオエラー -Audio file format not supported. Must be WAV. = オーディオファイル形式に対応していません。WAVである必要があります。 +Audio file format not supported. Must be WAV or MP3. = オーディオファイル形式に対応していません。WAVまたはMP3である必要があります。 AudioBufferingForBluetooth = Bluetoothに適したバッファ (低遅延) Auto = 自動 Device = デバイス @@ -71,7 +71,9 @@ Enable Sound = オーディオを有効にする Global volume = グローバルボリューム Microphone = マイクの設定 Microphone Device = マイク入力機器の選択 +Mix audio with other apps = Mix audio with other apps Mute = ミュート +Respect silent mode = Respect silent mode Reverb volume = リバーブボリューム Use new audio devices automatically = 新しいオーディオデバイスをオンにする Use global volume = グローバルボリュームを使う @@ -81,7 +83,7 @@ WASAPI (fast) = WASAPI (高速) Analog Binding = 右アナログパッドへの対応ボタン割り当て Analog Settings = アナログパッドの設定 Analog Style = 右アナログパッドのスタイル -Analog trigger threshold = Analog trigger threshold +Analog trigger threshold = アナログトリガーのしきい値 Auto-rotation speed = アナログの自動回転速度 Analog Limiter = アナログパッドのリミッタ Analog Stick = アナログパッド @@ -233,8 +235,9 @@ Log Console = ログコンソール(&L) Memory View... = メモリビュー(&V)... More Settings... = 詳細設定(&M)... Nearest = &Nearest +Pause when not focused = 非フォーカス時は一時停止する(&P) Recent = &Recent -Restart Graphics = Restart Graphics +Restart Graphics = グラフィクスを再起動 Skip Buffer Effects = ノンバッファレンダリング (高速化)(&S) Off = オフ(&O) Open Chat = Open Chat @@ -244,7 +247,6 @@ Open Memory Stick = メモリースティックを開く(&M) Open New Instance = 新しいインスタンスを開く OpenGL = &OpenGL Pause = 一時停止(&P) -Pause When Not Focused = 非フォーカス時は一時停止する(&P) Portrait = 縦 Portrait reversed = 縦 (反転) PPSSPP Forums = PPSSPPフォーラム(&F) @@ -307,6 +309,8 @@ Fragment = フラグメント Frame timing = フレームタイミング Framedump tests = フレームダンプのテスト Frame Profiler = フレームプロファイラ +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPUドライバをテスト GPU Profile = GPUプロファイル @@ -333,6 +337,7 @@ Run CPU Tests = CPUテストを実行する Save new textures = 新しいテクスチャを保存する Shader Viewer = シェーダビューワ Show Developer Menu = 開発者向けメニューを表示する +Show GPO LEDs = Show GPO LEDs Show on-screen messages = オンスクリーンメッセージを表示する Stats = 状況 System Information = システム情報 @@ -368,6 +373,7 @@ ConfirmLoad = データをロードしますか? ConnectingAP = アクセスポイントに接続中.\nしばらくお待ちください... ConnectingPleaseWait = 接続中.\nしばらくお待ちください... ConnectionName = 接続名 +Copy to clipboard = Copy to clipboard Corrupted Data = 破損したデータ Delete = 削除 Delete all = 全て削除 @@ -403,7 +409,7 @@ Log in = ログイン Log out = ログアウト Logged in! = ログインしました! Logging in... = ログイン中... -More information... = More information... +More information... = 詳細はこちら... Move = 移動 Move Down = 下へ移動 Move Up = 上へ移動 @@ -427,7 +433,7 @@ Saving = セーブ中です。\nしばらくお待ちください... SavingFailed = データをセーブできませんでした。 Search = 検索 seconds, 0:off = 秒, 0 = オフ -Select = セレクト +Select = 選択 Settings = 設定 Shift = シフト Skip = スキップ @@ -476,7 +482,7 @@ GenericVulkanError = グラフィックスの初期化に失敗しました。 InsufficientOpenGLDriver = OpenGLドライバのサポート不足が検出されました。\n\nお使いのGPUはPPSSPPの動作に必要なOpenGL 2.0をサポートしていません。\n\nお使いのGPUがOpenGL 2.0と互換性があるか確認してください。 互換性がある場合、GPUの開発元のウェブサイトから新しいグラフィックスドライバをインストールしてください。\n\n詳細についてはhttps://forums.ppsspp.orgのフォーラムを確認してください。 Just a directory. = ディレクトリです。 Missing key = キーがありません -MsgErrorCode = Error code: +MsgErrorCode = エラーコード: MsgErrorSavedataDataBroken = セーブデータが破損しています。 MsgErrorSavedataMSFull = メモリースティックに空きがありません。容量を確認してください。 MsgErrorSavedataNoData = 警告: セーブデータが見つかりません。 @@ -508,24 +514,24 @@ ZIP file detected (Require WINRAR) = ファイルが圧縮されています (ZI [Game] Asia = アジア -Calculate CRC = CRCを算出する -Click "Calculate CRC" to verify ISO = Click "Calculate CRC" to verify ISO +Calculate CRC = CRCを算出 +Click "Calculate CRC" to verify ISO = "CRCを算出" をクリックしてISOを検証します ConfirmDelete = 削除 -CRC checksum does not match, bad or modified ISO = CRC checksum does not match, bad or modified ISO +CRC checksum does not match, bad or modified ISO = CRCチェックサムが一致しません。不良であるか変更されたISOです Create Game Config = ゲームの設定を作成する Create Shortcut = ショートカットを作成する Delete Game = ゲームを削除する Delete Game Config = ゲームの設定を削除する Delete Save Data = セーブデータを削除する Europe = ヨーロッパ -File size incorrect, bad or modified ISO = File size incorrect, bad or modified ISO +File size incorrect, bad or modified ISO = ファイルサイズが正しくありません。不良であるか変更されたISOです Game = ゲーム -Game ID unknown - not in the ReDump database = Game ID unknown - not in the ReDump database +Game ID unknown - not in the ReDump database = 不明なゲームID - ReDumpのデータベースにありません Game Settings = ゲームの設定 Homebrew = 自作 Hong Kong = 香港 InstallData = データのインストール -ISO OK according to the ReDump project = ISO OK according to the ReDump project +ISO OK according to the ReDump project = ReDumpプロジェクトによるとISOは正常です。 Japan = 日本 Korea = 韓国 MB = MB @@ -534,9 +540,9 @@ Play = プレイ Remove From Recent = 履歴から削除する SaveData = セーブデータ Setting Background = 背景を設定 -Show In Folder = フォルダに表示する -Time Played: %1h %2m %3s = Time Played: %1h %2m %3s -Uncompressed = Uncompressed +Show In Folder = フォルダを表示する +Time Played: %1h %2m %3s = プレイ時間: %1時間 %2分 %3秒 +Uncompressed = 非圧縮 USA = USA Use UI background = UIの背景を使う @@ -562,7 +568,7 @@ Use UI background = UIの背景を使う 9x PSP = 9× PSP 10x PSP = 10× PSP 16x = 16× -AdrenoTools driver manager = AdrenoTools driver manager +AdrenoTools driver manager = AdrenoToolsドライバーマネージャー Aggressive = 最大限 Alternative Speed = カスタム速度1 (%で指定、0 = 無制限) Alternative Speed 2 = カスタム速度2 (%で指定、0 = 無制限) @@ -587,22 +593,22 @@ Cardboard Screen X Shift = X軸の位置変更 (余白に対する%) Cardboard Screen Y Shift = Y軸の位置変更 (余白に対する%) Cardboard VR Settings = Google Cardboard VRの設定 Cheats = チート -Copy to texture = Copy to texture -Current GPU Driver = Current GPU Driver +Copy to texture = テクスチャにコピー +Current GPU Driver = 現在のGPUドライバ Debugging = デバッグ -Default GPU driver = Default GPU driver +Default GPU driver = デフォルトのGPUドライバ DefaultCPUClockRequired = 警告: このゲームではCPUクロックをデフォルトに設定する必要があります。 Deposterize = ポスタライズを解除する Deposterize Tip = アップスケールされたテクスチャのバンディングを修正する Device = デバイス Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disable culling = Disable culling +Disable culling = カリングを無効化 Disabled = 無効 -Display Layout && Effects = 画面のレイアウトを編集する +Display layout & effects = 画面のレイアウトを編集する Display Resolution (HW scaler) = 画面解像度 (HWスケーラー) -Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 -Drivers = Drivers +Driver requires Android API version %1, current is %2 = ドライバーはAndroid API version %1を要求していますが, 現在 %2です +Drivers = ドライバー Enable Cardboard VR = Cardboard VRを有効にする FPS = FPS Frame Rate Control = フレームレートのコントロール @@ -620,11 +626,11 @@ High = 高 Hybrid = Hybrid Hybrid + Bicubic = Hybrid + Bicubic Ignore camera notch when centering = インカメラ液晶部分を画面センタリング領域に含めない -Install custom driver... = Install custom driver... +Install custom driver... = カスタムドライバーのインストール... Integer scale factor = Integer scale factor Internal Resolution = 内部解像度 Lazy texture caching = テクスチャキャッシュを遅延させる (高速化) -Lazy texture caching Tip = 高速化するが いくつかのゲームでテキスト表示が崩れる場合があります +Lazy texture caching Tip = 高速化するがいくつかのゲームでテキスト表示が崩れる場合があります Linear = Linear Low = 低 LowCurves = スプライン/ベジェ曲線の品質 @@ -632,17 +638,18 @@ LowCurves Tip = いくつかのゲームでのみ用いられ、曲線の滑ら Lower resolution for effects (reduces artifacts) = エフェクトを低解像度にする (生成物を減らす) Manual Scaling = 手動で拡大 Medium = 中 +Mirror camera image = Mirror camera image Mode = モード Must Restart = この変更を適用するにはPPSSPPを再起動してください Native device resolution = 機器のネイティブ解像度 Nearest = Nearest -No (default) = No (default) +No (default) = なし (既定) No buffer = バッファなし Render all frames = Render all frames Same as Rendering resolution = 自動 (レンダリング解像度と同じ) Show Battery % = Show Battery % Show Speed = 速度を表示する -Skip = Skip +Skip = スキップ Skip Buffer Effects = ノンバッファレンダリング (高速化) None = なし Number of Frames = フレーム数 @@ -665,7 +672,7 @@ Screen Scaling Filter = 画像スケーリングのフィルタ Show Debug Statistics = デバッグ情報を表示する Show FPS Counter = FPSを表示する Skip GPU Readbacks = GPUリードバックのスキップ -Smart 2D texture filtering = Smart 2D texture filtering +Smart 2D texture filtering = Smart 2Dテクスチャフィルタリング Software Rendering = ソフトウェアレンダリング (実験的) Software Skinning = ソフトウェアスキニング SoftwareSkinning Tip = スキンモデルの描画をCPUでまとめて行う。ほとんどのゲームが高速化します @@ -679,14 +686,14 @@ Texture Filtering = テクスチャフィルタリング Texture replacement pack activated = Texture replacement pack activated Texture Scaling = テクスチャスケーリング Texture Shader = テクスチャシェーダ -The chosen ZIP file doesn't contain a valid driver = The chosen ZIP file doesn't contain a valid driver +The chosen ZIP file doesn't contain a valid driver = 選択されたZIPファイルには有効なドライバが含まれていません Turn off Hardware Tessellation - unsupported = 「ハードウェアテッセレーション」をオフにしてください。サポートされていません Unlimited = 無制限 Up to 1 = 最大1 Up to 2 = 最大2 Upscale Level = アップスケールのレベル Upscale Type = アップスケールのタイプ -UpscaleLevel Tip = CPUに重い負荷 - カクつきを避けるためタイプによっては遅延するスケーリングがあるかもしれません +UpscaleLevel Tip = 高いCPU負荷 - カクつきを避けるため遅延するスケーリングがあるかもしれません Use all displays = 全てのディスプレイを使う VSync = VSync Vulkan = Vulkan @@ -694,33 +701,36 @@ Window Size = ウィンドウサイズ xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = ZIPファイルを削除 +Existing data = Existing data Install = インストールする Install game from ZIP file? = ZIPファイルからゲームをインストールしますか? +Install in folder = Install in folder Install textures from ZIP file? = ZIPファイルからテクスチャをインストールしますか? -Installation failed = Installation failed +Installation failed = インストール失敗 Installed! = インストールしました Texture pack doesn't support install = テクスチャパックがインストールをサポートしていません Zip archive corrupt = ZIPアーカイブが破損しています Zip file does not contain PSP software = ZIPファイルにPSPソフトウェアが含まれていません [KeyMapping] -Allow combo mappings = Allow combo mappings +Allow combo mappings = マルチボタン制御を許可 Autoconfigure = 自動設定 Autoconfigure for device = デバイスの自動設定 Bind All = 全ての割り当てを行う Clear All = 全てクリアする -Combo mappings are not enabled = Combo mappings are not enabled +Combo mappings are not enabled = マルチボタン制御が有効になっていません Control modifiers = Control modifiers Default All = デフォルトに戻す -Emulator controls = Emulator controls -Extended PSP controls = Extended PSP controls +Emulator controls = エミュレーターのコントロール +Extended PSP controls = 拡張したPSPのコントロール Map a new key for = 新しいキーを入力 Map Key = キーの割り当て指定 Map Mouse = マウスの割り当て指定 Replace = 置き換える Show PSP = PSP画像を表示 -Standard PSP controls = Standard PSP controls +Standard PSP controls = 通常のPSPのコントロール Strict combo input order = Strict combo input order You can press ESC to cancel. = Escを押すとキャンセルできます。 @@ -785,7 +795,7 @@ Display Landscape Reversed = 横表示[逆位置]に切り替え Double tap button = ダブルタップ時の設定 Down = 十字キー 下 Dpad = 十字キー -Exit App = Exit App +Exit App = アプリを終了 Frame Advance = コマ送り Hold = ホールド Home = Homeボタン @@ -828,8 +838,8 @@ Texture Dumping = テクスチャのダンプ Texture Replacement = テクスチャの置換 Toggle Fullscreen = フルスクリーンの切り替え Toggle mode = モードの切り替え -Toggle mouse input = Toggle mouse input -Toggle touch controls = Toggle touch controls +Toggle mouse input = マウス入力の切り替え +Toggle touch controls = タッチコントロールの切り替え Toggle WLAN = WLANの切り替え Triangle = △ Fast-forward = 速度制限を解除 @@ -839,7 +849,7 @@ Vol - = 音量を下げる Wlan = WLAN [Networking] -AdHoc Server = アドホックサーバ +AdHoc Server = アドホックサーバー AdhocServer Failed to Bind Port = アドホックサーバーがポートのバインドに失敗しました AM: Data from Unknown Port = AM: 不明なポートからのデータ Auto = 自動 @@ -854,10 +864,10 @@ Chat message = チャットメーッセージ Chat Screen Position = チャット画面の位置 Disconnected from AdhocServer = アドホックサーバーから切断する DNS Error Resolving = DNSエラーの解決 -Enable built-in PRO Adhoc Server = 内蔵PROアドホックサーバを有効にする +Enable built-in PRO Adhoc Server = 内蔵PROアドホックサーバーを有効にする Enable network chat = ネットワークチャットを有効にする Enable networking = ネットワーク/WLANを有効にする -Enable UPnP = UPnPを有効にする (検出に数秒かかる) +Enable UPnP = UPnPを有効にする (検出に数秒必要) EnableQuickChat = クイックチャットを有効にする Enter a new PSP nickname = PSPの新しいニックネームを入力する Enter Quick Chat 1 = クイックチャット1を入力する @@ -887,7 +897,7 @@ Quick Chat 3 = クイックチャット3 Quick Chat 4 = クイックチャット4 Quick Chat 5 = クイックチャット5 QuickChat = クイックチャット -Randomize = Randomize +Randomize = ランダム化 Send = 送信する Send Discord Presence information = Discordのプレゼンス情報を送信する Unable to find UPnP device = UPnPデバイスがみつかりません @@ -911,7 +921,7 @@ German = ドイツ語 Italian = イタリア語 Japanese = 日本語 Korean = 韓国語 -Games often don't support all languages = ゲームはすべての言語に対応していないことが多いです +Games often don't support all languages = ゲームはすべての言語には対応していないことが多いです Portuguese = ポルトガル語 Russian = ロシア語 Spanish = スペイン語 @@ -937,22 +947,22 @@ Undo last save = セーブ内容を戻す 5xBR = 5xBR pixel art upscaler 5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color -Amount = Amount +Amount = 範囲 Animation speed (0 -> disable) = Animation speed (0 -> disable) Aspect = Aspect Black border = Black border Bloom = Bloom BloomNoBlur = Bloom (no blur) -Brightness = Brightness +Brightness = 輝度 Cartoon = Cartoon CatmullRom = Bicubic (Catmull-Rom) Upscaler ColorCorrection = Color correction ColorPreservation = Color preservation -Contrast = Contrast +Contrast = コントラスト CRT = CRT scanlines FakeReflections = FakeReflections FXAA = FXAA Antialiasing -Gamma = Gamma +Gamma = ガンマ GreenLevel = Green level Intensity = Intensity LCDPersistence = LCD Persistence @@ -960,15 +970,15 @@ MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Natural Colors NaturalA = Natural Colors (no blur) Off = オフ -Power = Power +Power = 強さ PSPColor = PSP color RedBlue = Red/Blue glasses -Saturation = Saturation +Saturation = 彩度 Scanlines = Scanlines (CRT) Sharpen = Sharpen SideBySide = Side by side (SBS) SSAA(Gauss) = Supersampling AA (Gauss) -Strength = Strength +Strength = 強さ Tex4xBRZ = 4xBRZ TexMMPX = MMPX UpscaleBicubic = UpscaleBicubic @@ -998,7 +1008,7 @@ Privacy Policy = プライバシーポリシー Share PPSSPP = PPSSPPをシェアする specialthanks = スペシャルサンクス: specialthanksKeithGalocy = at NVIDIA (ハードウェア, アドバイス) -specialthanksMaxim = (素晴らしいAtrac3+デコーダ) +specialthanksMaxim = (彼の素晴らしいAtrac3+デコーダーに対して) testing = 動作テスト this translation by = 翻訳者: title = 高速で移植性のあるPSPエミュレータ @@ -1006,7 +1016,7 @@ tools = 使用されているフリーツール: # PPSSPPの翻訳者や翻訳への貢献者をここに追加してください。 # 翻訳者のクレジットは6行までです。 # 余った行は空白のままにしてください。1行に4人記載するのがベストのようです。 -translators1 = unknown, gary, nassau-tk +translators1 = unknown, gary, nassau-tk, nishinji translators2 = translators3 = translators4 = @@ -1018,17 +1028,17 @@ written = 速度と移植性を保つためにC++で書かれています [MemStick] Already contains PSP data = 既にPSPデータが存在しています。 -Cancelled - try again = Cancelled - try again +Cancelled - try again = キャンセルされました。もう一度お試しください Checking... = Checking... -Current = 現在の +Current = 現在 DataWillStay = データはPPSSPPをアンインストールしても残ります。 DataCanBeShared = 通常版/ゴールド間でのデータの共有が可能です。 DataCannotBeShared = 通常版/ゴールド間でのデータの共有は「できません」。 -Deleting... = Deleting... +Deleting... = 削除中... Done! = 完了! -EasyUSBAccess = PCとのUSB接続でフォルダにアクセスが簡単にできます。 +EasyUSBAccess = PCとのUSB接続で簡単にフォルダにアクセスできます。 Failed to move some files! = いくつかのファイルの移動に失敗しました! -Failed to save config = セーブコンフィグに失敗しました! +Failed to save config = コンフィグの保存に失敗しました! Free space = 空き容量 Manually specify PSP folder = PSPフォルダーを手動で設定する Move Data = データ移動 @@ -1046,15 +1056,19 @@ Create or Choose a PSP folder = フォルダの新規作成または既存フォ Use App Private Data = アプリのプライベートフォルダに保存 Use PSP folder at root of storage = デバイスの内部ストレージのルートに保存 Welcome to PPSSPP! = ようこそPPSSPPへ! -WhatsThis = What's This?! +WhatsThis = 詳細はこちら [RemoteISO] Browse Games = ゲームをブラウズする -Local Server Port = ローカルサーバのポート +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share +Local Server Port = ローカルサーバーのポート Manual Mode Client = マニュアルモードクライアント +Not currently sharing = Not currently sharing Remote disc streaming = リモートディスクストリーミング Remote Port = リモートポート -Remote Server = リモートサーバ +Remote Server = リモートサーバー Remote Subdirectory = リモートサブディレクトリ RemoteISODesc = 最近のリストにあるゲームがシェアされます RemoteISOLoading = 接続しました。ゲームリストをロードします... @@ -1063,14 +1077,14 @@ RemoteISOScanningTimeout = スキャンしています... デスクトップの RemoteISOWifi = 注意: 両方のデバイスを同じWi-Fiネットワークに接続してください RemoteISOWinFirewall = 警告: Windowsファイアウォールが共有をブロックしています Settings = 設定 -Share Games (Server) = ゲームをシェアする (サーバ) +Share Games (Server) = ゲームをシェアする (サーバー) Share on PPSSPP startup = PPSSPPの起動時にシェアする Show Remote tab on main screen = Show Remote tab on main screen Stop Sharing = シェアを停止する Stopping.. = 停止しています... [Reporting] -Bad = Bad +Bad = 悪い FeedbackCRCCalculating = Disc CRC: 計算中... FeedbackCRCValue = Disc CRC: %1 FeedbackDelayInfo = あなたのデータはバックグラウンドで送信されます。 @@ -1079,24 +1093,24 @@ FeedbackDisabled = 「互換性をコミュニティに報告する」を有効 FeedbackIncludeCRC = 注意: ディスクのCRCを送信するのでバッテリを消費します FeedbackIncludeScreen = スクリーンショットを含める FeedbackSubmitDone = あなたのデータを送信しました。 -FeedbackSubmitFail = サーバにデータを送信できませんでした。PPSSPPをアップデートしてみてください。 -FeedbackThanks = フィードバックをご送信いただいてありがとうございます! +FeedbackSubmitFail = サーバーにデータを送信できませんでした。PPSSPPをアップデートしてみてください。 +FeedbackThanks = フィードバックを送信いただきありがとうございます! Gameplay = ゲームプレイ Graphics = グラフィックス -Great = Great -In-game = In-game -In-game Description = ゲームプレイには入れるがバグが多すぎて完全には程遠い -Menu/Intro = Menu/Intro +Great = 良好 +In-game = インゲーム +In-game Description = ゲームはプレイできるもののバグが多すぎて完璧には程遠い +Menu/Intro = メニュー/イントロ Menu/Intro Description = ゲームプレイに入れない -Nothing = Nothing -Nothing Description = 全く動かない -OK = OK +Nothing = なし +Nothing Description = 全く動作しない +OK = 可 Open Browser = ブラウザを開く Overall = 総合評価 -Perfect = Perfect -Perfect Description = ゲーム全体に渡って完全なエミュレーション - 素晴らしい! +Perfect = 完璧 +Perfect Description = ゲーム全体を完璧にエミュレートしている Plays = Plays -Plays Description = 完全に遊べるがグリッチが生じる +Plays Description = 完全に遊べるがカクツキが生じる ReportButton = 報告する Show disc CRC = CRCを表示する Speed = 速度 @@ -1127,7 +1141,7 @@ Size = サイズ [Screen] Cardboard VR OFF = Cardboard VRオフ Chainfire3DWarning = 警告: Chainfire3Dを検出しました。問題が起きるかもしれません。 -ExtractedISOWarning = Extracted ISOs often don't work.\nPlay the ISO file directly. +ExtractedISOWarning = 解凍されたISOはしばしば動作しません。\nISOファイルを直接読み込ませてください。 Failed to load state = ステートのロードに失敗しました Failed to save state = ステートのセーブに失敗しました fixed = 速度: カスタム速度1 @@ -1165,10 +1179,12 @@ Connection Error = 接続エラー Install = インストールする Installed = インストール済み Launch Game = ゲームを起動する +License = ソフトウェアライセンス Loading... = ロードしています... MB = MB Size = サイズ Uninstall = アンインストールする +Website = Webサイト [SysInfo] %0.2f Hz = %0.2f Hz @@ -1196,7 +1212,7 @@ Debugger Present = デバッガーあり Depth buffer format = デプスバッファ形式 Device Info = デバイス情報 Directories = ディレクトリ -Display Color Formats = Display Color Formats +Display Color Formats = カラーフォーマットを表示 Display Information = ディスプレイ情報 DPI = DPI Driver bugs = ドライバーバグ @@ -1228,7 +1244,7 @@ Refresh rate = リフレッシュレート Release = リリース RW/RX exclusive = RW/RX専用 Sample rate = サンプルレート -Screen notch insets = Screen notch insets +Screen notch insets = スクリーンの切り欠き Shading Language = シェーディング言語 Storage = ストレージ情報 Sustained perf mode = 性能維持モード @@ -1237,8 +1253,8 @@ System Name = システム名 System Version = システムバージョン Threads = スレッド数 UI resolution = UI解像度 -Vendor = ベンダ -Vendor (detected) = ベンダ (検出されたもの) +Vendor = ベンダー +Vendor (detected) = ベンダー (検出による) Version Information = バージョン情報 Vulkan Extensions = Vulkan拡張 Vulkan Features = Vulkanの機能 @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkanの機能 (broken) = (壊れています) 12HR = 12時間 24HR = 24時間 +App switching mode = App switching mode Auto = 自動 Auto Load Savestate = 自動的にセーブステートをロードする AVI Dump started. = AVIダンプを開始しました @@ -1254,14 +1271,15 @@ AVI Dump stopped. = AVIダンプを停止しました Cache ISO in RAM = ISO全体をキャッシュする Change CPU Clock = CPUクロックを変更する (不安定) CPU Core = CPUコア -Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Dynarec/JIT (recommended) = Dynarec/JIT (推奨) +Enable plugins = プラグインを有効化 Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols -Game crashed = Game crashed -JIT using IR = JIT using IR +Game crashed = ゲームがクラッシュしました +JIT using IR = IRを使用したJIT Language = 言語 -Loaded plugin: %1 = Loaded plugin: %1 +Loaded plugin: %1 = 読み込まれたプラグイン: %1 Memory Stick folder = メモリースティックフォルダを変更する Memory Stick size = メモリースティックの容量の変更 (GB) Change Nickname = ニックネームを変更する @@ -1311,8 +1329,10 @@ No animation = アニメーションなし Not a PSP game = PSPのゲームではありません Off = オフ Oldest Save = 最も古いセーブ -Only JPG and PNG images are supported = Only JPG and PNG images are supported +Only JPG and PNG images are supported = JPGとPNG画像のみ対応しています Path does not exist! = パスが存在しません +Pause when not focused = 非フォーカス時は一時停止する(&P) +Plugins = プラグイン PSP Memory Stick = メモリースティックの設定 PSP Model = PSPのモデル PSP Settings = PSPの設定 @@ -1321,7 +1341,7 @@ PSP-2000/3000 = PSP-2000/3000 Recent games = Recent games Record Audio = オーディオを記録する Record Display = 画面を記録する -Recording = Recording +Recording = 記録 Reset Recording on Save/Load State = ステートをセーブ/ロードしたら記録をリセットする Restore Default Settings = 設定をデフォルトに戻す RetroAchievements = RetroAchievements @@ -1345,9 +1365,11 @@ Slot 4 = スロット4 Slot 5 = スロット5 Storage full = ストレージが一杯です Sustained performance mode = パフォーマンス維持モード +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = UIのテーマ Time Format = 時刻の形式 -Transparent UI background = Transparent UI background +Transparent UI background = 透明なUI背景 UI = ユーザーインターフェース UI Sound = UI操作音 UI background animation = UIの背景アニメーション @@ -1383,7 +1405,7 @@ Default = デフォルト %1 text field = %1 text field Choices: = Choices: List: = List: -Progress: %1% = Progress: %1% +Progress: %1% = 進捗: %1% Screen representation = Screen representation [Upgrade] Details = 詳細 @@ -1392,20 +1414,17 @@ Download = ダウンロード New version of PPSSPP available = 新しいバージョンのPPSSPPを利用できます [VR] +% of native FoV = ネイティブ視野角(FoV)の % 6DoF movement = 6DoF動作 -Camera type = Camera type Distance to 2D menus and scenes = 2Dメニューと空間までの距離 Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = 視野角のスケール Force 72Hz update = 72Hzに強制的に更新 -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = ヘッドアップディスプレイスケール Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = コントローラーの動きをキーにマッピングする -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = アクションを生成するために必要なモーション Stereoscopic vision (Experimental) = 立体映像 (実験的機能) Virtual reality = バーチャルリアリティー VR camera = VRカメラ diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 929c165828..0f9bf347fe 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Suoro backend (Wiwiti maneh, req) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Otomatis Device = Device @@ -71,7 +71,9 @@ Enable Sound = Ngatifke Suoro Global volume = Tingkat Volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Konsol Log Memory View... = Tampilan &Memory... More Settings... = Setelan sing luwih ... Nearest = &Nearest +Pause when not focused = &Ngaso Nalika Ora Fokus Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = Skip efek buffer (ora yakuwi,luwih cepet) @@ -244,7 +247,6 @@ Open Memory Stick = Mbukak &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Ngaso -Pause When Not Focused = &Ngaso Nalika Ora Fokus Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = &Forum PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Pigura Profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Mbukak Tes CPU Save new textures = Save new textures Shader Viewer = Tampilan shader Show Developer Menu = Tampilno menu pengembang +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = Informasi Sistem @@ -368,6 +373,7 @@ ConfirmLoad = Mbukak data iki? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Mbusek Delete all = Mbusek Kabeh @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Tata letak Tampilan editor +Display layout & effects = Tata letak Tampilan editor Display Resolution (HW scaler) = Resolusi tampilan (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Resolusi ngisor kanggo efek (nyuda artefak) Manual Scaling = Manual njongko Medium = Sedang +Mirror camera image = Mirror camera image Mode = Mode Must Restart = Wiwiti maneh PPSSPP kanggo aplikasi setelan. Native device resolution = Resolusi piranti asal @@ -694,9 +701,12 @@ Window Size = Ukuran window xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Mbusek berkas ZIP +Existing data = Existing data Install = Nginstal Install game from ZIP file? = Nginstal dolanan saka berkas ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Keinstal! @@ -734,9 +744,9 @@ Exit = Metu Game Settings = Setelan Dolanan Games = Dolanan Give PPSSPP permission to access storage = Menehi PPSSPP ijin kanggo ngakses panyimpenan -Homebrew & Demos = Homebrew && Demo +Homebrew & Demos = Homebrew & Demo How to get games = Dapatno dolanan -How to get homebrew & demos = Cara mendapatkan Homebrew && demo +How to get homebrew & demos = Cara mendapatkan Homebrew & demo Load = Mbukak... Loading... = Loading... PinPath = Pin @@ -1050,8 +1060,12 @@ written = Ditulis dalam C++ Kanggo kacepetan lan portabilitas [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Galat koneksi Install = Nginstal Installed = Mpun terpasang Launch Game = Bukak Dolanan +License = License Loading... = Nteni... MB = MB Size = Ukuran Uninstall = Copot +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12-Jam 24HR = 24-Jam +App switching mode = App switching mode Auto = Otomatis Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Pengembang Pribadi Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulasi Enable Cheats = Ngatifke Cheat @@ -1313,6 +1331,8 @@ Off = Mati Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Ngaso Nalika Ora Fokus +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = Setelan PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Penyimpenan lengkap Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Format wektu Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Unduh New version of PPSSPP available = Versi anyar PPSSPP mpun ono monggo di comot [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index 62fc4d246c..3ed05610fe 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -1,26 +1,26 @@ [Achievements] -%1 achievements, %2 points = %1 성과, %2 포인트 +%1 achievements, %2 points = %1 도전과제, %2 포인트 %1: Attempt started = %1: 순위표 시도 시작 %1: Attempt failed = %1: 순위표 시도 실패 Account = 계정 Achievement sound volume = Achievement 사운드 볼륨 -Achievement unlocked = 성과 잠금 해제 -Achievement progress = 성과 진행률 -Achievements = 성과 -Achievements enabled = 성과 활성화 -Achievements are disabled = 성과 비활성화 -Achievements with active challenges = 도전 과제가 활성화된 성과 +Achievement unlocked = 도전과제 잠금 해제 +Achievement progress = 도전과제 진행률 +Achievements = 도전과제 +Achievements enabled = 도전과제 활성화 +Achievements are disabled = 도전과제 비활성화 +Achievements with active challenges = 적극적인 도전을 통한 도전과제 Allow Save State in Hardcore Mode (but not Load State) = 하드코어 모드에서 상태 저장 허용 (로드 상태는 아님) -Almost completed achievements = 거의 완료된 성과 +Almost completed achievements = 거의 완료된 도전과제 Can't log in to RetroAchievements right now = 지금 RetroAchievements에 로그인할 수 없음 Challenge indicator = 도전 표시기 Contacting RetroAchievements server... = RetroAchievements 서버에 연결 중... Customize = 맞춤 설정 -Earned = %1 의 %2 성과 및 %3 의 %4 포인트 획득 +Earned = %2 의 %1 도전과제를 잠금 해제하고, %4 의 %3 포인트 획득 Encore Mode = 앙코르 모드 Failed logging in to RetroAchievements = RetroAchievements에 로그인 실패 -Failed to connect to RetroAchievements. Achievements will not unlock. = RetroAchievements에 연결하지 못했습니다. 성과가 잠금 해제되지 않습니다. -Failed to identify game. Achievements will not unlock. = 게임을 식별하지 못했습니다. 성과가 잠금 해제되지 않습니다. +Failed to connect to RetroAchievements. Achievements will not unlock. = RetroAchievements에 연결하지 못했습니다. 도전과제가 잠금 해제되지 않습니다. +Failed to identify game. Achievements will not unlock. = 게임을 식별하지 못했습니다. 도전과제가 잠금 해제되지 않습니다. Hardcore Mode (no savestates) = 도전 모드 (저장 상태 없음) Hardcore Mode = 도전 모드 How to use RetroAchievements = RetroAchievements 사용 방법 @@ -32,36 +32,36 @@ Leaderboard submission is enabled = 순위표 제출 활성화 Leaderboards = 순위표 Leaderboard tracker = 순위표 추적기 Links = 링크 -Locked achievements = 잠겨진 성과 +Locked achievements = 잠겨진 도전과제 Log bad memory accesses = 불량 메모리 접속 로그 Mastered %1 = 마스터한 %1 Around me = 내 주변 Notifications = 알림 -Recently unlocked achievements = 최근 잠금 해제된 성과 +Recently unlocked achievements = 최근 잠금 해제된 도전과제 Reconnected to RetroAchievements. = RetroAchievements에 다시 연결되었습니다. Register on www.retroachievements.org = www.retroachievements.org에 등록 RetroAchievements are not available for this game = 이 게임에서는 RetroAchievements 사용할 수 없음 RetroAchievements website = RetroAchievements 웹사이트 Rich Presence = 활동 상태 -Save state loaded without achievement data = 성과 데이터 없이 로드된 상태 저장 +Save state loaded without achievement data = 도전과제 데이터 없이 로드된 상태 저장 Save states not available in Hardcore Mode = 도전 모드에서 사용할 수 없는 저장 상태 Sound Effects = 사운드 효과 Statistics = 통계 Submitted %1 for %2 = 2에 %1을(를) 제출함 -Syncing achievements data... = 성과 데이터 동기화 중... +Syncing achievements data... = 도전과제 데이터 동기화 중... Test Mode = 테스트 모드 This feature is not available in Hardcore Mode = 도전 모드에서는 이 기능을 사용할 수 없음 -This game has no achievements = 이 게임에는 성과가 없음 +This game has no achievements = 이 게임에는 도전과제가 없음 Top players = 상위 플레이어 -Unlocked achievements = 잠금 해제된 성과 -Unsupported achievements = 지원되지 않는 성과 -Unofficial achievements = 비공식 성과 +Unlocked achievements = 잠금 해제된 도전과제 +Unsupported achievements = 지원되지 않는 도전과제 +Unofficial achievements = 비공식 도전과제 [Audio] Alternate speed volume = 대체 속도 볼륨 Audio backend = 오디오 백엔드 (재시작 요구) -Audio file format not supported. Must be WAV. = 오디오 파일 형식은 지원되지 않습니다. WAV여야 합니다. Audio Error = 오디오 오류 +Audio file format not supported. Must be WAV or MP3. = 오디오 파일 형식은 지원되지 않습니다. WAV/MP3여야 합니다. AudioBufferingForBluetooth = 블루투스 친화적 버퍼 (느림) Auto = 자동 Device = 장치 @@ -71,7 +71,9 @@ Enable Sound = 사운드 활성화 Global volume = 글로벌 볼륨 Microphone = 마이크로폰 Microphone Device = 마이크로폰 장치 +Mix audio with other apps = 다른 앱과 오디오 믹스 Mute = 음소거 +Respect silent mode = 무음 모드 존중 Reverb volume = 반향 볼륨 Use new audio devices automatically = 새 오디오 장치를 자동으로 사용 Use global volume = 글로벌 볼륨 사용 @@ -233,6 +235,7 @@ Log Console = 콘솔 로그(&L) Memory View... = 메모리 보기(&V)... More Settings... = 기타 설정(&M)... Nearest = 근접 필터링(&N) +Pause when not focused = 포커싱되지 않았을 때 일시 정지(&P) Restart Graphics = 그래픽 재시작 Skip Buffer Effects = 버퍼 효과 건너뛰기(&S) Off = 끔(&O) @@ -243,7 +246,6 @@ Open Memory Stick = 메모리 스틱 열기(&M) Open New Instance = 새로운 인스턴트 열기 OpenGL = OpenGL(&O) Pause = 일시 정지(&P) -Pause When Not Focused = 포커싱되지 않았을 때 일시 정지(&P) Portrait = 세로 방향 Portrait reversed = 세로 방향 반전 PPSSPP Forums = PPSSPP 포럼(&F) @@ -309,6 +311,8 @@ FPU = FPU Framedump tests = 프레임 덤프 테스트 Frame Profiler = 프레임 프로파일러 Frame timing = 프레임 타이밍 +GPI switch %1 = GPI 스위치 %1 +GPI/GPO switches/LEDs = GPI/GPO 스위치/LED GPU Allocator Viewer = GPU 할당기 뷰어 GPU Driver Test = GPU 드라이버 테스트 GPU Profile = GPU 프로파일 @@ -335,6 +339,7 @@ Run CPU Tests = CPU 테스트 실행 Save new textures = 새로운 텍스처 저장 Shader Viewer = 셰이더 뷰어 Show Developer Menu = 개발자 메뉴 표시 +Show GPO LEDs = GPO LED 표시 Show on-screen messages = 화면 메시지 표시 Stats = 상태 System Information = 시스템 정보 @@ -368,6 +373,7 @@ ConfirmLoad = 이 데이터를 불러오겠습니까? ConnectingAP = 접속 포인트에 연결하는 중입니다.\n잠시만 기다려 주세요... ConnectingPleaseWait = 연결 중입니다.\n잠시만 기다려 주세요... ConnectionName = 연결 이름 +Copy to clipboard = Copy to clipboard Corrupted Data = 손상된 데이터 Delete = 삭제 Delete all = 모두 삭제 @@ -535,7 +541,7 @@ Remove From Recent = "최근"에서 제거 SaveData = 저장데이터 Setting Background = 배경 설정 Show In Folder = 폴더에 표기 -Time Played: %1h %2m %3s = 플레이 시간: %1h %2m %3s +Time Played: %1h %2m %3s = 플레이 시간: %1시간 %2분 %3초 Uncompressed = 비압축 USA = 미국 Use UI background = UI 배경 사용 @@ -581,12 +587,13 @@ Copy to texture = 텍스처에 복사 Current GPU Driver = 현재 GPU 드라이버 Default GPU driver = 기본 GPU 드라이버 Disable culling = 컬링 비활성화 -Driver requires Android API version %1, current is %2 = 드라이버에는 Android API 버전 %1이(가) 필요하며, 현재는 %2입니다. +Display layout & effects = 화면 레이아웃 편집기 +Driver requires Android API version %1, current is %2 = 드라이버에는 안드로이드 API 버전 %1이(가) 필요하며, 현재는 %2입니다. Drivers = 드라이버 -GPUReadbackRequired = 경고: 이 게임은 "GPU 다시 읽기 건너뛰기"를 꺼짐으로 설정해야 합니다. +GPUReadbackRequired = 경고: 이 게임을 하려면 "GPU 리드백 건너뛰기"를 끄기로 설정해야 합니다. Both = 둘 다 Buffer graphics commands (faster, input lag) = 버퍼 그래픽 명령 (빠름, 입력 지연) -BufferedRenderingRequired = 경고: 이 게임은 "렌더링 모드"를 "버퍼링"으로 설정해야 합니다. +BufferedRenderingRequired = 경고: 이 게임은 "버퍼 효과 건너뛰기"와 호환되지 않음 Camera = 카메라 Camera Device = 카메라 장치 Cardboard Screen Size = 화면 크기(뷰포트의 %) @@ -602,7 +609,6 @@ Device = 장치 Direct3D 9 = 다이렉트3D 9 Direct3D 11 = 다이렉트3D 11 Disabled = 비활성화 -Display Layout && Effects = 화면 레이아웃 편집기 Display Resolution (HW scaler) = 화면 해상도(HW 스케일러) Enable Cardboard VR = 카드보드 VR 활성화 FPS = FPS @@ -628,10 +634,11 @@ Lazy texture caching Tip = 더 빠르지만 몇몇 게임에서 텍스트 문제 Linear = 선형 필터링 Low = 낮음 LowCurves = 스플라인/베지어 곡선 품질 -LowCurves Tip = 일부 게임에서만 사용되며 곡선의 부드러움을 제어합니다. +LowCurves Tip = 일부 게임에서만 사용되며, 곡선의 부드러움을 제어 Lower resolution for effects (reduces artifacts) = 효과에 대한 낮은 해상도 (인공물 감소) Manual Scaling = 수동 스케일링 Medium = 중간 +Mirror camera image = 미러 카메라 이미지 Mode = 모드 Must Restart = 이 변경 사항을 적용하려면 PPSSPP를 다시 시작해야 합니다. Native device resolution = 기본 장치 해상도 @@ -668,9 +675,9 @@ Skip GPU Readbacks = GPU 다시 읽기 건너뛰기 Smart 2D texture filtering = 스마트 2D 텍스처 필터링 Software Rendering = 소프트웨어 렌더링 (느림) Software Skinning = 소프트웨어 스키닝 -SoftwareSkinning Tip = 대부분의 게임에서 더 빠르게 CPU에서 스킨 모델 드로우를 결합합니다. +SoftwareSkinning Tip = CPU에서 스킨 처리된 모델 그리기를 결합하면, 대부분의 게임에서 더 빠르게 작업할 수 있음 Speed = 속도 -Speed Hacks = 속도 핵 (결함을 일으킬 수 있음) +Speed Hacks = 속도 핵 (렌더링 오류가 발생할 수 있음!) Stereo display shader = 스트레오 디스플레이 쉐이더 Stereo rendering = 스트레오 렌더링 Stretch = 늘이기 @@ -686,7 +693,7 @@ Up to 1 = 최대 1까지 Up to 2 = 최대 2까지 Upscale Level = 업스케일 레벨 Upscale Type = 업스케일 유형 -UpscaleLevel Tip = CPU 사용률 높음 - 버벅거림을 방지하기 위해 일부 확장이 지연될 수 있음 +UpscaleLevel Tip = CPU 사용률 높음 - 일부 크기 조정은 끊김 현상을 방지하기 위해 지연될 수 있음 Use all displays = 모든 화면 사용 VSync = 수직 동기화 Vulkan = Vulkan @@ -694,9 +701,12 @@ Window Size = 창 크기 xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = ZIP 파일 삭제 +Existing data = Existing data Install = 설치 Install game from ZIP file? = ZIP 파일에서 게임을 설치하겠습니까? +Install in folder = Install in folder Install textures from ZIP file? = ZIP 파일에서 텍스처를 설치하겠습니까? Installation failed = 설치 실패 Installed! = 설치되었습니다! @@ -734,7 +744,7 @@ Exit = 종료 Game Settings = 설정 Games = 게임 Give PPSSPP permission to access storage = PPSSPP에 저장공간 접속 권한 부여 -Homebrew & Demos = 홈브류 && 데모 +Homebrew & Demos = 홈브류 & 데모 How to get games = 게임을 어떻게 구할 수 있나요? How to get homebrew & demos = 홈브류 및 데모를 어떻게 구할 수 있나요? Load = 불러오기... @@ -781,7 +791,7 @@ DevMenu = 개발메뉴 Double tap button = 두 번 탭 버튼 Down = 십자 패드 아래쪽 Dpad = 십자 패드 -Exit App = App 종료 +Exit App = 앱 종료 Frame Advance = 프레임 어드밴스 Hold = 잠금 Home = 홈 @@ -815,10 +825,10 @@ Select = 선택 SpeedToggle = 속도 토글 Square = 네모 Start = 시작 -Swipe Down = 아래로 쓸어내림 -Swipe Left = 왼쪽으로 쓸어내림 -Swipe Right = 오른쪽으로 쓸어내림 -Swipe Up = 위로 쓸어내림 +Swipe Down = 아래로 밀기 +Swipe Left = 왼쪽으로 밀기 +Swipe Right = 오른쪽으로 밀기 +Swipe Up = 위로 밀기 tap to customize = 탭하여 맞춤 설정 Texture Dumping = 텍스처 덤핑 Texture Replacement = 텍스처 교체 @@ -829,7 +839,7 @@ Toggle touch controls = 터치 컨트롤 전환 Toggle WLAN = 무선랜 토글 Triangle = 세모 Fast-forward = 빨리 감기 -Up = 십자패드 위쪽 +Up = 십자 패드 위쪽 Vol + = 볼륨 + Vol - = 볼륨 - Wlan = 무선랜 @@ -840,7 +850,7 @@ Display Portrait Reversed = 세로방향 반전 표시 [Networking] AdHoc Server = Ad hoc 서버 -AdhocServer Failed to Bind Port = Ad Hoc 서버가 포트를 바인딩하지 못했습니다. +AdhocServer Failed to Bind Port = Ad Hoc 서버가 포트 바인딩 실패함 AM: Data from Unknown Port = AM: 알 수 없는 포트의 데이터 Auto = 자동 Change Mac Address = MAC 주소 변경 @@ -894,7 +904,7 @@ Unable to find UPnP device = UPnP 장치를 찾을 수 없습니다. UPnP (port-forwarding) = UPnP (포트 포워딩) UPnP need to be reinitialized = UPnP를 다시 초기화해야 합니다. UPnP use original port = UPnP는 원래 포트를 사용합니다 (활성화됨 = PSP 호환성) -UseOriginalPort Tip = 일부 기기나 게임에서는 작동하지 않을 수 있습니다. +UseOriginalPort Tip = 일부 기기나 게임에서는 작동하지 않을 수 있으므로, 위키를 참조하세요. Validating address... = 주소 검증하는 중... WLAN Channel = 무선랜 채널 You're in Offline Mode, go to lobby or online hall = 오프라인 모드입니다. 로비 또는 온라인 홀으로 이동합니다. @@ -971,11 +981,11 @@ Discord = 디스코드 info1 = PPSSPP는 교육 목적으로만 사용됩니다. info2 = 모든 게임에 대한 권리를 소유하고 있는지 확인하세요. info3 = UMD를 소유하거나 디지털을 구매하여 플레이합니다. -info4 = 실제 PSP의 PSN 스토어에서 다운로드하십시오. +info4 = 실기 PSP의 PSN 스토어에서 다운로드하십시오. info5 = PSP는 Sony, Inc.의 상표입니다. iOS builds = iOS 빌드 license = GPL 2.0+에 따른 무료 소프트웨어 -list = 호환성 목록, 포럼 및 개발 정보 +list = 호환성 목록, 포럼, 개발 정보 PPSSPP Forums = PPSSPP 포럼 Privacy Policy = 개인 정보 정책 Share PPSSPP = PPSSPP 공유 @@ -1050,13 +1060,17 @@ Spanish = 스페인어 [RemoteISO] Browse Games = 게임 찾아보기 +Connect = 접속 +Currently sharing = 현재 공유 중 +Files to share = 공유할 파일 Local Server Port = 로컬 서버 포트 Manual Mode Client = 수동 모드 클라이언트 +Not currently sharing = 현재 공유하지 않음 Remote disc streaming = 원격 디스크 스트리밍 Remote Port = 원격 포트 Remote Server = 원격 서버 Remote Subdirectory = 공유할 하위 폴더 -RemoteISODesc = 최근 게임 목록에 있는 게임들이 공유됩니다. +RemoteISODesc = "최근" 목록에 있는 게임이 공유됨 RemoteISOLoading = 접속 완료, 게임 목록 불러오는 중... RemoteISOScanning = 검색 중... 서버 장치의 "게임 공유하기" 버튼을 눌러주십시오. RemoteISOScanningTimeout = 검색 중... 방화벽 설정을 확인하십시오. @@ -1085,7 +1099,7 @@ Gameplay = 게임플레이 Graphics = 그래픽 Great = 좋음 In-game = 게임 내 -In-game Description = 게임이 실행되었지만 제대로 작동하지 않았습니다. +In-game Description = 게임이 실행되었지만, 제대로 작동하지 않았습니다. Menu/Intro = 메뉴/인트로 Menu/Intro Description = 게임 자체에 참여할 수 없음 Nothing = 아무것도 없음 @@ -1157,10 +1171,12 @@ Connection Error = 연결 오류 Install = 설치 Installed = 이미 설치됨 Launch Game = 게임 실행 +License = License Loading... = 불러오기 중... MB = 메가바이트 Size = 크기 Uninstall = 제거 +Website = Website [SysInfo] %d (%d per core, %d cores) = %d (코어 당 %d, 코어 %d 개) @@ -1239,6 +1255,7 @@ Display Color Formats = 디스플레이 색상 형식 (broken) = (고장) 12HR = 12시간 24HR = 24시간 +App switching mode = 앱 전환 모드 Auto = 자동 Auto Load Savestate = 상태 저장 자동 불러오기 AVI Dump started. = AVI 덤프가 시작됨 @@ -1270,6 +1287,7 @@ Display Homebrew on a grid = 그리드에 "홈브류 && 데모" 표시 Display Recent on a grid = 그리드에 "최근" 표시 Emulation = 에뮬레이션 Enable Cheats = 치트 활성화 +Enable plugins = 플러그인 활성화 Enable Compatibility Server Reports = 호환성 서버 보고서 활성화 Error: load undo state is from a different game = 오류: 불러오기 취소 상태는 다른 게임에서 가져옴 Failed to load state. Error in the file system. = 상태를 불러오지 못했습니다. 파일 시스템에 오류가 있습니다. @@ -1303,6 +1321,8 @@ Off = 끔 Oldest Save = 가장 오래된 저장 Only JPG and PNG images are supported = JPG 및 PNG 이미지만 지원됩니다. Path does not exist! = 경로가 존재하지 않습니다! +Pause when not focused = 포커싱되지 않았을 때 일시 정지(&P) +Plugins = 플러그인 PSP Memory Stick = PSP 메모리 스틱 PSP Model = PSP 모델 PSP Settings = PSP 설정 @@ -1334,6 +1354,8 @@ Slot 4 = 슬롯 4 Slot 5 = 슬롯 5 Storage full = 저장 공간 가득 참 Sustained performance mode = 지속 성능 모드 +Swipe once to switch app (indicator auto-hides) = 한 번 밀어 앱 전환 (표시기 자동 숨김) +Swipe twice to switch app (indicator stays visible) = 두 번 밀어 앱 전환 (표시기 계속 표시) Time Format = 시간 형식 Transparent UI background = 투명한 UI 배경 UI = UI @@ -1393,20 +1415,20 @@ Progress: %1% = 진행율: %1% Screen representation = 화면 표현 [VR] +% of native FoV = 실제 시야의 % 6DoF movement = 6DoF 이동 Distance to 2D menus and scenes = 2D 메뉴 및 장면까지의 거리 Distance to 3D scenes when VR disabled = VR 비활성화 시 3D 장면까지의 거리 +Enable immersive mode = 몰입형 모드 활성화 +Enable passthrough = 패스스루 활성화 Experts only = 전문가 전용 +Field of view scale = 시야 스케일 +Force 72Hz update = 강제 72Hz 업데이트 Game camera rotation step per frame = 프레임당 게임 카메라 회전 단계 Game camera uses rotation smoothing = 회전 스무딩을 사용하는 게임 카메라 -Force 72Hz update = 강제 72Hz 업데이트 Heads-up display scale = 헤드업 디스플레이 스케일 Heads-up display detection = 헤드업 디스플레이 감지 -Map controller movements to keys = 컨트롤러 이동을 키에 매핑 -Map HMD rotations on keys instead of VR camera = VR 카메라 대신 키에 HMD 회전 매핑하기 Manual switching between flat screen and VR using SCREEN key = 화면 키를 사용하여 평면 화면과 VR 간 수동 전환 -Camera type = 카메라 유형 -Motion needed to generate action = 동작 생성에 필요한 동작 Stereoscopic vision (Experimental) = 입체시 (실험적) Virtual reality = 가상 현실 VR camera = VR 카메라 diff --git a/assets/lang/ku_SO.ini b/assets/lang/ku_SO.ini new file mode 100644 index 0000000000..498f018fc7 --- /dev/null +++ b/assets/lang/ku_SO.ini @@ -0,0 +1,1446 @@ +# Thanks for your interest in translating PPSSPP. +# Please note, while translating: +# +# Hash/sharp symbols (#) in this file indicate a comment. Lines that begin without one are +# considered to be a part of the actual translations. +# +# Example 1: &File. This will make it so when you press ALT + F on Windows, it'll open the File menu. +# Example 2: Homebrew & Demos. This would show one real ampersand in the menu. +# I've Added a font named Rabar_014 because my language font looks better with it. +# وەرگێڕان کراوە لەلایەن محمد عمر حسێن، [ناوی بەڕێزت] +# تکایە هەر بەڕێزێک لەدوای من وەرگێڕانی کرد تەنها بە بەکارهێنانی بەرنامەی وەرگێران نەیکات +# بەڵکو ڕەچاوی بەکارهێنانی ڕۆژانە بکات بۆ بەکارهێنەر + +[Achievements] +%1 achievements, %2 points = %1 achievements, %2 points +%1: Attempt started = %1: Attempt started +%1: Attempt failed = %1: Attempt failed +Account = Account +Achievement sound volume = ئاستی دەنگی کردنەوەی دەستکەوت +Achievement unlocked = Achievement unlocked +Achievement progress = Achievement progress +Achievements = Achievements +Achievements enabled = Achievements enabled +Achievements are disabled = Achievements are disabled +Achievements with active challenges = Achievements with active challenges +Allow Save State in Hardcore Mode (but not Load State) = Allow Save State in Hardcore Mode (but not Load State) +Almost completed achievements = Almost completed achievements +Can't log in to RetroAchievements right now = Can't log in to RetroAchievements right now +Challenge indicator = Challenge indicator +Contacting RetroAchievements server... = Contacting RetroAchievements server... +Customize = Customize +Earned = You have unlocked %1 of %2 achievements, and earned %3 of %4 points +Encore Mode = Encore Mode +Failed logging in to RetroAchievements = Failed logging in to RetroAchievements +Failed to connect to RetroAchievements. Achievements will not unlock. = Failed to connect to RetroAchievements. Achievements will not unlock. +Failed to identify game. Achievements will not unlock. = Failed to identify game. Achievements will not unlock. +Hardcore Mode (no savestates) = Hardcore Mode (no savestates) +Hardcore Mode = Hardcore Mode +How to use RetroAchievements = How to use RetroAchievements +In Encore mode - listings may be wrong below = In Encore mode - listings may be wrong below +Leaderboard attempt started or failed = Leaderboard attempt started or failed +Leaderboard result submitted = Leaderboard result submitted +Leaderboard score submission = Leaderboard score submission +Leaderboard submission is enabled = Leaderboard submission is enabled +Leaderboards = Leaderboards +Leaderboard tracker = Leaderboard tracker +Links = Links +Locked achievements = دەستکەوتە قفڵ کراوەکان +Log bad memory accesses = Log bad memory accesses +Mastered %1 = Mastered %1 +Around me = Around me +Notifications = ئاگادارکردنەوەکان +Recently unlocked achievements = دەستکەوتە تازە کراوەکان +Reconnected to RetroAchievements. = RetroAchievements دووبارە پەیوەست بوویتەوە بە +Register on www.retroachievements.org = www.retroachievements.org خۆت تۆماربکە لە +RetroAchievements are not available for this game = بەردەست نییە بۆ ئەم یاریە RetroAchievements +RetroAchievements website = RetroAchievements وێبسایتی +Rich Presence = Rich Presence +Save state loaded without achievement data = Save state loaded without achievement data +Save states not available in Hardcore Mode = Save states not available in Hardcore Mode +Sound Effects = ئیفێکتەکانی دەنگ +Statistics = Statistics +Submitted %1 for %2 = Submitted %1 for %2 +Syncing achievements data... = Syncing achievements data... +Test Mode = Test Mode +This feature is not available in Hardcore Mode = This feature is not available in Hardcore Mode +This game has no achievements = ئەم یاریە دەستکەوتی نییە +Top players = Top players +Unlocked achievements = دەستکەوتە کراوەکان +Unsupported achievements = دەستکەوتە پاڵپشت نەکراوەکان +Unofficial achievements = دەستکەوتە نافەرمیەکان + +[Audio] +Alternate speed volume = خێرایی دەنگی جێگرەوە +Audio backend = باکئێندی دەنگ (پێویستە کە ئاپەکە دووبارە بکرێتەوە) +Audio file format not supported. Must be WAV or MP3. = بێت WAV, MP3 شێوازی دەنگەکە پاڵپشتی نەکراوە، مەرجە کە شێوازی +Audio Error = هەڵەی دەنگ ڕوویدا +AudioBufferingForBluetooth = (خاوتر) Bluetooth بەفەرێک باشبێت بۆ +Auto = Auto +Device = ئامێر +Disabled = لەکار خراوە +DSound (compatible) = DSound (گونجاو) +Enable Sound = بەکارکردنی دەنگ +Global volume = دەنگی گشتی +Microphone = مایکرۆفۆن +Microphone Device = ئامێری مایکرۆفۆن +Mix audio with other apps = Mix audio with other apps +Mute = بێدەنگ کردن +Respect silent mode = Respect silent mode +Reverb volume = ئاستی دەنگی گشت ئاڕاستە +Use new audio devices automatically = بەکارهێنانی ئامێری دەنگی تازە بە شێوەیەکی ئۆتۆماتیکی +Use global volume = بەکارهێنانی دەنگی گشتی +WASAPI (fast) = WASAPI (خێرا) + +[Controls] +Analog Binding = بەستنەوەی ئەنالۆگ +Analog Limiter = سنوورداری ئەنالۆگ +Analog Settings = ڕێکخستنەکانی ئەنالۆگ +Analog Stick = Analog stick +Analog Style = شێوازی ئانالۆگ +Analog trigger threshold = ئاستی کارپێکردنی ئەنالۆگ +AnalogLimiter Tip = When the analog limiter button is pressed +Auto = Auto +Auto-centering analog stick = هێنانە ناوەڕاستی ستیکی ئەنالۆگ بە شێوەی ئۆتۆماتیکی +Auto-hide buttons after delay = شاردنەوەی دوگمەکان بە شێوەی ئۆتۆماتیکی پاش +Auto-rotation speed = خێرایی خولانەوەی ئۆتۆماتیکی +Binds = بەستنەوەکان +Button Binding = بەستنەوەی دوگمەکان +Button Opacity = دیاربوونی دوگمەکان +Button style = شێوازی دوگمەکان +Calibrate Analog Stick = قەبارەدانان بۆ ستیکی ئەنالۆگ +Calibrate = Calibrate +Calibrated = Calibrated +Calibration = Calibration +Circular deadzone = Circular deadzone +Circular stick input = Circular stick input +Classic = کلاسیک +Confine Mouse = Trap mouse within window/display area +Control Mapping = Control mapping +Custom Key Setting = Custom Key Setting +Customize = Customize +Customize Touch Controls = Edit touch control layout... +D-PAD = دوگمەکان +Deadzone radius = Deadzone radius +Disable D-Pad diagonals (4-way touch) = Disable D-Pad diagonals (4-way touch) +Disable diagonal input = Disable diagonal input +Double tap = Double tap +Enable analog stick gesture = Enable analog stick gesture +Enable gesture control = Enable gesture control +Enable standard shortcut keys = Enable standard shortcut keys +frames = frames +Gesture = Gesture +Gesture mapping = Gesture mapping +Glowing borders = Glowing borders +HapticFeedback = Haptic feedback (vibration) +Hide touch analog stick background circle = Hide touch analog stick background circle +Icon = Icon +Ignore gamepads when not focused = Ignore gamepads when not focused +Ignore Windows Key = Disable Windows key +Invert Axes = Invert axes +Invert Tilt along X axis = Invert tilt along X axis +Invert Tilt along Y axis = Invert tilt along Y axis +Keep this button pressed when right analog is pressed = Keep this button pressed when right analog is pressed +Keyboard = Keyboard control settings +L/R Trigger Buttons = L/R trigger buttons +Landscape = Landscape +Landscape Auto = Landscape auto +Landscape Reversed = Landscape reversed +Low end radius = Low end radius +Mouse = Mouse settings +Mouse sensitivity = Mouse sensitivity +Mouse smoothing = Mouse smoothing +Mouse wheel button-release delay = Mouse wheel button-release delay +MouseControl Tip = You can now map mouse in control mapping screen by pressing the 'M' icon. +None (Disabled) = None (disabled) +Off = Off +OnScreen = On-screen touch controls +Portrait = Portrait +Portrait Reversed = Portrait reversed +PSP Action Buttons = PSP action buttons +Rapid fire interval = Rapid fire interval +Raw input = Raw input +Reset to defaults = Reset to defaults +Screen Rotation = Screen rotation +Sensitivity = Sensitivity +Sensitivity (scale) = Sensitivity (scale) +Shape = Shape +Show Touch Pause Menu Button = Show pause menu button +Sticky D-Pad (easier sweeping movements) = Sticky D-Pad (easier sweeping movements) +Swipe = Swipe +Swipe sensitivity = Swipe sensitivity +Swipe smoothing = Swipe smoothing +Thin borders = Thin borders +Tilt control setup = Tilt control setup +Tilt Input Type = Tilt input type +Tilt Sensitivity along X axis = Tilt sensitivity along X axis +Tilt Sensitivity along Y axis = Tilt sensitivity along Y axis +To Calibrate = Hold device at your preferred angle and press "Calibrate". +Toggle mode = Toggle mode +Repeat mode = Repeat mode +Touch Control Visibility = Touch control visibility +Use custom right analog = Use custom right analog +Use Mouse Control = Use mouse control +Visibility = Visibility +Visible = Visible +X = X +Y = Y + +[CwCheats] +Cheats = Cheats +Edit Cheat File = Edit cheat file +Import Cheats = Import from cheat.db +Import from %s = Import from %s +Refresh interval = Refresh interval + +[DesktopUI] +# If your language does not show well with the default font, you can use Font to specify a different one. +# Just add it to your language's ini file and uncomment it (remove the # by Font). +#Font = Trebuchet MS +Font = Rabar_014 +About PPSSPP... = PPSSPP زانیاری دەربارەی +Auto = ئۆتۆماتیکی +Auto Max Quality = بەرزترین کوالیتی ئۆتۆماتیکی +Backend = نیشاندانەوەی باکئێند(بەرنامەکە ریستارت دەکاتەوە) +Bicubic = &Bicubic +Break = شکاندنی یاری +Break on Load = شکاندنی یاری لەکاتی لۆو کردن +Buy Gold = PPSSPP کڕینی گۆلد +Control Mapping... = بەستنەوەی کۆنترۆڵەکان +Copy PSP memory base address = Copy PSP memory base &address +Debugging = &Debug +Deposterize = &Deposterize +Direct3D9 = Direct3D &9 +Direct3D11 = Direct3D &11 +Disassembly = &Disassembly... +Discord = Discord +Display Layout && Effects = شێوازی پیشاندان و ئیفێکتەکان +Display Rotation = خولاندنەوەی شاشە +Dump Next Frame to Log = D&ump next frame to log +Emulation = &Emulation +Enable Cheats = cheats بەکار‌ێنانی +Enable Sound = بەکارکردنی دەنگ +Exit = دەرچوون +Extract File... = گواستنەوەی فایل... +File = فایل +Frame Skipping = Frame پەڕاندنی +Frame Skipping Type = Frame شیوازی پەڕاندنی +Fullscreen = Fu&llscreen +Game Settings = سێتینگی یاریەکە +GE Debugger... = GE debugge&r... +GitHub = Git&Hub +Hardware Transform = &Hardware transform +Help = یارمەتی +Hybrid = &Hybrid +Hybrid + Bicubic = H&ybrid + bicubic +Ignore Illegal Reads/Writes = &Ignore illegal reads/writes +Ignore Windows Key = Ignore Windows key +Keep PPSSPP On Top = &Keep PPSSPP on top +Landscape = ئاسۆیی +Landscape reversed = ئاسۆیی پێچەوانە +Language... = زمان... +Linear = &Linear +Load = &Load... +Load .sym File... = Lo&ad .sym file... +Load Map File... = Load &Map file... +Load State = L&oad state +Load State File... = &Load state file... +Log Console = &Log console +Memory View... = بینینی میمۆری +More Settings... = سێتینگی زیاتر... +Nearest = نزیکترین +Pause when not focused = &Pause when not focused +Restart Graphics = دووبارە ئیش پێ کردنەوەی گرافیکەکان +Skip Buffer Effects = &Skip buffer effects +Off = کوژاندنەوە +Open Chat = کردنەوەی چات +Open Directory... = Open &directory... +Open from MS:/PSP/GAME... = O&pen from MS:/PSP/GAME... +Open Memory Stick = Open &Memory Stick +Open New Instance = Open new instance +OpenGL = &OpenGL +Pause = &Pause +Portrait = Portrait +Portrait reversed = Portrait reversed +PPSSPP Forums = PPSSPP &forums +Recent = &Recent +Record = &Record +Record Audio = Record &audio +Record Display = Record &display +Rendering Mode = Rendering m&ode +Rendering Resolution = &Rendering resolution +Reset = R&eset +Reset Symbol Table = Reset s&ymbol table +Run = &Run +Save .sym File... = Sav&e .sym file... +Save Map File... = &Save map file... +Save State = S&ave state +Save State File... = &Save state file... +Savestate Slot = Saves&tate slot +Screen Scaling Filter = Scr&een scaling filter +Show Debug Statistics = Show debu&g statistics +Show FPS Counter = Show &FPS counter +Skip Number of Frames = Skip number of frames +Skip Percent of FPS = Skip percent of FPS +Smart 2D texture filtering = Smart 2D texture filtering +Stop = &Stop +Switch UMD = Switch UMD +Take Screenshot = &Take screenshot +Texture Filtering = Te&xture filtering +Texture Scaling = &Texture scaling +Use Lossless Video Codec (FFV1) = &Use lossless video codec (FFV1) +Use output buffer for video = Use output buffer for video +VSync = VS&ync +Vulkan = Vulkan +Window Size = &Window size +www.ppsspp.org = Visit www.&ppsspp.org +xBRZ = &xBRZ + +[Developer] +Allocator Viewer = Allocator viewer (Vulkan) +Allow remote debugger = Allow remote debugger +Audio Debug = Audio Debug +Backspace = Backspace +Block address = Block address +By Address = By address +Control Debug = Control Debug +Copy savestates to memstick root = Copy save states to Memory Stick root +Create frame dump = Create frame dump +Create/Open textures.ini file for current game = Create/Open textures.ini file for current game +Current = Current +Debug overlay = Debug overlay +Debug stats = Debug stats +Dev Tools = Development tools +DevMenu = DevMenu +Disabled JIT functionality = Disabled JIT functionality +Draw Frametimes Graph = Draw frametimes graph +Dump Decrypted Eboot = Dump decrypted EBOOT.BIN on game boot +Dump next frame to log = Dump next frame to log +Enable driver bug workarounds = Enable driver bug workarounds +Enable Logging = Enable debug logging +Enter address = Enter address +Fast-forward mode = Fast-forward mode +Fragment = Fragment +FPU = FPU +Framedump tests = Framedump tests +Frame Profiler = Frame profiler +Frame timing = Frame timing +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs +GPU Allocator Viewer = GPU Allocator Viewer +GPU Driver Test = GPU driver test +GPU Profile = GPU profile +GPU log profiler = GPU log profiler +Jit Compare = JIT compare +JIT debug tools = JIT debug tools +Log Dropped Frame Statistics = Log dropped frame statistics +Log Level = Log level +Log View = Log view +Logging Channels = Logging channels +Multi-threaded rendering = Multi-threaded rendering +Next = Next +No block = No block +Off = Off +Prev = Previous +Random = Random +Replace textures = Replace textures +Reset = Reset +Reset limited logging = Reset limited logging +RestoreDefaultSettings = Restore these settings back to their defaults?\nYou can't undo this.\nPlease restart PPSSPP after restoring settings. +RestoreGameDefaultSettings = Are you sure you want to restore the game-specific settings\nback to the PPSSPP defaults? +Resume = بەردەوام بوون +Run CPU Tests = تاقیکردنەوەی سی پی یو ئەنجام بدە +Save new textures = Save new textures +Shader Viewer = Shader viewer +Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs +Show on-screen messages = Show on-screen messages +Stats = Stats +System Information = System information +Texture ini file created = Texture ini file created +Texture Replacement = Texture replacement +Toggle Freeze = Toggle freeze +Touchscreen Test = Touchscreen test +Ubershaders = Ubershaders +Vertex = Vertex +VFPU = VFPU + +[Dialog] +%d ms = %d ms +%d seconds = %d seconds +* PSP res = * PSP res +Active = چالاک +Back = گەڕانەوە +Bottom Center = خوارەوە ناوەڕاست +Bottom Left = خوارەوە چەپ +Bottom Right = خوارەوە ڕاست +Cancel = هەڵوەشاندنەوە +Center = ناوەڕاست +Center Left = ناوەڕاست چەپ +Center Right = لە ناوەڕاستدا ڕاست +Channel: = کەناڵ: +Changing this setting requires PPSSPP to restart. = PPSSPP گۆڕینی ئەم ڕێکخستنە پێویستی بە هەیە کە دووبارە دەستپێبکاتەوە. +Choose PPSSPP save folder = هەڵبژێرە PPSSPP فۆڵدەری خەزن کردنی +Confirm Overwrite = دەتەوێت زانیاریەکان دووبارە بنووسیتەوە لەسەر هەمان شوێن؟ +Confirm Save = ئایا دەتەوێت زانیاریەکان خەزن بکەیت؟ +ConfirmLoad = ئەم زانیاریانا لۆد ئەکەیت؟ +ConnectingAP = پەیوەندی ئەکەین بە خاڵی دەست بە یەک گەستن.\nتکایە بووەستە... +ConnectingPleaseWait = پەیوەندی ئەکەین.\nتکایە بووەستە... +ConnectionName = ناوی پەیوەندی +Copy to clipboard = Copy to clipboard +Corrupted Data = زانیاریەکە تێکچووە +Delete = سڕینەوە +Delete all = سڕینەوەی هەمووی +Delete completed = سڕینەوەکە سەرکەووتوو بوو +DeleteConfirm = زانیارە خەخن کراوە دەسڕدرێتەوە.\nئایا تۆ دڵنیایت لە بەردەوام بوون؟ +DeleteConfirmAll = ئایە تۆ دڵنیایت لە\nسڕینەوەی هەموو زانیاریە خەزنکروەکان بۆ ئەم یاریە؟? +DeleteConfirmGame = ئایا تۆ دڵنیایت کە\nئەم یاریە بسڕیتەوە لە ئامێرەکەت؟ ئەم کارە گەڕانەوەی نییە +DeleteConfirmGameConfig = ئایا تۆ دڵنیایت لە سڕینەوەی سێتینگەکانت بۆ ئەم یاریە؟ +DeleteFailed = نەتوانرا زانیاریەکان بسڕدرێنەوە. +Deleting = دەسڕدرێتەوە\nتکایە چاوەڕوان بە... +Disable All = لە کارخستنی هەمووی +Disabled = لە کارخرا +Dumps = Dumps +Edit = دەستکاری کردن +Enable All = بەکارپێکردنی هەمووی +Enabled = بەکارخرا +Enter = Enter +Failed to log in, check your username and password. = Failed to log in, check your username and password. +Failed to connect to server, check your internet connection. = Failed to connect to server, check your internet connection. +Filter = Filter +Finish = تەواوکردن +GE Frame Dumps = GE Frame Dumps +Grid = Grid +Inactive = ناچالاک +Installing... = Installing... +InternalError = An internal error has occurred. +Links = Links +Load = Load +Load completed = Load completed. +Loading = Loading\nPlease Wait... +LoadingFailed = Unable to load data. +Log in = Log in +Log out = Log out +Logging in... = Logging in... +Logged in! = Logged in! +More information... = More information... +Move = Move +Move Up = Move Up +Move Down = Move Down +Network Connection = Network Connection +NEW DATA = NEW DATA +No = No +None = None +ObtainingIP = Obtaining IP address.\nPlease wait... +OK = OK +Old savedata detected = Old savedata detected +Options = Options +Password = وشەی نهێنی +Remove = لابردن +Reset = Reset +Resize = گۆڕینی قەبارە +Restart = Restart +Retry = دووبارە هەوڵدانەوە +Save = خەزن کردن +Save completed = خەزن کرا +Saving = خەزن دەکرێت\nتکایە چاوەڕوان بە... +SavingFailed = ناتوانرێت زانیاریەکان خەزن بکرێت +Search = گەڕان +seconds, 0:off = چرکەکان، 0 = کوژاوە +Select = دەستنیشان کردن +Settings = سێتینگەکان +Shift = Shift +Skip = پەڕاندن +Snap = Snap +Space = Space +SSID = SSID +Submit = Submit +Supported = Supported +There is no data = زانیاری بوونی نیە لەسەری +Toggle All = Toggle all +Toggle List = Toggle list +Top Center = Top center +Top Left = Top left +Top Right = Top right +Unsupported = Unsupported +Username = Username +When you save, it will load on a PSP, but not an older PPSSPP = When you save, it will load on a PSP, but not an older PPSSPP +When you save, it will not work on outdated PSP Firmware anymore = When you save, it will not work on outdated PSP firmware anymore +Yes = بەڵێ +Zoom = نزیک کردنەوە + +[Error] +7z file detected (Require 7-Zip) = File is compressed (7z).\nPlease decompress first (try 7-Zip or WinRAR). +A PSP game couldn't be found on the disc. = A PSP game couldn't be found on the disc. +Cannot boot ELF located outside mountRoot. = Cannot boot ELF located outside mountRoot. +Could not save screenshot file = Could not save screenshot file. +D3D9or11 = Direct3D 9? (or "no" for Direct3D 11) +D3D11CompilerMissing = D3DCompiler_47.dll not found. Please install. Or press Yes to try again using Direct3D 9 instead. +D3D11InitializationError = Direct3D 11 initialization error +D3D11Missing = Your operating system version does not include D3D11. Please run Windows Update.\n\nPress Yes to try again using Direct3D 9 instead. +D3D11NotSupported = Your GPU does not appear to support Direct3D 11.\n\nWould you like to try again using Direct3D 9 instead? +Disk full while writing data = Disk full while writing data. +ELF file truncated - can't load = ELF file truncated - can't load +Error loading file = Could not load game. +Error reading file = Error reading file. +Failed initializing CPU/Memory = Failed initializing CPU or memory +Failed to load executable: = Failed to load executable: +File corrupt = File corrupt +Game disc read error - ISO corrupt = Game disc read error: ISO corrupt. +GenericAllStartupError = PPSSPP failed to start up with any graphics backend. Try upgrading your graphics and other drivers. +GenericBackendSwitchCrash = PPSSPP crashed while starting.\n\nThis usually means a graphics driver problem. Try upgrading your graphics drivers.\n\nGraphics backend has been switched: +GenericDirect3D9Error = Failed initializing graphics. Try upgrading your graphics drivers and DirectX 9 runtime.\n\nWould you like to try switching to OpenGL?\n\nError message: +GenericGraphicsError = Graphics Error +GenericOpenGLError = Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to DirectX 9?\n\nError message: +GenericVulkanError = Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to OpenGL?\n\nError message: +InsufficientOpenGLDriver = Insufficient OpenGL driver support detected!\n\nYour GPU reports that it does not support OpenGL 2.0. Would you like to try using DirectX instead?\n\nDirectX is currently compatible with less games, but on your GPU it may be the only choice.\n\nVisit the forums at https://forums.ppsspp.org for more information.\n\n +Just a directory. = Just a directory. +Missing key = Missing key +MsgErrorCode = Error code: +MsgErrorSavedataDataBroken = Save data was corrupt. +MsgErrorSavedataMSFull = Memory Stick full. Check your storage space. +MsgErrorSavedataNoData = Warning: no save data was found. +MsgErrorSavedataNoMS = Memory Stick not inserted. +No EBOOT.PBP, misidentified game = No EBOOT.PBP, misidentified game. +Not a valid disc image. = Not a valid disc image. +OpenGLDriverError = OpenGL driver error +PPSSPP doesn't support UMD Music. = PPSSPP doesn't support UMD Music. +PPSSPP doesn't support UMD Video. = PPSSPP doesn't support UMD Video. +PPSSPP plays PSP games, not PlayStation 1 or 2 games. = PPSSPP plays PSP games, not PlayStation 1 or 2 games. +PPSSPPDoesNotSupportInternet = PPSSPP currently does not support connecting to the Internet for DLC, PSN, or game updates. +PS1 EBOOTs are not supported by PPSSPP. = PS1 EBOOTs are not supported by PPSSPP. +PSX game image detected. = File is a MODE2 image. PPSSPP doesn't support PS1 games. +RAR file detected (Require UnRAR) = File is compressed (RAR).\nPlease decompress first (try UnRAR). +RAR file detected (Require WINRAR) = File is compressed (RAR).\nPlease decompress first (try WinRAR). +Running slow: try frameskip, sound is choppy when slow = Running slow: try frameskip, sound is choppy when slow +Running slow: Try turning off Software Rendering = Running slow: try turning off "software rendering" +Save encryption failed. This save won't work on real PSP = Save encryption failed. This save won't work on real PSP +textures.ini filenames may not be cross-platform = "textures.ini" filenames may not be cross-platform. +This is a saved state, not a game. = This is a saved state, not a game. +This is save data, not a game. = This is save data, not a game. +Unable to create cheat file, disk may be full = Unable to create cheat file, disk may be full. +Unable to initialize rendering engine. = Unable to initialize rendering engine. +Unable to write savedata, disk may be full = Unable to write savedata, disk may be full. +Warning: Video memory FULL, reducing upscaling and switching to slow caching mode = Warning: Video memory FULL, reducing upscaling and switching to slow caching mode. +Warning: Video memory FULL, switching to slow caching mode = Warning: Video memory FULL, switching to slow caching mode. +ZIP file detected (Require UnRAR) = File is compressed (ZIP).\nPlease decompress first (try UnRAR). +ZIP file detected (Require WINRAR) = File is compressed (ZIP).\nPlease decompress first (try WinRAR). + +[Game] +Asia = ئاسیا +Calculate CRC = Calculate CRC +Click "Calculate CRC" to verify ISO = Click "Calculate CRC" to verify ISO +ConfirmDelete = سڕینەوە +CRC checksum does not match, bad or modified ISO = CRC checksum does not match, bad or modified ISO +Create Game Config = درووستکردنی سێتینگی تایبەت بە یاریەکە +Create Shortcut = Create shortcut +Delete Game = سڕینەوەی یاریەکە +Delete Game Config = سڕینەوەی سێتینگی تایبەت بە یاریەکە +Delete Save Data = سڕینەوەی زانیاری خەزن کراوی یاریەکە +Europe = ئەوروپا +File size incorrect, bad or modified ISO = بریگەی فایلەکە هەڵەیە، ISO هەڵەیە یان دەستکاری کراوە +Game = یاری +Game ID unknown - not in the ReDump database = Game ID unknown - not in the ReDump database +Game Settings = سێتینگەکانی یاریەکە +Homebrew = Homebrew +Hong Kong = هۆنگ کۆنگ +InstallData = Data install +ISO OK according to the ReDump project = ISO OK according to the ReDump project +Japan = یابان +Korea = کۆریا +MB = MB +One moment please... = تکایە یەک چرکە... +Play = دەست کردن بە یاری +Remove From Recent = لابردن لە بەشی "Recent" +SaveData = Savedata +Setting Background = Setting background +Show In Folder = نیشاندانەوە لە فۆڵدەر +Time Played: %1h %2m %3s = Time Played: %1h %2m %3s +Uncompressed = Uncompressed +USA = USA +Use UI background = دا UI بەکارهێنانی لە باکگراوند + +[Graphics] +% of the void = % of the void +% of viewport = % of viewport +%, 0:unlimited = %, 0 = unlimited +(supersampling) = (supersampling) +(upscaling) = (upscaling) +1x PSP = 1× PSP +2x = 2× +2x PSP = 2× PSP +3x = 3× +3x PSP = 3× PSP +4x = 4× +4x PSP = 4x PSP (1080p) +5x = 5× +5x PSP = 5× PSP +6x PSP = 6× PSP +7x PSP = 7× PSP +8x = 8× +8x PSP = 8x PSP (4K) +9x PSP = 9× PSP +10x PSP = 10× PSP +16x = 16× +AdrenoTools driver manager = AdrenoTools driver manager +Aggressive = Aggressive +Alternative Speed = خێرایی جێگرەوە(بە ٪ دیاری بکە، 0 = بێسنوور) +Alternative Speed 2 = خێرایی جێگرەوەی دووهەم(بە ٪ دیاری بکە، 0 = بێسنوور) +Anisotropic Filtering = Anisotropic filtering +Antialiasing (MSAA) = Antialiasing (MSAA) +Aspect Ratio = Aspect Ratio +Auto = Auto +Auto (1:1) = Auto (1:1) +Auto FrameSkip = Auto frameskip +Auto Max Quality = Auto Max Quality +Auto Scaling = Auto scaling +Backend = Backend +Balanced = Balanced +Bicubic = Bicubic +Copy to texture = Copy to texture +Current GPU Driver = Current GPU Driver +Default GPU driver = Default GPU driver +Disable culling = Disable culling +Display layout & effects = Display layout & effects +Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 +Drivers = Drivers +GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +Both = Both +Buffer graphics commands (faster, input lag) = Buffer graphics commands (faster, input lag) +BufferedRenderingRequired = Warning: This game is not compatible with "Skip buffer effects" +Camera = Camera +Camera Device = Camera device +Cardboard Screen Size = Screen size (in % of the viewport) +Cardboard Screen X Shift = X shift (in % of the blank space) +Cardboard Screen Y Shift = Y shift (in % of the blank space) +Cardboard VR Settings = Google Cardboard VR settings +Cheats = Cheats +Debugging = Debugging +DefaultCPUClockRequired = Warning: This game requires the CPU clock to be set to default. +Deposterize = Deposterize +Deposterize Tip = Fixes visual banding glitches in upscaled textures +Device = Device +Direct3D 9 = Direct3D 9 +Direct3D 11 = Direct3D 11 +Disabled = Disabled +Display Resolution (HW scaler) = Display resolution (HW scaler) +Enable Cardboard VR = Enable Cardboard VR +FPS = FPS +Frame Rate Control = Framerate control +Frame Skipping = Frame skipping +Frame Skipping Type = Frame skipping type +FullScreen = Fullscreen +Geometry shader culling = Geometry shader culling +Hack Settings = Hack settings (may cause glitches) +Hardware Tessellation = Hardware tessellation +Hardware Transform = Hardware transform +hardware transform error - falling back to software = Hardware transform error, falling back to software +HardwareTessellation Tip = Uses hardware to make curves +High = High +Hybrid = Hybrid +Hybrid + Bicubic = Hybrid + Bicubic +Ignore camera notch when centering = Ignore camera notch when centering +Install custom driver... = Install custom driver... +Integer scale factor = Integer scale factor +Internal Resolution = Internal resolution +Lazy texture caching = Lazy texture caching (speedup) +Lazy texture caching Tip = Faster, but can cause text problems in a few games +Linear = Linear +Low = Low +LowCurves = Spline/Bezier curves quality +LowCurves Tip = Only used by some games, controls smoothness of curves +Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) +Manual Scaling = Manual scaling +Medium = Medium +Mirror camera image = Mirror camera image +Mode = Mode +Must Restart = You must restart PPSSPP for this change to take effect. +Native device resolution = Native device resolution +Nearest = Nearest +No (default) = No (default) +No buffer = No buffer +Same as Rendering resolution = Same as Rendering resolution +Show Battery % = Show Battery % +Show Speed = Show Speed +Skip = Skip +Skip Buffer Effects = Skip buffer effects +None = None +Number of Frames = Number of frames +Off = Off +OpenGL = OpenGL +Overlay Information = Overlay information +Partial Stretch = Partial stretch +Percent of FPS = Percent of FPS +Performance = Performance +Postprocessing shaders = Postprocessing shaders +Recreate Activity = Recreate activity +Render all frames = Render all frames +Render duplicate frames to 60hz = Render duplicate frames to 60 Hz +RenderDuplicateFrames Tip = Can make framerate smoother in games that run at lower framerates +Rendering Mode = Rendering mode +Rendering Resolution = Rendering resolution +RenderingMode NonBuffered Tip = Faster, but nothing may draw in some games +Rotation = Rotation +Safe = Safe +Screen Scaling Filter = Screen scaling filter +Show Debug Statistics = Show debug statistics +Show FPS Counter = Show FPS counter +Skip GPU Readbacks = Skip GPU Readbacks +Smart 2D texture filtering = Smart 2D texture filtering +Software Rendering = Software rendering (slow, accurate) +Software Skinning = Software skinning +SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games +Speed = Speed +Speed Hacks = Speed Hacks (can cause rendering errors!) +Stereo display shader = Stereo display shader +Stereo rendering = Stereo rendering +Stretch = Stretch +Texture Filter = Texture filtering +Texture Filtering = Texture filtering +Texture replacement pack activated = Texture replacement pack activated +Texture Scaling = Texture scaling +Texture Shader = Texture shader +The chosen ZIP file doesn't contain a valid driver = The chosen ZIP file doesn't contain a valid driver +Turn off Hardware Tessellation - unsupported = Turn off "hardware tessellation": unsupported +Unlimited = Unlimited +Up to 1 = Up to 1 +Up to 2 = Up to 2 +Upscale Level = Upscale level +Upscale Type = Upscale type +UpscaleLevel Tip = CPU heavy - some scaling may be delayed to avoid stutter +Use all displays = Use all displays +VSync = VSync +Vulkan = Vulkan +Window Size = Window size +xBRZ = xBRZ + +[InstallZip] +Data to import = Data to import +Delete ZIP file = Delete ZIP file +Existing data = Existing data +Install = Install +Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder +Install textures from ZIP file? = Install textures from ZIP file? +Installation failed = Installation failed +Installed! = Installed! +Texture pack doesn't support install = Texture pack doesn't support install +Zip archive corrupt = ZIP archive corrupt +Zip file does not contain PSP software = ZIP file does not contain PSP software + +[KeyMapping] +Allow combo mappings = Allow combo mappings +Autoconfigure = Auto configure +Autoconfigure for device = Autoconfigure for device +Bind All = Bind All +Clear All = Clear all +Combo mappings are not enabled = Combo mappings are not enabled +Control modifiers = Control modifiers +Default All = Restore defaults +Emulator controls = Emulator controls +Extended PSP controls = Extended PSP controls +Map a new key for = Map a new key for +Map Key = Map key +Map Mouse = Map mouse +Replace = Replace +Show PSP = Show PSP +Standard PSP controls = Standard PSP controls +Strict combo input order = Strict combo input order +You can press ESC to cancel. = You can press Esc to cancel. + +[MainMenu] +Browse = گەڕان... +Buy PPSSPP Gold = گۆلد بکڕە PPSSPP +Choose folder = فۆڵدەرێک هەڵبژێرە +Credits = لیستی کرێدیت +PPSSPP Homebrew Store = PPSSPP Homebrew Store +Exit = دەرچوون +Game Settings = سێتینگ +Games = یاریەکان +Give PPSSPP permission to access storage = بدە کە دەسەڵاتی خەزن کردنی هەبێت PPSSPP ڕێگە بە +Homebrew & Demos = یاری دێمۆ و دروستکراوە بچووکەکان +How to get games = چۆن یاریم دەست بکەوێت؟ +How to get homebrew & demos = How can I get homebrew & demos? +Load = Load... +Loading... = Loading... +PinPath = Pin +PPSSPP can't load games or save right now = PPSSPP can't load games or save right now +Recent = دوایین یاریەکان +SavesAreTemporary = PPSSPP is saving in temporary storage +SavesAreTemporaryGuidance = Extract PPSSPP somewhere to save permanently +SavesAreTemporaryIgnore = Ignore warning +UnpinPath = Unpin +UseBrowseOrLoad = بۆ هەڵبژاردنی فایلێک (Load) بەکاربێنە بۆ هەڵبژاردنی فۆڵدەرێک، یان (Browse) +www.ppsspp.org = www.ppsspp.org + +[MainSettings] +Audio = دەنگ +Controls = کۆنترۆڵەکان +Graphics = گرافیکەکان +Networking = نێتوۆرک +System = سیستەم +Tools = ئامرازەکان +Search = گەڕان + +[MappableControls] +Alt speed 1 = Alt speed 1 +Alt speed 2 = Alt speed 2 +An.Down = Analog Down +An.Left = Analog Left +An.Right = Analog Right +An.Up = Analog Up +Analog limiter = Analog limiter +Analog speed = Analog speed +Analog Stick = Analog stick +Audio/Video Recording = Audio/Video recording +AxisSwap = Axis swap +Circle = Circle +Cross = Cross +Custom %d = Custom %d +D-pad down = D-pad down +D-pad left = D-pad left +D-pad right = D-pad right +D-pad up = D-pad up +DevMenu = DevMenu +Double tap button = Double tap button +Down = Dpad Down +Dpad = Dpad +Exit App = Exit App +Frame Advance = Frame advance +Hold = Hold +Home = Home +L = L +Left = Dpad Left +Load State = Load state +Mute toggle = Mute toggle +Next Slot = Next slot +None = None +Note = Note +OpenChat = Open chat +Pause = Pause +Previous Slot = Previous Slot +R = R +RapidFire = Rapid-fire +Record = Record +Remote hold = Remote hold +Rewind = Rewind +Right = Dpad Right +Right Analog Stick = Right Analog Stick +RightAn.Down = RightAn.Down +RightAn.Left = RightAn.Left +RightAn.Right = RightAn.Right +RightAn.Up = RightAn.Up +Rotate Analog (CCW) = Rotate analog (CCW) +Rotate Analog (CW) = Rotate analog (CW) +Save State = Save state +Screen = Screen +Screenshot = Screenshot +Select = Select +SpeedToggle = Speed toggle +Square = Square +Start = Start +Swipe Down = Swipe Down +Swipe Left = Swipe Left +Swipe Right = Swipe Right +Swipe Up = Swipe Up +tap to customize = tap to customize +Texture Dumping = Texture dumping +Texture Replacement = Texture replacement +Toggle Fullscreen = Toggle fullscreen +Toggle mode = Toggle mode +Toggle mouse input = Toggle mouse input +Toggle touch controls = Toggle touch controls +Toggle WLAN = Toggle WLAN +Triangle = Triangle +Fast-forward = Fast-forward +Up = Dpad Up +Vol + = Vol + +Vol - = Vol - +Wlan = WLAN +Display Landscape = Display Landscape +Display Landscape Reversed = Display Landscape Reversed +Display Portrait = Display Portrait +Display Portrait Reversed = Display Portrait Reversed + +[Networking] +AdHoc Server = Ad hoc server +AdhocServer Failed to Bind Port = Ad hoc server failed to bind port +AM: Data from Unknown Port = AM: Data from Unknown Port +Auto = Auto +Change Mac Address = Change MAC address +ChangeMacSaveConfirm = Generate a new MAC address? +ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. +Change proAdhocServer Address = Change PRO ad hoc server IP address (localhost = multiple instances) +Chat = Chat +Chat Button Position = Chat button position +Chat Here = Chat here +Chat message = Chat message +Chat Screen Position = Chat screen position +Disconnected from AdhocServer = Disconnected from ad hoc server +DNS Error Resolving = DNS error resolving +Enable built-in PRO Adhoc Server = Enable built-in PRO ad hoc server +Enable network chat = Enable network chat +Enable networking = Enable networking/WLAN +Enable UPnP = Enable UPnP (need a few seconds to detect) +EnableQuickChat = Enable quick chat +Enter a new PSP nickname = Enter a new PSP nickname +Enter Quick Chat 1 = Enter quick chat 1 +Enter Quick Chat 2 = Enter quick chat 2 +Enter Quick Chat 3 = Enter quick chat 3 +Enter Quick Chat 4 = Enter quick chat 4 +Enter Quick Chat 5 = Enter quick chat 5 +Error = Error +Failed to Bind Localhost IP = Failed to bind localhost IP +Failed to Bind Port = Failed to bind port +Failed to connect to Adhoc Server = Failed to connect to ad hoc server +Forced First Connect = Forced first connect (faster connect) +GM: Data from Unknown Port = GM: Data from Unknown Port +Hostname = Hostname +Invalid IP or hostname = Invalid IP or hostname +Minimum Timeout = Minimum timeout (override in ms, 0 = default) +Misc = Miscellaneous (default = PSP compatibility) +Network connected = Network connected +Network initialized = Network initialized +Please change your Port Offset = Please change your port offset +Port offset = Port offset (0 = PSP compatibility) +Open PPSSPP Multiplayer Wiki Page = Open PPSSPP Multiplayer Wiki Page +proAdhocServer Address: = Ad hoc server address: +Quick Chat 1 = Quick chat 1 +Quick Chat 2 = Quick chat 2 +Quick Chat 3 = Quick chat 3 +Quick Chat 4 = Quick chat 4 +Quick Chat 5 = Quick chat 5 +QuickChat = Quick chat +Randomize = Randomize +Send = Send +Send Discord Presence information = Send Discord "Rich Presence" information +Unable to find UPnP device = Unable to find UPnP device +UPnP (port-forwarding) = UPnP (port forwarding) +UPnP need to be reinitialized = UPnP need to be reinitialized +UPnP use original port = UPnP use original port (enabled = PSP compatibility) +UseOriginalPort Tip = May not work for all devices or games, see wiki. +Validating address... = Validating address... +WLAN Channel = WLAN channel +You're in Offline Mode, go to lobby or online hall = You're in offline mode, go to lobby or online hall + +[Pause] +Cheats = Cheats +Continue = بەردەوام بە لە یاری +Create Game Config = سێتینگ درووست بکە بۆ ئەم یاریە +Delete Game Config = سێتینگی ئەم یاریە بسڕەوە +Exit to menu = چوونە دەرەوە بۆ مێنیو +Game Settings = سێتینگی یاریەکە +Load State = Load state +Rewind = Rewind +Save State = Save state +Settings = سێتینگ +Switch UMD = Switch UMD +Undo last load = Undo last load +Undo last save = Undo last save + +[PostShaders] +(duplicated setting, previous slider will be used) = (duplicated setting, previous slider will be used) +4xHqGLSL = 4xHQ pixel art upscaler +5xBR = 5xBR pixel art upscaler +5xBR-lv2 = 5xBR-lv2 pixel art upscaler +AAColor = AA-Color +Amount = Amount +Aspect = Aspect +Black border = Black border +Bloom = Bloom +BloomNoBlur = Bloom (no blur) +Brightness = Brightness +Cartoon = Cartoon +ColorCorrection = Color correction +ColorPreservation = Color preservation +Contrast = Contrast +CRT = CRT scanlines +FXAA = FXAA Antialiasing +Gamma = Gamma +GreenLevel = Green level +FakeReflections = FakeReflections +Intensity = Intensity +LCDPersistence = LCD Persistence +Natural = Natural Colors +NaturalA = Natural Colors (no blur) +Off = Off +Power = Power +PSPColor = PSP color +RedBlue = Red/Blue glasses +Saturation = Saturation +Scanlines = Scanlines (CRT) +Sharpen = Sharpen +SideBySide = Side by side (SBS) +SSAA(Gauss) = Supersampling AA (Gauss) +Strength = Strength +Tex4xBRZ = 4xBRZ +TexMMPX = MMPX +UpscaleBicubic = UpscaleBicubic +UpscaleSpline36 = Spline36 Upscaler +VideoSmoothingAA = Video Smoothing AA +Vignette = Vignette +Animation speed (0 -> disable) = Animation speed (0 -> disable) +CatmullRom = Bicubic (Catmull-Rom) Upscaler +MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler + +[PSPCredits] +all the forum mods = all the forum mods +build server = build server +Buy Gold = Buy Gold +check = Also check out Dolphin, the best Wii/GC emu around: +CheckOutPPSSPP = Check out PPSSPP, the awesome PSP emulator: https://www.ppsspp.org/ +contributors = Contributors: +created = درووست کراوە لەلایەن +Discord = Discord +info1 = PPSSPP is intended for educational purposes only. +info2 = Please make sure that you own the rights to any games +info3 = you play by owning the UMD or by buying the digital +info4 = download from the PSN store on your real PSP. +info5 = PSP is a trademark by Sony, Inc. +iOS builds = iOS builds +license = Free software under GPL 2.0+ +list = compatibility lists, forums, and development info +PPSSPP Forums = PPSSPP فۆڕمەکانی +Privacy Policy = سیاسەتی پاراستنی نهێنی +Share PPSSPP = بڵاو بکەرەوە PPSSPP +specialthanks = سوپاسی تایبەت بۆ: +specialthanksKeithGalocy = at NVIDIA (hardware, advice) +specialthanksMaxim = for his amazing Atrac3+ decoder work +testing = testing +this translation by = ئەم وەرگێڕانە لەلایەن: +title = A fast and portable PSP emulator +tools = Free tools used: +# Add translators or contributors who translated PPSSPP into your language here. +# Add translators1-6 for up to 6 lines of translator credits. +# Leave extra lines blank. 4 contributors per line seems to look best. +translators1 = MrYadro, mgaver, VIRGINKLM, raven02 +translators2 = sum2012, vnctdj, unknownbrackets, ufdada +translators3 = The Dax, wuspring, hrydgard, adrian17 +translators4 = papel, Mhamad99 +translators5 = +translators6 = +Twitter @PPSSPP_emu = Twitter @PPSSPP_emu +website = Check out the website: +written = Written in C++ for speed and portability + +[MemStick] +Already contains PSP data = Already contains PSP data +Cancelled - try again = Cancelled - try again +Checking... = Checking... +Create or Choose a PSP folder = Create or Choose a PSP folder +Current = Current +DataCanBeShared = Data can be shared between PPSSPP regular/Gold +DataCannotBeShared = Data CANNOT be shared between PPSSPP regular/Gold! +DataWillBeLostOnUninstall = Warning! Data will be lost when you uninstall PPSSPP! +DataWillStay = Data will stay even if you uninstall PPSSPP +Deleting... = Deleting... +Done! = Done! +EasyUSBAccess = Easy USB access +Failed to move some files! = Failed to move some files! +Failed to save config = Failed to save config +Free space = Free space +Manually specify PSP folder = Manually specify PSP folder +MemoryStickDescription = Choose where to keep PSP data (Memory Stick) +Move Data = Move Data +Selected PSP Data Folder = Selected PSP Data Folder +Skip for now = Skip for now +No data will be changed = No data will be changed +PPSSPP will restart after the change = PPSSPP will restart after the change +Starting move... = Starting move... +That folder doesn't work as a memstick folder. = That folder doesn't work as a memstick folder. +USBAccessThrough = USB access through Android/data/org.ppsspp.ppsspp/files +USBAccessThroughGold = USB access through Android/data/org.ppsspp.ppssppgold/files +Use App Private Data = Use App Private Data +Use PSP folder at root of storage = Use PSP folder at root of storage +Welcome to PPSSPP! = Welcome to PPSSPP! +WhatsThis = What's this? + +[PSPSettings] +Auto = Auto +Chinese (simplified) = چینی (سادۆکراو) +Chinese (traditional) = چینی (تەقلیدی) +Dutch = هۆڵەندی +English = ئینگلیزی +French = فەڕەنسی +Game language = زمانی یاری +German = ئەڵمانی +Italian = ئیتاڵی +Japanese = یابانی +Korean = کۆری +Games often don't support all languages = یاریەکان زۆربەی کات پاڵپشتی هەموو زمانەکان ناکەن +Portuguese = پورتوگالی +Russian = ڕووسی +Spanish = ئیسپانی + +[RemoteISO] +Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share +Local Server Port = Local server port +Manual Mode Client = Manually configure client +Not currently sharing = Not currently sharing +Remote disc streaming = Remote disc streaming +Remote Port = Remote port +Remote Server = Remote server +Remote Subdirectory = Remote subdirectory +RemoteISODesc = Games in your "Recent" list will be shared +RemoteISOLoading = Connected, loading game list... +RemoteISOScanning = Scanning... Click "share games" on your server device +RemoteISOScanningTimeout = Scanning... check your desktop's firewall settings +RemoteISOWifi = Note: Connect both devices to the same Wi-Fi network +RemoteISOWinFirewall = WARNING: Windows Firewall is blocking sharing +Settings = Settings +Share Games (Server) = Share games (server) +Share on PPSSPP startup = Share on PPSSPP startup +Show Remote tab on main screen = Show Remote tab on main screen +Stop Sharing = Stop sharing +Stopping.. = Stopping... + +[Reporting] +Bad = Bad +FeedbackCRCCalculating = Disc CRC: Calculating... +FeedbackCRCValue = Disc CRC: %1 +FeedbackDelayInfo = Your data is being submitted in the background. +FeedbackDesc = How's the emulation? Let us and the community know! +FeedbackDisabled = Compatibility server reports must be enabled. +FeedbackIncludeCRC = Note: Battery will be used to send a disc CRC +FeedbackIncludeScreen = Include a screenshot +FeedbackSubmitDone = Your data has been submitted. +FeedbackSubmitFail = Could not submit data to server. Try updating PPSSPP. +FeedbackThanks = Thanks for your feedback! +Gameplay = Gameplay +Graphics = Graphics +Great = Great +In-game = In-game +In-game Description = Gets into gameplay, but too buggy to complete +Menu/Intro = Menu/Intro +Menu/Intro Description = Can't get into the game itself +Nothing = Nothing +Nothing Description = Completely broken +OK = OK +Open Browser = Open reporting website +Overall = Overall +Perfect = Perfect +Perfect Description = Flawless emulation for the entire game - great! +Plays = Plays +Plays Description = Fully playable but might be with glitches +ReportButton = Report feedback +Show disc CRC = Show disc CRC +Speed = Speed +Submit Feedback = Submit feedback +SuggestionConfig = See reports on website for good settings. +SuggestionCPUSpeed0 = Disable locked CPU speed setting. +SuggestionDowngrade = Downgrade to an older PPSSPP version (please report this bug). +SuggestionsFound = Other users have reported better results. Tap "View Feedback" for more detail. +SuggestionsNone = This game isn't working for other users too. +SuggestionsWaiting = Submitting and checking other users feedback... +SuggestionUpgrade = Upgrade to a newer PPSSPP build. +SuggestionVerifyDisc = Check your ISO is a good copy of your disc. +Unselected Overall Description = How well does this game emulate? +View Feedback = View all feedbacks + +[Savedata] +Date = Date +Filename = Filename +No screenshot = No screenshot +None yet. Things will appear here after you save. = None yet. Things will appear here after you save. +Nothing matching '%1' was found. = Nothing matching '%1' was found. +Save Data = Save data +Save States = Save states +Savedata Manager = Savedata manager +Showing matches for '%1'. = Showing matches for '%1'. +Size = Size + +[Screen] +Cardboard VR OFF = Cardboard VR off +Chainfire3DWarning = WARNING: Chainfire3D detected, may cause problems. +ExtractedISOWarning = Extracted ISOs often don't work.\nPlay the ISO file directly. +Failed to load state = Failed to load state +Failed to save state = Failed to save state +fixed = Speed: alternate +GLToolsWarning = WARNING: GLTools detected, may cause problems. +In menu = In menu +Loaded State = State loaded +Loaded. Save in game, restart, and load for less bugs. = Loaded. Save in game, restart, and load for less bugs. +Loaded. Game may refuse to save over different savedata. = Loaded. Game may refuse to save over different savedata. +Loaded. Game may refuse to save over newer savedata. = Loaded. Game may refuse to save over newer savedata. +LoadStateDoesntExist = Failed to load state: Savestate doesn't exist! +LoadStateWrongVersion = Failed to load state: Savestate is for an older version of PPSSPP! +norewind = No rewind save states available. +Playing = Playing +PressESC = Press ESC to open the pause menu. +replaceTextures_false = Textures no longer are being replaced. +replaceTextures_true = Texture replacement is enabled. +Saved State = State saved +saveNewTextures_false = Texture saving was disabled. +saveNewTextures_true = Textures will now be saved to your storage. +SpeedCustom2 = Speed: alternate 2 +standard = Speed: standard +State load undone = State load undone +Untitled PSP game = Untitled PSP game + +[Store] +Connection Error = Connection error +Install = Install +Installed = Installed +Launch Game = Launch game +License = License +Loading... = Loading... +MB = MB +Size = Size +Uninstall = Uninstall +Website = Website + +[SysInfo] +%d (%d per core, %d cores) = %d (%d per core, %d cores) +%d bytes = %d bytes +%d Hz = %d Hz +%0.2f Hz = %0.2f Hz +(none detected) = (none detected) +3D API = 3D API +ABI = ABI +API Version = API version +Audio Information = Audio information +Board = Board +Build Config = Build config +Build Configuration = Build Configuration +Built by = Built by +Compressed texture formats = Compressed texture formats +Core Context = Core context +Cores = Cores +CPU Extensions = CPU extensions +CPU Information = CPU زانیاری +CPU Name = Name +D3DCompiler Version = D3DCompiler version +Debug = Debug +Debugger Present = Debugger present +Depth buffer format = Depth buffer format +Device Info = Device info +Directories = Directories +Display Information = Display information +DPI = DPI +Driver bugs = Driver bugs +Driver Version = Driver version +EGL Extensions = EGL extensions +Frames per buffer = Frames per buffer +GPU Flags = GPU Flags +GPU Information = GPU زانیاری +High precision float range = High precision float range +High precision int range = High precision int range +Icon cache = Icon cache +Instance = Instance +JIT available = JIT available +Lang/Region = زمان/هەرێم +Memory Page Size = Memory page size +Native resolution = Native resolution +No GPU driver bugs detected = No GPU driver bugs detected +OGL Extensions = OGL extensions +OpenGL ES 2.0 Extensions = OpenGL ES 2.0 extensions +OpenGL ES 3.0 Extensions = OpenGL ES 3.0 extensions +OpenGL Extensions = OpenGL extensions +Optimal frames per buffer = Optimal frames per buffer +Optimal sample rate = Optimal sample rate +OS Information = OS information +Pixel resolution = Pixel resolution +PPSSPP build = PPSSPP build +Present modes = Present modes +Refresh rate = Refresh rate +Release = Release +RW/RX exclusive = RW/RX exclusive +Sample rate = Sample rate +Screen notch insets = Screen notch insets +Shading Language = Shading language +Storage = Storage +Sustained perf mode = Sustained perf mode +System Information = System information +System Name = Name +System Version = System version +Threads = Threads +UI resolution = UI resolution +Vendor = Vendor +Vendor (detected) = Vendor (detected) +Version Information = Version information +Vulkan Extensions = Vulkan extensions +Vulkan Features = Vulkan features +Display Color Formats = Display Color Formats + +[System] +(broken) = (broken) +12HR = 12 کاتژمێری +24HR = 24 کاتژمێری +App switching mode = App switching mode +Auto = Auto +Auto Load Savestate = Auto load savestate +AVI Dump started. = AVI dump started +AVI Dump stopped. = AVI dump stopped +Cache ISO in RAM = Cache full ISO in RAM +Change CPU Clock = Change emulated PSP's CPU clock (unstable) +CPU Core = CPU core +Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins +JIT using IR = JIT using IR +Loaded plugin: %1 = Loaded plugin: %1 +Memory Stick folder = فۆڵدەری میمۆری +Memory Stick size = قەبارەی میمۆری +Change Nickname = گۆڕینی نازناو +ChangingMemstickPath = Save games, save states, and other data will not be copied to this folder.\n\nChange the Memory Stick folder? +ChangingMemstickPathInvalid = That path couldn't be used to save Memory Stick files. +Cheats = Cheats +Clear Recent = سڕینەوەی "دوایین یاریەکان" +Clear Recent Games List = "دوایین یاریەکان" سڕینەوەی لیستی +Clear UI background = UI لابردنی باکگراوندی +Confirmation Button = دوگمەی پشتڕاستکردنەوە(Confirm) +Date Format = Date format +Day Light Saving = Daylight savings +DDMMYYYY = DDMMYYYY +Decrease size = کەم کردنەوەی قەبارە +Developer Tools = Developer tools +Display Extra Info = زانیاری زیادە پیشان بدە +Display Games on a grid = نیشاندانەوەی "یاریەکان" لەسەر خشتەیەک +Display Homebrew on a grid = نیشاندانەوەی "دێمۆ و دروستکراوە بچووکەکان" لەسەر خشتەیەک +Display Recent on a grid = نیشاندانەوەی "دوایین یاریەکان" لەسەر خشتەیەک +Emulation = Emulation +Enable Cheats = Enable cheats +Enable Compatibility Server Reports = Enable compatibility server reports +Error: load undo state is from a different game = Error: load undo state is from a different game +Failed to load state. Error in the file system. = Failed to load state. Error in the file system. +Failed to save state. Error in the file system. = Failed to save state. Error in the file system. +Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. +Fast (lag on slow storage) = Fast (lag on slow storage) +Fast Memory = میمۆری خێرا(ناجێگیر) +Floating symbols = هێمای جوڵاو +Force real clock sync (slower, less lag) = Force real clock sync (slower, less lag) +Game crashed = Game crashed +Games list settings = سێتینگەکانی لیستی یاریەکان +General = گشتی +Grid icon size = Grid icon size +Help the PPSSPP team = Help the PPSSPP team +Host (bugs, less lag) = Host (bugs, less lag) +Ignore bad memory accesses = Ignore bad memory accesses +Increase size = زیادکردنی قەبارە +Interpreter = Interpreter +IO timing method = I/O timing method +IR Interpreter = IR interpreter +Language = زمان +Memory Stick Folder = Memory Stick folder +Memory Stick inserted = Memory Stick inserted +MHz, 0:default = MHz, 0 = default +MMDDYYYY = MMDDYYYY +Moving background = باکگراوندی جوڵاو +Newest Save = Newest save +No animation = بەبێ ئەنیمەیشن +Not a PSP game = Not a PSP game +Off = Off +Oldest Save = Oldest save +Only JPG and PNG images are supported = Only JPG and PNG images are supported +Path does not exist! = Path does not exist! +Pause when not focused = Pause when not focused +Plugins = Plugins +PSP Memory Stick = PSP Memory Stick +PSP Model = PSP مۆدێلی +PSP Settings = PSP settings +PSP-1000 = PSP-1000 +PSP-2000/3000 = PSP-2000/3000 +Recent games = تازەترین یاری کراوە +Record Audio = تۆمارکردنی دەنگ +Record Display = تۆمارکردنی شاشە +Recording = Recording +Reset Recording on Save/Load State = Reset recording on Save/Load state +Restore Default Settings = Restore PPSSPP's settings to default +RetroAchievements = RetroAchievements +Rewind Snapshot Interval = Rewind Snapshot Interval (mem hog) +Save path in installed.txt = Save path in installed.txt +Save path in My Documents = Save path in My Documents +Savestate Slot = Savestate slot +Savestate slot backups = Savestate slot backups +Screenshots as PNG = PNG خەزن کردنی سکریین شۆت بە شیوەی +Set Memory Stick folder = Set Memory Stick folder +Set UI background... = UI گۆڕینی باکگراوندی +Show ID = Show ID +Show region flag = Show region flag +Simulate UMD delays = Simulate UMD delays +Simulate UMD slow reading speed = Simulate UMD slow reading speed +Slot 1 = Slot 1 +Slot 2 = Slot 2 +Slot 3 = Slot 3 +Slot 4 = Slot 4 +Slot 5 = Slot 5 +Storage full = Storage full +Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) +Time Format = شێوازی کاتژمێر +Transparent UI background = ڕوون(شەفاف) UI باکگراوندێکی +UI = UI +UI Sound = UI دەنگی +UI background animation = UI ئەنیمەیشنی باکگراوندی +undo %c = backup %c +USB = USB +Use Lossless Video Codec (FFV1) = Use lossless video codec (FFV1) +Use O to confirm = بەکاربهێنە بۆ پشتراست کردنەوە (O) دوگمەی +Use output buffer (with overlay) for recording = Use output buffer (with overlay) for recording +Use system native keyboard = Use system native keyboard +Use X to confirm = بەکاربهێنە بۆ پشتراست کردنەوە (X) دوگمەی +VersionCheck = Check for new versions of PPSSPP +WARNING: Android battery save mode is on = WARNING: Android battery save mode is On +WARNING: Battery save mode is on = WARNING: Battery save mode is on +Waves = شەپۆل +YYYYMMDD = YYYYMMDD +Theme = Theme +Color Tint = گۆڕینی ڕەنگ +Color Saturation = تۆخی ڕەنگ +Show Memory Stick folder = نیشاندانی فۆڵدەری میمۆری + +[Themes] +Dark = Dark +Default = Default + +[TextureShaders] +Off = Off +TexMMPX = TexMMPX +Tex2xBRZ = Tex2xBRZ +Tex4xBRZ = Tex4xBRZ + +[Search] +No settings matched '%1' = No settings matched '%1' +Filtering settings by '%1' = Filtering settings by '%1' +Find settings = Find settings +Filter = فلتەر کردن +Clear filter = لابردنی فلتەر +Search term = Search term + +[Upgrade] +Details = Details +Dismiss = Dismiss +Download = Download +New version of PPSSPP available = New version of PPSSPP available + +[UI Elements] +%1 button = %1 button +%1 checkbox = %1 checkbox +%1 choice = %1 choice +%1 heading = %1 heading +%1 radio button = %1 radio button +%1 text field = %1 text field +Choices: = Choices: +List: = List: +Progress: %1% = Progress: %1% +Screen representation = Screen representation + +[VR] +% of native FoV = % of native FoV +6DoF movement = 6DoF movement +Distance to 2D menus and scenes = Distance to 2D menus and scenes +Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale +Force 72Hz update = Force 72Hz update +Heads-up display scale = Heads-up display scale +Heads-up display detection = Heads-up display detection +Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key +Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) +Virtual reality = Virtual reality +VR camera = VR camera +VR controllers = VR controllers diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index a8213bae12..f744319725 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = ຮູບແບບສຽງທີ່ຮອງຮັບ (ຕ້ອງຣີສຕາຣ໌ດ) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = ອັດຕະໂນມັດ Device = Device @@ -71,7 +71,9 @@ Enable Sound = ເປີດໃຊ້ງານສຽງ Global volume = ລະດັບສຽງຫຼັກ Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &ເກັບຄ່າຄອນໂຊລ Memory View... = &ມຸມມອງຄ່າຄວາມຈຳ... More Settings... = &ການຕັ້ງຄ່າອື່ນໆ... Nearest = &ພາບເປັນຮອຍຍັກໄດ້ +Pause when not focused = &ຢຸດຊົ່ວຄາວເມື່ອບໍ່ໄດ້ຫຼິ້ນ Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &ຂ້າມການໃຊ້ເອັບເຟັກບັບເຟີ້ (ບໍ່ມີບັບເຟີ້, ໄວຂຶ້ນ) @@ -244,7 +247,6 @@ Open Memory Stick = &ເປີດບ່ອນເກັບຂໍ້ມູນ Open New Instance = Open new instance OpenGL = &OpenGL Pause = &ຢຸດຊົ່ວຄາວ -Pause When Not Focused = &ຢຸດຊົ່ວຄາວເມື່ອບໍ່ໄດ້ຫຼິ້ນ Portrait = ແນວຕັ້ງ Portrait reversed = ກັບດ້ານແນວຕັ້ງ PPSSPP Forums = &ຟໍຣຳ PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = ລາຍລະອຽດຂອງເຟຣມ +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = ເອີ້ນໃຊ້ການທົດສອບ CPU Save new textures = ບັນທຶກພື້ນຜິວໃໝ່ Shader Viewer = ມຸມມອງການປັບໄລ່ເສດສີ Show Developer Menu = ສະແດງເມນູສຳລັບນັກພັດທະນາ +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = ສະຖິຕິ System Information = ຂໍ້ມູນຂອງລະບົບ @@ -368,6 +373,7 @@ ConfirmLoad = ຕ້ອງການໂຫຼດຂໍ້ມູນນີ້ຫຼ ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = ລຶບ Delete all = ລຶບທັງໝົດ @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = ແກ້ໄຂຮູບແບບໜ້າຈໍ +Display layout & effects = ແກ້ໄຂຮູບແບບໜ້າຈໍ Display Resolution (HW scaler) = ຄວາມລະອຽດໜ້າຈໍ (ຕາມຮາດແວຣ໌) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = ໃຊ້ສະເພາະບາງເກມ, ເພື່ອ Lower resolution for effects (reduces artifacts) = ຫຼຸດຄວາມລະອຽດຂອງເອັບເຟກໃຫ້ຕ່ຳລົງ (ແກ້ພາບແຈ້ງ) Manual Scaling = ກຳນົດຂະໜາດເອງ Medium = ປານກາງ +Mirror camera image = Mirror camera image Mode = ໂໝດ Must Restart = ເຈົ້າຄວນເລີ່ມ PPSSPP ໃໝ່ເພື່ອເຫັນຜົນການປ່ຽນແປງ. Native device resolution = ຄ່າຄວາມລະອຽດດັ້ງເດີມຂອງອຸປະກອນ @@ -694,9 +701,12 @@ Window Size = ຂະໜາດໜ້າຈໍ xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = ລຶບໄຟລ໌ ZIP +Existing data = Existing data Install = ຕິດຕັ້ງ Install game from ZIP file? = ຕິດຕັ້ງເກມຈາກໄຟລ໌ ZIP ຫຼືບໍ່? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = ຕິດຕັ້ງແລ້ວ! @@ -1050,8 +1060,12 @@ written = ຂຽນໂດຍພາສາ C++ ເພື່ອປະສິດທ [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = ການເຊື່ອມຕໍ່ລົ້ມເຫຼວ Install = ຕິດຕັ້ງ Installed = ຕິດຕັ້ງຮຽບຮ້ອຍແລ້ວ Launch Game = ເລີ່ມເກມ +License = License Loading... = ກຳລັງໂຫຼດ... MB = MB Size = ຂະໜາດ Uninstall = ຖອນການຕິດຕັ້ງ +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (ເສຍຫາຍ) 12HR = 12 ຊົ່ວໂມງ 24HR = 24 ຊົ່ວໂມງ +App switching mode = App switching mode Auto = ອັດຕະໂນມັດ Auto Load Savestate = Auto load savestate AVI Dump started. = ເລີ່ມຖ່າຍໂອນຂໍ້ມູນ AVI ແລ້ວ. @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = ເຄື່ອງມືສຳລັບນັກພັດທະນາ Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulation Enable Cheats = ເປີດໃຊ້ງານສູດໂກງ @@ -1313,6 +1331,8 @@ Off = ປິດ Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &ຢຸດຊົ່ວຄາວເມື່ອບໍ່ໄດ້ຫຼິ້ນ +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = ໂມເດລ PSP PSP Settings = ຕັ້ງຄ່າ PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = ບ່ອນເກັບຂໍ້ມູນເຕັມ Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = ຮູບແບບເວລາ Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = ດາວໂຫຼດ New version of PPSSPP available = ເວີຊັ່ນໃໝ່ຂອງ PPSSPP ພ້ອມໃຫ້ໂຫຼດແລ້ວ! [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index 0e496ec97d..15cefd32c9 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Audio backend (restart req.) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = Įjungti garsą Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = "&Statuso" konsolė Memory View... = Atminties &rodymas... More Settings... = &Daugiau parametrų... Nearest = &Arčiausias +Pause when not focused = &Stabdyti kai nefokusuota Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Atidaryti "&Memory Stick" Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pauzė -Pause When Not Focused = &Stabdyti kai nefokusuota Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &Forumai @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Atidaryti pagrindinio procesoriaus testus Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Rodyti kūrėjų meniu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = Sistemos informacija @@ -368,6 +373,7 @@ ConfirmLoad = Ar krauti šitus duomenis? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Ištrinti Delete all = Ištrinti viską @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Ekrano rezoliucija ("HW" ištiesinimas) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Vidutinė +Mirror camera image = Mirror camera image Mode = Režimas Must Restart = Jūs turite perkrauti "PPSSPP" programą, kad pakeisti parametrai turėtų efektą Native device resolution = Įrenginio rezoliucija @@ -694,9 +701,12 @@ Window Size = Lango dydis xBRZ = "xBRZ" [InstallZip] +Data to import = Data to import Delete ZIP file = Ištrinti ZIP failą +Existing data = Existing data Install = Instaliuoti Install game from ZIP file? = Instaliuoti žaidimą iš ZIP failo? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Instaliuota! @@ -1050,8 +1060,12 @@ written = Parašyta C++ kalboje dėl greičio ir portabilumo [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Prisijungimo klaida Install = Instaliuoti Installed = Jau instaliuota Launch Game = Paleisti žaidimą +License = License Loading... = Kraunama... MB = Megabaitai Size = Dydis Uninstall = Išinstaliuoti +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (ieteicams) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Kurėjų įrankiai Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emuliacija Enable Cheats = Įjungti kodus @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Stabdyti kai nefokusuota +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Emuliuojamo PSP modelis PSP Settings = PSP parametrai @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Laiko formatas Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Parsisiūsti New version of PPSSPP available = Galima nauja "PPSSPP" versija [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index c803e82048..f082e183ce 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Enjin suara (PPSSPP perlu dibuka semula) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = Upayakan suara Global volume = Volume keseluruhan Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Log Konsol Memory View... = Lihat &Memori... More Settings... = &Tetapan lanjutan... Nearest = &Terdekat +Pause when not focused = &Jeda ketika tidak difokus Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Buka &Memori Stik Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Jeda -Pause When Not Focused = &Jeda ketika tidak difokus Portrait = Portrait Portrait reversed = Portrait songsang PPSSPP Forums = PPSSPP &Forum @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = Ujian driver GPU GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Jalankan percubaan CPU Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Papar menu pembangun +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = Maklumat sistem @@ -368,6 +373,7 @@ ConfirmLoad = Muatkan data ini? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Padam Delete all = Padam semua @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = Mod Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution @@ -694,9 +701,12 @@ Window Size = Saiz tetingkap xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Padam fail ZIP +Existing data = Existing data Install = Pasang Install game from ZIP file? = Pasang permainan dari fail ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Dipasang! @@ -734,9 +744,9 @@ Exit = Keluar Game Settings = Tetapan Games = Permainan Give PPSSPP permission to access storage = Give PPSSPP permission to access storage -Homebrew & Demos = Homebrew && Demo +Homebrew & Demos = Homebrew & Demo How to get games = Bagaimana saya dapatkan permainan? -How to get homebrew & demos = Bagaimana saya dapatkan homebrew && demo? +How to get homebrew & demos = Bagaimana saya dapatkan homebrew & demo? Load = Muatkan... Loading... = Loading... PinPath = Pin @@ -1050,8 +1060,12 @@ written = Ditulis dengan C++ untuk kelajuan dan mudah alih [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Kesalahan Sambungan Install = Pasang Installed = Telah dipasang sebelumnya Launch Game = Launch game +License = License Loading... = Memuatkan... MB = MB Size = Saiz Uninstall = Nyahpasang +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12 JAM 24HR = 24 JAM +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Alatan Pengeluar Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulasi Enable Cheats = Upayakan cheat @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Jeda ketika tidak difokus +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Model PSP PSP Settings = Tetapan PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Format waktu Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Muat turun New version of PPSSPP available = Versi terbaru PPSSPP tersedia [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 828ff6cde6..336a60f550 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Audiobackend (vereist herstart) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-vriendelijke buffer (trager) Auto = Automatisch Device = Device @@ -71,7 +71,9 @@ Enable Sound = Geluid inschakelen Global volume = Globaal volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = Logboek&console Memory View... = &Geheugenweergave... More Settings... = &Meer instellingen... Nearest = &Naaste buur +Pause when not focused = &Pauzeren wanneer venster inactief is Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Buffereffecten nalaten (niet-gebufferd, sneller) @@ -244,7 +247,6 @@ Open Memory Stick = M&emory stick openen Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pauzeren -Pause When Not Focused = &Pauzeren wanneer venster inactief is Portrait = Portret Portrait reversed = Omgekeerd portret PPSSPP Forums = &PPSSPP-forum @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frameanalyse +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = CPU-controles uitvoeren Save new textures = Nieuwe textures opslaan Shader Viewer = Shader weergeven Show Developer Menu = Ontwikkelaarsmenu weergeven +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Statistieken System Information = Systeeminformatie @@ -368,6 +373,7 @@ ConfirmLoad = Wilt u deze data laden? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Wissen Delete all = Alles wissen @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Schermweergave bewerken +Display layout & effects = Schermweergave bewerken Display Resolution (HW scaler) = Schermresolutie (hardware) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Alleen gebruikt in sommige games, bestuurt de afronding van curv Lower resolution for effects (reduces artifacts) = Effectresolutie verlagen (minder objecten) Manual Scaling = Handmatig schalen Medium = Normaal +Mirror camera image = Mirror camera image Mode = Modus Must Restart = U moet PPSSPP herstarten om de wijzigingen door te voeren. Native device resolution = Apparaatresolutie @@ -694,9 +701,12 @@ Window Size = Venstergrootte xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = ZIP-bestand wissen +Existing data = Existing data Install = Installeren Install game from ZIP file? = Game installeren vanuit het ZIP-bestand? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installatie voltooid! @@ -1050,8 +1060,12 @@ written = Geschreven in C++ voor snelheid en draagbaarheid [RemoteISO] Browse Games = Games bladeren... +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Lokale serverpoort Manual Mode Client = Handmatige modus client +Not currently sharing = Not currently sharing Remote disc streaming = Externe schijf streamen Remote Port = Externe poort Remote Server = Externe server @@ -1165,10 +1179,12 @@ Connection Error = Verbindingsfout Install = Installeren Installed = Al geïnstalleerd Launch Game = Game starten +License = License Loading... = Laden MB = MB Size = Grootte Uninstall = Deïnstalleren +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan-functies (broken) = (defect) 12HR = 12-uursweergave 24HR = 24-uursweergave +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI-dump gestart @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU-core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Ontwikkelaarsopties Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulatie Enable Cheats = Cheats inschakelen @@ -1313,6 +1331,8 @@ Off = Uit Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Pauzeren wanneer venster inactief is +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP-model PSP Settings = PSP-instellingen @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Onvoldoende opslagruimte Sustained performance mode = Aanhoudende prestatiemodus +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Tijdweergave Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Downloaden New version of PPSSPP available = Er is een nieuwe versie van PPSSPP beschikbaar [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 2d8fb72303..f1f6258180 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Audio backend (restart req.) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Device @@ -71,7 +71,9 @@ Enable Sound = Lyd Global volume = Global volume Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest +Pause when not focused = &Pause When Not Focused Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Open &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &Forums @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Kjør CPU-test Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = Systeminformasjon @@ -368,6 +373,7 @@ ConfirmLoad = Load this data? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Slett Delete all = Delete all @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = Mode Must Restart = You must restart PPSSPP for this change to take effect. Native device resolution = Native device resolution @@ -694,9 +701,12 @@ Window Size = Window size xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Delete ZIP file +Existing data = Existing data Install = Install Install game from ZIP file? = Install game from ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Installed! @@ -734,9 +744,9 @@ Exit = Avslutt Game Settings = Instillinger Games = Spill Give PPSSPP permission to access storage = Give PPSSPP permission to access storage -Homebrew & Demos = Hjemmebrygg && Demoer +Homebrew & Demos = Hjemmebrygg & Demoer How to get games = Hvordan få spill -How to get homebrew & demos = Hvordan man skaffer Hjemmebrygg && Demoer +How to get homebrew & demos = Hvordan man skaffer Hjemmebrygg & Demoer Load = Laster... Loading... = Loading... PinPath = Pin @@ -1050,8 +1060,12 @@ written = Written in C++ for speed and portability [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1165,10 +1179,12 @@ Connection Error = Connection error Install = Install Installed = Installed Launch Game = Launch game +License = License Loading... = Loading... MB = MB Size = Size Uninstall = Uninstall +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (anbefales) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Utviklerverktøy Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulation Enable Cheats = Juks @@ -1313,6 +1331,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pause When Not Focused +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = PSP settings @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Storage full Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Time format Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Download New version of PPSSPP available = New version of PPSSPP available [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index a017d995a2..14f805d8fc 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -4,13 +4,13 @@ %1 achievements, %2 points = %1 Osiągnięć, %2 punktów Account = Konto Achievement progress = Postęp osiągnięcia -Achievement sound volume = Achievement sound volume +Achievement sound volume = Głośność dźwięku osiągnięcia Achievement unlocked = Osiągnięcie odblokowane Achievements = Osiągnięcia Achievements are disabled = Osiągnięcia są wyłączone Achievements enabled = Osiągnięcia włączone Achievements with active challenges = Osiągnięcia z aktywnymi wyzwaniami -Allow Save State in Hardcore Mode (but not Load State) = Allow Save State in Hardcore Mode (but not Load State) +Allow Save State in Hardcore Mode (but not Load State) = Pozwól na zapis stanu w Trybie Wyzwania (bez wczytywania zapisów) Almost completed achievements = Prawie ukończone osiągnięcia Around me = Wokół mnie Can't log in to RetroAchievements right now = W tym momencie nie można zalogować do RetroAchievements @@ -61,7 +61,7 @@ Unsupported achievements = Niewspierane osiągnięcia Alternate speed volume = Alternatywna prędkość emulacji Audio backend = Sterownik dźwięku (wymagany restart) Audio Error = Błąd Audio -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Niewspierany format pliku dźwiękowego. Plik musi być w formacie WAV lub MP3. AudioBufferingForBluetooth = Bufory dźwięku dost. do Bluetooth (wolniejsze) Auto = Automatyczny Device = Urządzenie @@ -71,7 +71,9 @@ Enable Sound = Włącz dźwięk Global volume = Głośność globalna Microphone = Mikrofon Microphone Device = Mikrofon +Mix audio with other apps = Miksuj audio z innymi aplikacjami Mute = Wycisz +Respect silent mode = Respect silent mode Reverb volume = Pogłos Use new audio devices automatically = Automatycznie używaj nowego urządzenia audio Use global volume = Używaj głośności globalnej @@ -91,7 +93,7 @@ Auto-hide buttons after delay = Automatyczne ukrywanie przycisków po: Auto-rotation speed = Prędkość automatycznego obracania Binds = Powiązania Button Binding = Konfiguracja przycisków -Button Opacity = Przeźroczystość przycisków +Button Opacity = Przezroczystość przycisków Button style = Styl przycisków Calibrate Analog Stick = Kalibracja Analoga Calibrate = Kalibracja @@ -135,7 +137,7 @@ Low end radius = Promień dolny Mouse = Ustawienia myszy Mouse sensitivity = Czułość myszy Mouse smoothing = Wygładzanie myszy -Mouse wheel button-release delay = Mouse wheel button-release delay +Mouse wheel button-release delay = Opóźnienie zwolnienia przycisku kółka myszy MouseControl Tip = Możesz teraz przypisać myszkę na ekranie mapowania przycisków klikając w ikonkę 'M'. None (Disabled) = Brak (wył.) Off = Wył. @@ -143,7 +145,7 @@ OnScreen = Przyciski ekranowe Portrait = Pionowo Portrait Reversed = Odwrócone pionowo PSP Action Buttons = Klawisze akcji PSP -Rapid fire interval = +Rapid fire interval = Odstęp pomiędzy strzałami w trybie autom. strzelania Raw input = Zwykłe wejście Repeat mode = Tryb powtarzania Reset to defaults = Domyślne @@ -184,14 +186,14 @@ Refresh interval = Szybkość odświeżania #Font = Trebuchet MS About PPSSPP... = O PPSSPP... Auto = Automatycznie -Auto Max Quality = Automatyczna maksymalna &Jakość +Auto Max Quality = Automatycznie (maksymalna jakość) Backend = &Sterownik obrazu (Restartuje PPSSPP) Bicubic = Dwusześcienne Break = Zatrzymaj Break on Load = Zatrzymaj po załadowaniu Buy Gold = Kup wersję Gold Control Mapping... = Ustawienia przycisków... -Copy PSP memory base address = Copy Skopiuj bazę i adresy pamięci PSP +Copy PSP memory base address = Skopiuj adres bazowy pamięci PSP Debugging = &Debugowanie Deposterize = Deposteryzacja Direct3D9 = &Direct3D9 @@ -233,8 +235,9 @@ Log Console = Konsola dziennika zdarzeń Memory View... = Podgląd pamięci... More Settings... = Więcej ustawień... Nearest = Najbliższe +Pause when not focused = Pauzuj, gdy okno nieaktywne Recent = &Ostatnie -Restart Graphics = Restart Graphics +Restart Graphics = Restartuj grafikę Skip Buffer Effects = &Nie renderuj efektów z bufora (niebuforowane, szybsze) Off = Wyłącz Open Chat = Otwórz Chat @@ -244,7 +247,6 @@ Open Memory Stick = Otwórz Kartę Pamięci Open New Instance = Otwórz nową instancję OpenGL = &OpenGL Pause = Pauza -Pause When Not Focused = Pauzuj, gdy okno nieaktywne Portrait = Pionowo Portrait reversed = Odwrócone pionowo PPSSPP Forums = Forum PPSSPP @@ -256,7 +258,7 @@ Rendering Resolution = Rozdzielczość renderowania Reset = Zrestartuj Reset Symbol Table = Resetuj tablicę symboli Run = Uruchom -Save .sym File... = Zapisz plik .&sym... +Save .sym File... = Zapisz plik .sym... Save Map File... = Zapisz plik .map... Save State = Zapisz stan Save State File... = Zapisz plik stanu @@ -266,7 +268,7 @@ Show Debug Statistics = Pokaż statystyki debugowania Show FPS Counter = Pokaż licznik FPS Skip Number of Frames = Pomiń ilość klatek Skip Percent of FPS = Pomiń procent FPS -Smart 2D texture filtering = Smart 2D texture filtering +Smart 2D texture filtering = Inteligentne filtrowanie tekstur 2D Stop = Zatrzymaj Switch UMD = Podmień UMD Take Screenshot = Wykonaj zrzut ekranu @@ -304,10 +306,12 @@ Enter address = Wprowadź adres Fast-forward mode = Pełna prędkość FPU = FPU Fragment = Fragment -Frame timing = Frame timing +Frame timing = Czasy klatek Framedump tests = Test zrzutu klatki Frame Profiler = Profiler klatki -GPU Allocator Viewer = GPU Allocator Viewer +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs +GPU Allocator Viewer = Podgląd alokacji GPU GPU Driver Test = Test sterownika GPU GPU log profiler = Profilowanie logów GPU GPU Profile = Profil GPU @@ -333,6 +337,7 @@ Run CPU Tests = Uruchom testy CPU Save new textures = Zapisz nową teksturę Shader Viewer = Podgląd Shaderów Show Developer Menu = Pokaż przycisk menu dewelopera +Show GPO LEDs = Pokaż piny LED GPO Show on-screen messages = Pokaż komunikaty na ekranie Stats = Statystyki System Information = Informacje o systemie @@ -342,7 +347,7 @@ Audio Debug = Debugowanie audio Control Debug = Debugowanie sterowania Toggle Freeze = Wł./Wył. zamrożenie Touchscreen Test = Test ekranu dotykowego -Ubershaders = Ubershaders +Ubershaders = Ubershadery Vertex = Vertex VFPU = VFPU @@ -368,6 +373,7 @@ ConfirmLoad = Wczytać te dane? ConnectingAP = Łączenie do punktu dostępowego.\nProszę czekać... ConnectingPleaseWait = Łączenie.\nProszę czekać... ConnectionName = Nazwa Połączenia +Copy to clipboard = Copy to clipboard Corrupted Data = Uszkodzone dane Delete = Usuń Delete all = Usuń wszystko @@ -393,7 +399,7 @@ GE Frame Dumps = Zrzuty klatek GE Grid = Rozmiar siatki Inactive = Nieaktywny Installing... = Instalowanie... -InternalError = Występił wewnętrzny błąd aplikacji +InternalError = Wystąpił wewnętrzny błąd aplikacji Links = Linki Load = Wczytaj Load completed = Ładowanie zakończone. @@ -403,7 +409,7 @@ Log in = Zaloguj Log out = Wyloguj Logged in! = Zalogowano! Logging in... = Logowanie... -More information... = More information... +More information... = Więcej informacji... Move = Przenieś Move Down = Przenieś w dół Move Up = Przenieś w górę @@ -492,8 +498,7 @@ PS1 EBOOTs are not supported by PPSSPP. = Pliki EBOOT PS1 nie są obsługiwane p PSX game image detected. = Plik jest obrazem MODE2. PPSSPP nie obsługuje gier z PS1. RAR file detected (Require UnRAR) = Wykryto plik RAR.\nRozpakuj go przed użyciem (spróbuj UnRAR). RAR file detected (Require WINRAR) = Wykryto plik RAR.\nRozpakuj go przed użyciem (spróbuj WinRAR). -Running slow: try frameskip, sound is choppy when slow = Running slow: try frameskip, sound is choppy when slow -Running slow: Wypróbuj pomijania klatek, dźwięk przerywa gdy emulacja spowalnia = Running slow: try frameskip, sound is choppy when slow +Running slow: try frameskip, sound is choppy when slow = Wypróbuj pomijania klatek, dźwięk przerywa gdy emulacja spowalnia Running slow: Try turning off Software Rendering = Running slow: try turning off "software rendering" Running slow: Wolne działanie: spróbuj pomijania klatek, dźwięk zacina przy wolnym działaniu Running slow: Wolne działanie: spróbuj wyłączyć "Renderowanie programowe" @@ -514,34 +519,34 @@ ZIP file detected (Require WINRAR) = Wykryto plik ZIP.\nRozpakuj go przed użyci [Game] Asia = Azja Calculate CRC = Oblicz CRC -Click "Calculate CRC" to verify ISO = Click "Calculate CRC" to verify ISO +Click "Calculate CRC" to verify ISO = Kliknij "Oblicz CRC" aby zweryfikować plik ISO ConfirmDelete = Usuń -CRC checksum does not match, bad or modified ISO = CRC checksum does not match, bad or modified ISO +CRC checksum does not match, bad or modified ISO = Niezgodna suma kontrolna CRC, plik ISO jest zły lub zmodyfikowany Create Game Config = Utwórz konfigurację gry Create Shortcut = Utwórz skrót Delete Game = Usuń grę Delete Game Config = Usuń konfigurację gry Delete Save Data = Usuń zapisy gry Europe = Europa -File size incorrect, bad or modified ISO = File size incorrect, bad or modified ISO +File size incorrect, bad or modified ISO = Nieprawidłowy rozmiar pliku, plik ISO jest zły lub zmodyfikowany Game = Gra -Game ID unknown - not in the ReDump database = Game ID unknown - not in the ReDump database +Game ID unknown - not in the ReDump database = Nieznane ID gry - ID nie znajduje się w bazie danych ReDump Game Settings = Ustawienia gry Homebrew = Homebrew Hong Kong = Hongkong InstallData = Zainstalowane dane -ISO OK according to the ReDump project = ISO OK according to the ReDump project +ISO OK according to the ReDump project = Plik ISO zgodny według projektu ReDump Japan = Japonia Korea = Korea MB = MB One moment please... = Chwileczkę... Play = Graj -Remove From Recent = Usuń z "Ostatnio uruchamianych tytułów" +Remove From Recent = Usuń z "Ostatnio uruchamianych" SaveData = Zapisy gier Setting Background = Ustawianie tła Show In Folder = Pokaż w folderze -Time Played: %1h %2m %3s = Time Played: %1h %2m %3s -Uncompressed = Uncompressed +Time Played: %1h %2m %3s = Czas gry: %1h %2m %3s +Uncompressed = Nieskompresowane USA = USA Use UI background = Użyj tego tła @@ -567,7 +572,7 @@ Use UI background = Użyj tego tła 9x PSP = 9× PSP 10x PSP = 10× PSP 16x = 16× -AdrenoTools driver manager = AdrenoTools driver manager +AdrenoTools driver manager = Menedżer sterowników AdrenoTools Aggressive = Agresywne Alternative Speed = Alternatywna prędkość (w %, 0 = bez limitu) Alternative Speed 2 = Alternatywna prędkość 2 (w %, 0 = bez limitu) @@ -593,21 +598,21 @@ Cardboard Screen Y Shift = Przesunięcie Y (% pustej przestrzeni) Cardboard VR Settings = Ustawienia Google Cardboard VR Cheats = Kody Copy to texture = Copy to texture -Current GPU Driver = Current GPU Driver +Current GPU Driver = Aktualny sterownik GPU Debugging = Debugowanie -Default GPU driver = Default GPU driver +Default GPU driver = Domyślny sterownik GPU DefaultCPUClockRequired = Uwaga: Ta gra wymaga, by częstotliwość taktowania CPU była domyślna. Deposterize = Deposteryzacja Deposterize Tip = Poprawia banding koloru na przeskalowanych teksturach Device = Urządzenie Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disable culling = Disable culling +Disable culling = Wyłącz culling Disabled = Wył. -Display Layout && Effects = Edytor położenia obrazu +Display layout & effects = Edytor położenia obrazu Display Resolution (HW scaler) = Rozdzielczość ekranu (skaler sprz.) -Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 -Drivers = Drivers +Driver requires Android API version %1, current is %2 = Sterownik wymaga wersji %1 Android API, aktualna wersja to %2 +Drivers = Sterowniki Enable Cardboard VR = Aktywuj Cardboard VR FPS = Tylko FPS Frame Rate Control = Kontrola klatek na sekundę @@ -625,7 +630,7 @@ High = Wysokie Hybrid = Hybrydowe Hybrid + Bicubic = Hybrydowe + Dwusześcienne Ignore camera notch when centering = Ignoruj przesunięcie kamery podczas centrowania -Install custom driver... = Install custom driver... +Install custom driver... = Zainstaluj niestandardowy sterownik... Integer scale factor = Całkowity współczynnik skali Internal Resolution = Rozdzielczość wewnętrzna Lazy texture caching = Leniwa pamięć tekstur (przyśpieszenie) @@ -637,17 +642,18 @@ LowCurves Tip = Używane tylko przez niektóre gry, kontroluje gładkość krzyw Lower resolution for effects (reduces artifacts) = Zmniejszenie rozdzielczość efektów (mniej błędów) Manual Scaling = Ręczne skalowanie Medium = Średnie +Mirror camera image = Mirror camera image Mode = Tryb Must Restart = Musisz zrestartować PPSSPP, aby zastosować zmiany. Native device resolution = Natywna rozdzielczość urządzenia Nearest = Najbliższe -No (default) = No (default) +No (default) = Nie (domyślne) No buffer = Bez bufora -Render all frames = Render all frames +Render all frames = Renderuj wszystkie klatki Same as Rendering resolution = Automatyczne (jak roz. renderowania) Show Battery % = Pokaż % baterii Show Speed = Pokaż prędkość -Skip = Skip +Skip = Pomiń Skip Buffer Effects = Nie renderuj efektów z bufora (niebuforowane, szybsze) None = Wył. Number of Frames = Ilość klatek @@ -670,7 +676,7 @@ Screen Scaling Filter = Filtrowanie skalowania ekranu Show Debug Statistics = Pokaż statystyki debugowania Show FPS Counter = Pokaż licznik FPS Skip GPU Readbacks = Pomiń odczyty zwrotne GPU -Smart 2D texture filtering = Smart 2D texture filtering +Smart 2D texture filtering = Inteligentne filtrowanie tekstur 2D Software Rendering = Renderowanie programowe (wolne) Software Skinning = Programowy skinning SoftwareSkinning Tip = Łączy na CPU wywołania rysujące modele z animacjami, przyspieszenie w większości gier @@ -684,7 +690,7 @@ Texture Filtering = Filtrowanie tekstur Texture replacement pack activated = Paczka podmienionych tekstur aktywowana Texture Scaling = Skalowanie tekstur Texture Shader = Shadery tekstur -The chosen ZIP file doesn't contain a valid driver = The chosen ZIP file doesn't contain a valid driver +The chosen ZIP file doesn't contain a valid driver = Wybrany plik ZIP nie zawiera prawidłowego sterownika Turn off Hardware Tessellation - unsupported = Wyłącz sprzętową teselację: opcja nie jest wspierana Unlimited = Bez limitu Up to 1 = Maks. jeden @@ -699,9 +705,12 @@ Window Size = Rozmiar okna xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Usuń plik ZIP +Existing data = Existing data Install = Zainstaluj Install game from ZIP file? = Zainstalować grę z pliku ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Czy zainstalować teksturę z archiwum ZIP? Installation failed = Installation failed Installed! = Zainstalowano! @@ -716,17 +725,17 @@ Autoconfigure for device = Skonfiguruj automatycznie Bind All = Przypisz (wszystkie) Clear All = Wyczyść (wszystkie) Combo mappings are not enabled = Mapowanie kombinacji jest wyłączone -Control modifiers = Control modifiers +Control modifiers = Modyfikatory sterowania Default All = Domyślne (wszystkie) -Emulator controls = Emulator controls -Extended PSP controls = Extended PSP controls +Emulator controls = Sterowanie emulatorem +Extended PSP controls = Rozszerzone sterowanie PSP Map a new key for = Przypisz nowy klawisz dla Map Key = Mapuj przycisk Map Mouse = Mapuj mysz Replace = Zamień Show PSP = Pokaż PSP -Standard PSP controls = Standard PSP controls -Strict combo input order = Strict combo input order +Standard PSP controls = Standardowe sterowanie PSP +Strict combo input order = Ścisła kolejność wprowadzania kombinacji You can press ESC to cancel. = Możesz zamknąć to okienko naciskając Esc. [MainMenu] @@ -833,8 +842,8 @@ Texture Dumping = Zrzut tekstur Texture Replacement = Podmiana tekstur Toggle Fullscreen = Wł./wył. pełny ekran Toggle mode = Tryb przełączania -Toggle mouse input = Toggle mouse input -Toggle touch controls = Toggle touch controls +Toggle mouse input = Przełącz sterowanie myszką +Toggle touch controls = Przełącz sterowanie dotykiem Toggle WLAN = Przełącz WLAN Triangle = Trójkąt Fast-forward = Pełna prędkość @@ -846,14 +855,14 @@ Wlan = WLAN [MemStick] Already contains PSP data = Już zawiera dane PSP Cancelled - try again = Anulowano - spróbuj ponownie -Checking... = Checking... +Checking... = Sprawdzanie... Create or Choose a PSP folder = Utwórz lub Wybierz folder PSP Current = Obecny DataCanBeShared = Dane mogą być udostępniane pomiędzy zwykłą wersją PPSSPP, a wersją Gold DataCannotBeShared = Dane NIE mogą być udostępniane pomiędzy zwykłą wersją PPSSPP, a wersją Gold! DataWillBeLostOnUninstall = Uwaga! Utracisz wszystkie dane po odinstalowaniu PPSSPP! DataWillStay = Dane zostaną na urządzeniu, nawet po odinstalowaniu PPSSPP. -Deleting... = Deleting... +Deleting... = Usuwanie... Done! = Ukończono! EasyUSBAccess = Łatwy dostęþ do USB Failed to move some files! = Nie udało się przenieść niektórych plików! @@ -913,7 +922,7 @@ Hostname = Nazwa hosta Invalid IP or hostname = Niepoprawny adres IP lub nazwa hosta Minimum Timeout = Minimalny czas oczekiwania (podaj w ms, domyślnie 0) Misc = Inne (domyślnie = Kompatybilność z PSP) -Network connected = Network connected +Network connected = Połączono do sieci Network initialized = Sieć została zainicjowana Please change your Port Offset = Proszę zmienić port Port offset = Zmień port (0 = zgodne z PSP) @@ -1045,7 +1054,7 @@ tools = Wykorzystane narzędzia: # Add translators1-6 for up to 6 lines of translator credits. # Leave extra lines blank. 4 contributors per line seems to look best. translators1 = Daniel Kluz, Michał Kasprzak, Mateusz Godlewski, Łukasz Bereza -translators2 = oop23, Silent, Patrxgt, Dominik +translators2 = oop23, Silent, Patrxgt, Dominik, eveninglatte translators3 = Poprzednią edycję tłumaczenia stworzyli: translators4 = hrydgard, The Dax, mikusp, adrian17 translators5 = @@ -1056,8 +1065,12 @@ written = Napisano w C++ dla wydajności i mobilności [RemoteISO] Browse Games = Przeglądaj gry +Connect = Połącz +Currently sharing = Currently sharing +Files to share = Pliki do udostępniania Local Server Port = Port serwera lokalnego Manual Mode Client = Ręcznie skonfiguruj klienta +Not currently sharing = Not currently sharing Remote disc streaming = Zdalna transmisja płyty Remote Port = Port serwera zdalnego Remote Server = Serwer zdalny @@ -1071,7 +1084,7 @@ RemoteISOWinFirewall = UWAGA: Zapora ogniowa Windows blokuje udostępnianie Settings = Ustawienia Share Games (Server) = Udostępniaj gry (serwer) Share on PPSSPP startup = Udostępniaj przy starcie PPSSPP -Show Remote tab on main screen = Show Remote tab on main screen +Show Remote tab on main screen = Pokaż kartę serwera zdalnego na ekranie głównym Stop Sharing = Zatrzymaj udostępnianie Stopping.. = Zatrzymywanie... @@ -1133,7 +1146,7 @@ Size = Rozmiar [Screen] Cardboard VR OFF = Wył. Cardboard VR Chainfire3DWarning = UWAGA: Wykryto Chainfire3D, może powodować problemy. -ExtractedISOWarning = Extracted ISOs often don't work.\nPlay the ISO file directly. +ExtractedISOWarning = Rozpakowane pliki ISO często nie działają.\nZaładuj plik ISO bezpośrednio. Failed to load state = Nie można wczytać zapisu stanu Failed to save state = Nie można zapisać stanu fixed = Prędkość: alternatywna @@ -1171,10 +1184,12 @@ Connection Error = Błąd połączenia Install = Zainstaluj Installed = Zainstalowane Launch Game = Rozpocznij grę +License = License Loading... = Ładowanie... MB = MB Size = Rozmiar Uninstall = Odinstaluj +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1213,11 +1228,11 @@ GPU Flags = Flagi GPU GPU Information = Informacje o GPU High precision float range = Zakres l. zmiennoprzecinkowych wys. precyzji High precision int range = Zakres l. całkowitych wys. precyzji -Icon cache = Icon cache -Instance = Instance +Icon cache = Pamięć podręczna ikon +Instance = Instancja JIT available = JIT dostępne Lang/Region = Język/Region -Memory Page Size = Rozmiar pamięci stronnicowania +Memory Page Size = Rozmiar strony (pamięć stronicowania) Native resolution = Natywna rozdzielczość No GPU driver bugs detected = Nie znaleziono żadnych błędów sterownika GPU OGL Extensions = Rozszerzenia OGL @@ -1253,6 +1268,7 @@ Vulkan Features = Opcje Vulkana (broken) = (nie działa) 12HR = 12 godzinny 24HR = 24 godzinny +App switching mode = App switching mode Auto = Automatyczny Auto Load Savestate = Automatyczne wczytywanie stanów zapisu AVI Dump started. = Rozpoczęto zrzut do AVI @@ -1263,13 +1279,14 @@ Color Saturation = Saturacja Color Tint = Odcień CPU Core = Rdzeń procesora Dynarec/JIT (recommended) = Dynarec/JIT (zalecana) +Enable plugins = Włącz pluginy Error: load undo state is from a different game = Błąd: ładowany stan pochodzi z innej gry Failed to load state for load undo. Error in the file system. = Błąd podczas ładowania stanu dla cofnięcia. Błąd systemu plików. Floating symbols = Przepływ symboli Game crashed = Gra uległa awarii -JIT using IR = JIT using IR +JIT using IR = JIT używając IR Language = Język -Loaded plugin: %1 = Loaded plugin: %1 +Loaded plugin: %1 = Załadowano plugin: %1 Memory Stick folder = Zmień folder Karty Pamięci Memory Stick size = Rozmiar Karty Pamięci Change Nickname = Zmień pseudonim @@ -1288,7 +1305,7 @@ Developer Tools = Narzędzia programistyczne Display Extra Info = Wyświetl dodatkowe informacje Display Games on a grid = Wyświetl "Gry" jako siatkę Display Homebrew on a grid = Wyświetl "Homebrew i Dema" jako siatkę -Display Recent on a grid = Wyświetlaj "Ostatnio Uruchamiane" w projekcji siatki +Display Recent on a grid = Wyświetlaj "Ostatnio Uruchamiane" jako siatkę Emulation = Emulacja Enable Cheats = Włącz kody Enable Compatibility Server Reports = Włącz serwer raportów kompatybilności @@ -1317,8 +1334,10 @@ No animation = Bez animacji Not a PSP game = To nie jest gra PSP Off = Wył. Oldest Save = Najstarszy zapis -Only JPG and PNG images are supported = Only JPG and PNG images are supported +Only JPG and PNG images are supported = Tylko pliki JPG i PNG są wspierane Path does not exist! = Ta ścieżka nie istnieje! +Pause when not focused = Pauzuj, gdy okno nieaktywne +Plugins = Pluginy PSP Memory Stick = Karta Pamięci PSP PSP Model = Model PSP PSP Settings = Ustawienia PSP @@ -1327,7 +1346,7 @@ PSP-2000/3000 = PSP-2000/3000 Recent games = Ostatnio uruchamiane tytuły Record Audio = Nagrywaj dźwięk Record Display = Nagrywaj obraz -Recording = Recording +Recording = Nagrywanie Reset Recording on Save/Load State = Resetuj nagrywanie przy zapisie/wczytaniu stanu Restore Default Settings = Przywróć domyślne ustawienia RetroAchievements = RetroAchievements @@ -1343,7 +1362,7 @@ Show ID = Pokazuj ID Show Memory Stick folder = Pokaż folder Karty Pamięci Show region flag = Pokazuj flagi regionu Simulate UMD delays = Symuluj opóźnienia UMD -Simulate UMD slow reading speed = Simulate UMD slow reading speed +Simulate UMD slow reading speed = Symuluj wolny czas odczytu UMD Slot 1 = Slot 1 Slot 2 = Slot 2 Slot 3 = Slot 3 @@ -1351,6 +1370,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Dysk zapełniony Sustained performance mode = Tryb wysokiej wydajności +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Motyw Time Format = Format czasu Transparent UI background = Przezroczyste tło interfejsu użytkownika @@ -1398,20 +1419,17 @@ Download = Pobierz New version of PPSSPP available = Dostępna jest nowa wersja PPSSPP! [VR] +% of native FoV = % natywnego FoV 6DoF movement = 6DoF movement -Camera type = Typ kamery -Distance to 2D menus and scenes = Dystans do elemtentów 2D -Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Tylko dla ekspertów +Distance to 2D menus and scenes = Dystans do elementów 2D +Distance to 3D scenes when VR disabled = Dystans do scen 3D przy wyłączonym VR +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Skala pola widzenia Force 72Hz update = Wymuś odświeżanie w 72Hz -Game camera rotation step per frame = Krok obrotu kamery gry na klatkę -Game camera uses rotation smoothing = Kamera gry wykorzystuje wygładzanie rotacji Heads-up display detection = Wykrywanie interfejsu w grze Heads-up display scale = Skala interfejsu w grze Manual switching between flat screen and VR using SCREEN key = Ręczne przełączanie między płaskim ekranem a VR za pomocą klawisza SCREEN -Map controller movements to keys = Przypisz ruch kontrolera do przycisków -Map HMD rotations on keys instead of VR camera = Przypisz rotację HMD na przyciskach, zamiast na kamerze VR -Motion needed to generate action = Aby wygenerować akcję, potrzebny jest ruch Stereoscopic vision (Experimental) = Widzenie stereoskopowe (Eksperymentalne) Virtual reality = Wirtualna rzeczywistość VR camera = Kamera VR diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index a5e2328105..22df13ac4e 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -18,7 +18,7 @@ # The hotkeys are only supported currently in the DesktopUI section, however. # # Example 1: &File. This will make it so when you press ALT + F on Windows, it'll open the File menu. -# Example 2: Homebrew && Demos. This would show one real ampersand in the menu. +# Example 2: Homebrew & Demos. This would show one real ampersand in the menu. # # Happy translating. @@ -27,7 +27,7 @@ %1: Attempt started = %1: A tentativa começou %1: Attempt failed = %1: A tentativa falhou Account = Conta -Achievement sound volume = Achievement sound volume +Achievement sound volume = Volume do som das conquistas Achievement unlocked = Conquistas Destrancadas Achievement progress = Progresso das Conquistas Achievements = Conquistas @@ -95,7 +95,9 @@ Enable Sound = Ativar áudio Global volume = Volume global Microphone = Microfone Microphone Device = Dispositivo Microfone +Mix audio with other apps = Misturar o áudio com os outros aplicativos Mute = Mudo +Respect silent mode = Respeitar o modo silencioso Reverb volume = Reverberar volume Use new audio devices automatically = Usar novos dispositivos de áudio automaticamente Use global volume = Usar volume global @@ -257,6 +259,7 @@ Log Console = &Console dos registros Memory View... = Visualização da &memória... More Settings... = &Mais configurações... Nearest = &Mais próximo +Pause when not focused = &Pausar quando não está focado Restart Graphics = Reiniciar os Gráficos Skip Buffer Effects = &Ignorar efeitos do buffer Off = &Desligado @@ -267,7 +270,6 @@ Open Memory Stick = Abrir &cartão de memória Open New Instance = Abrir nova instância OpenGL = &OpenGL Pause = &Pausar -Pause When Not Focused = &Pausar quando não focado Portrait = Retrato Portrait reversed = Retrato invertido PPSSPP Forums = Fórums do &PPSSPP @@ -306,7 +308,7 @@ xBRZ = &xBRZ [Developer] Allocator Viewer = Visualizador do alocador (Vulkan) -Allow remote debugger = Permitir debug remoto +Allow remote debugger = Permitir debugger remoto Audio Debug = Debug do Áudio Backspace = Backspace Block address = Bloquear endereço @@ -333,6 +335,8 @@ FPU = FPU Framedump tests = Testes dos dumps dos frames Frame Profiler = Analista dos frames Frame timing = Tempo do frame +GPI switch %1 = Interruptor do GPI %1 +GPI/GPO switches/LEDs = Interruptores/LEDs do GPI/GPO GPU Allocator Viewer = Visualizador do Distribuidor da GPU GPU Driver Test = Teste do driver da GPU GPU Profile = Perfil da GPU @@ -359,6 +363,7 @@ Run CPU Tests = Executar testes da CPU Save new textures = Salvar novas texturas Shader Viewer = Visualizador dos shaders Show Developer Menu = Mostrar menu do desenvolvedor +Show GPO LEDs = Mostrar os LEDS do GPO Show on-screen messages = Mostrar mensagens na tela Stats = Estatísticas System Information = Informação do sistema @@ -392,6 +397,7 @@ ConfirmLoad = Carregar estes dados? ConnectingAP = Conectando ao ponto de acesso.\nPor favor espere... ConnectingPleaseWait = Conectando.\nPor favor espere... ConnectionName = Nome da conexão +Copy to clipboard = Copy to clipboard Corrupted Data = Dados corrompidos Delete = Apagar Delete all = Apagar tudo @@ -605,7 +611,8 @@ Copy to texture = Copiar pra textura Current GPU Driver = Driver da GPU Atual Default GPU driver = Driver padrão da GPU Disable culling = Desativar o culling -Driver requires Android API version %1, current is %2 = O driver requer a versão da API do Android %1, a atual é %2 +Display layout & effects = Exibir o esquema & efeitos +Driver requires Android API version %1, current is %2 = O driver requer a versão %1 da API do Android, a atual é %2 Drivers = Drivers GPUReadbackRequired = Aviso: Este jogo requer que o "Ignorar Leituras da GPU" esteja definido como Desligado. Both = Ambos @@ -626,7 +633,6 @@ Device = Dispositivo Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disabled = Desativado -Display Layout && Effects = Exibir esquema && efeitos Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) Enable Cardboard VR = Ativa o cartaz da realidade virtual FPS = FPS @@ -644,7 +650,6 @@ High = Alta Hybrid = Híbrido Hybrid + Bicubic = Híbrido + bi-cúbico Ignore camera notch when centering = Ignora o nível da câmera quando centralizar -Install custom driver... = Install custom driver... Install Custom Driver... = Instalar Driver Personalizado... Integer scale factor = Fator de escala do inteiro Internal Resolution = Resolução interna @@ -657,14 +662,15 @@ LowCurves Tip = Usado só por alguns jogos, controla a suavidade das curvas Lower resolution for effects (reduces artifacts) = Resolução menor dos efeitos (reduz artefatos) Manual Scaling = Dimensionamento manual Medium = Média +Mirror camera image = Espelhar a imagem da câmera Mode = Modo Must Restart = Você deve reiniciar o PPSSPP pra esta mudança ter efeito. Native device resolution = Resolução nativa do dispositivo Nearest = Mais próximo No (default) = Não (padrão) No buffer = Sem buffer -Same as Rendering resolution = A mesma que a da resolução de renderização -Show Battery % = Mostrar Bateria % +Same as Rendering resolution = Igual a resolução da renderização +Show Battery % = Mostrar a % da Bateria Show Speed = Mostrar Velocidade Skip = Ignorar Skip Buffer Effects = Ignorar efeitos do buffer @@ -704,7 +710,6 @@ Texture Filtering = Filtragem das texturas Texture replacement pack activated = Pacote de substituição das texturas ativado Texture Scaling = Dimensionamento das texturas Texture Shader = Shader das texturas -The chosen ZIP file doesn't contain a valid driver = The chosen ZIP file doesn't contain a valid driver The file is not a ZIP file containing a compatible driver. = O arquivo não é um arquivo ZIP contendo um driver compatível. Turn off Hardware Tessellation - unsupported = Desligar a "Tesselação por hardware": não suportado. Unlimited = Ilimitado @@ -720,9 +725,12 @@ Window Size = Tamanho da janela xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Apagar arquivo ZIP +Existing data = Existing data Install = Instalar Install game from ZIP file? = Instalar o jogo do arquivo ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Instalar as texturas do arquivo ZIP? Installation failed = A instalação falhou Installed! = Instalado! @@ -741,13 +749,13 @@ Control modifiers = Modificadores do controle Default All = Restaurar os padrões Emulator controls = Controles do emulador Extended PSP controls = Controles extendidos do PSP -Map a new key for = Mapear uma nova tecla pra +Map a new key for = Mapear uma nova tecla pro(a) Map Key = Mapear tecla Map Mouse = Mapear o mouse Replace = Substituir Show PSP = Mostrar o PSP Standard PSP controls = Controles padrão do PSP -Strict combo input order = Strict combo input order +Strict combo input order = Ordem de entrada dos combos restrita You can press ESC to cancel. = Você pode pressionar o Esc pra cancelar. [MainMenu] @@ -798,7 +806,7 @@ Audio/Video Recording = Gravação de Áudio/Vídeo AxisSwap = Trocar eixos Circle = Círculo Cross = Cruz -Custom %d = Personalizar % +Custom %d = Personalizar %d D-pad down = Direcional pra baixo D-pad left = Direcional esquerdo D-pad right = Direcional direito @@ -1017,10 +1025,10 @@ tools = Ferramentas grátis usadas: # Leave extra lines blank. 4 contributors per line seems to look best. translators1 = Papel, gabrielmop, Efraim Lopes, AkiraJkr translators2 = Felipe -translators3 = -translators4 = -translators5 = -translators6 = +translators3 = +translators4 = +translators5 = +translators6 = Twitter @PPSSPP_emu = Twitter @PPSSPP_emu website = Verifique o site da web: written = Escrito em C++ pela velocidade e portabilidade @@ -1076,22 +1084,26 @@ Spanish = Espanhol [RemoteISO] Browse Games = Procurar jogos +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Porta do servidor local Manual Mode Client = Configurar o cliente manualmente +Not currently sharing = Not currently sharing Remote disc streaming = Streaming remoto do disco Remote Port = Porta remota Remote Server = Servidor remoto Remote Subdirectory = Sub-diretório remoto RemoteISODesc = Os jogos na sua lista de "Recentes" serão compartilhados RemoteISOLoading = Conectado, carregando a lista dos jogos... -RemoteISOScanning = Escaneando... Cliqme em "compartilhar jogos" no dispositivo do seu servidor +RemoteISOScanning = Escaneando... Clique em "compartilhar jogos" no dispositivo do seu servidor RemoteISOScanningTimeout = Escaneando... Verifique suas configurações do firewall na área de trabalho RemoteISOWifi = Nota: Conecte os dois dispositivos na mesma rede Wi-Fi RemoteISOWinFirewall = AVISO: O Firewall do Windows está bloqueando o compartilhamento Settings = Configurações Share Games (Server) = Compartilhar jogos (servidor) Share on PPSSPP startup = Compartilhar na inicialização do PPSSPP -Show Remote tab on main screen = Mostrar a aba Remoto na tela principal +Show Remote tab on main screen = Mostrar a aba "Remoto" na tela principal Stop Sharing = Parar com o compartilhamento Stopping.. = Parando... @@ -1147,7 +1159,7 @@ Nothing matching '%1' was found. = Nada combinando com o '%1' foi achado. Save Data = Dados salvos Save States = States salvos Savedata Manager = Gerenciador dos dados dos saves -Showing matches for '%1'. = Mostrando as combinações com o '%1'. +Showing matches for '%1'. = Mostrando as combinações do '%1'. Size = Tamanho [Screen] @@ -1183,10 +1195,12 @@ Connection Error = Erro de conexão Install = Instalar Installed = Instalada Launch Game = Iniciar jogo +License = License Loading... = Carregando... MB = MBs Size = Tamanho Uninstall = Desinstalar +Website = Website [SysInfo] %d (%d per core, %d cores) = %d (%d por núcleo, %d núcleos) @@ -1225,7 +1239,7 @@ GPU Information = Informações da GPU High precision float range = Alcance do flutuante de alta precisão High precision int range = Alcance do inteiro de alta precisão Icon cache = Cache do ícone -Instance = Instance +Instance = Instância JIT available = JIT disponível Lang/Region = Idioma/Região Memory Page Size = Tamanho da página de memória @@ -1245,7 +1259,7 @@ Refresh rate = Taxa de atualização Release = Lançamento RW/RX exclusive = Exclusivo do RW/RX Sample rate = Taxa de amostragem -Screen notch insets = Screen notch insets +Screen notch insets = Inserções dos níveis da tela Shading Language = Idioma do shader Storage = Armazenagem Sustained perf mode = Modo de performance sustentado @@ -1265,6 +1279,7 @@ Display Color Formats = Exibir Formatos das Cores (broken) = (quebrado) 12HR = 12 HRs 24HR = 24 HRs +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto-carregar o state salvo AVI Dump started. = Dump do AVI iniciado @@ -1273,7 +1288,7 @@ Cache ISO in RAM = Pôr a ISO inteira na RAM Change CPU Clock = Mudar o clock da CPU do PSP emulado (instável) CPU Core = Núcleo da CPU Dynarec/JIT (recommended) = Dynarec/JIT (recomendado) -JIT using IR = JIT using IR +JIT using IR = JIT usando o IR Loaded plugin: %1 = Plugin carregado: %1 Memory Stick folder = Pasta do cartão de memória Memory Stick size = Tamanho do cartão de memória @@ -1296,6 +1311,7 @@ Display Homebrew on a grid = Exibir "Homebrew && Demos" em uma grade Display Recent on a grid = Exibir "Recentes" em uma grade Emulation = Emulação Enable Cheats = Ativar trapaças +Enable plugins = Ativar plugins Enable Compatibility Server Reports = Ativar relatórios de compatibilidade com o servidor Error: load undo state is from a different game = Erro: o estado do carregamento desfeito é de um jogo diferente Failed to load state. Error in the file system. = Falhou em carregar o state. Erro no sistema de arquivos. @@ -1327,8 +1343,10 @@ No animation = Sem animação Not a PSP game = Não é um jogo de PSP Off = Desligado Oldest Save = Save mais antigo -Only JPG and PNG images are supported = Only JPG and PNG images are supported +Only JPG and PNG images are supported = Só imagens JPGs e PNGs são suportadas Path does not exist! = O caminho não existe! +Pause when not focused = &Pausar quando não está focado +Plugins = Plugins PSP Memory Stick = Cartão de Memória do PSP PSP Model = Modelo do PSP PSP Settings = Configurações do PSP @@ -1360,6 +1378,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Armazenamento cheio Sustained performance mode = Modo da performance sustentada +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Time Format = Formato da hora Transparent UI background = 2º plano transparente da interface do usuário UI = Interface do usuário @@ -1419,20 +1439,17 @@ Progress: %1% = Progresso: %1% Screen representation = Representação da tela [VR] +% of native FoV = % do campo de visão nativo 6DoF movement = Movimentação do 6DoF Distance to 2D menus and scenes = Distância até os menus e cenas 2D Distance to 3D scenes when VR disabled = Distância nas cenas em 3D quando a realidade virtual está desativada -Experts only = Só pra experts -Game camera rotation step per frame = Passo da rotação da câmera do jogo por frame -Game camera uses rotation smoothing = A câmera do jogo usa suavização da rotação +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Escala do campo de visão Force 72Hz update = Forçar atualização em 72 Hz Heads-up display scale = Escala do aviso antecipado da exibição Heads-up display detection = Detecção do aviso antecipado da exibição -Map controller movements to keys = Mapear os movimentos do controle nas teclas -Map HMD rotations on keys instead of VR camera = Rotações HMD do mapa nas teclas ao invés da câmera da realidade virtual Manual switching between flat screen and VR using SCREEN key = Troca manual entre a tela plana e a realidade virtual usando a tecla da TELA -Camera type = Tipo de câmera -Motion needed to generate action = Movimento necessário pra gerar ação Stereoscopic vision (Experimental) = Visão estereoscópica (Experimental) Virtual reality = Realidade virtual VR camera = Câmera da realidade virtual diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index 0d1d7e85b9..3c7a073712 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -18,7 +18,7 @@ # The hotkeys are only supported currently in the DesktopUI section, however. # # Example 1: &File. This will make it so when you press ALT + F on Windows, it'll open the File menu. -# Example 2: Homebrew && Demos. This would show one real ampersand in the menu. +# Example 2: Homebrew & Demos. This would show one real ampersand in the menu. # # Happy translating. @@ -85,7 +85,7 @@ Unsupported achievements = Conquistas incompatíveis Alternate speed volume = Velocidade alternativa do volume Audio backend = API de áudio (requer reiniciar) Audio Error = Erro no áudio -Audio file format not supported. Must be WAV. = Formato de ficheiro áudio não compatível. Use WAV. +Audio file format not supported. Must be WAV or MP3. = Formato de ficheiro áudio não compatível. Deve ser WAV ou MP3. AudioBufferingForBluetooth = Buffer amigável de Bluetooth (mais lento) Auto = Automático Device = Dispositivo @@ -95,7 +95,9 @@ Enable Sound = Ativar Áudio Global volume = Volume Global Microphone = Microfone Microphone Device = Dispositivo de Microfone +Mix audio with other apps = Mix audio with other apps Mute = Mudo +Respect silent mode = Respect silent mode Reverb volume = Reverberar volume Use new audio devices automatically = Usar novos dispositivos de áudio automaticamente Use global volume = Usar volume global @@ -257,6 +259,7 @@ Log Console = &Console dos Logs Memory View... = Visualização da &memória... More Settings... = &Mais Definições... Nearest = &Mais próximo +Pause when not focused = &Pausar quando a janela não estiver em foco Recent = &Recente Restart Graphics = Restart Graphics Skip Buffer Effects = &Ignorar efeitos de buffer (sem buffer, mais rápido) @@ -268,7 +271,6 @@ Open Memory Stick = Abrir &cartão de memória Open New Instance = Abrir Nova Instância OpenGL = &OpenGL Pause = &Pausar -Pause When Not Focused = &Pausar quando a janela não estiver em foco Portrait = Retrato Portrait reversed = Retrato invertido PPSSPP Forums = Fóruns do &PPSSPP @@ -331,6 +333,8 @@ Fragment = Fragmento Frame timing = Tempo do frame Framedump tests = Testes dos dumps dos frames Frame Profiler = Analista dos frames +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = Visualizador do Distribuidor da GPU GPU Driver Test = Teste do driver da GPU GPU Profile = Perfil da GPU @@ -357,6 +361,7 @@ Run CPU Tests = Executar testes na CPU Save new textures = Guardar novas texturas Shader Viewer = Visualizador dos Shaders Show Developer Menu = Mostrar Menu de Desenvolvedor +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Mostrar mensagens no ecrã Stats = Estatísticas System Information = Informação do sistema @@ -392,6 +397,7 @@ ConfirmLoad = Carregar estes dados? ConnectingAP = A conectar ao ponto de acesso.\nPor favor espere... ConnectingPleaseWait = A conectar.\nPor favor espere... ConnectionName = Nome da conexão +Copy to clipboard = Copy to clipboard Corrupted Data = Dados Corrompidos Delete = Eliminar Delete all = Eliminar tudo @@ -623,7 +629,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Desativado -Display Layout && Effects = Mostrar o editor dos esquemas +Display layout & effects = Mostrar o editor dos esquemas Display Resolution (HW scaler) = Resolução da tela (Dimensionador do hardware) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -656,6 +662,7 @@ LowCurves Tip = Usado só em alguns jogos, controla a suavidade das curvas Lower resolution for effects (reduces artifacts) = Menor Resolução dos efeitos (reduz artefatos) Manual Scaling = Dimensionamento manual Medium = Média +Mirror camera image = Mirror camera image Mode = Modo Must Restart = Deverás reiniciar o PPSSPP para esta mudança ter efeito. Native device resolution = Resolução Nativa do Dispositivo @@ -718,9 +725,12 @@ Window Size = Tamanho da janela xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Eliminar ficheiro .zip +Existing data = Existing data Install = Instalar Install game from ZIP file? = Instalar o jogo do ficheiro .zip? +Install in folder = Install in folder Install textures from ZIP file? = Instalar as texturas do ficheiro .zip? Installation failed = Installation failed Installed! = Instalado! @@ -1076,8 +1086,12 @@ WhatsThis = O que é isto? [RemoteISO] Browse Games = Procurar jogos +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Porta do servidor local Manual Mode Client = Definir o cliente manualmente +Not currently sharing = Not currently sharing Remote disc streaming = Streaming remoto do disco Remote Port = Porta remota Remote Server = Servidor remoto @@ -1183,10 +1197,12 @@ Connection Error = Erro de conexão Install = Instalar Installed = Já instalado Launch Game = Iniciar jogo +License = License Loading... = Carregando... MB = MBs Size = Tamanho Uninstall = Desinstalar +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1265,6 +1281,7 @@ Display Color Formats = Mostrar Formatos das Cores (broken) = (quebrado) 12HR = 12 HRs 24HR = 24 HRs +App switching mode = App switching mode Auto = Automático Auto Load Savestate = Carregar automaticamente o Estado salvo AVI Dump started. = Dump do AVI iniciado @@ -1273,6 +1290,7 @@ Cache ISO in RAM = Colocar a ISO inteira na memória RAM Change CPU Clock = Mudar o clock da CPU da PSP emulado (instável) CPU Core = Núcleo da CPU Dynarec/JIT (recommended) = Dynarec/JIT (recomendado) +Enable plugins = Enable plugins Game crashed = O jogo crashou JIT using IR = JIT using IR Language = Idioma @@ -1329,6 +1347,8 @@ Off = Desativado Oldest Save = Salvamento mais antigo Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = O caminho não existe! +Pause when not focused = &Pausar quando a janela não estiver em foco +Plugins = Plugins PSP Memory Stick = Cartão de memória da PSP PSP Model = Modelo da PSP PSP Settings = Definições da PSP @@ -1360,6 +1380,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Armazenamento cheio Sustained performance mode = Modo de performance sustentado +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Time Format = Formato da hora Transparent UI background = Cenário de fundo da interface do usuário transparente UI = Interface do usuário @@ -1419,20 +1441,17 @@ Progress: %1% = Progresso: %1% Screen representation = Representação da tela [VR] +% of native FoV = % do campo de visão (FoV) nativo 6DoF movement = Movimento 6DoF -Camera type = Tipo de câmera Distance to 2D menus and scenes = Distância aos menus e cenas 2D Distance to 3D scenes when VR disabled = Distância às cenas 3D quando a realidade virtual estiver desativada -Experts only = Apenas programadores +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Escala do campo de visão (FoV) Force 72Hz update = Forçar taxa de atualização de 72Hz -Game camera rotation step per frame = Passo da rotação da câmera do jogo por frame -Game camera uses rotation smoothing = A câmera do jogo usa suavização da rotação Heads-up display detection = Deteção do HUD Heads-up display scale = Escala do HUD Manual switching between flat screen and VR using SCREEN key = Alternar manualmente entre tela plana e realidade virtual usando a tecla da tela -Map controller movements to keys = Mapear movimentos do comando para teclas -Map HMD rotations on keys instead of VR camera = Mapear rotação HMD nas teclas em vez de na câmera de realidade virtual -Motion needed to generate action = Movimento necessário para gerar ação Stereoscopic vision (Experimental) = Visão estereoscópica (experimental) Virtual reality = Realidade Virtual VR camera = Câmera de realidade virtual diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index bdf4b02888..e4fff2753c 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Format intern audio (necesită restartare) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (mai lent) Auto = Automat Device = Device @@ -71,7 +71,9 @@ Enable Sound = Activează Sunet Global volume = Volum global Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -234,6 +236,7 @@ Log Console = &Log Console Memory View... = Memory &View... More Settings... = &More Settings... Nearest = &Nearest +Pause when not focused = &Pause When Not Focused Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skip buffer effects @@ -245,7 +248,6 @@ Open Memory Stick = Open &Memory Stick Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Pause -Pause When Not Focused = &Pause When Not Focused Portrait = Portrait Portrait reversed = Portrait reversed PPSSPP Forums = PPSSPP &Forums @@ -308,6 +310,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -334,6 +338,7 @@ Run CPU Tests = Run CPU tests Save new textures = Save new textures Shader Viewer = Shader viewer Show Developer Menu = Show developer menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = System information @@ -369,6 +374,7 @@ ConfirmLoad = Incarcă datele acestea? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Șterge Delete all = Șterge tot @@ -600,7 +606,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Rezoluție ecran (scalare HW) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -633,6 +639,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Rezoluții mai mici pt. efecte (reduce artefacte) Manual Scaling = Manual scaling Medium = Mediu +Mirror camera image = Mirror camera image Mode = Mod Must Restart = Trebuie să resartezi PPSSPP pt. ca această schimbare să aibă efect. Native device resolution = Rezoluție nativă dispozitiv @@ -695,9 +702,12 @@ Window Size = Mărime ecran xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Șterge fișier ZIP +Existing data = Existing data Install = Instalează Install game from ZIP file? = Instalează joc din fișier ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Instalat! @@ -735,9 +745,9 @@ Exit = Ieșire Game Settings = Setări Games = Jocuri Give PPSSPP permission to access storage = Give PPSSPP permission to access storage -Homebrew & Demos = Homebrew && Demo-uri +Homebrew & Demos = Homebrew & Demo-uri How to get games = Cum pot obține jocuri? -How to get homebrew & demos = Cum pot obține homebrew && demo-uri? +How to get homebrew & demos = Cum pot obține homebrew & demo-uri? Load = Deschide... Loading... = Loading... PinPath = Pin @@ -1051,8 +1061,12 @@ written = Scris in C++ pt. viteză si portabilitate [RemoteISO] Browse Games = Browse games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Local server port Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1166,10 +1180,12 @@ Connection Error = Eroare de conexiune Install = Instalare Installed = Deja instalat Launch Game = Launch game +License = License Loading... = Se încarcă... MB = MB Size = Mărime Uninstall = Dezinstalare +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1248,6 +1264,7 @@ Vulkan Features = Vulkan features (broken) = (broken) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Auto load savestate AVI Dump started. = AVI dump started @@ -1258,6 +1275,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (recommended) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1282,7 +1300,7 @@ Decrease size = Decrease size Developer Tools = Utilități dezvoltator Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulare Enable Cheats = Activează trișare @@ -1314,6 +1332,8 @@ Off = Off Oldest Save = Oldest save Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pause when not focused +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Model PSP PSP Settings = Setări PSP @@ -1346,6 +1366,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Stocare plină Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Format timp Transparent UI background = Transparent UI background @@ -1393,20 +1415,17 @@ Download = Descarcă New version of PPSSPP available = Nouă versiune de PPSSPP disponibilă. [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index 934a66b91b..367804a2cd 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -61,7 +61,7 @@ Unsupported achievements = Неподдерживаемые достижения Alternate speed volume = Громкость при другой скорости Audio backend = Аудио бэкенд (нужен перезапуск) Audio Error = Ошибка звука -Audio file format not supported. Must be WAV. = Формат аудиофайла не поддерживается. Он должен быть WAV. +Audio file format not supported. Must be WAV or MP3. = Формат аудиофайла не поддерживается. Он должен быть WAV/MP3. AudioBufferingForBluetooth = Буфер, подходящий для Bluetooth (медленнее) Auto = Авто Device = Устройство @@ -71,7 +71,9 @@ Enable Sound = Включить звук Global volume = Общая громкость Microphone = Микрофон Microphone Device = Устройство микрофона +Mix audio with other apps = Mix audio with other apps Mute = Без звука +Respect silent mode = Respect silent mode Reverb volume = Громкость реверберации Use new audio devices automatically = Переключаться на новые аудиоустройства автоматически Use global volume = Использовать общую громкость @@ -233,6 +235,7 @@ Log Console = Консоль отладки Memory View... = Просмотрщик па&мяти... More Settings... = &Ещё настройки... Nearest = &Ближайший +Pause when not focused = &Пауза, когда окно не в фокусе Recent = &Недавние Restart Graphics = Перезапустить графику Skip Buffer Effects = &Пропускать эффекты (небуферированный, быстрее) @@ -244,7 +247,6 @@ Open Memory Stick = Открыть карту памяти Open New Instance = Открыть новый экземпляр программы OpenGL = &OpenGL Pause = &Пауза -Pause When Not Focused = &Пауза, когда окно не в фокусе Portrait = Портретная Portrait reversed = Портретная (перевернутая) PPSSPP Forums = &Форум PPSSPP @@ -307,6 +309,8 @@ Fragment = Фрагмент Frame timing = Время кадра Framedump tests = Тест дампов кадров Frame Profiler = Профайлер кадров +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = Просмотрщик аллокатора ГП GPU Driver Test = Проверка драйвера ГП GPU log profiler = Профилировщик логов ГП @@ -333,6 +337,7 @@ Run CPU Tests = Запустить тесты ЦП Save new textures = Сохранять новые текстуры Shader Viewer = Просмотрщик шейдеров Show Developer Menu = Показывать меню разработчика +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Показывать сообщения на экране Stats = Статистика System Information = Информация о системе @@ -368,6 +373,7 @@ ConfirmLoad = Загрузить эти данные? ConnectingAP = Подключение к точке доступа.\nПожалуйста, подождите... ConnectingPleaseWait = Подключение.\nПожалуйста, подождите... ConnectionName = Имя повреждено +Copy to clipboard = Copy to clipboard Corrupted Data = Данные повреждены Delete = Удалить Delete all = Удалить всё @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Отключить отбраковку Disabled = Отключено -Display Layout && Effects = Расположение экрана и эффектов +Display layout & effects = Расположение экрана и эффектов Display Resolution (HW scaler) = Разрешение экрана (аппаратное) Driver requires Android API version %1, current is %2 = Для драйвера требуется Android API версии %1, текущая - %2 Drivers = Драйверы @@ -632,6 +638,7 @@ LowCurves Tip = Используется в некоторых играх, вл Lower resolution for effects (reduces artifacts) = Эффекты низкого качества (меньше артефактов) Manual Scaling = Свой масштаб Medium = Среднее +Mirror camera image = Mirror camera image Mode = Режим Must Restart = Вы должны перезапустить PPSSPP, чтобы изменения вступили в силу. Native device resolution = Разрешение устройства @@ -694,9 +701,12 @@ Window Size = Размер окна xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Удалить файл ZIP +Existing data = Existing data Install = Установить Install game from ZIP file? = Установить игру из файла ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Установить текстуры из файла ZIP? Installation failed = Не удалось установить Installed! = Установлено! @@ -1050,8 +1060,12 @@ WhatsThis = Что это такое? [RemoteISO] Browse Games = Просмотр игр +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Локальный порт сервера Manual Mode Client = Ручной режим клиента +Not currently sharing = Not currently sharing Remote disc streaming = Удалённая трансляция диска Remote Port = Удалённый порт Remote Server = Удалённый сервер @@ -1165,10 +1179,12 @@ Connection Error = Ошибка подключения Install = Установить Installed = Установлено Launch Game = Запустить игру +License = License Loading... = Загрузка... MB = Мб Size = Размер Uninstall = Удалить +Website = Website [SysInfo] %0.2f Hz = %0.2f Гц @@ -1247,6 +1263,7 @@ Vulkan Features = Возможности Vulkan (broken) = (сломано) 12HR = 12-часовой 24HR = 24-часовой +App switching mode = App switching mode Auto = Авто Auto Load Savestate = Автозагрузка состояния AVI Dump started. = Дамп AVI запущен @@ -1257,6 +1274,7 @@ Color Saturation = Насыщенность Color Tint = Оттенок цвета CPU Core = Ядро ЦП Dynarec/JIT (recommended) = Динамическая рекомпиляция/JIT (рекомендуемый) +Enable plugins = Enable plugins Game crashed = Игра вылетела JIT using IR = JIT с использованием IR Language = Язык @@ -1313,6 +1331,8 @@ Off = Отключено Oldest Save = Самое старое сохранение Only JPG and PNG images are supported = Поддерживаются только изображения в формате JPG и PNG Path does not exist! = Путь не существует! +Pause when not focused = &Пауза, когда окно не в фокусе +Plugins = Plugins PSP Memory Stick = Карта памяти PSP PSP Model = Модель PSP PSP Settings = Настройки PSP @@ -1345,6 +1365,8 @@ Slot 4 = Слот 4 Slot 5 = Слот 5 Storage full = Диск заполнен Sustained performance mode = Режим длительной работы +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Тема Time Format = Формат времени Transparent UI background = Прозрачный фон интерфейса @@ -1392,20 +1414,17 @@ Download = Загрузить New version of PPSSPP available = Доступна новая версия PPSSPP [VR] +% of native FoV = % стандартного угла обзора 6DoF movement = Движение 6DoF -Camera type = Тип камеры Distance to 2D menus and scenes = Расстояние до 2D-меню и сцен Distance to 3D scenes when VR disabled = Расстояние до 3D-сцен при отключенной ВР -Experts only = Только для экспертов +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Масштаб угла обзора Force 72Hz update = Принудительная частота обновления 72 Гц -Game camera rotation step per frame = Шаг поворота внутриигровой камеры за 1 кадр -Game camera uses rotation smoothing = При повороте внутриигровой камеры используется сглаживание Heads-up display detection = Обнаружение HUD Heads-up display scale = Масштаб HUD Manual switching between flat screen and VR using SCREEN key = Ручное переключение между плоским экраном и ВР с помощью клавиши SCREEN -Map controller movements to keys = Назначить движения контроллера на клавиши -Map HMD rotations on keys instead of VR camera = Назначить повороты наголовного дисплея на клавиши вместо камеры ВР -Motion needed to generate action = Необходимо движение для создания действия Stereoscopic vision (Experimental) = Стереоизображение (экспериментально) Virtual reality = Виртуальная реальность VR camera = Камера ВР diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 3adc877fef..8f8a098490 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -61,7 +61,7 @@ Unsupported achievements = Icke-stödda achievements Alternate speed volume = Volym vid alternativ hastighet Audio backend = Uppspelningsteknik (ändring kräver omstart!) Audio Error = Ljudfel -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Ljudformat stöds inte. Använd WAV eller MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (slower) Auto = Auto Device = Enhet @@ -71,7 +71,9 @@ Enable Sound = Ljud Global volume = Global volym Microphone = Mikrofon Microphone Device = Mikrofon-enhet +Mix audio with other apps = Mixa ljud med andra appar Mute = Tysta +Respect silent mode = Respektera tyst läge Reverb volume = Volym på reverb-effekt Use new audio devices automatically = Byt automatiskt till senast inkopplad ljudenhet Use global volume = Använd global volym @@ -233,6 +235,7 @@ Log Console = Loggkonsol Memory View... = Minnesvy... More Settings... = Mer inställningar... Nearest = Nearest +Pause when not focused = Pausa vid tappat fokus Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Skippa buffereffekter @@ -244,7 +247,6 @@ Open Memory Stick = Öppna Memory Stick Open New Instance = Öppna ny instans OpenGL = OpenGL Pause = Paus -Pause When Not Focused = Pausa vid tappat fokus Portrait = Porträtt Portrait reversed = Porträtt omvänt PPSSPP Forums = PPSSPP-forum @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump-tester Frame Profiler = Frame-profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU drivrutins-test GPU log profiler = GPU logg-profiler @@ -333,6 +337,7 @@ Run CPU Tests = Kör CPU-tester Save new textures = Spara nya texturer Shader Viewer = Shader-visare Show Developer Menu = Visa Developer-menyn +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Stats System Information = Systeminformation @@ -368,6 +373,7 @@ ConfirmLoad = Ladda denna data? ConnectingAP = Kopplar upp till acceesspunkten.\nVänta... ConnectingPleaseWait = Kopplar upp.\nVänta... ConnectionName = Uppkopplingsnamn +Copy to clipboard = Copy to clipboard Corrupted Data = Korrupt data #Default = Default Delete = Radera @@ -404,7 +410,7 @@ Log in = Logga in Log out = Logga ut Logged in! = Logged in! Logging in... = Logging in... -More information... = More information... +More information... = Mer information... Move = Flytta Move Down = Flytta ner Move Up = Flytta upp @@ -600,7 +606,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Avstängd -Display Layout && Effects = Skärmlayout och effekter +Display layout & effects = Skärmlayout och effekter Display Resolution (HW scaler) = Skärmupplösning (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -633,6 +639,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lägre upplösning för effekter (bättre kvalitet) Manual Scaling = Manuell skalning Medium = Medium +Mirror camera image = Mirror camera image Mode = Mode Must Restart = Starta om PPSSPP för att ändringen ska få effekt. Native device resolution = Native device resolution @@ -695,33 +702,36 @@ Window Size = Fönsterstorlek xBRZ = xBRZ [InstallZip] +Data to import = Data att importera Delete ZIP file = Ta bort ZIP-fil +Existing data = Existerande data Install = Installera Install game from ZIP file? = Installera spel från ZIP-fil? -Install textures from ZIP file? = Install textures from ZIP file? -Installation failed = Installation failed +Install in folder = Installera i mapp +Install textures from ZIP file? = Installera texturer från ZIP-fil? +Installation failed = Installation misslyckades Installed! = Installerad! -Texture pack doesn't support install = Texture pack doesn't support install -Zip archive corrupt = ZIP archive corrupt -Zip file does not contain PSP software = ZIP file does not contain PSP software +Texture pack doesn't support install = Texturpaketet stöder ej installation +Zip archive corrupt = ZIP-filen är korrupt +Zip file does not contain PSP software = ZIP-filen innehåller inte PSP-mjukvara [KeyMapping] -Allow combo mappings = Allow combo mappings +Allow combo mappings = Tillåt combo mappings Autoconfigure = Autokonfiguration Autoconfigure for device = Autokonfigurera för enhet Bind All = Bind All Clear All = Rensa Combo mappings are not enabled = Combo mappings are not enabled -Control modifiers = Control modifiers +Control modifiers = Kontroll-modifiers Default All = Återställ allt -Emulator controls = Emulator controls +Emulator controls = Emulator-kontroller Extended PSP controls = Extended PSP controls Map a new key for = Mappa ny knapp för Map Key = Mappa tangent Map Mouse = Mappa mus -Replace = Replace -Show PSP = Show PSP -Standard PSP controls = Standard PSP controls +Replace = Ersätt +Show PSP = Visa PSP +Standard PSP controls = Standard PSP-kontroller Strict combo input order = Strict combo input order You can press ESC to cancel. = Tryck ESC för att avbryta. @@ -735,11 +745,11 @@ Exit = Avsluta Game Settings = Inställningar Games = Spel Give PPSSPP permission to access storage = Ge PPSSPP tillstånd att komma åt lagring -Homebrew & Demos = Homebrew && Demos +Homebrew & Demos = Homebrew & Demos How to get games = Hur man skaffar spel -How to get homebrew & demos = Hur man skaffar homebrew && demos +How to get homebrew & demos = Hur man skaffar Homebrew & Demos Load = Ladda... -Loading... = Loading... +Loading... = Laddar... PinPath = Fäst PPSSPP can't load games or save right now = PPSSPP can't load games or save right now Recent = Senast spelat @@ -747,7 +757,7 @@ SavesAreTemporary = PPSSPP is saving in temporary storage SavesAreTemporaryGuidance = Extract PPSSPP somewhere to save permanently SavesAreTemporaryIgnore = Ignorera varning UnpinPath = Lossa -UseBrowseOrLoad = Use Browse to choose a folder, or Load to choose a file. +UseBrowseOrLoad = Använd Bläddra för att välja en mapp, eller Ladda för att välja en fil. www.ppsspp.org = www.ppsspp.org [MainSettings] @@ -962,7 +972,7 @@ Vignette = Vignett [PSPCredits] all the forum mods = all the forum mods -build server = build server +build server = bygg-server Buy Gold = Köp Guld check = Kolla också in Dolphin, den bästa Wii/GC-emulatorn CheckOutPPSSPP = Check out PPSSPP, the awesome PSP emulator: https://www.ppsspp.org/ @@ -1051,22 +1061,26 @@ WhatsThis = Vad är detta? [RemoteISO] Browse Games = Bläddra bland spel +Connect = Koppla upp +Currently sharing = Delar +Files to share = Filer att dela Local Server Port = Lokal serverport Manual Mode Client = Manuell klient -Remote disc streaming = Remote disc streaming -Remote Port = Remote port -Remote Server = Remote server -Remote Subdirectory = Remote subdirectory +Not currently sharing = Delar inte +Remote disc streaming = ISO-fjärrstreaming +Remote Port = Fjärr-port +Remote Server = Fjärr-server +Remote Subdirectory = Fjärr-subkatalog RemoteISODesc = Spel i din Senast-lista kommer delas RemoteISOLoading = Uppkopplad, laddar spel-lista... -RemoteISOScanning = Scanning... Click "share games" on your server device -RemoteISOScanningTimeout = Scanning... check your desktop's firewall settings +RemoteISOScanning = Skannar... Klicka "Dela spel" på din server-enhet +RemoteISOScanningTimeout = Skannar... kolla dina brandväggsinställningar RemoteISOWifi = Notera: Koppla båda enheterna till samma Wi-Fi-nätverk RemoteISOWinFirewall = VARNING: Windows Firewall blockerar delning Settings = Inställningar Share Games (Server) = Dela spel (server) Share on PPSSPP startup = Börja dela när PPSSPP startar -Show Remote tab on main screen = Show Remote tab on main screen +Show Remote tab on main screen = Visa Remote-fliken på main screen Stop Sharing = Sluta dela Stopping.. = Slutar... @@ -1166,10 +1180,12 @@ Connection Error = Uppkopplingsfel Install = Installera Installed = Installerad Launch Game = Starta spel +License = Licens Loading... = Laddar... MB = MB Size = Storlek Uninstall = Avinstallera +Website = Website [SysInfo] %d (%d per core, %d cores) = %d (%d per kärna, %d kärnor) @@ -1248,6 +1264,7 @@ Vulkan Features = Vulkan-features (broken) = (broken) 12HR = 12HR 24HR = 24HR +App switching mode = App switching mode Auto = Auto Auto Load Savestate = Ladda savestate automatiskt AVI Dump started. = AVI dump started @@ -1258,6 +1275,7 @@ Color Saturation = Färgmättnad Color Tint = Färgförskjutning CPU Core = CPU-kärna Dynarec/JIT (recommended) = Dynarec/JIT (rekommenderas) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Flytande symboler @@ -1281,7 +1299,7 @@ Decrease size = Minska storlek Developer Tools = Utvecklarverktyg Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Emulering Enable Cheats = Fusk @@ -1314,6 +1332,8 @@ Off = Off Oldest Save = Äldsta sparfilen Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Pausa vid tappat fokus +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP-modell PSP Settings = PSP-inställningar @@ -1346,6 +1366,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Lagringsutrymme fullt Sustained performance mode = Sustained performance mode +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Tema Time Format = Tidsformat Transparent UI background = Genomskinlig UI-bakground @@ -1393,20 +1415,17 @@ Download = Ladda ner New version of PPSSPP available = Ny version av PPSSPP tillgänglig [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF rörelse -Camera type = Kameratyp Distance to 2D menus and scenes = Avstånd till 2D-menyer och scener Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view-skala Force 72Hz update = Tvinga 72Hz uppdateringsfrekvens -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Mappa kontroller-rörelser till knappar -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR-kamera diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 2f0acc8672..a07c5cd806 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -61,7 +61,7 @@ Unsupported achievements = Mga hindi sinusuportahang tagumpay Alternate speed volume = Kahaliling bilis ng tunog Audio backend = Tunog ng instrumento (kailangan pang ulitin) Audio Error = Tunog ng pagkakamali -Audio file format not supported. Must be WAV. = Hindi suportado ang format ng file ng audio. Dapat ay WAV. +Audio file format not supported. Must be WAV or MP3. = Hindi suportado ang format ng file ng audio. Dapat ay WAV/MP3. AudioBufferingForBluetooth = Buffering ng Audio Para sa Bluetooth (mabagal) Auto = Awto Device = Kagamitan @@ -71,7 +71,9 @@ Enable Sound = Paganahin ang tunog Global volume = Pangkalahatang tunog Microphone = Mikropono Microphone Device = Device ng Mikropono +Mix audio with other apps = Mix audio with other apps Mute = Walang tunog +Respect silent mode = Respect silent mode Reverb volume = Maugong na tunog Use new audio devices automatically = Awtomatiko gamitin ang bagong tunog na kagamitan Use global volume = Paggamit ng pangkalahatang tunog @@ -233,6 +235,7 @@ Log Console = Log Console Memory View... = Memory View... More Settings... = Karagdagang settings... Nearest = Pinakamalapit +Pause when not focused = Ihinto kapag hindi naka pokus Recent = &Kamakailan Restart Graphics = I-Restart ang Graphics Skip Buffer Effects = Italon ang buffer effects @@ -244,7 +247,6 @@ Open Memory Stick = Buksan ang Memory Stick Open New Instance = Buksan ang Bagong Instance OpenGL = OpenGL Pause = Ihinto -Pause When Not Focused = Ihinto kapag hindi naka pokus Portrait = Patayo Portrait reversed = Pabaliktad na patayo PPSSPP Forums = PPSSPP Forums @@ -308,6 +310,8 @@ Fragment = Fragment Frame timing = Timing ng frame Framedump tests = Framedump tests Frame Profiler = Frame profiler +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -334,6 +338,7 @@ Run CPU Tests = Magsagawa ng CPU Tests Save new textures = I-save ang mga bagong texture Shader Viewer = Shader viewer Show Developer Menu = Ipakita ang Developer Menu +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Ipakita ang mensahe sa screen Stats = Istatistik System Information = Impormasyon tungkol sa sistema @@ -369,6 +374,7 @@ ConfirmLoad = Nais mo bang i-load ang datos? ConnectingAP = Kumokonekta na sa access point.\nSandali lamang... ConnectingPleaseWait = Kumokonekta na.\nSandali lamang... ConnectionName = Pangalan ng Koneksyon +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted ang data Delete = Burahin Delete all = Burahin Lahat @@ -600,7 +606,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Disabled -Display Layout && Effects = Display layout && effects +Display layout & effects = Display layout & effects Display Resolution (HW scaler) = Display resolution (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -633,6 +639,7 @@ LowCurves Tip = Only used by some games, controls smoothness of curves Lower resolution for effects (reduces artifacts) = Lower resolution for effects (reduces artifacts) Manual Scaling = Manual scaling Medium = Medium +Mirror camera image = Mirror camera image Mode = Mode Must Restart = Kailangan i-restart ang PPSSPP upang maging epiktibo ito Native device resolution = Native device resolution @@ -695,9 +702,12 @@ Window Size = Window size xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Burahin ang ZIP File +Existing data = Existing data Install = Install Install game from ZIP file? = I-install ang laro mula sa ZIP file? +Install in folder = Install in folder Install textures from ZIP file? = I-install ang texture mula sa ZIP file? Installation failed = Hindi mainstall Installed! = Naka-install na! @@ -741,7 +751,7 @@ How to get homebrew & demos = Paano makakukuha ng Homebrew at Demos Load = Ikarga Loading... = Nagkakarga... PinPath = I-Pin -PPSSPP can't load games or save right now = Ang PPSSPP ay hindi makapag-bukas/karga ng laro o save file +PPSSPP can't load games or save right now = Ang PPSSPP ay hindi makapag-bukas/karga ng laro o save file Recent = Nakaraang nilaro SavesAreTemporary = Ang PPSSPP ay sinesave sa pansamantalang storage SavesAreTemporaryGuidance = I-Extract ang PPSSPP kahit saan para itabi ng permanente @@ -1051,8 +1061,12 @@ written = Nakasulat sa C++ para sa bilis at portability [RemoteISO] Browse Games = I-browse ang mga laro +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Port ng lokal na server Manual Mode Client = Manual mode client +Not currently sharing = Not currently sharing Remote disc streaming = Remote disc streaming Remote Port = Remote port Remote Server = Remote server @@ -1134,7 +1148,7 @@ Failed to save state = Pumalya sa pag save ng save state fixed = Bilis: Salitan GLToolsWarning = Babala: Natukoy ang GLTools, maaaring magdulot ng mga problema. In menu = Sa menu -Load savestate failed = Pumalya sa pag load ng save state +#Load savestate failed = Pumalya sa pag load ng save state Loaded State = Nai-load na ang Load State Loaded. Game may refuse to save over different savedata. = Nakarga. Maaaring tumangging mag-save ang laro sa iba't ibang savedata. Loaded. Game may refuse to save over newer savedata. = Nakarga. Maaaring tumangging mag-save ang laro sa mas bagong savedata. @@ -1146,7 +1160,7 @@ Playing = Naglalaro PressESC = Pindutin ang ESC para mabuksan ang pause menu. replaceTextures_false = Hindi na pinapalitan ang mga texture. replaceTextures_true = Ang pagpapalit ng texture ay pinagana. -Save State Failed = Pumalya sa pag-save! +#Save State Failed = Pumalya sa pag-save! Saved State = Nai-save na ang kasalukuyang estado. saveNewTextures_false = Na-disable ang pag-save ng texture. saveNewTextures_true = Ise-save na ngayon ang mga texture sa iyong storage. @@ -1168,10 +1182,12 @@ Connection Error = May error sa Koneksyon. Install = I-Install Installed = Na-installed na Launch Game = Buksan ang laro +License = License Loading... = Binabasa... MB = MB Size = Sukat Uninstall = I-Uninstall +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1223,7 +1239,7 @@ OpenGL ES 3.0 Extensions = Mga Ekstensyon ni OpenGL ES 3.0 OpenGL Extensions = Mga Ekstensyon ni OpenGL Optimal frames per buffer = Optimal frames per buffer Optimal sample rate = Optimal sample rate -OS Information = Impormasyon ng iyong OS +OS Information = Impormasyon ng iyong OS Pixel resolution = Pixel resolution PPSSPP build = PPSSPP build Present modes = Kasalukuyan na 'modes' @@ -1250,6 +1266,7 @@ Vulkan Features = Mga Features ni Vulkan (broken) = (sira) 12HR = 12 Oras 24HR = 24 Oras +App switching mode = App switching mode Auto = Awto Auto Load Savestate = Awtomatik na pag load sa savestate AVI Dump started. = Nasimula na ang AVI dump @@ -1260,6 +1277,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (inirerekomenda) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: ang load undo state ay mula sa ibang laro Failed to load state for load undo. Error in the file system. = Nabigong i-load ang estado para sa pag-undo ng pag-load. Error sa file system. Floating symbols = Lumulutang na mga simbolo @@ -1284,7 +1302,7 @@ Decrease size = Paliitin ang sukat Developer Tools = Gamit ng developers Display Extra Info = Ipakita ang ekstrang impormasyon Display Games on a grid = Display "Mga laro" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Nakaraang nilaro" on a grid Emulation = Emulation Enable Cheats = Paganahin ang pandaraya @@ -1316,6 +1334,8 @@ Off = Nakapatay Oldest Save = Pinakalumang na i-save Only JPG and PNG images are supported = Tanging ang mga JPG at PNG na mga imahe ang sinusuportahan Path does not exist! = Hindi matagpuan ang sinasabing 'path'! +Pause when not focused = Ihinto kapag hindi naka pokus +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Modelo ng PSP PSP Settings = Settings ng PSP @@ -1348,6 +1368,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Puno na ang storage Sustained performance mode = Buksan ang 'Sustained performance mode' +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Pormat ng oras Transparent UI background = Transparent na UI background @@ -1396,20 +1418,17 @@ Download = Download New version of PPSSPP available = Meron nang bagong bersiyon ang PPSSPP [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Uri ng Camera Distance to 2D menus and scenes = Distansya sa mga 2D na menu at mga eksena Distance to 3D scenes when VR disabled = Distansya sa mga 3D na eksena noong hindi pinagana ang VR -Experts only = Mga eksperto lamang +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Hakbang sa pag-ikot ng camera ng laro sa bawat frame -Game camera uses rotation smoothing = Gumagamit ng rotation smoothing ang camera ng laro Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manu-manong pagpalipat-lipat sa pagitan ng flat screen at VR gamit ang SCREEN key -Map controller movements to keys = I-map ang mga paggalaw ng controller sa mga key -Map HMD rotations on keys instead of VR camera = I-map ang mga pag-ikot ng HMD sa mga key sa halip na VR camera -Motion needed to generate action = Kailangan ang paggalaw upang makabuo ng pagkilos Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual na Reyalidad VR camera = VR camera diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index a4d686d86f..9aabb24787 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -61,7 +61,7 @@ Unsupported achievements = เป้าหมายความสำเร็ Alternate speed volume = ระดับเสียงในโหมดเร่งความเร็ว Audio backend = รูปแบบเสียงที่สนับสนุน (จำเป็นต้องรีสตาร์ท) Audio Error = ระบบเสียงเกิดข้อผิดพลาด -Audio file format not supported. Must be WAV. = ไม่รองรับรูปแบบไฟล์เสียงประเภทนี้ จะใช้ได้แค่เฉพาะรูปแบบ WAV +Audio file format not supported. Must be WAV or MP3. = ไม่รองรับรูปแบบไฟล์เสียงประเภทนี้ จะใช้ได้แค่เฉพาะรูปแบบ WAV/MP3 AudioBufferingForBluetooth = บลูทูธ-เฟรนด์ลี่ บัฟเฟอร์ (ช้ากว่า) Auto = อัตโนมัติ Device = อุปกรณ์ @@ -71,7 +71,9 @@ Enable Sound = เปิดการใช้งานเสียง Global volume = ระดับเสียงหลัก Microphone = ไมโครโฟน Microphone Device = อุปกรณ์ไมโครโฟน +Mix audio with other apps = Mix audio with other apps Mute = เงียบ +Respect silent mode = Respect silent mode Reverb volume = ระดับเสียงก้อง Use global volume = ใช้ตามระดับเสียงหลัก Use new audio devices automatically = สลับไปใช้อุปกรณ์เสียงอันใหม่อัตโนมัติ @@ -233,6 +235,7 @@ Log Console = เก็บค่าคอนโซล Memory View... = มุมมองค่าความจำ... More Settings... = การตั้งค่าอื่นๆ... Nearest = แบบใกล้เคียง +Pause when not focused = หยุดชั่วคราวเมื่อไม่ได้เล่น Recent = &ครั้งล่าสุด Restart Graphics = รีสตาร์ทระบบกราฟิก Skip Buffer Effects = ข้ามการใช้บัฟเฟอร์เอฟเฟ็คท์ (ปิดบัฟเฟอร์) @@ -244,7 +247,6 @@ Open Memory Stick = เปิดที่เก็บบันทึกข้อ Open New Instance = เปิดหน้าจอแยกใหม่ OpenGL = โอเพ่นจีแอล Pause = หยุดชั่วคราว -Pause When Not Focused = หยุดชั่วคราวเมื่อไม่ได้เล่น Portrait = แนวตั้ง Portrait reversed = แนวตั้งกลับด้าน PPSSPP Forums = เว็บ PPSSPP Forums @@ -308,6 +310,8 @@ Framebuffer List = รายการของเฟรมบัฟเฟอร Framedump tests = ทดสอบไฟล์เฟรมดั๊มพ์ Frame Profiler = รายละเอียดของเฟรม Frame timing = ช่วงเวลาของเฟรม +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = ตัวแสดงการจัดสรร GPU GPU Driver Test = ทดสอบไดรเวอร์ GPU GPU log profiler = ตัวแสดงค่าโปรไฟล์ GPU @@ -334,6 +338,7 @@ Run CPU Tests = เรียกใช้การทดสอบซีพีย Save new textures = บันทึกพื้นผิวลงในแหล่งที่เก็บข้อมูล Shader Viewer = มุมมองการปรับเฉดแสงสี Show Developer Menu = แสดงเมนูสำหรับนักพัฒนา +Show GPO LEDs = Show GPO LEDs Show on-screen messages = แสดงข้อความการแจ้งเตือนต่างๆ Stats = สถิติ System Information = ข้อมูลโดยรวมของระบบ @@ -369,6 +374,7 @@ ConfirmLoad = ต้องการโหลดข้อมูลนี้หร ConnectingAP = กำลังเชื่อมต่อกับแอคเซสพอยต์\nโปรดรอสักครู่... ConnectingPleaseWait = กำลังเชื่อมต่อ\nโปรดรอ... ConnectionName = ชื่อเครือข่าย +Copy to clipboard = Copy to clipboard Corrupted Data = ข้อมูลเสียหาย Delete = ลบ Delete all = ลบทั้งหมด @@ -603,7 +609,7 @@ Direct3D 9 = ไดเร็คท์ 3D 9 Direct3D 11 = ไดเร็คท์ 3D 11 Disable culling = ปิดการใช้งาน culling Disabled = ปิดการใช้งาน -Display Layout && Effects = รูปแบบหน้าจอ และเอฟเฟ็คท์ +Display layout & effects = รูปแบบหน้าจอ และเอฟเฟ็คท์ Display Resolution (HW scaler) = ความละเอียดหน้าจอ (ตามฮาร์ดแวร์) Driver requires Android API version %1, current is %2 = ไดรเวอร์นี้ต้องการแอนดรอยด์ API ที่เวอร์ชั่น %1, แต่มือถือนี้ใช้เวอร์ชั่น %2 Drivers = ไดรเวอร์ @@ -638,6 +644,7 @@ LowCurves Tip = ใช้แค่ในบางเกม ช่วยปรั Lower resolution for effects (reduces artifacts) = ลดความละเอียดของเอฟเฟ็คต์ให้ต่ำลง (ลดขอบภาพสว่าง) Manual Scaling = กำหนดขนาดเอง Medium = ปานกลาง +Mirror camera image = Mirror camera image Mode = โหมด Must Restart = คุณควรรีสตาร์ท PPSSPP อีกครั้งนึง เพื่อให้เกิดผลลัพธ์ที่เปลี่ยนแปลง Native device resolution = ค่าความละเอียดดั้งเดิมของอุปกรณ์ @@ -701,9 +708,12 @@ Window Size = ขนาดของหน้าจอ xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = ลบไฟล์ ZIP +Existing data = Existing data Install = ติดตั้ง Install game from ZIP file? = ต้องการติดตั้งเกมจากไฟล์ ZIP เลยหรือไม่? +Install in folder = Install in folder Install textures from ZIP file? = ต้องการติดตั้งเท็คเจอร์จากไฟล์ ZIP เลยหรือไม่? Installation failed = การติดตั้งล้มเหลว Installed! = ติดตั้งเสร็จสิ้น! @@ -740,9 +750,9 @@ Exit = ออก Game Settings = ตั้งค่าเกม Games = เกมอื่นๆ Give PPSSPP permission to access storage = อนุญาตให้สิทธิ์เข้าถึงพื้นที่เก็บข้อมูลเครื่องผ่าน PPSSPP -Homebrew & Demos = เกมโฮมบริว&&เกมทดลองเล่น +Homebrew & Demos = เกมโฮมบริว&เกมทดลองเล่น How to get games = ต้องทำอย่างไรถึงจะได้รอมเกมมา? -How to get homebrew & demos = วิธีการรับเกมโฮมบริว&&เกมทดลองเล่น? +How to get homebrew & demos = วิธีการรับเกมโฮมบริว&เกมทดลองเล่น? Load = โหลด... Loading... = กำลังโหลด... PinPath = ปักหมุด @@ -1058,10 +1068,13 @@ written = เขียนโดยใช้ภาษา C++ เพื่อค [RemoteISO] Browse Games = ค้นหาไปยังเกม Choose directory = เลือกไปที่เส้นทางโฟลเดอร์ +Connect = Connect +Currently sharing = Currently sharing Default = ค่าดั้งเดิม Files to share = ไฟล์ที่ต้องการแชร์ Local Server Port = พอร์ตเซิร์ฟเวอร์แหล่งภายใน Manual Mode Client = ไคลเอ็นต์โหมดใช้งานด้วยตนเอง +Not currently sharing = Not currently sharing Recent files = ไฟล์เกมที่เล่นล่าสุด Remote disc streaming = เล่นเกมผ่านสตรีมมิ่ง Remote Port = ควบคุมพอร์ตจากระยะไกล @@ -1176,10 +1189,12 @@ Connection Error = การเชื่อมต่อล้มเหลว Install = ติดตั้ง Installed = ติดตั้งเรียบร้อย Launch Game = เริ่มเกม +License = License Loading... = กำลังโหลด... MB = เมกกะไบต์ Size = ขนาด Uninstall = ถอนการติดตั้ง +Website = Website [SysInfo] %0.2f Hz = %0.2f เฮิร์ต @@ -1274,6 +1289,7 @@ Warning = คำเตือน (broken) = (เสียหาย) 12HR = 12 ชั่วโมง 24HR = 24 ชั่วโมง +App switching mode = App switching mode Auto = อัตโนมัติ Auto Load Savestate = โหลดเซฟสเตทให้อัตโนมัติ AVI Dump started. = เริ่มการอัดบันทึกวีดีโอ @@ -1304,6 +1320,7 @@ Dynarec/JIT (recommended) = ไดนาเร็ค/JIT (แนะนำ) Emulation = การจำลองเสมือน Enable Cheats = เปิดใช้งานสูตรโกง Enable Compatibility Server Reports = เปิดใช้การส่ง-แนบรายงานข้อมูลเกมไปยังเซิร์ฟเวอร์ +Enable plugins = Enable plugins Error: load undo state is from a different game = ข้อผิดพลาด: โหลดข้อมูลสเตทที่สำรองไว้ มาจากคนละเกมกัน Failed to load state for load undo. Error in the file system. = ล้มเหลวในการโหลดสเตทเกมที่สำรองไว้ เนื่องจากไฟล์ระบบเสียหาย Failed to load state. Error in the file system. = ล้มเหลวในการโหลดสเตทเกม เนื่องจากไฟล์ระบบเสียหาย @@ -1340,6 +1357,8 @@ Off = ปิด Oldest Save = เซฟอันเก่าสุด Only JPG and PNG images are supported = รองรับเฉพาะไฟล์รูปภาพนามสกุล JPG และ PNG Path does not exist! = ไม่มีเส้นทางนี้อยู่! +Pause when not focused = หยุดชั่วคราวเมื่อไม่ได้เล่น +Plugins = Plugins PSP Memory Stick = แหล่งเก็บข้อมูล PSP PSP Model = โมเดลของ PSP PSP Settings = การตั้งค่า PSP @@ -1372,6 +1391,8 @@ Slot 4 = เซฟช่องที่ 4 Slot 5 = เซฟช่องที่ 5 Storage full = ที่เก็บข้อมูลเต็ม Sustained performance mode = โหมดประสิทธิภาพที่ยั่งยืน +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = ธีม Time Format = รูปแบบเวลา Transparent UI background = พื้นหลังของอินเตอร์เฟซแบบโปร่งใส @@ -1420,25 +1441,18 @@ Download = ดาวน์โหลด New version of PPSSPP available = PPSSPP เวอร์ชั่นใหม่พร้อมให้ดาวน์โหลดแล้ว! [VR] +% of native FoV = % ของค่า FoV ดั้งเดิม 6DoF movement = การเคลื่อนไหวแบบ 6DoF -Camera type = ปรับแต่งประเภทมุมกล้อง -Disabled = ปิดการใช้งาน Distance to 2D menus and scenes = ระยะห่างจากเมนูสองมิติ และฉาก Distance to 3D scenes when VR disabled = ระยะห่างจากฉากสามมิติ เมื่อ VR ถูกปิดใช้งาน +Enable immersive mode = Enable immersive mode Enable passthrough = เปิดใช้งานการส่งผ่าน -Experts only = สำหรับผู้เชี่ยวชาญเท่านั้น -First person -> Top view = มุมมองบุคคลที่หนึ่ง -> มุมมองจากด้านบน +Field of view scale = สเกลของมุมมองพื้นที่รอบตัว Force 72Hz update = บังคับรีเฟรชเรทไปที่ 72Hz -Game camera rotation step per frame = สเต็ปการหมุนมุมกล้องเกมต่อเฟรม -Game camera uses rotation smoothing = มุมกล้องเกมใช้การหมุนแบบนุ่มนวล Heads-up display detection = การตรวจจับ HUD Heads-up display scale = สเกลขนาดของ HUD Manual switching between flat screen and VR using SCREEN key = สลับโหมดระหว่าง จอแบน และ VR โดยใช้ปุ่ม SCREEN -Map controller movements to keys = เซ็ตปุ่มควบคุมด้วยท่าทางผ่านจอย -Map HMD rotations on keys instead of VR camera = เซ็ตการควบคุมการหมุน HMD โดยใช้ปุ่มกด แทนการใช้กล้อง VR -Motion needed to generate action = จำเป็นต้องขยับท่าทางเพื่อเซ็ตปุ่มที่ต้องการ Stereoscopic vision (Experimental) = มุมมองภาพแบบสามมิติ (ขั้นทดสอบ) -Top view -> First person = มุมมองจากด้านบน -> มุมมองบุคคลที่หนึ่ง Virtual reality = ความเป็นจริงเสมือน VR camera = มุมกล้อง VR VR controllers = จอยควบคุม VR diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index 346c7f6de4..06c80a32ba 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -1,67 +1,67 @@ [Achievements] -%1: Attempt failed = %1: Attempt failed -%1: Attempt started = %1: Attempt started -%1 achievements, %2 points = %1 achievements, %2 points -Account = Account -Achievement progress = Achievement progress -Achievement sound volume = Achievement sound volume -Achievement unlocked = Achievement unlocked -Achievements = Achievements -Achievements are disabled = Achievements are disabled -Achievements enabled = Achievements enabled -Achievements with active challenges = Achievements with active challenges -Allow Save State in Hardcore Mode (but not Load State) = Allow Save State in Hardcore Mode (but not Load State) -Almost completed achievements = Almost completed achievements -Around me = Around me -Can't log in to RetroAchievements right now = Can't log in to RetroAchievements right now -Challenge indicator = Challenge indicator -Contacting RetroAchievements server... = Contacting RetroAchievements server... -Customize = Customize -Earned = You have unlocked %1 of %2 achievements, and earned %3 of %4 points -Encore Mode = Encore Mode -Failed logging in to RetroAchievements = Failed logging in to RetroAchievements -Failed to connect to RetroAchievements. Achievements will not unlock. = Failed to connect to RetroAchievements. Achievements will not unlock. -Failed to identify game. Achievements will not unlock. = Failed to identify game. Achievements will not unlock. -Hardcore Mode (no savestates) = Hardcore Mode (no savestates) -Hardcore Mode = Hardcore Mode -How to use RetroAchievements = How to use RetroAchievements -In Encore mode - listings may be wrong below = In Encore mode - listings may be wrong below -Leaderboard attempt started or failed = Leaderboard attempt started or failed -Leaderboard result submitted = Leaderboard result submitted -Leaderboard score submission = Leaderboard score submission -Leaderboard submission is enabled = Leaderboard submission is enabled -Leaderboard tracker = Leaderboard tracker -Leaderboards = Leaderboards -Links = Links -Locked achievements = Locked achievements -Log bad memory accesses = Log bad memory accesses -Mastered %1 = Mastered %1 -Notifications = Notifications -Recently unlocked achievements = Recently unlocked achievements -Reconnected to RetroAchievements. = Reconnected to RetroAchievements. -Register on www.retroachievements.org = Register on www.retroachievements.org -RetroAchievements are not available for this game = RetroAchievements are not available for this game -RetroAchievements website = RetroAchievements website +%1: Attempt failed = %1: Deneme başarısız oldu +%1: Attempt started = %1: Deneme başladı +%1 achievements, %2 points = %1 başarım, %2 puan +Account = Hesap +Achievement progress = Başarım ilerlemesi +Achievement sound volume = Başarım ses ayarı +Achievement unlocked = Başarımın kilidi açıldı +Achievements = Başarımlar +Achievements are disabled = Başarımlar devre dışı +Achievements enabled = Başarımlar etkin +Achievements with active challenges = Etkin mücadeleler içeren başarımlar +Allow Save State in Hardcore Mode (but not Load State) = Hardcore Modda Durum Kayıtlarına izin verin (yükleme durumu değil) +Almost completed achievements = Neredeyse tamamlanmış başarımlar +Around me = Etrafımda +Can't log in to RetroAchievements right now = RetroAchievements'a şu anda giriş yapılamıyor +Challenge indicator = Mücadele işareti +Contacting RetroAchievements server... = RetroAchievements sunucusuna bağlanılıyor... +Customize = Özelleştir +Earned = %2 başarımın %1 kadarının kilidini açtınız ve %4 puanın %3 kadarını kazandınız +Encore Mode = Encore Mod +Failed logging in to RetroAchievements = RetroAchievements'a giriş başarısız oldu +Failed to connect to RetroAchievements. Achievements will not unlock. = RetroAchievements'a bağlantı başarısız oldu. Başarımların kilidi açılmayacak. +Failed to identify game. Achievements will not unlock. = Oyun belirlenemedi. Başarımların kilidi açılmayacak. +Hardcore Mode (no savestates) = Hardcore Mod (durum kaydı yok) +Hardcore Mode = Hardcore Mod +How to use RetroAchievements = RetroAchievements nasıl kullanılır +In Encore mode - listings may be wrong below = Encore moddasınız - aşağıdaki listelemeler yanlış olabilir +Leaderboard attempt started or failed = Liderlik tablosu denemesi başladı veya başarısız oldu +Leaderboard result submitted = Liderlik tablosu sonucu kaydedildi +Leaderboard score submission = Liderlik tablosu skoru kaydetme +Leaderboard submission is enabled = Liderlik tablosu kaydetme etkin +Leaderboard tracker = Liderlik tablosu izleyici +Leaderboards = Liderlik tabloları +Links = Bağlantılar +Locked achievements = Kilitli başarımlar +Log bad memory accesses = Kötü bellek erişimlerini günlükle +Mastered %1 = %1 ustalaşıldı +Notifications = Bildirimler +Recently unlocked achievements = Yakın zamanda kilidi açılan başarımlar +Reconnected to RetroAchievements. = RetroAchievements'a yeniden bağlanıldı. +Register on www.retroachievements.org = www.retroachievements.org'da kaydolun +RetroAchievements are not available for this game = RetroAchievements bu oyunda kullanılamaz +RetroAchievements website = RetroAchievements web sitesi Rich Presence = Rich Presence -Save state loaded without achievement data = Save state loaded without achievement data -Save states not available in Hardcore Mode = Save states not available in Hardcore Mode -Sound Effects = Sound Effects -Statistics = Statistics -Submitted %1 for %2 = Submitted %1 for %2 -Syncing achievements data... = Syncing achievements data... -Test Mode = Test Mode -This feature is not available in Hardcore Mode = This feature is not available in Hardcore Mode -This game has no achievements = This game has no achievements -Top players = Top players -Unlocked achievements = Unlocked achievements -Unofficial achievements = Unofficial achievements -Unsupported achievements = Unsupported achievements +Save state loaded without achievement data = Başarım verileri olmadan durum kaydını kaydet +Save states not available in Hardcore Mode = Durum kayıtları Hardcore Mod'da kullanılamaz +Sound Effects = Ses Efektleri +Statistics = İstatistikler +Submitted %1 for %2 = %2 için %1 kaydedildi +Syncing achievements data... = Başarım verileri eşitleniyor... +Test Mode = Sınama Modu +This feature is not available in Hardcore Mode = Bu özellik Hardcore Mod'da kullanılamaz +This game has no achievements = Bu oyunun başarımları yok +Top players = En iyi oyuncular +Unlocked achievements = Kilidi açılmış başarımlar +Unofficial achievements = Resmi olmayan başarımlar +Unsupported achievements = Desteklenmeyen başarımlar [Audio] Alternate speed volume = Alternatif hız hacmi Audio backend = Ses alttabanı (Yeniden başlatma gerekir) Audio Error = Ses Hatası -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Ses dosya biçimi desteklenmiyor. WAV, MP3 olmalı. AudioBufferingForBluetooth = Bluetooth uyumlu arabellek (daha yavaş) Auto = Otomatik Device = Cihaz @@ -71,7 +71,9 @@ Enable Sound = Sesi etkinleştir Global volume = Genel ses Microphone = Mikrofon Microphone Device = Mikrofon cihazı +Mix audio with other apps = Mix audio with other apps Mute = Sessiz +Respect silent mode = Respect silent mode Reverb volume = Yankı sesi Use new audio devices automatically = Otomatik olarak yeni ses cihazlarını kullan Use global volume = Genel ses seviyesini kullan @@ -83,7 +85,7 @@ Analog Limiter = Analog sınırlayıcı Analog Settings = Analog Ayarları Analog Stick = Analog çubuk Analog Style = Analog Biçimi -Analog trigger threshold = Analog trigger threshold +Analog trigger threshold = Analog tetik eşiği AnalogLimiter Tip = Analog sınırlayıcı tuşuna basınca Auto = Otomatik Auto-centering analog stick = Analog çubuğu otomatik ortala @@ -97,7 +99,7 @@ Calibrate Analog Stick = Analog Çubuğu Kalibre Et Calibrate = Kalibre Calibrated = Kalibre edildi Calibration = Kalibrasyon -Circular deadzone = Circular deadzone +Circular deadzone = Dairesel ölü bölge Circular stick input = Dairesel çubuk girişi Classic = Klasik Confine Mouse = Fareyi belirli bir pencere/görüntü alanı içinde sınırla @@ -110,10 +112,10 @@ Deadzone radius = Ölü bölge yarıçapı Disable D-Pad diagonals (4-way touch) = D-Pad'i devre dışı bırak (4'lü Yön Tuşları) Disable diagonal input = Diyagonal girişi devre dışı bırak Double tap = Çift dokunma -Enable analog stick gesture = Enable analog stick gesture +Enable analog stick gesture = Analog çubuk hareketini etkinleştir Enable gesture control = Hareket kontrolünü etkinleştir Enable standard shortcut keys = Standart kısayol tuşlarını etkinleştir -frames = frames +frames = kareler Gesture = Hareket Gesture mapping = Hareket kontrollerini düzenle Glowing borders = Parlayan kenarlar @@ -135,7 +137,7 @@ Low end radius = Düşük uç yarıçapı Mouse = Fare ayarları Mouse sensitivity = Fare hassasiyeti Mouse smoothing = Fare yumuşatma -Mouse wheel button-release delay = Mouse wheel button-release delay +Mouse wheel button-release delay = Fare tekerleği tuşunu bırakma gecikmesi MouseControl Tip = Fareye 'Kontrolleri Ayarlama' bölümünden 'M' simgesine basarak kontrol atayabilirsiniz. None (Disabled) = Hiçbiri (Devre dışı) Off = Kapalı @@ -143,7 +145,7 @@ OnScreen = Dokunmatik ekran kontrolleri Portrait = Dikey Portrait Reversed = Ters dikey PSP Action Buttons = PSP eylem tuşları -Rapid fire interval = Rapid fire interval +Rapid fire interval = Hızlı ateş aralığı Raw input = Saf girdi Repeat mode = Tekrar modu Reset to defaults = Varsayılanlara sıfırla @@ -152,7 +154,7 @@ Sensitivity (scale) = Hassasiyet (ölçek) Sensitivity = Hassasiyet Shape = Şekil Show Touch Pause Menu Button = Duraklama menüsü tuşunu göster -Sticky D-Pad (easier sweeping movements) = Sticky D-Pad (easier sweeping movements) +Sticky D-Pad (easier sweeping movements) = Yapışkan D-Pad (daha kolay sürükleme hareketleri) Swipe = Kaydır Swipe sensitivity = Kaydırma hassasiyeti Swipe smoothing = Pürüzsüz kaydırma @@ -161,7 +163,7 @@ Tilt control setup = Eğimi düzenle... Tilt Input Type = Eğim giriş türü Tilt Sensitivity along X axis = X ekseni boyunca eğim hassasiyeti Tilt Sensitivity along Y axis = Y ekseni boyunca eğim hassasiyeti -To Calibrate = Cihazı tercih ettiğiniz açıda tutun ve "Kalibre" ya basın. +To Calibrate = Cihazı tercih ettiğiniz açıda tutun ve "Kalibre"ye basın. Toggle mode = Geçiş modu Touch Control Visibility = Dokunmatik kontrol görünürlüğü Use custom right analog = Özel sağ analog kullan @@ -189,20 +191,20 @@ Auto = &Otomatik Auto Max Quality = Otomatik en yüksek &kalite Backend = Oluşturma &Arkaucu (PPSSPP'yi yeniden başlatır) Bicubic = &Bikübik -Break = Break -Break on Load = Break on load -Buy Gold = Altın Sürümünü Satın Al +Break = Kırılma +Break on Load = Yüklemede kırılma +Buy Gold = Gold Sürümünü Satın Al Control Mapping... = Kontrol Ayarlama... -Copy PSP memory base address = Copy PSP memory base &address +Copy PSP memory base address = PSP bellek tabanı &adresini kopyala Debugging = &Hata Ayıklama Deposterize = &Deposterize Direct3D9 = &Direct3D9 Direct3D11 = Direct3D &11 -Disassembly = &Disassembly... +Disassembly = &Sökme... Discord = Discord Display Layout && Effects = Ekran düzeni düzenleyici... Display Rotation = Ekran rotasyonu -Dump Next Frame to Log = D&ump Next Frame to Log +Dump Next Frame to Log = Sonraki Kareyi Günlüğe D&ökümle Emulation = &Emülasyon Enable Cheats = &Hileleri Aç Enable Sound = Sesi Aç @@ -213,7 +215,7 @@ Frame Skipping = &Kare Atlama Frame Skipping Type = Kare atlama türü Fullscreen = Tam Ekran Game Settings = &Oyun Ayarları -GE Debugger... = GE Debugge&r... +GE Debugger... = GE Hata Ayıklayıcıs&ı... GitHub = Git&Hub Hardware Transform = &Donanım Dönüştürme Help = Yardım @@ -235,18 +237,18 @@ Log Console = &Günlük Konsolu Memory View... = Bellek &Görünümü... More Settings... = &Daha Fazla Ayar... Nearest = &En Yakın -Recent = &Recent -Restart Graphics = Restart Graphics +Pause when not focused = &Başka programa geçildiğinde duraklat +Recent = &En Son +Restart Graphics = Ekran Kartını Yeniden Başlat Skip Buffer Effects = &Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) Off = &Kapalı -Open Chat = Open Chat +Open Chat = Sohbeti Aç Open Directory... = Dizin Aç... Open from MS:/PSP/GAME... = Şurdan Aç MS:/PSP/GAME... Open Memory Stick = Hafıza Kartını Aç -Open New Instance = Open new instance +Open New Instance = Yeni örnek aç OpenGL = &OpenGL Pause = PPSSPP Menüsü -Pause When Not Focused = &Başka programa geçildiğinde duraklat Portrait = Dikey Portrait reversed = Ters Dikey PPSSPP Forums = PPSSPP Forumları @@ -256,46 +258,46 @@ Record Display = Görüntü Kaydet Rendering Mode = İşleme Modu Rendering Resolution = &İşleme Çözünürlüğü Reset = Sıfırla -Reset Symbol Table = Reset S&ymbol Table +Reset Symbol Table = S&imge Tablosunu Sıfırla Run = Çalıştır Save .sym File... = .sym Dosyası Kaydet... Save Map File... = &Harita Dosyası Kaydet... Save State = Durum Kaydet Save State File... = &Durum Kaydı Dosyası... Savestate Slot = Durum Kaydı Yeri -Screen Scaling Filter = Scr&een Scaling Filter +Screen Scaling Filter = Ekr&an Ölçekleme Filtresi Show Debug Statistics = Hata Ayıklama İstatistiklerini Göster Show FPS Counter = FPS Sayacını Göster Skip Number of Frames = Şu kadar kare sayısını atla Skip Percent of FPS = Şu kadar FPS yüzdesini atla -Smart 2D texture filtering = Smart 2D texture filtering +Smart 2D texture filtering = Akıllı 2D doku filtreleme Stop = &Dur Switch UMD = UMD Değiştir Take Screenshot = &Ekran Görüntüsü Al Texture Filtering = Doku Filtreleme Texture Scaling = &Doku Ölçekleme -Use Lossless Video Codec (FFV1) = &Kayıpsız video kodek'i kullan (FFV1) +Use Lossless Video Codec (FFV1) = &Kayıpsız video kodeği kullan (FFV1) Use output buffer for video = Video için çıkış arabelleğini kullan VSync = Dikey Eşleme (VSync) Vulkan = Vulkan Window Size = &Pencere Boyutu -www.ppsspp.org = www.&ppsspp.org Ziyaret Et +www.ppsspp.org = www.&ppsspp.org'u Ziyaret Et xBRZ = &xBRZ [Developer] -Allocator Viewer = Allocator viewer (Vulkan) +Allocator Viewer = Ayırıcı görüntüleyici (Vulkan) Allow remote debugger = Uzaktan hata ayıklamaya izin ver Backspace = Silme Tuşu Block address = Adresi engelle By Address = Adrese Göre Copy savestates to memstick root = Durum kayıtlarını hafıza kartına kopyalayın -Create frame dump = Create frame dump +Create frame dump = Kare dökümü oluştur Create/Open textures.ini file for current game = Şu anki oyun için textures.ini dosyası Oluştur/Aç -Current = Current -Debug overlay = Debug overlay -Debug stats = Debug stats +Current = Şimdi +Debug overlay = Hata ayıklama yer paylaşımı +Debug stats = Hata ayıklama istatistikleri Dev Tools = Geliştirme araçları -DevMenu = DevMenu +DevMenu = Geliştirici Menüsü Disabled JIT functionality = JIT işlevselliğini devre dışı bırakın Draw Frametimes Graph = Kare süreleri grafiğini çizin Dump Decrypted Eboot = Şifresi çözülmüş EBOOT.BIN'i oyun açılışında temizleyin @@ -303,26 +305,28 @@ Dump next frame to log = Sonraki kareyi günlüğe dökümle Enable driver bug workarounds = Sürücü hatası geçici çözümlerini etkinleştirin Enable Logging = Hata ayıklama günlüğünü etkinleştirin Enter address = Adres Gir -Fast-forward mode = Fast-forward mode +Fast-forward mode = Hızlı ileri sarma modu FPU = FPU -Fragment = Fragment -Frame timing = Frame timing +Fragment = Parça +Frame timing = Kare zamanlama Framedump tests = Framedump testleri -Frame Profiler = Frame profiler -GPU Allocator Viewer = GPU Allocator Viewer +Frame Profiler = Frame profilleyici +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs +GPU Allocator Viewer = GPU Ayırıcı Görüntüleyici GPU Driver Test = GPU sürücü testi -GPU log profiler = GPU log profiler +GPU log profiler = GPU günlük profilleyici GPU Profile = GPU profili Jit Compare = Jit karşılaştırma JIT debug tools = JIT hata ayıklama araçları -Log Dropped Frame Statistics = Düşen kare istatistiklerini günlüğe kaydet +Log Dropped Frame Statistics = Düşen kare istatistiklerini günlükle Log Level = Günlük seviyesi Log View = Günlük görünümü Logging Channels = Günlük kanalları -Multi-threaded rendering = Multi-threaded rendering +Multi-threaded rendering = Çok izlekli işleme Next = Sonraki -No block = No block -Off = Off +No block = Blok yok +Off = Kapalı Prev = Önceki Random = Rastgele Replace textures = Dokuları değiştir @@ -333,24 +337,25 @@ RestoreGameDefaultSettings = Oyun için ayarlanmış olan özel ayarları PPSSPP Resume = Devam ettir Run CPU Tests = İşlemci testlerini başlat Save new textures = Yeni dokuları kaydet -Shader Viewer = Shader Görüntüleyici +Shader Viewer = Gölgelendirici Görüntüleyici Show Developer Menu = Geliştirici Menüsünü Göster +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Ekran üzerinde mesajları göster Stats = İstatistikler System Information = Sistem bilgisi -Texture ini file created = Texture ini file created +Texture ini file created = Doku ini dosyası oluşturuldu Texture Replacement = Doku değiştirme -Audio Debug = Ses hata ayıklamasını -Control Debug = Control Debug +Audio Debug = Ses hata ayıklaması +Control Debug = Hata ayıklamayı kontrol et Toggle Freeze = Donmayı Aç/Kapa Touchscreen Test = Dokunmatik ekran testi -Ubershaders = Ubershaders +Ubershaders = Ubershader'lar Vertex = Vertex VFPU = VFPU [Dialog] %d ms = %d ms -%d seconds = %d saniyeler +%d seconds = %d saniye * PSP res = * PSP Çözünürlüğü Active = Etkin Back = Geri @@ -364,12 +369,13 @@ Center Right = Sağ orta Changing this setting requires PPSSPP to restart. = Bu ayarın değiştirilmesi, PPSSPP'nin yeniden başlatılmasını gerektirir. Channel: = Kanal: Choose PPSSPP save folder = PPSSPP kayıt dosyası seç -Confirm Overwrite = Veriyi üstüne yazmak istiyor musun? -Confirm Save = Bu veriyi kaydetmek istiyor musun? -ConfirmLoad = Veriyi yüklemek istiyor musun? +Confirm Overwrite = Verinin üstüne yazmak istiyor musunuz? +Confirm Save = Bu veriyi kaydetmek istiyor musunuz? +ConfirmLoad = Veriyi yüklemek istiyor musunuz? ConnectingAP = Erişim noktasına bağlanılıyor.\nLütfen bekleyin.... ConnectingPleaseWait = Bağlanılıyor.\nLütfen bekleyin... ConnectionName = Bağlantı adı +Copy to clipboard = Copy to clipboard Corrupted Data = Bozuk veri Delete = Sil Delete all = Hepsini sil @@ -381,34 +387,34 @@ DeleteConfirmGameConfig = Bu oyun için ayarları silmek istediğine emin misin? DeleteFailed = Veri silinemedi. Deleting = Siliniyor\nLütfen Bekleyin... Disable All = Hepsini devre dışı bırak -Disabled = Disabled +Disabled = Devre dışı Dumps = Dökümler Edit = Düzenle Enable All = Hepsini etkinleştir -Enabled = Enabled +Enabled = Etkin Enter = Gir -Failed to connect to server, check your internet connection. = Failed to connect to server, check your internet connection. -Failed to log in, check your username and password. = Failed to log in, check your username and password. +Failed to connect to server, check your internet connection. = Sunucuya bağlanılamadı, internetinizi kontrol edin. +Failed to log in, check your username and password. = Giriş yapılamadı, kullanıcı adı ve şifrenizi kontrol edin. Filter = Filtre Finish = Bitir GE Frame Dumps = GE Kare Dökümleri Grid = Izgara Inactive = Ektin değil -Installing... = Installing... +Installing... = Yükleniyor... InternalError = Dahili bir hata oluştu. -Links = Links +Links = Bağlantılar Load = Yükle Load completed = Yükleme tamamlandı. Loading = Yükleniyor\nLütfen Bekleyin... LoadingFailed = Veri yüklenemedi. -Log in = Log in -Log out = Log out -Logged in! = Logged in! -Logging in... = Logging in... -More information... = More information... +Log in = Giriş yap +Log out = Çıkış yap +Logged in! = Giriş yapıldı! +Logging in... = Giriş yapılıyor... +More information... = Daha fazla bilgi... Move = Taşı -Move Down = Move Down -Move Up = Move Up +Move Down = Aşağı Taşı +Move Up = Yukarı Taşı Network Connection = Ağ Bağlantısı NEW DATA = YENİ VERİ No = Hayır @@ -417,8 +423,8 @@ ObtainingIP = IP adresi alınıyor.\nLütfen bekleyin... OK = Tamam Old savedata detected = Eski kayıt bulundu. Options = Ayarlar -Password = Password -Remove = Remove +Password = Şifre +Remove = Kaldır Reset = Sıfırla Resize = Yeniden Boyutlandır Restart = Tekrar başlat @@ -428,9 +434,9 @@ Save completed = Kaydedildi. Saving = Kaydediliyor\nLütfen Bekleyin... SavingFailed = Veri kaydedilemiyor. Search = Ara -seconds, 0:off = saniye, 0 = off +seconds, 0:off = saniye, 0 = kapalı Select = Seç -Settings = Settings +Settings = Ayarlar Shift = Shift Skip = Geç Snap = Hizala @@ -445,7 +451,7 @@ Top Center = Orta üst Top Left = Sol üst Top Right = Sağ üst Unsupported = Desteklenmiyor -Username = Username +Username = Kullanıcı adı When you save, it will load on a PSP, but not an older PPSSPP = Kayıt aldığında almış olduğunuz kayıt PSP'de yüklenebilecek ama eski bir PPSSPP sürümünde yüklenemeyecek. When you save, it will not work on outdated PSP Firmware anymore = Kaydettiğinde artık eski PSP yazılımı üzerinde çalışmayacaktır. Yes = Evet @@ -500,9 +506,9 @@ Save encryption failed. This save won't work on real PSP = Kayıt şifrelemesi b textures.ini filenames may not be cross-platform = "textures.ini" dosya adları çapraz platform olmayabilir. This is a saved state, not a game. = Bu bir durum kaydı, bir oyun değil This is save data, not a game. = Bu bir kayıt dosyası, bir oyun değil. -Unable to create cheat file, disk may be full = Hile dosyası oluşturulamadı, belkide disk doludur. -Unable to initialize rendering engine. = Render motoru başlatılamıyor. -Unable to write savedata, disk may be full = Kayıt verisi yazılamadı, belkide disk doludur. +Unable to create cheat file, disk may be full = Hile dosyası oluşturulamadı, belki de disk doludur. +Unable to initialize rendering engine. = İşleme motoru başlatılamıyor. +Unable to write savedata, disk may be full = Kayıt verisi yazılamadı, belki de disk doludur. Warning: Video memory FULL, reducing upscaling and switching to slow caching mode = UYARI: Video belleği (VRAM) DOLU, video ölçekleme azaltılıyor ve yavaş önbellekleme moduna geçiliyor. Warning: Video memory FULL, switching to slow caching mode = UYARI: Video belleği (VRAM) DOLU, yavaş önbellekleme moduna geçiliyor. ZIP file detected (Require UnRAR) = Dosya sıkıştırılmış (ZIP).\nLütfen ilk olarak dosyayı çıkartın (UnRAR'ı deneyin). @@ -511,23 +517,23 @@ ZIP file detected (Require WINRAR) = Dosya sıkıştırlmış (ZIP).\nLütfen il [Game] Asia = Asya Calculate CRC = CRC'yi Hesapla -Click "Calculate CRC" to verify ISO = Click "Calculate CRC" to verify ISO +Click "Calculate CRC" to verify ISO = ISO'yu doğrulamak için "CRC'yi Hesapla"ya tıklayın ConfirmDelete = Sil -CRC checksum does not match, bad or modified ISO = CRC checksum does not match, bad or modified ISO +CRC checksum does not match, bad or modified ISO = CRC sağlama toplamı eşleşmiyor, ISO hatalı veya değiştirilmiş olabilir. Create Game Config = Oyun için yapılandırma dosyası oluştur Create Shortcut = Kısayol oluştur Delete Game = Oyunu Sil Delete Game Config = Oyun ayarını sil Delete Save Data = Oyun kaydını sil Europe = Avrupa -File size incorrect, bad or modified ISO = File size incorrect, bad or modified ISO +File size incorrect, bad or modified ISO = Dosya boyutu yanlış, ISO hatalı veya değiştirilmiş olabilir. Game = Oyun -Game ID unknown - not in the ReDump database = Game ID unknown - not in the ReDump database +Game ID unknown - not in the ReDump database = Oyun ID'si bilinmiyor - ReDump veritabanında yok Game Settings = Oyun ayarları Homebrew = Homebrew Hong Kong = Hong Kong InstallData = Veri yükle -ISO OK according to the ReDump project = ISO OK according to the ReDump project +ISO OK according to the ReDump project = ReDump projesine göre ISO OK Japan = Japonya Korea = Kore MB = MB @@ -537,16 +543,16 @@ Remove From Recent = Geçmişten sil SaveData = Kayıt Setting Background = Arkaplan ayarlanıyor Show In Folder = Dosyada göster -Time Played: %1h %2m %3s = Time Played: %1h %2m %3s -Uncompressed = Uncompressed +Time Played: %1h %2m %3s = Oynandığı Süre: %1h %2m %3s +Uncompressed = Sıkıştırılmamış USA = ABD Use UI background = Arayüz arkaplanı olarak kullan [Graphics] -% of the void = % of the void -% of viewport = % of viewport +% of the void = boşluğun %'si +% of viewport = viewport'un %'si %, 0:unlimited = %, 0 = sınırsız -(supersampling) = (supersampling) +(supersampling) = (süper örnekleme) (upscaling) = (ölçekleme) 1x PSP = 1× PSP 2x = 2× @@ -564,13 +570,13 @@ Use UI background = Arayüz arkaplanı olarak kullan 9x PSP = 9× PSP 10x PSP = 10× PSP 16x = 16× -AdrenoTools driver manager = AdrenoTools driver manager +AdrenoTools driver manager = AdrenoTools sürücü yöneticisi Aggressive = Agresif Alternative Speed = Alternatif Hız (% 0 = sınırsız) Alternative Speed 2 = Alternatif Hız 2 (% 0 = sınırsız) Anisotropic Filtering = Anizotropik filtreleme -Antialiasing (MSAA) = Antialiasing (MSAA) -Aspect Ratio = Aspect Ratio +Antialiasing (MSAA) = Kenar yumuşatma (MSAA) +Aspect Ratio = En Boy Oranı Auto = Otomatik Auto (1:1) = Otomatik (1:1) Auto FrameSkip = Otomatik kare atlama @@ -578,41 +584,41 @@ Auto Max Quality = Otomatik En Yüksek Kalite Auto Scaling = Otomatik ölçekleme Backend = Arkauç Balanced = Dengeli -Bicubic = Çift Kübik +Bicubic = Bikübik Both = İkisi de -Buffer graphics commands (faster, input lag) = Grafik komutlarını arabellekle (daha hızlı, input lag'e sebep olabilir) +Buffer graphics commands (faster, input lag) = Grafik komutlarını arabellekle (daha hızlıdır, input lag'e sebep olabilir) BufferedRenderingRequired = Uyarı: Bu oyun "işleme modunun" "yükleyerek işleme"ye alınmasını gerektirir. Camera = Kamera Camera Device = Kamera cihazı -Cardboard Screen Size = Ekran Boyutu (görüntü alanının %si olarak) -Cardboard Screen X Shift = X shift (boş alanın %si olarak) -Cardboard Screen Y Shift = Y shift (boş alanın %si olarak) +Cardboard Screen Size = Ekran Boyutu (görüntü alanının %'si olarak) +Cardboard Screen X Shift = X shift (boş alanın %'si olarak) +Cardboard Screen Y Shift = Y shift (boş alanın %'si olarak) Cardboard VR Settings = Google Cardboard VR Ayarları Cheats = Hileler -Copy to texture = Copy to texture -Current GPU Driver = Current GPU Driver +Copy to texture = Dokuya kopyala +Current GPU Driver = Şimdiki GPU Sürücüsü Debugging = Hata Ayıklama -Default GPU driver = Default GPU driver +Default GPU driver = Varsayılan GPU Sürücüsü DefaultCPUClockRequired = Uyarı: Bu oyun CPU saatinin varsayılana ayarlanmasını gerektirir. Deposterize = Deposterize Deposterize Tip = Yeniden ölçeklenen dokulardaki görsel şerit hatalarını düzeltir Device = Cihaz Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disable culling = Disable culling +Disable culling = Ayırma işlemini devre dışı bırak Disabled = Devre dışı -Display Layout && Effects = Görüntü Düzeni Düzenleyicisi +Display layout & effects = Görüntü Düzeni Düzenleyicisi Display Resolution (HW scaler) = Görüntü Çözünürlüğü (HW scaler) -Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 -Drivers = Drivers +Driver requires Android API version %1, current is %2 = Sürücü, Android API'nin %1 sürümünü gerektiriyor, şu anki sürüm %2 +Drivers = Sürücüler Enable Cardboard VR = Cardboard VR'ı Etkinleştirin FPS = FPS Frame Rate Control = Kare hızı denetimi Frame Skipping = Kare atla Frame Skipping Type = Kare atlama türü FullScreen = Tam ekran -Geometry shader culling = Geometry shader culling -GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off. +Geometry shader culling = Geometri gölgelendiricisi ayıklama +GPUReadbackRequired = Uyarı: Bu oyun "GPU Okumalarını Atla" seçeneğinin Kapalı olarak ayarlanmasını gerektirir. Hack Settings = Hack ayarları (Küçük teknik problemlere neden olabilir.) Hardware Tessellation = Donanım Mozaikleme Hardware Transform = Donanım dönüştürme @@ -622,11 +628,11 @@ High = Yüksek Hybrid = Hibrit Hybrid + Bicubic = Hibrit + Bikübik Ignore camera notch when centering = Merkezleme sırasında kamera çentiğini yoksay -Install custom driver... = Install custom driver... -Integer scale factor = Integer scale factor +Install custom driver... = Özel sürücü yükle... +Integer scale factor = Tamsayı ölçek faktörü Internal Resolution = İç çözünürlük Lazy texture caching = Yavaş doku önbellekleme (hızlandırır) -Lazy texture caching Tip = Faster, but can cause text problems in a few games +Lazy texture caching Tip = Daha hızlıdır ancak bazı oyunlarda metin sorunlarına neden olabilir Linear = Doğrusal Low = Düşük LowCurves = Spline/Bezier eğri kalitesi @@ -634,17 +640,18 @@ LowCurves Tip = Sadece bazı oyunlar tarafından kullanılır, eğrilerin pürü Lower resolution for effects (reduces artifacts) = Efektler için daha az çözünürlük (sorunları azaltır) Manual Scaling = El ile ölçekleme Medium = Orta +Mirror camera image = Mirror camera image Mode = Mod -Must Restart = Bu değişikliğin uygulanması için PPSSPP'yi yeniden başlatmalısın. +Must Restart = Bu değişikliğin uygulanması için PPSSPP yeniden başlatılmalıdır. Native device resolution = Yerel aygıt çözünürlüğü Nearest = En yakın -No (default) = No (default) +No (default) = Hayır (varsayılan) No buffer = Arabellek/tampon bellek yok -Render all frames = Render all frames -Same as Rendering resolution = Otomatik (İşleme Çözünürlüğüyle Aynı) -Show Battery % = Show Battery % -Show Speed = Show Speed -Skip = Skip +Render all frames = Tüm kareleri işle +Same as Rendering resolution = Same as Rendering resolution +Show Battery % = Pil Yüzdesini Göster +Show Speed = Hızı Göster +Skip = Atla Skip Buffer Effects = Arabellek efektlerini atla (arabelleğe alınmaz, daha hızlıdır) None = Hiçbiri Number of Frames = Kare sayısı @@ -655,7 +662,7 @@ Partial Stretch = Tam ekran (kısmi sünme) Percent of FPS = FPS yüzdesi Performance = Performans Postprocessing shaders = Postprocessing gölgelendiricisi -Recreate Activity = Recreate activity +Recreate Activity = Etkinliği yeniden oluştur Render duplicate frames to 60hz = Yinelenen kareleri 60Hz'de işleyin RenderDuplicateFrames Tip = Daha düşük kare hızlarında çalışan oyunlarda kare hızını düzeltebilir Rendering Mode = İşleme modu @@ -666,29 +673,29 @@ Safe = Güvenli Screen Scaling Filter = Ekran ölçekleme filtresi Show Debug Statistics = Hata ayıklama istatistiklerini göster Show FPS Counter = FPS sayacını göster -Skip GPU Readbacks = Skip GPU Readbacks -Smart 2D texture filtering = Smart 2D texture filtering +Skip GPU Readbacks = GPU Okumalarını Atla +Smart 2D texture filtering = Akıllı 2D doku filtreleme Software Rendering = Yazılımsal işleme (Deneysel) -Software Skinning = Software skinning -SoftwareSkinning Tip = Combine skinned model draws on the CPU, faster in most games +Software Skinning = Yazılımsal Kaplama +SoftwareSkinning Tip = Kaplamalı model çizimlerini CPU'da birleştirin, çoğu oyunu hızlandırır Speed = Hız -Speed Hacks = Hız Hacks (Küçük teknik problemlere neden olabilir.) -Stereo display shader = Stereo display shader -Stereo rendering = Stereo rendering +Speed Hacks = Speed Hack'leri (Küçük teknik problemlere neden olabilir.) +Stereo display shader = Stereo ekran gölgelendiricisi +Stereo rendering = Stereo işleme Stretch = Serbest tam ekran (sünme) Texture Filter = Doku filtreleme Texture Filtering = Doku filtreleme -Texture replacement pack activated = Texture replacement pack activated +Texture replacement pack activated = Doku değiştirme paketi etkinleştirildi Texture Scaling = Doku ölçekleme Texture Shader = Doku gölgelendiricisi -The chosen ZIP file doesn't contain a valid driver = The chosen ZIP file doesn't contain a valid driver -Turn off Hardware Tessellation - unsupported = "Donanım mozaikleme"yi kapatın: desteklenmiyor +The chosen ZIP file doesn't contain a valid driver = Seçilen ZIP dosyası geçerli bir sürücü içermiyor +Turn off Hardware Tessellation - unsupported = "Donanım mozaikleme"yi kapatın: çünkü desteklenmiyor. Unlimited = Sınırsız Up to 1 = 1'e kadar Up to 2 = 2'ye kadar Upscale Level = Ölçeklendirme seviyesi Upscale Type = Ölçeklendirme türü -UpscaleLevel Tip = CPU ağır - takılmayı önlemek için bazı yeniden ölçeklendirmeler gecikebilir +UpscaleLevel Tip = CPU'ya ağır yüklenir - takılmayı önlemek için bazı yeniden ölçeklendirmeler gecikebilir Use all displays = Tüm ekranları kullan VSync = Dikey eşleme (Vsync) Vulkan = Vulkan @@ -696,34 +703,37 @@ Window Size = Pencere boyutu xBRZ = xBRZ [InstallZip] -Delete ZIP file = Zip dosyasını sil +Data to import = Data to import +Delete ZIP file = ZIP dosyasını sil +Existing data = Existing data Install = Yükle -Install game from ZIP file? = Zip dosyasından oyun yüklensin mi? -Install textures from ZIP file? = Zip dosyasından dokular yüklensin mi? -Installation failed = Installation failed +Install game from ZIP file? = ZIP dosyasından oyun yüklensin mi? +Install in folder = Install in folder +Install textures from ZIP file? = ZIP dosyasından dokular yüklensin mi? +Installation failed = Yükleme başarısız Installed! = Yüklendi! Texture pack doesn't support install = Doku paketi yüklemeyi desteklemiyor Zip archive corrupt = ZIP arşivi bozuk Zip file does not contain PSP software = ZIP dosyası PSP yazılımı içermiyor [KeyMapping] -Allow combo mappings = Allow combo mappings +Allow combo mappings = Birleşik eşlemelere izin ver Autoconfigure = Otomatik ayarla Autoconfigure for device = Cihaz için otomatik ayarla Bind All = Hepsini Bağla Clear All = Hepsini Temizle -Combo mappings are not enabled = Combo mappings are not enabled -Control modifiers = Control modifiers +Combo mappings are not enabled = Birleşik eşlemeler etkin değil +Control modifiers = Kontrol değiştiricileri Default All = Varsayılana Döndür -Emulator controls = Emulator controls -Extended PSP controls = Extended PSP controls +Emulator controls = Emülator kontrolleri +Extended PSP controls = Genişletilmiş PSP kontrolleri Map a new key for = Yeni bir tuş girin Map Key = Tuş girin -Map Mouse = Mouse eşleştir +Map Mouse = Fare eşleştir Replace = Değiştir Show PSP = PSP'yi Göster -Standard PSP controls = Standard PSP controls -Strict combo input order = Strict combo input order +Standard PSP controls = Standart PSP kontrolleri +Strict combo input order = Katı birleşik giriş sırası You can press ESC to cancel. = İptal etmek için Esc'ye basabilirsiniz. [MainMenu] @@ -755,8 +765,8 @@ www.ppsspp.org = www.ppsspp.org Audio = Ses Controls = Kontroller Graphics = Grafik -Networking = Ağ ayarları -Search = Ara +Networking = Ağ +Search = Arama System = Sistem Tools = Araçlar @@ -780,31 +790,31 @@ D-pad left = D-pad sol D-pad right = D-pad sağ D-pad up = D-pad yukarı DevMenu = Geliştirici Menüsü -Display Landscape = Display Landscape -Display Landscape Reversed = Display Landscape Reversed -Display Portrait = Display Portrait -Display Portrait Reversed = Display Portrait Reversed +Display Landscape = Yatay Ekran +Display Landscape Reversed = Ters Yatay Ekran +Display Portrait = Dikey Ekran +Display Portrait Reversed = Ters Dikey Ekran Double tap button = Düğmeye çift basın Down = Dpad Aşağı Dpad = Dpad -Exit App = Exit App -Frame Advance = Frame advance +Exit App = Uygulamadan Çık +Frame Advance = Kare ilerlemesi Hold = Basılı tut Home = Ev L = L Left = Dpad Sol Load State = Durum Yükle Mute toggle = Sessize al -Next Slot = Sonraki Yer +Next Slot = Sonraki Slot None = Hiçbiri Note = Not -OpenChat = Chat'i Aç +OpenChat = Sohbeti Aç Pause = PPSSPP Menüsü -Previous Slot = Previous Slot +Previous Slot = Önceki Slot R = R RapidFire = Seri Ateş -Record = Record -Remote hold = Remote hold +Record = Kayıt +Remote hold = Uzaktan tutma Rewind = Geri Sar Right = Dpad Sağ Right Analog Stick = Sağ Analog çubuk @@ -817,7 +827,7 @@ Rotate Analog (CW) = Analoğu döndür (CW) Save State = Durum Kaydet Screen = Ekran Screenshot = Ekran görüntüsü -Select = Select +Select = Seç SpeedToggle = Hızı ayarla Square = Kare Start = Başlat @@ -829,28 +839,28 @@ tap to customize = özelleştirmek için dokun Texture Dumping = Doku Dökümü Texture Replacement = Doku değiştirme Toggle Fullscreen = Tam ekran -Toggle mode = Toggle mode -Toggle mouse input = Toggle mouse input -Toggle touch controls = Toggle touch controls -Toggle WLAN = Toggle WLAN +Toggle mode = Geçiş modu +Toggle mouse input = Fare girişine geç +Toggle touch controls = Dokunmatik kontrollerine geç +Toggle WLAN = WLAN aç/kapat Triangle = Üçgen -Fast-forward = Fast-forward +Fast-forward = Hızlı ileri sar Up = Dpad Yukarı -Vol + = Vol + -Vol - = Vol - +Vol + = Ses + +Vol - = Ses - Wlan = WLAN [MemStick] Already contains PSP data = Zaten PSP verisi içeriyor -Cancelled - try again = Cancelled - try again -Checking... = Checking... +Cancelled - try again = İptal edildi - tekrar deneyin +Checking... = Kontrol ediliyor... Create or Choose a PSP folder = Bir PSP klasörü oluştur veya seç -Current = Current +Current = Şimdiki DataCanBeShared = Veri PPSSPP normal/Gold arasında paylaşılabilir DataCannotBeShared = Veri PPSSPP normal/Gold arasında PAYLAŞILAMAZ! DataWillBeLostOnUninstall = Uyarı! PPSSPP'yi kaldırdığınızda veriler kaybolacak! -DataWillStay = Data will stay even if you uninstall PPSSPP. -Deleting... = Deleting... +DataWillStay = PPSSPP'yi kaldırsanız bile veriler kalacaktır. +Deleting... = Siliniyor... Done! = Tamamlandı! EasyUSBAccess = Kolay USB erişimi Failed to move some files! = Bazı dosyalar taşınamadı! @@ -879,13 +889,13 @@ AM: Data from Unknown Port = AM: Bilinmeyen Porttan Veri Auto = Otomatik Change Mac Address = MAC adresini değiştir Change proAdhocServer Address = PRO Ad Hoc Server IP adresini değiştir (localhost = çoklu örnek) -ChangeMacSaveConfirm = Generate a new MAC address? -ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves. -Chat = Chat -Chat Button Position = Chat düğmesinin konumu +ChangeMacSaveConfirm = Yeni MAC adresi yaratılsın mı? +ChangeMacSaveWarning = Bazı oyunlar, kayıtlı verileri yüklerken MAC adresini doğrular; dolayısıyla bu, eski kayıtların bozulmasına neden olabilir. +Chat = Sohbet +Chat Button Position = Sohbet düğmesinin konumu Chat Here = Buraya yazın -Chat message = Chat mesajı -Chat Screen Position = Chat ekranının konumu +Chat message = Sohbet mesajı +Chat Screen Position = Sohbet ekranının konumu Disconnected from AdhocServer = Ad hoc sunucu bağlantısı kesildi DNS Error Resolving = DNS hatası teşhis ediliyor Enable built-in PRO Adhoc Server = Yerleşik PRO Ad Hoc Sunucusunu etkinleştir @@ -895,22 +905,22 @@ Enable UPnP = UPnP'yi etkinleştirin (algılamak için birkaç saniye gerekir) EnableQuickChat = Hızlı sohbeti etkinleştirin Enter a new PSP nickname = Yeni bir PSP kullanıcı adı girin Enter Quick Chat 1 = Hızlı sohbet 1'e girin -Enter Quick Chat 2 = Hızlı sohbet 2'ye girin +Enter Quick Chat 2 = Hızlı sohbet 2'e girin Enter Quick Chat 3 = Hızlı sohbet 3'e girin Enter Quick Chat 4 = Hızlı sohbet 4'e girin Enter Quick Chat 5 = Hızlı sohbet 5'e girin Error = Hata -Failed to Bind Localhost IP = Failed to bind localhost IP -Failed to Bind Port = Failed to bind port +Failed to Bind Localhost IP = Yerel ana makine IP'si bağlanamadı +Failed to Bind Port = Port bağlanamadı Failed to connect to Adhoc Server = Ad hoc sunucusuna bağlanılamadı Forced First Connect = Zorunlu ilk bağlantı (daha hızlı bağlantı) GM: Data from Unknown Port = GM: Bilinmeyen Porttan Veri -Hostname = Hostname -Invalid IP or hostname = Geçersiz IP veya host adı +Hostname = Ana makine adı +Invalid IP or hostname = Geçersiz IP veya ana makine adı Minimum Timeout = En düşük zaman aşımı (ms cinsinden geçersiz kılma, 0 = varsayılan) Misc = Çeşitli (varsayılan = PSP uyumluluğu) -Network connected = Network connected -Network initialized = Network Switch +Network connected = Ağ bağlandı +Network initialized = Ağ anahtarı Please change your Port Offset = Lütfen Port Offset'i değiştirin Port offset = Port offset(0 = PSP uyumluluğu) Open PPSSPP Multiplayer Wiki Page = PPSSPP Ad-Hoc Wiki Sayfası @@ -921,34 +931,34 @@ Quick Chat 3 = Hızlı sohbet 3 Quick Chat 4 = Hızlı sohbet 4 Quick Chat 5 = Hızlı sohbet 5 QuickChat = Hızlı sohbet -Randomize = Randomize +Randomize = Rastgeleleştir Send = Gönder -Send Discord Presence information = Discord "Rich Presence" bilgisi gönder +Send Discord Presence information = Discord'a Rich Presence bilgisi gönder Unable to find UPnP device = UPnP cihazı bulunamıyor UPnP (port-forwarding) = UPnP (port yönlendirme) UPnP need to be reinitialized = UPnP'nin yeniden başlatılması gerekiyor UPnP use original port = UPnP orijinal portu kullan (etkin = PSP uyumluluğu) -UseOriginalPort Tip = May not work for all devices or games, see wiki. +UseOriginalPort Tip = Tüm cihazlar veya oyunlarda çalışmayabilir, wiki'ye bakın. Validating address... = Adres doğrulanıyor... WLAN Channel = WLAN Kanalı You're in Offline Mode, go to lobby or online hall = Çevrimdışı moddasınız, lobiye veya çevrimiçi salona gidin [PSPSettings] -Auto = Auto -Chinese (simplified) = Chinese (simplified) -Chinese (traditional) = Chinese (traditional) -Dutch = Dutch -English = English -French = French -Game language = Game language -German = German -Italian = Italian -Japanese = Japanese -Korean = Korean -Games often don't support all languages = Games often don't support all languages -Portuguese = Portuguese -Russian = Russian -Spanish = Spanish +Auto = Otomatik +Chinese (simplified) = Çince (basitleştirilmiş) +Chinese (traditional) = Çince (geleneksel) +Dutch = Felemenkçe +English = İngilizce +French = Fransızca +Game language = Oyun dili +German = Almanca +Italian = İtalyanca +Japanese = Japonca +Korean = Korece +Games often don't support all languages = Oyunlar genellikle tüm dilleri desteklemez +Portuguese = Portekizce +Russian = Rusça +Spanish = İspanyolca [Pause] Cheats = Hileler @@ -963,7 +973,7 @@ Save State = Kaydet Settings = Ayarlar Switch UMD = UMD değiştir Undo last load = Son yüklemeyi geri al -Undo last save = Son kaydetmeyi geri al +Undo last save = Son kaydı geri al [PostShaders] (duplicated setting, previous slider will be used) = (yinelenen ayar, önceki kaydırıcı kullanılacaktır) 4xHqGLSL = 4xHQ pixel art upscaler @@ -971,37 +981,37 @@ Undo last save = Son kaydetmeyi geri al 5xBR-lv2 = 5xBR-lv2 pixel art upscaler AAColor = AA-Color Amount = Miktar -Animation speed (0 -> disable) = Animation speed (0 -> disable) +Animation speed (0 -> disable) = Animasyon hızı (0 -> devre dışı) Aspect = Aspect Black border = Siyah çerçeve Bloom = Bloom -BloomNoBlur = Bloom (no blur) +BloomNoBlur = Bloom (bulanıklık yok) Brightness = Parlaklık Cartoon = Çizgi film -CatmullRom = Bicubic (Catmull-Rom) Upscaler -ColorCorrection = Color correction -ColorPreservation = Color preservation +CatmullRom = Bikübik (Catmull-Rom) Upscaler +ColorCorrection = Renk düzeltme +ColorPreservation = Renk koruma Contrast = Karşıtlık CRT = CRT tarama çizgileri FakeReflections = FakeReflections FXAA = FXAA Kenar Yumuşatma Gamma = Gamma -GreenLevel = Green level +GreenLevel = Yeşil seviyesi Intensity = Yoğunluk -LCDPersistence = LCD Persistence +LCDPersistence = LCD Kalıcılığı MitchellNetravali = Bicubic (Mitchell-Netravali) Upscaler Natural = Doğal Renkler NaturalA = Doğal Renkler (bulanıklık yok) Off = Kapalı Power = Güç PSPColor = PSP rengi -RedBlue = Red/Blue glasses +RedBlue = Kırmızı/Mavi gözlük Saturation = Doygunluk Scanlines = Tarama Çizgileri (CRT) Sharpen = Keskinleştir -SideBySide = Side by side (SBS) +SideBySide = Yan yana (SBS) SSAA(Gauss) = Süper örneklemeli Kenar Yumuşatma (Gauss) -Strength = Strength +Strength = Kuvvet Tex4xBRZ = 4xBRZ TexMMPX = MMPX UpscaleBicubic = UpscaleBicubic @@ -1010,9 +1020,9 @@ VideoSmoothingAA = VideoSmoothingAA Vignette = Vinyet [PSPCredits] -all the forum mods = Bütün forum modlarına +all the forum mods = Bütün forum moderatörlerine build server = build server -Buy Gold = Altın Sürümü alın +Buy Gold = Gold Sürümü alın check = Ayrıca etraftaki en iyi Wii/GC emülatörü olan Dolphin'e göz atın: CheckOutPPSSPP = PPSSPP'ye göz atın: https://www.ppsspp.org/ contributors = Yardımcılar: @@ -1039,20 +1049,24 @@ tools = Kullanılan Ücretsiz Araçlar: # Add translators or contributors who translated PPSSPP into your language here. # Add translators1-6 for up to 6 lines of translator credits. # Leave extra lines blank. 4 contributors per line seems to look best. -translators1 = Gravityy -translators2 = mygizli04 -translators3 = Kyria Crown +translators1 = misty rosetta +translators2 = Gravityy +translators3 = mygizli04 translators4 = translators5 = translators6 = -Twitter @PPSSPP_emu = Twitter +Twitter @PPSSPP_emu = X @PPSSPP_emu website = PPSSPP.org written = Hız ve Taşınabilirlik için C++ ile Yazıldı [RemoteISO] Browse Games = Oyunlara bak... +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Yerel sunucu portu Manual Mode Client = Manuel mod istemcisi +Not currently sharing = Not currently sharing Remote disc streaming = Uzaktan disk akışı Remote Port = Uzaktan port Remote Server = Uzaktan sunucu @@ -1066,7 +1080,7 @@ RemoteISOWinFirewall = UYARI: Windows Güvenlik Duvarı paylaşımı engelliyor Settings = Ayarlar Share Games (Server) = Oyunları paylaş (sunucu) Share on PPSSPP startup = PPSSPP açılışında paylaşın -Show Remote tab on main screen = Show Remote tab on main screen +Show Remote tab on main screen = Uzak sekmesini ana ekranda göster Stop Sharing = Paylaşmayı durdur Stopping.. = Durduruluyor... @@ -1159,17 +1173,19 @@ Filter = Filtre Filtering settings by '%1' = Ayarlar '%1''e göre filtreleniyor Find settings = Ayarları ara No settings matched '%1' = '%1' ile eşleşen ayar yok -Search term = Search term +Search term = Arama terimi [Store] Connection Error = Bağlantı hatası Install = Yükle Installed = Zaten yüklü Launch Game = Oyunu başlat +License = License Loading... = Yükleniyor... MB = MB Size = Boyut Uninstall = Sil +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1185,8 +1201,8 @@ Board = Board Build Config = Yapı konfigürasyonu Build Configuration = Yapı konfigürasyonu Built by = Tarafından yapıldı -Compressed texture formats = Compressed texture formats -Core Context = Core context +Compressed texture formats = Sıkıştırılmış doku biçimleri +Core Context = Temel bağlam Cores = Çekirdekler CPU Extensions = CPU uzantıları CPU Information = CPU bilgisi @@ -1194,7 +1210,7 @@ CPU Name = Ad D3DCompiler Version = D3DCompiler sürümü Debug = Hata Ayıklama Debugger Present = Hata ayıklayıcı var -Depth buffer format = Depth buffer format +Depth buffer format = Derinlik tampon formatı Device Info = Cihaz bilgisi Directories = Dizinler Display Color Formats = Renk Biçimlerini Görüntüle @@ -1206,11 +1222,11 @@ EGL Extensions = EGL eklentileri Frames per buffer = Tampon başına çerçeveler GPU Flags = GPU Flags GPU Information = GPU bilgisi -High precision float range = High precision float range -High precision int range = High precision int range -Icon cache = Icon cache -Instance = Instance -JIT available = JIT available +High precision float range = Yüksek duyarlılıklı float aralığı +High precision int range = Yüksek duyarlılıklı int aralığı +Icon cache = Simge önbelleği +Instance = Örnek +JIT available = JIT mümkün Lang/Region = Dil/Bölge Memory Page Size = Bellek sayfa boyutu Native resolution = Yerel çözünürlük @@ -1222,14 +1238,14 @@ OpenGL Extensions = OpenGL eklentileri Optimal frames per buffer = Optimum tampon başına çerçeveler Optimal sample rate = Optimum örnekleme hızı OS Information = İşletim sistemi bilgisi -Pixel resolution = Pixel resolution +Pixel resolution = Piksel çözünürlüğü PPSSPP build = PPSSPP derlemesi -Present modes = Present modes +Present modes = Mevcut modlar Refresh rate = Yenileme hızı Release = Release RW/RX exclusive = RW/RX'e özel Sample rate = Örnekleme hızı -Screen notch insets = Screen notch insets +Screen notch insets = Ekran çentiği ekleri Shading Language = Gölgelendirme dili Storage = Depolama Sustained perf mode = Sürekli performans modu @@ -1237,9 +1253,9 @@ System Information = Sistem bilgisi System Name = Ad System Version = Sistem sürümü Threads = İzlekler -UI resolution = UI resolution +UI resolution = Arayüz çözünürlüğü Vendor = Üretici -Vendor (detected) = Üretici (tespit edildi) +Vendor (detected) = Üretici (tespit edilen) Version Information = Sürüm bilgisi Vulkan Extensions = Vulkan eklentileri Vulkan Features = Vulkan özellikleri @@ -1248,6 +1264,7 @@ Vulkan Features = Vulkan özellikleri (broken) = (bozuk) 12HR = 12 saat 24HR = 24 saat +App switching mode = App switching mode Auto = Otomatik Auto Load Savestate = Otomatik durum kaydı yükle AVI Dump started. = AVI kaydı başladı. @@ -1258,13 +1275,14 @@ Color Saturation = Renk Doygunluğu Color Tint = Renk Tonu CPU Core = İşlemci Çekirdeği Dynarec/JIT (recommended) = Dynarec/JIT (tavsiye edilen) +Enable plugins = Enable plugins Error: load undo state is from a different game = Hata: yükleme geri alma durumu farklı bir oyundan Failed to load state for load undo. Error in the file system. = Yüklemeyi geri alma durumu yüklenemedi. Dosya sisteminde hata. Floating symbols = Kayan simgeler -Game crashed = Game crashed -JIT using IR = JIT using IR +Game crashed = Oyun çöktü +JIT using IR = IR kullanarak JIT Language = Dil -Loaded plugin: %1 = Loaded plugin: %1 +Loaded plugin: %1 = Yüklenen uzantı: %1 Memory Stick folder = Hafıza Kartı klasörü Memory Stick size = Hafıza Kartı boyutu Change Nickname = Kullanıcı adını değiştir @@ -1296,7 +1314,7 @@ Games list settings = Oyun listesi ayarları General = Genel Grid icon size = Izgara simge boyutu Help the PPSSPP team = PPSSPP takımına yardım et -Host (bugs, less lag) = Host (buglu, daha az kasma) +Host (bugs, less lag) = Ana makine (buglu, daha az kasma) Ignore bad memory accesses = Kötü bellek erişimlerini yoksay Increase size = Boyutu arttır Interpreter = Tercüman @@ -1312,8 +1330,10 @@ No animation = animasyon yok Not a PSP game = Bir PSP oyunu değil Off = Kapalı Oldest Save = En eski kayıt -Only JPG and PNG images are supported = Only JPG and PNG images are supported +Only JPG and PNG images are supported = Sadece JPG ve PNG resimleri desteklenir Path does not exist! = Yol mevcut değil! +Pause when not focused = &Başka programa geçildiğinde duraklat +Plugins = Plugins PSP Memory Stick = PSP Hafıza Kartı PSP Model = PSP modeli PSP Settings = PSP ayarları @@ -1322,7 +1342,7 @@ PSP-2000/3000 = PSP-2000/3000 Recent games = En son oyunlar Record Audio = Sesi kaydet Record Display = Görüntüyü kaydet -Recording = Recording +Recording = Kaydediliyor Reset Recording on Save/Load State = Kaydet/Yükle durumunda kaydı sıfırla Restore Default Settings = Varsayılan ayarları yükle RetroAchievements = RetroAchievements @@ -1332,13 +1352,13 @@ Save path in My Documents = Dosyaları "Belgeler"'e kaydet Savestate Slot = Durum kaydı yeri Savestate slot backups = Durum kaydı slot yedekleri Screenshots as PNG = Ekran görüntülerini PNG olarak kaydet -Set Memory Stick folder = Set Memory Stick folder +Set Memory Stick folder = Hafıza Kartı klasörünü seç Set UI background... = Arayüz arkaplanı ayarla... Show ID = ID'yi göster Show Memory Stick folder = Hafıza Kartı klasörünü göster Show region flag = Bölge bayrağını göster Simulate UMD delays = UMD gecikmelerini simule et -Simulate UMD slow reading speed = Simulate UMD slow reading speed +Simulate UMD slow reading speed = UMD yavaş okuma hızını simule et Slot 1 = Slot 1 Slot 2 = Slot 2 Slot 3 = Slot 3 @@ -1346,12 +1366,14 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Depolama dolu Sustained performance mode = Sürekli performans modu +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Tema Time Format = Zaman biçimi -Transparent UI background = Transparent UI background -UI = Kullanıcı arayüzü -UI background animation = UI arka plan animasyonu -UI Sound = UI sesi +Transparent UI background = Şeffaf arayüz arkaplanı +UI = Arayüz +UI background animation = Arayüz arkaplan animasyonu +UI Sound = Arayüz sesleri undo %c = %c 'yi yedekle USB = USB Use Lossless Video Codec (FFV1) = Kayıpsız video codec'i kullan (FFV1) @@ -1366,13 +1388,13 @@ Waves = Dalgalar YYYYMMDD = YYYYAAGG [TextureShaders] -Off = Off +Off = Kapalı TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ [Themes] -Dark = Dark +Dark = Koyu Default = Varsayılan [UI Elements] @@ -1384,30 +1406,27 @@ Default = Varsayılan %1 text field = %1 metin alanı Choices: = Seçenekler: List: = Liste: -Progress: %1% = Progress: %1% +Progress: %1% = İlerleme: %1% Screen representation = Ekran gösterimi [Upgrade] Details = Detaylar Dismiss = Reddet Download = İndir -New version of PPSSPP available = PPSSPP'nin yeni versiyonu mevcut +New version of PPSSPP available = PPSSPP'nin yeni sürümü mevcut [VR] -6DoF movement = 6DoF movement -Camera type = Camera type -Distance to 2D menus and scenes = Distance to 2D menus and scenes -Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only -Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing -Heads-up display detection = Heads-up display detection -Heads-up display scale = Heads-up display scale -Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action -Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) -Virtual reality = Virtual reality -VR camera = VR camera -VR controllers = VR controllers +% of native FoV = % of native FoV +6DoF movement = 6DoF hareketi +Distance to 2D menus and scenes = 2D menülere ve sahnelere olan mesafe +Distance to 3D scenes when VR disabled = VR devre dışı bırakıldığında 3D sahnelere olan mesafe +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale +Force 72Hz update = 72Hz güncellemeyi zorla +Heads-up display detection = HUD algılama +Heads-up display scale = HUD ölçeği +Manual switching between flat screen and VR using SCREEN key = SCREEN tuşunu kullanarak düz ekran ve VR arasında manuel geçiş +Stereoscopic vision (Experimental) = Stereoskopik görüş (Deneysel) +Virtual reality = Sanal gerçeklik +VR camera = VR kamera +VR controllers = VR kontrolcüleri diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 2092010c12..7ba65e614f 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Гучність при альтернативній швидкості Audio backend = Бекенд аудіо (потрібне перезавантаження) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Буфер, який підходить для Bluetooth (повільніше) Auto = Авто Device = Пристрій @@ -71,7 +71,9 @@ Enable Sound = Ввімкнути звук Global volume = Глобальна гучність Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Вимкнути звук +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Увімкніть новий аудіопристрій Use global volume = Використовувати загальну гучність @@ -233,6 +235,7 @@ Log Console = Консоль журналу (log) Memory View... = Переглядач па&м'яті... More Settings... = &Ще налаштування... Nearest = &Найближчий +Pause when not focused = &Пауза коли вікно не в фокусі Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = &Пропустити ефекти (небуферований, швидше) @@ -244,7 +247,6 @@ Open Memory Stick = Відкрити карту пам'яті Open New Instance = Open new instance OpenGL = &OpenGL Pause = &Пауза -Pause When Not Focused = &Пауза коли вікно не в фокусі Portrait = Портретне Portrait reversed = Портретна (перевернуто) PPSSPP Forums = &Форум PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Профілі кадрів +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = Перевірка драйверу GPU GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Запустити тести CPU Save new textures = Зберегти нові текстури Shader Viewer = Переглядач шейдеру Show Developer Menu = Показати меню розробника +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Статистика System Information = Інформація про систему @@ -368,6 +373,7 @@ ConfirmLoad = Завантажити ці дані? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Видалити Delete all = Видалити все @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Вимкнено -Display Layout && Effects = Редактор розташування екрану +Display layout & effects = Редактор розташування екрану Display Resolution (HW scaler) = Розширення екрану (HW масштабування) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Використовується лише в деяких ігр Lower resolution for effects (reduces artifacts) = Ефекти низької якості (зменшує артефакти) Manual Scaling = Свій масштаб Medium = Середня +Mirror camera image = Mirror camera image Mode = Режим Must Restart = Ви повинні перезавантажити PPSSPP, щоб зміни вступили в силу. Native device resolution = Роздільна здатність пристрою @@ -694,9 +701,12 @@ Window Size = Розмір вікна xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Видалити ZIP файл +Existing data = Existing data Install = Встановити Install game from ZIP file? = Встановити гру з ZIP-файлу? +Install in folder = Install in folder Install textures from ZIP file? = Встановити текстури з ZIP-файлу? Installation failed = Installation failed Installed! = Встановлено! @@ -1050,8 +1060,12 @@ written = Написаний на C++ для швидкості \nта підт [RemoteISO] Browse Games = Перегляд ігор +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Локальний порт сервера Manual Mode Client = Клієнт в ручному режимі +Not currently sharing = Not currently sharing Remote disc streaming = Віддалена трансляція диску Remote Port = Віддалений порт Remote Server = Віддалений сервер @@ -1165,10 +1179,12 @@ Connection Error = Помилка підключення Install = Встановити Installed = Вже встановлено Launch Game = Запустити гри +License = License Loading... = Завантаження... MB = Мб Size = Розмір Uninstall = Видалити +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Особливості Vulkan (broken) = (зламано) 12HR = 12 годин 24HR = 24 години +App switching mode = App switching mode Auto = Авто Auto Load Savestate = Автоматичне завантаження збережень AVI Dump started. = Дамп AVI запущено @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = Ядро CPU Dynarec/JIT (recommended) = Динамічна рекомпіляція/JIT (рекомендований) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Зменшити розмір Developer Tools = Інструменти розробника Display Extra Info = Відобразити додаткову інформацію Display Games on a grid = Відображати "Ігри" на сітці -Display Homebrew on a grid = Відображати "Homebrew && Demos" на сітці +Display Homebrew on a grid = Відображати "Homebrew & Demos" на сітці Display Recent on a grid = Відображати "Останні" в сітці Emulation = Емуляція Enable Cheats = Ввімкнути чит-коди @@ -1313,6 +1331,8 @@ Off = Вимкнено Oldest Save = Найстаріші збереження Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = &Пауза коли вікно не в фокусі +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = Модель PSP PSP Settings = Налаштування PSP @@ -1345,6 +1365,8 @@ Slot 4 = Слот 4 Slot 5 = Слот 5 Storage full = Пам'ять заповнено Sustained performance mode = Режим тривалої роботи +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Формат часу Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Завантажити New version of PPSSPP available = Доступна нова версія PPSSPP [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index 38cb1009a2..4f5473cb61 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -61,7 +61,7 @@ Unsupported achievements = Unsupported achievements Alternate speed volume = Alternate speed volume Audio backend = Âm thanh backend (hãy khởi động lại.) Audio Error = Audio Error -Audio file format not supported. Must be WAV. = Audio file format not supported. Must be WAV. +Audio file format not supported. Must be WAV or MP3. = Audio file format not supported. Must be WAV or MP3. AudioBufferingForBluetooth = Bluetooth-friendly buffer (chậm) Auto = Tự động Device = Device @@ -71,7 +71,9 @@ Enable Sound = Mở âm thanh Global volume = Âm lượng Microphone = Microphone Microphone Device = Microphone device +Mix audio with other apps = Mix audio with other apps Mute = Mute +Respect silent mode = Respect silent mode Reverb volume = Reverb volume Use new audio devices automatically = Use new audio devices automatically Use global volume = Use global volume @@ -233,6 +235,7 @@ Log Console = Log Console Memory View... = Xem bộ nhớ... More Settings... = Các thiết lập khác... Nearest = Gần nhất +Pause when not focused = Dừng trò chơi khi "ko tập trung" Recent = &Recent Restart Graphics = Restart Graphics Skip Buffer Effects = Bỏ qua hiệu ứng đệm (Không bộ nhớ đệm, nhanh hơn) @@ -244,7 +247,6 @@ Open Memory Stick = Mở Memory Stick Open New Instance = Open new instance OpenGL = OpenGL Pause = Tạm dừng -Pause When Not Focused = Dừng trò chơi khi "ko tập trung" Portrait = Chiều dọc Portrait reversed = Chiều dọc đảo ngược PPSSPP Forums = Diễn đàn PPSSPP @@ -307,6 +309,8 @@ Fragment = Fragment Frame timing = Frame timing Framedump tests = Framedump tests Frame Profiler = Khung hồ sơ +GPI switch %1 = GPI switch %1 +GPI/GPO switches/LEDs = GPI/GPO switches/LEDs GPU Allocator Viewer = GPU Allocator Viewer GPU Driver Test = GPU driver test GPU log profiler = GPU log profiler @@ -333,6 +337,7 @@ Run CPU Tests = Chạy thử CPU Save new textures = Lưu file textures mới Shader Viewer = Xem trước đỗ bóng Show Developer Menu = Hiện menu NPH +Show GPO LEDs = Show GPO LEDs Show on-screen messages = Show on-screen messages Stats = Thống kê System Information = Thông tin hệ thống @@ -368,6 +373,7 @@ ConfirmLoad = Load dữ liệu này? ConnectingAP = Connecting to the access point.\nPlease wait... ConnectingPleaseWait = Connecting.\nPlease wait... ConnectionName = Connection name +Copy to clipboard = Copy to clipboard Corrupted Data = Corrupted data Delete = Xóa Delete all = Xóa tất cả @@ -599,7 +605,7 @@ Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 Disable culling = Disable culling Disabled = Vô hiệu hóa -Display Layout && Effects = Chỉnh bố trí hiển thị +Display layout & effects = Chỉnh bố trí hiển thị Display Resolution (HW scaler) = Độ phân giải màn hình (HW scaler) Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 Drivers = Drivers @@ -632,6 +638,7 @@ LowCurves Tip = Chỉ được sử dụng bởi một số trò chơi, kiểm s Lower resolution for effects (reduces artifacts) = Độ phân giải thấp cho các hiệu ứng (làm giảm vật thể) Manual Scaling = Nhân rộng thủ công Medium = Trung bình +Mirror camera image = Mirror camera image Mode = Chế độ Must Restart = Bạn cần khởi động lại PPSSPP để những thay đổi có hiệu lực. Native device resolution = Độ phân giải tự nhiên. @@ -694,9 +701,12 @@ Window Size = Kích cỡ cửa sổ xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = Xóa file ZIP +Existing data = Existing data Install = Cài đặt Install game from ZIP file? = Cài đặt trò chơi từ file ZIP? +Install in folder = Install in folder Install textures from ZIP file? = Install textures from ZIP file? Installation failed = Installation failed Installed! = Đã cài xong! @@ -1050,8 +1060,12 @@ written = Được viết bằng C++ cho tốc độ và portability [RemoteISO] Browse Games = Duyệt games +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = Cổng sever nội bộ Manual Mode Client = Chế độ khách thủ công +Not currently sharing = Not currently sharing Remote disc streaming = Điều khiển đĩa từ xa Remote Port = Cổng từ xa Remote Server = server từ xa @@ -1165,10 +1179,12 @@ Connection Error = Lỗi kết nối Install = Cài Installed = Đã cài rồi Launch Game = Launch game +License = License Loading... = Đang load... MB = MB Size = Kích cỡ Uninstall = Gỡ +Website = Website [SysInfo] %0.2f Hz = %0.2f Hz @@ -1247,6 +1263,7 @@ Vulkan Features = Tính năng Vulkan (broken) = (Bị hỏng) 12HR = 12H 24HR = 24H +App switching mode = App switching mode Auto = Tự động Auto Load Savestate = Auto load savestate AVI Dump started. = Đưa AVI vào bắt đầu @@ -1257,6 +1274,7 @@ Color Saturation = Color Saturation Color Tint = Color Tint CPU Core = CPU core Dynarec/JIT (recommended) = Dynarec/JIT (khuyến khích) +Enable plugins = Enable plugins Error: load undo state is from a different game = Error: load undo state is from a different game Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system. Floating symbols = Floating symbols @@ -1281,7 +1299,7 @@ Decrease size = Decrease size Developer Tools = Công cụ NPH Display Extra Info = Display extra info Display Games on a grid = Display "Games" on a grid -Display Homebrew on a grid = Display "Homebrew && Demos" on a grid +Display Homebrew on a grid = Display "Homebrew & Demos" on a grid Display Recent on a grid = Display "Recent" on a grid Emulation = Giả lập Enable Cheats = mở cheat @@ -1313,6 +1331,8 @@ Off = Tắt Oldest Save = Save cũ nhất Only JPG and PNG images are supported = Only JPG and PNG images are supported Path does not exist! = Path does not exist! +Pause when not focused = Dừng trò chơi khi "ko tập trung" +Plugins = Plugins PSP Memory Stick = PSP Memory Stick PSP Model = PSP model PSP Settings = Thiết lập PSP @@ -1345,6 +1365,8 @@ Slot 4 = Slot 4 Slot 5 = Slot 5 Storage full = Bộ nhớ đầy Sustained performance mode = Chế độ hiệu suất duy trì +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Theme = Theme Time Format = Chỉnh định dạng thời gian (12/24) Transparent UI background = Transparent UI background @@ -1392,20 +1414,17 @@ Download = Tải về New version of PPSSPP available = Đã có phiên bản mới của PPSSPP [VR] +% of native FoV = % of native FoV 6DoF movement = 6DoF movement -Camera type = Camera type Distance to 2D menus and scenes = Distance to 2D menus and scenes Distance to 3D scenes when VR disabled = Distance to 3D scenes when VR disabled -Experts only = Experts only +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = Field of view scale Force 72Hz update = Force 72Hz update -Game camera rotation step per frame = Game camera rotation step per frame -Game camera uses rotation smoothing = Game camera uses rotation smoothing Heads-up display detection = Heads-up display detection Heads-up display scale = Heads-up display scale Manual switching between flat screen and VR using SCREEN key = Manual switching between flat screen and VR using SCREEN key -Map controller movements to keys = Map controller movements to keys -Map HMD rotations on keys instead of VR camera = Map HMD rotations on keys instead of VR camera -Motion needed to generate action = Motion needed to generate action Stereoscopic vision (Experimental) = Stereoscopic vision (Experimental) Virtual reality = Virtual reality VR camera = VR camera diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 065566b891..1b72e2b5a2 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -4,7 +4,7 @@ %1 achievements, %2 points = %1成就,%2点数 Account = 账号 Achievement progress = 成就进度 -Achievement sound volume = Achievement sound volume +Achievement sound volume = 成就提示音 Achievement unlocked = 成就达成! Achievements = 成就 Achievements are disabled = 未启用成就功能 @@ -61,7 +61,7 @@ Unsupported achievements = 不支持的成绩 Alternate speed volume = 备选速度时的音量 Audio backend = 音频引擎 Audio Error = 音频错误 -Audio file format not supported. Must be WAV. = 音频文件格式不支持,必须是WAV。 +Audio file format not supported. Must be WAV or MP3. = 音频文件格式不支持,必须是WAV或MP3。 AudioBufferingForBluetooth = 适合蓝牙缓冲区 (更慢) Auto = 自动 Device = 设备 @@ -71,7 +71,9 @@ Enable Sound = 开启声音 Global volume = 全局音量 Microphone = 麦克风 Microphone Device = 麦克风设备 +Mix audio with other apps = 允许其他APP同时播放音频 Mute = 静音 +Respect silent mode = 跟随系统静音模式 Reverb volume = 混响音量 Use new audio devices automatically = 自动使用新的音频设备 Use global volume = 使用全局音量 @@ -198,7 +200,7 @@ Direct3D9 = Direct3D 9 Direct3D11 = Direct3D 11 Disassembly = 反汇编…(&D) Discord = Discord -Display Layout && Effects = 屏幕布局和滤镜编辑… +Display Layout && Effects = 屏幕布局和滤镜… Display Rotation = 显示旋转 Dump Next Frame to Log = 转储下一帧到日志(&U) Emulation = 模拟(&E) @@ -233,6 +235,7 @@ Log Console = 控制台日志(&L) Memory View... = 查看内存…(&V) More Settings... = 更多设置…(&M) Nearest = 邻近取样(&N) +Pause when not focused = 后台运行时自动暂停(&P) Recent = 最近游戏(&R) Restart Graphics = 重启渲染 Skip Buffer Effects = 跳过缓冲效果(更快)(&S) @@ -244,7 +247,6 @@ Open Memory Stick = 打开记忆棒(&M) Open New Instance = 双开模拟器 OpenGL = OpenGL Pause = 暂停(&P) -Pause When Not Focused = 后台运行时自动暂停(&P) Portrait = 纵向 Portrait reversed = 纵向反转 PPSSPP Forums = PPSSPP官方论坛(&F) @@ -261,17 +263,17 @@ Save Map File... = 保存内存镜像文件…(&S) Save State = 快速存档 (&A) Save State File... = 保存即时存档…(&S) Savestate Slot = 即时存档插槽(&T) -Screen Scaling Filter = 屏幕缩放方法(&E) +Screen Scaling Filter = 屏幕缩放算法(&E) Show Debug Statistics = 显示调试信息(&G) Show FPS Counter = 显示帧率(&F) Skip Number of Frames = 帧的数量 Skip Percent of FPS = 帧率比例 -Smart 2D texture filtering = 自动检测像素风游戏 +Smart 2D texture filtering = 自动保留2D纹理像素风格 Stop = 停止(&S) Switch UMD = 切换UMD光盘 Take Screenshot = 屏幕截图(&T) -Texture Filtering = 纹理过滤方法(&X) -Texture Scaling = 纹理缩放方法(&T) +Texture Filtering = 纹理过滤算法(&X) +Texture Scaling = 纹理缩放算法(&T) Use Lossless Video Codec (FFV1) = 使用无损视频编码器(FFV1)(&U) Use output buffer for video = 录制包括输出缓冲 VSync = 垂直同步(&Y) @@ -307,6 +309,8 @@ Fragment = 片段着色器 Frame timing = 帧时间统计信息 Framedump tests = 帧转储测试 Frame Profiler = 帧分析器 +GPI switch %1 = GPI交换机%1 +GPI/GPO switches/LEDs = GPI/GPO信号指示灯 GPU Allocator Viewer = GPU分配器查看 GPU Driver Test = GPU驱动程序测试 GPU log profiler = GPU日志分析器 @@ -326,13 +330,14 @@ Random = 随机 Replace textures = 纹理替换 Reset = 重置 Reset limited logging = 重置受限日志 -RestoreDefaultSettings = 您确定要将所有设置恢复到默认?\n该操作无法撤销。\n操作将在PPSSPP重新启动后生效。 +RestoreDefaultSettings = 您确定要将所有设置恢复到默认?\n该操作一旦执行无法撤销。\n操作将在PPSSPP重新启动后生效。 RestoreGameDefaultSettings = 您确定要将此游戏设置\n恢复为PPSSPP默认吗? Resume = 恢复 Run CPU Tests = 运行CPU测试 Save new textures = 保存新纹理 Shader Viewer = 着色器查看器 Show Developer Menu = 显示开发者菜单 +Show GPO LEDs = 显示GPO指示灯 Show on-screen messages = 屏幕上方显示消息 Stats = 统计数据 System Information = 系统信息 @@ -359,7 +364,7 @@ Cancel = 取消 Center = 中心 Center Left = 左中间 Center Right = 右中间 -Changing this setting requires PPSSPP to restart. = 设置生效需要重新启动PPSSPP。 +Changing this setting requires PPSSPP to restart. = 更改这项设置需要PPSSPP重启。 Channel: = 信道: Choose PPSSPP save folder = 选择PPSSPP存档的文件夹 Confirm Overwrite = 您要覆盖这个存档吗? @@ -368,6 +373,7 @@ ConfirmLoad = 您要载入这个存档吗? ConnectingAP = 连接到接入点。\n请稍候… ConnectingPleaseWait = 连接中。\n请稍候… ConnectionName = 连接名称 +Copy to clipboard = Copy to clipboard Corrupted Data = 数据损坏 Delete = 删除 Delete all = 全部删除 @@ -387,7 +393,7 @@ Enabled = 启用 Enter = 确定 Failed to connect to server, check your internet connection. = 未连接到服务器,请检查网络情况 Failed to log in, check your username and password. = 无法登录,请检查账号密码 -Filter = 筛选 +Filter = 输入关键词 Finish = 完成 GE Frame Dumps = GE帧转储 Grid = 网格尺寸 @@ -403,7 +409,7 @@ Log in = 登录 Log out = 退出 Logged in! = 登录成功! Logging in... = 登录中… -More information... = 更多了解... +More information... = 了解更多... Move = 移动位置 Move Down = 移至下层 Move Up = 移至上层 @@ -426,11 +432,11 @@ Save completed = 保存完成。 Saving = 保存中。\n请稍候… SavingFailed = 无法保存存档。 Search = 搜索 -seconds, 0:off = 秒后,0=不隐藏 +seconds, 0:off = 秒间隔,0=关闭 Select = 选择 Settings = 设置 Shift = 翻页 -Skip = 跳过 +Skip = 是,跳过 Snap = 网格对齐 Space = 空格键 SSID = 网络名称 @@ -522,7 +528,7 @@ File size incorrect, bad or modified ISO = 文件大小与原版不符, 此ISO Game = 游戏 Game ID unknown - not in the ReDump database = 未知的游戏ID - ReDump数据库暂未收录 Game Settings = 游戏设置 -Homebrew = 自制游戏 +Homebrew = 自制应用 Hong Kong = 香港 InstallData = 安装数据 ISO OK according to the ReDump project = ISO镜像与ReDump数据库校验相符 @@ -533,12 +539,12 @@ One moment please... = 请稍候… Play = 启动 Remove From Recent = 从最近游玩中删除 SaveData = 存档 -Setting Background = 设置背景 +Setting Background = 设置壁纸中 Show In Folder = 在文件夹中显示 Time Played: %1h %2m %3s = 游玩时间:%1小时 %2分 %3秒 Uncompressed = 已解压 USA = 美国 -Use UI background = 使用背景为壁纸 +Use UI background = 使用此游戏为壁纸 [Graphics] % of the void = %的边框 @@ -552,17 +558,17 @@ Use UI background = 使用背景为壁纸 3x = 3倍 3x PSP = 3倍PSP 4x = 4倍 -4x PSP = 4倍PSP - 1080p +4x PSP = 4倍PSP (对应1080p) 5x = 5倍 -5x PSP = 5倍PSP -6x PSP = 6倍PSP +5x PSP = 5倍PSP (对应1.5K) +6x PSP = 6倍PSP (对应2K+) 7x PSP = 7倍PSP 8x = 8倍 -8x PSP = 8倍PSP - 4K +8x PSP = 8倍PSP (对应4K) 9x PSP = 9倍PSP 10x PSP = 10倍PSP 16x = 16倍 -AdrenoTools driver manager = 高通驱动管理器 +AdrenoTools driver manager = 骁龙GPU驱动管理 Aggressive = 激进 Alternative Speed = 备选速度1 Alternative Speed 2 = 备选速度2 @@ -570,7 +576,7 @@ Anisotropic Filtering = 各向异性过滤 Antialiasing (MSAA) = 抗锯齿 (多重采样) Aspect Ratio = 宽高比例 Auto = 自动 -Auto (1:1) = 自动 (1:1) +Auto (1:1) = 自动适配 Auto FrameSkip = 自动跳帧 Auto Max Quality = 自动最佳质量 Auto Scaling = 自动缩放 @@ -578,8 +584,8 @@ Backend = 渲染引擎 Balanced = 均衡 Bicubic = 双三次 Both = 全部显示 -Buffer graphics commands (faster, input lag) = 缓冲图形命令 (提高帧率,增加延迟) -BufferedRenderingRequired = 警告:此游戏需要关闭“跳过缓冲效果”。 +Buffer graphics commands (faster, input lag) = 缓冲图形命令 (增加性能,提高延迟) +BufferedRenderingRequired = 警告:此游戏不推荐开启“跳过缓冲效果”。 Camera = 摄像头设置 Camera Device = 摄像头设备 Cardboard Screen Size = 屏幕大小 (视区%) @@ -588,23 +594,23 @@ Cardboard Screen Y Shift = 垂直% Cardboard VR Settings = 谷歌纸板VR设置 Cheats = 金手指 Copy to texture = 复制到纹理 -Current GPU Driver = 使用的GPU驱动 +Current GPU Driver = 当前使用的GPU驱动 Debugging = 调试设置 -Default GPU driver = 默认GPU驱动程序 +Default GPU driver = 原版默认驱动 DefaultCPUClockRequired = 警告:此游戏需要将CPU频率设置为默认。 Deposterize = 色调融合 -Deposterize Tip = 修复纹理被放大时可见的缝隙 +Deposterize Tip = 修补纹理放大时可见的缝隙 Device = 设备 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disable culling = 关闭遮挡剔除 +Disable culling = 禁用遮挡剔除 (修复模型错误) Disabled = 禁用 -Display Layout && Effects = 屏幕布局和滤镜 +Display layout & effects = 屏幕布局和滤镜 Display Resolution (HW scaler) = 屏幕分辨率 -Driver requires Android API version %1, current is %2 = 驱动需要Android API版本 %1, 目前仅满足%2 +Driver requires Android API version %1, current is %2 = 驱动需要Android API版本 %1, 目前系统版本为%2 Drivers = 驱动程序 Enable Cardboard VR = 启用Cardboard VR -FPS = 每秒帧数 (FPS) +FPS = 帧率 (FPS) Frame Rate Control = 帧率设置 Frame Skipping = 跳帧 Frame Skipping Type = 跳帧方式 @@ -613,14 +619,14 @@ Geometry shader culling = 几何着色器剔除 GPUReadbackRequired = 警告:此游戏需要关闭“跳过GPU块传输”。 Hack Settings = 渲染修正 (用于修复错误) Hardware Tessellation = 硬件曲面细分 -Hardware Transform = 硬件几何变换 -hardware transform error - falling back to software = 硬件几何变换错误,改回软件模式 -HardwareTessellation Tip = 使用硬件加速曲线渲染 +Hardware Transform = 硬件几何变换 (提速) +hardware transform error - falling back to software = 硬件几何变换出现错误,将使用软件模式 +HardwareTessellation Tip = 曲线绘制交由GPU处理,仅极少数游戏使用此设置 High = 高质量 Hybrid = 混合 Hybrid + Bicubic = 混合+双三次 Ignore camera notch when centering = 忽略摄像头挖孔 -Install custom driver... = 安装自选驱动程序... +Install custom driver... = 安装第三方驱动程序... Integer scale factor = 整倍缩放 Internal Resolution = 内部分辨率 Lazy texture caching = 延迟纹理缓存 (提速) @@ -628,20 +634,21 @@ Lazy texture caching Tip = 更快,使部分游戏文字渲染出错 Linear = 线性过滤 Low = 低质量 LowCurves = 贝塞尔曲线质量 (提速) -LowCurves Tip = 适用于极少部分游戏,控制曲线的细节质量 -Lower resolution for effects (reduces artifacts) = 降低特效分辨率 (减少特效瑕疵) +LowCurves Tip = 调整曲线的绘制质量,仅极少数游戏使用此设置 +Lower resolution for effects (reduces artifacts) = 降低特效分辨率 (修复光晕效果) Manual Scaling = 手动缩放 Medium = 中质量 +Mirror camera image = 镜像翻转摄像头画面 Mode = 渲染模式 -Must Restart = 重启PPSSPP才能使这项设置生效。 -Native device resolution = 屏幕原生分辨率 -Nearest = 邻近取样 +Must Restart = 这项设置需要PPSSPP重启生效。 +Native device resolution = 原生分辨率 +Nearest = 邻近取样 (像素化) No (default) = 关闭 (默认) No buffer = 关闭缓冲 Render all frames = 逐帧渲染 -Same as Rendering resolution = 自动 (渲染分辨率) -Show Battery % = 显示电量% -Show Speed = 显示速度 +Same as Rendering resolution = 自动设置 (同渲染分辨率) +Show Battery % = 显示电量百分比 +Show Speed = 显示运行速度 Skip = 跳过 Skip Buffer Effects = 跳过缓冲效果 (提速) None = 不显示 @@ -651,42 +658,42 @@ OpenGL = OpenGL Overlay Information = 显示信息 Partial Stretch = 部分拉伸 Percent of FPS = 帧率的比例 -Performance = 性能设置 -Postprocessing shaders = 后处理着色器 +Performance = 性能优化 +Postprocessing shaders = 后处理滤镜 Recreate Activity = 重建进程 -Render duplicate frames to 60hz = 渲染重复帧到60Hz -RenderDuplicateFrames Tip = 在默认帧率较低的游戏中,使帧显示更稳定 -Rendering Mode = 渲染设置 +Render duplicate frames to 60hz = 渲染重复帧以对应60Hz +RenderDuplicateFrames Tip = 对于默认帧率较低的游戏,使帧率曲线更平滑稳定 +Rendering Mode = 基础渲染设置 Rendering Resolution = 渲染分辨率 -RenderingMode NonBuffered Tip = 提升速度,并使某些游戏特效丢失 +RenderingMode NonBuffered Tip = 提升渲染性能,使游戏特效部分丢失 Rotation = 方向 Safe = 安全 -Screen Scaling Filter = 画面缩放方法 +Screen Scaling Filter = 画面缩放算法 Show Debug Statistics = 显示调试信息 Show FPS Counter = 显示帧率 Skip GPU Readbacks = 跳过GPU块传输 -Smart 2D texture filtering = 自动检测像素风游戏 -Software Rendering = 软件渲染 (慢) +Smart 2D texture filtering = 自动保留2D纹理像素风格 +Software Rendering = 软件渲染 (慢速) Software Skinning = 软件蒙皮 -SoftwareSkinning Tip = 将模型绘制转移至CPU,在较多游戏中更快,但也有减速的反例 +SoftwareSkinning Tip = 交由CPU端优化模型绘制,此选项对于多数游戏更快,而部分游戏会减速 Speed = 运行速度 -Speed Hacks = 额外提速 (可影响画面渲染) +Speed Hacks = 提速修改 (降低渲染精度) Stereo display shader = 立体显示模式 Stereo rendering = 立体渲染 Stretch = 拉伸 -Texture Filter = 纹理过滤方法 +Texture Filter = 纹理过滤算法 Texture Filtering = 纹理过滤 -Texture replacement pack activated = 已使用纹理替换包 +Texture replacement pack activated = 纹理替换包已生效 Texture Scaling = 纹理缩放 Texture Shader = 纹理着色器 (GPU加速) -The chosen ZIP file doesn't contain a valid driver = 选择的ZIP文件不含有效的显卡驱动。 -Turn off Hardware Tessellation - unsupported = 关闭“硬件曲面细分”:不支持 +The chosen ZIP file doesn't contain a valid driver = 选择的ZIP文件里无有效的GPU驱动。 +Turn off Hardware Tessellation - unsupported = 由于系统不支持,“硬件曲面细分”关闭 Unlimited = 无限制 Up to 1 = 最高缓冲1帧 Up to 2 = 最高缓冲2帧 -Upscale Level = 纹理缩放等级 +Upscale Level = 纹理缩放尺寸 Upscale Type = 纹理缩放 (CPU) -UpscaleLevel Tip = 为了减轻CPU负担,缩放可能会延后。 +UpscaleLevel Tip = 为了均衡CPU负担,缩放可能会延后。 Use all displays = 使用全部显示器 VSync = 垂直同步 Vulkan = Vulkan @@ -694,20 +701,23 @@ Window Size = 窗口大小 xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = 删除ZIP文件 +Existing data = Existing data Install = 安装 Install game from ZIP file? = 从ZIP文件安装游戏? +Install in folder = Install in folder Install textures from ZIP file? = 从ZIP文件安装纹理包? Installation failed = 安装失败! Installed! = 安装完成! -Texture pack doesn't support install = 此纹理包不支持安装 +Texture pack doesn't support install = 这个纹理包不支持安装使用 Zip archive corrupt = ZIP文档损坏 -Zip file does not contain PSP software = ZIP文件不包含PSP软件 +Zip file does not contain PSP software = 这个ZIP压缩包未包含PSP游戏 [KeyMapping] Allow combo mappings = 多键合一 Autoconfigure = 自动配置 -Autoconfigure for device = 根据设备配置 +Autoconfigure for device = 自动映射输入设备 Bind All = 全部映射 Clear All = 全部清除 Combo mappings are not enabled = 请打开多键合一 @@ -721,22 +731,22 @@ Map Mouse = 鼠标映射 Replace = 替换现有 Show PSP = PSP 布局 Standard PSP controls = PSP基本按键 -Strict combo input order = Strict combo input order -You can press ESC to cancel. = 可以按下Esc键取消 +Strict combo input order = 依据顺序出招 +You can press ESC to cancel. = 按下Esc键退出 [MainMenu] Browse = 浏览... Buy PPSSPP Gold = 购买黄金版 Choose folder = 选择文件夹 Credits = 开发团队 -PPSSPP Homebrew Store = 从PPSSPP自制软件商店下载 +PPSSPP Homebrew Store = PPSSPP自制应用商店 Exit = 退出程序 Game Settings = 游戏设置 Games = 载入新游戏 -Give PPSSPP permission to access storage = 给予PPSSPP访问存储空间的权限 -Homebrew & Demos = 自制游戏与试玩 +Give PPSSPP permission to access storage = 请授权PPSSPP读写必要的存储空间 +Homebrew & Demos = 自制应用与演示软件 How to get games = 如何获得游戏? -How to get homebrew & demos = 如何获得自制游戏与试玩? +How to get homebrew & demos = 如何获得自制应用与演示软件? Load = 载入游戏… Loading... = 读取中… PinPath = 置顶文件夹 @@ -746,7 +756,7 @@ SavesAreTemporary = PPSSPP正在临时空间内存档 SavesAreTemporaryGuidance = 请将PPSSPP解压出来以使存档永久保留 SavesAreTemporaryIgnore = 忽略警告 UnpinPath = 取消置顶 -UseBrowseOrLoad = 浏览以选择文件夹,或者加载以读取游戏文件 +UseBrowseOrLoad = 点击“浏览”查找您存放游戏的文件夹,点击“加载”可以读取单个游戏文件 www.ppsspp.org = 访问官网 [MainSettings] @@ -786,7 +796,7 @@ Double tap button = 双击时按键 Down = 方向键:下 Dpad = 方向键 Exit App = 关闭模拟器 -Frame Advance = 逐帧播放 +Frame Advance = 逐帧递进 Hold = 锁键 Home = Home键 L = L @@ -840,35 +850,35 @@ Wlan = WLAN键 [MemStick] Already contains PSP data = 已含有PSP数据 -Cancelled - try again = 已取消 - 请再次重试 +Cancelled - try again = 已取消 - 请重试 Checking... = 检测中... -Create or Choose a PSP folder = 创建或者选择PSP文件夹 +Create or Choose a PSP folder = 新建PSP文件夹/选择原有PSP目录 Current = 目前 -DataCanBeShared = 数据可以在普通版/黄金版之间共用 -DataCannotBeShared = 数据无法在普通版/黄金版之间共用! -DataWillBeLostOnUninstall = 警告!卸载PPSSPP后全部数据将丢失! -DataWillStay = 卸载PPSSPP时数据能保留。 +DataCanBeShared = 普通和黄金版之间数据互通 +DataCannotBeShared = 数据无法在普通和黄金版之间互通! +DataWillBeLostOnUninstall = 警告:除非手动备份转移,卸载APP时将擦除全部数据和存档 +DataWillStay = 即使卸载PPSSPP,数据也能保留。 Deleting... = 删除中... Done! = 完成! -EasyUSBAccess = USB连接更简单 +EasyUSBAccess = 备份、转移、连电脑更简单 Failed to move some files! = 无法移动部分文件! Failed to save config = 无法保存配置! -Free space = 可用空间 +Free space = 可用的空间 Manually specify PSP folder = 手动指定PSP文件夹 -MemoryStickDescription = 选择PSP文件的存放位置 (记忆棒) +MemoryStickDescription = 开始之前,请选择PSP数据的存放空间 Move Data = 移动PSP数据 -Selected PSP Data Folder = 选择PSP数据文件夹 +Selected PSP Data Folder = 您提供的PSP数据文件夹 No data will be changed = 数据不会更改 -PPSSPP will restart after the change = 完成设置后会重启PPSSPP -Skip for now = 暂时跳过 +PPSSPP will restart after the change = 更改这项设置需要PPSSPP重启。 +Skip for now = 我想跳过 Starting move... = 开始移动… That folder doesn't work as a memstick folder. = 您选择的文件夹无法作为记忆棒路径。 -USBAccessThrough = USB连接时请打开Android/data/org.ppsspp.ppsspp/files -USBAccessThroughGold = USB连接时请打开Android/data/org.ppsspp.ppssppgold/files -Use App Private Data = 在APP内置的路径中保存 +USBAccessThrough = 查找、备份数据时,目录为Android/data/org.ppsspp.ppsspp/files +USBAccessThroughGold = 查找、备份数据时,目录为Android/data/org.ppsspp.ppssppgold/files +Use App Private Data = 仅在APP内部权限目录存档 Use PSP folder at root of storage = 在手机路径中保存PSP文件 -Welcome to PPSSPP! = 欢迎使用PPSSPP! -WhatsThis = 这个设置有什么用? +Welcome to PPSSPP! = 欢迎您使用PPSSPP,只需要简单几步即可! +WhatsThis = 为什么要设置? [Networking] AdHoc Server = Ad Hoc服务器 @@ -878,7 +888,7 @@ Auto = 自动 Change Mac Address = 更改MAC地址 Change proAdhocServer Address = 更改PRO Ad Hoc服务器IP地址 ChangeMacSaveConfirm = 确认随机生成新的MAC地址? -ChangeMacSaveWarning = 部分游戏会在载入存档时会验证MAC地址,\n可能会破坏存档,建议备份您的存档。 +ChangeMacSaveWarning = 部分游戏会在载入存档时会验证MAC地址,\n可能会破坏存档,建议备份您的存档或MAC地址。 Chat = 聊天 Chat Button Position = 聊天按钮位置 Chat Here = 在此处聊天 @@ -888,8 +898,8 @@ Disconnected from AdhocServer = 与Ad Hoc服务器断开连接 DNS Error Resolving = DNS解析错误 Enable built-in PRO Adhoc Server = 启用内置PRO Ad Hoc服务器 Enable network chat = 启用聊天 -Enable networking = 启用联网/无线网络 -Enable UPnP = 启用UPnP (需要几秒钟检测) +Enable networking = 启用联网功能 +Enable UPnP = 启用UPnP (要一些检测时间) EnableQuickChat = 启用快速聊天 Enter a new PSP nickname = 输入新的PSP昵称 Enter Quick Chat 1 = 输入快速聊天1 @@ -922,7 +932,7 @@ Quick Chat 5 = 快速聊天5 QuickChat = 快速聊天 Randomize = 随机生成 Send = 发送 -Send Discord Presence information = 发送 Discord 在线状态 +Send Discord Presence information = Discord 显示在线状态 Unable to find UPnP device = 未找到UPnP设备 UPnP (port-forwarding) = UPnP (端口转发) UPnP need to be reinitialized = UPnP 需要重新初始化 @@ -952,8 +962,8 @@ Spanish = 西班牙语 [Pause] Cheats = 金手指 Continue = 继续游戏 -Create Game Config = 建立游戏配置 -Delete Game Config = 删除游戏配置 +Create Game Config = 建立游戏预设配置 +Delete Game Config = 删除游戏预设配置 Exit to menu = 返回主菜单 Game Settings = 游戏设置 Load State = 载入即时存档 @@ -1012,12 +1022,12 @@ CatmullRom = Catmull-Rom双三插值缩放 [PSPCredits] all the forum mods = 论坛所有的管理员 build server = 编译服务器 -Buy Gold = 购买黄金版 +Buy Gold = 升级黄金版 check = 同时请浏览我们的海豚Dolphin模拟器,最好用的Wii/NGC模拟器 CheckOutPPSSPP = 浏览我们的PPSSPP,一款超级棒的PSP模拟器:https://www.ppsspp.org/ contributors = 贡献者: created = 作者: -Discord = Discord +Discord = Discord服务器 info1 = PPSSPP只用于教学研究,不应被用于商业用途。 info2 = 请确认您持有游戏镜像的正版拷贝: info3 = 这可以是您购买了游戏的UMD光盘, @@ -1026,9 +1036,9 @@ info5 = PSP™是索尼公司的注册商标。 iOS builds = 负责iOS编译 license = 遵循GPL 2.0+许可协议的自由软件 list = 以了解兼容性列表、官方论坛以及开发动态 -PPSSPP Forums = PPSSPP官方论坛 +PPSSPP Forums = 官方论坛 Privacy Policy = 隐私政策 -Share PPSSPP = 分享PPSSPP +Share PPSSPP = 分享给好友 specialthanks = 鸣谢: specialthanksKeithGalocy = 的硬件工作和指导,他来自NVIDIA specialthanksMaxim = 的出色的Atrac3+解码器工作 @@ -1045,62 +1055,66 @@ translators3 = xzapk、Arthur200000、Playhi、PeaceShi translators4 = Nargacuga、driver1998、xujibbs、Croden1999 translators5 = translators6 = -Twitter @PPSSPP_emu = 推特 (Twitter) +Twitter @PPSSPP_emu = X (Twitter) website = 请查阅官方网站 written = 使用C++编写以保证速度与移植性 [RemoteISO] Browse Games = 浏览游戏 +Connect = 连接状态 +Currently sharing = 目前共享中 +Files to share = 共享的游戏 Local Server Port = 本地服务器端口 Manual Mode Client = 手动配置客户端 +Not currently sharing = 游戏共享已关闭 Remote disc streaming = 远程游戏串流 Remote Port = 远程端口 Remote Server = 远程服务器 Remote Subdirectory = 远程子路径 RemoteISODesc = 您最近列表中的游戏将被共享 RemoteISOLoading = 已连接,正在载入游戏列表… -RemoteISOScanning = 扫描中…在您的服务器设备上点击“共享游戏” +RemoteISOScanning = 扫描中…在您的服务器设备上点击“发起游戏共享” RemoteISOScanningTimeout = 扫描中…请检查您防火墙的设置 RemoteISOWifi = 说明: 请将设备连接到同一Wi-Fi网络下 RemoteISOWinFirewall = 警告:Windows防火墙正在阻挡游戏共享 Settings = 设置 -Share Games (Server) = 共享游戏 (服务器) -Share on PPSSPP startup = PPSSPP启动时共享 -Show Remote tab on main screen = 主界面显示远程栏 +Share Games (Server) = 发起游戏共享 +Share on PPSSPP startup = 启动PPSSPP时自动打开共享 +Show Remote tab on main screen = 主页显示远程游戏标签栏 Stop Sharing = 停止共享 Stopping.. = 正在停止… [Reporting] -Bad = 很差 +Bad = 糟糕 FeedbackCRCCalculating = 游戏CRC:计算中… FeedbackCRCValue = 游戏CRC:%1 FeedbackDelayInfo = 您的数据正在后台提交。 -FeedbackDesc = 这款游戏兼容性怎样?请告诉我们和社区! +FeedbackDesc = 这款游戏兼容性怎样?请分享给我们和玩家社区! FeedbackDisabled = 需要启用“向服务器报告兼容性问题”选项 -FeedbackIncludeCRC = 注意:将使用少部分电量发送CRC校验码 -FeedbackIncludeScreen = 同时发送一张截图 +FeedbackIncludeCRC = 注意:将使用少许电量发送CRC校验码 +FeedbackIncludeScreen = 附带发送一张截图 FeedbackSubmitDone = 您的数据已提交。 FeedbackSubmitFail = 无法向服务器提交数据,请尝试更新PPSSPP。 FeedbackThanks = 感谢您的反馈! -Gameplay = 游戏过程正常 -Graphics = 画面无错误 -Great = 非常好 -In-game = 能进游戏 -In-game Description = 游戏能够运行,但问题太多,不能愉快通关 -Menu/Intro = 仅在主界面/开头动画 -Menu/Intro Description = 看到个菜单,但无法正常游玩 +Gameplay = 游戏运行 +Graphics = 画面效果 +Great = 良好 +In-game = 勉强运行 +In-game Description = 游戏能进入游玩过程,但运行错误太多,想愉快通关不可能 +Menu/Intro = 卡主界面 +Menu/Intro Description = 已经加载到菜单界面,但无法正常进入游玩 Nothing = 无法运行 -Nothing Description = 完全无法游玩,启动直接黑屏或者崩溃 -OK = 还行 +Nothing Description = 完全无法运行,启动后黑屏或者崩溃 +OK = 中规中矩 Open Browser = 打开反馈网站 -Overall = 总体概括 -Perfect = 非常完美 -Perfect Description = 游戏全程完美模拟——太赞了! +Overall = 总体评级 +Perfect = 效果完美 +Perfect Description = 游戏全程完美,0模拟错误——太赞了! Plays = 基本可玩 -Plays Description =游戏大部分都可玩,偶尔有一些小错误但不影响 +Plays Description =游戏处于比较可玩的状态,有一些小错误,但不影响游玩过程。 ReportButton = 报告反馈 Show disc CRC = 查看游戏CRC -Speed = 运行速度快 +Speed = 运行速度 Submit Feedback = 提交反馈 SuggestionConfig = 请参阅网站上的报告以了解最佳设置。 SuggestionCPUSpeed0 = 请禁用修改CPU速度设置。 @@ -1117,18 +1131,18 @@ View Feedback = 查看所有反馈 Date = 日期 Filename = 文件名 No screenshot = 没有截图 -None yet. Things will appear here after you save. = 暂无,在你保存后将会在此出现存档。 -Nothing matching '%1' was found. = 没有找到关于“%1”的结果 +None yet. Things will appear here after you save. = 这里暂无内容,游戏存下数据之后再回来吧。 +Nothing matching '%1' was found. = 没有找到名为“%1”的游戏存档。 Save Data = 保存的存档 -Save States = 保存的即时存档 -Savedata Manager = 存档数据管理器 -Showing matches for '%1'. = 找到符合“%1”的搜索结果。 +Save States = 即时存档 +Savedata Manager = 存档管理器 +Showing matches for '%1'. = 搜索到名称为“%1”的游戏存档。 Size = 大小 [Screen] Cardboard VR OFF = Cardboard VR关闭 Chainfire3DWarning = 警告:检测到Chainfire3D (3D神器),可能会导致问题。 -ExtractedISOWarning = ISO文件解压缩后可能引起问题\n推荐直接加载整个ISO文件。 +ExtractedISOWarning = ISO文件解压缩后可能引起问题\n推荐使用完整ISO文件。 Failed to load state = 无法载入即时存档 Failed to save state = 无法保存即时存档 fixed = 速度:预设1 @@ -1158,10 +1172,12 @@ Connection Error = 网络错误 Install = 安装 Installed = 已安装 Launch Game = 开始游戏 +License = 软件许可证 Loading... = 载入中… MB = MB Size = 大小 Uninstall = 卸载 +Website = 网站 [SysInfo] %0.2f Hz = %0.2f Hz @@ -1200,7 +1216,7 @@ GPU Information = GPU信息 High precision float range = 高精度浮点范围 High precision int range = 高精度整数范围 Icon cache = 图标缓存 -Instance = Instance +Instance = 进程 JIT available = JIT可用 Lang/Region = 语言/区域 Memory Page Size = 内存页大小 @@ -1219,7 +1235,7 @@ Refresh rate = 刷新率 Release = 发布版 RW/RX exclusive = RW/RX独占 Sample rate = 采样率 -Screen notch insets = Screen notch insets +Screen notch insets = 屏幕前摄坐标 Shading Language = 着色语言 Storage = 存储 Sustained perf mode = 持续性能模式 @@ -1234,33 +1250,37 @@ Version Information = 版本信息 Vulkan Extensions = Vulkan扩展 Vulkan Features = Vulkan特性 Driver bugs = 驱动检测 -No GPU driver bugs detected = GPU驱动运行正常 +No GPU driver bugs detected = GPU驱动运行良好 [System] (broken) = (损坏) 12HR = 12小时制 24HR = 24小时制 +App switching mode = App switching mode Auto = 自动 Auto Load Savestate = 自动载入即时存档 AVI Dump started. = AVI转储开始 AVI Dump stopped. = AVI转储停止 Cache ISO in RAM = 在内存中缓存完整ISO Change CPU Clock = 修改PSP的CPU频率 (不稳定) -CPU Core = CPU核心模式 +CPU Core = CPU模拟核心 Dynarec/JIT (recommended) = 动态重编译 (推荐) -JIT using IR = JIT using IR +Enable plugins = 启用插件 +JIT using IR = IR动态重编译 Loaded plugin: %1 = 已加载插件: %1 Only JPG and PNG images are supported = 只支持JPG和PNG图片 -Recording = 录制中 +Pause when not focused = 后台运行时自动暂停(&P) +Plugins = 插件 +Recording = 录制 RetroAchievements = 成就系统 Rewind Snapshot Interval = 倒带快照间隔 Color Tint = 颜色色调 Color Saturation = 饱和度 Error: load undo state is from a different game = 错误:撤回的即时存档是来自不同游戏的 Failed to load state for load undo. Error in the file system. = 无法撤回加载即时存档,文件系统有错误。 -Floating symbols = 飘浮按键 +Floating symbols = 键入游趣 Game crashed = 游戏发生崩溃。 -Language = 语言设置 +Language = 显示语言 Memory Stick folder = 记忆棒目录 Memory Stick size = 记忆棒大小 Change Nickname = 修改昵称 @@ -1272,7 +1292,7 @@ Clear Recent Games List = 清除“最近的游戏”内容 Clear UI background = 清除壁纸 Confirmation Button = 确认按钮 Date Format = 日期格式 -Day Light Saving = 夏令时 +Day Light Saving = 使用夏令时 DDMMYYYY = 日/月/年 Decrease size = 减小尺寸 Developer Tools = 开发者工具 @@ -1285,7 +1305,7 @@ Enable Cheats = 开启金手指 Enable Compatibility Server Reports = 向服务器报告兼容性问题 Failed to load state. Error in the file system. = 无法载入即时存档,文件系统出错。 Failed to save state. Error in the file system. = 无法保存即时存档,文件系统出错。 -Fast (lag on slow storage) = 快速模式 (存储低速时有延迟) +Fast (lag on slow storage) = 快速模式 (低速存储有延迟) Fast Memory = 快速内存 (不稳定) Force real clock sync (slower, less lag) = 强制同步实际时钟 (降低延迟,很慢) Games list settings = 游戏列表设置 @@ -1293,16 +1313,16 @@ General = 常规设置 Grid icon size = 图标方格尺寸 Help the PPSSPP team = 帮助PPSSPP团队 Host (bugs, less lag) = 主机模式 (有错误,较少延迟) -Ignore bad memory accesses = 忽略错误内存访问 +Ignore bad memory accesses = 忽略错误内存访问 (缓解游戏崩溃) Increase size = 增大尺寸 Interpreter = 解释器 IO timing method = I/O时序方法 IR Interpreter = IR解释器 Memory Stick Folder = 记忆棒文件夹 Memory Stick inserted = 插入记忆棒 -MHz, 0:default = MHz, 默认设置为0 +MHz, 0:default = MHz, 0为默认设置 MMDDYYYY = 月/日/年 -Moving background = 动态壁纸 +Moving background = 灵动壁纸 Newest Save = 最新的即时存档 No animation = 静态壁纸 Not a PSP game = 这不是一个PSP游戏 @@ -1314,7 +1334,7 @@ PSP Model = PSP机型 PSP Settings = PSP设置 PSP-1000 = PSP-1000 PSP-2000/3000 = PSP-2000/3000 -Recent games = 最近的游戏 +Recent games = 近日常玩 Record Audio = 录制音频 Record Display = 录制视频 Reset Recording on Save/Load State = 保存/载入存档时重置录制 @@ -1326,7 +1346,7 @@ Savestate Slot = 即时存档插槽 Savestate slot backups = 即时存档备份 Screenshots as PNG = 将截图保存为PNG格式 Set Memory Stick folder = 设置记忆棒文件夹 -Set UI background... = 设置壁纸… +Set UI background... = 自定义壁纸… Show ID = 游戏ID Show region flag = 地区标识 Simulate UMD delays = 模拟UMD延迟 @@ -1338,24 +1358,26 @@ Slot 4 = 插槽4 Slot 5 = 插槽5 Storage full = 存储空间已满 Sustained performance mode = 持续性能模式 (使长时间运行的应用运行更流畅) +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Time Format = 时间格式 -Transparent UI background = 透明游戏背景 +Transparent UI background = 游戏时使用半透明界面 UI = 用户界面 UI background animation = 背景动画 UI Sound = 按键音效 undo %c = 备份%c USB = USB路径 Use Lossless Video Codec (FFV1) = 使用无损视频编码器 (FFV1) -Use O to confirm = 使用按键O -Use output buffer (with overlay) for recording = 录制输出缓冲区 (包含叠加信息) -Use system native keyboard = 使用系统原生键盘 -Use X to confirm = 使用按键X +Use O to confirm = 按键O +Use output buffer (with overlay) for recording = 录制输出缓冲区 (包含叠加层) +Use system native keyboard = 使用系统键盘输入 +Use X to confirm = 按键X VersionCheck = 检查PPSSPP新版本 WARNING: Android battery save mode is on = 警告:安卓省电模式已开启 WARNING: Battery save mode is on = 警告:省电模式已开启 -Waves = 波浪动画 +Waves = 流光幻舞 YYYYMMDD = 年/月/日 -Theme = 主题 +Theme = 主题模式 Show Memory Stick folder = 打开记忆棒文件夹 [TextureShaders] @@ -1387,28 +1409,25 @@ Download = 下载 New version of PPSSPP available = 检测到新版本的PPSSPP [Search] -Filtering settings by '%1' = 查找“%1”的结果 +Filtering settings by '%1' = 找到名为“%1”的设置 Find settings = 查找选项 -Filter = 搜索 -Clear filter = 取消筛选 -No settings matched '%1' = 没有找到选项“%1” +Filter = 搜索设置 +Clear filter = 结束搜索 +No settings matched '%1' = 没有找到名为“%1”的设置 Search term = 搜索关键词 [VR] +% of native FoV = 原生视角的% 6DoF movement = 6自由度移动 -Camera type = 相机类型 Distance to 2D menus and scenes = 2D菜单和场景的距离 Distance to 3D scenes when VR disabled = 3D场景的距离 (VR关闭时) -Experts only = 专家模式 +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = 视角比例 Force 72Hz update = 强制72Hz刷新 -Game camera rotation step per frame = 游戏视角每帧灵敏度 -Game camera uses rotation smoothing = 游戏视角平滑转动 Heads-up display detection = HUD检测 Heads-up display scale = HUD比例 Manual switching between flat screen and VR using SCREEN key = 使用SCREEN键切换荧幕模式和VR模式 -Map controller movements to keys = 映射控制器移动到键位 -Map HMD rotations on keys instead of VR camera = 映射头显转动到键位,而不是VR视角 -Motion needed to generate action = 产生动作的感应值 Stereoscopic vision (Experimental) = 立体视觉 (实验性) Virtual reality = 虚拟现实 VR camera = VR视角 diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index 6796cac9da..3c5f05c45d 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -4,7 +4,7 @@ %1 achievements, %2 points = %1 個成就,%2 個點數 Account = 帳戶 Achievement progress = 成就進度 -Achievement sound volume = Achievement sound volume +Achievement sound volume = 成就音效音量 Achievement unlocked = 成就已解鎖 Achievements = 成就 Achievements are disabled = 成就已停用 @@ -61,7 +61,7 @@ Unsupported achievements = 不支援的成就 Alternate speed volume = 替代速度音量 Audio backend = 音訊後端 (需要重新啟動) Audio Error = 音訊錯誤 -Audio file format not supported. Must be WAV. = 音訊檔案格式不支援,必須為 WAV。 +Audio file format not supported. Must be WAV or MP3. = 音訊檔案格式不支援,必須是 WAV 或 MP3。 AudioBufferingForBluetooth = 藍牙友好緩衝區 (更慢) Auto = 自動 Device = 裝置 @@ -71,7 +71,9 @@ Enable Sound = 啟用音效 Global volume = 全域音量 Microphone = 麥克風 Microphone Device = 麥克風裝置 +Mix audio with other apps = 與其他應用程式混合音訊 Mute = 靜音 +Respect silent mode = 尊重靜音模式 Reverb volume = 混響裝置音量 Use new audio devices automatically = 自動使用新音訊裝置 Use global volume = 使用全域音量 @@ -83,7 +85,7 @@ Analog Limiter = 類比限制器 Analog Settings = 類比設定 Analog Stick = 類比搖桿 Analog Style = 類比樣式 -Analog trigger threshold = Analog trigger threshold +Analog trigger threshold = 類比觸發閾值 AnalogLimiter Tip = 類比限制器按鈕被按下時 Auto = 自動 Auto-centering analog stick = 自動置中類比搖桿 @@ -97,7 +99,7 @@ Calibrate Analog Stick = 校正類比搖桿 Calibrate = 校正 Calibrated = 已校正 Calibration = 校正 -Circular deadzone = 圓形低端半徑 +Circular deadzone = 圓形死區 Circular stick input = 圓形搖桿輸入 Classic = 傳統 Confine Mouse = 在視窗/顯示區域內截獲滑鼠 @@ -135,7 +137,7 @@ Low end radius = 低端半徑 Mouse = 滑鼠設定 Mouse sensitivity = 滑鼠敏感度 Mouse smoothing = 滑鼠平滑度 -Mouse wheel button-release delay = Mouse wheel button-release delay +Mouse wheel button-release delay = 滑鼠滾輪按鈕釋放延遲 MouseControl Tip = 您現在可以透過按下「M」圖示在控制對應畫面中對應滑鼠。 None (Disabled) = 無 (已停用) Off = 關閉 @@ -176,7 +178,7 @@ Cheats = 密技 Edit Cheat File = 編輯密技檔案 Import Cheats = 從 cheat.db 匯入 Import from %s = 從 %s 匯入 -Refresh interval = 重新整理速率 +Refresh interval = 重新整理間隔 [DesktopUI] # If your language does not show well with the default font, you can use Font to specify a different one. @@ -233,8 +235,9 @@ Log Console = 記錄主控台(&L) Memory View... = 記憶體檢視(&V)… More Settings... = 更多設定(&M)… Nearest = 鄰近取樣(&N) +Pause when not focused = 未聚焦時暫停(&P) Recent = 最近(&R) -Restart Graphics = Restart Graphics +Restart Graphics = 重新啟動圖形 Skip Buffer Effects = 跳過緩衝區效果(&S) Off = 關閉(&O) Open Chat = 開啟聊天 @@ -244,7 +247,6 @@ Open Memory Stick = 開啟記憶棒(&M) Open New Instance = 開啟新執行個體 OpenGL = OpenGL(&O) Pause = 暫停(&P) -Pause When Not Focused = 未聚焦時暫停(&P) Portrait = 直向 Portrait reversed = 直向反轉 PPSSPP Forums = PPSSPP 論壇(&F) @@ -266,7 +268,7 @@ Show Debug Statistics = 顯示偵錯統計資料(&G) Show FPS Counter = 顯示 FPS 計數器(&F) Skip Number of Frames = 跳過影格數 Skip Percent of FPS = 跳過 FPS 百分比 -Smart 2D texture filtering = Smart 2D texture filtering +Smart 2D texture filtering = 智慧 2D 紋理過濾 Stop = 停止(&S) Switch UMD = 切換 UMD Take Screenshot = 擷取螢幕畫面(&T) @@ -301,12 +303,14 @@ Dump next frame to log = 將下一個影格傾印至記錄 Enable driver bug workarounds = 啟用驅動程式錯誤因應措施 Enable Logging = 啟用偵錯記錄 Enter address = 輸入位址 -Fast-forward mode = 快轉 +Fast-forward mode = 快轉模式 FPU = FPU Fragment = 片段 Frame timing = 影格計時 Framedump tests = 影格傾印測試 Frame Profiler = 影格分析工具 +GPI switch %1 = GPI 開關 %1 +GPI/GPO switches/LEDs = GPI/GPO 開關/LED GPU Allocator Viewer = GPU 配置器檢視器 GPU Driver Test = GPU 驅動程式測試 GPU Profile = GPU 設定檔 @@ -333,6 +337,7 @@ Run CPU Tests = 執行 CPU 測試 Save new textures = 儲存新紋理 Shader Viewer = 著色器檢視器 Show Developer Menu = 顯示開發人員選單 +Show GPO LEDs = 顯示 GPO LED Show on-screen messages = 顯示螢幕訊息 Stats = 統計資料 System Information = 系統資訊 @@ -347,7 +352,7 @@ Vertex = 頂點 VFPU = VFPU [Dialog] -%d ms = %d ms +%d ms = %d 毫秒 %d seconds = %d 秒 * PSP res = * PSP 解析度 Active = 啟用 @@ -368,6 +373,7 @@ ConfirmLoad = 要載入這個存檔的資料嗎? ConnectingAP = 正在連線至存取點\n請稍候… ConnectingPleaseWait = 正在連線\n請稍候… ConnectionName = 連線名稱 +Copy to clipboard = Copy to clipboard Corrupted Data = 已損毀的資料 Delete = 刪除 Delete all = 全部刪除 @@ -403,7 +409,7 @@ Log in = 登入 Log out = 登出 Logged in! = 已登入! Logging in... = 正在登入… -More information... = More information... +More information... = 更多資訊… Move = 移動 Move Down = 下移 Move Up = 上移 @@ -562,7 +568,7 @@ Use UI background = 使用 UI 背景 9x PSP = 9× PSP 10x PSP = 10× PSP 16x = 16× -AdrenoTools driver manager = AdrenoTools driver manager +AdrenoTools driver manager = AdrenoTools 驅動程式管理員 Aggressive = 積極 Alternative Speed = 替代速度 (於 %,0 = 無限制) Alternative Speed 2 = 替代速度 2 (於 %,0 = 無限制) @@ -587,22 +593,22 @@ Cardboard Screen X Shift = X 移位 (於 % 的空白區) Cardboard Screen Y Shift = Y 移位 (於 % 的空白區) Cardboard VR Settings = Google Cardboard VR 設定 Cheats = 密技 -Copy to texture = Copy to texture -Current GPU Driver = Current GPU Driver +Copy to texture = 複製到紋理 +Current GPU Driver = 目前 GPU 驅動程式 Debugging = 偵錯 -Default GPU driver = Default GPU driver +Default GPU driver = 預設 GPU 驅動程式 DefaultCPUClockRequired = 警告:這個遊戲需要將 CPU 時脈設為預設值 Deposterize = 色調混合 Deposterize Tip = 修正放大化紋理中的視覺帶狀故障 Device = 裝置 Direct3D 9 = Direct3D 9 Direct3D 11 = Direct3D 11 -Disable culling = Disable culling -Disabled = Disabled -Display Layout && Effects = 顯示版面配置與效果 +Disable culling = 停用揀選 +Disabled = 已停用 +Display layout & effects = 顯示版面配置與效果 Display Resolution (HW scaler) = 顯示解析度 (硬體縮放) -Driver requires Android API version %1, current is %2 = Driver requires Android API version %1, current is %2 -Drivers = Drivers +Driver requires Android API version %1, current is %2 = 驅動程式需要 Android API 版本為 %1,目前為 %2 +Drivers = 驅動程式 Enable Cardboard VR = 啟用 Cardboard VR FPS = FPS Frame Rate Control = 影格速率控制 @@ -620,7 +626,7 @@ High = 高 Hybrid = 混合 Hybrid + Bicubic = 混合 + 雙立方 Ignore camera notch when centering = 置中時忽略相機凹口 -Install custom driver... = Install custom driver... +Install custom driver... = 安裝自訂驅動程式… Integer scale factor = 整數縮放比例 Internal Resolution = 內部解析度 Lazy texture caching = 消極式紋理快取 (加速) @@ -632,17 +638,18 @@ LowCurves Tip = 僅供少數遊戲使用,控制曲線平滑度 Lower resolution for effects (reduces artifacts) = 降低效果解析度 (降低失真) Manual Scaling = 手動縮放 Medium = 中 +Mirror camera image = 鏡像相機圖像 Mode = 模式 Must Restart = 您必須重新啟動 PPSSPP 以使這項變更生效 Native device resolution = 原生裝置解析度 Nearest = 鄰近取樣 -No (default) = No (default) +No (default) = 無 (預設) No buffer = 無緩衝 Render all frames = 轉譯所有影格 Same as Rendering resolution = 同於轉譯解析度 Show Battery % = 顯示電池百分比 Show Speed = 顯示速度 -Skip = Skip +Skip = 跳過 Skip Buffer Effects = 跳過緩衝區效果 None = 無 Number of Frames = 影格數 @@ -665,7 +672,7 @@ Screen Scaling Filter = 螢幕縮放濾鏡 Show Debug Statistics = 顯示偵錯統計資料 Show FPS Counter = 顯示 FPS 計數器 Skip GPU Readbacks = 跳過 GPU 讀回 -Smart 2D texture filtering = Smart 2D texture filtering +Smart 2D texture filtering = 智慧 2D 紋理過濾 Software Rendering = 軟體轉譯 (慢) Software Skinning = 軟體除皮 SoftwareSkinning Tip = 結合除皮模組在 CPU 上繪製,在多數遊戲上更快 @@ -675,11 +682,11 @@ Stereo display shader = 立體顯示著色器 Stereo rendering = 立體轉譯 Stretch = 延伸 Texture Filter = 紋理濾鏡 -Texture Filtering = 紋理濾鏡 +Texture Filtering = 紋理過濾 Texture replacement pack activated = 紋理取代套件已啟用 Texture Scaling = 紋理縮放 Texture Shader = 紋理著色器 -The chosen ZIP file doesn't contain a valid driver = The chosen ZIP file doesn't contain a valid driver +The chosen ZIP file doesn't contain a valid driver = 選擇的 ZIP 檔案不包含有效的驅動程式 Turn off Hardware Tessellation - unsupported = 關閉「硬體鑲嵌」:不支援 Unlimited = 無限制 Up to 1 = 最多至 1 @@ -694,11 +701,14 @@ Window Size = 視窗大小 xBRZ = xBRZ [InstallZip] +Data to import = Data to import Delete ZIP file = 刪除 ZIP 檔案 +Existing data = Existing data Install = 安裝 Install game from ZIP file? = 從 ZIP 檔案安裝遊戲? +Install in folder = Install in folder Install textures from ZIP file? = 從 ZIP 檔案安裝紋理? -Installation failed = Installation failed +Installation failed = 安裝失敗 Installed! = 已安裝! Texture pack doesn't support install = 紋理套件不支援安裝 Zip archive corrupt = ZIP 封存損毀 @@ -711,17 +721,17 @@ Autoconfigure for device = 自動設定裝置 Bind All = 全部繫結 Clear All = 全部清除 Combo mappings are not enabled = 組合對應未啟用 -Control modifiers = Control modifiers +Control modifiers = 控制修改程式 Default All = 重設為預設值 -Emulator controls = Emulator controls -Extended PSP controls = Extended PSP controls +Emulator controls = 模擬器控制 +Extended PSP controls = 擴充 PSP 控制 Map a new key for = 對應新按鍵: Map Key = 對應按鍵 Map Mouse = 對應滑鼠 Replace = 取代 Show PSP = 顯示 PSP -Standard PSP controls = Standard PSP controls -Strict combo input order = Strict combo input order +Standard PSP controls = 標準 PSP 控正 +Strict combo input order = 嚴格組合輸入順序 You can press ESC to cancel. = 您可以按下 ESC 取消 [MainMenu] @@ -824,8 +834,8 @@ Texture Dumping = 紋理傾印 Texture Replacement = 紋理取代 Toggle Fullscreen = 切換全螢幕 Toggle mode = 切換模式 -Toggle mouse input = Toggle mouse input -Toggle touch controls = Toggle touch controls +Toggle mouse input = 切換滑鼠輸入 +Toggle touch controls = 切換觸控控制 Toggle WLAN = 切換 WLAN Triangle = △ Fast-forward = 快轉 @@ -875,7 +885,7 @@ Hostname = 主機名稱 Invalid IP or hostname = 無效的 IP 或主機名稱 Minimum Timeout = 最小逾時 (單位為毫秒,0 = 預設) Misc = 雜項 (預設 = PSP 相容性) -Network connected = Network connected +Network connected = 網路已連線 Network initialized = 網路已初始化 Please change your Port Offset = 請變更您的連接埠位移 Port offset = 連接埠位移 (0 = PSP 相容性) @@ -1019,14 +1029,14 @@ written = 使用 C++ 編寫,以保證建置速度和相容性 [MemStick] Already contains PSP data = 已包含 PSP 資料 Cancelled - try again = 已取消 - 再試一次 -Checking... = Checking... +Checking... = 正在檢查… Create or Choose a PSP folder = 建立或選擇 PSP 資料夾 Current = 目前 DataCanBeShared = 資料可在 PPSSPP 標準版/黃金版之間共用 DataCannotBeShared = 資料無法在 PPSSPP 標準版/黃金版之間共用! DataWillBeLostOnUninstall = 警告!資料會在解除安裝 PPSSPP 後遺失! DataWillStay = 資料會在解除安裝 PPSSPP 後保留 -Deleting... = Deleting... +Deleting... = 正在刪除… Done! = 完成! EasyUSBAccess = USB 輕鬆存取 Failed to move some files! = 無法移動部分檔案! @@ -1050,8 +1060,12 @@ WhatsThis = 這是什麼? [RemoteISO] Browse Games = 瀏覽遊戲 +Connect = Connect +Currently sharing = Currently sharing +Files to share = Files to share Local Server Port = 本機伺服器連接埠 Manual Mode Client = 手動設定用戶端 +Not currently sharing = Not currently sharing Remote disc streaming = 遠端光碟串流 Remote Port = 遠端連接埠 Remote Server = 遠端伺服器 @@ -1065,7 +1079,7 @@ RemoteISOWinFirewall = 警告:Windows 防火牆已封鎖共用 Settings = 設定 Share Games (Server) = 共用遊戲 (伺服器) Share on PPSSPP startup = PPSSPP 啟動時共用 -Show Remote tab on main screen = Show Remote tab on main screen +Show Remote tab on main screen = 在主要螢幕上顯示遠端標籤 Stop Sharing = 停止共用 Stopping.. = 正在停止… @@ -1127,7 +1141,7 @@ Size = 大小 [Screen] Cardboard VR OFF = Cardboard VR 關閉 Chainfire3DWarning = 警告:偵測到 Chainfire3D,可能會造成問題 -ExtractedISOWarning = Extracted ISOs often don't work.\nPlay the ISO file directly. +ExtractedISOWarning = 解壓縮的 ISO 可能無法運作。\n請直接使用 ISO 檔案。 Failed to load state = 無法載入存檔 Failed to save state = 無法儲存存檔 fixed = 速度:替代 @@ -1157,10 +1171,12 @@ Connection Error = 連線錯誤 Install = 安裝 Installed = 已安裝 Launch Game = 啟動遊戲 +License = 軟體許可 Loading... = 正在載入… MB = MB Size = 大小 Uninstall = 解除安裝 +Website = 網站 [SysInfo] %0.2f Hz = %0.2f Hz @@ -1199,7 +1215,7 @@ GPU Information = GPU 資訊 High precision float range = 高精確度浮點數範圍 High precision int range = 高精確度整數範圍 Icon cache = 圖示快取 -Instance = Instance +Instance = 執行個體 JIT available = 可用 JIT Lang/Region = 語言/區域 Memory Page Size = 記憶體分頁大小 @@ -1219,7 +1235,7 @@ Refresh rate = 重新整理速率 Release = 發行版本 RW/RX exclusive = RW/RX 排除 Sample rate = 取樣率 -Screen notch insets = Screen notch insets +Screen notch insets = 螢幕凹口插入 Shading Language = 網底語言 Storage = 儲存空間 Sustained perf mode = 持續效能模式 @@ -1239,6 +1255,7 @@ Display Color Formats = 顯示器色彩格式 (broken) = (已損毀) 12HR = 12 小時制 24HR = 24 小時制 +App switching mode = App switching mode Auto = 自動 Auto Load Savestate = 自動載入存檔 AVI Dump started. = AVI 傾印已啟動 @@ -1246,11 +1263,12 @@ AVI Dump stopped. = AVI 傾印已停止 Cache ISO in RAM = 將完整 ISO 快取於 RAM Change CPU Clock = 變更模擬 PSP CPU 時脈 (不穩定) CPU Core = CPU 核心 -Dynarec/JIT (recommended) = 動態重新編譯/JIT +Dynarec/JIT (recommended) = 動態重新編譯/JIT (建議) +Enable plugins = 啟用外掛程式 Game crashed = 遊戲已當機 -JIT using IR = JIT using IR +JIT using IR = JIT 使用 IR Language = 語言 -Loaded plugin: %1 = Loaded plugin: %1 +Loaded plugin: %1 = 載入的外掛程式: %1 Memory Stick folder = 記憶棒資料夾 Memory Stick size = 記憶棒大小 Change Nickname = 變更暱稱 @@ -1301,8 +1319,10 @@ No animation = 靜態背景 Not a PSP game = 這不是 PSP 遊戲 Off = 關閉 Oldest Save = 最舊存檔 -Only JPG and PNG images are supported = Only JPG and PNG images are supported +Only JPG and PNG images are supported = 僅支援 JPG 和 PNG 影像 Path does not exist! = 路徑不存在! +Pause when not focused = 未聚焦時暫停(&P) +Plugins = 外掛程式 PSP Memory Stick = PSP 記憶棒 PSP Model = PSP 型號 PSP Settings = PSP 設定 @@ -1311,7 +1331,7 @@ PSP-2000/3000 = PSP-2000/3000 Recent games = 最近遊戲 Record Audio = 錄製音訊 Record Display = 錄製視訊 -Recording = Recording +Recording = 錄製 Reset Recording on Save/Load State = 儲存/載入存檔時重設錄製 Restore Default Settings = 將 PPSSPP 設定重設為預設值 RetroAchievements = RetroAchievements @@ -1334,6 +1354,8 @@ Slot 4 = 插槽 4 Slot 5 = 插槽 5 Storage full = 儲存空間已滿 Sustained performance mode = 持續效能模式 +Swipe once to switch app (indicator auto-hides) = Swipe once to switch app (indicator auto-hides) +Swipe twice to switch app (indicator stays visible) = Swipe twice to switch app (indicator stays visible) Time Format = 時間格式 Transparent UI background = 透明 UI 背景 UI = UI @@ -1393,20 +1415,17 @@ Progress: %1% = 進度:%1% Screen representation = 螢幕呈現 [VR] +% of native FoV = % 於原生視野 6DoF movement = 六自由度移動 -Camera type = 相機類型 Distance to 2D menus and scenes = 2D 選單及場景距離 Distance to 3D scenes when VR disabled = VR 停用時的 3D 場景距離 -Experts only = 僅限專家 +Enable immersive mode = Enable immersive mode +Enable passthrough = Enable passthrough +Field of view scale = 視野縮放 Force 72Hz update = 強制 72Hz 更新 -Game camera rotation step per frame = 遊戲相機每影格旋轉步數 -Game camera uses rotation smoothing = 遊戲相機使用旋轉平滑 Heads-up display detection = 抬頭顯示器偵測 Heads-up display scale = 抬頭顯示器縮放 Manual switching between flat screen and VR using SCREEN key = 使用「螢幕」按鍵在平面螢幕和 VR 間手動切換 -Map controller movements to keys = 將控制器移動對應至按鍵 -Map HMD rotations on keys instead of VR camera = 將 HMD 旋轉對應至按鍵而非 VR 相機 -Motion needed to generate action = 需要產生活動的運動 Stereoscopic vision (Experimental) = 立體視覺 (實驗性) Virtual reality = 虛擬實境 VR camera = VR 相機 diff --git a/assets/langregion.ini b/assets/langregion.ini index 6c9d8b1016..7e12509d2e 100644 --- a/assets/langregion.ini +++ b/assets/langregion.ini @@ -12,6 +12,7 @@ pt_PT = "Português" pt_BR = "Português Brasileiro" ru_RU = "Русский" ko_KR = "한국어" +ku_SO = "کوردی ناوەندی" zh_TW = "繁體中文" zh_CN = "简体中文" ar_AE = "العربية" diff --git a/b-appstore.sh b/b-appstore.sh new file mode 100755 index 0000000000..0cb1854f21 --- /dev/null +++ b/b-appstore.sh @@ -0,0 +1,48 @@ +# Build script for iOS app store + +echo "PPSSPP App Store XCode generator script" + +# Set the development team ID as a DEVTEAM env variable. + +if [[ -z "${DEVTEAM}" ]]; then + echo "DEVTEAM not in environment, exiting" + exit 1 +fi + +if [[ -z "${GOLD}" ]]; then + echo "GOLD is not set (should be YES or NO), exiting" + exit 1 +fi + +FOLDER_NAME="build-ios" + +if [[ "$GOLD" = "YES" ]]; then + echo "GOLD is set to YES, setting folder to build-ios-gold" + FOLDER_NAME="build-ios-gold" +else + echo "Non-GOLD build." +fi + +echo "Clearing and re-creating output directory" +rm -rf $FOLDER_NAME +mkdir $FOLDER_NAME + +pushd $FOLDER_NAME + +BUILD_TYPE=Release + +cmake .. -DIOS_APP_STORE=ON -DGOLD=$GOLD -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/ios.cmake -DDEVELOPMENT_TEAM_ID=${DEVTEAM} -DIOS_PLATFORM=OS -GXcode +# TODO: Get a MoltenVK somewhere. +#cp ../MoltenVK/iOS/Frameworks/libMoltenVK.dylib PPSSPP.app/Frameworks +popd + +# Very gross hack +# Avoid XCode race condition (???) by pre-generating git-version.cpp +cmake -DSOURCE_DIR=. -DOUTPUT_DIR=$FOLDER_NAME -P git-version.cmake + +echo +echo "*** Done. Now run the following command to open in XCode, then run or archive:" +echo " open $FOLDER_NAME/PPSSPP.xcodeproj" + +# To open the xcode project: +# open build-ios/PPSSPP.xcodeproj \ No newline at end of file diff --git a/b.sh b/b.sh index 7ec3499d91..938a66f85f 100755 --- a/b.sh +++ b/b.sh @@ -72,9 +72,18 @@ do --sanitize) echo "Enabling address-sanitizer if available" CMAKE_ARGS="-DUSE_ASAN=ON ${CMAKE_ARGS}" ;; + --sanitizeub) echo "Enabling ub-sanitizer if available" + CMAKE_ARGS="-DUSE_UBSAN=ON ${CMAKE_ARGS}" + ;; --gold) echo "Gold build enabled" CMAKE_ARGS="-DGOLD=ON ${CMAKE_ARGS}" ;; + --alderlake) echo "Alderlake opt" + CMAKE_ARGS="-DCMAKE_C_FLAGS=\"-march=alderlake\" -DCMAKE_CPP_FLAGS=\"-march=alderlake\"" + ;; + --no_mmap) echo "Disable mmap" + CMAKE_ARGS="-DUSE_NO_MMAP=ON ${CMAKE_ARGS}" + ;; *) MAKE_OPT="$1 ${MAKE_OPT}" ;; esac diff --git a/build.gradle b/build.gradle index e0b7d16f2c..81857b9297 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.3.1' + classpath 'com.android.tools.build:gradle:8.6.0' } } diff --git a/cmake/Toolchains/ios.cmake b/cmake/Toolchains/ios.cmake index 2e5dca4ca2..5ffad1d907 100644 --- a/cmake/Toolchains/ios.cmake +++ b/cmake/Toolchains/ios.cmake @@ -12,7 +12,7 @@ # PPSSPP platform flags set(MOBILE_DEVICE ON) set(USING_GLES2 ON) -set(IPHONEOS_DEPLOYMENT_TARGET 11.0) +set(IPHONEOS_DEPLOYMENT_TARGET 12.0) add_definitions( -DGL_ETC1_RGB8_OES=0 -U__STRICT_ANSI__ diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index fe6b714516..b0aa7adb2b 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -28,6 +28,8 @@ set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "" FORCE) set(ENABLE_GLSLANG_INSTALL OFF) add_subdirectory(glslang EXCLUDE_FROM_ALL) add_subdirectory(snappy) +add_subdirectory(minimp3) +add_subdirectory(at3_standalone) add_subdirectory(udis86) add_subdirectory(SPIRV-Cross-build) add_subdirectory(rcheevos-build) diff --git a/ext/OpenXR-SDK b/ext/OpenXR-SDK index 288d3a7ebc..be392bf694 160000 --- a/ext/OpenXR-SDK +++ b/ext/OpenXR-SDK @@ -1 +1 @@ -Subproject commit 288d3a7ebc1ad959f62d51da75baa3d27438c499 +Subproject commit be392bf6949adeeabad5082aa79d12aacbda781f diff --git a/ext/at3_standalone/CMakeLists.txt b/ext/at3_standalone/CMakeLists.txt new file mode 100644 index 0000000000..ced9df1024 --- /dev/null +++ b/ext/at3_standalone/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required (VERSION 3.16) +project (at3_standalone) + +set(SRC_DIR .) + +# format +set(ALL_SOURCE_FILES + # rapi + ${SRC_DIR}/atrac.cpp + ${SRC_DIR}/atrac3.cpp + ${SRC_DIR}/atrac3plus.cpp + ${SRC_DIR}/atrac3plusdec.cpp + ${SRC_DIR}/atrac3plusdsp.cpp + ${SRC_DIR}/get_bits.cpp + ${SRC_DIR}/compat.cpp + ${SRC_DIR}/fft.cpp + ${SRC_DIR}/mem.cpp + ) + +add_library(at3_standalone STATIC ${ALL_SOURCE_FILES}) diff --git a/ext/at3_standalone/README.txt b/ext/at3_standalone/README.txt new file mode 100644 index 0000000000..640a77f8eb --- /dev/null +++ b/ext/at3_standalone/README.txt @@ -0,0 +1 @@ +This is the atrac3/atrac3+ decoders from ffmpeg, extracted to be standalone from ffmpeg. \ No newline at end of file diff --git a/ext/at3_standalone/aac_defines.h b/ext/at3_standalone/aac_defines.h new file mode 100644 index 0000000000..d9aa087fc3 --- /dev/null +++ b/ext/at3_standalone/aac_defines.h @@ -0,0 +1,112 @@ +/* + * AAC defines + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AAC_DEFINES_H +#define AVCODEC_AAC_DEFINES_H + +#ifndef USE_FIXED +#define USE_FIXED 0 +#endif + +#if USE_FIXED + +#include "libavutil/softfloat.h" + +#define FFT_FLOAT 0 +#define FFT_FIXED_32 1 + +#define AAC_RENAME(x) x ## _fixed +#define AAC_RENAME_32(x) x ## _fixed_32 +typedef int INTFLOAT; +typedef int64_t INT64FLOAT; +typedef int16_t SHORTFLOAT; +typedef SoftFloat AAC_FLOAT; +typedef int AAC_SIGNE; +#define FIXR(a) ((int)((a) * 1 + 0.5)) +#define FIXR10(a) ((int)((a) * 1024.0 + 0.5)) +#define Q23(a) (int)((a) * 8388608.0 + 0.5) +#define Q30(x) (int)((x)*1073741824.0 + 0.5) +#define Q31(x) (int)((x)*2147483648.0 + 0.5) +#define RANGE15(x) x +#define GET_GAIN(x, y) (-(y) << (x)) + 1024 +#define AAC_MUL16(x, y) (int)(((int64_t)(x) * (y) + 0x8000) >> 16) +#define AAC_MUL26(x, y) (int)(((int64_t)(x) * (y) + 0x2000000) >> 26) +#define AAC_MUL30(x, y) (int)(((int64_t)(x) * (y) + 0x20000000) >> 30) +#define AAC_MUL31(x, y) (int)(((int64_t)(x) * (y) + 0x40000000) >> 31) +#define AAC_MADD28(x, y, a, b) (int)((((int64_t)(x) * (y)) + \ + ((int64_t)(a) * (b)) + \ + 0x8000000) >> 28) +#define AAC_MADD30(x, y, a, b) (int)((((int64_t)(x) * (y)) + \ + ((int64_t)(a) * (b)) + \ + 0x20000000) >> 30) +#define AAC_MADD30_V8(x, y, a, b, c, d, e, f) (int)((((int64_t)(x) * (y)) + \ + ((int64_t)(a) * (b)) + \ + ((int64_t)(c) * (d)) + \ + ((int64_t)(e) * (f)) + \ + 0x20000000) >> 30) +#define AAC_MSUB30(x, y, a, b) (int)((((int64_t)(x) * (y)) - \ + ((int64_t)(a) * (b)) + \ + 0x20000000) >> 30) +#define AAC_MSUB30_V8(x, y, a, b, c, d, e, f) (int)((((int64_t)(x) * (y)) + \ + ((int64_t)(a) * (b)) - \ + ((int64_t)(c) * (d)) - \ + ((int64_t)(e) * (f)) + \ + 0x20000000) >> 30) +#define AAC_MSUB31_V3(x, y, z) (int)((((int64_t)(x) * (z)) - \ + ((int64_t)(y) * (z)) + \ + 0x40000000) >> 31) +#define AAC_HALF_SUM(x, y) (x) >> 1 + (y) >> 1 +#define AAC_SRA_R(x, y) (int)(((x) + (1 << ((y) - 1))) >> (y)) + +#else + +#define FFT_FLOAT 1 +#define FFT_FIXED_32 0 + +typedef float INTFLOAT; +typedef float INT64FLOAT; +typedef float SHORTFLOAT; +typedef float AAC_FLOAT; +typedef unsigned AAC_SIGNE; +#define FIXR(x) ((float)(x)) +#define FIXR10(x) ((float)(x)) +#define Q23(x) x +#define Q30(x) x +#define Q31(x) x +#define RANGE15(x) (32768.0 * (x)) +#define GET_GAIN(x, y) powf((x), -(y)) +#define AAC_MUL16(x, y) ((x) * (y)) +#define AAC_MUL26(x, y) ((x) * (y)) +#define AAC_MUL30(x, y) ((x) * (y)) +#define AAC_MUL31(x, y) ((x) * (y)) +#define AAC_MADD28(x, y, a, b) ((x) * (y) + (a) * (b)) +#define AAC_MADD30(x, y, a, b) ((x) * (y) + (a) * (b)) +#define AAC_MADD30_V8(x, y, a, b, c, d, e, f) ((x) * (y) + (a) * (b) + \ + (c) * (d) + (e) * (f)) +#define AAC_MSUB30(x, y, a, b) ((x) * (y) - (a) * (b)) +#define AAC_MSUB30_V8(x, y, a, b, c, d, e, f) ((x) * (y) + (a) * (b) - \ + (c) * (d) - (e) * (f)) +#define AAC_MSUB31_V3(x, y, z) ((x) - (y)) * (z) +#define AAC_HALF_SUM(x, y) ((x) + (y)) * 0.5f +#define AAC_SRA_R(x, y) (x) + +#endif /* USE_FIXED */ + +#endif /* AVCODEC_AAC_DEFINES_H */ diff --git a/ext/at3_standalone/at3_decoders.h b/ext/at3_standalone/at3_decoders.h new file mode 100644 index 0000000000..019ebe306d --- /dev/null +++ b/ext/at3_standalone/at3_decoders.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +// Notes +// +// Performance-wise, these are OK. +// For Atrac3+, the bottleneck is two functions: decode_qu_spectra and ff_atrac3p_ipqf. At least the latter is quite SIMD-able. + +// The full external API for the standalone Atrac3/3+ decoder. + +struct ATRAC3Context; +struct ATRAC3PContext; + +// If the block_align passed in is 0, tries to audio detect. +// flush_buffers should be called when seeking before the next decode_frame. + +ATRAC3Context *atrac3_alloc(int channels, int *block_align, const uint8_t *extra_data, int extra_data_size); +void atrac3_free(ATRAC3Context *ctx); +void atrac3_flush_buffers(ATRAC3Context *ctx); +int atrac3_decode_frame(ATRAC3Context *ctx, float *out_data[2], int *nb_samples, const uint8_t *buf, int buf_size); + +ATRAC3PContext *atrac3p_alloc(int channels, int *block_align); +void atrac3p_free(ATRAC3PContext *ctx); +void atrac3p_flush_buffers(ATRAC3PContext *ctx); +int atrac3p_decode_frame(ATRAC3PContext *ctx, float *out_data[2], int *nb_samples, const uint8_t *buf, int buf_size); diff --git a/ext/at3_standalone/atrac.cpp b/ext/at3_standalone/atrac.cpp new file mode 100644 index 0000000000..7fce83e40c --- /dev/null +++ b/ext/at3_standalone/atrac.cpp @@ -0,0 +1,164 @@ +/* + * common functions for the ATRAC family of decoders + * + * Copyright (c) 2006-2013 Maxim Poliakovski + * Copyright (c) 2006-2008 Benjamin Larsson + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + */ + +#include +#include +#include +#include + +#include "atrac.h" + +float av_atrac_sf_table[64]; +static float qmf_window[48]; + +static const float qmf_48tap_half[24] = { + -0.00001461907, -0.00009205479,-0.000056157569,0.00030117269, + 0.0002422519, -0.00085293897,-0.0005205574, 0.0020340169, + 0.00078333891, -0.0042153862, -0.00075614988, 0.0078402944, + -0.000061169922,-0.01344162, 0.0024626821, 0.021736089, + -0.007801671, -0.034090221, 0.01880949, 0.054326009, + -0.043596379, -0.099384367, 0.13207909, 0.46424159 +}; + +void ff_atrac_generate_tables(void) +{ + int i; + float s; + + /* Generate scale factors */ + if (!av_atrac_sf_table[63]) + for (i=0 ; i<64 ; i++) + av_atrac_sf_table[i] = pow(2.0, (i - 15) / 3.0); + + /* Generate the QMF window. */ + if (!qmf_window[47]) + for (i=0 ; i<24; i++) { + s = qmf_48tap_half[i] * 2.0; + qmf_window[i] = qmf_window[47 - i] = s; + } +} + +void ff_atrac_init_gain_compensation(AtracGCContext *gctx, int id2exp_offset, + int loc_scale) +{ + int i; + + gctx->loc_scale = loc_scale; + gctx->loc_size = 1 << loc_scale; + gctx->id2exp_offset = id2exp_offset; + + /* Generate gain level table. */ + for (i = 0; i < 16; i++) + gctx->gain_tab1[i] = powf(2.0, id2exp_offset - i); + + /* Generate gain interpolation table. */ + for (i = -15; i < 16; i++) + gctx->gain_tab2[i + 15] = powf(2.0, -1.0f / gctx->loc_size * i); +} + +void ff_atrac_gain_compensation(AtracGCContext *gctx, float *in, float *prev, + AtracGainInfo *gc_now, AtracGainInfo *gc_next, + int num_samples, float *out) +{ + float lev, gc_scale, gain_inc; + int i, pos, lastpos; + + gc_scale = gc_next->num_points ? gctx->gain_tab1[gc_next->lev_code[0]] + : 1.0f; + + if (!gc_now->num_points) { + for (pos = 0; pos < num_samples; pos++) + out[pos] = in[pos] * gc_scale + prev[pos]; + } else { + pos = 0; + + for (i = 0; i < gc_now->num_points; i++) { + lastpos = gc_now->loc_code[i] << gctx->loc_scale; + + lev = gctx->gain_tab1[gc_now->lev_code[i]]; + gain_inc = gctx->gain_tab2[(i + 1 < gc_now->num_points ? gc_now->lev_code[i + 1] + : gctx->id2exp_offset) - + gc_now->lev_code[i] + 15]; + + /* apply constant gain level and overlap */ + for (; pos < lastpos; pos++) + out[pos] = (in[pos] * gc_scale + prev[pos]) * lev; + + /* interpolate between two different gain levels */ + for (; pos < lastpos + gctx->loc_size; pos++) { + out[pos] = (in[pos] * gc_scale + prev[pos]) * lev; + lev *= gain_inc; + } + } + + for (; pos < num_samples; pos++) + out[pos] = in[pos] * gc_scale + prev[pos]; + } + + /* copy the overlapping part into the delay buffer */ + memcpy(prev, &in[num_samples], num_samples * sizeof(float)); +} + +void ff_atrac_iqmf(float *inlo, float *inhi, unsigned int nIn, float *pOut, + float *delayBuf, float *temp) +{ + int i, j; + float *p1, *p3; + + memcpy(temp, delayBuf, 46*sizeof(float)); + + p3 = temp + 46; + + /* loop1 */ + for(i=0; i<(int)nIn; i+=2){ + p3[2*i+0] = inlo[i ] + inhi[i ]; + p3[2*i+1] = inlo[i ] - inhi[i ]; + p3[2*i+2] = inlo[i+1] + inhi[i+1]; + p3[2*i+3] = inlo[i+1] - inhi[i+1]; + } + + /* loop2 */ + p1 = temp; + for (j = (int)nIn; j != 0; j--) { + float s1 = 0.0; + float s2 = 0.0; + + for (i = 0; i < 48; i += 2) { + s1 += p1[i] * qmf_window[i]; + s2 += p1[i+1] * qmf_window[i+1]; + } + + pOut[0] = s2; + pOut[1] = s1; + + p1 += 2; + pOut += 2; + } + + /* Update the delay buffer. */ + memcpy(delayBuf, temp + nIn*2, 46*sizeof(float)); +} diff --git a/ext/at3_standalone/atrac.h b/ext/at3_standalone/atrac.h new file mode 100644 index 0000000000..3a68c8e092 --- /dev/null +++ b/ext/at3_standalone/atrac.h @@ -0,0 +1,99 @@ +/* + * common functions for the ATRAC family of decoders + * + * Copyright (c) 2009-2013 Maxim Poliakovski + * Copyright (c) 2009 Benjamin Larsson + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * ATRAC common header + */ + +#include "compat.h" + +#ifndef AVCODEC_ATRAC_H +#define AVCODEC_ATRAC_H + +/** + * Gain control parameters for one subband. + */ +typedef struct AtracGainInfo { + int num_points; ///< number of gain control points + int lev_code[7]; ///< level at corresponding control point + int loc_code[7]; ///< location of gain control points +} AtracGainInfo; + +/** + * Gain compensation context structure. + */ +typedef struct AtracGCContext { + float gain_tab1[16]; ///< gain compensation level table + float gain_tab2[31]; ///< gain compensation interpolation table + int id2exp_offset; ///< offset for converting level index into level exponent + int loc_scale; ///< scale of location code = 2^loc_scale samples + int loc_size; ///< size of location code in samples +} AtracGCContext; + +extern float av_atrac_sf_table[64]; + +/** + * Generate common tables. + */ +void ff_atrac_generate_tables(void); + +/** + * Initialize gain compensation context. + * + * @param gctx pointer to gain compensation context to initialize + * @param id2exp_offset offset for converting level index into level exponent + * @param loc_scale location size factor + */ +void ff_atrac_init_gain_compensation(AtracGCContext *gctx, int id2exp_offset, + int loc_scale); + +/** + * Apply gain compensation and perform the MDCT overlapping part. + * + * @param gctx pointer to gain compensation context + * @param in input buffer + * @param prev previous buffer to perform overlap against + * @param gc_now gain control information for current frame + * @param gc_next gain control information for next frame + * @param num_samples number of samples to process + * @param out output data goes here + */ +void ff_atrac_gain_compensation(AtracGCContext *gctx, float *in, float *prev, + AtracGainInfo *gc_now, AtracGainInfo *gc_next, + int num_samples, float *out); + +/** + * Quadrature mirror synthesis filter. + * + * @param inlo lower part of spectrum + * @param inhi higher part of spectrum + * @param nIn size of spectrum buffer + * @param pOut out buffer + * @param delayBuf delayBuf buffer + * @param temp temp buffer + */ +void ff_atrac_iqmf(float *inlo, float *inhi, unsigned int nIn, float *pOut, + float *delayBuf, float *temp); + +#endif /* AVCODEC_ATRAC_H */ diff --git a/ext/at3_standalone/atrac3.cpp b/ext/at3_standalone/atrac3.cpp new file mode 100644 index 0000000000..6c1afcb166 --- /dev/null +++ b/ext/at3_standalone/atrac3.cpp @@ -0,0 +1,927 @@ +/* + * ATRAC3 compatible decoder + * Copyright (c) 2006-2008 Maxim Poliakovski + * Copyright (c) 2006-2008 Benjamin Larsson + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * ATRAC3 compatible decoder. + * This decoder handles Sony's ATRAC3 data. + * + * Container formats used to store ATRAC3 data: + * RealMedia (.rm), RIFF WAV (.wav, .at3), Sony OpenMG (.oma, .aa3). + * + * To use this decoder, a calling application must supply the extradata + * bytes provided in the containers above. + */ +#define _USE_MATH_DEFINES + +#include +#include +#include +#include + +#include "float_dsp.h" +#include "fft.h" +#include "mem.h" +#include "compat.h" +#include "get_bits.h" + +#include "atrac.h" +#include "atrac3data.h" + +#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) + +#define JOINT_STEREO 0x12 +#define STEREO 0x2 + +#define SAMPLES_PER_FRAME 1024 +#define MDCT_SIZE 512 + +typedef struct GainBlock { + AtracGainInfo g_block[4]; +} GainBlock; + +typedef struct TonalComponent { + int pos; + int num_coefs; + float coef[8]; +} TonalComponent; + +typedef struct ChannelUnit { + int bands_coded; + int num_components; + float prev_frame[SAMPLES_PER_FRAME]; + int gc_blk_switch; + TonalComponent components[64]; + GainBlock gain_block[2]; + + DECLARE_ALIGNED(32, float, spectrum)[SAMPLES_PER_FRAME]; + DECLARE_ALIGNED(32, float, imdct_buf)[SAMPLES_PER_FRAME]; + + float delay_buf1[46]; ///mdct_ctx, output, input); + + /* Perform windowing on the output. */ + vector_fmul(output, mdct_window, MDCT_SIZE); +} + +/* + * indata descrambling, only used for data coming from the rm container + */ +static int decode_bytes(const uint8_t *input, uint8_t *out, int bytes) +{ + int i, off; + uint32_t c; + const uint32_t *buf; + uint32_t *output = (uint32_t *)out; + + off = (intptr_t)input & 3; + buf = (const uint32_t *)(input - off); + if (off) + c = av_be2ne32((0x537F6103U >> (off * 8)) | (0x537F6103U << (32 - (off * 8)))); + else + c = av_be2ne32(0x537F6103U); + bytes += 3 + off; + for (i = 0; i < bytes / 4; i++) + output[i] = c ^ buf[i]; + + //if (off) + // avpriv_request_sample(NULL, "Offset of %d", off); + + return off; +} + +static void init_imdct_window(void) +{ + int i, j; + + /* generate the mdct window, for details see + * http://wiki.multimedia.cx/index.php?title=RealAudio_atrc#Windows */ + for (i = 0, j = 255; i < 128; i++, j--) { + float wi = sin(((i + 0.5) / 256.0 - 0.5) * M_PI) + 1.0; + float wj = sin(((j + 0.5) / 256.0 - 0.5) * M_PI) + 1.0; + float w = 0.5 * (wi * wi + wj * wj); + mdct_window[i] = mdct_window[511 - i] = wi / w; + mdct_window[j] = mdct_window[511 - j] = wj / w; + } +} + +void atrac3_free(ATRAC3Context *ctx) +{ + av_freep(&ctx->units); + av_freep(&ctx->decoded_bytes_buffer); + + ff_mdct_end(&ctx->mdct_ctx); + av_freep(&ctx); +} + +/** + * Mantissa decoding + * + * @param selector which table the output values are coded with + * @param coding_flag constant length coding or variable length coding + * @param mantissas mantissa output table + * @param num_codes number of values to get + */ +static void read_quant_spectral_coeffs(GetBitContext *gb, int selector, + int coding_flag, int *mantissas, + int num_codes) +{ + int i, code, huff_symb; + + if (selector == 1) + num_codes /= 2; + + if (coding_flag != 0) { + /* constant length coding (CLC) */ + int num_bits = clc_length_tab[selector]; + + if (selector > 1) { + for (i = 0; i < num_codes; i++) { + if (num_bits) + code = get_sbits(gb, num_bits); + else + code = 0; + mantissas[i] = code; + } + } else { + for (i = 0; i < num_codes; i++) { + if (num_bits) + code = get_bits(gb, num_bits); // num_bits is always 4 in this case + else + code = 0; + mantissas[i * 2 ] = mantissa_clc_tab[code >> 2]; + mantissas[i * 2 + 1] = mantissa_clc_tab[code & 3]; + } + } + } else { + /* variable length coding (VLC) */ + if (selector != 1) { + for (i = 0; i < num_codes; i++) { + huff_symb = get_vlc2(gb, spectral_coeff_tab[selector-1].table, + spectral_coeff_tab[selector-1].bits, 3); + huff_symb += 1; + code = huff_symb >> 1; + if (huff_symb & 1) + code = -code; + mantissas[i] = code; + } + } else { + for (i = 0; i < num_codes; i++) { + huff_symb = get_vlc2(gb, spectral_coeff_tab[selector - 1].table, + spectral_coeff_tab[selector - 1].bits, 3); + mantissas[i * 2 ] = mantissa_vlc_tab[huff_symb * 2 ]; + mantissas[i * 2 + 1] = mantissa_vlc_tab[huff_symb * 2 + 1]; + } + } + } +} + +/** + * Restore the quantized band spectrum coefficients + * + * @return subband count, fix for broken specification/files + */ +static int decode_spectrum(GetBitContext *gb, float *output) +{ + int num_subbands, coding_mode, i, j, first, last, subband_size; + int subband_vlc_index[32], sf_index[32]; + int mantissas[128]; + float scale_factor; + + num_subbands = get_bits(gb, 5); // number of coded subbands + coding_mode = get_bits1(gb); // coding Mode: 0 - VLC/ 1-CLC + + /* get the VLC selector table for the subbands, 0 means not coded */ + for (i = 0; i <= num_subbands; i++) + subband_vlc_index[i] = get_bits(gb, 3); + + /* read the scale factor indexes from the stream */ + for (i = 0; i <= num_subbands; i++) { + if (subband_vlc_index[i] != 0) + sf_index[i] = get_bits(gb, 6); + } + + for (i = 0; i <= num_subbands; i++) { + first = subband_tab[i ]; + last = subband_tab[i + 1]; + + subband_size = last - first; + + if (subband_vlc_index[i] != 0) { + /* decode spectral coefficients for this subband */ + /* TODO: This can be done faster is several blocks share the + * same VLC selector (subband_vlc_index) */ + read_quant_spectral_coeffs(gb, subband_vlc_index[i], coding_mode, + mantissas, subband_size); + + /* decode the scale factor for this subband */ + scale_factor = av_atrac_sf_table[sf_index[i]] * + inv_max_quant[subband_vlc_index[i]]; + + /* inverse quantize the coefficients */ + for (j = 0; first < last; first++, j++) + output[first] = mantissas[j] * scale_factor; + } else { + /* this subband was not coded, so zero the entire subband */ + memset(output + first, 0, subband_size * sizeof(*output)); + } + } + + /* clear the subbands that were not coded */ + first = subband_tab[i]; + memset(output + first, 0, (SAMPLES_PER_FRAME - first) * sizeof(*output)); + return num_subbands; +} + +/** + * Restore the quantized tonal components + * + * @param components tonal components + * @param num_bands number of coded bands + */ +static int decode_tonal_components(GetBitContext *gb, + TonalComponent *components, int num_bands) +{ + int i, b, c, m; + int nb_components, coding_mode_selector, coding_mode; + int band_flags[4], mantissa[8]; + int component_count = 0; + + nb_components = get_bits(gb, 5); + + /* no tonal components */ + if (nb_components == 0) + return 0; + + coding_mode_selector = get_bits(gb, 2); + if (coding_mode_selector == 2) + return AVERROR_INVALIDDATA; + + coding_mode = coding_mode_selector & 1; + + for (i = 0; i < nb_components; i++) { + int coded_values_per_component, quant_step_index; + + for (b = 0; b <= num_bands; b++) + band_flags[b] = get_bits1(gb); + + coded_values_per_component = get_bits(gb, 3); + + quant_step_index = get_bits(gb, 3); + if (quant_step_index <= 1) + return AVERROR_INVALIDDATA; + + if (coding_mode_selector == 3) + coding_mode = get_bits1(gb); + + for (b = 0; b < (num_bands + 1) * 4; b++) { + int coded_components; + + if (band_flags[b >> 2] == 0) + continue; + + coded_components = get_bits(gb, 3); + + for (c = 0; c < coded_components; c++) { + TonalComponent *cmp = &components[component_count]; + int sf_index, coded_values, max_coded_values; + float scale_factor; + + sf_index = get_bits(gb, 6); + if (component_count >= 64) + return AVERROR_INVALIDDATA; + + cmp->pos = b * 64 + get_bits(gb, 6); + + max_coded_values = SAMPLES_PER_FRAME - cmp->pos; + coded_values = coded_values_per_component + 1; + coded_values = FFMIN(max_coded_values, coded_values); + + scale_factor = av_atrac_sf_table[sf_index] * + inv_max_quant[quant_step_index]; + + read_quant_spectral_coeffs(gb, quant_step_index, coding_mode, + mantissa, coded_values); + + cmp->num_coefs = coded_values; + + /* inverse quant */ + for (m = 0; m < coded_values; m++) + cmp->coef[m] = mantissa[m] * scale_factor; + + component_count++; + } + } + } + + return component_count; +} + +/** + * Decode gain parameters for the coded bands + * + * @param block the gainblock for the current band + * @param num_bands amount of coded bands + */ +static int decode_gain_control(GetBitContext *gb, GainBlock *block, + int num_bands) +{ + int b, j; + int *level, *loc; + + AtracGainInfo *gain = block->g_block; + + for (b = 0; b <= num_bands; b++) { + gain[b].num_points = get_bits(gb, 3); + level = gain[b].lev_code; + loc = gain[b].loc_code; + + for (j = 0; j < gain[b].num_points; j++) { + level[j] = get_bits(gb, 4); + loc[j] = get_bits(gb, 5); + if (j && loc[j] <= loc[j - 1]) + return AVERROR_INVALIDDATA; + } + } + + /* Clear the unused blocks. */ + for (; b < 4 ; b++) + gain[b].num_points = 0; + + return 0; +} + +/** + * Combine the tonal band spectrum and regular band spectrum + * + * @param spectrum output spectrum buffer + * @param num_components number of tonal components + * @param components tonal components for this band + * @return position of the last tonal coefficient + */ +static int add_tonal_components(float *spectrum, int num_components, + TonalComponent *components) +{ + int i, j, last_pos = -1; + float *input, *output; + + for (i = 0; i < num_components; i++) { + last_pos = FFMAX(components[i].pos + components[i].num_coefs, last_pos); + input = components[i].coef; + output = &spectrum[components[i].pos]; + + for (j = 0; j < components[i].num_coefs; j++) + output[j] += input[j]; + } + + return last_pos; +} + +#define INTERPOLATE(old, new, nsample) \ + ((old) + (nsample) * 0.125 * ((new) - (old))) + +static void reverse_matrixing(float *su1, float *su2, int *prev_code, + int *curr_code) +{ + int i, nsample, band; + float mc1_l, mc1_r, mc2_l, mc2_r; + + for (i = 0, band = 0; band < 4 * 256; band += 256, i++) { + int s1 = prev_code[i]; + int s2 = curr_code[i]; + nsample = band; + + if (s1 != s2) { + /* Selector value changed, interpolation needed. */ + mc1_l = matrix_coeffs[s1 * 2 ]; + mc1_r = matrix_coeffs[s1 * 2 + 1]; + mc2_l = matrix_coeffs[s2 * 2 ]; + mc2_r = matrix_coeffs[s2 * 2 + 1]; + + /* Interpolation is done over the first eight samples. */ + for (; nsample < band + 8; nsample++) { + float c1 = su1[nsample]; + float c2 = su2[nsample]; + c2 = c1 * INTERPOLATE(mc1_l, mc2_l, nsample - band) + + c2 * INTERPOLATE(mc1_r, mc2_r, nsample - band); + su1[nsample] = c2; + su2[nsample] = c1 * 2.0 - c2; + } + } + + /* Apply the matrix without interpolation. */ + switch (s2) { + case 0: /* M/S decoding */ + for (; nsample < band + 256; nsample++) { + float c1 = su1[nsample]; + float c2 = su2[nsample]; + su1[nsample] = c2 * 2.0; + su2[nsample] = (c1 - c2) * 2.0; + } + break; + case 1: + for (; nsample < band + 256; nsample++) { + float c1 = su1[nsample]; + float c2 = su2[nsample]; + su1[nsample] = (c1 + c2) * 2.0; + su2[nsample] = c2 * -2.0; + } + break; + case 2: + case 3: + for (; nsample < band + 256; nsample++) { + float c1 = su1[nsample]; + float c2 = su2[nsample]; + su1[nsample] = c1 + c2; + su2[nsample] = c1 - c2; + } + break; + default: + av_assert1(0); + } + } +} + +static void get_channel_weights(int index, int flag, float ch[2]) +{ + if (index == 7) { + ch[0] = 1.0; + ch[1] = 1.0; + } else { + ch[0] = (index & 7) / 7.0; + ch[1] = sqrt(2 - ch[0] * ch[0]); + if (flag) + FFSWAP(float, ch[0], ch[1]); + } +} + +static void channel_weighting(float *su1, float *su2, int *p3) +{ + int band, nsample; + /* w[x][y] y=0 is left y=1 is right */ + float w[2][2]; + + if (p3[1] != 7 || p3[3] != 7) { + get_channel_weights(p3[1], p3[0], w[0]); + get_channel_weights(p3[3], p3[2], w[1]); + + for (band = 256; band < 4 * 256; band += 256) { + for (nsample = band; nsample < band + 8; nsample++) { + su1[nsample] *= INTERPOLATE(w[0][0], w[0][1], nsample - band); + su2[nsample] *= INTERPOLATE(w[1][0], w[1][1], nsample - band); + } + for(; nsample < band + 256; nsample++) { + su1[nsample] *= w[1][0]; + su2[nsample] *= w[1][1]; + } + } + } +} + +/** + * Decode a Sound Unit + * + * @param snd the channel unit to be used + * @param output the decoded samples before IQMF in float representation + * @param channel_num channel number + * @param coding_mode the coding mode (JOINT_STEREO or regular stereo/mono) + */ +static int decode_channel_sound_unit(ATRAC3Context *q, GetBitContext *gb, + ChannelUnit *snd, float *output, + int channel_num, int coding_mode) +{ + int band, ret, num_subbands, last_tonal, num_bands; + GainBlock *gain1 = &snd->gain_block[ snd->gc_blk_switch]; + GainBlock *gain2 = &snd->gain_block[1 - snd->gc_blk_switch]; + + if (coding_mode == JOINT_STEREO && channel_num == 1) { + if (get_bits(gb, 2) != 3) { + av_log(AV_LOG_ERROR,"JS mono Sound Unit id != 3."); + return AVERROR_INVALIDDATA; + } + } else { + if (get_bits(gb, 6) != 0x28) { + av_log(AV_LOG_ERROR,"Sound Unit id != 0x28."); + return AVERROR_INVALIDDATA; + } + } + + /* number of coded QMF bands */ + snd->bands_coded = get_bits(gb, 2); + + ret = decode_gain_control(gb, gain2, snd->bands_coded); + if (ret) + return ret; + + snd->num_components = decode_tonal_components(gb, snd->components, + snd->bands_coded); + if (snd->num_components < 0) + return snd->num_components; + + num_subbands = decode_spectrum(gb, snd->spectrum); + + /* Merge the decoded spectrum and tonal components. */ + last_tonal = add_tonal_components(snd->spectrum, snd->num_components, + snd->components); + + + /* calculate number of used MLT/QMF bands according to the amount of coded + spectral lines */ + num_bands = (subband_tab[num_subbands] - 1) >> 8; + if (last_tonal >= 0) + num_bands = FFMAX((last_tonal + 256) >> 8, num_bands); + + + /* Reconstruct time domain samples. */ + for (band = 0; band < 4; band++) { + /* Perform the IMDCT step without overlapping. */ + if (band <= num_bands) + imlt(q, &snd->spectrum[band * 256], snd->imdct_buf, band & 1); + else + memset(snd->imdct_buf, 0, 512 * sizeof(*snd->imdct_buf)); + + /* gain compensation and overlapping */ + ff_atrac_gain_compensation(&q->gainc_ctx, snd->imdct_buf, + &snd->prev_frame[band * 256], + &gain1->g_block[band], &gain2->g_block[band], + 256, &output[band * 256]); + } + + /* Swap the gain control buffers for the next frame. */ + snd->gc_blk_switch ^= 1; + + return 0; +} + +static int decode_frame(ATRAC3Context *q, int block_align, int channels, const uint8_t *databuf, + float **out_samples) +{ + int ret, i; + uint8_t *ptr1; + + if (q->coding_mode == JOINT_STEREO) { + /* channel coupling mode */ + /* decode Sound Unit 1 */ + init_get_bits(&q->gb, databuf, block_align * 8); + + ret = decode_channel_sound_unit(q, &q->gb, q->units, out_samples[0], 0, + JOINT_STEREO); + if (ret != 0) + return ret; + + /* Framedata of the su2 in the joint-stereo mode is encoded in + * reverse byte order so we need to swap it first. */ + if (databuf == q->decoded_bytes_buffer) { + uint8_t *ptr2 = q->decoded_bytes_buffer + block_align - 1; + ptr1 = q->decoded_bytes_buffer; + for (i = 0; i < block_align / 2; i++, ptr1++, ptr2--) + FFSWAP(uint8_t, *ptr1, *ptr2); + } else { + const uint8_t *ptr2 = databuf + block_align - 1; + for (i = 0; i < block_align; i++) + q->decoded_bytes_buffer[i] = *ptr2--; + } + + /* Skip the sync codes (0xF8). */ + ptr1 = q->decoded_bytes_buffer; + for (i = 4; *ptr1 == 0xF8; i++, ptr1++) { + if (i >= block_align) + return AVERROR_INVALIDDATA; + } + + + /* set the bitstream reader at the start of the second Sound Unit*/ + init_get_bits8(&q->gb, ptr1, q->decoded_bytes_buffer + block_align - ptr1); + + /* Fill the Weighting coeffs delay buffer */ + memmove(q->weighting_delay, &q->weighting_delay[2], + 4 * sizeof(*q->weighting_delay)); + q->weighting_delay[4] = get_bits1(&q->gb); + q->weighting_delay[5] = get_bits(&q->gb, 3); + + for (i = 0; i < 4; i++) { + q->matrix_coeff_index_prev[i] = q->matrix_coeff_index_now[i]; + q->matrix_coeff_index_now[i] = q->matrix_coeff_index_next[i]; + q->matrix_coeff_index_next[i] = get_bits(&q->gb, 2); + } + + /* Decode Sound Unit 2. */ + ret = decode_channel_sound_unit(q, &q->gb, &q->units[1], + out_samples[1], 1, JOINT_STEREO); + if (ret != 0) + return ret; + + /* Reconstruct the channel coefficients. */ + reverse_matrixing(out_samples[0], out_samples[1], + q->matrix_coeff_index_prev, + q->matrix_coeff_index_now); + + channel_weighting(out_samples[0], out_samples[1], q->weighting_delay); + } else { + /* normal stereo mode or mono */ + /* Decode the channel sound units. */ + for (i = 0; i < channels; i++) { + /* Set the bitstream reader at the start of a channel sound unit. */ + init_get_bits(&q->gb, + databuf + i * block_align / channels, + block_align * 8 / channels); + + ret = decode_channel_sound_unit(q, &q->gb, &q->units[i], + out_samples[i], i, q->coding_mode); + if (ret != 0) + return ret; + } + } + + /* Apply the iQMF synthesis filter. */ + for (i = 0; i < channels; i++) { + float *p1 = out_samples[i]; + float *p2 = p1 + 256; + float *p3 = p2 + 256; + float *p4 = p3 + 256; + ff_atrac_iqmf(p1, p2, 256, p1, q->units[i].delay_buf1, q->temp_buf); + ff_atrac_iqmf(p4, p3, 256, p3, q->units[i].delay_buf2, q->temp_buf); + ff_atrac_iqmf(p1, p3, 512, p1, q->units[i].delay_buf3, q->temp_buf); + } + + return 0; +} + +int atrac3_decode_frame(ATRAC3Context *ctx, float *out_data[2], int *nb_samples, const uint8_t *buf, int buf_size) +{ + int ret; + const uint8_t *databuf; + + const int block_align = ctx->block_align; + const int channels = ctx->channels; + + *nb_samples = 0; + + if (buf_size < block_align) { + av_log(AV_LOG_ERROR, + "Frame too small (%d bytes). Truncated file?", buf_size); + return AVERROR_INVALIDDATA; + } + + /* Check if we need to descramble and what buffer to pass on. */ + if (ctx->scrambled_stream) { + decode_bytes(buf, ctx->decoded_bytes_buffer, block_align); + databuf = ctx->decoded_bytes_buffer; + } else { + databuf = buf; + } + + ret = decode_frame(ctx, block_align, channels, databuf, out_data); + if (ret) { + av_log(AV_LOG_ERROR, "Frame decoding error!"); + return ret; + } + + *nb_samples = SAMPLES_PER_FRAME; + return block_align; +} + +void atrac3_flush_buffers(ATRAC3Context *c) { + // There's no known correct way to do this, so let's just reset some stuff. + memset(c->temp_buf, 0, sizeof(c->temp_buf)); +} + +static void atrac3_init_static_data(void) +{ + int i; + + init_imdct_window(); + ff_atrac_generate_tables(); + + /* Initialize the VLC tables. */ + for (i = 0; i < 7; i++) { + spectral_coeff_tab[i].table = &atrac3_vlc_table[atrac3_vlc_offs[i]]; + spectral_coeff_tab[i].table_allocated = atrac3_vlc_offs[i + 1] - + atrac3_vlc_offs[i ]; + init_vlc(&spectral_coeff_tab[i], 9, huff_tab_sizes[i], + huff_bits[i], 1, 1, + huff_codes[i], 1, 1, INIT_VLC_USE_NEW_STATIC); + } +} + +static int static_init_done; + +ATRAC3Context *atrac3_alloc(int channels, int *block_align, const uint8_t *extra_data, int extra_data_size) { + int i, ret; + int version, delay, samples_per_frame, frame_factor; + + const uint8_t *edata_ptr = extra_data; + + if (channels <= 0 || channels > 2) { + av_log(AV_LOG_ERROR, "Channel configuration error!"); + return nullptr; + } + + ATRAC3Context *q = (ATRAC3Context *)av_mallocz(sizeof(ATRAC3Context)); + q->channels = channels; + if (*block_align) { + q->block_align = *block_align; + } else { + // Atrac3 (unlike Atrac3+) requires a specified block align. + atrac3_free(q); + return nullptr; + } + + if (!static_init_done) + atrac3_init_static_data(); + static_init_done = 1; + + /* Take care of the codec-specific extradata. */ + if (extra_data_size == 14) { + /* Parse the extradata, WAV format */ + av_log(AV_LOG_DEBUG, "[0-1] %d", + bytestream_get_le16(&edata_ptr)); // Unknown value always 1 + edata_ptr += 4; // samples per channel + q->coding_mode = bytestream_get_le16(&edata_ptr); + av_log(AV_LOG_DEBUG,"[8-9] %d", + bytestream_get_le16(&edata_ptr)); //Dupe of coding mode + frame_factor = bytestream_get_le16(&edata_ptr); // Unknown always 1 + av_log(AV_LOG_DEBUG,"[12-13] %d", + bytestream_get_le16(&edata_ptr)); // Unknown always 0 + + /* setup */ + samples_per_frame = SAMPLES_PER_FRAME * channels; + version = 4; + delay = 0x88E; + q->coding_mode = q->coding_mode ? JOINT_STEREO : STEREO; + q->scrambled_stream = 0; + + if (q->block_align != 96 * channels * frame_factor && + q->block_align != 152 * channels * frame_factor && + q->block_align != 192 * channels * frame_factor) { + av_log(AV_LOG_ERROR, "Unknown frame/channel/frame_factor " + "configuration %d/%d/%d", block_align, + channels, frame_factor); + atrac3_free(q); + return nullptr; + } + } else if (extra_data_size == 12 || extra_data_size == 10) { + /* Parse the extradata, RM format. */ + version = bytestream_get_be32(&edata_ptr); + samples_per_frame = bytestream_get_be16(&edata_ptr); + delay = bytestream_get_be16(&edata_ptr); + q->coding_mode = bytestream_get_be16(&edata_ptr); + q->scrambled_stream = 1; + + } else { + av_log(AV_LOG_ERROR, "Unknown extradata size %d.", + extra_data_size); + atrac3_free(q); + return nullptr; + } + + /* Check the extradata */ + + if (version != 4) { + av_log(AV_LOG_ERROR, "Version %d != 4.", version); + atrac3_free(q); + return nullptr; + } + + if (samples_per_frame != SAMPLES_PER_FRAME && + samples_per_frame != SAMPLES_PER_FRAME * 2) { + av_log(AV_LOG_ERROR, "Unknown amount of samples per frame %d.", + samples_per_frame); + atrac3_free(q); + return nullptr; + } + + if (delay != 0x88E) { + av_log(AV_LOG_ERROR, "Unknown amount of delay %x != 0x88E.", + delay); + atrac3_free(q); + return nullptr; + } + + if (q->coding_mode == STEREO) + av_log(AV_LOG_DEBUG, "Normal stereo detected."); + else if (q->coding_mode == JOINT_STEREO) { + if (channels != 2) { + av_log(AV_LOG_ERROR, "Invalid coding mode"); + atrac3_free(q); + return nullptr; + } + av_log(AV_LOG_DEBUG, "Joint stereo detected."); + } else { + av_log(AV_LOG_ERROR, "Unknown channel coding mode %x!", + q->coding_mode); + atrac3_free(q); + return nullptr; + } + + q->decoded_bytes_buffer = (uint8_t *)av_mallocz(FFALIGN(q->block_align, 4) + AV_INPUT_BUFFER_PADDING_SIZE); + + /* initialize the MDCT transform */ + if ((ret = ff_mdct_init(&q->mdct_ctx, 9, 1, 1.0 / 32768)) < 0) { + av_log(AV_LOG_ERROR, "Error initializing MDCT"); + av_freep(&q->decoded_bytes_buffer); + + return nullptr; + } + + /* init the joint-stereo decoding data */ + q->weighting_delay[0] = 0; + q->weighting_delay[1] = 7; + q->weighting_delay[2] = 0; + q->weighting_delay[3] = 7; + q->weighting_delay[4] = 0; + q->weighting_delay[5] = 7; + + for (i = 0; i < 4; i++) { + q->matrix_coeff_index_prev[i] = 3; + q->matrix_coeff_index_now[i] = 3; + q->matrix_coeff_index_next[i] = 3; + } + + ff_atrac_init_gain_compensation(&q->gainc_ctx, 4, 3); + + q->units = (ChannelUnit *)av_mallocz_array(channels, sizeof(*q->units)); + return q; +} diff --git a/ext/at3_standalone/atrac3data.h b/ext/at3_standalone/atrac3data.h new file mode 100644 index 0000000000..5d91274f48 --- /dev/null +++ b/ext/at3_standalone/atrac3data.h @@ -0,0 +1,141 @@ +/* + * ATRAC3 compatible decoder data + * Copyright (c) 2006-2007 Maxim Poliakovski + * Copyright (c) 2006-2007 Benjamin Larsson + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * ATRAC3 AKA RealAudio 8 compatible decoder data + */ + +#ifndef AVCODEC_ATRAC3DATA_H +#define AVCODEC_ATRAC3DATA_H + +#include + +/* VLC tables */ + +static const uint8_t huffcode1[9] = { + 0x0, 0x4, 0x5, 0xC, 0xD, 0x1C, 0x1D, 0x1E, 0x1F +}; + +static const uint8_t huffbits1[9] = { 1, 3, 3, 4, 4, 5, 5, 5, 5 }; + +static const uint8_t huffcode2[5] = { 0x0, 0x4, 0x5, 0x6, 0x7 }; + +static const uint8_t huffbits2[5] = { 1, 3, 3, 3, 3 }; + +static const uint8_t huffcode3[7] = { 0x0, 0x4, 0x5, 0xC, 0xD, 0xE, 0xF }; + +static const uint8_t huffbits3[7] = { 1, 3, 3, 4, 4, 4, 4 }; + +static const uint8_t huffcode4[9] = { + 0x0, 0x4, 0x5, 0xC, 0xD, 0x1C, 0x1D, 0x1E, 0x1F +}; + +static const uint8_t huffbits4[9] = { 1, 3, 3, 4, 4, 5, 5, 5, 5 }; + +static const uint8_t huffcode5[15] = { + 0x00, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B, 0x1C, + 0x1D, 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x0D +}; + +static const uint8_t huffbits5[15] = { + 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 4, 4 +}; + +static const uint8_t huffcode6[31] = { + 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x78, 0x79, 0x7A, + 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x08, 0x09 +}; + +static const uint8_t huffbits6[31] = { + 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, + 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 4, 4 +}; + +static const uint8_t huffcode7[63] = { + 0x00, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0x68, 0x69, 0x6A, 0x6B, 0x6C, + 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, + 0x75, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, + 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, + 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x02, 0x03 +}; + +static const uint8_t huffbits7[63] = { + 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4 +}; + +static const uint8_t huff_tab_sizes[7] = { + 9, 5, 7, 9, 15, 31, 63, +}; + +static const uint8_t* const huff_codes[7] = { + huffcode1, huffcode2, huffcode3, huffcode4, huffcode5, huffcode6, huffcode7 +}; + +static const uint8_t* const huff_bits[7] = { + huffbits1, huffbits2, huffbits3, huffbits4, huffbits5, huffbits6, huffbits7, +}; + +static const uint16_t atrac3_vlc_offs[9] = { + 0, 512, 1024, 1536, 2048, 2560, 3072, 3584, 4096 +}; + +/* selector tables */ + +static const uint8_t clc_length_tab[8] = { 0, 4, 3, 3, 4, 4, 5, 6 }; + +static const int8_t mantissa_clc_tab[4] = { 0, 1, -2, -1 }; + +static const int8_t mantissa_vlc_tab[18] = { + 0, 0, 0, 1, 0, -1, 1, 0, -1, 0, 1, 1, 1, -1, -1, 1, -1, -1 +}; + + +/* tables for the scalefactor decoding */ + +static const float inv_max_quant[8] = { + 0.0, 1.0 / 1.5, 1.0 / 2.5, 1.0 / 3.5, + 1.0 / 4.5, 1.0 / 7.5, 1.0 / 15.5, 1.0 / 31.5 +}; + +static const uint16_t subband_tab[33] = { + 0, 8, 16, 24, 32, 40, 48, 56, + 64, 80, 96, 112, 128, 144, 160, 176, + 192, 224, 256, 288, 320, 352, 384, 416, + 448, 480, 512, 576, 640, 704, 768, 896, + 1024 +}; + +/* joint stereo related tables */ +static const float matrix_coeffs[8] = { + 0.0, 2.0, 2.0, 2.0, 0.0, 0.0, 1.0, 1.0 +}; + +#endif /* AVCODEC_ATRAC3DATA_H */ diff --git a/ext/at3_standalone/atrac3plus.cpp b/ext/at3_standalone/atrac3plus.cpp new file mode 100644 index 0000000000..0844deed59 --- /dev/null +++ b/ext/at3_standalone/atrac3plus.cpp @@ -0,0 +1,1820 @@ +/* + * ATRAC3+ compatible decoder + * + * Copyright (c) 2010-2013 Maxim Poliakovski + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Bitstream parser for ATRAC3+ decoder. + */ + +#include +#include + +#include "get_bits.h" +#include "atrac3plus.h" +#include "atrac3plus_data.h" + +static VLC_TYPE tables_data[154276][2]; +static VLC wl_vlc_tabs[4]; +static VLC sf_vlc_tabs[8]; +static VLC ct_vlc_tabs[4]; +static VLC spec_vlc_tabs[112]; +static VLC gain_vlc_tabs[11]; +static VLC tone_vlc_tabs[7]; + +static const uint8_t ff_logg2_tab[256] = { + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +// todo: Replace with clz type instructions. +int av_log2(unsigned int v) +{ + int n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_logg2_tab[v]; + + return n; +} + +/** + * Generate canonical VLC table from given descriptor. + * + * @param[in] cb ptr to codebook descriptor + * @param[in] xlat ptr to translation table or NULL + * @param[in,out] tab_offset starting offset to the generated vlc table + * @param[out] out_vlc ptr to vlc table to be generated + */ +static void build_canonical_huff(const uint8_t *cb, const uint8_t *xlat, + int *tab_offset, VLC *out_vlc) +{ + int i, b; + uint16_t codes[256]; + uint8_t bits[256]; + unsigned code = 0; + int index = 0; + int min_len = *cb++; // get shortest codeword length + int max_len = *cb++; // get longest codeword length + + for (b = min_len; b <= max_len; b++) { + for (i = *cb++; i > 0; i--) { + av_assert0(index < 256); + bits[index] = b; + codes[index] = code++; + index++; + } + code <<= 1; + } + + out_vlc->table = &tables_data[*tab_offset]; + out_vlc->table_allocated = 1 << max_len; + + ff_init_vlc_sparse(out_vlc, max_len, index, bits, 1, 1, codes, 2, 2, + xlat, 1, 1, INIT_VLC_USE_NEW_STATIC); + + *tab_offset += 1 << max_len; +} + +void ff_atrac3p_init_vlcs(void) +{ + int i, wl_vlc_offs, ct_vlc_offs, sf_vlc_offs, tab_offset; + + static const int wl_nb_bits[4] = { 2, 3, 5, 5 }; + static const int wl_nb_codes[4] = { 3, 5, 8, 8 }; + static const uint8_t * const wl_bits[4] = { + atrac3p_wl_huff_bits1, atrac3p_wl_huff_bits2, + atrac3p_wl_huff_bits3, atrac3p_wl_huff_bits4 + }; + static const uint8_t * const wl_codes[4] = { + atrac3p_wl_huff_code1, atrac3p_wl_huff_code2, + atrac3p_wl_huff_code3, atrac3p_wl_huff_code4 + }; + static const uint8_t * const wl_xlats[4] = { + atrac3p_wl_huff_xlat1, atrac3p_wl_huff_xlat2, NULL, NULL + }; + + static const int ct_nb_bits[4] = { 3, 4, 4, 4 }; + static const int ct_nb_codes[4] = { 4, 8, 8, 8 }; + static const uint8_t * const ct_bits[4] = { + atrac3p_ct_huff_bits1, atrac3p_ct_huff_bits2, + atrac3p_ct_huff_bits2, atrac3p_ct_huff_bits3 + }; + static const uint8_t * const ct_codes[4] = { + atrac3p_ct_huff_code1, atrac3p_ct_huff_code2, + atrac3p_ct_huff_code2, atrac3p_ct_huff_code3 + }; + static const uint8_t * const ct_xlats[4] = { + NULL, NULL, atrac3p_ct_huff_xlat1, NULL + }; + + static const int sf_nb_bits[8] = { 9, 9, 9, 9, 6, 6, 7, 7 }; + static const int sf_nb_codes[8] = { 64, 64, 64, 64, 16, 16, 16, 16 }; + static const uint8_t * const sf_bits[8] = { + atrac3p_sf_huff_bits1, atrac3p_sf_huff_bits1, atrac3p_sf_huff_bits2, + atrac3p_sf_huff_bits3, atrac3p_sf_huff_bits4, atrac3p_sf_huff_bits4, + atrac3p_sf_huff_bits5, atrac3p_sf_huff_bits6 + }; + static const uint16_t * const sf_codes[8] = { + atrac3p_sf_huff_code1, atrac3p_sf_huff_code1, atrac3p_sf_huff_code2, + atrac3p_sf_huff_code3, atrac3p_sf_huff_code4, atrac3p_sf_huff_code4, + atrac3p_sf_huff_code5, atrac3p_sf_huff_code6 + }; + static const uint8_t * const sf_xlats[8] = { + atrac3p_sf_huff_xlat1, atrac3p_sf_huff_xlat2, NULL, NULL, + atrac3p_sf_huff_xlat4, atrac3p_sf_huff_xlat5, NULL, NULL + }; + + static const uint8_t * const gain_cbs[11] = { + atrac3p_huff_gain_npoints1_cb, atrac3p_huff_gain_npoints1_cb, + atrac3p_huff_gain_lev1_cb, atrac3p_huff_gain_lev2_cb, + atrac3p_huff_gain_lev3_cb, atrac3p_huff_gain_lev4_cb, + atrac3p_huff_gain_loc3_cb, atrac3p_huff_gain_loc1_cb, + atrac3p_huff_gain_loc4_cb, atrac3p_huff_gain_loc2_cb, + atrac3p_huff_gain_loc5_cb + }; + static const uint8_t * const gain_xlats[11] = { + NULL, atrac3p_huff_gain_npoints2_xlat, atrac3p_huff_gain_lev1_xlat, + atrac3p_huff_gain_lev2_xlat, atrac3p_huff_gain_lev3_xlat, + atrac3p_huff_gain_lev4_xlat, atrac3p_huff_gain_loc3_xlat, + atrac3p_huff_gain_loc1_xlat, atrac3p_huff_gain_loc4_xlat, + atrac3p_huff_gain_loc2_xlat, atrac3p_huff_gain_loc5_xlat + }; + + static const uint8_t * const tone_cbs[7] = { + atrac3p_huff_tonebands_cb, atrac3p_huff_numwavs1_cb, + atrac3p_huff_numwavs2_cb, atrac3p_huff_wav_ampsf1_cb, + atrac3p_huff_wav_ampsf2_cb, atrac3p_huff_wav_ampsf3_cb, + atrac3p_huff_freq_cb + }; + static const uint8_t * const tone_xlats[7] = { + NULL, NULL, atrac3p_huff_numwavs2_xlat, atrac3p_huff_wav_ampsf1_xlat, + atrac3p_huff_wav_ampsf2_xlat, atrac3p_huff_wav_ampsf3_xlat, + atrac3p_huff_freq_xlat + }; + + for (i = 0, wl_vlc_offs = 0, ct_vlc_offs = 2508; i < 4; i++) { + wl_vlc_tabs[i].table = &tables_data[wl_vlc_offs]; + wl_vlc_tabs[i].table_allocated = 1 << wl_nb_bits[i]; + ct_vlc_tabs[i].table = &tables_data[ct_vlc_offs]; + ct_vlc_tabs[i].table_allocated = 1 << ct_nb_bits[i]; + + ff_init_vlc_sparse(&wl_vlc_tabs[i], wl_nb_bits[i], wl_nb_codes[i], + wl_bits[i], 1, 1, + wl_codes[i], 1, 1, + wl_xlats[i], 1, 1, + INIT_VLC_USE_NEW_STATIC); + + ff_init_vlc_sparse(&ct_vlc_tabs[i], ct_nb_bits[i], ct_nb_codes[i], + ct_bits[i], 1, 1, + ct_codes[i], 1, 1, + ct_xlats[i], 1, 1, + INIT_VLC_USE_NEW_STATIC); + + wl_vlc_offs += wl_vlc_tabs[i].table_allocated; + ct_vlc_offs += ct_vlc_tabs[i].table_allocated; + } + + for (i = 0, sf_vlc_offs = 76; i < 8; i++) { + sf_vlc_tabs[i].table = &tables_data[sf_vlc_offs]; + sf_vlc_tabs[i].table_allocated = 1 << sf_nb_bits[i]; + + ff_init_vlc_sparse(&sf_vlc_tabs[i], sf_nb_bits[i], sf_nb_codes[i], + sf_bits[i], 1, 1, + sf_codes[i], 2, 2, + sf_xlats[i], 1, 1, + INIT_VLC_USE_NEW_STATIC); + sf_vlc_offs += sf_vlc_tabs[i].table_allocated; + } + + tab_offset = 2564; + + /* build huffman tables for spectrum decoding */ + for (i = 0; i < 112; i++) { + if (atrac3p_spectra_tabs[i].cb) + build_canonical_huff(atrac3p_spectra_tabs[i].cb, + atrac3p_spectra_tabs[i].xlat, + &tab_offset, &spec_vlc_tabs[i]); + else + spec_vlc_tabs[i].table = 0; + } + + /* build huffman tables for gain data decoding */ + for (i = 0; i < 11; i++) + build_canonical_huff(gain_cbs[i], gain_xlats[i], &tab_offset, &gain_vlc_tabs[i]); + + /* build huffman tables for tone decoding */ + for (i = 0; i < 7; i++) + build_canonical_huff(tone_cbs[i], tone_xlats[i], &tab_offset, &tone_vlc_tabs[i]); +} + +/** + * Decode number of coded quantization units. + * + * @param[in] gb the GetBit context + * @param[in,out] chan ptr to the channel parameters + * @param[in,out] ctx ptr to the channel unit context + * @return result code: 0 = OK, otherwise - error code + */ +static int num_coded_units(GetBitContext *gb, Atrac3pChanParams *chan, + Atrac3pChanUnitCtx *ctx) +{ + chan->fill_mode = get_bits(gb, 2); + if (!chan->fill_mode) { + chan->num_coded_vals = ctx->num_quant_units; + } else { + chan->num_coded_vals = get_bits(gb, 5); + if (chan->num_coded_vals > ctx->num_quant_units) { + av_log(AV_LOG_ERROR, + "Invalid number of transmitted units!\n"); + return AVERROR_INVALIDDATA; + } + + if (chan->fill_mode == 3) + chan->split_point = get_bits(gb, 2) + (chan->ch_num << 1) + 1; + } + + return 0; +} + +/** + * Add weighting coefficients to the decoded word-length information. + * + * @param[in,out] ctx ptr to the channel unit context + * @param[in,out] chan ptr to the channel parameters + * @param[in] wtab_idx index of the table of weights + * @return result code: 0 = OK, otherwise - error code + */ +static int add_wordlen_weights(Atrac3pChanUnitCtx *ctx, + Atrac3pChanParams *chan, int wtab_idx) +{ + int i; + const int8_t *weights_tab = + &atrac3p_wl_weights[chan->ch_num * 3 + wtab_idx - 1][0]; + + for (i = 0; i < ctx->num_quant_units; i++) { + chan->qu_wordlen[i] += weights_tab[i]; + if (chan->qu_wordlen[i] < 0 || chan->qu_wordlen[i] > 7) { + av_log(AV_LOG_ERROR, + "WL index out of range: pos=%d, val=%d!\n", + i, chan->qu_wordlen[i]); + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +/** + * Subtract weighting coefficients from decoded scalefactors. + * + * @param[in,out] ctx ptr to the channel unit context + * @param[in,out] chan ptr to the channel parameters + * @param[in] wtab_idx index of table of weights + * @return result code: 0 = OK, otherwise - error code + */ +static int subtract_sf_weights(Atrac3pChanUnitCtx *ctx, + Atrac3pChanParams *chan, int wtab_idx) +{ + int i; + const int8_t *weights_tab = &atrac3p_sf_weights[wtab_idx - 1][0]; + + for (i = 0; i < ctx->used_quant_units; i++) { + chan->qu_sf_idx[i] -= weights_tab[i]; + if (chan->qu_sf_idx[i] < 0 || chan->qu_sf_idx[i] > 63) { + av_log(AV_LOG_ERROR, + "SF index out of range: pos=%d, val=%d!\n", + i, chan->qu_sf_idx[i]); + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +/** + * Unpack vector quantization tables. + * + * @param[in] start_val start value for the unpacked table + * @param[in] shape_vec ptr to table to unpack + * @param[out] dst ptr to output array + * @param[in] num_values number of values to unpack + */ +static inline void unpack_vq_shape(int start_val, const int8_t *shape_vec, + int *dst, int num_values) +{ + int i; + + if (num_values) { + dst[0] = dst[1] = dst[2] = start_val; + for (i = 3; i < num_values; i++) + dst[i] = start_val - shape_vec[atrac3p_qu_num_to_seg[i] - 1]; + } +} + +#define UNPACK_SF_VQ_SHAPE(gb, dst, num_vals) \ + start_val = get_bits((gb), 6); \ + unpack_vq_shape(start_val, &atrac3p_sf_shapes[get_bits((gb), 6)][0], \ + (dst), (num_vals)) + +/** + * Decode word length for each quantization unit of a channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_channel_wordlen(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, int ch_num) +{ + int i, weight_idx = 0, delta, diff, pos, delta_bits, min_val, flag, + ret, start_val; + VLC *vlc_tab; + Atrac3pChanParams *chan = &ctx->channels[ch_num]; + Atrac3pChanParams *ref_chan = &ctx->channels[0]; + + chan->fill_mode = 0; + + switch (get_bits(gb, 2)) { /* switch according to coding mode */ + case 0: /* coded using constant number of bits */ + for (i = 0; i < ctx->num_quant_units; i++) + chan->qu_wordlen[i] = get_bits(gb, 3); + break; + case 1: + if (ch_num) { + if ((ret = num_coded_units(gb, chan, ctx)) < 0) + return ret; + + if (chan->num_coded_vals) { + vlc_tab = &wl_vlc_tabs[get_bits(gb, 2)]; + + for (i = 0; i < chan->num_coded_vals; i++) { + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_wordlen[i] = (ref_chan->qu_wordlen[i] + delta) & 7; + } + } + } else { + weight_idx = get_bits(gb, 2); + if ((ret = num_coded_units(gb, chan, ctx)) < 0) + return ret; + + if (chan->num_coded_vals) { + pos = get_bits(gb, 5); + if (pos > chan->num_coded_vals) { + av_log(AV_LOG_ERROR, + "WL mode 1: invalid position!\n"); + return AVERROR_INVALIDDATA; + } + + delta_bits = get_bits(gb, 2); + min_val = get_bits(gb, 3); + + for (i = 0; i < pos; i++) + chan->qu_wordlen[i] = get_bits(gb, 3); + + for (i = pos; i < chan->num_coded_vals; i++) + chan->qu_wordlen[i] = (min_val + get_bitsz(gb, delta_bits)) & 7; + } + } + break; + case 2: + if ((ret = num_coded_units(gb, chan, ctx)) < 0) + return ret; + + if (ch_num && chan->num_coded_vals) { + vlc_tab = &wl_vlc_tabs[get_bits(gb, 2)]; + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_wordlen[0] = (ref_chan->qu_wordlen[0] + delta) & 7; + + for (i = 1; i < chan->num_coded_vals; i++) { + diff = ref_chan->qu_wordlen[i] - ref_chan->qu_wordlen[i - 1]; + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_wordlen[i] = (chan->qu_wordlen[i - 1] + diff + delta) & 7; + } + } else if (chan->num_coded_vals) { + flag = get_bits(gb, 1); + vlc_tab = &wl_vlc_tabs[get_bits(gb, 1)]; + + start_val = get_bits(gb, 3); + unpack_vq_shape(start_val, + &atrac3p_wl_shapes[start_val][get_bits(gb, 4)][0], + chan->qu_wordlen, chan->num_coded_vals); + + if (!flag) { + for (i = 0; i < chan->num_coded_vals; i++) { + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_wordlen[i] = (chan->qu_wordlen[i] + delta) & 7; + } + } else { + for (i = 0; i < (chan->num_coded_vals & - 2); i += 2) + if (!get_bits1(gb)) { + chan->qu_wordlen[i] = (chan->qu_wordlen[i] + + get_vlc2(gb, vlc_tab->table, + vlc_tab->bits, 1)) & 7; + chan->qu_wordlen[i + 1] = (chan->qu_wordlen[i + 1] + + get_vlc2(gb, vlc_tab->table, + vlc_tab->bits, 1)) & 7; + } + + if (chan->num_coded_vals & 1) + chan->qu_wordlen[i] = (chan->qu_wordlen[i] + + get_vlc2(gb, vlc_tab->table, + vlc_tab->bits, 1)) & 7; + } + } + break; + case 3: + weight_idx = get_bits(gb, 2); + if ((ret = num_coded_units(gb, chan, ctx)) < 0) + return ret; + + if (chan->num_coded_vals) { + vlc_tab = &wl_vlc_tabs[get_bits(gb, 2)]; + + /* first coefficient is coded directly */ + chan->qu_wordlen[0] = get_bits(gb, 3); + + for (i = 1; i < chan->num_coded_vals; i++) { + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_wordlen[i] = (chan->qu_wordlen[i - 1] + delta) & 7; + } + } + break; + } + + if (chan->fill_mode == 2) { + for (i = chan->num_coded_vals; i < ctx->num_quant_units; i++) + chan->qu_wordlen[i] = ch_num ? get_bits1(gb) : 1; + } else if (chan->fill_mode == 3) { + pos = ch_num ? chan->num_coded_vals + chan->split_point + : ctx->num_quant_units - chan->split_point; + if (pos > FF_ARRAY_ELEMS(chan->qu_wordlen)) { + av_log(AV_LOG_ERROR, "Split point beyond array"); + pos = FF_ARRAY_ELEMS(chan->qu_wordlen); + } + for (i = chan->num_coded_vals; i < pos; i++) + chan->qu_wordlen[i] = 1; + } + + if (weight_idx) + return add_wordlen_weights(ctx, chan, weight_idx); + + return 0; +} + +/** + * Decode scale factor indexes for each quant unit of a channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_channel_sf_idx(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, int ch_num) +{ + int i, weight_idx = 0, delta, diff, num_long_vals, + delta_bits, min_val, vlc_sel, start_val; + VLC *vlc_tab; + Atrac3pChanParams *chan = &ctx->channels[ch_num]; + Atrac3pChanParams *ref_chan = &ctx->channels[0]; + + switch (get_bits(gb, 2)) { /* switch according to coding mode */ + case 0: /* coded using constant number of bits */ + for (i = 0; i < ctx->used_quant_units; i++) + chan->qu_sf_idx[i] = get_bits(gb, 6); + break; + case 1: + if (ch_num) { + vlc_tab = &sf_vlc_tabs[get_bits(gb, 2)]; + + for (i = 0; i < ctx->used_quant_units; i++) { + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_sf_idx[i] = (ref_chan->qu_sf_idx[i] + delta) & 0x3F; + } + } else { + weight_idx = get_bits(gb, 2); + if (weight_idx == 3) { + UNPACK_SF_VQ_SHAPE(gb, chan->qu_sf_idx, ctx->used_quant_units); + + num_long_vals = get_bits(gb, 5); + delta_bits = get_bits(gb, 2); + min_val = get_bits(gb, 4) - 7; + + for (i = 0; i < num_long_vals; i++) + chan->qu_sf_idx[i] = (chan->qu_sf_idx[i] + + get_bits(gb, 4) - 7) & 0x3F; + + /* all others are: min_val + delta */ + for (i = num_long_vals; i < ctx->used_quant_units; i++) + chan->qu_sf_idx[i] = (chan->qu_sf_idx[i] + min_val + + get_bitsz(gb, delta_bits)) & 0x3F; + } else { + num_long_vals = get_bits(gb, 5); + delta_bits = get_bits(gb, 3); + min_val = get_bits(gb, 6); + if (num_long_vals > ctx->used_quant_units || delta_bits == 7) { + av_log(AV_LOG_ERROR, + "SF mode 1: invalid parameters!\n"); + return AVERROR_INVALIDDATA; + } + + /* read full-precision SF indexes */ + for (i = 0; i < num_long_vals; i++) + chan->qu_sf_idx[i] = get_bits(gb, 6); + + /* all others are: min_val + delta */ + for (i = num_long_vals; i < ctx->used_quant_units; i++) + chan->qu_sf_idx[i] = (min_val + + get_bitsz(gb, delta_bits)) & 0x3F; + } + } + break; + case 2: + if (ch_num) { + vlc_tab = &sf_vlc_tabs[get_bits(gb, 2)]; + + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_sf_idx[0] = (ref_chan->qu_sf_idx[0] + delta) & 0x3F; + + for (i = 1; i < ctx->used_quant_units; i++) { + diff = ref_chan->qu_sf_idx[i] - ref_chan->qu_sf_idx[i - 1]; + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_sf_idx[i] = (chan->qu_sf_idx[i - 1] + diff + delta) & 0x3F; + } + } else { + vlc_tab = &sf_vlc_tabs[get_bits(gb, 2) + 4]; + + UNPACK_SF_VQ_SHAPE(gb, chan->qu_sf_idx, ctx->used_quant_units); + + for (i = 0; i < ctx->used_quant_units; i++) { + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_sf_idx[i] = (chan->qu_sf_idx[i] + + sign_extend(delta, 4)) & 0x3F; + } + } + break; + case 3: + if (ch_num) { + /* copy coefficients from reference channel */ + for (i = 0; i < ctx->used_quant_units; i++) + chan->qu_sf_idx[i] = ref_chan->qu_sf_idx[i]; + } else { + weight_idx = get_bits(gb, 2); + vlc_sel = get_bits(gb, 2); + vlc_tab = &sf_vlc_tabs[vlc_sel]; + + if (weight_idx == 3) { + vlc_tab = &sf_vlc_tabs[vlc_sel + 4]; + + UNPACK_SF_VQ_SHAPE(gb, chan->qu_sf_idx, ctx->used_quant_units); + + diff = (get_bits(gb, 4) + 56) & 0x3F; + chan->qu_sf_idx[0] = (chan->qu_sf_idx[0] + diff) & 0x3F; + + for (i = 1; i < ctx->used_quant_units; i++) { + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + diff = (diff + sign_extend(delta, 4)) & 0x3F; + chan->qu_sf_idx[i] = (diff + chan->qu_sf_idx[i]) & 0x3F; + } + } else { + /* 1st coefficient is coded directly */ + chan->qu_sf_idx[0] = get_bits(gb, 6); + + for (i = 1; i < ctx->used_quant_units; i++) { + delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + chan->qu_sf_idx[i] = (chan->qu_sf_idx[i - 1] + delta) & 0x3F; + } + } + } + break; + } + + if (weight_idx && weight_idx < 3) + return subtract_sf_weights(ctx, chan, weight_idx); + + return 0; +} + +/** + * Decode word length information for each channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] num_channels number of channels to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_quant_wordlen(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels) +{ + int ch_num, i, ret; + + for (ch_num = 0; ch_num < num_channels; ch_num++) { + memset(ctx->channels[ch_num].qu_wordlen, 0, + sizeof(ctx->channels[ch_num].qu_wordlen)); + + if ((ret = decode_channel_wordlen(gb, ctx, ch_num)) < 0) + return ret; + } + + /* scan for last non-zero coeff in both channels and + * set number of quant units having coded spectrum */ + for (i = ctx->num_quant_units - 1; i >= 0; i--) + if (ctx->channels[0].qu_wordlen[i] || + (num_channels == 2 && ctx->channels[1].qu_wordlen[i])) + break; + ctx->used_quant_units = i + 1; + + return 0; +} + +/** + * Decode scale factor indexes for each channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] num_channels number of channels to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_scale_factors(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels) +{ + int ch_num, ret; + + if (!ctx->used_quant_units) + return 0; + + for (ch_num = 0; ch_num < num_channels; ch_num++) { + memset(ctx->channels[ch_num].qu_sf_idx, 0, + sizeof(ctx->channels[ch_num].qu_sf_idx)); + + if ((ret = decode_channel_sf_idx(gb, ctx, ch_num)) < 0) + return ret; + } + + return 0; +} + +/** + * Decode number of code table values. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @return result code: 0 = OK, otherwise - error code + */ +static int get_num_ct_values(GetBitContext *gb, Atrac3pChanUnitCtx *ctx) +{ + int num_coded_vals; + + if (get_bits1(gb)) { + num_coded_vals = get_bits(gb, 5); + if (num_coded_vals > ctx->used_quant_units) { + av_log(AV_LOG_ERROR, + "Invalid number of code table indexes: %d!\n", num_coded_vals); + return AVERROR_INVALIDDATA; + } + return num_coded_vals; + } else + return ctx->used_quant_units; +} + +#define DEC_CT_IDX_COMMON(OP) \ + num_vals = get_num_ct_values(gb, ctx); \ + if (num_vals < 0) \ + return num_vals; \ + \ + for (i = 0; i < num_vals; i++) { \ + if (chan->qu_wordlen[i]) { \ + chan->qu_tab_idx[i] = OP; \ + } else if (ch_num && ref_chan->qu_wordlen[i]) \ + /* get clone master flag */ \ + chan->qu_tab_idx[i] = get_bits1(gb); \ + } + +#define CODING_DIRECT get_bits(gb, num_bits) + +#define CODING_VLC get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1) + +#define CODING_VLC_DELTA \ + (!i) ? CODING_VLC \ + : (pred + get_vlc2(gb, delta_vlc->table, \ + delta_vlc->bits, 1)) & mask; \ + pred = chan->qu_tab_idx[i] + +#define CODING_VLC_DIFF \ + (ref_chan->qu_tab_idx[i] + \ + get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1)) & mask + +/** + * Decode code table indexes for each quant unit of a channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_channel_code_tab(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num) +{ + int i, num_vals, num_bits, pred; + int mask = ctx->use_full_table ? 7 : 3; /* mask for modular arithmetic */ + VLC *vlc_tab, *delta_vlc; + Atrac3pChanParams *chan = &ctx->channels[ch_num]; + Atrac3pChanParams *ref_chan = &ctx->channels[0]; + + chan->table_type = get_bits1(gb); + + switch (get_bits(gb, 2)) { /* switch according to coding mode */ + case 0: /* directly coded */ + num_bits = ctx->use_full_table + 2; + DEC_CT_IDX_COMMON(CODING_DIRECT); + break; + case 1: /* entropy-coded */ + vlc_tab = ctx->use_full_table ? &ct_vlc_tabs[1] + : ct_vlc_tabs; + DEC_CT_IDX_COMMON(CODING_VLC); + break; + case 2: /* entropy-coded delta */ + if (ctx->use_full_table) { + vlc_tab = &ct_vlc_tabs[1]; + delta_vlc = &ct_vlc_tabs[2]; + } else { + vlc_tab = ct_vlc_tabs; + delta_vlc = ct_vlc_tabs; + } + pred = 0; + DEC_CT_IDX_COMMON(CODING_VLC_DELTA); + break; + case 3: /* entropy-coded difference to master */ + if (ch_num) { + vlc_tab = ctx->use_full_table ? &ct_vlc_tabs[3] + : ct_vlc_tabs; + DEC_CT_IDX_COMMON(CODING_VLC_DIFF); + } + break; + } + + return 0; +} + +/** + * Decode code table indexes for each channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] num_channels number of channels to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_code_table_indexes(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels) +{ + int ch_num, ret; + + if (!ctx->used_quant_units) + return 0; + + ctx->use_full_table = get_bits1(gb); + + for (ch_num = 0; ch_num < num_channels; ch_num++) { + memset(ctx->channels[ch_num].qu_tab_idx, 0, + sizeof(ctx->channels[ch_num].qu_tab_idx)); + + if ((ret = decode_channel_code_tab(gb, ctx, ch_num)) < 0) + return ret; + } + + return 0; +} + +/** + * Decode huffman-coded spectral lines for a given quant unit. + * + * This is a generalized version for all known coding modes. + * Its speed can be improved by creating separate functions for each mode. + * + * @param[in] gb the GetBit context + * @param[in] tab code table telling how to decode spectral lines + * @param[in] vlc_tab ptr to the huffman table associated with the code table + * @param[out] out pointer to buffer where decoded data should be stored + * @param[in] num_specs number of spectral lines to decode + */ +static void decode_qu_spectra(GetBitContext *gb, const Atrac3pSpecCodeTab *tab, + VLC *vlc_tab, int16_t *out, const int num_specs) +{ + int i, j, pos, cf; + int group_size = tab->group_size; + int num_coeffs = tab->num_coeffs; + int bits = tab->bits; + int is_signed = tab->is_signed; + unsigned val; + const unsigned bitmask = ((1 << bits) - 1); // mask to clear higher bits. + + for (pos = 0; pos < num_specs;) { + if (group_size == 1 || get_bits1(gb)) { + for (j = 0; j < group_size; j++) { + val = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); + for (i = 0; i < num_coeffs; i++) { + cf = val & bitmask; + if (is_signed) + cf = sign_extend(cf, bits); + else if (cf && get_bits1(gb)) + cf = -cf; + + out[pos++] = cf; + val >>= bits; + } + } + } else /* group skipped */ + pos += group_size * num_coeffs; + } +} + +/** + * Decode huffman-coded IMDCT spectrum for all channels. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] num_channels number of channels to process + */ +static void decode_spectrum(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels) +{ + int i, ch_num, qu, wordlen, codetab, tab_index, num_specs; + const Atrac3pSpecCodeTab *tab; + Atrac3pChanParams *chan; + + for (ch_num = 0; ch_num < num_channels; ch_num++) { + chan = &ctx->channels[ch_num]; + + memset(chan->spectrum, 0, sizeof(chan->spectrum)); + + /* set power compensation level to disabled */ + memset(chan->power_levs, ATRAC3P_POWER_COMP_OFF, sizeof(chan->power_levs)); + + for (qu = 0; qu < ctx->used_quant_units; qu++) { + num_specs = av_atrac3p_qu_to_spec_pos[qu + 1] - + av_atrac3p_qu_to_spec_pos[qu]; + + wordlen = chan->qu_wordlen[qu]; + codetab = chan->qu_tab_idx[qu]; + if (wordlen) { + if (!ctx->use_full_table) + codetab = atrac3p_ct_restricted_to_full[chan->table_type][wordlen - 1][codetab]; + + tab_index = (chan->table_type * 8 + codetab) * 7 + wordlen - 1; + tab = &atrac3p_spectra_tabs[tab_index]; + + /* this allows reusing VLC tables */ + if (tab->redirect >= 0) + tab_index = tab->redirect; + + decode_qu_spectra(gb, tab, &spec_vlc_tabs[tab_index], + &chan->spectrum[av_atrac3p_qu_to_spec_pos[qu]], + num_specs); + } else if (ch_num && ctx->channels[0].qu_wordlen[qu] && !codetab) { + /* copy coefficients from master */ + memcpy(&chan->spectrum[av_atrac3p_qu_to_spec_pos[qu]], + &ctx->channels[0].spectrum[av_atrac3p_qu_to_spec_pos[qu]], + num_specs * + sizeof(chan->spectrum[av_atrac3p_qu_to_spec_pos[qu]])); + chan->qu_wordlen[qu] = ctx->channels[0].qu_wordlen[qu]; + } + } + + /* Power compensation levels only present in the bitstream + * if there are more than 2 quant units. The lowest two units + * correspond to the frequencies 0...351 Hz, whose shouldn't + * be affected by the power compensation. */ + if (ctx->used_quant_units > 2) { + num_specs = atrac3p_subband_to_num_powgrps[ctx->num_coded_subbands - 1]; + for (i = 0; i < num_specs; i++) + chan->power_levs[i] = get_bits(gb, 4); + } + } +} + +/** + * Retrieve specified amount of flag bits from the input bitstream. + * The data can be shortened in the case of the following two common conditions: + * if all bits are zero then only one signal bit = 0 will be stored, + * if all bits are ones then two signal bits = 1,0 will be stored. + * Otherwise, all necessary bits will be directly stored + * prefixed by two signal bits = 1,1. + * + * @param[in] gb ptr to the GetBitContext + * @param[out] out where to place decoded flags + * @param[in] num_flags number of flags to process + * @return: 0 = all flag bits are zero, 1 = there is at least one non-zero flag bit + */ +static int get_subband_flags(GetBitContext *gb, uint8_t *out, int num_flags) +{ + int i, result; + + memset(out, 0, num_flags); + + result = get_bits1(gb); + if (result) { + if (get_bits1(gb)) + for (i = 0; i < num_flags; i++) + out[i] = get_bits1(gb); + else + memset(out, 1, num_flags); + } + + return result; +} + +/** + * Decode mdct window shape flags for all channels. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] num_channels number of channels to process + */ +static void decode_window_shape(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels) +{ + int ch_num; + + for (ch_num = 0; ch_num < num_channels; ch_num++) + get_subband_flags(gb, ctx->channels[ch_num].wnd_shape, + ctx->num_subbands); +} + +/** + * Decode number of gain control points. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @param[in] coded_subbands number of subbands to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_gainc_npoints(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num, int coded_subbands) +{ + int i, delta, delta_bits, min_val; + Atrac3pChanParams *chan = &ctx->channels[ch_num]; + Atrac3pChanParams *ref_chan = &ctx->channels[0]; + + switch (get_bits(gb, 2)) { /* switch according to coding mode */ + case 0: /* fixed-length coding */ + for (i = 0; i < coded_subbands; i++) + chan->gain_data[i].num_points = get_bits(gb, 3); + break; + case 1: /* variable-length coding */ + for (i = 0; i < coded_subbands; i++) + chan->gain_data[i].num_points = + get_vlc2(gb, gain_vlc_tabs[0].table, + gain_vlc_tabs[0].bits, 1); + break; + case 2: + if (ch_num) { /* VLC modulo delta to master channel */ + for (i = 0; i < coded_subbands; i++) { + delta = get_vlc2(gb, gain_vlc_tabs[1].table, + gain_vlc_tabs[1].bits, 1); + chan->gain_data[i].num_points = + (ref_chan->gain_data[i].num_points + delta) & 7; + } + } else { /* VLC modulo delta to previous */ + chan->gain_data[0].num_points = + get_vlc2(gb, gain_vlc_tabs[0].table, + gain_vlc_tabs[0].bits, 1); + + for (i = 1; i < coded_subbands; i++) { + delta = get_vlc2(gb, gain_vlc_tabs[1].table, + gain_vlc_tabs[1].bits, 1); + chan->gain_data[i].num_points = + (chan->gain_data[i - 1].num_points + delta) & 7; + } + } + break; + case 3: + if (ch_num) { /* copy data from master channel */ + for (i = 0; i < coded_subbands; i++) + chan->gain_data[i].num_points = + ref_chan->gain_data[i].num_points; + } else { /* shorter delta to min */ + delta_bits = get_bits(gb, 2); + min_val = get_bits(gb, 3); + + for (i = 0; i < coded_subbands; i++) { + chan->gain_data[i].num_points = min_val + get_bitsz(gb, delta_bits); + if (chan->gain_data[i].num_points > 7) + return AVERROR_INVALIDDATA; + } + } + } + + return 0; +} + +/** + * Implements coding mode 3 (slave) for gain compensation levels. + * + * @param[out] dst ptr to the output array + * @param[in] ref ptr to the reference channel + */ +static inline void gainc_level_mode3s(AtracGainInfo *dst, AtracGainInfo *ref) +{ + int i; + + for (i = 0; i < dst->num_points; i++) + dst->lev_code[i] = (i >= ref->num_points) ? 7 : ref->lev_code[i]; +} + +/** + * Implements coding mode 1 (master) for gain compensation levels. + * + * @param[in] gb the GetBit context + * @param[in] ctx ptr to the channel unit context + * @param[out] dst ptr to the output array + */ +static inline void gainc_level_mode1m(GetBitContext *gb, + Atrac3pChanUnitCtx *ctx, + AtracGainInfo *dst) +{ + int i, delta; + + if (dst->num_points > 0) + dst->lev_code[0] = get_vlc2(gb, gain_vlc_tabs[2].table, + gain_vlc_tabs[2].bits, 1); + + for (i = 1; i < dst->num_points; i++) { + delta = get_vlc2(gb, gain_vlc_tabs[3].table, + gain_vlc_tabs[3].bits, 1); + dst->lev_code[i] = (dst->lev_code[i - 1] + delta) & 0xF; + } +} + +/** + * Decode level code for each gain control point. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @param[in] coded_subbands number of subbands to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_gainc_levels(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num, int coded_subbands) +{ + int sb, i, delta, delta_bits, min_val, pred; + Atrac3pChanParams *chan = &ctx->channels[ch_num]; + Atrac3pChanParams *ref_chan = &ctx->channels[0]; + + switch (get_bits(gb, 2)) { /* switch according to coding mode */ + case 0: /* fixed-length coding */ + for (sb = 0; sb < coded_subbands; sb++) + for (i = 0; i < chan->gain_data[sb].num_points; i++) + chan->gain_data[sb].lev_code[i] = get_bits(gb, 4); + break; + case 1: + if (ch_num) { /* VLC modulo delta to master channel */ + for (sb = 0; sb < coded_subbands; sb++) + for (i = 0; i < chan->gain_data[sb].num_points; i++) { + delta = get_vlc2(gb, gain_vlc_tabs[5].table, + gain_vlc_tabs[5].bits, 1); + pred = (i >= ref_chan->gain_data[sb].num_points) + ? 7 : ref_chan->gain_data[sb].lev_code[i]; + chan->gain_data[sb].lev_code[i] = (pred + delta) & 0xF; + } + } else { /* VLC modulo delta to previous */ + for (sb = 0; sb < coded_subbands; sb++) + gainc_level_mode1m(gb, ctx, &chan->gain_data[sb]); + } + break; + case 2: + if (ch_num) { /* VLC modulo delta to previous or clone master */ + for (sb = 0; sb < coded_subbands; sb++) + if (chan->gain_data[sb].num_points > 0) { + if (get_bits1(gb)) + gainc_level_mode1m(gb, ctx, &chan->gain_data[sb]); + else + gainc_level_mode3s(&chan->gain_data[sb], + &ref_chan->gain_data[sb]); + } + } else { /* VLC modulo delta to lev_codes of previous subband */ + if (chan->gain_data[0].num_points > 0) + gainc_level_mode1m(gb, ctx, &chan->gain_data[0]); + + for (sb = 1; sb < coded_subbands; sb++) + for (i = 0; i < chan->gain_data[sb].num_points; i++) { + delta = get_vlc2(gb, gain_vlc_tabs[4].table, + gain_vlc_tabs[4].bits, 1); + pred = (i >= chan->gain_data[sb - 1].num_points) + ? 7 : chan->gain_data[sb - 1].lev_code[i]; + chan->gain_data[sb].lev_code[i] = (pred + delta) & 0xF; + } + } + break; + case 3: + if (ch_num) { /* clone master */ + for (sb = 0; sb < coded_subbands; sb++) + gainc_level_mode3s(&chan->gain_data[sb], + &ref_chan->gain_data[sb]); + } else { /* shorter delta to min */ + delta_bits = get_bits(gb, 2); + min_val = get_bits(gb, 4); + + for (sb = 0; sb < coded_subbands; sb++) + for (i = 0; i < chan->gain_data[sb].num_points; i++) { + chan->gain_data[sb].lev_code[i] = min_val + get_bitsz(gb, delta_bits); + if (chan->gain_data[sb].lev_code[i] > 15) + return AVERROR_INVALIDDATA; + } + } + break; + } + + return 0; +} + +/** + * Implements coding mode 0 for gain compensation locations. + * + * @param[in] gb the GetBit context + * @param[in] ctx ptr to the channel unit context + * @param[out] dst ptr to the output array + * @param[in] pos position of the value to be processed + */ +static inline void gainc_loc_mode0(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + AtracGainInfo *dst, int pos) +{ + int delta_bits; + + if (!pos || dst->loc_code[pos - 1] < 15) + dst->loc_code[pos] = get_bits(gb, 5); + else if (dst->loc_code[pos - 1] >= 30) + dst->loc_code[pos] = 31; + else { + delta_bits = av_log2(30 - dst->loc_code[pos - 1]) + 1; + dst->loc_code[pos] = dst->loc_code[pos - 1] + + get_bits(gb, delta_bits) + 1; + } +} + +/** + * Implements coding mode 1 for gain compensation locations. + * + * @param[in] gb the GetBit context + * @param[in] ctx ptr to the channel unit context + * @param[out] dst ptr to the output array + */ +static inline void gainc_loc_mode1(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + AtracGainInfo *dst) +{ + int i; + VLC *tab; + + if (dst->num_points > 0) { + /* 1st coefficient is stored directly */ + dst->loc_code[0] = get_bits(gb, 5); + + for (i = 1; i < dst->num_points; i++) { + /* switch VLC according to the curve direction + * (ascending/descending) */ + tab = (dst->lev_code[i] <= dst->lev_code[i - 1]) + ? &gain_vlc_tabs[7] + : &gain_vlc_tabs[9]; + dst->loc_code[i] = dst->loc_code[i - 1] + + get_vlc2(gb, tab->table, tab->bits, 1); + } + } +} + +/** + * Decode location code for each gain control point. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @param[in] coded_subbands number of subbands to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_gainc_loc_codes(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num, int coded_subbands) +{ + int sb, i, delta, delta_bits, min_val, pred, more_than_ref; + AtracGainInfo *dst, *ref; + VLC *tab; + Atrac3pChanParams *chan = &ctx->channels[ch_num]; + Atrac3pChanParams *ref_chan = &ctx->channels[0]; + + switch (get_bits(gb, 2)) { /* switch according to coding mode */ + case 0: /* sequence of numbers in ascending order */ + for (sb = 0; sb < coded_subbands; sb++) + for (i = 0; i < chan->gain_data[sb].num_points; i++) + gainc_loc_mode0(gb, ctx, &chan->gain_data[sb], i); + break; + case 1: + if (ch_num) { + for (sb = 0; sb < coded_subbands; sb++) { + if (chan->gain_data[sb].num_points <= 0) + continue; + dst = &chan->gain_data[sb]; + ref = &ref_chan->gain_data[sb]; + + /* 1st value is vlc-coded modulo delta to master */ + delta = get_vlc2(gb, gain_vlc_tabs[10].table, + gain_vlc_tabs[10].bits, 1); + pred = ref->num_points > 0 ? ref->loc_code[0] : 0; + dst->loc_code[0] = (pred + delta) & 0x1F; + + for (i = 1; i < dst->num_points; i++) { + more_than_ref = i >= ref->num_points; + if (dst->lev_code[i] > dst->lev_code[i - 1]) { + /* ascending curve */ + if (more_than_ref) { + delta = + get_vlc2(gb, gain_vlc_tabs[9].table, + gain_vlc_tabs[9].bits, 1); + dst->loc_code[i] = dst->loc_code[i - 1] + delta; + } else { + if (get_bits1(gb)) + gainc_loc_mode0(gb, ctx, dst, i); // direct coding + else + dst->loc_code[i] = ref->loc_code[i]; // clone master + } + } else { /* descending curve */ + tab = more_than_ref ? &gain_vlc_tabs[7] + : &gain_vlc_tabs[10]; + delta = get_vlc2(gb, tab->table, tab->bits, 1); + if (more_than_ref) + dst->loc_code[i] = dst->loc_code[i - 1] + delta; + else + dst->loc_code[i] = (ref->loc_code[i] + delta) & 0x1F; + } + } + } + } else /* VLC delta to previous */ + for (sb = 0; sb < coded_subbands; sb++) + gainc_loc_mode1(gb, ctx, &chan->gain_data[sb]); + break; + case 2: + if (ch_num) { + for (sb = 0; sb < coded_subbands; sb++) { + if (chan->gain_data[sb].num_points <= 0) + continue; + dst = &chan->gain_data[sb]; + ref = &ref_chan->gain_data[sb]; + if (dst->num_points > ref->num_points || get_bits1(gb)) + gainc_loc_mode1(gb, ctx, dst); + else /* clone master for the whole subband */ + for (i = 0; i < chan->gain_data[sb].num_points; i++) + dst->loc_code[i] = ref->loc_code[i]; + } + } else { + /* data for the first subband is coded directly */ + for (i = 0; i < chan->gain_data[0].num_points; i++) + gainc_loc_mode0(gb, ctx, &chan->gain_data[0], i); + + for (sb = 1; sb < coded_subbands; sb++) { + if (chan->gain_data[sb].num_points <= 0) + continue; + dst = &chan->gain_data[sb]; + + /* 1st value is vlc-coded modulo delta to the corresponding + * value of the previous subband if any or zero */ + delta = get_vlc2(gb, gain_vlc_tabs[6].table, + gain_vlc_tabs[6].bits, 1); + pred = dst[-1].num_points > 0 + ? dst[-1].loc_code[0] : 0; + dst->loc_code[0] = (pred + delta) & 0x1F; + + for (i = 1; i < dst->num_points; i++) { + more_than_ref = i >= dst[-1].num_points; + /* Select VLC table according to curve direction and + * presence of prediction. */ + tab = &gain_vlc_tabs[(dst->lev_code[i] > dst->lev_code[i - 1]) * + 2 + more_than_ref + 6]; + delta = get_vlc2(gb, tab->table, tab->bits, 1); + if (more_than_ref) + dst->loc_code[i] = dst->loc_code[i - 1] + delta; + else + dst->loc_code[i] = (dst[-1].loc_code[i] + delta) & 0x1F; + } + } + } + break; + case 3: + if (ch_num) { /* clone master or direct or direct coding */ + for (sb = 0; sb < coded_subbands; sb++) + for (i = 0; i < chan->gain_data[sb].num_points; i++) { + if (i >= ref_chan->gain_data[sb].num_points) + gainc_loc_mode0(gb, ctx, &chan->gain_data[sb], i); + else + chan->gain_data[sb].loc_code[i] = + ref_chan->gain_data[sb].loc_code[i]; + } + } else { /* shorter delta to min */ + delta_bits = get_bits(gb, 2) + 1; + min_val = get_bits(gb, 5); + + for (sb = 0; sb < coded_subbands; sb++) + for (i = 0; i < chan->gain_data[sb].num_points; i++) + chan->gain_data[sb].loc_code[i] = min_val + i + + get_bits(gb, delta_bits); + } + break; + } + + /* Validate decoded information */ + for (sb = 0; sb < coded_subbands; sb++) { + dst = &chan->gain_data[sb]; + for (i = 0; i < chan->gain_data[sb].num_points; i++) { + if (dst->loc_code[i] < 0 || dst->loc_code[i] > 31 || + (i && dst->loc_code[i] <= dst->loc_code[i - 1])) { + av_log(AV_LOG_ERROR, + "Invalid gain location: ch=%d, sb=%d, pos=%d, val=%d\n", + ch_num, sb, i, dst->loc_code[i]); + return AVERROR_INVALIDDATA; + } + } + } + + return 0; +} + +/** + * Decode gain control data for all channels. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] num_channels number of channels to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_gainc_data(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels) +{ + int ch_num, coded_subbands, sb, ret; + + for (ch_num = 0; ch_num < num_channels; ch_num++) { + memset(ctx->channels[ch_num].gain_data, 0, + sizeof(*ctx->channels[ch_num].gain_data) * ATRAC3P_SUBBANDS); + + if (get_bits1(gb)) { /* gain control data present? */ + coded_subbands = get_bits(gb, 4) + 1; + if (get_bits1(gb)) /* is high band gain data replication on? */ + ctx->channels[ch_num].num_gain_subbands = get_bits(gb, 4) + 1; + else + ctx->channels[ch_num].num_gain_subbands = coded_subbands; + + if ((ret = decode_gainc_npoints(gb, ctx, ch_num, coded_subbands)) < 0 || + (ret = decode_gainc_levels(gb, ctx, ch_num, coded_subbands)) < 0 || + (ret = decode_gainc_loc_codes(gb, ctx, ch_num, coded_subbands)) < 0) + return ret; + + if (coded_subbands > 0) { /* propagate gain data if requested */ + for (sb = coded_subbands; sb < ctx->channels[ch_num].num_gain_subbands; sb++) + ctx->channels[ch_num].gain_data[sb] = + ctx->channels[ch_num].gain_data[sb - 1]; + } + } else { + ctx->channels[ch_num].num_gain_subbands = 0; + } + } + + return 0; +} + +/** + * Decode envelope for all tones of a channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @param[in] band_has_tones ptr to an array of per-band-flags: + * 1 - tone data present + */ +static void decode_tones_envelope(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num, int band_has_tones[]) +{ + int sb; + Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info; + Atrac3pWavesData *ref = ctx->channels[0].tones_info; + + if (!ch_num || !get_bits1(gb)) { /* mode 0: fixed-length coding */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb]) + continue; + dst[sb].pend_env.has_start_point = get_bits1(gb); + dst[sb].pend_env.start_pos = dst[sb].pend_env.has_start_point + ? get_bits(gb, 5) : -1; + dst[sb].pend_env.has_stop_point = get_bits1(gb); + dst[sb].pend_env.stop_pos = dst[sb].pend_env.has_stop_point + ? get_bits(gb, 5) : 32; + } + } else { /* mode 1(slave only): copy master */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb]) + continue; + dst[sb].pend_env.has_start_point = ref[sb].pend_env.has_start_point; + dst[sb].pend_env.has_stop_point = ref[sb].pend_env.has_stop_point; + dst[sb].pend_env.start_pos = ref[sb].pend_env.start_pos; + dst[sb].pend_env.stop_pos = ref[sb].pend_env.stop_pos; + } + } +} + +/** + * Decode number of tones for each subband of a channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @param[in] band_has_tones ptr to an array of per-band-flags: + * 1 - tone data present + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_band_numwavs(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num, int band_has_tones[]) +{ + int mode, sb, delta; + Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info; + Atrac3pWavesData *ref = ctx->channels[0].tones_info; + + mode = get_bits(gb, ch_num + 1); + switch (mode) { + case 0: /** fixed-length coding */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) + if (band_has_tones[sb]) + dst[sb].num_wavs = get_bits(gb, 4); + break; + case 1: /** variable-length coding */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) + if (band_has_tones[sb]) + dst[sb].num_wavs = + get_vlc2(gb, tone_vlc_tabs[1].table, + tone_vlc_tabs[1].bits, 1); + break; + case 2: /** VLC modulo delta to master (slave only) */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) + if (band_has_tones[sb]) { + delta = get_vlc2(gb, tone_vlc_tabs[2].table, + tone_vlc_tabs[2].bits, 1); + delta = sign_extend(delta, 3); + dst[sb].num_wavs = (ref[sb].num_wavs + delta) & 0xF; + } + break; + case 3: /** copy master (slave only) */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) + if (band_has_tones[sb]) + dst[sb].num_wavs = ref[sb].num_wavs; + break; + } + + /** initialize start tone index for each subband */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) + if (band_has_tones[sb]) { + if (ctx->waves_info->tones_index + dst[sb].num_wavs > 48) { + av_log(AV_LOG_ERROR, + "Too many tones: %d (max. 48)!\n", + ctx->waves_info->tones_index + dst[sb].num_wavs); + return AVERROR_INVALIDDATA; + } + dst[sb].start_index = ctx->waves_info->tones_index; + ctx->waves_info->tones_index += dst[sb].num_wavs; + } + + return 0; +} + +/** + * Decode frequency information for each subband of a channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @param[in] band_has_tones ptr to an array of per-band-flags: + * 1 - tone data present + */ +static void decode_tones_frequency(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num, int band_has_tones[]) +{ + int sb, i, direction, nbits, pred, delta; + Atrac3pWaveParam *iwav, *owav; + Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info; + Atrac3pWavesData *ref = ctx->channels[0].tones_info; + + if (!ch_num || !get_bits1(gb)) { /* mode 0: fixed-length coding */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb] || !dst[sb].num_wavs) + continue; + iwav = &ctx->waves_info->waves[dst[sb].start_index]; + direction = (dst[sb].num_wavs > 1) ? get_bits1(gb) : 0; + if (direction) { /** packed numbers in descending order */ + if (dst[sb].num_wavs) + iwav[dst[sb].num_wavs - 1].freq_index = get_bits(gb, 10); + for (i = dst[sb].num_wavs - 2; i >= 0 ; i--) { + nbits = av_log2(iwav[i+1].freq_index) + 1; + iwav[i].freq_index = get_bits(gb, nbits); + } + } else { /** packed numbers in ascending order */ + for (i = 0; i < dst[sb].num_wavs; i++) { + if (!i || iwav[i - 1].freq_index < 512) + iwav[i].freq_index = get_bits(gb, 10); + else { + nbits = av_log2(1023 - iwav[i - 1].freq_index) + 1; + iwav[i].freq_index = get_bits(gb, nbits) + + 1024 - (1 << nbits); + } + } + } + } + } else { /* mode 1: VLC modulo delta to master (slave only) */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb] || !dst[sb].num_wavs) + continue; + iwav = &ctx->waves_info->waves[ref[sb].start_index]; + owav = &ctx->waves_info->waves[dst[sb].start_index]; + for (i = 0; i < dst[sb].num_wavs; i++) { + delta = get_vlc2(gb, tone_vlc_tabs[6].table, + tone_vlc_tabs[6].bits, 1); + delta = sign_extend(delta, 8); + pred = (i < ref[sb].num_wavs) ? iwav[i].freq_index : + (ref[sb].num_wavs ? iwav[ref[sb].num_wavs - 1].freq_index : 0); + owav[i].freq_index = (pred + delta) & 0x3FF; + } + } + } +} + +/** + * Decode amplitude information for each subband of a channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @param[in] band_has_tones ptr to an array of per-band-flags: + * 1 - tone data present + */ +static void decode_tones_amplitude(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num, int band_has_tones[]) +{ + int mode, sb, j, i, diff, maxdiff, fi, delta, pred; + Atrac3pWaveParam *wsrc, *wref; + int refwaves[48] = { 0 }; + Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info; + Atrac3pWavesData *ref = ctx->channels[0].tones_info; + + if (ch_num) { + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb] || !dst[sb].num_wavs) + continue; + wsrc = &ctx->waves_info->waves[dst[sb].start_index]; + wref = &ctx->waves_info->waves[ref[sb].start_index]; + for (j = 0; j < dst[sb].num_wavs; j++) { + for (i = 0, fi = 0, maxdiff = 1024; i < ref[sb].num_wavs; i++) { + diff = FFABS(wsrc[j].freq_index - wref[i].freq_index); + if (diff < maxdiff) { + maxdiff = diff; + fi = i; + } + } + + if (maxdiff < 8) + refwaves[dst[sb].start_index + j] = fi + ref[sb].start_index; + else if (j < ref[sb].num_wavs) + refwaves[dst[sb].start_index + j] = j + ref[sb].start_index; + else + refwaves[dst[sb].start_index + j] = -1; + } + } + } + + mode = get_bits(gb, ch_num + 1); + + switch (mode) { + case 0: /** fixed-length coding */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb] || !dst[sb].num_wavs) + continue; + if (ctx->waves_info->amplitude_mode) + for (i = 0; i < dst[sb].num_wavs; i++) + ctx->waves_info->waves[dst[sb].start_index + i].amp_sf = get_bits(gb, 6); + else + ctx->waves_info->waves[dst[sb].start_index].amp_sf = get_bits(gb, 6); + } + break; + case 1: /** min + VLC delta */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb] || !dst[sb].num_wavs) + continue; + if (ctx->waves_info->amplitude_mode) + for (i = 0; i < dst[sb].num_wavs; i++) + ctx->waves_info->waves[dst[sb].start_index + i].amp_sf = + get_vlc2(gb, tone_vlc_tabs[3].table, + tone_vlc_tabs[3].bits, 1) + 20; + else + ctx->waves_info->waves[dst[sb].start_index].amp_sf = + get_vlc2(gb, tone_vlc_tabs[4].table, + tone_vlc_tabs[4].bits, 1) + 24; + } + break; + case 2: /** VLC modulo delta to master (slave only) */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb] || !dst[sb].num_wavs) + continue; + for (i = 0; i < dst[sb].num_wavs; i++) { + delta = get_vlc2(gb, tone_vlc_tabs[5].table, + tone_vlc_tabs[5].bits, 1); + delta = sign_extend(delta, 5); + pred = refwaves[dst[sb].start_index + i] >= 0 ? + ctx->waves_info->waves[refwaves[dst[sb].start_index + i]].amp_sf : 34; + ctx->waves_info->waves[dst[sb].start_index + i].amp_sf = (pred + delta) & 0x3F; + } + } + break; + case 3: /** clone master (slave only) */ + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb]) + continue; + for (i = 0; i < dst[sb].num_wavs; i++) + ctx->waves_info->waves[dst[sb].start_index + i].amp_sf = + refwaves[dst[sb].start_index + i] >= 0 + ? ctx->waves_info->waves[refwaves[dst[sb].start_index + i]].amp_sf + : 32; + } + break; + } +} + +/** + * Decode phase information for each subband of a channel. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] ch_num channel to process + * @param[in] band_has_tones ptr to an array of per-band-flags: + * 1 - tone data present + */ +static void decode_tones_phase(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int ch_num, int band_has_tones[]) +{ + int sb, i; + Atrac3pWaveParam *wparam; + Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info; + + for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) { + if (!band_has_tones[sb]) + continue; + wparam = &ctx->waves_info->waves[dst[sb].start_index]; + for (i = 0; i < dst[sb].num_wavs; i++) + wparam[i].phase_index = get_bits(gb, 5); + } +} + +/** + * Decode tones info for all channels. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] num_channels number of channels to process + * @return result code: 0 = OK, otherwise - error code + */ +static int decode_tones_info(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels) +{ + int ch_num, i, ret; + int band_has_tones[16]; + + for (ch_num = 0; ch_num < num_channels; ch_num++) + memset(ctx->channels[ch_num].tones_info, 0, + sizeof(*ctx->channels[ch_num].tones_info) * ATRAC3P_SUBBANDS); + + ctx->waves_info->tones_present = get_bits1(gb); + if (!ctx->waves_info->tones_present) + return 0; + + memset(ctx->waves_info->waves, 0, sizeof(ctx->waves_info->waves)); + + ctx->waves_info->amplitude_mode = get_bits1(gb); + if (!ctx->waves_info->amplitude_mode) { + avpriv_report_missing_feature(avctx, "GHA amplitude mode 0"); + return AVERROR_PATCHWELCOME; + } + + ctx->waves_info->num_tone_bands = + get_vlc2(gb, tone_vlc_tabs[0].table, + tone_vlc_tabs[0].bits, 1) + 1; + + if (num_channels == 2) { + get_subband_flags(gb, ctx->waves_info->tone_sharing, ctx->waves_info->num_tone_bands); + get_subband_flags(gb, ctx->waves_info->tone_master, ctx->waves_info->num_tone_bands); + get_subband_flags(gb, ctx->waves_info->invert_phase, ctx->waves_info->num_tone_bands); + } + + ctx->waves_info->tones_index = 0; + + for (ch_num = 0; ch_num < num_channels; ch_num++) { + for (i = 0; i < ctx->waves_info->num_tone_bands; i++) + band_has_tones[i] = !ch_num ? 1 : !ctx->waves_info->tone_sharing[i]; + + decode_tones_envelope(gb, ctx, ch_num, band_has_tones); + if ((ret = decode_band_numwavs(gb, ctx, ch_num, band_has_tones)) < 0) + return ret; + + decode_tones_frequency(gb, ctx, ch_num, band_has_tones); + decode_tones_amplitude(gb, ctx, ch_num, band_has_tones); + decode_tones_phase(gb, ctx, ch_num, band_has_tones); + } + + if (num_channels == 2) { + for (i = 0; i < ctx->waves_info->num_tone_bands; i++) { + if (ctx->waves_info->tone_sharing[i]) + ctx->channels[1].tones_info[i] = ctx->channels[0].tones_info[i]; + + if (ctx->waves_info->tone_master[i]) + FFSWAP(Atrac3pWavesData, ctx->channels[0].tones_info[i], + ctx->channels[1].tones_info[i]); + } + } + + return 0; +} + +int ff_atrac3p_decode_channel_unit(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels) +{ + int ret; + + /* parse sound header */ + ctx->num_quant_units = get_bits(gb, 5) + 1; + if (ctx->num_quant_units > 28 && ctx->num_quant_units < 32) { + av_log(AV_LOG_ERROR, + "Invalid number of quantization units: %d!\n", + ctx->num_quant_units); + return AVERROR_INVALIDDATA; + } + + ctx->mute_flag = get_bits1(gb); + + /* decode various sound parameters */ + if ((ret = decode_quant_wordlen(gb, ctx, num_channels)) < 0) + return ret; + + ctx->num_subbands = atrac3p_qu_to_subband[ctx->num_quant_units - 1] + 1; + ctx->num_coded_subbands = ctx->used_quant_units + ? atrac3p_qu_to_subband[ctx->used_quant_units - 1] + 1 + : 0; + + if ((ret = decode_scale_factors(gb, ctx, num_channels)) < 0) + return ret; + + if ((ret = decode_code_table_indexes(gb, ctx, num_channels)) < 0) + return ret; + + decode_spectrum(gb, ctx, num_channels); + + if (num_channels == 2) { + get_subband_flags(gb, ctx->swap_channels, ctx->num_coded_subbands); + get_subband_flags(gb, ctx->negate_coeffs, ctx->num_coded_subbands); + } + + decode_window_shape(gb, ctx, num_channels); + + if ((ret = decode_gainc_data(gb, ctx, num_channels)) < 0) + return ret; + + if ((ret = decode_tones_info(gb, ctx, num_channels)) < 0) + return ret; + + /* decode global noise info */ + ctx->noise_present = get_bits1(gb); + if (ctx->noise_present) { + ctx->noise_level_index = get_bits(gb, 4); + ctx->noise_table_index = get_bits(gb, 4); + } + + return 0; +} diff --git a/ext/at3_standalone/atrac3plus.h b/ext/at3_standalone/atrac3plus.h new file mode 100644 index 0000000000..c2d2759ca0 --- /dev/null +++ b/ext/at3_standalone/atrac3plus.h @@ -0,0 +1,236 @@ +/* + * ATRAC3+ compatible decoder + * + * Copyright (c) 2010-2013 Maxim Poliakovski + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Global structures, constants and data for ATRAC3+ decoder. + */ + +#ifndef AVCODEC_ATRAC3PLUS_H +#define AVCODEC_ATRAC3PLUS_H + +#include + +#include "float_dsp.h" +#include "atrac.h" +#include "fft.h" +#include "get_bits.h" + +/** Global unit sizes */ +#define ATRAC3P_SUBBANDS 16 ///< number of PQF subbands +#define ATRAC3P_SUBBAND_SAMPLES 128 ///< number of samples per subband +#define ATRAC3P_FRAME_SAMPLES (ATRAC3P_SUBBAND_SAMPLES * ATRAC3P_SUBBANDS) + +#define ATRAC3P_PQF_FIR_LEN 12 ///< length of the prototype FIR of the PQF + +/** Global constants */ +#define ATRAC3P_POWER_COMP_OFF 15 ///< disable power compensation + +/** ATRAC3+ channel unit types */ +enum Atrac3pChannelUnitTypes { + CH_UNIT_MONO = 0, ///< unit containing one coded channel + CH_UNIT_STEREO = 1, ///< unit containing two jointly-coded channels + CH_UNIT_EXTENSION = 2, ///< unit containing extension information + CH_UNIT_TERMINATOR = 3 ///< unit sequence terminator +}; + +/** Per-channel IPQF history */ +typedef struct Atrac3pIPQFChannelCtx { + DECLARE_ALIGNED(32, float, buf1)[ATRAC3P_PQF_FIR_LEN * 2][8]; + DECLARE_ALIGNED(32, float, buf2)[ATRAC3P_PQF_FIR_LEN * 2][8]; + int pos; +} Atrac3pIPQFChannelCtx; + +/** Amplitude envelope of a group of sine waves */ +typedef struct Atrac3pWaveEnvelope { + int has_start_point; ///< indicates start point within the GHA window + int has_stop_point; ///< indicates stop point within the GHA window + int start_pos; ///< start position expressed in n*4 samples + int stop_pos; ///< stop position expressed in n*4 samples +} Atrac3pWaveEnvelope; + +/** Parameters of a group of sine waves */ +typedef struct Atrac3pWavesData { + Atrac3pWaveEnvelope pend_env; ///< pending envelope from the previous frame + Atrac3pWaveEnvelope curr_env; ///< group envelope from the current frame + int num_wavs; ///< number of sine waves in the group + int start_index; ///< start index into global tones table for that subband +} Atrac3pWavesData; + +/** Parameters of a single sine wave */ +typedef struct Atrac3pWaveParam { + int freq_index; ///< wave frequency index + int amp_sf; ///< quantized amplitude scale factor + int amp_index; ///< quantized amplitude index + int phase_index; ///< quantized phase index +} Atrac3pWaveParam; + +/** Sound channel parameters */ +typedef struct Atrac3pChanParams { + int ch_num; + int num_coded_vals; ///< number of transmitted quant unit values + int fill_mode; + int split_point; + int table_type; ///< table type: 0 - tone?, 1- noise? + int qu_wordlen[32]; ///< array of word lengths for each quant unit + int qu_sf_idx[32]; ///< array of scale factor indexes for each quant unit + int qu_tab_idx[32]; ///< array of code table indexes for each quant unit + int16_t spectrum[2048]; ///< decoded IMDCT spectrum + uint8_t power_levs[5]; ///< power compensation levels + + /* imdct window shape history (2 frames) for overlapping. */ + uint8_t wnd_shape_hist[2][ATRAC3P_SUBBANDS]; ///< IMDCT window shape, 0=sine/1=steep + uint8_t *wnd_shape; ///< IMDCT window shape for current frame + uint8_t *wnd_shape_prev; ///< IMDCT window shape for previous frame + + /* gain control data history (2 frames) for overlapping. */ + AtracGainInfo gain_data_hist[2][ATRAC3P_SUBBANDS]; ///< gain control data for all subbands + AtracGainInfo *gain_data; ///< gain control data for next frame + AtracGainInfo *gain_data_prev; ///< gain control data for previous frame + int num_gain_subbands; ///< number of subbands with gain control data + + /* tones data history (2 frames) for overlapping. */ + Atrac3pWavesData tones_info_hist[2][ATRAC3P_SUBBANDS]; + Atrac3pWavesData *tones_info; + Atrac3pWavesData *tones_info_prev; +} Atrac3pChanParams; + +/* Per-unit sine wave parameters */ +typedef struct Atrac3pWaveSynthParams { + int tones_present; ///< 1 - tones info present + int amplitude_mode; ///< 1 - low range, 0 - high range + int num_tone_bands; ///< number of PQF bands with tones + uint8_t tone_sharing[ATRAC3P_SUBBANDS]; ///< 1 - subband-wise tone sharing flags + uint8_t tone_master[ATRAC3P_SUBBANDS]; ///< 1 - subband-wise tone channel swapping + uint8_t invert_phase[ATRAC3P_SUBBANDS]; ///< 1 - subband-wise phase inversion + int tones_index; ///< total sum of tones in this unit + Atrac3pWaveParam waves[48]; +} Atrac3pWaveSynthParams; + +/** Channel unit parameters */ +typedef struct Atrac3pChanUnitCtx { + /* channel unit variables */ + int unit_type; ///< unit type (mono/stereo) + int num_quant_units; + int num_subbands; + int used_quant_units; ///< number of quant units with coded spectrum + int num_coded_subbands; ///< number of subbands with coded spectrum + int mute_flag; ///< mute flag + int use_full_table; ///< 1 - full table list, 0 - restricted one + int noise_present; ///< 1 - global noise info present + int noise_level_index; ///< global noise level index + int noise_table_index; ///< global noise RNG table index + uint8_t swap_channels[ATRAC3P_SUBBANDS]; ///< 1 - perform subband-wise channel swapping + uint8_t negate_coeffs[ATRAC3P_SUBBANDS]; ///< 1 - subband-wise IMDCT coefficients negation + Atrac3pChanParams channels[2]; + + /* Variables related to GHA tones */ + Atrac3pWaveSynthParams wave_synth_hist[2]; ///< waves synth history for two frames + Atrac3pWaveSynthParams *waves_info; + Atrac3pWaveSynthParams *waves_info_prev; + + Atrac3pIPQFChannelCtx ipqf_ctx[2]; + DECLARE_ALIGNED(32, float, prev_buf)[2][ATRAC3P_FRAME_SAMPLES]; ///< overlapping buffer +} Atrac3pChanUnitCtx; + +/** + * Initialize VLC tables for bitstream parsing. + */ +void ff_atrac3p_init_vlcs(void); + +/** + * Decode bitstream data of a channel unit. + * + * @param[in] gb the GetBit context + * @param[in,out] ctx ptr to the channel unit context + * @param[in] num_channels number of channels to process + * @return result code: 0 = OK, otherwise - error code + */ +int ff_atrac3p_decode_channel_unit(GetBitContext *gb, Atrac3pChanUnitCtx *ctx, + int num_channels); + +/** + * Initialize IMDCT transform. + * + * @param[in] mdct_ctx pointer to MDCT transform context + */ +void ff_atrac3p_init_imdct(FFTContext *mdct_ctx); + +/** + * Initialize sine waves synthesizer. + */ +void ff_atrac3p_init_wave_synth(void); + +/** + * Synthesize sine waves for a particular subband. + * + * @param[in] ch_unit pointer to the channel unit context + * @param[in] fdsp pointer to float DSP context + * @param[in] ch_num which channel to process + * @param[in] sb which subband to process + * @param[out] out receives processed data + */ +void ff_atrac3p_generate_tones(Atrac3pChanUnitCtx *ch_unit, int ch_num, int sb, float *out); + +/** + * Perform power compensation aka noise dithering. + * + * @param[in] ctx ptr to the channel context + * @param[in] ch_index which channel to process + * @param[in,out] sp ptr to channel spectrum to process + * @param[in] rng_index indicates which RNG table to use + * @param[in] sb_num which subband to process + */ +void ff_atrac3p_power_compensation(Atrac3pChanUnitCtx *ctx, int ch_index, + float *sp, int rng_index, int sb_num); + +/** + * Regular IMDCT and windowing without overlapping, + * with spectrum reversal in the odd subbands. + * + * @param[in] fdsp pointer to float DSP context + * @param[in] mdct_ctx pointer to MDCT transform context + * @param[in] pIn float input + * @param[out] pOut float output + * @param[in] wind_id which MDCT window to apply + * @param[in] sb subband number + */ +void ff_atrac3p_imdct(FFTContext *mdct_ctx, float *pIn, + float *pOut, int wind_id, int sb); + +/** + * Subband synthesis filter based on the polyphase quadrature (pseudo-QMF) + * filter bank. + * + * @param[in] dct_ctx ptr to the pre-initialized IDCT context + * @param[in,out] hist ptr to the filter history + * @param[in] in input data to process + * @param[out] out receives processed data + */ +void ff_atrac3p_ipqf(FFTContext *dct_ctx, Atrac3pIPQFChannelCtx *hist, + const float *in, float *out); + +extern const uint16_t av_atrac3p_qu_to_spec_pos[33]; +extern const float av_atrac3p_sf_tab[64]; +extern const float av_atrac3p_mant_tab[8]; + +#endif /* AVCODEC_ATRAC3PLUS_H */ diff --git a/ext/at3_standalone/atrac3plus_data.h b/ext/at3_standalone/atrac3plus_data.h new file mode 100644 index 0000000000..2a107eef1f --- /dev/null +++ b/ext/at3_standalone/atrac3plus_data.h @@ -0,0 +1,1914 @@ +/* + * ATRAC3+ compatible decoder + * + * Copyright (c) 2010-2013 Maxim Poliakovski + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_ATRAC3PLUS_DATA_H +#define AVCODEC_ATRAC3PLUS_DATA_H + +#include +#include + +/** VLC tables for wordlen */ +static const uint8_t atrac3p_wl_huff_code1[3] = { 0, 2, 3 }; + +static const uint8_t atrac3p_wl_huff_bits1[3] = { 1, 2, 2 }; + +static const uint8_t atrac3p_wl_huff_xlat1[3] = { 0, 1, 7 }; + +static const uint8_t atrac3p_wl_huff_code2[5] = { 0, 4, 5, 6, 7 }; + +static const uint8_t atrac3p_wl_huff_bits2[5] = { 1, 3, 3, 3, 3 }; + +static const uint8_t atrac3p_wl_huff_xlat2[5] = { 0, 1, 2, 6, 7 }; + +static const uint8_t atrac3p_wl_huff_code3[8] = { + 0, 4, 0xC, 0x1E, 0x1F, 0xD, 0xE, 5 +}; + +static const uint8_t atrac3p_wl_huff_bits3[8] = { 1, 3, 4, 5, 5, 4, 4, 3 }; + +static const uint8_t atrac3p_wl_huff_code4[8] = { + 0, 4, 0xC, 0xD, 0x1E, 0x1F, 0xE, 5 +}; + +static const uint8_t atrac3p_wl_huff_bits4[8] = { 1, 3, 4, 4, 5, 5, 4, 3 }; + +/** VLC tables for scale factor indexes */ +static const uint16_t atrac3p_sf_huff_code1[64] = { + 0, 2, 3, 4, 5, 0xC, 0xD, 0xE0, + 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0x1CE, 0x1CF, + 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1D5, 0x1D6, 0x1D7, + 0x1D8, 0x1D9, 0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF, + 0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4, 0x1E5, 0x1E6, 0x1E7, + 0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x1EC, 0x1ED, 0x1EE, 0x1EF, + 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, 0x1F5, 0x1F6, 0x1F7, + 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, 0x1FD, 0x1FE, 0x1FF +}; + +static const uint8_t atrac3p_sf_huff_bits1[64] = { + 2, 3, 3, 3, 3, 4, 4, 8, 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 +}; + +static const uint8_t atrac3p_sf_huff_xlat1[64] = { + 0, 1, 61, 62, 63, 2, 60, 3, 4, 5, 6, 57, 58, 59, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 +}; + +static const uint8_t atrac3p_sf_huff_xlat2[64] = { + 0, 1, 2, 62, 63, 3, 61, 4, 5, 6, 57, 58, 59, 60, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 +}; + +static const uint16_t atrac3p_sf_huff_code2[64] = { + 0, 4, 0x18, 0x19, 0x70, 0x1CA, 0x1CB, 0x1CC, + 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, + 0x1D5, 0x1D6, 0x1D7, 0x1D8, 0x1D9, 0x1DA, 0x1DB, 0x1DC, + 0x1DD, 0x1DE, 0x1DF, 0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4, + 0x1E5, 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x1EC, + 0x1ED, 0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, + 0x1F5, 0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, + 0x1FD, 0x1FE, 0x1FF, 0xE4, 0x71, 0x1A, 0x1B, 5 +}; + +static const uint8_t atrac3p_sf_huff_bits2[64] = { + 1, 3, 5, 5, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 5, 5, 3 +}; + +static const uint16_t atrac3p_sf_huff_code3[64] = { + 0, 2, 3, 0x18, 0x19, 0x70, 0x1CC, 0x1CD, + 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1D5, + 0x1D6, 0x1D7, 0x1D8, 0x1D9, 0x1DA, 0x1DB, 0x1DC, 0x1DD, + 0x1DE, 0x1DF, 0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4, 0x1E5, + 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x1EC, 0x1ED, + 0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, 0x1F5, + 0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, 0x1FD, + 0x1FE, 0x1FF, 0x71, 0x72, 0x1A, 0x1B, 4, 5 +}; + +static const uint8_t atrac3p_sf_huff_bits3[64] = { + 2, 3, 3, 5, 5, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 5, 5, 3, 3 +}; + +static const uint16_t atrac3p_sf_huff_code4[16] = { + 0, 2, 3, 4, 5, 0xC, 0xD, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0, 0x3D, 0x3E, 0x3F +}; + +static const uint8_t atrac3p_sf_huff_bits4[16] = { + 2, 3, 3, 3, 3, 4, 4, 6, 6, 6, 6, 6, 0, 6, 6, 6 +}; + +static const uint8_t atrac3p_sf_huff_xlat4[16] = { + 0, 1, 13, 14, 15, 2, 12, 3, 4, 5, 6, 7, 8, 9, 10, 11 +}; + +static const uint8_t atrac3p_sf_huff_xlat5[16] = { + 0, 1, 2, 14, 15, 3, 13, 4, 5, 6, 7, 9, 8, 10, 11, 12 +}; + +static const uint16_t atrac3p_sf_huff_code5[16] = { + 0, 4, 0xC, 0x1C, 0x78, 0x79, 0x7A, 0x7B, + 0, 0x7C, 0x7D, 0x7E, 0x7F, 0x1D, 0xD, 5 +}; + +static const uint8_t atrac3p_sf_huff_bits5[16] = { + 1, 3, 4, 5, 7, 7, 7, 7, 0, 7, 7, 7, 7, 5, 4, 3 +}; + +static const uint16_t atrac3p_sf_huff_code6[16] = { + 0, 2, 3, 0xC, 0x1C, 0x3C, 0x7C, 0x7D, 0, 0x7E, 0x7F, 0x3D, 0x1D, 0xD, 4, 5 +}; + +static const uint8_t atrac3p_sf_huff_bits6[16] = { + 2, 3, 3, 4, 5, 6, 7, 7, 0, 7, 7, 6, 5, 4, 3, 3 +}; + +/** VLC tables for code table indexes */ +static const uint8_t atrac3p_ct_huff_code1[4] = { 0, 2, 6, 7 }; + +static const uint8_t atrac3p_ct_huff_bits1[4] = { 1, 2, 3, 3 }; + +static const uint8_t atrac3p_ct_huff_code2[8] = { 0, 2, 3, 4, 5, 6, 0xE, 0xF }; + +static const uint8_t atrac3p_ct_huff_bits2[8] = { 2, 3, 3, 3, 3, 3, 4, 4 }; + +static const uint8_t atrac3p_ct_huff_xlat1[8] = { 0, 1, 2, 3, 6, 7, 4, 5 }; + +static const uint8_t atrac3p_ct_huff_code3[8] = { + 0, 4, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF +}; + +static const uint8_t atrac3p_ct_huff_bits3[8] = { 1, 3, 4, 4, 4, 4, 4, 4 }; + +/* weights for quantized word lengths */ +static const int8_t atrac3p_wl_weights[6][32] = { + { 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, + { 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 6, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 2, 2, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +/* weights for quantized scale factors + * sf_weights[i] = i / (tab_idx + 1) + * where tab_idx = [1,2] */ +static const int8_t atrac3p_sf_weights[2][32] = { + { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15 }, + { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, + 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10 } +}; + +/** Ungroup table for word length segments. + * Numbers in this table tell which coeff belongs to which segment. */ +static const uint8_t atrac3p_qu_num_to_seg[32] = { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, + 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9 +}; + +/** Map quant unit number to subband number */ +static const uint8_t atrac3p_qu_to_subband[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +/** Map subband number to number of power compensation groups */ +static const int atrac3p_subband_to_num_powgrps[16] = { + 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5 +}; + +/** 3D base shape tables. The values are grouped together as follows: + * [num_start_values = 8][num_shape_tables = 16][num_seg_coeffs = 9] + * For each of the 8 start values there are 16 different shapes each + * 9 coefficients long. */ +static const int8_t atrac3p_wl_shapes[8][16][9] = { + { { 0, 0, 0, 0, 0, 0, 0, -2, -1 }, + { 0, 0, 0, 0, 0, 0, 0, -5, -1 }, + { 0, 0, 0, -7, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, -7, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, -5, 0, 0 }, + { 0, 0, 0, 0, -5, 0, 0, 0, 0 }, + { -7, -7, 0, 0, 0, 0, 0, 0, 0 }, + { 0, -7, 0, 0, 0, 0, 0, 0, 0 }, + { -2, -2, -5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, -2, -5, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, -2, -5, 0, 0 }, + { 0, 0, 0, -5, 0, 0, 0, 0, 0 }, + { 0, -2, -7, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, -2, -5, 0, 0, 0 }, + { 0, 0, 0, -5, -5, 0, 0, 0, 0 }, + { 0, 0, 0, -5, -2, 0, 0, 0, 0 } }, + { { -1, -5, -3, -2, -1, -1, 0, 0, 0 }, + { -2, -5, -3, -3, -2, -1, -1, 0, 0 }, + { 0, -1, -1, -1, 0, 0, 0, 0, 0 }, + { -1, -3, 0, 0, 0, 0, 0, 0, 0 }, + { -1, -2, 0, 0, 0, 0, 0, 0, 0 }, + { -1, -3, -1, 0, 0, 0, 0, 1, 1 }, + { -1, -5, -3, -3, -2, -1, 0, 0, 0 }, + { -1, -1, -4, -2, -2, -1, -1, 0, 0 }, + { -1, -1, -3, -2, -3, -1, -1, -1, 0 }, + { -1, -4, -2, -3, -1, 0, 0, 0, 0 }, + { 0, -1, -2, -2, -1, -1, 0, 0, 0 }, + { 0, -2, -1, 0, 0, 0, 0, 0, 0 }, + { -1, -1, 0, 0, 0, 0, 0, 0, 0 }, + { -1, -1, -3, -2, -2, -1, -1, -1, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, -1, -3, -2, -2, -1, -1, -1, 0 }, }, + { { -1, -2, 0, 1, 1, 1, 1, 1, 1 }, + { 0, -1, 1, 1, 1, 1, 1, 1, 1 }, + { 0, -2, 1, 1, 1, 1, 1, 1, 1 }, + { 0, -2, 0, 1, 1, 1, 1, 1, 1 }, + { -1, -1, 0, 1, 1, 1, 1, 1, 1 }, + { 0, 0, -1, 0, 1, 1, 1, 1, 1 }, + { -1, -1, 1, 1, 1, 1, 1, 1, 1 }, + { 0, 0, -1, 1, 1, 1, 1, 1, 1 }, + { 0, -1, 0, 1, 1, 1, 1, 1, 1 }, + { -1, -1, -1, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 1, 1, 1, 1, 1 }, + { 0, 0, 0, 1, 1, 1, 1, 1, 1 }, + { 0, -1, -1, 1, 1, 1, 1, 1, 1 }, + { 0, 1, 0, 1, 1, 1, 1, 1, 1 }, + { 0, -3, -2, 1, 1, 1, 1, 2, 2 }, + { -3, -5, -3, 2, 2, 2, 2, 2, 2 }, }, + { { -1, -2, 0, 2, 2, 2, 2, 2, 2 }, + { -1, -2, 0, 1, 2, 2, 2, 2, 2 }, + { 0, -2, 0, 2, 2, 2, 2, 2, 2 }, + { -1, 0, 1, 2, 2, 2, 2, 2, 2 }, + { 0, 0, 1, 2, 2, 2, 2, 2, 2 }, + { 0, -2, 0, 1, 2, 2, 2, 2, 2 }, + { 0, -1, 1, 2, 2, 2, 2, 2, 2 }, + { -1, -1, 0, 2, 2, 2, 2, 2, 2 }, + { -1, -1, 0, 1, 2, 2, 2, 2, 2 }, + { -1, -2, -1, 2, 2, 2, 2, 2, 2 }, + { 0, -1, 0, 2, 2, 2, 2, 2, 2 }, + { 1, 1, 0, 1, 2, 2, 2, 2, 2 }, + { 0, 1, 2, 2, 2, 2, 2, 2, 2 }, + { 1, 0, 0, 1, 2, 2, 2, 2, 2 }, + { 0, 0, 0, 1, 2, 2, 2, 2, 2 }, + { -1, -1, -1, 1, 2, 2, 2, 2, 2 }, }, + { { 0, 1, 2, 3, 3, 3, 3, 3, 3 }, + { 1, 1, 2, 3, 3, 3, 3, 3, 3 }, + { -1, 0, 1, 2, 3, 3, 3, 3, 3 }, + { 0, 0, 2, 3, 3, 3, 3, 3, 3 }, + { -1, 0, 1, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 1, 3, 3, 3, 3, 3, 3 }, + { 1, 2, 3, 3, 3, 3, 3, 3, 3 }, + { 1, 2, 2, 3, 3, 3, 3, 3, 3 }, + { 0, 1, 1, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 1, 2, 3, 3, 3, 3, 3 }, + { -1, 1, 2, 3, 3, 3, 3, 3, 3 }, + { -1, 0, 2, 3, 3, 3, 3, 3, 3 }, + { 2, 2, 3, 3, 3, 3, 3, 3, 3 }, + { 1, 1, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 2, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 1, 1, 2, 3, 3, 3, 3, 3 }, }, + { { 0, 1, 2, 3, 4, 4, 4, 4, 4 }, + { 1, 2, 3, 4, 4, 4, 4, 4, 4 }, + { 0, 0, 2, 3, 4, 4, 4, 4, 4 }, + { 1, 1, 2, 4, 4, 4, 4, 4, 4 }, + { 0, 1, 2, 4, 4, 4, 4, 4, 4 }, + { -1, 0, 1, 3, 4, 4, 4, 4, 4 }, + { 0, 0, 1, 3, 4, 4, 4, 4, 4 }, + { 1, 1, 2, 3, 4, 4, 4, 4, 4 }, + { 0, 1, 1, 3, 4, 4, 4, 4, 4 }, + { 2, 2, 3, 4, 4, 4, 4, 4, 4 }, + { 1, 1, 3, 4, 4, 4, 4, 4, 4 }, + { 1, 2, 2, 4, 4, 4, 4, 4, 4 }, + { -1, 0, 2, 3, 4, 4, 4, 4, 4 }, + { 0, 1, 3, 4, 4, 4, 4, 4, 4 }, + { 1, 2, 2, 3, 4, 4, 4, 4, 4 }, + { 0, 2, 3, 4, 4, 4, 4, 4, 4 }, }, + { { 1, 2, 3, 4, 5, 5, 5, 5, 5 }, + { 0, 1, 2, 3, 4, 5, 5, 5, 5 }, + { 0, 1, 2, 3, 5, 5, 5, 5, 5 }, + { 1, 1, 3, 4, 5, 5, 5, 5, 5 }, + { 1, 1, 2, 4, 5, 5, 5, 5, 5 }, + { 1, 2, 2, 4, 5, 5, 5, 5, 5 }, + { 1, 1, 2, 3, 5, 5, 5, 5, 5 }, + { 2, 2, 3, 4, 5, 5, 5, 5, 5 }, + { 0, 1, 2, 4, 5, 5, 5, 5, 5 }, + { 2, 2, 3, 5, 5, 5, 5, 5, 5 }, + { 1, 2, 3, 5, 5, 5, 5, 5, 5 }, + { 0, 1, 3, 4, 5, 5, 5, 5, 5 }, + { 1, 2, 2, 3, 5, 5, 5, 5, 5 }, + { 2, 3, 4, 5, 5, 5, 5, 5, 5 }, + { 0, 2, 3, 4, 5, 5, 5, 5, 5 }, + { 1, 1, 1, 3, 4, 5, 5, 5, 5 }, }, + { { 1, 2, 3, 4, 5, 5, 5, 6, 6 }, + { 1, 2, 3, 4, 5, 6, 6, 6, 6 }, + { 2, 3, 4, 5, 6, 6, 6, 6, 6 }, + { 1, 2, 3, 4, 6, 6, 6, 6, 6 }, + { 2, 2, 3, 4, 5, 5, 5, 6, 6 }, + { 1, 2, 3, 4, 5, 5, 6, 6, 6 }, + { 2, 2, 3, 4, 6, 6, 6, 6, 6 }, + { 2, 2, 3, 4, 5, 6, 6, 6, 6 }, + { 2, 2, 4, 5, 6, 6, 6, 6, 6 }, + { 2, 2, 3, 5, 6, 6, 6, 6, 6 }, + { 1, 2, 3, 5, 6, 6, 6, 6, 6 }, + { 2, 3, 3, 5, 6, 6, 6, 6, 6 }, + { 1, 2, 4, 5, 6, 6, 6, 6, 6 }, + { 2, 2, 3, 4, 5, 5, 6, 6, 6 }, + { 2, 3, 3, 4, 6, 6, 6, 6, 6 }, + { 1, 3, 4, 5, 6, 6, 6, 6, 6 } } +}; + +/** 2D base shape tables for scale factor coding. + * The values are grouped together as follows: + * [num_shape_tables = 64][num_seg_coeffs = 9] */ +static const int8_t atrac3p_sf_shapes[64][9] = { + { -3, -2, -1, 0, 3, 5, 6, 8, 40 }, + { -3, -2, 0, 1, 7, 9, 11, 13, 20 }, + { -1, 0, 0, 1, 6, 8, 10, 13, 41 }, + { 0, 0, 0, 2, 5, 5, 6, 8, 14 }, + { 0, 0, 0, 2, 6, 7, 8, 11, 47 }, + { 0, 0, 1, 2, 5, 7, 8, 10, 32 }, + { 0, 0, 1, 3, 8, 10, 12, 14, 47 }, + { 0, 0, 2, 4, 9, 10, 12, 14, 40 }, + { 0, 0, 3, 5, 9, 10, 12, 14, 22 }, + { 0, 1, 3, 5, 10, 14, 18, 22, 31 }, + { 0, 2, 5, 6, 10, 10, 10, 12, 46 }, + { 0, 2, 5, 7, 12, 14, 15, 18, 44 }, + { 1, 1, 4, 5, 7, 7, 8, 9, 15 }, + { 1, 2, 2, 2, 4, 5, 7, 9, 26 }, + { 1, 2, 2, 3, 6, 7, 7, 8, 47 }, + { 1, 2, 2, 3, 6, 8, 10, 13, 22 }, + { 1, 3, 4, 7, 13, 17, 21, 24, 41 }, + { 1, 4, 0, 4, 10, 12, 13, 14, 17 }, + { 2, 3, 3, 3, 6, 8, 10, 13, 48 }, + { 2, 3, 3, 4, 9, 12, 14, 17, 47 }, + { 2, 3, 3, 5, 10, 12, 14, 17, 25 }, + { 2, 3, 5, 7, 8, 9, 9, 9, 13 }, + { 2, 3, 5, 9, 16, 21, 25, 28, 33 }, + { 2, 4, 5, 8, 12, 14, 17, 19, 26 }, + { 2, 4, 6, 8, 12, 13, 13, 15, 20 }, + { 2, 4, 7, 12, 20, 26, 30, 32, 35 }, + { 3, 3, 5, 6, 12, 14, 16, 19, 34 }, + { 3, 4, 4, 5, 7, 9, 10, 11, 48 }, + { 3, 4, 5, 6, 8, 9, 10, 11, 16 }, + { 3, 5, 5, 5, 7, 9, 10, 13, 35 }, + { 3, 5, 5, 7, 10, 12, 13, 15, 49 }, + { 3, 5, 7, 7, 8, 7, 9, 12, 21 }, + { 3, 5, 7, 8, 12, 14, 15, 15, 24 }, + { 3, 5, 7, 10, 16, 21, 24, 27, 44 }, + { 3, 5, 8, 14, 21, 26, 28, 29, 42 }, + { 3, 6, 10, 13, 18, 19, 20, 22, 27 }, + { 3, 6, 11, 16, 24, 27, 28, 29, 31 }, + { 4, 5, 4, 3, 4, 6, 8, 11, 18 }, + { 4, 6, 5, 6, 9, 10, 12, 14, 20 }, + { 4, 6, 7, 6, 6, 6, 7, 8, 46 }, + { 4, 6, 7, 9, 13, 16, 18, 20, 48 }, + { 4, 6, 7, 9, 14, 17, 20, 23, 31 }, + { 4, 6, 9, 11, 14, 15, 15, 17, 21 }, + { 4, 8, 13, 20, 27, 32, 35, 36, 38 }, + { 5, 6, 6, 4, 5, 6, 7, 6, 6 }, + { 5, 7, 7, 8, 9, 9, 10, 12, 49 }, + { 5, 8, 9, 9, 10, 11, 12, 13, 42 }, + { 5, 8, 10, 12, 15, 16, 17, 19, 42 }, + { 5, 8, 12, 17, 26, 31, 32, 33, 44 }, + { 5, 9, 13, 16, 20, 22, 23, 23, 35 }, + { 6, 8, 8, 7, 6, 5, 6, 8, 15 }, + { 6, 8, 8, 8, 9, 10, 12, 16, 24 }, + { 6, 8, 8, 9, 10, 10, 11, 11, 13 }, + { 6, 8, 10, 13, 19, 21, 24, 26, 32 }, + { 6, 9, 10, 11, 13, 13, 14, 16, 49 }, + { 7, 9, 9, 10, 13, 14, 16, 19, 27 }, + { 7, 10, 12, 13, 16, 16, 17, 17, 27 }, + { 7, 10, 12, 14, 17, 19, 20, 22, 48 }, + { 8, 9, 10, 9, 10, 11, 11, 11, 19 }, + { 8, 11, 12, 12, 13, 13, 13, 13, 17 }, + { 8, 11, 13, 14, 16, 17, 19, 20, 27 }, + { 8, 12, 17, 22, 26, 28, 29, 30, 33 }, + { 10, 14, 16, 19, 21, 22, 22, 24, 28 }, + { 10, 15, 17, 18, 21, 22, 23, 25, 43 } +}; + +static const uint8_t atrac3p_ct_restricted_to_full[2][7][4] = { + { { 0, 5, 4, 1 }, + { 0, 1, 2, 3 }, + { 3, 0, 4, 2 }, + { 4, 0, 1, 2 }, + { 1, 0, 4, 3 }, + { 3, 0, 2, 1 }, + { 0, 3, 1, 2 } }, + { { 4, 0, 1, 2 }, + { 0, 3, 2, 1 }, + { 0, 1, 2, 3 }, + { 0, 1, 2, 4 }, + { 0, 1, 2, 3 }, + { 1, 4, 2, 0 }, + { 0, 1, 2, 3 } } +}; + +/** Tables for spectrum coding */ +static const uint8_t huff_a01_cb[14] = { + 1, 12, 1, 0, 0, 1, 7, 0, 19, 5, 13, 21, 6, 8 +}; + +static const uint8_t huff_a01_xlat[81] = { + 0x00, 0x03, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x50, 0xD0, 0x70, + 0xF0, 0xC4, 0x14, 0x34, 0x4C, 0x1C, 0x3C, 0x41, 0xC1, 0x31, 0x05, 0x0D, + 0xC3, 0x13, 0x07, 0x0F, 0x44, 0xCC, 0x11, 0x43, 0x33, 0x54, 0x74, 0xDC, + 0xFC, 0x71, 0x15, 0x4D, 0xCD, 0x1D, 0xD3, 0xC7, 0x37, 0x3F, 0xD4, 0xF4, + 0x5C, 0x7C, 0x51, 0xD1, 0xF1, 0x45, 0xC5, 0x35, 0xDD, 0x3D, 0x53, 0x73, + 0xF3, 0x47, 0x17, 0x77, 0x4F, 0xCF, 0x1F, 0x55, 0xF5, 0x7D, 0xD7, 0x5F, + 0xFF, 0xD5, 0x75, 0x5D, 0xFD, 0x57, 0xF7, 0xDF, 0x7F +}; + +static const uint8_t huff_a02_cb[13] = { + 2, 12, 1, 0, 4, 11, 0, 1, 29, 6, 20, 7, 2 +}; + +static const uint8_t huff_a02_xlat[81] = { + 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x51, + 0x05, 0x45, 0x15, 0x55, 0x90, 0x80, 0x20, 0x60, 0x84, 0x94, 0x24, 0x64, + 0x08, 0x48, 0x18, 0x58, 0x81, 0x91, 0x21, 0x85, 0x95, 0x65, 0x09, 0x49, + 0x19, 0x59, 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 0x88, 0x61, + 0x25, 0x29, 0x69, 0x5A, 0xA0, 0xA4, 0x98, 0x28, 0x68, 0xA1, 0xA5, 0x89, + 0x99, 0xA9, 0x82, 0x92, 0x22, 0x62, 0x96, 0x26, 0x66, 0x0A, 0x4A, 0x1A, + 0xA8, 0x86, 0xA6, 0x8A, 0x9A, 0x2A, 0x6A, 0xA2, 0xAA +}; + +static const uint8_t huff_a03_cb[9] = { 3, 9, 1, 8, 0, 13, 18, 7, 2 }; + +static const uint8_t huff_a03_xlat[49] = { + 0x00, 0x08, 0x38, 0x01, 0x09, 0x39, 0x07, 0x0F, 0x3F, 0x10, 0x30, 0x11, + 0x31, 0x02, 0x0A, 0x3A, 0x05, 0x06, 0x0E, 0x3E, 0x17, 0x37, 0x18, 0x28, + 0x19, 0x29, 0x2A, 0x32, 0x03, 0x0B, 0x33, 0x3B, 0x0D, 0x15, 0x3D, 0x16, + 0x1E, 0x36, 0x1F, 0x2F, 0x12, 0x1A, 0x13, 0x2B, 0x1D, 0x35, 0x2E, 0x1B, + 0x2D +}; + +static const uint8_t huff_a04_cb[4] = { 2, 3, 2, 4 }; +static const uint8_t huff_a04_xlat[6] = { 1, 2, 0, 3, 4, 5 }; + +static const uint8_t huff_a05_cb[12] = { + 3, 12, 1, 3, 5, 8, 12, 23, 72, 68, 31, 2 +}; + +static const uint8_t huff_a05_xlat[225] = { + 0x00, 0x10, 0xF0, 0x01, 0x11, 0xF1, 0x0F, 0x1F, 0xFF, 0x20, 0xE0, 0xE1, + 0x02, 0xF2, 0x0E, 0x1E, 0x2F, 0x30, 0xD0, 0x21, 0x12, 0x22, 0xE2, 0x03, + 0x0D, 0x2E, 0xEE, 0xFE, 0xEF, 0x40, 0xC0, 0x31, 0xC1, 0xD1, 0x32, 0xD2, + 0x13, 0x23, 0xE3, 0xF3, 0x04, 0xF4, 0x0C, 0x1C, 0x1D, 0x2D, 0xED, 0xFD, + 0x3E, 0xDE, 0x3F, 0xDF, 0x50, 0x60, 0x70, 0x90, 0xA0, 0xB0, 0x41, 0x51, + 0x61, 0x71, 0x91, 0xA1, 0xB1, 0x42, 0x62, 0x92, 0xA2, 0xC2, 0x33, 0xC3, + 0xD3, 0x14, 0x24, 0x34, 0xD4, 0xE4, 0x05, 0x15, 0xF5, 0x06, 0x16, 0x26, + 0xE6, 0xF6, 0x07, 0x17, 0xE7, 0xF7, 0x09, 0x19, 0x29, 0xF9, 0x0A, 0x1A, + 0x2A, 0xEA, 0xFA, 0x0B, 0x1B, 0xFB, 0x2C, 0x3C, 0xDC, 0xEC, 0xFC, 0x3D, + 0x4D, 0xCD, 0xDD, 0x4E, 0x6E, 0x7E, 0xAE, 0xCE, 0x4F, 0x5F, 0x6F, 0x7F, + 0x9F, 0xAF, 0xBF, 0xCF, 0x52, 0x72, 0xB2, 0x43, 0x53, 0x63, 0x73, 0x93, + 0xA3, 0xB3, 0x44, 0x64, 0x74, 0x94, 0xA4, 0xB4, 0xC4, 0x25, 0x35, 0xA5, + 0xC5, 0xD5, 0xE5, 0x36, 0x46, 0xB6, 0xC6, 0xD6, 0x27, 0x37, 0x47, 0xB7, + 0xC7, 0xD7, 0x39, 0x49, 0x59, 0xC9, 0xD9, 0xE9, 0x3A, 0x4A, 0x5A, 0xCA, + 0xDA, 0x2B, 0x3B, 0x4B, 0x6B, 0x7B, 0xDB, 0xEB, 0x4C, 0x5C, 0x6C, 0x7C, + 0x9C, 0xAC, 0xCC, 0x5D, 0x6D, 0x7D, 0x9D, 0xAD, 0xBD, 0x5E, 0x9E, 0xBE, + 0x54, 0x45, 0x55, 0x65, 0x75, 0x95, 0xB5, 0x56, 0x66, 0x76, 0x96, 0xA6, + 0x57, 0x67, 0x97, 0xA7, 0x69, 0x79, 0xA9, 0xB9, 0x6A, 0x7A, 0x9A, 0xAA, + 0xBA, 0x5B, 0x9B, 0xAB, 0xBB, 0xCB, 0xBC, 0x77, 0x99 +}; + +static const uint8_t huff_a06_cb[7] = { + 2, 6, 1, 3, 2, 6, 4 +}; + +static const uint8_t huff_a06_xlat[16] = { + 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 10, 11, 12, 15 +}; + +static const uint8_t huff_a07_cb[11] = { + 2, 10, 1, 2, 2, 2, 6, 14, 21, 13, 2 +}; + +static const uint8_t huff_a07_xlat[63] = { + 0, 1, 63, 2, 62, 3, 61, 4, 5, 6, 58, 59, 60, 7, 8, 9, + 10, 26, 27, 28, 36, 37, 38, 54, 55, 56, 57, 11, 12, 13, 14, 15, + 16, 25, 29, 30, 31, 33, 34, 35, 39, 47, 48, 49, 50, 51, 52, 53, + 17, 18, 19, 20, 21, 22, 23, 41, 42, 43, 44, 45, 46, 24, 40 +}; + +static const uint8_t huff_a11_cb[13] = { + 1, 11, 1, 0, 0, 0, 8, 1, 18, 9, 22, 10, 12 +}; + +static const uint8_t huff_a11_xlat[81] = { + 0x00, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x03, 0xD0, 0x50, 0x70, + 0xF0, 0xC4, 0x34, 0x4C, 0xCC, 0x1C, 0x41, 0xC1, 0x31, 0x05, 0x0D, 0x43, + 0xC3, 0x13, 0x07, 0x0F, 0x44, 0x14, 0x74, 0xDC, 0x3C, 0x11, 0x1D, 0x33, + 0x37, 0x54, 0xD4, 0xF4, 0x5C, 0x7C, 0xFC, 0xD1, 0x71, 0xF1, 0x15, 0x35, + 0x4D, 0xCD, 0xDD, 0x3D, 0xD3, 0x73, 0x47, 0xC7, 0x17, 0x77, 0x3F, 0x51, + 0x45, 0xC5, 0x55, 0x53, 0xF3, 0x4F, 0xCF, 0x1F, 0xFF, 0xD5, 0x75, 0xF5, + 0x5D, 0x7D, 0xFD, 0x57, 0xD7, 0xF7, 0x5F, 0xDF, 0x7F +}; + +static const uint8_t huff_a12_cb[8] = { 5, 10, 16, 11, 32, 19, 1, 2 }; + +static const uint8_t huff_a12_xlat[81] = { + 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 0x01, 0x41, 0x11, 0x51, + 0x05, 0x45, 0x15, 0x55, 0x90, 0x94, 0x58, 0x91, 0x95, 0x19, 0x59, 0x06, + 0x46, 0x16, 0x56, 0x80, 0x60, 0x84, 0x24, 0x64, 0xA4, 0x08, 0x48, 0x18, + 0x68, 0x81, 0x21, 0x61, 0xA1, 0x85, 0x25, 0x65, 0xA5, 0x09, 0x49, 0x99, + 0x69, 0xA9, 0x02, 0x42, 0x12, 0x52, 0x96, 0x26, 0x66, 0x1A, 0x5A, 0x20, + 0xA0, 0x88, 0x98, 0x28, 0xA8, 0x89, 0x29, 0x82, 0x92, 0x22, 0x62, 0x86, + 0xA6, 0x0A, 0x4A, 0x9A, 0x6A, 0xAA, 0xA2, 0x8A, 0x2A +}; + +static const uint8_t huff_a13_cb[12] = { + 1, 10, 1, 0, 0, 4, 2, 2, 9, 15, 12, 4 +}; + +static const uint8_t huff_a13_xlat[49] = { + 0x00, 0x08, 0x38, 0x01, 0x07, 0x39, 0x0F, 0x09, 0x3F, 0x10, 0x30, 0x31, + 0x02, 0x3A, 0x06, 0x0E, 0x3E, 0x17, 0x18, 0x28, 0x11, 0x29, 0x0A, 0x32, + 0x03, 0x0B, 0x3B, 0x05, 0x0D, 0x3D, 0x16, 0x1F, 0x37, 0x19, 0x12, 0x1A, + 0x2A, 0x13, 0x33, 0x15, 0x35, 0x1E, 0x2E, 0x36, 0x2F, 0x1B, 0x2B, 0x1D, + 0x2D +}; + +static const uint8_t huff_a14_cb[12] = { + 2, 11, 1, 0, 4, 3, 5, 16, 28, 34, 26, 4 +}; + +static const uint8_t huff_a14_xlat[121] = { + 0x00, 0x10, 0xF0, 0x01, 0x0F, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x11, 0x02, + 0x0E, 0x30, 0x50, 0xB0, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x03, 0x05, 0x0B, + 0x0D, 0x1E, 0xFE, 0x2F, 0xEF, 0x40, 0xC0, 0x31, 0x51, 0xB1, 0xC1, 0xD1, + 0x22, 0x52, 0xE2, 0x13, 0xF3, 0x04, 0x15, 0xF5, 0x1B, 0xEB, 0xFB, 0x0C, + 0x1D, 0xFD, 0x2E, 0x5E, 0xEE, 0x3F, 0x5F, 0xBF, 0xDF, 0x41, 0x32, 0x42, + 0xB2, 0xD2, 0x23, 0x53, 0xB3, 0xE3, 0x14, 0x24, 0xE4, 0xF4, 0x25, 0x35, + 0xD5, 0xE5, 0x2B, 0x3B, 0xDB, 0x1C, 0x2C, 0xBC, 0xEC, 0xFC, 0x2D, 0xBD, + 0xED, 0x3E, 0x4E, 0xBE, 0xDE, 0x4F, 0xCF, 0xC2, 0x33, 0x43, 0xC3, 0xD3, + 0x34, 0x44, 0x54, 0xB4, 0xD4, 0x45, 0x55, 0xC5, 0x4B, 0xCB, 0x3C, 0x4C, + 0x5C, 0xCC, 0xDC, 0x3D, 0x4D, 0x5D, 0xCD, 0xDD, 0xCE, 0xC4, 0xB5, 0x5B, + 0xBB +}; + +static const uint8_t huff_a15_cb[9] = { 5, 11, 9, 12, 16, 44, 98, 42, 4 }; + +static const uint8_t huff_a15_xlat[225] = { + 0x00, 0x10, 0xF0, 0x01, 0x11, 0xF1, 0x0F, 0x1F, 0xFF, 0x20, 0xE0, 0x21, + 0xE1, 0x02, 0x12, 0xF2, 0x0E, 0x1E, 0xFE, 0x2F, 0xEF, 0x30, 0xD0, 0x31, + 0xD1, 0x22, 0xE2, 0x03, 0x13, 0xF3, 0x0D, 0x1D, 0xFD, 0x2E, 0xEE, 0x3F, + 0xDF, 0x40, 0x60, 0x70, 0x90, 0xA0, 0xC0, 0x41, 0xC1, 0x32, 0x42, 0xC2, + 0xD2, 0x23, 0x33, 0xD3, 0xE3, 0x04, 0x14, 0x24, 0xE4, 0xF4, 0x06, 0x16, + 0xF6, 0x07, 0x09, 0x0A, 0x1A, 0xFA, 0x0C, 0x1C, 0x2C, 0xEC, 0xFC, 0x2D, + 0x3D, 0xDD, 0xED, 0x3E, 0x4E, 0xCE, 0xDE, 0x4F, 0xCF, 0x50, 0xB0, 0x51, + 0x61, 0x71, 0x91, 0xA1, 0xB1, 0x52, 0x62, 0x72, 0x92, 0xA2, 0xB2, 0x43, + 0x53, 0x63, 0x73, 0x93, 0xA3, 0xC3, 0x34, 0x44, 0x64, 0xA4, 0xC4, 0xD4, + 0x05, 0x15, 0x25, 0x35, 0xD5, 0xE5, 0xF5, 0x26, 0x36, 0x46, 0xC6, 0xD6, + 0xE6, 0x17, 0x27, 0x37, 0xC7, 0xD7, 0xE7, 0xF7, 0x19, 0x29, 0x39, 0xC9, + 0xD9, 0xE9, 0xF9, 0x2A, 0x3A, 0x4A, 0x5A, 0xCA, 0xDA, 0xEA, 0x0B, 0x1B, + 0x2B, 0x3B, 0xCB, 0xDB, 0xEB, 0xFB, 0x3C, 0x4C, 0x6C, 0x7C, 0x9C, 0xAC, + 0xBC, 0xCC, 0xDC, 0x4D, 0x5D, 0x6D, 0x7D, 0x9D, 0xAD, 0xBD, 0xCD, 0x5E, + 0x6E, 0x7E, 0x9E, 0xAE, 0xBE, 0x5F, 0x6F, 0x7F, 0x9F, 0xAF, 0xBF, 0xB3, + 0x54, 0x74, 0x94, 0xB4, 0x45, 0x55, 0x65, 0x75, 0x95, 0xA5, 0xB5, 0xC5, + 0x56, 0x66, 0x76, 0x96, 0xA6, 0xB6, 0x47, 0x57, 0x67, 0xA7, 0xB7, 0x49, + 0x59, 0x69, 0xA9, 0xB9, 0x6A, 0x7A, 0x9A, 0xAA, 0xBA, 0x4B, 0x5B, 0x6B, + 0x7B, 0x9B, 0xAB, 0xBB, 0x5C, 0x77, 0x97, 0x79, 0x99 +}; + +static const uint8_t huff_a16_cb[13] = { + 2, 12, 1, 1, 2, 2, 5, 7, 21, 54, 85, 62, 16 +}; + +static const uint8_t huff_a16_xlat[256] = { + 0x00, 0x01, 0x10, 0x11, 0x21, 0x12, 0x20, 0x31, 0x02, 0x22, 0x13, 0x30, + 0x41, 0x32, 0x03, 0x23, 0x14, 0x24, 0x40, 0x51, 0x61, 0xD1, 0xE1, 0x42, + 0x52, 0xD2, 0x33, 0x43, 0xD3, 0x04, 0x34, 0x05, 0x15, 0x25, 0x16, 0x1D, + 0x2D, 0x1E, 0x2E, 0x50, 0x60, 0xD0, 0xE0, 0xF0, 0x71, 0x81, 0xF1, 0x62, + 0x72, 0xE2, 0xF2, 0x53, 0x63, 0xE3, 0xF3, 0x44, 0x54, 0xD4, 0xE4, 0xF4, + 0x35, 0x45, 0x55, 0xD5, 0xE5, 0xF5, 0x06, 0x26, 0x36, 0xD6, 0x07, 0x17, + 0x27, 0x37, 0xD7, 0x18, 0x28, 0x1C, 0x0D, 0x3D, 0x4D, 0x5D, 0x6D, 0x8D, + 0x0E, 0x3E, 0x4E, 0x5E, 0x0F, 0x1F, 0x2F, 0x3F, 0x5F, 0x70, 0x80, 0x90, + 0xC0, 0x91, 0xA1, 0xB1, 0xC1, 0x82, 0x92, 0xA2, 0xC2, 0x73, 0x83, 0x93, + 0xA3, 0xC3, 0x64, 0x74, 0x84, 0x94, 0xA4, 0xC4, 0x65, 0x75, 0x85, 0x46, + 0x56, 0x66, 0xC6, 0xE6, 0xF6, 0x47, 0x57, 0xE7, 0xF7, 0x08, 0x38, 0x48, + 0x58, 0x68, 0xD8, 0xE8, 0xF8, 0x09, 0x19, 0x29, 0x39, 0x59, 0xD9, 0xE9, + 0xF9, 0x1A, 0x2A, 0x3A, 0xDA, 0xEA, 0xFA, 0x1B, 0x2B, 0xDB, 0xEB, 0xFB, + 0x0C, 0x2C, 0x3C, 0xDC, 0xEC, 0x7D, 0x9D, 0xAD, 0xBD, 0xCD, 0x6E, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0x4F, 0x6F, 0x7F, 0x8F, 0xAF, 0xA0, 0xB2, + 0xB3, 0xB4, 0x95, 0xA5, 0xB5, 0xC5, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0x67, + 0x77, 0x87, 0x97, 0xC7, 0x78, 0x88, 0x98, 0xC8, 0x49, 0x69, 0x79, 0x89, + 0x99, 0xC9, 0x0A, 0x4A, 0x5A, 0x6A, 0x7A, 0xCA, 0x0B, 0x3B, 0x4B, 0x5B, + 0x6B, 0xCB, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xFC, + 0xDD, 0xED, 0xFD, 0xDE, 0xEE, 0xFE, 0x9F, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF, + 0xB0, 0xA7, 0xB7, 0xA8, 0xB8, 0xA9, 0xB9, 0x8A, 0x9A, 0xAA, 0xBA, 0x7B, + 0x8B, 0x9B, 0xAB, 0xBB +}; + +static const uint8_t huff_a17_cb[9] = { 3, 9, 3, 2, 5, 7, 17, 23, 6 }; + +static const uint8_t huff_a17_xlat[63] = { + 0, 1, 63, 2, 62, 3, 4, 59, 60, 61, 5, 6, 7, 8, 56, 57, + 58, 9, 10, 11, 12, 13, 14, 26, 27, 36, 37, 38, 50, 51, 52, 53, + 54, 55, 15, 16, 17, 18, 19, 20, 21, 25, 28, 29, 30, 31, 33, 34, + 35, 39, 43, 44, 45, 46, 47, 48, 49, 22, 23, 24, 40, 41, 42 +}; + +static const uint8_t huff_a21_cb[14] = { + 1, 12, 1, 0, 0, 2, 6, 0, 7, 21, 15, 17, 8, 4 +}; + +static const uint8_t huff_a21_xlat[81] = { + 0x00, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x03, 0xD0, 0x70, 0x34, + 0x1C, 0x0D, 0x13, 0x07, 0x50, 0xF0, 0x44, 0xC4, 0x14, 0x74, 0x4C, 0xCC, + 0xDC, 0x3C, 0x41, 0xC1, 0x11, 0x31, 0x05, 0x1D, 0x43, 0xC3, 0x33, 0x37, + 0x0F, 0x54, 0xF4, 0xFC, 0xD1, 0x71, 0x15, 0x4D, 0xCD, 0xDD, 0xD3, 0x73, + 0x47, 0xC7, 0x77, 0x3F, 0xD4, 0x5C, 0x7C, 0x51, 0xF1, 0x45, 0xC5, 0x55, + 0x35, 0x3D, 0x53, 0xF3, 0x17, 0x4F, 0xCF, 0x1F, 0xFF, 0x75, 0xF5, 0x5D, + 0x7D, 0xD7, 0xF7, 0x5F, 0xDF, 0xD5, 0xFD, 0x57, 0x7F +}; + +static const uint8_t huff_a22_cb[10] = { 2, 9, 1, 4, 0, 4, 3, 8, 3, 2 }; + +static const uint8_t huff_a22_xlat[25] = { + 0x00, 0x08, 0x38, 0x01, 0x07, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x02, 0x06, + 0x30, 0x11, 0x31, 0x0A, 0x3A, 0x0E, 0x17, 0x37, 0x32, 0x16, 0x3E, 0x12, + 0x36 +}; + +static const uint8_t huff_a23_cb[9] = { 3, 9, 5, 0, 4, 6, 10, 16, 8 }; + +static const uint8_t huff_a23_xlat[49] = { + 0x00, 0x08, 0x38, 0x01, 0x07, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x30, 0x02, + 0x3A, 0x06, 0x0E, 0x18, 0x28, 0x11, 0x31, 0x0A, 0x03, 0x05, 0x3E, 0x17, + 0x37, 0x19, 0x29, 0x12, 0x2A, 0x32, 0x0B, 0x33, 0x3B, 0x0D, 0x15, 0x3D, + 0x16, 0x1E, 0x36, 0x1F, 0x2F, 0x1A, 0x13, 0x1B, 0x2B, 0x1D, 0x2D, 0x35, + 0x2E +}; + +static const uint8_t huff_a24_cb[5] = { 2, 4, 3, 1, 2 }; + +static const uint8_t huff_a25_cb[5] = { 2, 4, 1, 5, 2 }; + +static const uint8_t huff_a25_xlat[8] = { 1, 0, 2, 3, 4, 5, 6, 7 }; + +static const uint8_t huff_a26_cb[10] = { 4, 11, 3, 4, 12, 15, 34, 83, 75, 30 }; + +static const uint8_t huff_a26_xlat[256] = { + 0x00, 0x01, 0x11, 0x10, 0x21, 0x12, 0x22, 0x20, 0x30, 0x31, 0x41, 0x02, + 0x32, 0x03, 0x13, 0x23, 0x33, 0x14, 0x24, 0x40, 0x51, 0x61, 0x42, 0x52, + 0x43, 0x53, 0x04, 0x34, 0x44, 0x15, 0x25, 0x35, 0x16, 0x26, 0x50, 0x60, + 0x71, 0x81, 0xD1, 0x62, 0x72, 0x82, 0xD2, 0x63, 0x73, 0xD3, 0x54, 0x64, + 0x05, 0x45, 0x55, 0x65, 0x06, 0x36, 0x46, 0x56, 0x17, 0x27, 0x37, 0x47, + 0x18, 0x28, 0x38, 0x19, 0x1D, 0x2D, 0x3D, 0x1E, 0x70, 0x80, 0x90, 0xD0, + 0xE0, 0x91, 0xA1, 0xB1, 0xC1, 0xE1, 0xF1, 0x92, 0xA2, 0xC2, 0xE2, 0xF2, + 0x83, 0x93, 0xA3, 0xC3, 0xE3, 0xF3, 0x74, 0x84, 0x94, 0xA4, 0xC4, 0xD4, + 0xE4, 0xF4, 0x75, 0x85, 0x95, 0xD5, 0xE5, 0x66, 0x76, 0x86, 0xD6, 0xE6, + 0x07, 0x57, 0x67, 0x77, 0xD7, 0x08, 0x48, 0x58, 0x68, 0xD8, 0x09, 0x29, + 0x39, 0x49, 0x59, 0x69, 0x1A, 0x2A, 0x3A, 0x4A, 0x1B, 0x2B, 0x1C, 0x2C, + 0x3C, 0x4C, 0x0D, 0x4D, 0x5D, 0x6D, 0x7D, 0x8D, 0x0E, 0x2E, 0x3E, 0x4E, + 0x5E, 0x6E, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0xA0, 0xB0, 0xC0, 0xF0, 0xB2, + 0xB3, 0xB4, 0xA5, 0xB5, 0xC5, 0xF5, 0x96, 0xA6, 0xB6, 0xC6, 0xF6, 0x87, + 0x97, 0xA7, 0xB7, 0xC7, 0xE7, 0xF7, 0x78, 0x88, 0x98, 0xA8, 0xC8, 0xE8, + 0xF8, 0x79, 0x89, 0x99, 0xC9, 0xD9, 0xE9, 0xF9, 0x0A, 0x5A, 0x6A, 0x7A, + 0x8A, 0xDA, 0xEA, 0xFA, 0x0B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0xDB, + 0x0C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xDC, 0x9D, 0xAD, 0xBD, 0xCD, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0x0F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xB8, 0xA9, + 0xB9, 0x9A, 0xAA, 0xBA, 0xCA, 0x9B, 0xAB, 0xBB, 0xCB, 0xEB, 0xFB, 0xAC, + 0xBC, 0xCC, 0xEC, 0xFC, 0xDD, 0xED, 0xFD, 0xCE, 0xDE, 0xEE, 0xFE, 0xBF, + 0xCF, 0xDF, 0xEF, 0xFF +}; + +static const uint8_t huff_a27_cb[7] = { 4, 8, 3, 14, 10, 20, 16 }; + +static const uint8_t huff_a27_xlat[63] = { + 0, 2, 3, 1, 5, 6, 7, 9, 54, 55, 56, 58, 59, 60, 61, 62, + 63, 4, 8, 10, 11, 12, 14, 49, 52, 53, 57, 13, 15, 16, 17, 18, + 19, 22, 23, 25, 26, 30, 39, 43, 44, 45, 46, 47, 48, 50, 51, 20, + 21, 24, 27, 28, 29, 31, 33, 34, 35, 36, 37, 38, 40, 41, 42 +}; + +static const uint8_t huff_a31_cb[8] = { 1, 6, 1, 0, 3, 1, 0, 4 }; + +static const uint8_t huff_a31_xlat[9] = { + 0x00, 0x04, 0x0C, 0x01, 0x03, 0x05, 0x0D, 0x07, 0x0F +}; + +static const uint8_t huff_a32_cb[13] = { + 1, 11, 1, 0, 0, 2, 2, 6, 12, 18, 19, 15, 6 +}; + +static const uint8_t huff_a32_xlat[81] = { + 0x00, 0x40, 0x01, 0x10, 0x04, 0x80, 0x50, 0x20, 0x14, 0x05, 0x02, 0x90, + 0x60, 0x44, 0x54, 0x24, 0x08, 0x18, 0x41, 0x11, 0x15, 0x09, 0x06, 0xA0, + 0x84, 0x94, 0x64, 0xA4, 0x48, 0x58, 0x28, 0x51, 0x21, 0x45, 0x55, 0x25, + 0x19, 0x12, 0x16, 0x0A, 0x1A, 0x68, 0xA8, 0x81, 0x91, 0x61, 0xA1, 0x85, + 0x95, 0x65, 0xA5, 0x49, 0x59, 0x29, 0x69, 0x42, 0x52, 0x46, 0x56, 0x2A, + 0x88, 0x98, 0x89, 0x99, 0xA9, 0x82, 0x92, 0x22, 0x62, 0x86, 0x26, 0x66, + 0x4A, 0x5A, 0x6A, 0xA2, 0x96, 0xA6, 0x8A, 0x9A, 0xAA +}; + +static const uint8_t huff_a33_cb[12] = { + 3, 12, 1, 1, 13, 1, 14, 28, 33, 81, 32, 52 +}; + +static const uint8_t huff_a33_xlat[256] = { + 0x00, 0x10, 0x40, 0x50, 0x04, 0x44, 0x14, 0x54, 0x01, 0x41, 0x11, 0x51, + 0x05, 0x45, 0x15, 0x55, 0x90, 0x20, 0x94, 0x64, 0x18, 0x21, 0x95, 0x19, + 0x69, 0x02, 0x52, 0x06, 0x46, 0x16, 0x80, 0x60, 0x84, 0xD4, 0x24, 0x08, + 0x48, 0x58, 0x68, 0x81, 0x91, 0x61, 0x85, 0x25, 0x65, 0xA5, 0x09, 0x49, + 0x59, 0x29, 0x42, 0x12, 0x56, 0x96, 0xA6, 0x0A, 0x17, 0x1B, 0xD0, 0xC4, + 0x74, 0xF4, 0x88, 0xC8, 0x28, 0xA1, 0x71, 0xC5, 0xD5, 0x75, 0x99, 0xB9, + 0x4D, 0x1D, 0x2D, 0x6D, 0x22, 0x62, 0x66, 0x4A, 0x1A, 0x9A, 0x6A, 0x8E, + 0x5E, 0x43, 0x23, 0x07, 0x47, 0x57, 0x6B, 0xC0, 0xA0, 0xE0, 0x70, 0xB0, + 0xA4, 0xE4, 0x34, 0xB4, 0x98, 0xD8, 0xA8, 0x38, 0x78, 0x0C, 0x4C, 0x1C, + 0x5C, 0x9C, 0x6C, 0x7C, 0xC1, 0xD1, 0xE1, 0x31, 0xE5, 0x35, 0xB5, 0xF5, + 0x89, 0xA9, 0x79, 0xF9, 0x0D, 0xCD, 0x9D, 0xDD, 0xAD, 0x3D, 0x7D, 0x82, + 0xC2, 0x92, 0xD2, 0xE2, 0x72, 0xF2, 0x86, 0xD6, 0xE6, 0x76, 0xB6, 0x8A, + 0x5A, 0xDA, 0xEA, 0xFA, 0x4E, 0x1E, 0x9E, 0xEE, 0x03, 0x13, 0x53, 0x97, + 0xB7, 0x0B, 0x4B, 0x8B, 0x5B, 0x9B, 0xEB, 0x7B, 0x0F, 0x4F, 0x1F, 0x5F, + 0x9F, 0x2F, 0x3F, 0xBF, 0xE8, 0xB8, 0xF8, 0x8C, 0x2C, 0x3C, 0xFC, 0xB1, + 0xC9, 0xD9, 0xE9, 0x39, 0x5D, 0xED, 0xBD, 0xA2, 0x32, 0x26, 0x36, 0x2A, + 0xAA, 0xBA, 0x0E, 0x2E, 0x6E, 0x83, 0xC3, 0x93, 0x63, 0xB3, 0xA7, 0x37, + 0x30, 0xF0, 0xCC, 0xDC, 0xAC, 0xEC, 0xBC, 0xF1, 0x8D, 0xFD, 0xB2, 0xC6, + 0xF6, 0xCA, 0x3A, 0x7A, 0xCE, 0xDE, 0xAE, 0x3E, 0x7E, 0xBE, 0xFE, 0xD3, + 0xA3, 0xE3, 0x33, 0x73, 0xF3, 0x87, 0xC7, 0xD7, 0x27, 0x67, 0xE7, 0x77, + 0xF7, 0xCB, 0xDB, 0x2B, 0xAB, 0x3B, 0xBB, 0xFB, 0x8F, 0xCF, 0xDF, 0x6F, + 0xAF, 0xEF, 0x7F, 0xFF +}; + +static const uint8_t huff_a34_cb[7] = { 1, 5, 1, 1, 1, 1, 2 }; + +static const uint8_t huff_a34_xlat[6] = { 1, 0, 2, 3, 4, 5 }; + +static const uint8_t huff_a35_cb[11] = { 2, 10, 1, 0, 2, 3, 6, 19, 9, 75, 110 }; + +static const uint8_t huff_a35_xlat[225] = { + 0x00, 0xF0, 0x0F, 0x10, 0x01, 0xFF, 0x20, 0xE0, 0x11, 0xF1, 0x0E, 0x1F, + 0x30, 0x40, 0xD0, 0x21, 0xE1, 0x02, 0x12, 0x22, 0xE2, 0xF2, 0x03, 0x13, + 0x1E, 0x2E, 0x3E, 0xEE, 0xFE, 0x2F, 0xEF, 0xD2, 0x43, 0xF3, 0x04, 0x0D, + 0x2D, 0x3D, 0x3F, 0xDF, 0x50, 0x60, 0x70, 0x90, 0xB0, 0x31, 0x41, 0x91, + 0xA1, 0xC1, 0xD1, 0x42, 0xA2, 0xC2, 0x23, 0x33, 0xE3, 0x24, 0x34, 0xB4, + 0xD4, 0xF4, 0x05, 0x15, 0x45, 0xE5, 0x16, 0x36, 0x56, 0xA6, 0xC6, 0xD6, + 0xF6, 0x57, 0xC7, 0xF7, 0x09, 0x29, 0x49, 0x59, 0x69, 0xF9, 0x0A, 0x2A, + 0x3A, 0x4A, 0xDA, 0xEA, 0xFA, 0x0B, 0x2B, 0xAB, 0xEB, 0xFB, 0x0C, 0x1C, + 0x2C, 0x3C, 0x4C, 0x5C, 0xCC, 0xDC, 0xFC, 0x1D, 0x4D, 0x6D, 0xBD, 0xCD, + 0xED, 0xFD, 0x4E, 0x6E, 0xCE, 0xDE, 0x7F, 0xA0, 0xC0, 0x51, 0x61, 0x71, + 0xB1, 0x32, 0x52, 0x62, 0x72, 0x92, 0xB2, 0x53, 0x63, 0x73, 0x93, 0xA3, + 0xB3, 0xC3, 0xD3, 0x14, 0x44, 0x54, 0x64, 0x74, 0x94, 0xA4, 0xC4, 0xE4, + 0x25, 0x35, 0x55, 0x65, 0x75, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xF5, 0x06, + 0x26, 0x46, 0x66, 0x76, 0x96, 0xB6, 0xE6, 0x07, 0x17, 0x27, 0x37, 0x47, + 0x67, 0x77, 0x97, 0xA7, 0xB7, 0xD7, 0xE7, 0x19, 0x39, 0x79, 0x99, 0xA9, + 0xB9, 0xC9, 0xD9, 0xE9, 0x1A, 0x5A, 0x6A, 0x7A, 0x9A, 0xAA, 0xBA, 0xCA, + 0x1B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x9B, 0xBB, 0xCB, 0xDB, 0x6C, 0x7C, + 0x9C, 0xAC, 0xBC, 0xEC, 0x5D, 0x7D, 0x9D, 0xAD, 0xDD, 0x5E, 0x7E, 0x9E, + 0xAE, 0xBE, 0x4F, 0x5F, 0x6F, 0x9F, 0xAF, 0xBF, 0xCF +}; + +static const uint8_t huff_a36_cb[12] = { + 3, 12, 1, 3, 5, 5, 13, 27, 69, 96, 35, 2 +}; + +static const uint8_t huff_a36_xlat[256] = { + 0x00, 0x10, 0x01, 0x11, 0x20, 0x21, 0x02, 0x12, 0x22, 0x31, 0x41, 0x32, + 0x13, 0x23, 0x30, 0x40, 0x51, 0x42, 0x03, 0x33, 0x43, 0x04, 0x14, 0x24, + 0x34, 0x15, 0x25, 0x50, 0x61, 0x71, 0xD1, 0x52, 0x62, 0x72, 0xD2, 0x53, + 0x63, 0xD3, 0x44, 0x54, 0x64, 0x05, 0x35, 0x45, 0x55, 0x16, 0x26, 0x36, + 0x46, 0x17, 0x27, 0x1D, 0x2D, 0x3D, 0x60, 0x70, 0xD0, 0x81, 0x91, 0xA1, + 0xC1, 0xE1, 0xF1, 0x82, 0x92, 0xC2, 0xE2, 0xF2, 0x73, 0x83, 0xE3, 0xF3, + 0x74, 0x84, 0xC4, 0xD4, 0xE4, 0xF4, 0x65, 0x75, 0x85, 0xD5, 0xE5, 0x06, + 0x56, 0x66, 0xD6, 0xE6, 0x07, 0x37, 0x47, 0x57, 0x67, 0xD7, 0xE7, 0x18, + 0x28, 0x38, 0x48, 0x58, 0xD8, 0x19, 0x29, 0x2A, 0x1C, 0x2C, 0x0D, 0x4D, + 0x5D, 0x6D, 0x7D, 0x8D, 0x9D, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, + 0x1F, 0x2F, 0x3F, 0x80, 0x90, 0xA0, 0xC0, 0xE0, 0xF0, 0xB1, 0xA2, 0xB2, + 0x93, 0xA3, 0xB3, 0xC3, 0x94, 0xA4, 0xB4, 0x95, 0xA5, 0xB5, 0xC5, 0xF5, + 0x76, 0x86, 0x96, 0xA6, 0xC6, 0xF6, 0x77, 0x87, 0x97, 0xA7, 0xC7, 0xF7, + 0x08, 0x68, 0x78, 0x88, 0x98, 0xC8, 0xE8, 0xF8, 0x09, 0x39, 0x49, 0x59, + 0x69, 0x79, 0x89, 0xD9, 0xE9, 0xF9, 0x0A, 0x1A, 0x3A, 0x4A, 0x5A, 0x6A, + 0xDA, 0xEA, 0xFA, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0xDB, 0xEB, 0xFB, 0x0C, + 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xDC, 0xEC, 0xAD, 0xBD, 0xCD, + 0xDD, 0xED, 0x0E, 0x8E, 0x9E, 0xAE, 0xBE, 0x0F, 0x4F, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xB0, 0xB6, 0xB7, 0xA8, 0xB8, 0x99, 0xA9, 0xB9, 0xC9, + 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0x0B, 0x6B, 0x7B, 0x8B, 0x9B, 0xCB, + 0xAC, 0xBC, 0xCC, 0xFC, 0xFD, 0xCE, 0xDE, 0xEE, 0xFE, 0xBF, 0xCF, 0xDF, + 0xEF, 0xFF, 0xAB, 0xBB +}; + +static const uint8_t huff_a37_cb[7] = { 4, 8, 7, 6, 8, 22, 20 }; + +static const uint8_t huff_a37_xlat[63] = { + 0, 1, 2, 3, 61, 62, 63, 4, 5, 6, 58, 59, 60, 7, 8, 9, + 10, 54, 55, 56, 57, 11, 12, 13, 14, 15, 16, 25, 26, 27, 28, 29, + 30, 35, 36, 37, 38, 48, 49, 50, 51, 52, 53, 17, 18, 19, 20, 21, + 22, 23, 24, 31, 33, 34, 39, 40, 41, 42, 43, 44, 45, 46, 47 +}; + +static const uint8_t huff_a41_cb[14] = { + 1, 12, 1, 0, 0, 6, 2, 0, 0, 0, 19, 9, 24, 20 +}; + +static const uint8_t huff_a41_xlat[81] = { + 0x00, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x03, 0x50, 0xD0, 0x70, + 0xF0, 0xC4, 0x34, 0x4C, 0xCC, 0x1C, 0x41, 0xC1, 0x31, 0x05, 0x0D, 0x43, + 0xC3, 0x13, 0x07, 0x0F, 0x44, 0x14, 0x74, 0xDC, 0x3C, 0x11, 0x1D, 0x33, + 0x37, 0x54, 0xD4, 0xF4, 0x5C, 0x7C, 0xFC, 0xD1, 0x71, 0xF1, 0xC5, 0x15, + 0x35, 0x4D, 0xCD, 0xDD, 0x3D, 0xD3, 0x73, 0x47, 0xC7, 0x17, 0x77, 0x1F, + 0x3F, 0x51, 0x45, 0x55, 0xD5, 0x75, 0xF5, 0x5D, 0x7D, 0xFD, 0x53, 0xF3, + 0x57, 0xD7, 0xF7, 0x4F, 0xCF, 0x5F, 0xDF, 0x7F, 0xFF +}; + +static const uint8_t huff_a42_cb[10] = { 3, 10, 1, 2, 13, 1, 31, 13, 16, 4 }; + +static const uint8_t huff_a42_xlat[81] = { + 0x00, 0x40, 0x01, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 0x41, 0x11, 0x51, + 0x05, 0x45, 0x15, 0x55, 0x59, 0x80, 0x90, 0x20, 0x60, 0x84, 0x94, 0x24, + 0x64, 0x08, 0x48, 0x18, 0x58, 0x81, 0x91, 0x21, 0x61, 0x85, 0x95, 0x25, + 0x65, 0x09, 0x49, 0x19, 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, + 0xA0, 0xA4, 0x68, 0xA1, 0xA5, 0x99, 0x29, 0x69, 0x96, 0x66, 0x4A, 0x1A, + 0x5A, 0x88, 0x98, 0x28, 0x89, 0xA9, 0x82, 0x92, 0x22, 0x62, 0x86, 0x26, + 0xA6, 0x0A, 0x9A, 0x2A, 0x6A, 0xA8, 0xA2, 0x8A, 0xAA +}; + +static const uint8_t huff_a43_cb[5] = { 2, 4, 2, 3, 2 }; + +static const uint8_t huff_a43_xlat[7] = { 0, 7, 1, 2, 6, 3, 5 }; + +static const uint8_t huff_a44_cb[9] = { 4, 10, 5, 4, 12, 17, 47, 24, 12 }; + +static const uint8_t huff_a44_xlat[121] = { + 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x21, + 0xE1, 0x02, 0x12, 0xF2, 0x0E, 0x1E, 0xFE, 0x2F, 0xEF, 0x30, 0x50, 0xD0, + 0xD1, 0x22, 0xE2, 0x03, 0x13, 0xF3, 0x0D, 0x1D, 0x2D, 0xFD, 0x2E, 0xEE, + 0x3F, 0xDF, 0x40, 0xB0, 0xC0, 0x31, 0x41, 0x51, 0xB1, 0xC1, 0x32, 0xB2, + 0xC2, 0xD2, 0x23, 0xB3, 0xD3, 0xE3, 0x04, 0x14, 0xE4, 0xF4, 0x05, 0x15, + 0xD5, 0xE5, 0xF5, 0x0B, 0x1B, 0x2B, 0x3B, 0xEB, 0xFB, 0x0C, 0x1C, 0x2C, + 0xFC, 0x3D, 0x5D, 0xED, 0x3E, 0x4E, 0x5E, 0xBE, 0xDE, 0x4F, 0x5F, 0xBF, + 0xCF, 0x42, 0x52, 0x33, 0x53, 0xC3, 0x24, 0xB4, 0xD4, 0x25, 0x35, 0xC5, + 0x4B, 0xCB, 0xDB, 0x3C, 0x4C, 0x5C, 0xDC, 0xEC, 0x4D, 0xBD, 0xCD, 0xDD, + 0xCE, 0x43, 0x34, 0x44, 0x54, 0xC4, 0x45, 0x55, 0xB5, 0x5B, 0xBB, 0xBC, + 0xCC +}; + +static const uint8_t huff_a45_cb[5] = { 2, 4, 2, 2, 4 }; + +static const uint8_t huff_a45_xlat[8] = { 1, 2, 0, 3, 4, 5, 6, 7 }; + +static const uint8_t huff_a46_cb[7] = { 5, 9, 1, 16, 31, 36, 172 }; + +static const uint8_t huff_a46_xlat[256] = { + 0x02, 0x00, 0x30, 0x21, 0x31, 0x41, 0x61, 0x12, 0x22, 0x42, 0x62, 0x43, + 0x53, 0x24, 0x45, 0x26, 0x27, 0x10, 0x40, 0xB0, 0x01, 0x11, 0x81, 0x32, + 0x52, 0x72, 0x92, 0x03, 0x13, 0x33, 0x63, 0x14, 0x34, 0x54, 0x64, 0x74, + 0x05, 0x15, 0x25, 0x35, 0x55, 0x65, 0x06, 0x46, 0x56, 0x57, 0x67, 0x88, + 0x20, 0x51, 0x91, 0xD1, 0xF2, 0x23, 0x83, 0x93, 0x04, 0x44, 0x84, 0x94, + 0x75, 0x85, 0xC5, 0x36, 0x66, 0x96, 0xB6, 0x07, 0x37, 0x97, 0x08, 0x28, + 0x38, 0x48, 0x68, 0x09, 0x69, 0x79, 0x0A, 0x2A, 0x1B, 0x9B, 0x2C, 0x4D, + 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xC0, 0xD0, 0xE0, 0xF0, 0x71, 0xA1, + 0xB1, 0xC1, 0xE1, 0xF1, 0x82, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0x73, 0xA3, + 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, 0x95, + 0xA5, 0xB5, 0xD5, 0xE5, 0xF5, 0x16, 0x76, 0x86, 0xA6, 0xC6, 0xD6, 0xE6, + 0xF6, 0x17, 0x47, 0x77, 0x87, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, 0x18, + 0x58, 0x78, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, 0x19, 0x29, 0x39, + 0x49, 0x59, 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, 0x1A, 0x3A, + 0x4A, 0x5A, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0xAB, 0xBB, 0xCB, 0xDB, + 0xEB, 0xFB, 0x0C, 0x1C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC, + 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, 0x0D, 0x1D, 0x2D, 0x3D, 0x5D, 0x6D, 0x7D, + 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, 0x0E, 0x1E, 0x2E, 0x3E, + 0x4E, 0x5E, 0x6E, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xBF, + 0xCF, 0xDF, 0xEF, 0xFF +}; + +static const uint8_t huff_a47_cb[8] = { 4, 9, 5, 12, 9, 12, 15, 10 }; + +static const uint8_t huff_a47_xlat[63] = { + 0, 1, 2, 62, 63, 3, 4, 5, 6, 8, 54, 56, 57, 58, 59, 60, + 61, 7, 9, 10, 11, 12, 13, 14, 53, 55, 15, 16, 17, 18, 19, 20, + 21, 36, 37, 39, 42, 52, 22, 25, 28, 35, 38, 40, 41, 43, 45, 46, + 47, 48, 49, 50, 51, 23, 24, 26, 27, 29, 30, 31, 33, 34, 44 +}; + +static const uint8_t huff_a51_cb[12] = { + 2, 11, 1, 0, 6, 2, 6, 18, 4, 26, 6, 12 +}; + +static const uint8_t huff_a51_xlat[81] = { + 0x00, 0x40, 0xC0, 0x30, 0x04, 0x01, 0x03, 0x10, 0x0C, 0xD0, 0x70, 0x34, + 0x1C, 0x0D, 0x07, 0x50, 0xF0, 0x44, 0xC4, 0x14, 0x4C, 0xCC, 0x3C, 0x41, + 0xC1, 0x11, 0x31, 0x05, 0x43, 0xC3, 0x13, 0x33, 0x0F, 0x74, 0xDC, 0x1D, + 0x37, 0x54, 0xD4, 0xF4, 0x5C, 0x7C, 0xFC, 0xD1, 0x71, 0xF1, 0xC5, 0x15, + 0x35, 0x4D, 0xCD, 0xDD, 0x3D, 0x53, 0xD3, 0x73, 0x47, 0xC7, 0x17, 0x77, + 0x4F, 0x1F, 0x3F, 0x51, 0x45, 0x55, 0xF3, 0xCF, 0xFF, 0xD5, 0x75, 0xF5, + 0x5D, 0x7D, 0xFD, 0x57, 0xD7, 0xF7, 0x5F, 0xDF, 0x7F +}; + +static const uint8_t huff_a52_cb[12] = { 1, 10, 1, 0, 2, 2, 0, 4, 3, 8, 3, 2 }; + +static const uint8_t huff_a52_xlat[25] = { + 0x00, 0x08, 0x38, 0x01, 0x07, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x02, 0x06, + 0x30, 0x11, 0x31, 0x0A, 0x3A, 0x0E, 0x17, 0x37, 0x32, 0x16, 0x3E, 0x12, + 0x36 +}; + +static const uint8_t huff_a53_xlat[7] = { 0, 1, 2, 6, 7, 3, 5 }; + +static const uint8_t huff_a54_cb[8] = { 4, 9, 4, 7, 12, 19, 21, 58 }; + +static const uint8_t huff_a54_xlat[121] = { + 0x00, 0x01, 0x0F, 0x1F, 0x10, 0xE0, 0xF0, 0x11, 0xF1, 0x2F, 0xFF, 0x20, + 0x21, 0xE1, 0x02, 0x12, 0xF2, 0x03, 0xF3, 0x0E, 0x2E, 0xFE, 0x3F, 0x30, + 0x40, 0xD0, 0xC1, 0xD1, 0x22, 0xC2, 0x33, 0xE3, 0x0C, 0xCC, 0x0D, 0x1D, + 0x2D, 0xFD, 0x1E, 0x3E, 0x5E, 0xEF, 0xC0, 0x52, 0xB2, 0xD2, 0x43, 0xC3, + 0xD3, 0x24, 0x45, 0xF5, 0x4B, 0x5B, 0xFB, 0x1C, 0x3D, 0xBD, 0xDD, 0xEE, + 0xBF, 0xCF, 0xDF, 0x50, 0xB0, 0x31, 0x41, 0x51, 0xB1, 0x32, 0x42, 0xE2, + 0x13, 0x23, 0x53, 0xB3, 0x04, 0x14, 0x34, 0x44, 0x54, 0xB4, 0xC4, 0xD4, + 0xE4, 0xF4, 0x05, 0x15, 0x25, 0x35, 0x55, 0xB5, 0xC5, 0xD5, 0xE5, 0x0B, + 0x1B, 0x2B, 0x3B, 0xBB, 0xCB, 0xDB, 0xEB, 0x2C, 0x3C, 0x4C, 0x5C, 0xBC, + 0xDC, 0xEC, 0xFC, 0x4D, 0x5D, 0xCD, 0xED, 0x4E, 0xBE, 0xCE, 0xDE, 0x4F, + 0x5F +}; + +static const uint8_t huff_a55_cb[8] = { 1, 6, 1, 1, 1, 0, 3, 2 }; + +static const uint8_t huff_a55_xlat[8] = { 0, 1, 2, 3, 6, 7, 4, 5 }; + +static const uint8_t huff_a56_cb[7] = { 3, 7, 1, 8, 6, 8, 8 }; + +static const uint8_t huff_a56_xlat[31] = { + 4, 0, 1, 2, 3, 28, 29, 30, 31, 5, 6, 7, 24, 25, 27, 8, + 9, 14, 19, 21, 22, 23, 26, 10, 11, 12, 13, 15, 17, 18, 20 +}; + +static const uint8_t huff_a57_cb[9] = { 3, 9, 1, 5, 7, 8, 16, 22, 4 }; + +static const uint8_t huff_a57_xlat[63] = { + 0, 1, 2, 61, 62, 63, 3, 4, 5, 6, 58, 59, + 60, 7, 8, 9, 10, 54, 55, 56, 57, 11, 12, 13, + 14, 15, 26, 27, 28, 36, 37, 38, 49, 50, 51, 52, + 53, 16, 17, 18, 19, 20, 21, 23, 24, 25, 29, 30, + 31, 33, 34, 35, 39, 43, 44, 45, 46, 47, 48, 22, + 40, 41, 42 +}; + +static const uint8_t huff_a61_cb[12] = { + 2, 11, 1, 0, 8, 0, 1, 16, 10, 29, 12, 4 +}; + +static const uint8_t huff_a61_xlat[81] = { + 0x00, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x03, 0x70, 0x50, 0xD0, + 0xF0, 0x44, 0xC4, 0x14, 0x34, 0x4C, 0x1C, 0x3C, 0x31, 0x05, 0x0D, 0x13, + 0x07, 0x0F, 0x74, 0xCC, 0xDC, 0xFC, 0x41, 0xC1, 0x11, 0x43, 0xC3, 0x33, + 0x54, 0xD4, 0xF4, 0x5C, 0x7C, 0x51, 0xD1, 0x71, 0xF1, 0x45, 0xC5, 0x15, + 0x35, 0x4D, 0xCD, 0x1D, 0x3D, 0x53, 0xD3, 0x73, 0xF3, 0x47, 0xC7, 0x17, + 0x37, 0x4F, 0xCF, 0x1F, 0x3F, 0x55, 0xD5, 0x75, 0xF5, 0x5D, 0xDD, 0xFD, + 0x57, 0xD7, 0x77, 0xF7, 0xFF, 0x7D, 0x5F, 0xDF, 0x7F +}; + +static const uint8_t huff_a62_cb[8] = { 3, 8, 5, 2, 2, 9, 5, 2 }; + +static const uint8_t huff_a62_xlat[25] = { + 0x00, 0x08, 0x38, 0x01, 0x07, 0x39, 0x0F, 0x09, 0x3F, 0x10, 0x30, 0x31, + 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x37, 0x11, 0x0A, 0x32, 0x16, 0x3E, 0x12, + 0x36 +}; + +static const uint8_t huff_a63_cb[11] = { + 3, 11, 1, 1, 10, 4, 16, 29, 46, 75, 74 +}; + +static const uint8_t huff_a63_xlat[256] = { + 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x01, 0x41, 0x05, 0x45, 0x55, + 0x54, 0x11, 0x51, 0x15, 0x80, 0x90, 0x60, 0x24, 0x64, 0xA4, 0x48, 0x61, + 0x95, 0x25, 0xA5, 0x02, 0x42, 0x52, 0x16, 0x56, 0x20, 0x84, 0x94, 0x18, + 0x58, 0x81, 0x91, 0x85, 0x65, 0x09, 0x49, 0x19, 0x59, 0x99, 0x29, 0x69, + 0x79, 0x5D, 0x12, 0x62, 0x06, 0x46, 0x86, 0x66, 0x1A, 0x5A, 0x6A, 0x47, + 0x17, 0xC0, 0xA0, 0xE0, 0xC4, 0xD4, 0x74, 0x08, 0x78, 0x0C, 0x4C, 0x1C, + 0x5C, 0xD1, 0x21, 0xE1, 0x71, 0xC5, 0xE5, 0x75, 0xB5, 0x89, 0xBD, 0x92, + 0x22, 0x96, 0xA6, 0x36, 0x0A, 0x4A, 0x8A, 0x9A, 0x2A, 0x7A, 0xDE, 0x6E, + 0x43, 0x13, 0x53, 0x23, 0x07, 0x77, 0x4B, 0x1B, 0x9B, 0x6B, 0x2F, 0xD0, + 0x30, 0x70, 0xE4, 0x34, 0xF4, 0xC8, 0x98, 0x28, 0x68, 0xA8, 0xE8, 0x38, + 0xB8, 0xF8, 0x9C, 0x2C, 0x6C, 0x7C, 0xA1, 0xB1, 0xD5, 0x35, 0xC9, 0xD9, + 0xA9, 0xE9, 0x39, 0xB9, 0xF9, 0xCD, 0x1D, 0x2D, 0xAD, 0x7D, 0xC2, 0xD2, + 0xA2, 0xB2, 0xF2, 0xC6, 0x26, 0x76, 0xB6, 0xDA, 0xAA, 0xEA, 0x3A, 0xFA, + 0x0E, 0x4E, 0x2E, 0x7E, 0xBE, 0xFE, 0x03, 0x83, 0x63, 0xA3, 0xB3, 0x87, + 0x57, 0x97, 0xD7, 0x27, 0x0B, 0x8B, 0x5B, 0x2B, 0xAB, 0xCF, 0x1F, 0x9F, + 0x7F, 0xBF, 0xB0, 0xF0, 0xB4, 0x88, 0xD8, 0x8C, 0xCC, 0xDC, 0xAC, 0xEC, + 0x3C, 0xBC, 0xFC, 0xC1, 0x31, 0xF1, 0xF5, 0x0D, 0x4D, 0x8D, 0x9D, 0xDD, + 0x6D, 0xED, 0x3D, 0xFD, 0x82, 0xE2, 0x32, 0x72, 0xD6, 0xE6, 0xF6, 0xCA, + 0xBA, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xAE, 0xEE, 0x3E, 0xC3, 0x93, 0xD3, + 0xE3, 0x33, 0x73, 0xF3, 0xC7, 0x67, 0xA7, 0xE7, 0x37, 0xB7, 0xF7, 0xCB, + 0xDB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, 0x0F, 0x4F, 0x8F, 0x5F, 0xDF, 0x6F, + 0xAF, 0xEF, 0x3F, 0xFF +}; + +static const uint8_t huff_a64_cb[8] = { 4, 9, 1, 7, 12, 36, 63, 2 }; + +static const uint8_t huff_a64_xlat[121] = { + 0x00, 0x10, 0x20, 0xE0, 0xF0, 0x02, 0x0E, 0xEF, 0x30, 0x01, 0x11, 0x21, + 0x31, 0xF1, 0x12, 0xF2, 0x1E, 0xEE, 0xDF, 0xFF, 0x40, 0xC0, 0xD0, 0xD1, + 0xE1, 0x22, 0x32, 0x42, 0xD2, 0xE2, 0x03, 0x13, 0x23, 0xB3, 0xC3, 0xE3, + 0xF3, 0xE4, 0x05, 0xF5, 0x2B, 0x0C, 0xFC, 0x1D, 0x2D, 0xBD, 0xDD, 0xFD, + 0x2E, 0x4E, 0xDE, 0xFE, 0x0F, 0x1F, 0x2F, 0x3F, 0x50, 0xB0, 0x41, 0x51, + 0xB1, 0xC1, 0x52, 0xB2, 0xC2, 0x33, 0x43, 0x53, 0xD3, 0x04, 0x14, 0x24, + 0x34, 0x44, 0x54, 0xB4, 0xC4, 0xD4, 0xF4, 0x15, 0x25, 0x35, 0x45, 0x55, + 0xB5, 0xC5, 0xD5, 0xE5, 0x0B, 0x1B, 0x3B, 0x4B, 0x5B, 0xBB, 0xCB, 0xDB, + 0xEB, 0xFB, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0xBC, 0xCC, 0xDC, 0xEC, 0x0D, + 0x3D, 0x4D, 0x5D, 0xCD, 0xED, 0x3E, 0x5E, 0xBE, 0xCE, 0x4F, 0xCF, 0x5F, + 0xBF +}; + +static const uint8_t huff_a65_cb[8] = { 2, 7, 3, 0, 1, 3, 4, 4 }; + +static const uint8_t huff_a65_xlat[15] = { + 0, 1, 15, 14, 2, 3, 13, 4, 6, 10, 12, 5, 7, 9, 11 +}; + +static const uint8_t huff_a66_cb[11] = { 2, 10, 1, 2, 2, 6, 8, 6, 3, 1, 2 }; + +static const uint8_t huff_a66_xlat[31] = { + 0, 1, 31, 2, 30, 3, 4, 15, 17, 28, 29, 5, 6, 7, 8, 24, + 25, 26, 27, 9, 10, 11, 21, 22, 23, 12, 19, 20, 13, 14, 18 +}; + +static const uint8_t huff_a67_cb[10] = { 2, 9, 1, 1, 3, 4, 6, 13, 25, 10 }; + +static const uint8_t huff_a67_xlat[63] = { + 0, 1, 2, 62, 63, 3, 4, 60, 61, 5, 6, 7, 57, 58, 59, 8, + 9, 10, 11, 12, 13, 26, 38, 52, 53, 54, 55, 56, 14, 15, 16, 17, + 18, 19, 25, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 39, 45, 46, + 47, 48, 49, 50, 51, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44 +}; + +static const uint8_t huff_a71_cb[5] = { 1, 3, 1, 1, 2 }; + +static const uint8_t huff_a72_cb[12] = { + 2, 11, 1, 0, 4, 8, 3, 8, 24, 17, 12, 4 +}; + +static const uint8_t huff_a72_xlat[81] = { + 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x05, + 0x15, 0x51, 0x45, 0x55, 0x80, 0x90, 0x20, 0x64, 0x08, 0x19, 0x02, 0x06, + 0x60, 0x84, 0x94, 0x24, 0x48, 0x18, 0x58, 0x81, 0x91, 0x21, 0x61, 0x85, + 0x95, 0x25, 0x65, 0x09, 0x49, 0x59, 0x42, 0x12, 0x52, 0x46, 0x16, 0x56, + 0xA0, 0xA4, 0x98, 0x28, 0x68, 0xA1, 0xA5, 0x99, 0x29, 0x69, 0x96, 0x26, + 0x66, 0x0A, 0x4A, 0x1A, 0x5A, 0x88, 0xA8, 0x89, 0xA9, 0x82, 0x92, 0x22, + 0x62, 0x86, 0xA6, 0x2A, 0x6A, 0xA2, 0x8A, 0x9A, 0xAA +}; + +static const uint8_t huff_a73_cb[11] = { 2, 10, 1, 1, 5, 2, 8, 7, 13, 8, 4 }; + +static const uint8_t huff_a73_xlat[49] = { + 0x00, 0x08, 0x38, 0x01, 0x39, 0x07, 0x0F, 0x09, 0x3F, 0x10, 0x30, 0x31, + 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x11, 0x0A, 0x32, 0x0D, 0x16, 0x3E, 0x37, + 0x18, 0x28, 0x19, 0x29, 0x12, 0x2A, 0x03, 0x3B, 0x05, 0x15, 0x1E, 0x1F, + 0x2F, 0x1A, 0x0B, 0x2B, 0x33, 0x35, 0x3D, 0x2E, 0x36, 0x13, 0x1B, 0x1D, + 0x2D +}; + +static const uint8_t huff_a74_cb[14] = { + 1, 12, 1, 0, 0, 4, 0, 4, 5, 9, 30, 45, 21, 2 +}; + +static const uint8_t huff_a74_xlat[121] = { + 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x02, + 0xF2, 0x0E, 0x21, 0xE1, 0x12, 0xE2, 0x1E, 0x2E, 0xFE, 0x2F, 0xEF, 0x30, + 0x50, 0xB0, 0xC0, 0xD0, 0x31, 0xB1, 0xD1, 0x22, 0xD2, 0x03, 0x13, 0xE3, + 0xF3, 0xF4, 0x05, 0xE5, 0xF5, 0x0B, 0x1B, 0x0C, 0x0D, 0x1D, 0x2D, 0xFD, + 0x3E, 0xEE, 0x3F, 0x5F, 0xDF, 0x40, 0x41, 0x51, 0xC1, 0x32, 0x42, 0x52, + 0xB2, 0xC2, 0x23, 0x33, 0xB3, 0xC3, 0xD3, 0x04, 0x14, 0x24, 0xD4, 0xE4, + 0x15, 0x25, 0xC5, 0xD5, 0x2B, 0x3B, 0xEB, 0xFB, 0x1C, 0x2C, 0x3C, 0x5C, + 0xEC, 0xFC, 0x3D, 0x5D, 0xDD, 0xED, 0x4E, 0x5E, 0xBE, 0xCE, 0xDE, 0x4F, + 0xBF, 0xCF, 0x43, 0x53, 0x34, 0x54, 0xB4, 0xC4, 0x35, 0x45, 0x55, 0xB5, + 0x4B, 0x5B, 0xCB, 0xDB, 0x4C, 0xBC, 0xCC, 0xDC, 0x4D, 0xBD, 0xCD, 0x44, + 0xBB +}; + +static const uint8_t huff_a75_cb[7] = { 2, 6, 1, 3, 3, 4, 4 }; + +static const uint8_t huff_a75_xlat[15] = { + 0, 1, 14, 15, 2, 3, 13, 4, 6, 10, 12, 5, 7, 9, 11 +}; + +static const uint8_t huff_a76_cb[12] = { + 3, 12, 1, 3, 4, 8, 10, 36, 60, 78, 48, 8 +}; + +static const uint8_t huff_a76_xlat[256] = { + 0x00, 0x10, 0x01, 0x11, 0x20, 0x21, 0x02, 0x12, 0x30, 0x31, 0x41, 0x22, + 0x03, 0x13, 0x23, 0x14, 0x40, 0x51, 0x61, 0x32, 0x42, 0x33, 0x04, 0x24, + 0x15, 0x16, 0x50, 0x60, 0xD0, 0x71, 0x81, 0xD1, 0xE1, 0xF1, 0x52, 0x62, + 0x72, 0xD2, 0x43, 0x53, 0x63, 0xD3, 0x34, 0x44, 0x54, 0x05, 0x25, 0x35, + 0x45, 0x06, 0x26, 0x36, 0x17, 0x27, 0x18, 0x0D, 0x1D, 0x2D, 0x3D, 0x1E, + 0x2E, 0x1F, 0x70, 0x80, 0xE0, 0xF0, 0x91, 0xA1, 0xC1, 0x82, 0x92, 0xC2, + 0xE2, 0xF2, 0x73, 0x83, 0x93, 0xE3, 0xF3, 0x64, 0x74, 0x84, 0xD4, 0xE4, + 0xF4, 0x55, 0x65, 0xD5, 0xE5, 0xF5, 0x46, 0x56, 0x66, 0xD6, 0x07, 0x37, + 0x47, 0x57, 0x08, 0x28, 0x38, 0x48, 0x19, 0x29, 0x39, 0x1A, 0x2A, 0x1B, + 0x1C, 0x2C, 0x3C, 0x4D, 0x5D, 0x6D, 0x0E, 0x3E, 0x4E, 0x5E, 0x0F, 0x2F, + 0x3F, 0x4F, 0x90, 0xA0, 0xB0, 0xC0, 0xB1, 0xA2, 0xB2, 0xA3, 0xB3, 0xC3, + 0x94, 0xA4, 0xB4, 0xC4, 0x75, 0x85, 0x95, 0xA5, 0xC5, 0x76, 0x86, 0x96, + 0xE6, 0xF6, 0x67, 0x77, 0x87, 0xD7, 0xE7, 0xF7, 0x58, 0x68, 0x78, 0x88, + 0xD8, 0xE8, 0xF8, 0x09, 0x49, 0x59, 0x69, 0xD9, 0xE9, 0xF9, 0x0A, 0x3A, + 0x4A, 0x5A, 0xDA, 0xEA, 0x0B, 0x2B, 0x3B, 0x4B, 0xDB, 0x0C, 0x4C, 0x5C, + 0x6C, 0xDC, 0x7D, 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0x6E, 0x7E, 0x8E, 0x9E, + 0xAE, 0xBE, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xB5, 0xA6, 0xB6, 0xC6, + 0x97, 0xA7, 0xC7, 0x98, 0xA8, 0xB8, 0xC8, 0x79, 0x89, 0x99, 0xA9, 0xB9, + 0xC9, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xCA, 0xFA, 0x5B, 0x6B, 0x7B, 0x8B, + 0xCB, 0xEB, 0xFB, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xEC, 0xFC, 0xDD, 0xED, + 0xFD, 0xCE, 0xDE, 0xEE, 0xFE, 0xBF, 0xCF, 0xDF, 0xB7, 0xBA, 0x9B, 0xAB, + 0xBB, 0xCC, 0xEF, 0xFF +}; + +static const uint8_t huff_b01_cb[14] = { + 1, 12, 1, 0, 0, 2, 6, 0, 11, 13, 12, 24, 4, 8 +}; + +static const uint8_t huff_b01_xlat[81] = { + 0x00, 0x01, 0x03, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x50, 0xD0, 0x70, + 0xF0, 0x34, 0x1C, 0x05, 0x0D, 0x13, 0x07, 0x0F, 0x44, 0xC4, 0x14, 0x4C, + 0xCC, 0x3C, 0x41, 0xC1, 0x11, 0x31, 0x43, 0xC3, 0x33, 0x54, 0x74, 0xDC, + 0xFC, 0x71, 0x15, 0x4D, 0x1D, 0xD3, 0xC7, 0x37, 0x3F, 0xD4, 0xF4, 0x5C, + 0x7C, 0x51, 0xD1, 0xF1, 0x45, 0xC5, 0x55, 0x35, 0xCD, 0xDD, 0x3D, 0x53, + 0x73, 0xF3, 0x47, 0x17, 0x77, 0x4F, 0xCF, 0x1F, 0xFF, 0xF5, 0x7D, 0xD7, + 0x5F, 0xD5, 0x75, 0x5D, 0xFD, 0x57, 0xF7, 0xDF, 0x7F +}; + +static const uint8_t huff_b02_cb[14] = { + 1, 12, 1, 0, 0, 4, 0, 8, 4, 9, 19, 13, 13, 10 +}; + +static const uint8_t huff_b02_xlat[81] = { + 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x05, + 0x15, 0x80, 0x51, 0x45, 0x55, 0x90, 0x20, 0x60, 0x24, 0x08, 0x18, 0x09, + 0x02, 0x06, 0x84, 0x94, 0x64, 0x48, 0x58, 0x81, 0x91, 0x21, 0x61, 0x95, + 0x25, 0x65, 0x19, 0x59, 0x42, 0x12, 0x46, 0x16, 0x56, 0xA0, 0xA4, 0x28, + 0x68, 0x85, 0xA5, 0x49, 0x29, 0x69, 0x52, 0x0A, 0x1A, 0x5A, 0x88, 0x98, + 0xA1, 0x89, 0x99, 0xA9, 0x22, 0x62, 0x96, 0x26, 0x66, 0x4A, 0x6A, 0xA8, + 0x82, 0x92, 0xA2, 0x86, 0xA6, 0x8A, 0x9A, 0x2A, 0xAA +}; + +static const uint8_t huff_b03_cb[11] = { 1, 9, 1, 0, 0, 4, 0, 5, 12, 13, 14 }; + +static const uint8_t huff_b03_xlat[49] = { + 0x00, 0x08, 0x38, 0x01, 0x07, 0x30, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x18, + 0x28, 0x31, 0x02, 0x3A, 0x03, 0x05, 0x06, 0x0E, 0x17, 0x37, 0x11, 0x19, + 0x29, 0x0A, 0x32, 0x0B, 0x3B, 0x0D, 0x15, 0x3D, 0x3E, 0x1F, 0x2F, 0x12, + 0x1A, 0x2A, 0x13, 0x1B, 0x2B, 0x33, 0x1D, 0x2D, 0x35, 0x16, 0x1E, 0x2E, + 0x36 +}; + +static const uint8_t huff_b04_cb[12] = { + 2, 11, 1, 0, 4, 4, 5, 9, 30, 45, 21, 2 +}; + +static const uint8_t huff_b04_xlat[121] = { + 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x02, + 0xF2, 0x0E, 0x21, 0xE1, 0x12, 0xE2, 0x1E, 0x2E, 0xFE, 0x2F, 0xEF, 0x30, + 0x50, 0xB0, 0xC0, 0xD0, 0x31, 0xB1, 0xD1, 0x22, 0xD2, 0x03, 0x13, 0xE3, + 0xF3, 0xF4, 0x05, 0xE5, 0xF5, 0x0B, 0x1B, 0x0C, 0x0D, 0x1D, 0x2D, 0xFD, + 0x3E, 0xEE, 0x3F, 0x5F, 0xDF, 0x40, 0x41, 0x51, 0xC1, 0x32, 0x42, 0x52, + 0xB2, 0xC2, 0x23, 0x33, 0xB3, 0xC3, 0xD3, 0x04, 0x14, 0x24, 0xD4, 0xE4, + 0x15, 0x25, 0xC5, 0xD5, 0x2B, 0x3B, 0xEB, 0xFB, 0x1C, 0x2C, 0x3C, 0x5C, + 0xEC, 0xFC, 0x3D, 0x5D, 0xDD, 0xED, 0x4E, 0x5E, 0xBE, 0xCE, 0xDE, 0x4F, + 0xBF, 0xCF, 0x43, 0x53, 0x34, 0x54, 0xB4, 0xC4, 0x35, 0x45, 0x55, 0xB5, + 0x4B, 0x5B, 0xCB, 0xDB, 0x4C, 0xBC, 0xCC, 0xDC, 0x4D, 0xBD, 0xCD, 0x44, + 0xBB +}; + +static const uint8_t huff_b05_cb[11] = { + 3, 11, 1, 4, 4, 4, 12, 30, 73, 75, 22 +}; + +static const uint8_t huff_b05_xlat[225] = { + 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x02, + 0x0E, 0x30, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x03, 0x0D, 0x1E, 0xFE, 0x2F, + 0xEF, 0x40, 0x60, 0x70, 0x90, 0xA0, 0xC0, 0x31, 0xD1, 0x22, 0x32, 0xD2, + 0xE2, 0x13, 0x23, 0xE3, 0xF3, 0x04, 0x06, 0x07, 0x09, 0x0A, 0x0C, 0x1D, + 0x2D, 0xFD, 0x2E, 0x3E, 0xEE, 0x3F, 0xDF, 0x50, 0xB0, 0x41, 0x51, 0x61, + 0x71, 0x91, 0xA1, 0xB1, 0xC1, 0x42, 0x62, 0x72, 0x92, 0xA2, 0xC2, 0x33, + 0x93, 0xA3, 0xD3, 0x14, 0x24, 0xE4, 0xF4, 0x05, 0x15, 0xF5, 0x16, 0x26, + 0xD6, 0xE6, 0xF6, 0x17, 0x27, 0xD7, 0xE7, 0xF7, 0x19, 0x29, 0x39, 0xE9, + 0xF9, 0x1A, 0x2A, 0xEA, 0xFA, 0x0B, 0x1B, 0xFB, 0x1C, 0x2C, 0xEC, 0xFC, + 0x3D, 0x7D, 0x9D, 0xDD, 0xED, 0x4E, 0x6E, 0x7E, 0x9E, 0xAE, 0xCE, 0xDE, + 0x4F, 0x5F, 0x6F, 0x7F, 0x9F, 0xAF, 0xBF, 0xCF, 0x52, 0xB2, 0x43, 0x53, + 0x63, 0x73, 0xB3, 0xC3, 0x34, 0x44, 0x64, 0x74, 0x94, 0xA4, 0xB4, 0xC4, + 0xD4, 0x25, 0x35, 0x65, 0x75, 0x95, 0xA5, 0xD5, 0xE5, 0x36, 0x46, 0x56, + 0x66, 0xA6, 0xB6, 0xC6, 0x37, 0x47, 0x57, 0xB7, 0xC7, 0x49, 0x59, 0x69, + 0xB9, 0xC9, 0xD9, 0x3A, 0x4A, 0x5A, 0x6A, 0xAA, 0xBA, 0xCA, 0xDA, 0x2B, + 0x3B, 0x6B, 0x7B, 0x9B, 0xAB, 0xDB, 0xEB, 0x3C, 0x4C, 0x6C, 0x7C, 0x9C, + 0xAC, 0xCC, 0xDC, 0x4D, 0x5D, 0x6D, 0xAD, 0xBD, 0xCD, 0x5E, 0xBE, 0x54, + 0x45, 0x55, 0xB5, 0xC5, 0x76, 0x96, 0x67, 0x77, 0x97, 0xA7, 0x79, 0x99, + 0xA9, 0x7A, 0x9A, 0x4B, 0x5B, 0xBB, 0xCB, 0x5C, 0xBC +}; + +static const uint8_t huff_b07_cb[9] = { 3, 9, 3, 2, 4, 8, 23, 13, 10 }; + +static const uint8_t huff_b07_xlat[63] = { + 0, 1, 63, 2, 62, 3, 4, 60, 61, 5, 6, 7, 8, 56, 57, 58, + 59, 9, 10, 11, 12, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, + 37, 38, 39, 51, 52, 53, 54, 55, 13, 14, 15, 16, 17, 18, 19, 45, + 46, 47, 48, 49, 50, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44 +}; + +static const uint8_t huff_b12_cb[10] = { 3, 10, 1, 3, 12, 0, 30, 9, 18, 8 }; + +static const uint8_t huff_b12_xlat[81] = { + 0x00, 0x40, 0x04, 0x01, 0x10, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x51, + 0x05, 0x45, 0x15, 0x55, 0x80, 0x90, 0x20, 0x60, 0x84, 0x94, 0x24, 0x64, + 0x08, 0x48, 0x18, 0x81, 0x91, 0x61, 0x85, 0x95, 0x25, 0x65, 0x09, 0x49, + 0x19, 0x59, 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 0xA4, 0x58, + 0x68, 0x21, 0xA5, 0x29, 0x69, 0x1A, 0x5A, 0xA0, 0x88, 0x98, 0x28, 0xA1, + 0x89, 0x99, 0xA9, 0x92, 0x22, 0x62, 0x86, 0x96, 0x26, 0x66, 0x0A, 0x4A, + 0x6A, 0xA8, 0x82, 0xA2, 0xA6, 0x8A, 0x9A, 0x2A, 0xAA +}; + +static const uint8_t huff_b14_cb[14] = { + 1, 12, 1, 0, 0, 4, 0, 3, 5, 16, 28, 34, 26, 4 +}; + +static const uint8_t huff_b14_xlat[121] = { + 0x00, 0x10, 0xF0, 0x01, 0x0F, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x11, 0x02, + 0x0E, 0x30, 0x50, 0xB0, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x03, 0x05, 0x0B, + 0x0D, 0x1E, 0xFE, 0x2F, 0xEF, 0x40, 0xC0, 0x31, 0x51, 0xB1, 0xC1, 0xD1, + 0x22, 0x52, 0xE2, 0x13, 0xF3, 0x04, 0x15, 0xF5, 0x1B, 0xEB, 0xFB, 0x0C, + 0x1D, 0xFD, 0x2E, 0x5E, 0xEE, 0x3F, 0x5F, 0xBF, 0xDF, 0x41, 0x32, 0x42, + 0xB2, 0xD2, 0x23, 0x53, 0xB3, 0xE3, 0x14, 0x24, 0xE4, 0xF4, 0x25, 0x35, + 0xD5, 0xE5, 0x2B, 0x3B, 0xDB, 0x1C, 0x2C, 0xBC, 0xEC, 0xFC, 0x2D, 0xBD, + 0xED, 0x3E, 0x4E, 0xBE, 0xDE, 0x4F, 0xCF, 0xC2, 0x33, 0x43, 0xC3, 0xD3, + 0x34, 0x44, 0x54, 0xB4, 0xD4, 0x45, 0x55, 0xC5, 0x4B, 0xCB, 0x3C, 0x4C, + 0x5C, 0xCC, 0xDC, 0x3D, 0x4D, 0x5D, 0xCD, 0xDD, 0xCE, 0xC4, 0xB5, 0x5B, + 0xBB +}; + +static const uint8_t huff_b16_cb[11] = { + 4, 12, 4, 4, 9, 13, 37, 76, 72, 39, 2 +}; + +static const uint8_t huff_b16_xlat[256] = { + 0x00, 0x10, 0x01, 0x11, 0x20, 0x21, 0x02, 0x12, 0x30, 0x31, 0x41, 0x22, + 0x32, 0x03, 0x13, 0x23, 0x14, 0x40, 0x51, 0x61, 0x42, 0x52, 0x33, 0x43, + 0x04, 0x24, 0x34, 0x15, 0x25, 0x16, 0x50, 0x60, 0x70, 0x71, 0x81, 0xD1, + 0xE1, 0x62, 0x72, 0x82, 0xD2, 0x53, 0x63, 0x73, 0xD3, 0x44, 0x54, 0x05, + 0x35, 0x45, 0x55, 0x06, 0x26, 0x36, 0x07, 0x17, 0x27, 0x37, 0x18, 0x28, + 0x19, 0x1D, 0x2D, 0x3D, 0x1E, 0x2E, 0x1F, 0x80, 0x90, 0xD0, 0xE0, 0xF0, + 0x91, 0xA1, 0xB1, 0xC1, 0xF1, 0x92, 0xA2, 0xB2, 0xC2, 0xE2, 0xF2, 0x83, + 0x93, 0xA3, 0xC3, 0xE3, 0xF3, 0x64, 0x74, 0x84, 0x94, 0xD4, 0xE4, 0xF4, + 0x65, 0x75, 0x85, 0xD5, 0xE5, 0x46, 0x56, 0x66, 0x76, 0xD6, 0xE6, 0x47, + 0x57, 0x67, 0xD7, 0x08, 0x38, 0x48, 0x58, 0x09, 0x29, 0x39, 0x49, 0x0A, + 0x1A, 0x2A, 0x3A, 0x1B, 0x2B, 0x0C, 0x1C, 0x2C, 0x3C, 0x0D, 0x4D, 0x5D, + 0x6D, 0x7D, 0x0E, 0x3E, 0x4E, 0x5E, 0x6E, 0x0F, 0x2F, 0x3F, 0x4F, 0xA0, + 0xB0, 0xC0, 0xB3, 0xA4, 0xB4, 0xC4, 0x95, 0xA5, 0xB5, 0xC5, 0xF5, 0x86, + 0x96, 0xA6, 0xB6, 0xC6, 0xF6, 0x77, 0x87, 0x97, 0xA7, 0xC7, 0xE7, 0xF7, + 0x68, 0x78, 0x88, 0x98, 0xD8, 0xE8, 0xF8, 0x59, 0x69, 0x79, 0x89, 0xD9, + 0xE9, 0xF9, 0x4A, 0x5A, 0x6A, 0x7A, 0xDA, 0xEA, 0x0B, 0x3B, 0x4B, 0x5B, + 0xDB, 0xEB, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0xDC, 0x8D, 0x9D, 0xAD, 0xBD, + 0xCD, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xB7, + 0xA8, 0xB8, 0xC8, 0x99, 0xA9, 0xB9, 0xC9, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, + 0xFA, 0x6B, 0x7B, 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xFB, 0x9C, 0xAC, 0xBC, + 0xCC, 0xEC, 0xFC, 0xDD, 0xED, 0xFD, 0xCE, 0xDE, 0xEE, 0xFE, 0xAF, 0xBF, + 0xCF, 0xDF, 0xEF, 0xFF +}; + +static const uint8_t huff_b26_cb[12] = { + 3, 12, 2, 2, 4, 5, 11, 26, 67, 78, 51, 10 +}; + +static const uint8_t huff_b26_xlat[256] = { + 0x00, 0x01, 0x10, 0x11, 0x20, 0x21, 0x02, 0x12, 0x30, 0x31, 0x22, 0x03, + 0x13, 0x40, 0x41, 0x51, 0x32, 0x42, 0x23, 0x33, 0x04, 0x14, 0x24, 0x15, + 0x50, 0x61, 0x71, 0xD1, 0xE1, 0x52, 0x62, 0xD2, 0x43, 0x53, 0xD3, 0x34, + 0x44, 0x05, 0x25, 0x35, 0x06, 0x16, 0x26, 0x17, 0x18, 0x1D, 0x2D, 0x3D, + 0x1E, 0x2E, 0x60, 0x70, 0x80, 0xD0, 0xE0, 0xF0, 0x81, 0x91, 0xA1, 0xC1, + 0xF1, 0x72, 0x82, 0x92, 0xC2, 0xE2, 0xF2, 0x63, 0x73, 0xE3, 0xF3, 0x54, + 0x64, 0x74, 0xD4, 0xE4, 0xF4, 0x45, 0x55, 0x65, 0xD5, 0xE5, 0xF5, 0x36, + 0x46, 0x56, 0xD6, 0xE6, 0x07, 0x27, 0x37, 0x47, 0xD7, 0x08, 0x28, 0x38, + 0x19, 0x29, 0x1A, 0x1B, 0x1C, 0x2C, 0x0D, 0x4D, 0x5D, 0x6D, 0x7D, 0x0E, + 0x3E, 0x4E, 0x5E, 0x6E, 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x90, 0xA0, 0xC0, + 0xB1, 0xA2, 0xB2, 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0x84, 0x94, 0xA4, 0xC4, + 0x75, 0x85, 0x95, 0xC5, 0x66, 0x76, 0x86, 0x96, 0xC6, 0xF6, 0x57, 0x67, + 0x77, 0xE7, 0xF7, 0x48, 0x58, 0x68, 0x78, 0xD8, 0xE8, 0xF8, 0x09, 0x39, + 0x49, 0x59, 0xD9, 0xE9, 0xF9, 0x0A, 0x2A, 0x3A, 0x4A, 0xDA, 0xEA, 0x0B, + 0x2B, 0x3B, 0xDB, 0xEB, 0x0C, 0x3C, 0x4C, 0x5C, 0x6C, 0xDC, 0x8D, 0x9D, + 0xAD, 0xBD, 0xCD, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xB0, 0xB4, 0xA5, 0xB5, 0xA6, 0xB6, 0x87, 0x97, 0xA7, + 0xB7, 0xC7, 0x88, 0x98, 0xA8, 0xC8, 0x69, 0x79, 0x89, 0x99, 0xA9, 0xC9, + 0x5A, 0x6A, 0x7A, 0x9A, 0xCA, 0xFA, 0x4B, 0x5B, 0x6B, 0x7B, 0xCB, 0xFB, + 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xEC, 0xFC, 0xDD, 0xED, 0xFD, 0xDE, + 0xEE, 0xFE, 0xBF, 0xCF, 0xDF, 0xEF, 0xB8, 0xB9, 0x8A, 0xAA, 0xBA, 0x8B, + 0x9B, 0xAB, 0xBB, 0xFF +}; + +static const uint8_t huff_b32_cb[12] = { + 2, 11, 1, 0, 4, 6, 7, 10, 22, 11, 16, 4 +}; + +static const uint8_t huff_b32_xlat[81] = { + 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x41, 0x11, 0x05, 0x80, + 0x54, 0x51, 0x45, 0x15, 0x55, 0x02, 0x90, 0x20, 0x60, 0x84, 0x24, 0x08, + 0x18, 0x09, 0x12, 0x06, 0xA0, 0x94, 0x64, 0x48, 0x58, 0x81, 0x91, 0x21, + 0x61, 0x85, 0x95, 0x25, 0x65, 0x49, 0x19, 0x59, 0x42, 0x52, 0x46, 0x16, + 0x56, 0x0A, 0xA4, 0x28, 0x68, 0xA1, 0xA5, 0x29, 0x69, 0x26, 0x4A, 0x1A, + 0x5A, 0x88, 0x98, 0xA8, 0x89, 0x99, 0xA9, 0x82, 0x92, 0x22, 0x62, 0x86, + 0x96, 0x66, 0x9A, 0x2A, 0x6A, 0xA2, 0xA6, 0x8A, 0xAA +}; + +static const uint8_t huff_b33_cb[13] = { + 2, 12, 1, 0, 0, 4, 11, 8, 28, 92, 97, 13, 2 +}; + +static const uint8_t huff_b33_xlat[256] = { + 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x51, + 0x05, 0x45, 0x15, 0x55, 0x20, 0x95, 0x65, 0x49, 0x59, 0x52, 0x46, 0x16, + 0x80, 0x90, 0x60, 0x84, 0x94, 0x24, 0x64, 0xA4, 0x08, 0x48, 0x18, 0x58, + 0x81, 0x91, 0x21, 0x61, 0x85, 0x25, 0x09, 0x19, 0x69, 0x02, 0x42, 0x12, + 0x06, 0x56, 0x5A, 0x57, 0xD0, 0x74, 0x68, 0x5C, 0xC1, 0xD5, 0xA5, 0xE5, + 0x75, 0xB5, 0xF5, 0x99, 0xD9, 0xA9, 0xE9, 0x79, 0xB9, 0xF9, 0x1D, 0x5D, + 0x9D, 0xDD, 0x6D, 0xAD, 0xED, 0x7D, 0xBD, 0xFD, 0x82, 0x92, 0xD2, 0x62, + 0x96, 0xD6, 0x26, 0x66, 0xA6, 0xE6, 0x76, 0xB6, 0xF6, 0x0A, 0x4A, 0x1A, + 0x9A, 0xDA, 0x2A, 0x6A, 0xAA, 0xEA, 0x7A, 0xBA, 0xFA, 0x5E, 0x9E, 0xDE, + 0x6E, 0xAE, 0xEE, 0x7E, 0xBE, 0xFE, 0x03, 0x13, 0x53, 0x17, 0x97, 0xD7, + 0x67, 0xA7, 0xE7, 0x77, 0xB7, 0xF7, 0x5B, 0x9B, 0xDB, 0x6B, 0xAB, 0xEB, + 0x7B, 0xBB, 0xFB, 0x5F, 0x9F, 0xDF, 0x6F, 0xAF, 0xEF, 0x7F, 0xBF, 0xFF, + 0xC0, 0xA0, 0xE0, 0x30, 0xC4, 0xD4, 0xE4, 0x34, 0xB4, 0xF4, 0x88, 0xC8, + 0x98, 0xD8, 0x28, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, 0x0C, 0x4C, 0x1C, + 0x9C, 0xDC, 0x6C, 0xAC, 0xEC, 0x7C, 0xBC, 0xFC, 0xD1, 0xA1, 0xE1, 0x31, + 0x71, 0xB1, 0xF1, 0xC5, 0x35, 0x89, 0xC9, 0x29, 0x39, 0x0D, 0x4D, 0x8D, + 0xCD, 0x2D, 0x3D, 0x22, 0xA2, 0xE2, 0x72, 0xB2, 0xF2, 0x86, 0xC6, 0x36, + 0x8A, 0xCA, 0x3A, 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x2E, 0x3E, 0x43, 0x83, + 0x93, 0xD3, 0x23, 0x63, 0xA3, 0xE3, 0x73, 0xB3, 0xF3, 0x07, 0x47, 0x87, + 0xC7, 0x27, 0x37, 0x4B, 0x8B, 0xCB, 0x1B, 0x2B, 0x3B, 0x4F, 0x8F, 0xCF, + 0x1F, 0x70, 0xB0, 0xF0, 0x8C, 0xCC, 0x2C, 0x3C, 0xC2, 0x32, 0xC3, 0x0F, + 0x2F, 0x3F, 0x33, 0x0B +}; + +static const uint8_t huff_b35_cb[14] = { + 1, 12, 1, 0, 0, 0, 4, 6, 6, 14, 42, 63, 59, 30 +}; + +static const uint8_t huff_b35_xlat[225] = { + 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x02, 0x0E, 0x1F, 0xFF, 0x20, + 0xE0, 0x21, 0xF2, 0xFE, 0xEF, 0x30, 0xD0, 0xE1, 0x12, 0x22, 0xE2, 0x03, + 0x0D, 0x1D, 0x1E, 0x2E, 0xEE, 0x2F, 0xDF, 0x40, 0x60, 0x70, 0x90, 0xA0, + 0xB0, 0xC0, 0x31, 0x71, 0x91, 0xC1, 0xD1, 0x32, 0xD2, 0x13, 0xE3, 0xF3, + 0x04, 0x05, 0x06, 0x07, 0x17, 0xF7, 0x09, 0x19, 0x0A, 0x1A, 0xFA, 0x0C, + 0x1C, 0x2D, 0xED, 0xFD, 0x3E, 0x7E, 0xDE, 0x3F, 0x6F, 0x7F, 0x9F, 0xAF, + 0xCF, 0x50, 0x41, 0x51, 0x61, 0xA1, 0xB1, 0x62, 0x72, 0x92, 0xA2, 0xC2, + 0x23, 0x33, 0x63, 0x73, 0x93, 0xA3, 0xD3, 0x14, 0x24, 0x34, 0xD4, 0xE4, + 0xF4, 0x15, 0xF5, 0x16, 0x26, 0xD6, 0xE6, 0xF6, 0x27, 0x37, 0x47, 0xE7, + 0x29, 0x39, 0xC9, 0xD9, 0xE9, 0xF9, 0x2A, 0xEA, 0x0B, 0x1B, 0xFB, 0x2C, + 0x7C, 0xEC, 0xFC, 0x3D, 0x4D, 0x6D, 0x7D, 0xDD, 0x4E, 0x5E, 0x6E, 0x9E, + 0xAE, 0xCE, 0x4F, 0x5F, 0x42, 0x52, 0xB2, 0x43, 0xB3, 0xC3, 0x44, 0x64, + 0x74, 0x94, 0xA4, 0x25, 0x35, 0x65, 0x75, 0x95, 0xA5, 0xE5, 0x36, 0x46, + 0x66, 0x76, 0x96, 0xA6, 0xB6, 0xC6, 0x57, 0xA7, 0xB7, 0xC7, 0xD7, 0x59, + 0xA9, 0xB9, 0x3A, 0x4A, 0x6A, 0xCA, 0xDA, 0x2B, 0x3B, 0x6B, 0x9B, 0xAB, + 0xDB, 0xEB, 0x3C, 0x6C, 0x9C, 0xAC, 0xCC, 0xDC, 0x5D, 0x9D, 0xAD, 0xBD, + 0xCD, 0xBE, 0xBF, 0x53, 0x54, 0xB4, 0xC4, 0x45, 0x55, 0xB5, 0xC5, 0xD5, + 0x56, 0x67, 0x77, 0x97, 0x49, 0x69, 0x79, 0x99, 0x5A, 0x7A, 0x9A, 0xAA, + 0xBA, 0x4B, 0x5B, 0x7B, 0xBB, 0xCB, 0x4C, 0x5C, 0xBC +}; + +static const uint8_t huff_b37_cb[13] = { + 1, 11, 1, 0, 2, 0, 2, 2, 6, 17, 14, 13, 6 +}; + +static const uint8_t huff_b37_xlat[63] = { + 0, 1, 63, 2, 62, 3, 61, 4, 5, 6, 58, 59, 60, 7, 8, 9, + 10, 25, 26, 27, 28, 29, 34, 35, 37, 38, 39, 55, 56, 57, 11, 13, + 14, 15, 30, 31, 33, 36, 49, 50, 51, 52, 53, 54, 12, 16, 17, 18, + 19, 21, 41, 43, 44, 45, 46, 47, 48, 20, 22, 23, 24, 40, 42 +}; + +static const uint8_t huff_b41_cb[14] = { + 1, 12, 1, 0, 0, 1, 7, 0, 20, 4, 10, 24, 2, 12 +}; + +static const uint8_t huff_b41_xlat[81] = { + 0x00, 0x01, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x03, 0x50, 0xD0, 0x70, + 0xF0, 0xC4, 0x14, 0x34, 0x4C, 0x1C, 0x3C, 0xC1, 0x11, 0x31, 0x05, 0x0D, + 0xC3, 0x13, 0x33, 0x07, 0x0F, 0x44, 0xCC, 0x41, 0x43, 0x54, 0x74, 0xDC, + 0xFC, 0x71, 0x15, 0x4D, 0x1D, 0x37, 0x3F, 0xD4, 0xF4, 0x5C, 0x7C, 0x51, + 0xD1, 0xF1, 0x45, 0xC5, 0x35, 0xCD, 0xDD, 0x3D, 0x53, 0xD3, 0x73, 0xF3, + 0x47, 0xC7, 0x17, 0x77, 0x4F, 0xCF, 0x1F, 0x55, 0xFF, 0xD5, 0x75, 0xF5, + 0x5D, 0x7D, 0xFD, 0x57, 0xD7, 0xF7, 0x5F, 0xDF, 0x7F +}; + +static const uint8_t huff_b42_cb[11] = { 1, 9, 1, 0, 1, 3, 2, 3, 7, 4, 4 }; + +static const uint8_t huff_b42_xlat[25] = { + 0x00, 0x07, 0x08, 0x38, 0x01, 0x39, 0x0F, 0x10, 0x09, 0x3F, 0x30, 0x31, + 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x11, 0x0A, 0x3E, 0x37, 0x12, 0x32, 0x16, + 0x36 +}; + +static const uint8_t huff_b43_cb[10] = { 2, 9, 1, 1, 3, 4, 9, 15, 12, 4 }; + +static const uint8_t huff_b43_xlat[49] = { + 0x00, 0x07, 0x08, 0x38, 0x01, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x30, 0x31, + 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x37, 0x18, 0x28, 0x11, 0x19, 0x29, 0x0A, + 0x03, 0x0B, 0x3B, 0x05, 0x0D, 0x3D, 0x3E, 0x1F, 0x2F, 0x12, 0x1A, 0x2A, + 0x32, 0x13, 0x33, 0x15, 0x35, 0x16, 0x1E, 0x2E, 0x36, 0x1B, 0x2B, 0x1D, + 0x2D +}; + +static const uint8_t huff_b47_cb[10] = { 2, 9, 1, 1, 3, 4, 6, 14, 22, 12 }; + +static const uint8_t huff_b47_xlat[63] = { + 0, 1, 2, 62, 63, 3, 4, 60, 61, 5, 6, 7, 57, 58, 59, 8, + 9, 10, 11, 12, 26, 27, 37, 38, 52, 53, 54, 55, 56, 13, 14, 15, + 16, 17, 18, 25, 28, 29, 30, 31, 33, 34, 35, 36, 39, 46, 47, 48, + 49, 50, 51, 19, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44, 45 +}; + +static const uint8_t huff_b52_cb[11] = { 1, 9, 1, 0, 1, 3, 2, 3, 7, 4, 4 }; + +static const uint8_t huff_b52_xlat[25] = { + 0x00, 0x01, 0x08, 0x38, 0x07, 0x39, 0x0F, 0x30, 0x09, 0x3F, 0x10, 0x31, + 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x11, 0x0A, 0x3E, 0x37, 0x12, 0x32, 0x16, + 0x36 +}; + +static const uint8_t huff_b53_cb[7] = { 1, 5, 1, 1, 1, 0, 4 }; // same as b63!!! + +static const uint8_t huff_b53_xlat[7] = { 0, 7, 1, 2, 3, 5, 6 }; + +static const uint8_t huff_b56_cb[11] = { 1, 9, 1, 0, 2, 0, 2, 4, 11, 9, 2 }; + +static const uint8_t huff_b56_xlat[31] = { + 0, 1, 31, 2, 30, 3, 4, 13, 29, 5, 6, 7, 14, 15, 17, 18, + 19, 26, 27, 28, 8, 9, 12, 20, 21, 22, 23, 24, 25, 10, 11 +}; + +static const uint8_t huff_b62_cb[14] = { + 1, 12, 1, 0, 0, 2, 3, 5, 12, 14, 18, 15, 9, 2 +}; + +static const uint8_t huff_b62_xlat[81] = { + 0x00, 0x40, 0x01, 0x10, 0x04, 0x02, 0x80, 0x50, 0x90, 0x05, 0x06, 0x20, + 0x60, 0x44, 0x14, 0x54, 0x24, 0x08, 0x18, 0x41, 0x11, 0x15, 0x09, 0xA0, + 0x84, 0x94, 0x64, 0xA4, 0x28, 0x51, 0x45, 0x55, 0x19, 0x12, 0x16, 0x0A, + 0x1A, 0x48, 0x58, 0x68, 0x81, 0x91, 0x21, 0x61, 0x85, 0x95, 0x25, 0x65, + 0x49, 0x59, 0x29, 0x69, 0x42, 0x46, 0x56, 0x88, 0x98, 0xA8, 0xA1, 0xA5, + 0x99, 0xA9, 0x52, 0x22, 0x26, 0x66, 0x4A, 0x5A, 0x2A, 0x6A, 0x89, 0x82, + 0x92, 0x62, 0x86, 0x96, 0xA6, 0x8A, 0xAA, 0xA2, 0x9A +}; + +static const uint8_t huff_b63_cb[7] = { 1, 5, 1, 1, 1, 0, 4 }; + +static const uint8_t huff_b63_xlat[7] = { 0, 1, 7, 2, 3, 5, 6 }; + +static const uint8_t huff_b64_cb[7] = { 1, 5, 1, 1, 1, 1, 2 }; + +static const uint8_t huff_b64_xlat[6] = { 1, 0, 2, 5, 3, 4 }; + +static const uint8_t huff_b65_cb[14] = { + 1, 12, 1, 0, 0, 2, 2, 2, 6, 12, 34, 92, 54, 20 +}; + +static const uint8_t huff_b65_xlat[225] = { + 0x00, 0xF0, 0x01, 0x10, 0x0F, 0x11, 0xF1, 0x20, 0xE0, 0x02, 0x0E, 0x1F, + 0xFF, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x07, 0x0A, 0x0D, 0x1E, 0xFE, 0x2F, + 0xEF, 0x30, 0x70, 0x90, 0xA0, 0xC0, 0x71, 0x91, 0xC1, 0xD1, 0x32, 0x92, + 0xE2, 0x03, 0x13, 0x63, 0x04, 0x06, 0xE6, 0xE7, 0xF7, 0x09, 0x19, 0x39, + 0xFA, 0x0C, 0x1C, 0xDD, 0xED, 0xFD, 0x2E, 0x7E, 0x9E, 0x3F, 0x9F, 0x40, + 0x50, 0x60, 0xB0, 0x31, 0x41, 0x61, 0xA1, 0xB1, 0x22, 0x42, 0x72, 0xA2, + 0xB2, 0xC2, 0xD2, 0x23, 0x33, 0x73, 0xA3, 0xC3, 0xD3, 0xE3, 0xF3, 0x14, + 0x24, 0x34, 0x44, 0x74, 0xD4, 0xE4, 0x05, 0x25, 0x45, 0x65, 0x95, 0xA5, + 0x16, 0x26, 0x46, 0x76, 0xA6, 0xB6, 0xC6, 0xD6, 0xF6, 0x17, 0x27, 0x37, + 0x47, 0x67, 0xA7, 0xD7, 0x29, 0x69, 0xB9, 0xD9, 0xE9, 0xF9, 0x1A, 0x2A, + 0x3A, 0x9A, 0xCA, 0xDA, 0xEA, 0x0B, 0x1B, 0x3B, 0x6B, 0xEB, 0xFB, 0x2C, + 0x6C, 0xEC, 0xFC, 0x1D, 0x2D, 0x4D, 0x6D, 0x9D, 0xAD, 0x3E, 0x4E, 0x6E, + 0xAE, 0xCE, 0xEE, 0x4F, 0x5F, 0x6F, 0xDF, 0x51, 0x52, 0x62, 0x43, 0x93, + 0xB3, 0x54, 0x94, 0xA4, 0xF4, 0x15, 0x75, 0xB5, 0xE5, 0xF5, 0x36, 0x56, + 0x66, 0x96, 0x57, 0x77, 0x49, 0x59, 0xA9, 0xC9, 0x4A, 0x5A, 0x6A, 0x7A, + 0xAA, 0xBA, 0x2B, 0x4B, 0x7B, 0x9B, 0xAB, 0xDB, 0x3C, 0x4C, 0x7C, 0x9C, + 0xAC, 0xBC, 0xCC, 0x3D, 0x5D, 0x7D, 0xBD, 0xCD, 0x5E, 0xBE, 0xDE, 0xBF, + 0xCF, 0x53, 0x64, 0xB4, 0xC4, 0x35, 0x55, 0xC5, 0xD5, 0x97, 0xB7, 0xC7, + 0x79, 0x99, 0x5B, 0xBB, 0xCB, 0x5C, 0xDC, 0x7F, 0xAF +}; + +static const uint8_t huff_b66_cb[14] = { + 1, 12, 1, 0, 0, 3, 0, 3, 3, 10, 40, 85, 61, 50 +}; + +static const uint8_t huff_b66_xlat[256] = { + 0x00, 0x10, 0x01, 0x11, 0x21, 0x02, 0x12, 0x20, 0x22, 0x13, 0x30, 0x31, + 0x41, 0xD1, 0xE1, 0x32, 0x52, 0x03, 0x23, 0x2D, 0x40, 0x50, 0x60, 0x80, + 0xD0, 0xE0, 0x51, 0x61, 0xF1, 0x42, 0x62, 0xD2, 0xE2, 0xF2, 0x33, 0x43, + 0xC3, 0xD3, 0xE3, 0x04, 0x14, 0xD4, 0xF4, 0x25, 0x35, 0x16, 0x17, 0xF7, + 0xD8, 0x1C, 0x3C, 0x0D, 0x1D, 0x3D, 0x5D, 0x0E, 0x1E, 0x2E, 0x7E, 0x2F, + 0xC0, 0xF0, 0x71, 0x81, 0x91, 0xC1, 0x72, 0x82, 0x92, 0xB2, 0xC2, 0x53, + 0x63, 0x73, 0x93, 0xA3, 0xF3, 0x24, 0x44, 0x64, 0x84, 0xA4, 0xB4, 0x05, + 0x15, 0x95, 0xD5, 0x06, 0x26, 0x36, 0x46, 0x96, 0xD6, 0xE6, 0xF6, 0x07, + 0x27, 0x37, 0xD7, 0xE7, 0x08, 0x18, 0x28, 0x38, 0xE8, 0xF8, 0x09, 0x19, + 0x29, 0xE9, 0xF9, 0x0A, 0x1A, 0xCA, 0xDA, 0xEA, 0x0B, 0x1B, 0xDB, 0xEB, + 0xFB, 0x2C, 0x4C, 0x5C, 0x7C, 0x8C, 0x4D, 0x6D, 0x8D, 0x9D, 0xFD, 0x3E, + 0x5E, 0x6E, 0x8E, 0x9E, 0xEE, 0x0F, 0x1F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, + 0xCF, 0x70, 0xA1, 0xA2, 0x83, 0xB3, 0x34, 0x74, 0xC4, 0xE4, 0x55, 0x65, + 0x85, 0xA5, 0xC5, 0xE5, 0xF5, 0x56, 0x66, 0x76, 0x86, 0xA6, 0xC6, 0x57, + 0x67, 0x77, 0x97, 0xA7, 0x48, 0x88, 0x98, 0x49, 0x59, 0x79, 0x99, 0x3A, + 0x4A, 0x8A, 0xBA, 0xFA, 0x2B, 0x7B, 0x0C, 0xAC, 0xBC, 0xCC, 0xEC, 0x7D, + 0xAD, 0xBD, 0xDD, 0x4E, 0xBE, 0xCE, 0xFE, 0x8F, 0x9F, 0xAF, 0xBF, 0xDF, + 0xEF, 0xFF, 0x90, 0xA0, 0xB0, 0xB1, 0x54, 0x94, 0x45, 0x75, 0xB5, 0xB6, + 0x47, 0x87, 0xB7, 0xC7, 0x58, 0x68, 0x78, 0xA8, 0xB8, 0xC8, 0x39, 0x69, + 0x89, 0xA9, 0xB9, 0xC9, 0xD9, 0x2A, 0x5A, 0x6A, 0x7A, 0x9A, 0xAA, 0x3B, + 0x4B, 0x5B, 0x6B, 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0x6C, 0x9C, 0xDC, 0xFC, + 0xCD, 0xED, 0xAE, 0xDE +}; + +static const uint8_t huff_b67_cb[10] = { 2, 9, 1, 2, 1, 4, 7, 10, 26, 12 }; + +static const uint8_t huff_b67_xlat[63] = { + 0, 1, 63, 62, 2, 3, 60, 61, 4, 5, 6, 7, 57, 58, 59, 8, + 9, 10, 11, 12, 52, 53, 54, 55, 56, 13, 14, 15, 16, 17, 18, 25, + 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 46, 47, 48, + 49, 50, 51, 19, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44, 45 +}; + +static const uint8_t huff_b71_cb[14] = { + 1, 12, 1, 0, 0, 1, 7, 0, 19, 5, 13, 23, 0, 12 +}; + +static const uint8_t huff_b71_xlat[81] = { + 0x00, 0x03, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x50, 0xD0, 0x70, + 0xF0, 0xC4, 0x14, 0x34, 0x4C, 0x1C, 0x3C, 0xC1, 0x11, 0x31, 0x05, 0x0D, + 0x13, 0x33, 0x07, 0x0F, 0x44, 0xCC, 0x41, 0x43, 0xC3, 0x54, 0x74, 0xDC, + 0xFC, 0xF1, 0xC5, 0x15, 0x1D, 0x53, 0xC7, 0x37, 0x4F, 0x3F, 0xD4, 0xF4, + 0x5C, 0x7C, 0x51, 0xD1, 0x71, 0x45, 0x55, 0x35, 0x4D, 0xCD, 0xDD, 0x3D, + 0xD3, 0x73, 0xF3, 0x47, 0x17, 0x77, 0xCF, 0x1F, 0xFF, 0xD5, 0x75, 0xF5, + 0x5D, 0x7D, 0xFD, 0x57, 0xD7, 0xF7, 0x5F, 0xDF, 0x7F +}; + +static const uint8_t huff_b73_cb[13] = { + 1, 11, 1, 0, 0, 0, 1, 4, 9, 4, 103, 110, 24 +}; + +static const uint8_t huff_b73_xlat[256] = { + 0x00, 0x40, 0x10, 0x04, 0x01, 0x05, 0x50, 0x14, 0x54, 0x41, 0x11, 0x51, + 0x45, 0x15, 0x55, 0x44, 0x95, 0x6A, 0x03, 0x80, 0xC0, 0x90, 0xD0, 0x94, + 0xD4, 0x24, 0x64, 0x58, 0x91, 0xA1, 0x85, 0xD5, 0x25, 0x65, 0xA5, 0xE5, + 0x75, 0xB5, 0xF5, 0x19, 0x59, 0x99, 0xD9, 0x69, 0xA9, 0xE9, 0x79, 0xB9, + 0xF9, 0x4D, 0x5D, 0x9D, 0xDD, 0x6D, 0xAD, 0xED, 0x7D, 0xBD, 0xFD, 0x02, + 0x42, 0x52, 0x06, 0x46, 0x16, 0x56, 0x96, 0xD6, 0x26, 0x66, 0xA6, 0xE6, + 0x76, 0xB6, 0xF6, 0x1A, 0x5A, 0x9A, 0xDA, 0xAA, 0xEA, 0x7A, 0xBA, 0xFA, + 0x5E, 0x9E, 0xDE, 0x6E, 0xAE, 0xEE, 0x7E, 0xBE, 0xFE, 0x07, 0x47, 0x57, + 0x97, 0xD7, 0x67, 0xA7, 0xE7, 0x77, 0xB7, 0xF7, 0x5B, 0x9B, 0xDB, 0x6B, + 0xAB, 0xEB, 0x7B, 0xBB, 0xFB, 0x5F, 0x9F, 0xDF, 0x6F, 0xAF, 0xEF, 0x7F, + 0xBF, 0xFF, 0x20, 0x60, 0x70, 0xB0, 0xF0, 0x84, 0xC4, 0xA4, 0xE4, 0x74, + 0xB4, 0xF4, 0x08, 0x88, 0x18, 0x98, 0xD8, 0x68, 0xA8, 0xE8, 0x78, 0xB8, + 0xF8, 0x1C, 0x5C, 0x9C, 0xDC, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, + 0x81, 0xD1, 0x21, 0x61, 0xE1, 0x71, 0xB1, 0xF1, 0xC5, 0x35, 0x09, 0x49, + 0x89, 0xC9, 0x29, 0x39, 0x0D, 0x8D, 0xCD, 0x1D, 0x2D, 0x3D, 0x92, 0xD2, + 0x22, 0x62, 0xA2, 0xE2, 0x72, 0xB2, 0xF2, 0x86, 0xC6, 0x36, 0x0A, 0x4A, + 0x8A, 0xCA, 0x2A, 0x3A, 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x2E, 0x3E, 0x13, + 0x53, 0x93, 0xD3, 0x63, 0xA3, 0xE3, 0x73, 0xB3, 0xF3, 0x87, 0xC7, 0x17, + 0x27, 0x37, 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x2B, 0x3B, 0x0F, 0x4F, 0x8F, + 0xCF, 0x1F, 0x2F, 0x3F, 0xA0, 0xE0, 0x30, 0x34, 0x48, 0xC8, 0x28, 0x38, + 0x0C, 0x4C, 0x8C, 0xCC, 0x2C, 0xC1, 0x31, 0x82, 0xC2, 0x12, 0x32, 0x43, + 0x83, 0xC3, 0x23, 0x33 +}; + +static const uint8_t huff_b74_cb[8] = { 1, 6, 1, 0, 2, 2, 2, 4 }; + +static const uint8_t huff_b74_xlat[11] = { + 0, 1, 15, 2, 14, 5, 13, 3, 4, 11, 12 +}; + +static const uint8_t huff_b75_cb[13] = { + 2, 12, 1, 4, 0, 0, 0, 8, 11, 24, 53, 64, 60 +}; + +static const uint8_t huff_b75_xlat[225] = { + 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x20, 0xE0, 0x11, 0xF1, 0x02, 0x0E, 0x1F, + 0xFF, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x03, 0x0D, 0x1E, 0xFE, 0x2F, 0xEF, + 0x30, 0x40, 0x60, 0x70, 0x90, 0xA0, 0xC0, 0x31, 0xD1, 0x22, 0xE2, 0x13, + 0xF3, 0x04, 0x06, 0x07, 0x09, 0x0C, 0x1D, 0xFD, 0x2E, 0xEE, 0x3F, 0xDF, + 0x50, 0xB0, 0x41, 0x61, 0x71, 0x91, 0xA1, 0xC1, 0x32, 0x62, 0x72, 0x92, + 0xA2, 0xD2, 0x23, 0xD3, 0xE3, 0x14, 0xF4, 0x05, 0x16, 0x26, 0xE6, 0xF6, + 0x17, 0x27, 0xE7, 0xF7, 0x19, 0x29, 0xF9, 0x0A, 0x1A, 0x2A, 0xFA, 0x0B, + 0x1C, 0x2C, 0xFC, 0x2D, 0x3D, 0xED, 0x3E, 0x4E, 0x7E, 0x9E, 0xDE, 0x4F, + 0x6F, 0x7F, 0x9F, 0xAF, 0xCF, 0x51, 0xB1, 0x42, 0x52, 0xB2, 0xC2, 0x33, + 0x63, 0x73, 0x93, 0xA3, 0xB3, 0xC3, 0x24, 0x34, 0x74, 0xA4, 0xD4, 0xE4, + 0x15, 0x25, 0x65, 0x95, 0xE5, 0xF5, 0x36, 0xD6, 0x37, 0x47, 0xC7, 0xD7, + 0x39, 0x59, 0xB9, 0xC9, 0xD9, 0xE9, 0x3A, 0x6A, 0xDA, 0xEA, 0x1B, 0x2B, + 0x9B, 0xAB, 0xEB, 0xFB, 0x6C, 0x7C, 0x9C, 0xAC, 0xEC, 0x4D, 0x6D, 0x7D, + 0x9D, 0xAD, 0xBD, 0xDD, 0x5E, 0x6E, 0xAE, 0xCE, 0x5F, 0x43, 0x53, 0x44, + 0x54, 0x64, 0x94, 0xB4, 0xC4, 0x35, 0x45, 0x55, 0x75, 0xA5, 0xB5, 0xC5, + 0xD5, 0x46, 0x56, 0x66, 0x76, 0x96, 0xA6, 0xB6, 0xC6, 0x57, 0x67, 0x77, + 0x97, 0xA7, 0xB7, 0x49, 0x69, 0x79, 0x99, 0xA9, 0x4A, 0x5A, 0x7A, 0x9A, + 0xAA, 0xBA, 0xCA, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0xBB, 0xCB, 0xDB, 0x3C, + 0x4C, 0x5C, 0xBC, 0xCC, 0xDC, 0x5D, 0xCD, 0xBE, 0xBF +}; + +static const uint8_t huff_b77_cb[12] = { + 2, 11, 1, 0, 4, 6, 10, 12, 7, 15, 4, 4 +}; + +static const uint8_t huff_b77_xlat[63] = { + 0, 1, 2, 62, 63, 3, 4, 5, 59, 60, 61, 6, 7, 8, 9, 10, + 54, 55, 56, 57, 58, 11, 12, 13, 14, 15, 16, 47, 49, 50, 51, 52, + 53, 17, 18, 19, 20, 45, 46, 48, 21, 22, 23, 24, 25, 26, 27, 37, + 38, 39, 40, 41, 42, 43, 44, 28, 29, 30, 35, 31, 33, 34, 36 +}; + +/** Tables for spectrum coding. */ +typedef struct Atrac3pSpecCodeTab { + uint8_t group_size; ///< number of coefficients grouped together + uint8_t num_coeffs; ///< 1 - map index to a single value, > 1 - map index to a vector of values + uint8_t bits; ///< number of bits a single coefficient occupy + uint8_t is_signed; ///< 1 - values in that table are signed ones, otherwise - absolute ones + + int redirect; ///< if >= 0: tells which huffman table must be reused + const uint8_t *cb; ///< pointer to the codebook descriptor + const uint8_t *xlat; ///< pointer to the translation table or NULL if none +} Atrac3pSpecCodeTab; + +static const Atrac3pSpecCodeTab atrac3p_spectra_tabs[112] = { + /* table set = A */ + /* code table = 0 */ + { 1, 4, 2, 1, -1, huff_a01_cb, huff_a01_xlat }, // wordlen = 1 + { 1, 4, 2, 0, -1, huff_a02_cb, huff_a02_xlat }, // wordlen = 2 + { 1, 2, 3, 1, -1, huff_a03_cb, huff_a03_xlat }, // wordlen = 3 + { 1, 1, 3, 0, -1, huff_a04_cb, huff_a04_xlat }, // wordlen = 4 + { 1, 2, 4, 1, -1, huff_a05_cb, huff_a05_xlat }, // wordlen = 5 + { 1, 1, 4, 0, -1, huff_a06_cb, huff_a06_xlat }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_a07_cb, huff_a07_xlat }, // wordlen = 7 + + /* code table = 1 */ + { 4, 4, 2, 1, -1, huff_a11_cb, huff_a11_xlat }, // wordlen = 1 + { 1, 4, 2, 0, -1, huff_a12_cb, huff_a12_xlat }, // wordlen = 2 + { 1, 2, 3, 1, -1, huff_a13_cb, huff_a13_xlat }, // wordlen = 3 + { 1, 2, 4, 1, -1, huff_a14_cb, huff_a14_xlat }, // wordlen = 4 + { 1, 2, 4, 1, -1, huff_a15_cb, huff_a15_xlat }, // wordlen = 5 + { 1, 2, 4, 0, -1, huff_a16_cb, huff_a16_xlat }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_a17_cb, huff_a17_xlat }, // wordlen = 7 + + /* code table = 2 */ + { 1, 4, 2, 1, -1, huff_a21_cb, huff_a21_xlat }, // wordlen = 1 + { 1, 2, 3, 1, -1, huff_a22_cb, huff_a22_xlat }, // wordlen = 2 + { 1, 2, 3, 1, -1, huff_a23_cb, huff_a23_xlat }, // wordlen = 3 + { 1, 1, 3, 0, -1, huff_a24_cb, NULL }, // wordlen = 4 + { 1, 1, 3, 0, -1, huff_a25_cb, huff_a25_xlat }, // wordlen = 5 + { 1, 2, 4, 0, -1, huff_a26_cb, huff_a26_xlat }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_a27_cb, huff_a27_xlat }, // wordlen = 7 + + /* code table = 3 */ + { 1, 2, 2, 1, -1, huff_a31_cb, huff_a31_xlat }, // wordlen = 1 + { 1, 4, 2, 0, -1, huff_a32_cb, huff_a32_xlat }, // wordlen = 2 + { 1, 4, 2, 0, -1, huff_a33_cb, huff_a33_xlat }, // wordlen = 3 + { 1, 1, 3, 0, -1, huff_a34_cb, huff_a34_xlat }, // wordlen = 4 + { 1, 2, 4, 1, -1, huff_a35_cb, huff_a35_xlat }, // wordlen = 5 + { 1, 2, 4, 0, -1, huff_a36_cb, huff_a36_xlat }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_a37_cb, huff_a37_xlat }, // wordlen = 7 + + /* code table = 4 */ + { 1, 4, 2, 1, -1, huff_a41_cb, huff_a41_xlat }, // wordlen = 1 + { 1, 4, 2, 0, -1, huff_a42_cb, huff_a42_xlat }, // wordlen = 2 + { 1, 1, 3, 1, -1, huff_a43_cb, huff_a43_xlat }, // wordlen = 3 + { 1, 2, 4, 1, -1, huff_a44_cb, huff_a44_xlat }, // wordlen = 4 + { 1, 1, 3, 0, -1, huff_a45_cb, huff_a45_xlat }, // wordlen = 5 + { 1, 2, 4, 0, -1, huff_a46_cb, huff_a46_xlat }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_a47_cb, huff_a47_xlat }, // wordlen = 7 + + /* code table = 5 */ + { 1, 4, 2, 1, -1, huff_a51_cb, huff_a51_xlat }, // wordlen = 1 + { 1, 2, 3, 1, -1, huff_a52_cb, huff_a52_xlat }, // wordlen = 2 + { 1, 1, 3, 1, -1, huff_a43_cb, huff_a53_xlat }, // wordlen = 3 + { 1, 2, 4, 1, -1, huff_a54_cb, huff_a54_xlat }, // wordlen = 4 + { 1, 1, 3, 0, -1, huff_a55_cb, huff_a55_xlat }, // wordlen = 5 + { 1, 1, 5, 1, -1, huff_a56_cb, huff_a56_xlat }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_a57_cb, huff_a57_xlat }, // wordlen = 7 + + /* code table = 6 */ + { 2, 4, 2, 1, -1, huff_a61_cb, huff_a61_xlat }, // wordlen = 1 + { 1, 2, 3, 1, -1, huff_a62_cb, huff_a62_xlat }, // wordlen = 2 + { 1, 4, 2, 0, -1, huff_a63_cb, huff_a63_xlat }, // wordlen = 3 + { 1, 2, 4, 1, -1, huff_a64_cb, huff_a64_xlat }, // wordlen = 4 + { 1, 1, 4, 1, -1, huff_a65_cb, huff_a65_xlat }, // wordlen = 5 + { 1, 1, 5, 1, -1, huff_a66_cb, huff_a66_xlat }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_a67_cb, huff_a67_xlat }, // wordlen = 7 + + /* code table = 7 */ + { 1, 2, 1, 0, -1, huff_a71_cb, NULL }, // wordlen = 1 + { 2, 4, 2, 0, -1, huff_a72_cb, huff_a72_xlat }, // wordlen = 2 + { 1, 2, 3, 1, -1, huff_a73_cb, huff_a73_xlat }, // wordlen = 3 + { 1, 2, 4, 1, -1, huff_a74_cb, huff_a74_xlat }, // wordlen = 4 + { 1, 1, 4, 1, -1, huff_a75_cb, huff_a75_xlat }, // wordlen = 5 + { 2, 2, 4, 0, -1, huff_a76_cb, huff_a76_xlat }, // wordlen = 6 + { 4, 1, 6, 1, 6, NULL, NULL }, // wordlen = 7 + + /* table set = B */ + /* code table = 0 */ + { 4, 4, 2, 1, -1, huff_b01_cb, huff_b01_xlat }, // wordlen = 1 + { 1, 4, 2, 0, -1, huff_b02_cb, huff_b02_xlat }, // wordlen = 2 + { 4, 2, 3, 1, -1, huff_b03_cb, huff_b03_xlat }, // wordlen = 3 + { 1, 2, 4, 1, -1, huff_b04_cb, huff_b04_xlat }, // wordlen = 4 + { 1, 2, 4, 1, -1, huff_b05_cb, huff_b05_xlat }, // wordlen = 5 + { 1, 1, 4, 0, 5, NULL, NULL }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_b07_cb, huff_b07_xlat }, // wordlen = 7 + + /* code table = 1 */ + { 1, 4, 2, 1, 14, NULL, NULL }, // wordlen = 1 + { 1, 4, 2, 0, -1, huff_b12_cb, huff_b12_xlat }, // wordlen = 2 + { 1, 2, 3, 1, 9, NULL, NULL }, // wordlen = 3 + { 1, 2, 4, 1, -1, huff_b14_cb, huff_b14_xlat }, // wordlen = 4 + { 1, 2, 4, 1, 11, NULL, NULL }, // wordlen = 5 + { 1, 2, 4, 0, -1, huff_b16_cb, huff_b16_xlat }, // wordlen = 6 + { 1, 1, 6, 1, 6, NULL, NULL }, // wordlen = 7 + + /* code table = 2 */ + { 4, 4, 2, 1, 28, NULL, NULL }, // wordlen = 1 + { 4, 4, 2, 0, 22, NULL, NULL }, // wordlen = 2 + { 1, 2, 3, 1, 2, NULL, NULL }, // wordlen = 3 + { 1, 2, 4, 1, 31, NULL, NULL }, // wordlen = 4 + { 2, 2, 4, 1, 60, NULL, NULL }, // wordlen = 5 + { 2, 2, 4, 0, -1, huff_b26_cb, huff_b26_xlat }, // wordlen = 6 + { 4, 1, 6, 1, 6, NULL, NULL }, // wordlen = 7 + + /* code table = 3 */ + { 1, 4, 2, 1, 35, NULL, NULL }, // wordlen = 1 + { 1, 4, 2, 0, -1, huff_b32_cb, huff_b32_xlat }, // wordlen = 2 + { 1, 4, 2, 0, -1, huff_b33_cb, huff_b33_xlat }, // wordlen = 3 + { 2, 2, 4, 1, 59, NULL, NULL }, // wordlen = 4 + { 1, 2, 4, 1, -1, huff_b35_cb, huff_b35_xlat }, // wordlen = 5 + { 1, 2, 4, 0, 75, NULL, NULL }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_b37_cb, huff_b37_xlat }, // wordlen = 7 + + /* code table = 4 */ + { 1, 4, 2, 1, -1, huff_b41_cb, huff_b41_xlat }, // wordlen = 1 + { 4, 2, 3, 1, -1, huff_b42_cb, huff_b42_xlat }, // wordlen = 2 + { 1, 2, 3, 1, -1, huff_b43_cb, huff_b43_xlat }, // wordlen = 3 + { 4, 2, 4, 1, 66, NULL, NULL }, // wordlen = 4 + { 1, 1, 3, 0, 32, NULL, NULL }, // wordlen = 5 + { 1, 2, 4, 0, 12, NULL, NULL }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_b47_cb, huff_b47_xlat }, // wordlen = 7 + + /* code table = 5 */ + { 2, 4, 2, 1, 42, NULL, NULL }, // wordlen = 1 + { 1, 2, 3, 1, -1, huff_b52_cb, huff_b52_xlat }, // wordlen = 2 + { 4, 1, 3, 1, -1, huff_b53_cb, huff_b53_xlat }, // wordlen = 3 + { 1, 1, 3, 0, 17, NULL, NULL }, // wordlen = 4 + { 1, 1, 3, 0, 39, NULL, NULL }, // wordlen = 5 + { 1, 1, 5, 1, -1, huff_b56_cb, huff_b56_xlat }, // wordlen = 6 + { 2, 1, 6, 1, 62, NULL, NULL }, // wordlen = 7 + + /* code table = 6 */ + { 1, 4, 2, 1, 28, NULL, NULL }, // wordlen = 1 + { 1, 4, 2, 0, -1, huff_b62_cb, huff_b62_xlat }, // wordlen = 2 + { 1, 1, 3, 1, -1, huff_b63_cb, huff_b63_xlat }, // wordlen = 3 + { 1, 1, 3, 0, -1, huff_b64_cb, huff_b64_xlat }, // wordlen = 4 + { 4, 2, 4, 1, -1, huff_b65_cb, huff_b65_xlat }, // wordlen = 5 + { 1, 2, 4, 0, -1, huff_b66_cb, huff_b66_xlat }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_b67_cb, huff_b67_xlat }, // wordlen = 7 + + /* code table = 7 */ + { 1, 4, 2, 1, -1, huff_b71_cb, huff_b71_xlat }, // wordlen = 1 + { 4, 4, 2, 0, 78, NULL, NULL }, // wordlen = 2 + { 4, 4, 2, 0, -1, huff_b73_cb, huff_b73_xlat }, // wordlen = 3 + { 1, 1, 4, 1, -1, huff_b74_cb, huff_b74_xlat }, // wordlen = 4 + { 1, 2, 4, 1, -1, huff_b75_cb, huff_b75_xlat }, // wordlen = 5 + { 1, 1, 5, 1, 47, NULL, NULL }, // wordlen = 6 + { 1, 1, 6, 1, -1, huff_b77_cb, huff_b77_xlat }, // wordlen = 7 +}; + +/* Huffman tables for gain control data. */ +static const uint8_t atrac3p_huff_gain_npoints1_cb[9] = { + 1, 7, 1, 1, 1, 1, 1, 1, 2 +}; + +static const uint8_t atrac3p_huff_gain_npoints2_xlat[8] = { + 0, 1, 7, 2, 6, 3, 4, 5 +}; + +static const uint8_t atrac3p_huff_gain_lev1_cb[9] = { 1, 7, 1, 0, 2, 2, 1, 2, 8 }; +static const uint8_t atrac3p_huff_gain_lev1_xlat[16] = { + 7, 5, 8, 6, 9, 4, 10, 11, 0, 1, 2, 3, 12, 13, 14, 15 +}; + +static const uint8_t atrac3p_huff_gain_lev2_cb[11] = { + 1, 9, 1, 1, 1, 1, 1, 0, 2, 0, 8 +}; + +static const uint8_t atrac3p_huff_gain_lev2_xlat[15] = { + 15, 14, 1, 13, 2, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11 +}; + +static const uint8_t atrac3p_huff_gain_lev3_cb[11] = { + 1, 9, 1, 0, 3, 1, 1, 0, 2, 0, 8 +}; + +static const uint8_t atrac3p_huff_gain_lev3_xlat[16] = { + 0, 1, 14, 15, 2, 13, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11 +}; + +static const uint8_t atrac3p_huff_gain_lev4_cb[11] = { + 1, 9, 1, 1, 1, 1, 1, 0, 1, 2, 8 +}; + +static const uint8_t atrac3p_huff_gain_lev4_xlat[16] = { + 0, 1, 15, 14, 2, 13, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11 +}; + +static const uint8_t atrac3p_huff_gain_loc1_cb[9] = { 2, 8, 1, 2, 4, 4, 4, 0, 16 }; +static const uint8_t atrac3p_huff_gain_loc1_xlat[31] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +static const uint8_t atrac3p_huff_gain_loc2_cb[8] = { 3, 8, 5, 3, 2, 3, 2, 16 }; +static const uint8_t atrac3p_huff_gain_loc2_xlat[31] = { + 2, 3, 4, 5, 6, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +static const uint8_t atrac3p_huff_gain_loc3_cb[7] = { 2, 6, 1, 0, 2, 11, 18 }; +static const uint8_t atrac3p_huff_gain_loc3_xlat[32] = { + 0, 1, 31, 2, 3, 4, 5, 6, 7, 26, 27, 28, 29, 30, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 +}; + +static const uint8_t atrac3p_huff_gain_loc4_cb[5] = { 4, 6, 3, 23, 6 }; +static const uint8_t atrac3p_huff_gain_loc4_xlat[32] = { + 0, 28, 29, 1, 2, 3, 4, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 30, 31, 5, 6, 7, 8, 9, 10 +}; + +static const uint8_t atrac3p_huff_gain_loc5_cb[9] = { 1, 7, 1, 0, 0, 3, 2, 6, 20 }; +static const uint8_t atrac3p_huff_gain_loc5_xlat[32] = { + 0, 1, 2, 31, 3, 4, 5, 6, 7, 8, 29, 30, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 +}; + +/* Huffman tables for GHA waves data. */ +static const uint8_t atrac3p_huff_tonebands_cb[8] = { 1, 6, 1, 0, 1, 2, 4, 8 }; +static const uint8_t atrac3p_huff_numwavs1_cb[9] = { 1, 7, 1, 1, 1, 1, 1, 1, 2 }; +static const uint8_t atrac3p_huff_numwavs2_cb[8] = { 1, 6, 1, 1, 1, 1, 0, 4 }; +static const uint8_t atrac3p_huff_numwavs2_xlat[8] = { 0, 1, 7, 2, 3, 4, 5, 6 }; +static const uint8_t atrac3p_huff_wav_ampsf1_cb[7] = { 4, 8, 10, 8, 6, 0, 8 }; +static const uint8_t atrac3p_huff_wav_ampsf1_xlat[32] = { + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 5, 6, 7, 18, 19, 20, + 21, 22, 4, 23, 24, 25, 26, 27, 0, 1, 2, 3, 28, 29, 30, 31 +}; + +static const uint8_t atrac3p_huff_wav_ampsf2_cb[7] = { 4, 8, 11, 5, 6, 6, 4 }; +static const uint8_t atrac3p_huff_wav_ampsf2_xlat[32] = { + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 14, 15, 16, 17, 29, + 9, 10, 11, 12, 13, 30, 4, 5, 6, 7, 8, 31, 0, 1, 2, 3 +}; + +static const uint8_t atrac3p_huff_wav_ampsf3_cb[9] = { 2, 8, 1, 3, 3, 1, 4, 4, 16 }; +static const uint8_t atrac3p_huff_wav_ampsf3_xlat[32] = { + 0, 1, 2, 31, 3, 29, 30, 4, 5, 6, 27, 28, 7, 24, 25, 26, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 +}; + +static const uint8_t atrac3p_huff_freq_cb[13] = { + 1, 11, 1, 0, 0, 2, 2, 0, 9, 9, 29, 104, 100 +}; + +static const uint8_t atrac3p_huff_freq_xlat[256] = { + 0, 1, 255, 2, 254, 3, 4, 5, 6, 7, 8, 251, 252, 253, 9, 10, + 11, 12, 246, 247, 248, 249, 250, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 243, 244, 245, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193 +}; + +#endif /* AVCODEC_ATRAC3PLUS_DATA_H */ diff --git a/ext/at3_standalone/atrac3plusdec.cpp b/ext/at3_standalone/atrac3plusdec.cpp new file mode 100644 index 0000000000..c57cee7a97 --- /dev/null +++ b/ext/at3_standalone/atrac3plusdec.cpp @@ -0,0 +1,363 @@ +/* + * ATRAC3+ compatible decoder + * + * Copyright (c) 2010-2013 Maxim Poliakovski + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Sony ATRAC3+ compatible decoder. + * + * Container formats used to store its data: + * RIFF WAV (.at3) and Sony OpenMG (.oma, .aa3). + * + * Technical description of this codec can be found here: + * http://wiki.multimedia.cx/index.php?title=ATRAC3plus + * + * Kudos to Benjamin Larsson and Michael Karcher + * for their precious technical help! + */ + +#include +#include + +#include "float_dsp.h" +#include "get_bits.h" +#include "compat.h" +#include "atrac.h" +#include "mem.h" +#include "atrac3plus.h" + +struct ATRAC3PContext { + GetBitContext gb; + + DECLARE_ALIGNED(32, float, samples)[2][ATRAC3P_FRAME_SAMPLES]; ///< quantized MDCT spectrum + DECLARE_ALIGNED(32, float, mdct_buf)[2][ATRAC3P_FRAME_SAMPLES]; ///< output of the IMDCT + DECLARE_ALIGNED(32, float, time_buf)[2][ATRAC3P_FRAME_SAMPLES]; ///< output of the gain compensation + DECLARE_ALIGNED(32, float, outp_buf)[2][ATRAC3P_FRAME_SAMPLES]; + + AtracGCContext gainc_ctx; ///< gain compensation context + FFTContext mdct_ctx; + FFTContext ipqf_dct_ctx; ///< IDCT context used by IPQF + + Atrac3pChanUnitCtx *ch_units; ///< global channel units + + int num_channel_blocks; ///< number of channel blocks + uint8_t channel_blocks[5]; ///< channel configuration descriptor + + int block_align; +}; + +void atrac3p_free(ATRAC3PContext *ctx) +{ + av_freep(&ctx->ch_units); + ff_mdct_end(&ctx->mdct_ctx); + ff_mdct_end(&ctx->ipqf_dct_ctx); + av_freep(&ctx); +} + +static int set_channel_params(ATRAC3PContext *ctx, int channels) { + memset(ctx->channel_blocks, 0, sizeof(ctx->channel_blocks)); + switch (channels) { + case 1: + ctx->num_channel_blocks = 1; + ctx->channel_blocks[0] = CH_UNIT_MONO; + break; + case 2: + ctx->num_channel_blocks = 1; + ctx->channel_blocks[0] = CH_UNIT_STEREO; + break; + case 3: + ctx->num_channel_blocks = 2; + ctx->channel_blocks[0] = CH_UNIT_STEREO; + ctx->channel_blocks[1] = CH_UNIT_MONO; + break; + case 4: + ctx->num_channel_blocks = 3; + ctx->channel_blocks[0] = CH_UNIT_STEREO; + ctx->channel_blocks[1] = CH_UNIT_MONO; + ctx->channel_blocks[2] = CH_UNIT_MONO; + break; + case 6: + ctx->num_channel_blocks = 4; + ctx->channel_blocks[0] = CH_UNIT_STEREO; + ctx->channel_blocks[1] = CH_UNIT_MONO; + ctx->channel_blocks[2] = CH_UNIT_STEREO; + ctx->channel_blocks[3] = CH_UNIT_MONO; + break; + case 7: + ctx->num_channel_blocks = 5; + ctx->channel_blocks[0] = CH_UNIT_STEREO; + ctx->channel_blocks[1] = CH_UNIT_MONO; + ctx->channel_blocks[2] = CH_UNIT_STEREO; + ctx->channel_blocks[3] = CH_UNIT_MONO; + ctx->channel_blocks[4] = CH_UNIT_MONO; + break; + case 8: + ctx->num_channel_blocks = 5; + ctx->channel_blocks[0] = CH_UNIT_STEREO; + ctx->channel_blocks[1] = CH_UNIT_MONO; + ctx->channel_blocks[2] = CH_UNIT_STEREO; + ctx->channel_blocks[3] = CH_UNIT_STEREO; + ctx->channel_blocks[4] = CH_UNIT_MONO; + break; + default: + av_log(AV_LOG_ERROR, + "Unsupported channel count: %d!\n", channels); + return AVERROR_INVALIDDATA; + } + return 0; +} + +ATRAC3PContext *atrac3p_alloc(int channels, int *block_align) { + int i, ch, ret; + + ATRAC3PContext *ctx = (ATRAC3PContext *)av_mallocz(sizeof(ATRAC3PContext)); + ctx->block_align = *block_align; + + if (!*block_align) { + // No block align was passed in, using the default. + *block_align = 0x000002e8; + } + + ff_atrac3p_init_vlcs(); + + /* initialize IPQF */ + ff_mdct_init(&ctx->ipqf_dct_ctx, 5, 1, 32.0 / 32768.0); + + ff_atrac3p_init_imdct(&ctx->mdct_ctx); + + ff_atrac_init_gain_compensation(&ctx->gainc_ctx, 6, 2); + + ff_atrac3p_init_wave_synth(); + + if ((ret = set_channel_params(ctx, channels)) < 0) { + atrac3p_free(ctx); + return nullptr; + } + + ctx->ch_units = (Atrac3pChanUnitCtx *)av_mallocz_array(ctx->num_channel_blocks, sizeof(*ctx->ch_units)); + + if (!ctx->ch_units) { + atrac3p_free(ctx); + return nullptr; + } + + for (i = 0; i < ctx->num_channel_blocks; i++) { + for (ch = 0; ch < 2; ch++) { + ctx->ch_units[i].channels[ch].ch_num = ch; + ctx->ch_units[i].channels[ch].wnd_shape = &ctx->ch_units[i].channels[ch].wnd_shape_hist[0][0]; + ctx->ch_units[i].channels[ch].wnd_shape_prev = &ctx->ch_units[i].channels[ch].wnd_shape_hist[1][0]; + ctx->ch_units[i].channels[ch].gain_data = &ctx->ch_units[i].channels[ch].gain_data_hist[0][0]; + ctx->ch_units[i].channels[ch].gain_data_prev = &ctx->ch_units[i].channels[ch].gain_data_hist[1][0]; + ctx->ch_units[i].channels[ch].tones_info = &ctx->ch_units[i].channels[ch].tones_info_hist[0][0]; + ctx->ch_units[i].channels[ch].tones_info_prev = &ctx->ch_units[i].channels[ch].tones_info_hist[1][0]; + } + + ctx->ch_units[i].waves_info = &ctx->ch_units[i].wave_synth_hist[0]; + ctx->ch_units[i].waves_info_prev = &ctx->ch_units[i].wave_synth_hist[1]; + } + + return ctx; +} + +static void decode_residual_spectrum(Atrac3pChanUnitCtx *ctx, + float out[2][ATRAC3P_FRAME_SAMPLES], + int num_channels) +{ + int i, sb, ch, qu, nspeclines, RNG_index; + float *dst, q; + int16_t *src; + /* calculate RNG table index for each subband */ + int sb_RNG_index[ATRAC3P_SUBBANDS] = { 0 }; + + if (ctx->mute_flag) { + for (ch = 0; ch < num_channels; ch++) + memset(out[ch], 0, ATRAC3P_FRAME_SAMPLES * sizeof(*out[ch])); + return; + } + + for (qu = 0, RNG_index = 0; qu < ctx->used_quant_units; qu++) + RNG_index += ctx->channels[0].qu_sf_idx[qu] + + ctx->channels[1].qu_sf_idx[qu]; + + for (sb = 0; sb < ctx->num_coded_subbands; sb++, RNG_index += 128) + sb_RNG_index[sb] = RNG_index & 0x3FC; + + /* inverse quant and power compensation */ + for (ch = 0; ch < num_channels; ch++) { + /* clear channel's residual spectrum */ + memset(out[ch], 0, ATRAC3P_FRAME_SAMPLES * sizeof(*out[ch])); + + for (qu = 0; qu < ctx->used_quant_units; qu++) { + src = &ctx->channels[ch].spectrum[av_atrac3p_qu_to_spec_pos[qu]]; + dst = &out[ch][av_atrac3p_qu_to_spec_pos[qu]]; + nspeclines = av_atrac3p_qu_to_spec_pos[qu + 1] - + av_atrac3p_qu_to_spec_pos[qu]; + + if (ctx->channels[ch].qu_wordlen[qu] > 0) { + q = av_atrac3p_sf_tab[ctx->channels[ch].qu_sf_idx[qu]] * + av_atrac3p_mant_tab[ctx->channels[ch].qu_wordlen[qu]]; + for (i = 0; i < nspeclines; i++) + dst[i] = src[i] * q; + } + } + + for (sb = 0; sb < ctx->num_coded_subbands; sb++) + ff_atrac3p_power_compensation(ctx, ch, &out[ch][0], + sb_RNG_index[sb], sb); + } + + if (ctx->unit_type == CH_UNIT_STEREO) { + for (sb = 0; sb < ctx->num_coded_subbands; sb++) { + if (ctx->swap_channels[sb]) { + for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES; i++) + FFSWAP(float, out[0][sb * ATRAC3P_SUBBAND_SAMPLES + i], + out[1][sb * ATRAC3P_SUBBAND_SAMPLES + i]); + } + + /* flip coefficients' sign if requested */ + if (ctx->negate_coeffs[sb]) + for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES; i++) + out[1][sb * ATRAC3P_SUBBAND_SAMPLES + i] = -(out[1][sb * ATRAC3P_SUBBAND_SAMPLES + i]); + } + } +} + +static void reconstruct_frame(ATRAC3PContext *ctx, Atrac3pChanUnitCtx *ch_unit, + int num_channels) +{ + int ch, sb; + + for (ch = 0; ch < num_channels; ch++) { + for (sb = 0; sb < ch_unit->num_subbands; sb++) { + /* inverse transform and windowing */ + ff_atrac3p_imdct(&ctx->mdct_ctx, + &ctx->samples[ch][sb * ATRAC3P_SUBBAND_SAMPLES], + &ctx->mdct_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES], + (ch_unit->channels[ch].wnd_shape_prev[sb] << 1) + + ch_unit->channels[ch].wnd_shape[sb], sb); + + /* gain compensation and overlapping */ + ff_atrac_gain_compensation(&ctx->gainc_ctx, + &ctx->mdct_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES], + &ch_unit->prev_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES], + &ch_unit->channels[ch].gain_data_prev[sb], + &ch_unit->channels[ch].gain_data[sb], + ATRAC3P_SUBBAND_SAMPLES, + &ctx->time_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES]); + } + + /* zero unused subbands in both output and overlapping buffers */ + memset(&ch_unit->prev_buf[ch][ch_unit->num_subbands * ATRAC3P_SUBBAND_SAMPLES], + 0, + (ATRAC3P_SUBBANDS - ch_unit->num_subbands) * + ATRAC3P_SUBBAND_SAMPLES * + sizeof(ch_unit->prev_buf[ch][ch_unit->num_subbands * ATRAC3P_SUBBAND_SAMPLES])); + memset(&ctx->time_buf[ch][ch_unit->num_subbands * ATRAC3P_SUBBAND_SAMPLES], + 0, + (ATRAC3P_SUBBANDS - ch_unit->num_subbands) * + ATRAC3P_SUBBAND_SAMPLES * + sizeof(ctx->time_buf[ch][ch_unit->num_subbands * ATRAC3P_SUBBAND_SAMPLES])); + + /* resynthesize and add tonal signal */ + if (ch_unit->waves_info->tones_present || + ch_unit->waves_info_prev->tones_present) { + for (sb = 0; sb < ch_unit->num_subbands; sb++) + if (ch_unit->channels[ch].tones_info[sb].num_wavs || + ch_unit->channels[ch].tones_info_prev[sb].num_wavs) { + ff_atrac3p_generate_tones(ch_unit, ch, sb, + &ctx->time_buf[ch][sb * 128]); + } + } + + /* subband synthesis and acoustic signal output */ + ff_atrac3p_ipqf(&ctx->ipqf_dct_ctx, &ch_unit->ipqf_ctx[ch], + &ctx->time_buf[ch][0], &ctx->outp_buf[ch][0]); + } + + /* swap window shape and gain control buffers. */ + for (ch = 0; ch < num_channels; ch++) { + FFSWAP(uint8_t *, ch_unit->channels[ch].wnd_shape, + ch_unit->channels[ch].wnd_shape_prev); + FFSWAP(AtracGainInfo *, ch_unit->channels[ch].gain_data, + ch_unit->channels[ch].gain_data_prev); + FFSWAP(Atrac3pWavesData *, ch_unit->channels[ch].tones_info, + ch_unit->channels[ch].tones_info_prev); + } + + FFSWAP(Atrac3pWaveSynthParams *, ch_unit->waves_info, ch_unit->waves_info_prev); +} + +int atrac3p_decode_frame(ATRAC3PContext *ctx, float *out_data[2], int *nb_samples, const uint8_t *indata, int indata_size) +{ + int i, ret, ch_unit_id, ch_block = 0, out_ch_index = 0, channels_to_process; + float **samples_p = out_data; + + *nb_samples = 0; + + if ((ret = init_get_bits8(&ctx->gb, indata, indata_size)) < 0) + return ret; + + if (get_bits1(&ctx->gb)) { + av_log(AV_LOG_ERROR, "Invalid start bit!"); + return AVERROR_INVALIDDATA; + } + + while (get_bits_left(&ctx->gb) >= 2 && + (ch_unit_id = get_bits(&ctx->gb, 2)) != CH_UNIT_TERMINATOR) { + if (ch_unit_id == CH_UNIT_EXTENSION) { + avpriv_report_missing_feature("Channel unit extension"); + return AVERROR_PATCHWELCOME; + } + if (ch_block >= ctx->num_channel_blocks || + ctx->channel_blocks[ch_block] != ch_unit_id) { + av_log(AV_LOG_ERROR, + "Frame data doesn't match channel configuration!"); + return AVERROR_INVALIDDATA; + } + + ctx->ch_units[ch_block].unit_type = ch_unit_id; + channels_to_process = ch_unit_id + 1; + + if ((ret = ff_atrac3p_decode_channel_unit(&ctx->gb, + &ctx->ch_units[ch_block], + channels_to_process)) < 0) + return ret; + + decode_residual_spectrum(&ctx->ch_units[ch_block], ctx->samples, + channels_to_process); + reconstruct_frame(ctx, &ctx->ch_units[ch_block], + channels_to_process); + + for (i = 0; i < channels_to_process; i++) + memcpy(samples_p[out_ch_index + i], ctx->outp_buf[i], + ATRAC3P_FRAME_SAMPLES * sizeof(**samples_p)); + + ch_block++; + out_ch_index += channels_to_process; + } + + *nb_samples = ATRAC3P_FRAME_SAMPLES; + return FFMIN(ctx->block_align, indata_size); +} + +void atrac3p_flush_buffers(ATRAC3PContext *ctx) { + // TODO: Not sure what should be zeroed here. +} diff --git a/ext/at3_standalone/atrac3plusdsp.cpp b/ext/at3_standalone/atrac3plusdsp.cpp new file mode 100644 index 0000000000..a070148e0e --- /dev/null +++ b/ext/at3_standalone/atrac3plusdsp.cpp @@ -0,0 +1,714 @@ +/* + * ATRAC3+ compatible decoder + * + * Copyright (c) 2010-2013 Maxim Poliakovski + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DSP functions for ATRAC3+ decoder. + */ + +#include "ppsspp_config.h" + +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) + +#include + +#elif PPSSPP_ARCH(ARM_NEON) + +#if defined(_MSC_VER) && PPSSPP_ARCH(ARM64) +#include +#else +#include +#endif + +#endif + +#define _USE_MATH_DEFINES +#include +#include + +#include "float_dsp.h" +#include "fft.h" +#include "atrac3plus.h" + +/** + * Map quant unit number to its position in the spectrum. + * To get the number of spectral lines in each quant unit do the following: + * num_specs = qu_to_spec_pos[i+1] - qu_to_spec_pos[i] + */ +const uint16_t av_atrac3p_qu_to_spec_pos[33] = { + 0, 16, 32, 48, 64, 80, 96, 112, + 128, 160, 192, 224, 256, 288, 320, 352, + 384, 448, 512, 576, 640, 704, 768, 896, + 1024, 1152, 1280, 1408, 1536, 1664, 1792, 1920, + 2048 +}; + +/* Scalefactors table. */ +/* Approx. Equ: pow(2.0, (i - 16.0 + 0.501783948) / 3.0) */ +const float av_atrac3p_sf_tab[64] = { + 0.027852058, 0.0350914, 0.044212341, 0.055704117, 0.0701828, + 0.088424683, 0.11140823, 0.1403656, 0.17684937, 0.22281647, 0.2807312, 0.35369873, + 0.44563293, 0.5614624, 0.70739746, 0.89126587, 1.1229248, 1.4147949, 1.7825317, + 2.2458496, 2.8295898, 3.5650635, 4.4916992, 5.6591797, 7.130127, 8.9833984, + 11.318359, 14.260254, 17.966797, 22.636719, 28.520508, 35.933594, 45.273438, + 57.041016, 71.867188, 90.546875, 114.08203, 143.73438, 181.09375, 228.16406, + 287.46875, 362.1875, 456.32812, 574.9375, 724.375, 912.65625, 1149.875, + 1448.75, 1825.3125, 2299.75, 2897.5, 3650.625, 4599.5, 5795.0, + 7301.25, 9199.0, 11590.0, 14602.5, 18398.0, 23180.0, 29205.0, + 36796.0, 46360.0, 58410.0 +}; + +/* Mantissa table. */ +/* pow(10, x * log10(2) + 0.05) / 2 / ([1,2,3,5,7,15,31] + 0.5) */ +const float av_atrac3p_mant_tab[8] = { + 0.0, + 0.74801636, + 0.44882202, + 0.32058716, + 0.20400238, + 0.1496048, + 0.07239151, + 0.035619736 +}; + +DECLARE_ALIGNED(32, float, av_sine_64)[64]; +DECLARE_ALIGNED(32, float, av_sine_128)[128]; + +// Generate a sine window. +static void ff_sine_window_init(float *window, int n) { + int i; + for (i = 0; i < n; i++) + window[i] = sinf((i + 0.5) * (M_PI / (2.0 * n))); +} + +#define ATRAC3P_MDCT_SIZE (ATRAC3P_SUBBAND_SAMPLES * 2) + +void ff_atrac3p_init_imdct(FFTContext *mdct_ctx) +{ + ff_sine_window_init(av_sine_64, 64); + ff_sine_window_init(av_sine_128, 128); + + /* Initialize the MDCT transform. */ + ff_mdct_init(mdct_ctx, 8, 1, -1.0); +} + +#define TWOPI (2 * M_PI) + +#define DEQUANT_PHASE(ph) (((ph) & 0x1F) << 6) + +static DECLARE_ALIGNED(32, float, sine_table)[2048]; ///< wave table +static DECLARE_ALIGNED(32, float, hann_window)[256]; ///< Hann windowing function +static float amp_sf_tab[64]; ///< scalefactors for quantized amplitudes + +void ff_atrac3p_init_wave_synth(void) +{ + int i; + + /* generate sine wave table */ + for (i = 0; i < 2048; i++) + sine_table[i] = sin(TWOPI * i / 2048); + + /* generate Hann window */ + for (i = 0; i < 256; i++) + hann_window[i] = (1.0f - cos(TWOPI * i / 256.0f)) * 0.5f; + + /* generate amplitude scalefactors table */ + for (i = 0; i < 64; i++) + amp_sf_tab[i] = exp2f((i - 3) / 4.0f); +} + +/** + * Synthesize sine waves according to given parameters. + * + * @param[in] synth_param ptr to common synthesis parameters + * @param[in] waves_info parameters for each sine wave + * @param[in] envelope envelope data for all waves in a group + * @param[in] invert_phase flag indicating 180° phase shift + * @param[in] reg_offset region offset for trimming envelope data + * @param[out] out receives sythesized data + */ +static void waves_synth(Atrac3pWaveSynthParams *synth_param, + Atrac3pWavesData *waves_info, + Atrac3pWaveEnvelope *envelope, + int invert_phase, int reg_offset, float *out) +{ + int i, wn, inc, pos; + double amp; + Atrac3pWaveParam *wave_param = &synth_param->waves[waves_info->start_index]; + + for (wn = 0; wn < waves_info->num_wavs; wn++, wave_param++) { + /* amplitude dequantization */ + amp = amp_sf_tab[wave_param->amp_sf] * + (!synth_param->amplitude_mode + ? (wave_param->amp_index + 1) / 15.13f + : 1.0f); + + inc = wave_param->freq_index; + pos = DEQUANT_PHASE(wave_param->phase_index) - (reg_offset ^ 128) * inc & 2047; + + /* waveform generation */ + for (i = 0; i < 128; i++) { + out[i] += sine_table[pos] * amp; + pos = (pos + inc) & 2047; + } + } + + /* invert phase if requested */ + if (invert_phase) + vector_fmul_scalar(out, -1.0f, 128); + + /* fade in with steep Hann window if requested */ + if (envelope->has_start_point) { + pos = (envelope->start_pos << 2) - reg_offset; + if (pos > 0 && pos <= 128) { + memset(out, 0, pos * sizeof(*out)); + if (!envelope->has_stop_point || + envelope->start_pos != envelope->stop_pos) { + out[pos + 0] *= hann_window[0]; + out[pos + 1] *= hann_window[32]; + out[pos + 2] *= hann_window[64]; + out[pos + 3] *= hann_window[96]; + } + } + } + + /* fade out with steep Hann window if requested */ + if (envelope->has_stop_point) { + pos = ((envelope->stop_pos + 1) << 2) - reg_offset; + if (pos > 0 && pos <= 128) { + out[pos - 4] *= hann_window[96]; + out[pos - 3] *= hann_window[64]; + out[pos - 2] *= hann_window[32]; + out[pos - 1] *= hann_window[0]; + memset(&out[pos], 0, (128 - pos) * sizeof(out[pos])); + } + } +} + +void ff_atrac3p_generate_tones(Atrac3pChanUnitCtx *ch_unit, int ch_num, int sb, float *out) +{ + DECLARE_ALIGNED(32, float, wavreg1)[128] = { 0 }; + DECLARE_ALIGNED(32, float, wavreg2)[128] = { 0 }; + int i, reg1_env_nonzero, reg2_env_nonzero; + Atrac3pWavesData *tones_now = &ch_unit->channels[ch_num].tones_info_prev[sb]; + Atrac3pWavesData *tones_next = &ch_unit->channels[ch_num].tones_info[sb]; + + /* reconstruct full envelopes for both overlapping regions + * from truncated bitstream data */ + if (tones_next->pend_env.has_start_point && + tones_next->pend_env.start_pos < tones_next->pend_env.stop_pos) { + tones_next->curr_env.has_start_point = 1; + tones_next->curr_env.start_pos = tones_next->pend_env.start_pos + 32; + } else if (tones_now->pend_env.has_start_point) { + tones_next->curr_env.has_start_point = 1; + tones_next->curr_env.start_pos = tones_now->pend_env.start_pos; + } else { + tones_next->curr_env.has_start_point = 0; + tones_next->curr_env.start_pos = 0; + } + + if (tones_now->pend_env.has_stop_point && + tones_now->pend_env.stop_pos >= tones_next->curr_env.start_pos) { + tones_next->curr_env.has_stop_point = 1; + tones_next->curr_env.stop_pos = tones_now->pend_env.stop_pos; + } else if (tones_next->pend_env.has_stop_point) { + tones_next->curr_env.has_stop_point = 1; + tones_next->curr_env.stop_pos = tones_next->pend_env.stop_pos + 32; + } else { + tones_next->curr_env.has_stop_point = 0; + tones_next->curr_env.stop_pos = 64; + } + + /* is the visible part of the envelope non-zero? */ + reg1_env_nonzero = (tones_now->curr_env.stop_pos < 32) ? 0 : 1; + reg2_env_nonzero = (tones_next->curr_env.start_pos >= 32) ? 0 : 1; + + /* synthesize waves for both overlapping regions */ + if (tones_now->num_wavs && reg1_env_nonzero) + waves_synth(ch_unit->waves_info_prev, tones_now, &tones_now->curr_env, + ch_unit->waves_info_prev->invert_phase[sb] & ch_num, + 128, wavreg1); + + if (tones_next->num_wavs && reg2_env_nonzero) + waves_synth(ch_unit->waves_info, tones_next, &tones_next->curr_env, + ch_unit->waves_info->invert_phase[sb] & ch_num, 0, wavreg2); + + /* Hann windowing for non-faded wave signals */ + if (tones_now->num_wavs && tones_next->num_wavs && + reg1_env_nonzero && reg2_env_nonzero) { + vector_fmul(wavreg1, &hann_window[128], 128); + vector_fmul(wavreg2, hann_window, 128); + } else { + if (tones_now->num_wavs && !tones_now->curr_env.has_stop_point) + vector_fmul(wavreg1, &hann_window[128], 128); + + if (tones_next->num_wavs && !tones_next->curr_env.has_start_point) + vector_fmul(wavreg2, hann_window, 128); + } + + /* Overlap and add to residual */ + for (i = 0; i < 128; i++) + out[i] += wavreg1[i] + wavreg2[i]; +} + +static const int subband_to_powgrp[ATRAC3P_SUBBANDS] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4 +}; + +/* noise table for power compensation */ +static const float noise_tab[1024] = { + -0.01358032, -0.05593872, 0.01696777, -0.14871216, -0.26412964, -0.09893799, 0.25723267, + 0.02008057, -0.72235107, -0.44351196, -0.22985840, 0.16833496, 0.46902466, 0.05917358, + -0.15179443, 0.41299438, -0.01287842, 0.13360596, 0.43557739, -0.09530640, -0.58422852, + 0.39266968, -0.08343506, -0.25604248, 0.22848511, 0.26013184, -0.65588379, 0.17288208, + -0.08673096, -0.05203247, 0.07299805, -0.28665161, -0.35806274, 0.06552124, -0.09387207, + 0.21099854, -0.28347778, -0.72402954, 0.05050659, -0.10635376, -0.18853760, 0.29724121, + 0.20703125, -0.29791260, -0.37634277, 0.47970581, -0.09976196, 0.32641602, -0.29248047, + -0.28237915, 0.26028442, -0.36157227, 0.22042847, -0.03222656, -0.37268066, -0.03759766, + 0.09909058, 0.23284912, 0.19320679, 0.14453125, -0.02139282, -0.19702148, 0.31533813, + -0.16741943, 0.35031128, -0.35656738, -0.66128540, -0.00701904, 0.20898438, 0.26837158, + -0.33706665, -0.04568481, 0.12600708, 0.10284424, 0.07321167, -0.18280029, 0.38101196, + 0.21301270, 0.04541016, 0.01156616, -0.26391602, -0.02346802, -0.22125244, 0.29760742, + -0.36233521, -0.31314087, -0.13967896, -0.11276245, -0.19433594, 0.34490967, 0.02343750, + 0.21963501, -0.02777100, -0.67678833, -0.08999634, 0.14233398, -0.27697754, 0.51422119, + -0.05047607, 0.48327637, 0.37167358, -0.60806274, 0.18728638, -0.15191650, 0.00637817, + 0.02832031, -0.15618896, 0.60644531, 0.21826172, 0.06384277, -0.31863403, 0.08816528, + 0.15447998, -0.07015991, -0.08154297, -0.40966797, -0.39785767, -0.11709595, 0.22052002, + 0.18466187, -0.17257690, 0.03759766, -0.06195068, 0.00433350, 0.12176514, 0.34011841, + 0.25610352, -0.05294800, 0.41033936, 0.16854858, -0.76187134, 0.13845825, -0.19418335, + -0.21524048, -0.44412231, -0.08160400, -0.28195190, -0.01873779, 0.15524292, -0.37438965, + -0.44860840, 0.43096924, -0.24746704, 0.49856567, 0.14859009, 0.38159180, 0.20541382, + -0.39175415, -0.65850830, -0.43716431, 0.13037109, -0.05111694, 0.39956665, 0.21447754, + -0.04861450, 0.33654785, 0.10589600, -0.88085938, -0.30822754, 0.38577271, 0.30047607, + 0.38836670, 0.09118652, -0.36477661, -0.01641846, -0.23031616, 0.26058960, 0.18859863, + -0.21868896, -0.17861938, -0.29754639, 0.09777832, 0.10806274, -0.51605225, 0.00076294, + 0.13259888, 0.11090088, -0.24084473, 0.24957275, 0.01379395, -0.04141235, -0.04937744, + 0.57394409, 0.27410889, 0.27587891, 0.45013428, -0.32592773, 0.11160278, -0.00970459, + 0.29092407, 0.03356934, -0.70925903, 0.04882812, 0.43499756, 0.07720947, -0.27554321, + -0.01742554, -0.08413696, -0.04028320, -0.52850342, -0.07330322, 0.05181885, 0.21362305, + -0.18765259, 0.07058716, -0.03009033, 0.32662964, 0.27023315, -0.28002930, 0.17568970, + 0.03338623, 0.30242920, -0.03921509, 0.32174683, -0.23733521, 0.08575439, -0.38269043, + 0.09194946, -0.07238770, 0.17941284, -0.51278687, -0.25146484, 0.19790649, -0.19195557, + 0.16549683, 0.42456055, 0.39129639, -0.02868652, 0.17980957, 0.24902344, -0.76583862, + -0.20959473, 0.61013794, 0.37011719, 0.36859131, -0.04486084, 0.10678101, -0.15994263, + -0.05328369, 0.28463745, -0.06420898, -0.36987305, -0.28009033, -0.11764526, 0.04312134, + -0.08038330, 0.04885864, -0.03067017, -0.00042725, 0.34289551, -0.00988770, 0.34838867, + 0.32516479, -0.16271973, 0.38269043, 0.03240967, 0.12417603, -0.14331055, -0.34902954, + -0.18325806, 0.29421997, 0.44284058, 0.75170898, -0.67245483, -0.12176514, 0.27914429, + -0.29806519, 0.19863892, 0.30087280, 0.22680664, -0.36633301, -0.32534790, -0.57553101, + -0.16641235, 0.43811035, 0.08331299, 0.15942383, 0.26516724, -0.24240112, -0.11761475, + -0.16827393, -0.14260864, 0.46343994, 0.11804199, -0.55514526, -0.02520752, -0.14309692, + 0.00448608, 0.02749634, -0.30545044, 0.70965576, 0.45108032, 0.66439819, -0.68255615, + -0.12496948, 0.09146118, -0.21109009, -0.23791504, 0.79943848, -0.35205078, -0.24963379, + 0.18719482, -0.19079590, 0.07458496, 0.07623291, -0.28781128, -0.37121582, -0.19580078, + -0.01773071, -0.16717529, 0.13040161, 0.14672852, 0.42379761, 0.03582764, 0.11431885, + 0.05145264, 0.44702148, 0.08963013, 0.01367188, -0.54519653, -0.12692261, 0.21176147, + 0.04925537, 0.30670166, -0.11029053, 0.19555664, -0.27740479, 0.23043823, 0.15554810, + -0.19299316, -0.25729370, 0.17800903, -0.03579712, -0.05065918, -0.06933594, -0.09500122, + -0.07821655, 0.23889160, -0.31900024, 0.03073120, -0.00415039, 0.61315918, 0.37176514, + -0.13442993, -0.15536499, -0.19216919, -0.37899780, 0.19992065, 0.02630615, -0.12573242, + 0.25927734, -0.02447510, 0.29629517, -0.40731812, -0.17333984, 0.24310303, -0.10607910, + 0.14828491, 0.08792114, -0.18743896, -0.05572510, -0.04833984, 0.10473633, -0.29028320, + -0.67687988, -0.28170776, -0.41687012, 0.05413818, -0.23284912, 0.09555054, -0.08969116, + -0.15112305, 0.12738037, 0.35986328, 0.28948975, 0.30691528, 0.23956299, 0.06973267, + -0.31198120, -0.18450928, 0.22280884, -0.21600342, 0.23522949, -0.61840820, -0.13012695, + 0.26412964, 0.47320557, -0.26440430, 0.38757324, 0.17352295, -0.26104736, -0.25866699, + -0.12274170, -0.29733276, 0.07687378, 0.18588257, -0.08880615, 0.31185913, 0.05313110, + -0.10885620, -0.14901733, -0.22323608, -0.08538818, 0.19812012, 0.19732666, -0.18927002, + 0.29058838, 0.25555420, -0.48599243, 0.18768311, 0.01345825, 0.34887695, 0.21530151, + 0.19857788, 0.18661499, -0.01394653, -0.09063721, -0.38781738, 0.27160645, -0.20379639, + -0.32119751, -0.23889160, 0.27096558, 0.24951172, 0.07922363, 0.07479858, -0.50946045, + 0.10220337, 0.58364868, -0.19503784, -0.18560791, -0.01165771, 0.47195435, 0.22430420, + -0.38635254, -0.03732300, -0.09179688, 0.06991577, 0.15106201, 0.20605469, -0.05969238, + -0.41821289, 0.12231445, -0.04672241, -0.05117798, -0.11523438, -0.51849365, -0.04077148, + 0.44284058, -0.64086914, 0.17019653, 0.02236938, 0.22848511, -0.23214722, -0.32354736, + -0.14068604, -0.29690552, -0.19891357, 0.02774048, -0.20965576, -0.52191162, -0.19299316, + -0.07290649, 0.49053955, -0.22302246, 0.05642700, 0.13122559, -0.20819092, -0.83590698, + -0.08181763, 0.26797485, -0.00091553, -0.09457397, 0.17089844, -0.27020264, 0.30270386, + 0.05496216, 0.09564209, -0.08590698, 0.02130127, 0.35931396, 0.21728516, -0.15396118, + -0.05053711, 0.02719116, 0.16302490, 0.43212891, 0.10229492, -0.40820312, 0.21646118, + 0.08435059, -0.11145020, -0.39962769, -0.05618286, -0.10223389, -0.60839844, 0.33724976, + -0.06341553, -0.47369385, -0.32852173, 0.05242920, 0.19635010, -0.19137573, -0.67901611, + 0.16180420, 0.05133057, -0.22283936, 0.09646606, 0.24288940, -0.45007324, 0.08804321, + 0.14053345, 0.22619629, -0.01000977, 0.36355591, -0.19863892, -0.30364990, -0.24118042, + -0.57461548, 0.26498413, 0.04345703, -0.09796143, -0.47714233, -0.23739624, 0.18737793, + 0.08926392, -0.02795410, 0.00305176, -0.08700562, -0.38711548, 0.03222656, 0.10940552, + -0.41906738, -0.01620483, -0.47061157, 0.37985229, -0.21624756, 0.47976685, -0.20046997, + -0.62533569, -0.26907349, -0.02877808, 0.00671387, -0.29071045, -0.24685669, -0.15722656, + -0.26055908, 0.29968262, 0.28225708, -0.08990479, -0.16748047, -0.46759033, -0.25067139, + -0.25183105, -0.45932007, 0.05828857, 0.29006958, 0.23840332, -0.17974854, 0.26931763, + 0.10696411, -0.06848145, -0.17126465, -0.10522461, -0.55386353, -0.42306519, -0.07608032, + 0.24380493, 0.38586426, 0.16882324, 0.26751709, 0.17303467, 0.35809326, -0.22094727, + -0.30703735, -0.28497314, -0.04321289, 0.15219116, -0.17071533, -0.39334106, 0.03439331, + -0.10809326, -0.30590820, 0.26449585, -0.07412720, 0.13638306, -0.01062012, 0.27996826, + 0.04397583, -0.05557251, -0.56933594, 0.03363037, -0.00949097, 0.52642822, -0.44329834, + 0.28308105, -0.05499268, -0.23312378, -0.29870605, -0.05123901, 0.26831055, -0.35238647, + -0.30993652, 0.34646606, -0.19775391, 0.44595337, 0.13769531, 0.45358276, 0.19961548, + 0.42681885, 0.15722656, 0.00128174, 0.23757935, 0.40988159, 0.25164795, -0.00732422, + -0.12405396, -0.43420410, -0.00402832, 0.34243774, 0.36264038, 0.18807983, -0.09301758, + -0.10296631, 0.05532837, -0.31652832, 0.14337158, 0.35040283, 0.32540894, 0.05728149, + -0.12030029, -0.25942993, -0.20312500, -0.16491699, -0.46051025, -0.08004761, 0.50772095, + 0.16168213, 0.28439331, 0.08105469, -0.19104004, 0.38589478, -0.16400146, -0.25454712, + 0.20281982, -0.20730591, -0.06311035, 0.32937622, 0.15032959, -0.05340576, 0.30487061, + -0.11648560, 0.38009644, -0.20062256, 0.43466187, 0.01150513, 0.35754395, -0.13146973, + 0.67489624, 0.05212402, 0.27914429, -0.39431763, 0.75308228, -0.13366699, 0.24453735, + 0.42248535, -0.65905762, -0.00546265, -0.03491211, -0.13659668, -0.08294678, -0.45666504, + 0.27188110, 0.12731934, 0.61148071, 0.10449219, -0.28836060, 0.00091553, 0.24618530, + 0.13119507, 0.05685425, 0.17355347, 0.42034912, 0.08514404, 0.24536133, 0.18951416, + -0.19107056, -0.15036011, 0.02334595, 0.54986572, 0.32321167, -0.16104126, -0.03054810, + 0.43594360, 0.17309570, 0.61053467, 0.24731445, 0.33334351, 0.15240479, 0.15588379, + 0.36425781, -0.30407715, -0.13302612, 0.00427246, 0.04171753, -0.33178711, 0.34216309, + -0.12463379, -0.02764893, 0.05905151, -0.31436157, 0.16531372, 0.34542847, -0.03292847, + 0.12527466, -0.12313843, -0.13171387, 0.04757690, -0.45095825, -0.19085693, 0.35342407, + -0.23239136, -0.34387207, 0.11264038, -0.15740967, 0.05273438, 0.74942017, 0.21505737, + 0.08514404, -0.42391968, -0.19531250, 0.35293579, 0.25305176, 0.15731812, -0.70324707, + -0.21591187, 0.35604858, 0.14132690, 0.11724854, 0.15853882, -0.24597168, 0.07019043, + 0.02127075, 0.12658691, 0.06390381, -0.12292480, 0.15441895, -0.47640991, 0.06195068, + 0.58981323, -0.15151978, -0.03604126, -0.45059204, -0.01672363, -0.46997070, 0.25750732, + 0.18084717, 0.06661987, 0.13253784, 0.67828369, 0.11370850, 0.11325073, -0.04611206, + -0.07791138, -0.36544800, -0.06747437, -0.31594849, 0.16131592, 0.41983032, 0.11071777, + -0.36889648, 0.30963135, -0.37875366, 0.58508301, 0.00393677, 0.12338257, 0.03424072, + -0.21728516, -0.12838745, -0.46981812, 0.05868530, -0.25015259, 0.27407837, 0.65240479, + -0.34429932, -0.15179443, 0.14056396, 0.33505249, 0.28826904, 0.09921265, 0.34390259, + 0.13656616, -0.23608398, 0.00863647, 0.02627563, -0.19119263, 0.19775391, -0.07214355, + 0.07809448, 0.03454590, -0.03417969, 0.00033569, -0.23095703, 0.18673706, 0.05798340, + 0.03814697, -0.04318237, 0.05487061, 0.08633423, 0.55950928, -0.06347656, 0.10333252, + 0.25305176, 0.05853271, 0.12246704, -0.25543213, -0.34262085, -0.36437988, -0.21304321, + -0.05093384, 0.02777100, 0.07620239, -0.21215820, -0.09326172, 0.19021606, -0.40579224, + -0.01193237, 0.19845581, -0.35336304, -0.07397461, 0.20104980, 0.08615112, -0.44375610, + 0.11419678, 0.24453735, -0.16555786, -0.05081177, -0.01406860, 0.27893066, -0.18692017, + 0.07473755, 0.03451538, -0.39733887, 0.21548462, -0.22534180, -0.39651489, -0.04989624, + -0.57662964, 0.06390381, 0.62020874, -0.13470459, 0.04345703, -0.21862793, -0.02789307, + 0.51696777, -0.27587891, 0.39004517, 0.09857178, -0.00738525, 0.31317139, 0.00048828, + -0.46572876, 0.29531860, -0.10009766, -0.27856445, 0.03594971, 0.25048828, -0.74584961, + -0.25350952, -0.03302002, 0.31188965, 0.01571655, 0.46710205, 0.21591187, 0.07260132, + -0.42132568, -0.53900146, -0.13674927, -0.16571045, -0.34454346, 0.12359619, -0.11184692, + 0.00967407, 0.34576416, -0.05761719, 0.34848022, 0.17645264, -0.39395142, 0.10339355, + 0.18215942, 0.20697021, 0.59109497, -0.11560059, -0.07385254, 0.10397339, 0.35437012, + -0.22863770, 0.01794434, 0.17559814, -0.17495728, 0.12142944, 0.10928345, -1.00000000, + -0.01379395, 0.21237183, -0.27035522, 0.27319336, -0.37066650, 0.41354370, -0.40054321, + 0.00689697, 0.26321411, 0.39266968, 0.65298462, 0.41625977, -0.13909912, 0.78375244, + -0.30941772, 0.20169067, -0.39367676, 0.94021606, -0.24066162, 0.05557251, -0.24533081, + -0.05444336, -0.76754761, -0.19375610, -0.11041260, -0.17532349, 0.16006470, 0.02188110, + 0.17465210, -0.04342651, -0.56777954, -0.40988159, 0.26687622, 0.11700439, -0.00344849, + -0.05395508, 0.37426758, -0.40719604, -0.15032959, -0.01660156, 0.04196167, -0.04559326, + -0.12969971, 0.12011719, 0.08419800, -0.11199951, 0.35174561, 0.10275269, -0.25686646, + 0.48446655, 0.03225708, 0.28408813, -0.18701172, 0.36282349, -0.03280640, 0.32302856, + 0.17233276, 0.48269653, 0.31112671, -0.04946899, 0.12774658, 0.52685547, 0.10211182, + 0.05953979, 0.05999756, 0.20144653, 0.00744629, 0.27316284, 0.24377441, 0.39672852, + 0.01702881, -0.35513306, 0.11364746, -0.13555908, 0.48880005, -0.15417480, -0.09149170, + -0.02615356, 0.46246338, -0.72250366, 0.22332764, 0.23849487, -0.25686646, -0.08514404, + -0.02062988, -0.34494019, -0.02297974, -0.80386353, -0.08074951, -0.12689209, -0.06896973, + 0.24099731, -0.35650635, -0.09558105, 0.29254150, 0.23132324, -0.16726685, 0.00000000, + -0.24237061, 0.30899048, 0.29504395, -0.20898438, 0.17059326, -0.07672119, -0.14395142, + 0.05572510, 0.20602417, -0.51550293, -0.03167725, -0.48840332, -0.20425415, 0.14144897, + 0.07275391, -0.76669312, -0.22488403, 0.20651245, 0.03259277, 0.00085449, 0.03039551, + 0.47555542, 0.38351440 +}; + +/** Noise level table for power compensation. + * Equ: pow(2.0f, (double)(6 - i) / 3.0f) where i = 0...15 */ +static const float pwc_levs[16] = { + 3.96875, 3.15625, 2.5, 2.0, 1.59375, 1.25, 1.0, 0.78125, + 0.625, 0.5, 0.40625, 0.3125, 0.25, 0.1875, 0.15625, 0.0 +}; + +/** Map subband number to quant unit number. */ +static const int subband_to_qu[17] = { + 0, 8, 12, 16, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +}; + +void ff_atrac3p_power_compensation(Atrac3pChanUnitCtx *ctx, int ch_index, + float *sp, int rng_index, int sb) +{ + AtracGainInfo *g1, *g2; + float pwcsp[ATRAC3P_SUBBAND_SAMPLES], *dst, grp_lev, qu_lev; + int i, gain_lev, gcv = 0, qu, nsp; + int swap_ch = (ctx->unit_type == CH_UNIT_STEREO && ctx->swap_channels[sb]) ? 1 : 0; + + if (ctx->channels[ch_index ^ swap_ch].power_levs[subband_to_powgrp[sb]] == ATRAC3P_POWER_COMP_OFF) + return; + + /* generate initial noise spectrum */ + for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES; i++, rng_index++) + pwcsp[i] = noise_tab[rng_index & 0x3FF]; + + /* check gain control information */ + g1 = &ctx->channels[ch_index ^ swap_ch].gain_data[sb]; + g2 = &ctx->channels[ch_index ^ swap_ch].gain_data_prev[sb]; + + gain_lev = (g1->num_points > 0) ? (6 - g1->lev_code[0]) : 0; + + for (i = 0; i < g2->num_points; i++) + gcv = FFMAX(gcv, gain_lev - (g2->lev_code[i] - 6)); + + for (i = 0; i < g1->num_points; i++) + gcv = FFMAX(gcv, 6 - g1->lev_code[i]); + + grp_lev = pwc_levs[ctx->channels[ch_index ^ swap_ch].power_levs[subband_to_powgrp[sb]]] / (1 << gcv); + + /* skip the lowest two quant units (frequencies 0...351 Hz) for subband 0 */ + for (qu = subband_to_qu[sb] + (!sb ? 2 : 0); qu < subband_to_qu[sb + 1]; qu++) { + if (ctx->channels[ch_index].qu_wordlen[qu] <= 0) + continue; + + qu_lev = av_atrac3p_sf_tab[ctx->channels[ch_index].qu_sf_idx[qu]] * + av_atrac3p_mant_tab[ctx->channels[ch_index].qu_wordlen[qu]] / + (1 << ctx->channels[ch_index].qu_wordlen[qu]) * grp_lev; + + dst = &sp[av_atrac3p_qu_to_spec_pos[qu]]; + nsp = av_atrac3p_qu_to_spec_pos[qu + 1] - av_atrac3p_qu_to_spec_pos[qu]; + + for (i = 0; i < nsp; i++) + dst[i] += pwcsp[i] * qu_lev; + } +} + +void ff_atrac3p_imdct(FFTContext *mdct_ctx, float *pIn, + float *pOut, int wind_id, int sb) +{ + int i; + + if (sb & 1) + for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES / 2; i++) + FFSWAP(float, pIn[i], pIn[ATRAC3P_SUBBAND_SAMPLES - 1 - i]); + + imdct_calc(mdct_ctx, pOut, pIn); + + /* Perform windowing on the output. + * ATRAC3+ uses two different MDCT windows: + * - The first one is just the plain sine window of size 256 + * - The 2nd one is the plain sine window of size 128 + * wrapped into zero (at the start) and one (at the end) regions. + * Both regions are 32 samples long. */ + if (wind_id & 2) { /* 1st half: steep window */ + memset(pOut, 0, sizeof(float) * 32); + vector_fmul(&pOut[32], av_sine_64, 64); + } else /* 1st half: simple sine window */ + vector_fmul(pOut, av_sine_128, ATRAC3P_MDCT_SIZE / 2); + + if (wind_id & 1) { /* 2nd half: steep window */ + vector_fmul_reverse(&pOut[160], av_sine_64, 64); + memset(&pOut[224], 0, sizeof(float) * 32); + } else /* 2nd half: simple sine window */ + vector_fmul_reverse(&pOut[128], av_sine_128, ATRAC3P_MDCT_SIZE / 2); +} + +/* lookup table for fast modulo 23 op required for cyclic buffers of the IPQF */ +static const int mod23_lut[26] = { + 23, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0 +}; + +/* First half of the 384-tap IPQF filtering coefficients. */ +static const float ipqf_coeffs1[ATRAC3P_PQF_FIR_LEN][16] = { + { -5.8336207e-7, -8.0604229e-7, -4.2005411e-7, -4.4400572e-8, + 3.226247e-8, 3.530856e-8, 1.2660377e-8, 0.000010516783, + -0.000011838618, 6.005389e-7, 0.0000014333754, 0.0000023108685, + 0.0000032569742, 0.0000046192422, 0.0000063894258, 0.0000070302972 }, + { -0.0000091622824, -0.000010502935, -0.0000079212787, -0.0000041712024, + -0.0000026336629, -0.0000015432918, -5.7168614e-7, 0.0000018111954, + 0.000023530851, 0.00002780562, 0.000032302323, 0.000036968919, + 0.000041575615, 0.000045337845, 0.000046043948, 0.000048585582 }, + { -0.000064464548, -0.000068306952, -0.000073081472, -0.00007612785, + -0.000074850752, -0.000070208509, -0.000062285151, -0.000058270442, + -0.000056296329, -0.000049888811, -0.000035615325, -0.000018532943, + 0.0000016657353, 0.00002610587, 0.000053397067, 0.00008079566 }, + { -0.00054488552, -0.00052537228, -0.00049731287, -0.00045778, + -0.00040612387, -0.00034301577, -0.00026866337, -0.00018248901, + -0.000084307925, 0.000025081157, 0.00014135583, 0.00026649953, + 0.00039945057, 0.00053928449, 0.00068422867, 0.00083093712 }, + { -0.0014771431, -0.001283227, -0.0010566821, -0.00079780724, + -0.00050782406, -0.00018855913, 0.00015771533, 0.00052769453, + 0.00091862219, 0.001326357, 0.0017469483, 0.0021754825, + 0.0026067684, 0.0030352892, 0.0034549395, 0.0038591374 }, + { -0.0022995141, -0.001443546, -0.00049266568, 0.00055068987, + 0.001682895, 0.0028992873, 0.0041943151, 0.0055614738, + 0.0069935122, 0.0084823566, 0.010018963, 0.011593862, + 0.013196872, 0.014817309, 0.016444042, 0.018065533 }, + { -0.034426283, -0.034281436, -0.033992987, -0.033563249, + -0.032995768, -0.032295227, -0.031467363, -0.030518902, + -0.02945766, -0.028291954, -0.027031265, -0.025685543, + -0.024265358, -0.022781773, -0.021246184, -0.019670162 }, + { -0.0030586775, -0.0037203205, -0.0042847847, -0.0047529764, + -0.0051268316, -0.0054091476, -0.0056034233, -0.005714261, + -0.0057445862, -0.0057025906, -0.0055920109, -0.0054194843, + -0.0051914565, -0.0049146507, -0.0045959447, -0.0042418269 }, + { -0.0016376863, -0.0017651899, -0.0018608454, -0.0019252141, + -0.0019593791, -0.0019653172, -0.0019450618, -0.0018990048, + -0.00183808, -0.0017501717, -0.0016481078, -0.0015320742, + -0.0014046903, -0.0012685474, -0.001125814, -0.00097943726 }, + { -0.00055432378, -0.00055472925, -0.00054783461, -0.00053276919, + -0.00051135791, -0.00048466062, -0.00045358928, -0.00042499689, + -0.00036942671, -0.0003392619, -0.00030001783, -0.00025986304, + -0.0002197204, -0.00018116167, -0.00014691355, -0.00011279432 }, + { -0.000064147389, -0.00006174868, -0.000054267788, -0.000047133824, + -0.000042927582, -0.000039477309, -0.000036340745, -0.000029687517, + -0.000049787737, -0.000041577889, -0.000033864744, -0.000026534748, + -0.000019841305, -0.000014789486, -0.000013131184, -0.0000099198869 }, + { -0.0000062990207, -0.0000072701259, -0.000011984052, -0.000017348082, + -0.000019907106, -0.000021348773, -0.000021961965, -0.000012203576, + -0.000010840992, 4.6299544e-7, 5.2588763e-7, 2.7792686e-7, + -2.3649704e-7, -0.0000010897784, -9.171448e-7, -5.22682e-7 } +}; + +/* Second half of the 384-tap IPQF filtering coefficients. */ +static const float ipqf_coeffs2[ATRAC3P_PQF_FIR_LEN][16] = { + { 5.22682e-7, 9.171448e-7, 0.0000010897784, 2.3649704e-7, + -2.7792686e-7, -5.2588763e-7, -4.6299544e-7, 0.000010840992, + -0.000012203576, -0.000021961965, -0.000021348773, -0.000019907106, + -0.000017348082, -0.000011984052, -0.0000072701259, -0.0000062990207 }, + { 0.0000099198869, 0.000013131184, 0.000014789486, 0.000019841305, + 0.000026534748, 0.000033864744, 0.000041577889, 0.000049787737, + -0.000029687517, -0.000036340745, -0.000039477309, -0.000042927582, + -0.000047133824, -0.000054267788, -0.00006174868, -0.000064147389 }, + { 0.00011279432, 0.00014691355, 0.00018116167, 0.0002197204, + 0.00025986304, 0.00030001783, 0.0003392619, 0.00036942671, + -0.00042499689, -0.00045358928, -0.00048466062, -0.00051135791, + -0.00053276919, -0.00054783461, -0.00055472925, -0.00055432378 }, + { 0.00097943726, 0.001125814, 0.0012685474, 0.0014046903, + 0.0015320742, 0.0016481078, 0.0017501717, 0.00183808, + -0.0018990048, -0.0019450618, -0.0019653172, -0.0019593791, + -0.0019252141, -0.0018608454, -0.0017651899, -0.0016376863 }, + { 0.0042418269, 0.0045959447, 0.0049146507, 0.0051914565, + 0.0054194843, 0.0055920109, 0.0057025906, 0.0057445862, + -0.005714261, -0.0056034233, -0.0054091476, -0.0051268316, + -0.0047529764, -0.0042847847, -0.0037203205, -0.0030586775 }, + { 0.019670162, 0.021246184, 0.022781773, 0.024265358, + 0.025685543, 0.027031265, 0.028291954, 0.02945766, + -0.030518902, -0.031467363, -0.032295227, -0.032995768, + -0.033563249, -0.033992987, -0.034281436, -0.034426283 }, + { -0.018065533, -0.016444042, -0.014817309, -0.013196872, + -0.011593862, -0.010018963, -0.0084823566, -0.0069935122, + 0.0055614738, 0.0041943151, 0.0028992873, 0.001682895, + 0.00055068987, -0.00049266568, -0.001443546, -0.0022995141 }, + { -0.0038591374, -0.0034549395, -0.0030352892, -0.0026067684, + -0.0021754825, -0.0017469483, -0.001326357, -0.00091862219, + 0.00052769453, 0.00015771533, -0.00018855913, -0.00050782406, + -0.00079780724, -0.0010566821, -0.001283227, -0.0014771431 }, + { -0.00083093712, -0.00068422867, -0.00053928449, -0.00039945057, + -0.00026649953, -0.00014135583, -0.000025081157, 0.000084307925, + -0.00018248901, -0.00026866337, -0.00034301577, -0.00040612387, + -0.00045778, -0.00049731287, -0.00052537228, -0.00054488552 }, + { -0.00008079566, -0.000053397067, -0.00002610587, -0.0000016657353, + 0.000018532943, 0.000035615325, 0.000049888811, 0.000056296329, + -0.000058270442, -0.000062285151, -0.000070208509, -0.000074850752, + -0.00007612785, -0.000073081472, -0.000068306952, -0.000064464548 }, + { -0.000048585582, -0.000046043948, -0.000045337845, -0.000041575615, + -0.000036968919, -0.000032302323, -0.00002780562, -0.000023530851, + 0.0000018111954, -5.7168614e-7, -0.0000015432918, -0.0000026336629, + -0.0000041712024, -0.0000079212787, -0.000010502935, -0.0000091622824 }, + { -0.0000070302972, -0.0000063894258, -0.0000046192422, -0.0000032569742, + -0.0000023108685, -0.0000014333754, -6.005389e-7, 0.000011838618, + 0.000010516783, 1.2660377e-8, 3.530856e-8, 3.226247e-8, + -4.4400572e-8, -4.2005411e-7, -8.0604229e-7, -5.8336207e-7 } +}; + +void ff_atrac3p_ipqf(FFTContext *dct_ctx, Atrac3pIPQFChannelCtx *hist, + const float *in, float *out) +{ + int i, s, sb, t, pos_now, pos_next; + float idct_in [ATRAC3P_SUBBANDS]; + float idct_out[ATRAC3P_SUBBANDS]; + + memset(out, 0, ATRAC3P_FRAME_SAMPLES * sizeof(*out)); + + for (s = 0; s < ATRAC3P_SUBBAND_SAMPLES; s++) { + /* pick up one sample from each subband */ + for (sb = 0; sb < ATRAC3P_SUBBANDS; sb++) + idct_in[sb] = in[sb * ATRAC3P_SUBBAND_SAMPLES + s]; + + /* Calculate the sine and cosine part of the PQF using IDCT-IV */ + imdct_half(dct_ctx, idct_out, idct_in); + + /* append the result to the history */ + const int hist_pos = hist->pos; + for (i = 0; i < 8; i++) { + hist->buf1[hist_pos][i] = idct_out[i + 8]; + } + for (i = 0; i < 8; i++) { + hist->buf2[hist_pos][i] = idct_out[7 - i]; + } + + pos_now = hist->pos; + pos_next = mod23_lut[pos_now + 2]; // pos_next = (pos_now + 1) % 23; + + for (t = 0; t < ATRAC3P_PQF_FIR_LEN; t++) { + const float *buf1 = hist->buf1[pos_now]; + const float *buf2 = hist->buf2[pos_next]; + const float *coeffs1 = ipqf_coeffs1[t]; + const float *coeffs2 = ipqf_coeffs2[t]; + + float *outp = out + s * 16; +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) + auto _mm_reverse = [](__m128 x) -> __m128 { + return _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)); + }; + _mm_storeu_ps(outp, _mm_add_ps(_mm_loadu_ps(outp), _mm_add_ps( + _mm_mul_ps(_mm_loadu_ps(buf1), _mm_loadu_ps(coeffs1)), + _mm_mul_ps(_mm_loadu_ps(buf2), _mm_loadu_ps(coeffs2))))); + _mm_storeu_ps(outp + 4, _mm_add_ps(_mm_loadu_ps(outp + 4), _mm_add_ps( + _mm_mul_ps(_mm_loadu_ps(buf1 + 4), _mm_loadu_ps(coeffs1 + 4)), + _mm_mul_ps(_mm_loadu_ps(buf2 + 4), _mm_loadu_ps(coeffs2 + 4))))); + + _mm_storeu_ps(outp + 8, _mm_add_ps(_mm_loadu_ps(outp + 8), _mm_add_ps( + _mm_mul_ps(_mm_reverse(_mm_loadu_ps(buf1 + 4)), _mm_loadu_ps(coeffs1 + 8)), + _mm_mul_ps(_mm_reverse(_mm_loadu_ps(buf2 + 4)), _mm_loadu_ps(coeffs2 + 8))))); + _mm_storeu_ps(outp + 12, _mm_add_ps(_mm_loadu_ps(outp + 12), _mm_add_ps( + _mm_mul_ps(_mm_reverse(_mm_loadu_ps(buf1)), _mm_loadu_ps(coeffs1 + 12)), + _mm_mul_ps(_mm_reverse(_mm_loadu_ps(buf2)), _mm_loadu_ps(coeffs2 + 12))))); +#elif PPSSPP_ARCH(ARM_NEON) + auto vreverseq_f32 = [](float32x4_t x) -> float32x4_t { + float32x4_t rev = vrev64q_f32(x); + float32x2_t high = vget_high_f32(rev); //{4,3} + float32x2_t low = vget_low_f32(rev); //{1,2} + return vcombine_f32(high, low); //{4,3,2,1} + }; + vst1q_f32(outp, vaddq_f32(vld1q_f32(outp), vaddq_f32( + vmulq_f32(vld1q_f32(buf1), vld1q_f32(coeffs1)), + vmulq_f32(vld1q_f32(buf2), vld1q_f32(coeffs2))))); + vst1q_f32(outp + 4, vaddq_f32(vld1q_f32(outp + 4), vaddq_f32( + vmulq_f32(vld1q_f32(buf1 + 4), vld1q_f32(coeffs1 + 4)), + vmulq_f32(vld1q_f32(buf2 + 4), vld1q_f32(coeffs2 + 4))))); + + vst1q_f32(outp + 8, vaddq_f32(vld1q_f32(outp + 8), vaddq_f32( + vmulq_f32(vreverseq_f32(vld1q_f32(buf1 + 4)), vld1q_f32(coeffs1 + 8)), + vmulq_f32(vreverseq_f32(vld1q_f32(buf2 + 4)), vld1q_f32(coeffs2 + 8))))); + vst1q_f32(outp + 12, vaddq_f32(vld1q_f32(outp + 12), vaddq_f32( + vmulq_f32(vreverseq_f32(vld1q_f32(buf1)), vld1q_f32(coeffs1 + 12)), + vmulq_f32(vreverseq_f32(vld1q_f32(buf2)), vld1q_f32(coeffs2 + 12))))); +#else + for (i = 0; i < 8; i++) { + outp[i] += buf1[i] * coeffs1[i] + buf2[i] * coeffs2[i]; + } + for (i = 0; i < 8; i++) { + outp[i + 8] += buf1[7 - i] * coeffs1[i + 8] + buf2[7 - i] * coeffs2[i + 8]; + } +#endif + + pos_now = mod23_lut[pos_next + 2]; // pos_now = (pos_now + 2) % 23; + pos_next = mod23_lut[pos_now + 2]; // pos_next = (pos_next + 2) % 23; + } + + hist->pos = mod23_lut[hist->pos]; // hist->pos = (hist->pos - 1) % 23; + } +} diff --git a/ext/at3_standalone/compat.cpp b/ext/at3_standalone/compat.cpp new file mode 100644 index 0000000000..33dbe59a5d --- /dev/null +++ b/ext/at3_standalone/compat.cpp @@ -0,0 +1,25 @@ +#include +#include + +#include "compat.h" +#include "Common/Log.h" + +void av_log(int level, const char *fmt, ...) { + char buffer[512]; + va_list vl; + va_start(vl, fmt); + size_t retval = vsnprintf(buffer, sizeof(buffer), fmt, vl); + va_end(vl); + + // lazy + switch (level) { + case AV_LOG_DEBUG: + case AV_LOG_TRACE: + case AV_LOG_VERBOSE: DEBUG_LOG(Log::ME, "Atrac3/3+: %s", buffer); break; + case AV_LOG_ERROR: ERROR_LOG(Log::ME, "Atrac3/3+: %s", buffer); break; + case AV_LOG_INFO: INFO_LOG(Log::ME, "Atrac3/3+: %s", buffer); break; + case AV_LOG_WARNING: + default: + WARN_LOG(Log::ME, "Atrac3/3+: %s", buffer); break; + } +} diff --git a/ext/at3_standalone/compat.h b/ext/at3_standalone/compat.h new file mode 100644 index 0000000000..f282f0c9c5 --- /dev/null +++ b/ext/at3_standalone/compat.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +// Compat hacks to make an FFMPEG-like environment, so we can keep the core code mostly unchanged. + +#if defined(__clang__) +#define DECLARE_ALIGNED(n, t, v) t __attribute__((aligned(n))) v +#define DECLARE_ASM_CONST(n, t, v) static const t av_used __attribute__((aligned(n))) v +#define av_restrict __restrict +#elif defined(__GNUC__) +#define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v +#define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v +#define av_restrict __restrict__ +#elif defined(_MSC_VER) +#define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v +#define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v +#define av_restrict __restrict +#else +#define DECLARE_ALIGNED(n,t,v) t v +#define DECLARE_ASM_CONST(n,t,v) static const t v +#define av_restrict +#endif + +#define AV_HAVE_FAST_UNALIGNED 0 +#define AV_INPUT_BUFFER_PADDING_SIZE 32 + +// TODO: This should work but doesn't?? +// #define BITSTREAM_READER_LE + +#define LOCAL_ALIGNED(bits, type, name, subscript) type name subscript +#define av_alias +#define av_unused +#define av_assert0(cond) +#define av_assert1(cond) +#define av_assert2(cond) +#define av_printf_format(a,b) +#define avpriv_report_missing_feature(...) + +#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. +#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. + +#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) + +#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input +#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome + +#define AV_LOG_ERROR 16 +#define AV_LOG_WARNING 24 +#define AV_LOG_INFO 32 +#define AV_LOG_VERBOSE 40 +#define AV_LOG_DEBUG 48 +#define AV_LOG_TRACE 56 + +void av_log(int level, const char *fmt, ...) av_printf_format(3, 4); + + /** + * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they + * are not representable as absolute values of their type. This is the same + * as with *abs() + * @see FFNABS() + */ +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) + +#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) + +#ifdef _MSC_VER +#pragma warning(disable:4305) +#pragma warning(disable:4244) +#pragma warning(disable:4101) // unused variable +#endif + +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) +#define av_be2ne32(x) AV_BSWAP32C((x)) diff --git a/ext/at3_standalone/fft.cpp b/ext/at3_standalone/fft.cpp new file mode 100644 index 0000000000..2e3d040ace --- /dev/null +++ b/ext/at3_standalone/fft.cpp @@ -0,0 +1,403 @@ +/* + * FFT/IFFT transforms + * Copyright (c) 2008 Loren Merritt + * Copyright (c) 2002 Fabrice Bellard + * Partly based on libdjbfft by D. J. Bernstein + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * FFT/IFFT transforms. + */ + +#include +#include + +#define _USE_MATH_DEFINES +#include + +#include "mem.h" +#include "fft.h" + +#define sqrthalf (float)M_SQRT1_2 + +void imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); + +/* cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse */ +COSTABLE(16); +COSTABLE(32); +COSTABLE(64); +COSTABLE(128); +COSTABLE(256); +COSTABLE(512); +COSTABLE(1024); + +static FFTSample * const av_cos_tabs[] = { + NULL, NULL, NULL, NULL, + av_cos_16, + av_cos_32, + av_cos_64, + av_cos_128, + av_cos_256, + av_cos_512, + av_cos_1024, +}; + +void fft_calc(FFTContext *s, FFTComplex *z); + +static int split_radix_permutation(int i, int n, int inverse) +{ + int m; + if(n <= 2) return i&1; + m = n >> 1; + if(!(i&m)) return split_radix_permutation(i, m, inverse)*2; + m >>= 1; + if(inverse == !(i&m)) return split_radix_permutation(i, m, inverse)*4 + 1; + else return split_radix_permutation(i, m, inverse)*4 - 1; +} + +void ff_init_ff_cos_tabs(int index) +{ + int i; + int m = 1<= 16; + else if (i < n/2) + return is_second_half_of_fft32(i, n/2); + else if (i < 3*n/4) + return is_second_half_of_fft32(i - n/2, n/4); + else + return is_second_half_of_fft32(i - 3*n/4, n/4); +} + +int ff_fft_init(FFTContext *s, int nbits, int inverse) +{ + int i, j, n; + + if (nbits < 2 || nbits > 16) + goto fail; + s->nbits = nbits; + n = 1 << nbits; + + s->revtab = (uint16_t *)av_malloc(n * sizeof(uint16_t)); + if (!s->revtab) + goto fail; + s->tmp_buf = (FFTComplex *)av_malloc(n * sizeof(FFTComplex)); + if (!s->tmp_buf) + goto fail; + s->inverse = inverse; + + for(j=4; j<=nbits; j++) { + ff_init_ff_cos_tabs(j); + } + + for(i=0; iinverse) & (n - 1); + s->revtab[index] = j; + } + + return 0; + fail: + av_freep(&s->revtab); + av_freep(&s->tmp_buf); + return -1; +} + +void ff_fft_end(FFTContext *s) +{ + av_freep(&s->revtab); + av_freep(&s->tmp_buf); +} + +#define BF(x, y, a, b) do { \ + x = a - b; \ + y = a + b; \ + } while (0) + +#define BUTTERFLIES(a0,a1,a2,a3) {\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, a0.re, t5);\ + BF(a3.im, a1.im, a1.im, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, a1.re, t4);\ + BF(a2.im, a0.im, a0.im, t6);\ +} + +// force loading all the inputs before storing any. +// this is slightly slower for small data, but avoids store->load aliasing +// for addresses separated by large powers of 2. +#define BUTTERFLIES_BIG(a0,a1,a2,a3) {\ + FFTSample r0=a0.re, i0=a0.im, r1=a1.re, i1=a1.im;\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, r0, t5);\ + BF(a3.im, a1.im, i1, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, r1, t4);\ + BF(a2.im, a0.im, i0, t6);\ +} + +#define TRANSFORM(a0,a1,a2,a3,wre,wim) {\ + CMUL(t1, t2, a2.re, a2.im, wre, -wim);\ + CMUL(t5, t6, a3.re, a3.im, wre, wim);\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +#define TRANSFORM_ZERO(a0,a1,a2,a3) {\ + t1 = a2.re;\ + t2 = a2.im;\ + t5 = a3.re;\ + t6 = a3.im;\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +/* z[0...8n-1], w[1...2n-1] */ +#define PASS(name)\ +static void name(FFTComplex *z, const FFTSample *wre, unsigned int n)\ +{\ + FFTDouble t1, t2, t3, t4, t5, t6;\ + int o1 = 2*n;\ + int o2 = 4*n;\ + int o3 = 6*n;\ + const FFTSample *wim = wre+o1;\ + n--;\ +\ + TRANSFORM_ZERO(z[0],z[o1],z[o2],z[o3]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + do {\ + z += 2;\ + wre += 2;\ + wim -= 2;\ + TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + } while(--n);\ +} + +PASS(pass) +#undef BUTTERFLIES +#define BUTTERFLIES BUTTERFLIES_BIG +PASS(pass_big) + +#define DECL_FFT(n,n2,n4)\ +static void fft##n(FFTComplex *z)\ +{\ + fft##n2(z);\ + fft##n4(z+n4*2);\ + fft##n4(z+n4*3);\ + pass(z,av_cos_##n,n4/2);\ +} + +static void fft4(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6, t7, t8; + + BF(t3, t1, z[0].re, z[1].re); + BF(t8, t6, z[3].re, z[2].re); + BF(z[2].re, z[0].re, t1, t6); + BF(t4, t2, z[0].im, z[1].im); + BF(t7, t5, z[2].im, z[3].im); + BF(z[3].im, z[1].im, t4, t8); + BF(z[3].re, z[1].re, t3, t7); + BF(z[2].im, z[0].im, t2, t5); +} + +static void fft8(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6; + + fft4(z); + + BF(t1, z[5].re, z[4].re, -z[5].re); + BF(t2, z[5].im, z[4].im, -z[5].im); + BF(t5, z[7].re, z[6].re, -z[7].re); + BF(t6, z[7].im, z[6].im, -z[7].im); + + BUTTERFLIES(z[0],z[2],z[4],z[6]); + TRANSFORM(z[1],z[3],z[5],z[7],sqrthalf,sqrthalf); +} + +static void fft16(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6; + FFTSample cos_16_1 = av_cos_16[1]; + FFTSample cos_16_3 = av_cos_16[3]; + + fft8(z); + fft4(z+8); + fft4(z+12); + + TRANSFORM_ZERO(z[0],z[4],z[8],z[12]); + TRANSFORM(z[2],z[6],z[10],z[14],sqrthalf,sqrthalf); + TRANSFORM(z[1],z[5],z[9],z[13],cos_16_1,cos_16_3); + TRANSFORM(z[3],z[7],z[11],z[15],cos_16_3,cos_16_1); +} +DECL_FFT(32,16,8) +DECL_FFT(64,32,16) +DECL_FFT(128,64,32) +DECL_FFT(256,128,64) +DECL_FFT(512,256,128) +#define pass pass_big +DECL_FFT(1024,512,256) + +static void (* const fft_dispatch[])(FFTComplex*) = { + fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024, +}; + +void fft_calc(FFTContext *s, FFTComplex *z) { + fft_dispatch[s->nbits-2](z); +} + +#include +#include + +#include "fft.h" +#include "mem.h" + +/** + * init MDCT or IMDCT computation. + */ +int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale) +{ + int n, n4, i; + double alpha, theta; + int tstep; + + memset(s, 0, sizeof(*s)); + n = 1 << nbits; + s->mdct_bits = nbits; + s->mdct_size = n; + n4 = n >> 2; + s->mdct_permutation = FF_MDCT_PERM_NONE; + + if (ff_fft_init(s, s->mdct_bits - 2, inverse) < 0) + goto fail; + + s->tcos = (FFTSample *)av_malloc_array(n / 2, sizeof(FFTSample)); + if (!s->tcos) + goto fail; + + switch (s->mdct_permutation) { + case FF_MDCT_PERM_NONE: + s->tsin = s->tcos + n4; + tstep = 1; + break; + case FF_MDCT_PERM_INTERLEAVE: + s->tsin = s->tcos + 1; + tstep = 2; + break; + default: + goto fail; + } + + theta = 1.0 / 8.0 + (scale < 0 ? n4 : 0); + scale = sqrt(fabs(scale)); + for (i = 0; i < n4; i++) { + alpha = 2 * M_PI * (i + theta) / n; + s->tcos[i * tstep] = -cos(alpha) * scale; + s->tsin[i * tstep] = -sin(alpha) * scale; + } + return 0; +fail: + ff_mdct_end(s); + return -1; +} + +/** + * Compute the middle half of the inverse MDCT of size N = 2^nbits, + * thus excluding the parts that can be derived by symmetry + * @param output N/2 samples + * @param input N/2 samples + */ +void imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + int k, n8, n4, n2, n, j; + const uint16_t *revtab = s->revtab; + const FFTSample *tcos = s->tcos; + const FFTSample *tsin = s->tsin; + const FFTSample *in1, *in2; + FFTComplex *z = (FFTComplex *)output; + + n = 1 << s->mdct_bits; + n2 = n >> 1; + n4 = n >> 2; + n8 = n >> 3; + + /* pre rotation */ + in1 = input; + in2 = input + n2 - 1; + for (k = 0; k < n4; k++) { + j = revtab[k]; + CMUL(z[j].re, z[j].im, *in2, *in1, tcos[k], tsin[k]); + in1 += 2; + in2 -= 2; + } + fft_calc(s, z); + + /* post rotation + reordering */ + for (k = 0; k < n8; k++) { + FFTSample r0, i0, r1, i1; + CMUL(r0, i1, z[n8 - k - 1].im, z[n8 - k - 1].re, tsin[n8 - k - 1], tcos[n8 - k - 1]); + CMUL(r1, i0, z[n8 + k].im, z[n8 + k].re, tsin[n8 + k], tcos[n8 + k]); + z[n8 - k - 1].re = r0; + z[n8 - k - 1].im = i0; + z[n8 + k].re = r1; + z[n8 + k].im = i1; + } +} + +/** + * Compute inverse MDCT of size N = 2^nbits + * @param output N samples + * @param input N/2 samples + */ +void imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + int k; + int n = 1 << s->mdct_bits; + int n2 = n >> 1; + int n4 = n >> 2; + + imdct_half(s, output + n4, input); + + for (k = 0; k < n4; k++) { + output[k] = -output[n2 - k - 1]; + output[n - k - 1] = output[n2 + k]; + } +} + +void ff_mdct_end(FFTContext *s) +{ + av_freep(&s->tcos); + ff_fft_end(s); +} diff --git a/ext/at3_standalone/fft.h b/ext/at3_standalone/fft.h new file mode 100644 index 0000000000..9df03ca19b --- /dev/null +++ b/ext/at3_standalone/fft.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#define CMUL(dre, dim, are, aim, bre, bim) do { \ + (dre) = (are) * (bre) - (aim) * (bim); \ + (dim) = (are) * (bim) + (aim) * (bre); \ + } while (0) + +#include + +#include "compat.h" + +typedef float FFTSample; + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +typedef float FFTDouble; + +/* FFT computation */ + +enum mdct_permutation_type { + FF_MDCT_PERM_NONE, + FF_MDCT_PERM_INTERLEAVE, +}; + +struct FFTContext { + int nbits; + int inverse; + uint16_t *revtab; + FFTComplex *tmp_buf; + int mdct_size; /* size of MDCT (i.e. number of input data * 2) */ + int mdct_bits; /* n = 2^nbits */ + /* pre/post rotation tables */ + FFTSample *tcos; + FFTSample *tsin; + + enum mdct_permutation_type mdct_permutation; +}; + +/** + * Do a complex FFT with the parameters defined in ff_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ +void fft_calc(struct FFTContext *s, FFTComplex *z); +void imdct_calc(struct FFTContext *s, FFTSample *output, const FFTSample *input); +void imdct_half(struct FFTContext *s, FFTSample *output, const FFTSample *input); + +#define COSTABLE(size) \ + DECLARE_ALIGNED(32, FFTSample, av_cos_##size)[size/2] + +extern COSTABLE(16); +extern COSTABLE(32); +extern COSTABLE(64); +extern COSTABLE(128); +extern COSTABLE(256); +extern COSTABLE(512); +extern COSTABLE(1024); +extern COSTABLE(2048); +extern COSTABLE(4096); +extern COSTABLE(8192); +extern COSTABLE(16384); +extern COSTABLE(32768); +extern COSTABLE(65536); + +/** + * Initialize the cosine table in ff_cos_tabs[index] + * @param index index in ff_cos_tabs array of the table to initialize + */ +void ff_init_ff_cos_tabs(int index); + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +int ff_fft_init(FFTContext *s, int nbits, int inverse); + +void ff_fft_end(FFTContext *s); + +int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale); +void ff_mdct_end(FFTContext *s); diff --git a/ext/at3_standalone/float_dsp.h b/ext/at3_standalone/float_dsp.h new file mode 100644 index 0000000000..c9664a814b --- /dev/null +++ b/ext/at3_standalone/float_dsp.h @@ -0,0 +1,53 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "compat.h" + +inline void vector_fmul(float * av_restrict dst, const float * av_restrict src, int len) { + for (int i = 0; i < len; i++) + dst[i] = dst[i] * src[i]; +} + +/** +* Multiply a vector of floats by a scalar float. Source and +* destination vectors must overlap exactly or not at all. +*/ +inline void vector_fmul_scalar(float *dst, float mul, int len) { + for (int i = 0; i < len; i++) + dst[i] *= mul; +} + +/** +* Calculate the entry wise product of two vectors of floats, and store the result +* in a vector of floats. The second vector of floats is iterated over +* in reverse order. +* +* @param dst output and first input vector +* constraints: 32-byte aligned +* @param src second input vector +* constraints: 32-byte aligned +* @param len number of elements in the input +* constraints: multiple of 16 +*/ +inline void vector_fmul_reverse(float * av_restrict dst, const float * av_restrict src, int len) { + src += len - 1; + for (int i = 0; i < len; i++) + dst[i] *= src[-i]; +} diff --git a/ext/at3_standalone/get_bits.cpp b/ext/at3_standalone/get_bits.cpp new file mode 100644 index 0000000000..50d3969219 --- /dev/null +++ b/ext/at3_standalone/get_bits.cpp @@ -0,0 +1,324 @@ +/* + * Common bit i/o utils + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * Copyright (c) 2010 Loren Merritt + * + * alternative bitstream reader & writer by Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * bitstream api. + */ + +#include +#include + +#include "compat.h" +#include "mem.h" +#include "get_bits.h" + +static const uint8_t ff_reverse[256] = { +0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, +0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, +0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, +0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, +0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, +0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, +0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, +0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, +0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, +0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, +0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, +0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, +0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, +0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, +0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, +0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF, +}; + +/* VLC decoding */ + +#define GET_DATA(v, table, i, wrap, size) \ +{ \ + const uint8_t *ptr = (const uint8_t *)table + i * wrap; \ + switch(size) { \ + case 1: \ + v = *(const uint8_t *)ptr; \ + break; \ + case 2: \ + v = *(const uint16_t *)ptr; \ + break; \ + default: \ + v = *(const uint32_t *)ptr; \ + break; \ + } \ +} + +static int alloc_table(VLC *vlc, int size, int use_static) +{ + int index = vlc->table_size; + + vlc->table_size += size; + if (vlc->table_size > vlc->table_allocated) { + if (use_static) + abort(); // cannot do anything, init_vlc() is used with too little memory + vlc->table_allocated += (1 << vlc->bits); + vlc->table = (VLC_TYPE(*)[2])av_realloc_f(vlc->table, vlc->table_allocated, sizeof(VLC_TYPE) * 2); + if (!vlc->table) { + vlc->table_allocated = 0; + vlc->table_size = 0; + return AVERROR(ENOMEM); + } + memset(vlc->table + vlc->table_allocated - (unsigned int)(1UL << vlc->bits), 0, sizeof(VLC_TYPE) * 2 << vlc->bits); + } + return index; +} + +static inline uint32_t bitswap_32(uint32_t x) +{ + return (uint32_t)ff_reverse[ x & 0xFF] << 24 | + (uint32_t)ff_reverse[(x >> 8) & 0xFF] << 16 | + (uint32_t)ff_reverse[(x >> 16) & 0xFF] << 8 | + (uint32_t)ff_reverse[ x >> 24]; +} + +typedef struct VLCcode { + /** codeword, with the first bit-to-be-read in the msb + * (even if intended for a little-endian bitstream reader) */ + uint32_t code; + uint16_t symbol; + uint8_t bits; +} VLCcode; + +static int compare_vlcspec(const void *a, const void *b) +{ + const VLCcode *sa = (VLCcode *)a; + const VLCcode *sb = (VLCcode *)b; + return (sa->code >> 1) - (sb->code >> 1); +} +/** + * Build VLC decoding tables suitable for use with get_vlc(). + * + * @param vlc the context to be initted + * + * @param table_nb_bits max length of vlc codes to store directly in this table + * (Longer codes are delegated to subtables.) + * + * @param nb_codes number of elements in codes[] + * + * @param codes descriptions of the vlc codes + * These must be ordered such that codes going into the same subtable are contiguous. + * Sorting by VLCcode.code is sufficient, though not necessary. + */ +static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, + VLCcode *codes, int flags) +{ + int table_size, table_index, index, code_prefix, symbol, subtable_bits; + int i, j, k, n, nb, inc; + uint32_t code; + volatile VLC_TYPE (* volatile table)[2]; // the double volatile is needed to prevent a internal compiler error in gcc 4.2 + + table_size = 1 << table_nb_bits; + if (table_nb_bits > 30) + return -1; + table_index = alloc_table(vlc, table_size, flags & INIT_VLC_USE_NEW_STATIC); + if (table_index < 0) + return table_index; + table = (volatile VLC_TYPE (*)[2])&vlc->table[table_index]; + + /* first pass: map codes and compute auxiliary table sizes */ + for (i = 0; i < nb_codes; i++) { + n = codes[i].bits; + code = codes[i].code; + symbol = codes[i].symbol; + if (n <= table_nb_bits) { + /* no need to add another table */ + j = code >> (32 - table_nb_bits); + nb = 1 << (table_nb_bits - n); + inc = 1; + if (flags & INIT_VLC_LE) { + j = bitswap_32(code); + inc = 1 << n; + } + for (k = 0; k < nb; k++) { + int bits = table[j][1]; + if (bits != 0 && bits != n) { + av_log(AV_LOG_ERROR, "incorrect codes"); + return AVERROR_INVALIDDATA; + } + table[j][1] = n; //bits + table[j][0] = symbol; + j += inc; + } + } else { + /* fill auxiliary table recursively */ + n -= table_nb_bits; + code_prefix = code >> (32 - table_nb_bits); + subtable_bits = n; + codes[i].bits = n; + codes[i].code = code << table_nb_bits; + for (k = i+1; k < nb_codes; k++) { + n = codes[k].bits - table_nb_bits; + if (n <= 0) + break; + code = codes[k].code; + if (code >> (32 - table_nb_bits) != code_prefix) + break; + codes[k].bits = n; + codes[k].code = code << table_nb_bits; + subtable_bits = FFMAX(subtable_bits, n); + } + subtable_bits = FFMIN(subtable_bits, table_nb_bits); + j = (flags & INIT_VLC_LE) ? bitswap_32(code_prefix) >> (32 - table_nb_bits) : code_prefix; + table[j][1] = -subtable_bits; + index = build_table(vlc, subtable_bits, k-i, codes+i, flags); + if (index < 0) + return index; + /* note: realloc has been done, so reload tables */ + table = (volatile VLC_TYPE (*)[2])&vlc->table[table_index]; + table[j][0] = index; //code + i = k-1; + } + } + + for (i = 0; i < table_size; i++) { + if (table[i][1] == 0) //bits + table[i][0] = -1; //codes + } + + return table_index; +} + + +/* Build VLC decoding tables suitable for use with get_vlc(). + + 'nb_bits' set the decoding table size (2^nb_bits) entries. The + bigger it is, the faster is the decoding. But it should not be too + big to save memory and L1 cache. '9' is a good compromise. + + 'nb_codes' : number of vlcs codes + + 'bits' : table which gives the size (in bits) of each vlc code. + + 'codes' : table which gives the bit pattern of of each vlc code. + + 'symbols' : table which gives the values to be returned from get_vlc(). + + 'xxx_wrap' : give the number of bytes between each entry of the + 'bits' or 'codes' tables. + + 'xxx_size' : gives the number of bytes of each entry of the 'bits' + or 'codes' tables. + + 'wrap' and 'size' make it possible to use any memory configuration and types + (byte/word/long) to store the 'bits', 'codes', and 'symbols' tables. + + 'use_static' should be set to 1 for tables, which should be freed + with av_free_static(), 0 if ff_free_vlc() will be used. +*/ +int ff_init_vlc_sparse(VLC *vlc_arg, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags) +{ + VLCcode *buf; + int i, j, ret; + VLCcode localbuf[1500]; // the maximum currently needed is 1296 by rv34 + VLC localvlc, *vlc; + + vlc = vlc_arg; + vlc->bits = nb_bits; + if (flags & INIT_VLC_USE_NEW_STATIC) { + av_assert0(nb_codes + 1 <= FF_ARRAY_ELEMS(localbuf)); + buf = localbuf; + localvlc = *vlc_arg; + vlc = &localvlc; + vlc->table_size = 0; + } else { + vlc->table = NULL; + vlc->table_allocated = 0; + vlc->table_size = 0; + + buf = (VLCcode *)av_malloc_array((nb_codes + 1), sizeof(VLCcode)); + if (!buf) + return AVERROR(ENOMEM); + } + + + av_assert0(symbols_size <= 2 || !symbols); + j = 0; +#define COPY(condition)\ + for (i = 0; i < nb_codes; i++) { \ + GET_DATA(buf[j].bits, bits, i, bits_wrap, bits_size); \ + if (!(condition)) \ + continue; \ + if (buf[j].bits > 3*nb_bits || buf[j].bits>32) { \ + av_log(AV_LOG_ERROR, "Too long VLC (%d) in init_vlc", buf[j].bits);\ + if (!(flags & INIT_VLC_USE_NEW_STATIC)) \ + av_free(buf); \ + return -1; \ + } \ + GET_DATA(buf[j].code, codes, i, codes_wrap, codes_size); \ + if (buf[j].code >= (1LL< nb_bits); + // qsort is the slowest part of init_vlc, and could probably be improved or avoided + qsort(buf, j, sizeof(struct VLCcode), compare_vlcspec); + COPY(buf[j].bits && buf[j].bits <= nb_bits); + nb_codes = j; + + ret = build_table(vlc, nb_bits, nb_codes, buf, flags); + + if (flags & INIT_VLC_USE_NEW_STATIC) { + if(vlc->table_size != vlc->table_allocated) + av_log(AV_LOG_ERROR, "needed %d had %d", vlc->table_size, vlc->table_allocated); + + av_assert0(ret >= 0); + *vlc_arg = *vlc; + } else { + av_free(buf); + if (ret < 0) { + av_freep(&vlc->table); + return ret; + } + } + return 0; +} + +void ff_free_vlc(VLC *vlc) +{ + av_freep(&vlc->table); +} diff --git a/ext/at3_standalone/get_bits.h b/ext/at3_standalone/get_bits.h new file mode 100644 index 0000000000..9366026eea --- /dev/null +++ b/ext/at3_standalone/get_bits.h @@ -0,0 +1,479 @@ +/* + * copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once +#include +#include + +#include "compat.h" +#include "intreadwrite.h" + +#ifndef NEG_SSR32 +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +#endif + +#ifndef NEG_USR32 +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +static inline unsigned zero_extend(unsigned val, unsigned bits) +{ + return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits); +} + +static inline int sign_extend(int val, unsigned bits) +{ + unsigned shift = 8 * sizeof(int) - bits; + union { unsigned u; int s; } v = { (unsigned)val << shift }; + return v.s >> shift; +} + +/* + * Safe bitstream reading: + * optionally, the get_bits API can check to ensure that we + * don't read past input buffer boundaries. This is protected + * with CONFIG_SAFE_BITSTREAM_READER at the global level, and + * then below that with UNCHECKED_BITSTREAM_READER at the per- + * decoder level. This means that decoders that check internally + * can "#define UNCHECKED_BITSTREAM_READER 1" to disable + * overread checks. + * Boundary checking causes a minor performance penalty so for + * applications that won't want/need this, it can be disabled + * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0". + */ +#ifndef UNCHECKED_BITSTREAM_READER +#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER +#endif + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; + int index; + int size_in_bits; + int size_in_bits_plus8; +} GetBitContext; + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +/* Bitstream reader API docs: + * name + * arbitrary name which is used as prefix for the internal variables + * + * gb + * getbitcontext + * + * OPEN_READER(name, gb) + * load gb into local variables + * + * CLOSE_READER(name, gb) + * store local vars in gb + * + * UPDATE_CACHE(name, gb) + * Refill the internal cache from the bitstream. + * After this call at least MIN_CACHE_BITS will be available. + * + * GET_CACHE(name, gb) + * Will output the contents of the internal cache, + * next bit is MSB of 32 or 64 bit (FIXME 64bit). + * + * SHOW_UBITS(name, gb, num) + * Will return the next num bits. + * + * SHOW_SBITS(name, gb, num) + * Will return the next num bits and do sign extension. + * + * SKIP_BITS(name, gb, num) + * Will skip over the next num bits. + * Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER. + * + * SKIP_CACHE(name, gb, num) + * Will remove the next num bits from the cache (note SKIP_COUNTER + * MUST be called before UPDATE_CACHE / CLOSE_READER). + * + * SKIP_COUNTER(name, gb, num) + * Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS). + * + * LAST_SKIP_BITS(name, gb, num) + * Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER. + * + * BITS_LEFT(name, gb) + * Return the number of bits left + * + * For examples see get_bits, show_bits, skip_bits, get_vlc. + */ + +#ifdef LONG_BITSTREAM_READER +# define MIN_CACHE_BITS 32 +#else +# define MIN_CACHE_BITS 25 +#endif + +#define OPEN_READER_NOSIZE(name, gb) \ + unsigned int name ## _index = (gb)->index; \ + unsigned int av_unused name ## _cache + +#if UNCHECKED_BITSTREAM_READER +#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) + +#define BITS_AVAILABLE(name, gb) 1 +#else +#define OPEN_READER(name, gb) \ + OPEN_READER_NOSIZE(name, gb); \ + unsigned int name ## _size_plus8 = (gb)->size_in_bits_plus8 + +#define BITS_AVAILABLE(name, gb) name ## _index < name ## _size_plus8 +#endif + +#define CLOSE_READER(name, gb) (gb)->index = name ## _index + +# ifdef LONG_BITSTREAM_READER + +# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ + AV_RL64((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB64((gb)->buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7)) + +#else + +# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ + AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7) + +#endif + + +#ifdef BITSTREAM_READER_LE + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) + +# define SKIP_CACHE(name, gb, num) name ## _cache >>= (num) + +#else + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb) + +# define SKIP_CACHE(name, gb, num) name ## _cache <<= (num) + +#endif + +#if UNCHECKED_BITSTREAM_READER +# define SKIP_COUNTER(name, gb, num) name ## _index += (num) +#else +# define SKIP_COUNTER(name, gb, num) \ + name ## _index = FFMIN(name ## _size_plus8, name ## _index + (num)) +#endif + +#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index)) + +#define SKIP_BITS(name, gb, num) \ + do { \ + SKIP_CACHE(name, gb, num); \ + SKIP_COUNTER(name, gb, num); \ + } while (0) + +#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) + +#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num) +#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num) + +#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num) +#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num) + +#ifdef BITSTREAM_READER_LE +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num) +#else +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num) +#endif + +#define GET_CACHE(name, gb) ((uint32_t) name ## _cache) + +static inline int get_bits_count(const GetBitContext *s) +{ + return s->index; +} + +static inline int get_sbits(GetBitContext *s, int n) +{ + int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_SBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +/** + * Read 1-25 bits. + */ +static inline unsigned int get_bits(GetBitContext *s, int n) +{ + int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +/** + * Read 0-25 bits. + */ +static inline int get_bitsz(GetBitContext *s, int n) +{ + return n ? get_bits(s, n) : 0; +} + +static inline unsigned int get_bits_le(GetBitContext *s, int n) +{ + int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE_LE(re, s); + tmp = SHOW_UBITS_LE(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +static inline void skip_bits(GetBitContext *s, int n) +{ + OPEN_READER(re, s); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +} + +static inline unsigned int get_bits1(GetBitContext *s) +{ + unsigned int index = s->index; + uint8_t result = s->buffer[index >> 3]; +#ifdef BITSTREAM_READER_LE + result >>= index & 7; + result &= 1; +#else + result <<= index & 7; + result >>= 8 - 1; +#endif +#if !UNCHECKED_BITSTREAM_READER + if (s->index < s->size_in_bits_plus8) +#endif + index++; + s->index = index; + + return result; +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param bit_size the size of the buffer in bits + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, + int bit_size) +{ + int buffer_size; + int ret = 0; + + if (bit_size >= INT_MAX - 7 || bit_size < 0 || !buffer) { + bit_size = 0; + buffer = NULL; + ret = AVERROR_INVALIDDATA; + } + + buffer_size = (bit_size + 7) >> 3; + + s->buffer = buffer; + s->size_in_bits = bit_size; + s->size_in_bits_plus8 = bit_size + 8; + s->buffer_end = buffer + buffer_size; + s->index = 0; + + return ret; +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param byte_size the size of the buffer in bytes + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer, + int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits(s, buffer, byte_size * 8); +} + +static inline const uint8_t *align_get_bits(GetBitContext *s) +{ + int n = -get_bits_count(s) & 7; + if (n) + skip_bits(s, n); + return s->buffer + (s->index >> 3); +} + +#define init_vlc(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + flags) \ + ff_init_vlc_sparse(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + NULL, 0, 0, flags) + +int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags); +void ff_free_vlc(VLC *vlc); + +#define INIT_VLC_LE 2 +#define INIT_VLC_USE_NEW_STATIC 4 + +#define INIT_VLC_STATIC(vlc, bits, a, b, c, d, e, f, g, static_size) \ + do { \ + static VLC_TYPE table[static_size][2]; \ + (vlc)->table = table; \ + (vlc)->table_allocated = static_size; \ + init_vlc(vlc, bits, a, b, c, d, e, f, g, INIT_VLC_USE_NEW_STATIC); \ + } while (0) + +/** + * If the vlc code is invalid and max_depth=1, then no bits will be removed. + * If the vlc code is invalid and max_depth>1, then the number of bits removed + * is undefined. + */ +#define GET_VLC(code, name, gb, table, bits, max_depth) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + code = table[index][0]; \ + n = table[index][1]; \ + \ + if (max_depth > 1 && n < 0) { \ + LAST_SKIP_BITS(name, gb, bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + } \ + } \ + SKIP_BITS(name, gb, n); \ + } while (0) + +/** + * Parse a vlc code. + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be read to completely + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + + GET_VLC(code, re, s, table, bits, max_depth); + + CLOSE_READER(re, s); + + return code; +} + +static inline int get_bits_left(GetBitContext *gb) +{ + return gb->size_in_bits - get_bits_count(gb); +} + +#include "intreadwrite.h" + +typedef struct GetByteContext { + const uint8_t *buffer, *buffer_end, *buffer_start; +} GetByteContext; + +#define DEF(type, name, bytes, read, write) \ +static inline type bytestream_get_ ## name(const uint8_t **b) \ +{ \ + (*b) += bytes; \ + return read(*b - bytes); \ +} \ +static inline type bytestream2_get_ ## name ## u(GetByteContext *g) \ +{ \ + return bytestream_get_ ## name(&g->buffer); \ +} \ +static inline type bytestream2_get_ ## name(GetByteContext *g) \ +{ \ + if (g->buffer_end - g->buffer < bytes) { \ + g->buffer = g->buffer_end; \ + return 0; \ + } \ + return bytestream2_get_ ## name ## u(g); \ +} + +DEF(unsigned int, le32, 4, AV_RL32, AV_WL32) +DEF(unsigned int, le24, 3, AV_RL24, AV_WL24) +DEF(unsigned int, le16, 2, AV_RL16, AV_WL16) +DEF(unsigned int, be32, 4, AV_RB32, AV_WB32) +DEF(unsigned int, be24, 3, AV_RB24, AV_WB24) +DEF(unsigned int, be16, 2, AV_RB16, AV_WB16) diff --git a/ext/at3_standalone/intreadwrite.h b/ext/at3_standalone/intreadwrite.h new file mode 100644 index 0000000000..c6d776c10e --- /dev/null +++ b/ext/at3_standalone/intreadwrite.h @@ -0,0 +1,336 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once +#include + +#include "compat.h" + +typedef union { + uint64_t u64; + uint32_t u32[2]; + uint16_t u16[4]; + uint8_t u8 [8]; + double f64; + float f32[2]; +} av_alias av_alias64; + +typedef union { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8 [4]; + float f32; +} av_alias av_alias32; + +typedef union { + uint16_t u16; + uint8_t u8 [2]; +} av_alias av_alias16; + +#include "compat.h" + +# if defined(AV_RN16) && !defined(AV_RL16) +# define AV_RL16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RL16) +# define AV_RN16(p) AV_RL16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WL16) +# define AV_WL16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WL16) +# define AV_WN16(p, v) AV_WL16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RL24) +# define AV_RL24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RL24) +# define AV_RN24(p) AV_RL24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WL24) +# define AV_WL24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WL24) +# define AV_WN24(p, v) AV_WL24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RL32) +# define AV_RL32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RL32) +# define AV_RN32(p) AV_RL32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WL32) +# define AV_WL32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WL32) +# define AV_WN32(p, v) AV_WL32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RL48) +# define AV_RL48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RL48) +# define AV_RN48(p) AV_RL48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WL48) +# define AV_WL48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WL48) +# define AV_WN48(p, v) AV_WL48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RL64) +# define AV_RL64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RL64) +# define AV_RN64(p) AV_RL64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WL64) +# define AV_WL64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WL64) +# define AV_WN64(p, v) AV_WL64(p, v) +# endif + +/* + * Define AV_[RW]N helper macros to simplify definitions not provided + * by per-arch headers. + */ +#if AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) +# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#else + +#ifndef AV_RB16 +# define AV_RB16(x) \ + ((((const uint8_t*)(x))[0] << 8) | \ + ((const uint8_t*)(x))[1]) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[1] = (d); \ + ((uint8_t*)(p))[0] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RL16 +# define AV_RL16(x) \ + ((((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RB32 +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d)>>8; \ + ((uint8_t*)(p))[1] = (d)>>16; \ + ((uint8_t*)(p))[0] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RL32 +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RB64 +# define AV_RB64(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ + (uint64_t)((const uint8_t*)(x))[7]) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[7] = (d); \ + ((uint8_t*)(p))[6] = (d)>>8; \ + ((uint8_t*)(p))[5] = (d)>>16; \ + ((uint8_t*)(p))[4] = (d)>>24; \ + ((uint8_t*)(p))[3] = (d)>>32; \ + ((uint8_t*)(p))[2] = (d)>>40; \ + ((uint8_t*)(p))[1] = (d)>>48; \ + ((uint8_t*)(p))[0] = (d)>>56; \ + } while(0) +#endif + +#ifndef AV_RL64 +# define AV_RL64(x) \ + (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + ((uint8_t*)(p))[6] = (d)>>48; \ + ((uint8_t*)(p))[7] = (d)>>56; \ + } while(0) +#endif + +# define AV_RN(s, p) AV_RL##s(p) +# define AV_WN(s, p, v) AV_WL##s(p, v) + +#endif /* HAVE_FAST_UNALIGNED */ + +#ifndef AV_RN16 +# define AV_RN16(p) AV_RN(16, p) +#endif + +#ifndef AV_RN32 +# define AV_RN32(p) AV_RN(32, p) +#endif + +#ifndef AV_RN64 +# define AV_RN64(p) AV_RN(64, p) +#endif + +#ifndef AV_WN16 +# define AV_WN16(p, v) AV_WN(16, p, v) +#endif + +#ifndef AV_WN32 +# define AV_WN32(p, v) AV_WN(32, p, v) +#endif + +#ifndef AV_WN64 +# define AV_WN64(p, v) AV_WN(64, p, v) +#endif + +# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) +# define AV_RL(s, p) AV_RN##s(p) +# define AV_WL(s, p, v) AV_WN##s(p, v) + +#define AV_RB8(x) (((const uint8_t*)(x))[0]) +#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) + +#define AV_RL8(x) AV_RB8(x) +#define AV_WL8(p, d) AV_WB8(p, d) + +#ifndef AV_RB16 +# define AV_RB16(p) AV_RB(16, p) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, v) AV_WB(16, p, v) +#endif + +#ifndef AV_RL16 +# define AV_RL16(p) AV_RL(16, p) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, v) AV_WL(16, p, v) +#endif + +#ifndef AV_RB32 +# define AV_RB32(p) AV_RB(32, p) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, v) AV_WB(32, p, v) +#endif + +#ifndef AV_RL32 +# define AV_RL32(p) AV_RL(32, p) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, v) AV_WL(32, p, v) +#endif + +#ifndef AV_RB64 +# define AV_RB64(p) AV_RB(64, p) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, v) AV_WB(64, p, v) +#endif + +#ifndef AV_RL64 +# define AV_RL64(p) AV_RL(64, p) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, v) AV_WL(64, p, v) +#endif + +#ifndef AV_RB24 +# define AV_RB24(x) \ + ((((const uint8_t*)(x))[0] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[2]) +#endif +#ifndef AV_WB24 +# define AV_WB24(p, d) do { \ + ((uint8_t*)(p))[2] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[0] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RL24 +# define AV_RL24(x) \ + ((((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL24 +# define AV_WL24(p, d) do { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + } while(0) +#endif diff --git a/ext/at3_standalone/mem.cpp b/ext/at3_standalone/mem.cpp new file mode 100644 index 0000000000..4577223662 --- /dev/null +++ b/ext/at3_standalone/mem.cpp @@ -0,0 +1,106 @@ +/* + * default memory allocator for libavutil + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * default memory allocator for libavutil + */ + +#define _XOPEN_SOURCE 600 + +#include +#include +#include +#include + +#include "compat.h" +#include "intreadwrite.h" +#include "mem.h" + + /** + * Multiply two size_t values checking for overflow. + * @return 0 if success, AVERROR(EINVAL) if overflow. + */ +static inline int av_size_mult(size_t a, size_t b, size_t *r) +{ + size_t t = a * b; + /* Hack inspired from glibc: only try the division if nelem and elsize + * are both greater than sqrt(SIZE_MAX). */ + if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) + return AVERROR(EINVAL); + *r = t; + return 0; +} + +#define ALIGN (HAVE_AVX ? 32 : 16) + +void *av_malloc(size_t size) +{ + void *ptr = NULL; + ptr = malloc(size); + if(!ptr && !size) { + size = 1; + ptr= av_malloc(1); + } + return ptr; +} + +void *av_realloc(void *ptr, size_t size) +{ + return realloc(ptr, size + !size); +} + +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) +{ + size_t size; + void *r; + + if (av_size_mult(elsize, nelem, &size)) { + av_free(ptr); + return NULL; + } + r = av_realloc(ptr, size); + if (!r && size) + av_free(ptr); + return r; +} + +void av_free(void *ptr) +{ + free(ptr); +} + +void av_freep(void *arg) +{ + void *val; + + memcpy(&val, arg, sizeof(val)); + memset(arg, 0, sizeof(val)); + av_free(val); +} + +void *av_mallocz(size_t size) +{ + void *ptr = av_malloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} diff --git a/ext/at3_standalone/mem.h b/ext/at3_standalone/mem.h new file mode 100644 index 0000000000..0e01ff92a4 --- /dev/null +++ b/ext/at3_standalone/mem.h @@ -0,0 +1,132 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include +#include +#include +#include + +#include "compat.h" + +/** + * Allocate a block of size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU). + * @param size Size in bytes for the memory block to be allocated. + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_mallocz() + */ +void *av_malloc(size_t size); + +/** + * Allocate a block of size * nmemb bytes with av_malloc(). + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_malloc() + */ +static inline void *av_malloc_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_malloc(nmemb * size); +} + +/** + * Allocate or reallocate a block of memory. + * If ptr is NULL and size > 0, allocate a new block. If + * size is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or NULL. + * @param size Size in bytes of the memory block to be allocated or + * reallocated. + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated or the function is used to free the memory block. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +void *av_realloc(void *ptr, size_t size); + +/** + * Allocate or reallocate a block of memory. + * This function does the same thing as av_realloc, except: + * - It takes two arguments and checks the result of the multiplication for + * integer overflow. + * - It frees the input block in case of failure, thus avoiding the memory + * leak with the classic "buf = realloc(buf); if (!buf) return -1;". + */ +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); + +/** + * Free a memory block which has been allocated with av_malloc(z)() or + * av_realloc(). + * @param ptr Pointer to the memory block which should be freed. + * @note ptr = NULL is explicitly allowed. + * @note It is recommended that you use av_freep() instead. + * @see av_freep() + */ +void av_free(void *ptr); + +/** + * Allocate a block of size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU) and + * zero all the bytes of the block. + * @param size Size in bytes for the memory block to be allocated. + * @return Pointer to the allocated block, NULL if it cannot be allocated. + * @see av_malloc() + */ +void *av_mallocz(size_t size); + +/** + * Allocate a block of size * nmemb bytes with av_mallocz(). + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_mallocz() + * @see av_malloc_array() + */ +static inline void *av_mallocz_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + +/** + * Free a memory block which has been allocated with av_malloc(z)() or + * av_realloc() and set the pointer pointing to it to NULL. + * @param ptr Pointer to the pointer to the memory block which should + * be freed. + * @note passing a pointer to a NULL pointer is safe and leads to no action. + * @see av_free() + */ +void av_freep(void *ptr); + +/** + * @} + */ diff --git a/ext/jpge/jpge.cpp b/ext/jpge/jpge.cpp index d9cc1866d3..8448197b66 100644 --- a/ext/jpge/jpge.cpp +++ b/ext/jpge/jpge.cpp @@ -30,6 +30,7 @@ #include "jpge.h" +#include #include #include @@ -933,7 +934,6 @@ namespace jpge { } // Higher level wrappers/examples (optional). -#include class cfile_stream : public output_stream { diff --git a/ext/libkirk/AES.c b/ext/libkirk/AES.c index c27ae01c61..89a942bcac 100644 --- a/ext/libkirk/AES.c +++ b/ext/libkirk/AES.c @@ -1313,7 +1313,7 @@ void AES_cbc_encrypt(AES_ctx *ctx, const u8 *src, u8 *dst, int size) { //step 1: copy block to dst memcpy(dst, src, 16); - //step 2: XOR with previous block + //step 2: XOR with previous block (if not the first block) if(i) xor_128(dst, block_buff, dst); //step 3: encrypt the block -> it land in block buffer AES_encrypt(ctx, dst, block_buff); diff --git a/ext/libkirk/amctrl.c b/ext/libkirk/amctrl.c index d144ca792c..3116c39725 100644 --- a/ext/libkirk/amctrl.c +++ b/ext/libkirk/amctrl.c @@ -608,7 +608,7 @@ PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey) u8 *fkey; int retv; - //DEBUG_LOG(HLE, "Open PGD ..."); + //DEBUG_LOG(Log::HLE, "Open PGD ..."); pgd = (PGD_DESC*)malloc(sizeof(PGD_DESC)); memset(pgd, 0, sizeof(PGD_DESC)); @@ -637,7 +637,7 @@ PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey) if(pgd_flag&1) fkey = (u8*)dnas_key1AA0; if(fkey==NULL){ - //ERROR_LOG(HLE, "pgd_open: invalid pgd_flag! %08x\n", pgd_flag); + //ERROR_LOG(Log::HLE, "pgd_open: invalid pgd_flag! %08x\n", pgd_flag); free(pgd); return NULL; } @@ -647,7 +647,7 @@ PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey) sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x80); retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x80, fkey); if(retv){ - //ERROR_LOG(HLE, "pgd_open: MAC_80 check failed!: %08x(%d)\n", retv, retv); + //ERROR_LOG(Log::HLE, "pgd_open: MAC_80 check failed!: %08x(%d)\n", retv, retv); free(pgd); return NULL; } @@ -659,7 +659,7 @@ PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey) // use given vkey retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x70, pgd_vkey); if(retv){ - //ERROR_LOG(HLE, "pgd_open: MAC_70 check failed!: %08x(%d)\n", retv, retv); + //ERROR_LOG(Log::HLE, "pgd_open: MAC_70 check failed!: %08x(%d)\n", retv, retv); free(pgd); return NULL; }else{ diff --git a/ext/libkirk/kirk_engine.c b/ext/libkirk/kirk_engine.c index 69a300a702..192f0bae1d 100644 --- a/ext/libkirk/kirk_engine.c +++ b/ext/libkirk/kirk_engine.c @@ -413,7 +413,7 @@ int kirk_CMD11(u8* outbuff, u8* inbuff, int size) // Generate an ECDSA Key pair // offset 0 = private key (0x14 len) // offset 0x14 = public key point (0x28 len) -int kirk_CMD12(u8 * outbuff, int outsize) { +int kirk_CMD12(u8 *outbuff, int outsize) { u8 k[0x15]; KIRK_CMD12_BUFFER * keypair = (KIRK_CMD12_BUFFER *) outbuff; @@ -442,25 +442,30 @@ int kirk_CMD13(u8 * outbuff, int outsize,u8 * inbuff, int insize) { return KIRK_OPERATION_SUCCESS; } -int kirk_CMD14(u8 * outbuff, int outsize) { +int kirk_CMD14(u8 *outbuff, int outsize) { u8 temp[0x104]; + // This was added to mollify valgrind. + memset(temp, 0xAA, sizeof(temp)); + KIRK_SHA1_HEADER *header = (KIRK_SHA1_HEADER *) temp; // Some randomly selected data for a "key" to add to each randomization - u8 key[0x10] = { 0xA7, 0x2E, 0x4C, 0xB6, 0xC3, 0x34, 0xDF, 0x85, 0x70, 0x01, 0x49, 0xFC, 0xC0, 0x87, 0xC4, 0x77 }; + static const u8 random_data[0x10] = { 0xA7, 0x2E, 0x4C, 0xB6, 0xC3, 0x34, 0xDF, 0x85, 0x70, 0x01, 0x49, 0xFC, 0xC0, 0x87, 0xC4, 0x77 }; u32 curtime; //if(outsize != 0x14) return KIRK_INVALID_SIZE; // Need real error code if(outsize <=0) return KIRK_OPERATION_SUCCESS; memcpy(temp+4, PRNG_DATA,0x14); // This uses the standard C time function for portability. - curtime=(u32)time(0); + curtime = (u32)time(0); temp[0x18] = curtime &0xFF; temp[0x19] = (curtime>>8) &0xFF; temp[0x1A] = (curtime>>16) &0xFF; temp[0x1B] = (curtime>>24) &0xFF; - memcpy(&temp[0x1C], key, 0x10); - //This leaves the remainder of the 0x100 bytes in temp to whatever remains on the stack + memcpy(&temp[0x1C], random_data, 0x10); + + // WARNING: These next two lines of comments are no longer accurate since I added the memset above. + // This leaves the remainder of the 0x100 bytes in temp to whatever remains on the stack // in an uninitialized state. This should add unpredicableness to the results as well header->data_size=0x100; kirk_CMD11(PRNG_DATA, temp, 0x104); @@ -666,10 +671,11 @@ int kirk_init() int kirk_init2(u8 * rnd_seed, u32 seed_size, u32 fuseid_90, u32 fuseid_94) { u8 temp[0x104]; + memset(temp, 0xAA, sizeof(temp)); KIRK_SHA1_HEADER *header = (KIRK_SHA1_HEADER *) temp; // Another randomly selected data for a "key" to add to each randomization - u8 key[0x10] = {0x07, 0xAB, 0xEF, 0xF8, 0x96, 0x8C, 0xF3, 0xD6, 0x14, 0xE0, 0xEB, 0xB2, 0x9D, 0x8B, 0x4E, 0x74}; + static const u8 key[0x10] = {0x07, 0xAB, 0xEF, 0xF8, 0x96, 0x8C, 0xF3, 0xD6, 0x14, 0xE0, 0xEB, 0xB2, 0x9D, 0x8B, 0x4E, 0x74}; u32 curtime; //Set PRNG_DATA initially, otherwise use what ever uninitialized data is in the buffer @@ -677,7 +683,8 @@ int kirk_init2(u8 * rnd_seed, u32 seed_size, u32 fuseid_90, u32 fuseid_94) { u8 * seedbuf; KIRK_SHA1_HEADER *seedheader; seedbuf=(u8*)malloc(seed_size+4); - seedheader= (KIRK_SHA1_HEADER *) seedbuf; + memset(seedbuf, 0, seed_size+4); + seedheader = (KIRK_SHA1_HEADER *) seedbuf; seedheader->data_size = seed_size; kirk_CMD11(PRNG_DATA, seedbuf, seed_size+4); free(seedbuf); diff --git a/ext/libpng17/CMakeLists.txt b/ext/libpng17/CMakeLists.txt index d2829cd3fe..6c155a686a 100644 --- a/ext/libpng17/CMakeLists.txt +++ b/ext/libpng17/CMakeLists.txt @@ -1,6 +1,7 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.8) +project(libpng17) -add_library(png17 +add_library(png17 STATIC pngconf.h pngdebug.h png.c @@ -23,4 +24,20 @@ add_library(png17 pngwio.c pngwrite.c pngwtran.c - pngwutil.c) + pngwutil.c +) + +# Add arm files for ARM processors +if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm(64)?|aarch64") + set (ARM_FILES arm/arm_init.c + ) + + # Check if it's 32 bit + if("${CMAKE_SIZEOF_VOID_P}" EQUAL 4) + list(APPEND ARM_FILES arm/filter_neon.S) + else() + list(APPEND ARM_FILES arm/filter_neon_intrinsics.c) + endif() + + target_sources(png17 PRIVATE ${ARM_FILES}) +endif() diff --git a/ext/minimp3/CMakeLists.txt b/ext/minimp3/CMakeLists.txt new file mode 100644 index 0000000000..4b347f3509 --- /dev/null +++ b/ext/minimp3/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required (VERSION 3.16) +project (minimp3) + +set(SRC_DIR .) + +# format +set(ALL_SOURCE_FILES + # rapi + ${SRC_DIR}/minimp3.cpp + ) + +add_library(minimp3 STATIC ${ALL_SOURCE_FILES}) diff --git a/ext/minimp3/minimp3.cpp b/ext/minimp3/minimp3.cpp new file mode 100644 index 0000000000..f4b41e0904 --- /dev/null +++ b/ext/minimp3/minimp3.cpp @@ -0,0 +1,11 @@ +// Gotta define it somewhere. +#define MINIMP3_IMPLEMENTATION +#define MINIMP3_NO_STDIO + +#ifdef _MSC_VER +#pragma warning(disable:4267) +#pragma warning(disable:4244) +#endif + +#include "minimp3.h" +#include "minimp3_ex.h" diff --git a/ext/minimp3/minimp3.h b/ext/minimp3/minimp3.h new file mode 100644 index 0000000000..3220ae1a85 --- /dev/null +++ b/ext/minimp3/minimp3.h @@ -0,0 +1,1865 @@ +#ifndef MINIMP3_H +#define MINIMP3_H +/* + https://github.com/lieff/minimp3 + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. + This software is distributed without any warranty. + See . +*/ +#include + +#define MINIMP3_MAX_SAMPLES_PER_FRAME (1152*2) + +typedef struct +{ + int frame_bytes, frame_offset, channels, hz, layer, bitrate_kbps; +} mp3dec_frame_info_t; + +typedef struct +{ + float mdct_overlap[2][9*32], qmf_state[15*2*32]; + int reserv, free_format_bytes; + unsigned char header[4], reserv_buf[511]; +} mp3dec_t; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void mp3dec_init(mp3dec_t *dec); +#ifndef MINIMP3_FLOAT_OUTPUT +typedef int16_t mp3d_sample_t; +#else /* MINIMP3_FLOAT_OUTPUT */ +typedef float mp3d_sample_t; +void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples); +#endif /* MINIMP3_FLOAT_OUTPUT */ +int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MINIMP3_H */ +#if defined(MINIMP3_IMPLEMENTATION) && !defined(_MINIMP3_IMPLEMENTATION_GUARD) +#define _MINIMP3_IMPLEMENTATION_GUARD + +#include +#include + +#define MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */ +#ifndef MAX_FRAME_SYNC_MATCHES +#define MAX_FRAME_SYNC_MATCHES 10 +#endif /* MAX_FRAME_SYNC_MATCHES */ + +#define MAX_L3_FRAME_PAYLOAD_BYTES MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */ + +#define MAX_BITRESERVOIR_BYTES 511 +#define SHORT_BLOCK_TYPE 2 +#define STOP_BLOCK_TYPE 3 +#define MODE_MONO 3 +#define MODE_JOINT_STEREO 1 +#define HDR_SIZE 4 +#define HDR_IS_MONO(h) (((h[3]) & 0xC0) == 0xC0) +#define HDR_IS_MS_STEREO(h) (((h[3]) & 0xE0) == 0x60) +#define HDR_IS_FREE_FORMAT(h) (((h[2]) & 0xF0) == 0) +#define HDR_IS_CRC(h) (!((h[1]) & 1)) +#define HDR_TEST_PADDING(h) ((h[2]) & 0x2) +#define HDR_TEST_MPEG1(h) ((h[1]) & 0x8) +#define HDR_TEST_NOT_MPEG25(h) ((h[1]) & 0x10) +#define HDR_TEST_I_STEREO(h) ((h[3]) & 0x10) +#define HDR_TEST_MS_STEREO(h) ((h[3]) & 0x20) +#define HDR_GET_STEREO_MODE(h) (((h[3]) >> 6) & 3) +#define HDR_GET_STEREO_MODE_EXT(h) (((h[3]) >> 4) & 3) +#define HDR_GET_LAYER(h) (((h[1]) >> 1) & 3) +#define HDR_GET_BITRATE(h) ((h[2]) >> 4) +#define HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3) +#define HDR_GET_MY_SAMPLE_RATE(h) (HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3) +#define HDR_IS_FRAME_576(h) ((h[1] & 14) == 2) +#define HDR_IS_LAYER_1(h) ((h[1] & 6) == 6) + +#define BITS_DEQUANTIZER_OUT -1 +#define MAX_SCF (255 + BITS_DEQUANTIZER_OUT*4 - 210) +#define MAX_SCFI ((MAX_SCF + 3) & ~3) + +#define MINIMP3_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define MINIMP3_MAX(a, b) ((a) < (b) ? (b) : (a)) + +#if !defined(MINIMP3_NO_SIMD) + +#if !defined(MINIMP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) +/* x64 always have SSE2, arm64 always have neon, no need for generic code */ +#define MINIMP3_ONLY_SIMD +#endif /* SIMD checks... */ + +#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) +#if defined(_MSC_VER) +#include +#endif /* defined(_MSC_VER) */ +#include +#define HAVE_SSE 1 +#define HAVE_SIMD 1 +#define VSTORE _mm_storeu_ps +#define VLD _mm_loadu_ps +#define VSET _mm_set1_ps +#define VADD _mm_add_ps +#define VSUB _mm_sub_ps +#define VMUL _mm_mul_ps +#define VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y)) +#define VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y)) +#define VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s)) +#define VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)) +typedef __m128 f4; +#if defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) +#define minimp3_cpuid __cpuid +#else /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ +static __inline__ __attribute__((always_inline)) void minimp3_cpuid(int CPUInfo[], const int InfoType) +{ +#if defined(__PIC__) + __asm__ __volatile__( +#if defined(__x86_64__) + "push %%rbx\n" + "cpuid\n" + "xchgl %%ebx, %1\n" + "pop %%rbx\n" +#else /* defined(__x86_64__) */ + "xchgl %%ebx, %1\n" + "cpuid\n" + "xchgl %%ebx, %1\n" +#endif /* defined(__x86_64__) */ + : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#else /* defined(__PIC__) */ + __asm__ __volatile__( + "cpuid" + : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#endif /* defined(__PIC__)*/ +} +#endif /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ +static int have_simd(void) +{ +#ifdef MINIMP3_ONLY_SIMD + return 1; +#else /* MINIMP3_ONLY_SIMD */ + static int g_have_simd; + int CPUInfo[4]; +#ifdef MINIMP3_TEST + static int g_counter; + if (g_counter++ > 100) + return 0; +#endif /* MINIMP3_TEST */ + if (g_have_simd) + goto end; + minimp3_cpuid(CPUInfo, 0); + g_have_simd = 1; + if (CPUInfo[0] > 0) + { + minimp3_cpuid(CPUInfo, 1); + g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; /* SSE2 */ + } +end: + return g_have_simd - 1; +#endif /* MINIMP3_ONLY_SIMD */ +} +#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) +#include +#define HAVE_SSE 0 +#define HAVE_SIMD 1 +#define VSTORE vst1q_f32 +#define VLD vld1q_f32 +#define VSET vmovq_n_f32 +#define VADD vaddq_f32 +#define VSUB vsubq_f32 +#define VMUL vmulq_f32 +#define VMAC(a, x, y) vmlaq_f32(a, x, y) +#define VMSB(a, x, y) vmlsq_f32(a, x, y) +#define VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) +#define VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) +typedef float32x4_t f4; +static int have_simd() +{ /* TODO: detect neon for !MINIMP3_ONLY_SIMD */ + return 1; +} +#else /* SIMD checks... */ +#define HAVE_SSE 0 +#define HAVE_SIMD 0 +#ifdef MINIMP3_ONLY_SIMD +#error MINIMP3_ONLY_SIMD used, but SSE/NEON not enabled +#endif /* MINIMP3_ONLY_SIMD */ +#endif /* SIMD checks... */ +#else /* !defined(MINIMP3_NO_SIMD) */ +#define HAVE_SIMD 0 +#endif /* !defined(MINIMP3_NO_SIMD) */ + +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) +#define HAVE_ARMV6 1 +static __inline__ __attribute__((always_inline)) int32_t minimp3_clip_int16_arm(int32_t a) +{ + int32_t x = 0; + __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} +#else +#define HAVE_ARMV6 0 +#endif + +typedef struct +{ + const uint8_t *buf; + int pos, limit; +} bs_t; + +typedef struct +{ + float scf[3*64]; + uint8_t total_bands, stereo_bands, bitalloc[64], scfcod[64]; +} L12_scale_info; + +typedef struct +{ + uint8_t tab_offset, code_tab_width, band_count; +} L12_subband_alloc_t; + +typedef struct +{ + const uint8_t *sfbtab; + uint16_t part_23_length, big_values, scalefac_compress; + uint8_t global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; + uint8_t table_select[3], region_count[3], subblock_gain[3]; + uint8_t preflag, scalefac_scale, count1_table, scfsi; +} L3_gr_info_t; + +typedef struct +{ + bs_t bs; + uint8_t maindata[MAX_BITRESERVOIR_BYTES + MAX_L3_FRAME_PAYLOAD_BYTES]; + L3_gr_info_t gr_info[4]; + float grbuf[2][576], scf[40], syn[18 + 15][2*32]; + uint8_t ist_pos[2][39]; +} mp3dec_scratch_t; + +static void bs_init(bs_t *bs, const uint8_t *data, int bytes) +{ + bs->buf = data; + bs->pos = 0; + bs->limit = bytes*8; +} + +static uint32_t get_bits(bs_t *bs, int n) +{ + uint32_t next, cache = 0, s = bs->pos & 7; + int shl = n + s; + const uint8_t *p = bs->buf + (bs->pos >> 3); + if ((bs->pos += n) > bs->limit) + return 0; + next = *p++ & (255 >> s); + while ((shl -= 8) > 0) + { + cache |= next << shl; + next = *p++; + } + return cache | (next >> -shl); +} + +static int hdr_valid(const uint8_t *h) +{ + return h[0] == 0xff && + ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) && + (HDR_GET_LAYER(h) != 0) && + (HDR_GET_BITRATE(h) != 15) && + (HDR_GET_SAMPLE_RATE(h) != 3); +} + +static int hdr_compare(const uint8_t *h1, const uint8_t *h2) +{ + return hdr_valid(h2) && + ((h1[1] ^ h2[1]) & 0xFE) == 0 && + ((h1[2] ^ h2[2]) & 0x0C) == 0 && + !(HDR_IS_FREE_FORMAT(h1) ^ HDR_IS_FREE_FORMAT(h2)); +} + +static unsigned hdr_bitrate_kbps(const uint8_t *h) +{ + static const uint8_t halfrate[2][3][15] = { + { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } }, + { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } }, + }; + return 2*halfrate[!!HDR_TEST_MPEG1(h)][HDR_GET_LAYER(h) - 1][HDR_GET_BITRATE(h)]; +} + +static unsigned hdr_sample_rate_hz(const uint8_t *h) +{ + static const unsigned g_hz[3] = { 44100, 48000, 32000 }; + return g_hz[HDR_GET_SAMPLE_RATE(h)] >> (int)!HDR_TEST_MPEG1(h) >> (int)!HDR_TEST_NOT_MPEG25(h); +} + +static unsigned hdr_frame_samples(const uint8_t *h) +{ + return HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)HDR_IS_FRAME_576(h)); +} + +static int hdr_frame_bytes(const uint8_t *h, int free_format_size) +{ + int frame_bytes = hdr_frame_samples(h)*hdr_bitrate_kbps(h)*125/hdr_sample_rate_hz(h); + if (HDR_IS_LAYER_1(h)) + { + frame_bytes &= ~3; /* slot align */ + } + return frame_bytes ? frame_bytes : free_format_size; +} + +static int hdr_padding(const uint8_t *h) +{ + return HDR_TEST_PADDING(h) ? (HDR_IS_LAYER_1(h) ? 4 : 1) : 0; +} + +#ifndef MINIMP3_ONLY_MP3 +static const L12_subband_alloc_t *L12_subband_alloc_table(const uint8_t *hdr, L12_scale_info *sci) +{ + const L12_subband_alloc_t *alloc; + int mode = HDR_GET_STEREO_MODE(hdr); + int nbands, stereo_bands = (mode == MODE_MONO) ? 0 : (mode == MODE_JOINT_STEREO) ? (HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32; + + if (HDR_IS_LAYER_1(hdr)) + { + static const L12_subband_alloc_t g_alloc_L1[] = { { 76, 4, 32 } }; + alloc = g_alloc_L1; + nbands = 32; + } else if (!HDR_TEST_MPEG1(hdr)) + { + static const L12_subband_alloc_t g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } }; + alloc = g_alloc_L2M2; + nbands = 30; + } else + { + static const L12_subband_alloc_t g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } }; + int sample_rate_idx = HDR_GET_SAMPLE_RATE(hdr); + unsigned kbps = hdr_bitrate_kbps(hdr) >> (int)(mode != MODE_MONO); + if (!kbps) /* free-format */ + { + kbps = 192; + } + + alloc = g_alloc_L2M1; + nbands = 27; + if (kbps < 56) + { + static const L12_subband_alloc_t g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } }; + alloc = g_alloc_L2M1_lowrate; + nbands = sample_rate_idx == 2 ? 12 : 8; + } else if (kbps >= 96 && sample_rate_idx != 1) + { + nbands = 30; + } + } + + sci->total_bands = (uint8_t)nbands; + sci->stereo_bands = (uint8_t)MINIMP3_MIN(stereo_bands, nbands); + + return alloc; +} + +static void L12_read_scalefactors(bs_t *bs, uint8_t *pba, uint8_t *scfcod, int bands, float *scf) +{ + static const float g_deq_L12[18*3] = { +#define DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x + DQ(3),DQ(7),DQ(15),DQ(31),DQ(63),DQ(127),DQ(255),DQ(511),DQ(1023),DQ(2047),DQ(4095),DQ(8191),DQ(16383),DQ(32767),DQ(65535),DQ(3),DQ(5),DQ(9) + }; + int i, m; + for (i = 0; i < bands; i++) + { + float s = 0; + int ba = *pba++; + int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0; + for (m = 4; m; m >>= 1) + { + if (mask & m) + { + int b = get_bits(bs, 6); + s = g_deq_L12[ba*3 - 6 + b % 3]*(1 << 21 >> b/3); + } + *scf++ = s; + } + } +} + +static void L12_read_scale_info(const uint8_t *hdr, bs_t *bs, L12_scale_info *sci) +{ + static const uint8_t g_bitalloc_code_tab[] = { + 0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16, + 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16, + 0,17,18, 3,19,4,5,16, + 0,17,18,16, + 0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15, + 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14, + 0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16 + }; + const L12_subband_alloc_t *subband_alloc = L12_subband_alloc_table(hdr, sci); + + int i, k = 0, ba_bits = 0; + const uint8_t *ba_code_tab = g_bitalloc_code_tab; + + for (i = 0; i < sci->total_bands; i++) + { + uint8_t ba; + if (i == k) + { + k += subband_alloc->band_count; + ba_bits = subband_alloc->code_tab_width; + ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset; + subband_alloc++; + } + ba = ba_code_tab[get_bits(bs, ba_bits)]; + sci->bitalloc[2*i] = ba; + if (i < sci->stereo_bands) + { + ba = ba_code_tab[get_bits(bs, ba_bits)]; + } + sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0; + } + + for (i = 0; i < 2*sci->total_bands; i++) + { + sci->scfcod[i] = sci->bitalloc[i] ? HDR_IS_LAYER_1(hdr) ? 2 : get_bits(bs, 2) : 6; + } + + L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf); + + for (i = sci->stereo_bands; i < sci->total_bands; i++) + { + sci->bitalloc[2*i + 1] = 0; + } +} + +static int L12_dequantize_granule(float *grbuf, bs_t *bs, L12_scale_info *sci, int group_size) +{ + int i, j, k, choff = 576; + for (j = 0; j < 4; j++) + { + float *dst = grbuf + group_size*j; + for (i = 0; i < 2*sci->total_bands; i++) + { + int ba = sci->bitalloc[i]; + if (ba != 0) + { + if (ba < 17) + { + int half = (1 << (ba - 1)) - 1; + for (k = 0; k < group_size; k++) + { + dst[k] = (float)((int)get_bits(bs, ba) - half); + } + } else + { + unsigned mod = (2 << (ba - 17)) + 1; /* 3, 5, 9 */ + unsigned code = get_bits(bs, mod + 2 - (mod >> 3)); /* 5, 7, 10 */ + for (k = 0; k < group_size; k++, code /= mod) + { + dst[k] = (float)((int)(code % mod - mod/2)); + } + } + } + dst += choff; + choff = 18 - choff; + } + } + return group_size*4; +} + +static void L12_apply_scf_384(L12_scale_info *sci, const float *scf, float *dst) +{ + int i, k; + memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); + for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) + { + for (k = 0; k < 12; k++) + { + dst[k + 0] *= scf[0]; + dst[k + 576] *= scf[3]; + } + } +} +#endif /* MINIMP3_ONLY_MP3 */ + +static int L3_read_side_info(bs_t *bs, L3_gr_info_t *gr, const uint8_t *hdr) +{ + static const uint8_t g_scf_long[8][23] = { + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 }, + { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 }, + { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 } + }; + static const uint8_t g_scf_short[8][40] = { + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 8,8,8,8,8,8,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } + }; + static const uint8_t g_scf_mixed[8][40] = { + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 12,12,12,4,4,4,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, + { 6,6,6,6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } + }; + + unsigned tables, scfsi = 0; + int main_data_begin, part_23_sum = 0; + int sr_idx = HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); + int gr_count = HDR_IS_MONO(hdr) ? 1 : 2; + + if (HDR_TEST_MPEG1(hdr)) + { + gr_count *= 2; + main_data_begin = get_bits(bs, 9); + scfsi = get_bits(bs, 7 + gr_count); + } else + { + main_data_begin = get_bits(bs, 8 + gr_count) >> gr_count; + } + + do + { + if (HDR_IS_MONO(hdr)) + { + scfsi <<= 4; + } + gr->part_23_length = (uint16_t)get_bits(bs, 12); + part_23_sum += gr->part_23_length; + gr->big_values = (uint16_t)get_bits(bs, 9); + if (gr->big_values > 288) + { + return -1; + } + gr->global_gain = (uint8_t)get_bits(bs, 8); + gr->scalefac_compress = (uint16_t)get_bits(bs, HDR_TEST_MPEG1(hdr) ? 4 : 9); + gr->sfbtab = g_scf_long[sr_idx]; + gr->n_long_sfb = 22; + gr->n_short_sfb = 0; + if (get_bits(bs, 1)) + { + gr->block_type = (uint8_t)get_bits(bs, 2); + if (!gr->block_type) + { + return -1; + } + gr->mixed_block_flag = (uint8_t)get_bits(bs, 1); + gr->region_count[0] = 7; + gr->region_count[1] = 255; + if (gr->block_type == SHORT_BLOCK_TYPE) + { + scfsi &= 0x0F0F; + if (!gr->mixed_block_flag) + { + gr->region_count[0] = 8; + gr->sfbtab = g_scf_short[sr_idx]; + gr->n_long_sfb = 0; + gr->n_short_sfb = 39; + } else + { + gr->sfbtab = g_scf_mixed[sr_idx]; + gr->n_long_sfb = HDR_TEST_MPEG1(hdr) ? 8 : 6; + gr->n_short_sfb = 30; + } + } + tables = get_bits(bs, 10); + tables <<= 5; + gr->subblock_gain[0] = (uint8_t)get_bits(bs, 3); + gr->subblock_gain[1] = (uint8_t)get_bits(bs, 3); + gr->subblock_gain[2] = (uint8_t)get_bits(bs, 3); + } else + { + gr->block_type = 0; + gr->mixed_block_flag = 0; + tables = get_bits(bs, 15); + gr->region_count[0] = (uint8_t)get_bits(bs, 4); + gr->region_count[1] = (uint8_t)get_bits(bs, 3); + gr->region_count[2] = 255; + } + gr->table_select[0] = (uint8_t)(tables >> 10); + gr->table_select[1] = (uint8_t)((tables >> 5) & 31); + gr->table_select[2] = (uint8_t)((tables) & 31); + gr->preflag = HDR_TEST_MPEG1(hdr) ? get_bits(bs, 1) : (gr->scalefac_compress >= 500); + gr->scalefac_scale = (uint8_t)get_bits(bs, 1); + gr->count1_table = (uint8_t)get_bits(bs, 1); + gr->scfsi = (uint8_t)((scfsi >> 12) & 15); + scfsi <<= 4; + gr++; + } while(--gr_count); + + if (part_23_sum + bs->pos > bs->limit + main_data_begin*8) + { + return -1; + } + + return main_data_begin; +} + +static void L3_read_scalefactors(uint8_t *scf, uint8_t *ist_pos, const uint8_t *scf_size, const uint8_t *scf_count, bs_t *bitbuf, int scfsi) +{ + int i, k; + for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2) + { + int cnt = scf_count[i]; + if (scfsi & 8) + { + memcpy(scf, ist_pos, cnt); + } else + { + int bits = scf_size[i]; + if (!bits) + { + memset(scf, 0, cnt); + memset(ist_pos, 0, cnt); + } else + { + int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; + for (k = 0; k < cnt; k++) + { + int s = get_bits(bitbuf, bits); + ist_pos[k] = (s == max_scf ? -1 : s); + scf[k] = s; + } + } + } + ist_pos += cnt; + scf += cnt; + } + scf[0] = scf[1] = scf[2] = 0; +} + +static float L3_ldexp_q2(float y, int exp_q2) +{ + static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f }; + int e; + do + { + e = MINIMP3_MIN(30*4, exp_q2); + y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2)); + } while ((exp_q2 -= e) > 0); + return y; +} + +static void L3_decode_scalefactors(const uint8_t *hdr, uint8_t *ist_pos, bs_t *bs, const L3_gr_info_t *gr, float *scf, int ch) +{ + static const uint8_t g_scf_partitions[3][28] = { + { 6,5,5, 5,6,5,5,5,6,5, 7,3,11,10,0,0, 7, 7, 7,0, 6, 6,6,3, 8, 8,5,0 }, + { 8,9,6,12,6,9,9,9,6,9,12,6,15,18,0,0, 6,15,12,0, 6,12,9,6, 6,18,9,0 }, + { 9,9,6,12,9,9,9,9,9,9,12,6,18,18,0,0,12,12,12,0,12, 9,9,6,15,12,9,0 } + }; + const uint8_t *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb]; + uint8_t scf_size[4], iscf[40]; + int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi; + float gain; + + if (HDR_TEST_MPEG1(hdr)) + { + static const uint8_t g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 }; + int part = g_scfc_decode[gr->scalefac_compress]; + scf_size[1] = scf_size[0] = (uint8_t)(part >> 2); + scf_size[3] = scf_size[2] = (uint8_t)(part & 3); + } else + { + static const uint8_t g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 }; + int k, modprod, sfc, ist = HDR_TEST_I_STEREO(hdr) && ch; + sfc = gr->scalefac_compress >> ist; + for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4) + { + for (modprod = 1, i = 3; i >= 0; i--) + { + scf_size[i] = (uint8_t)(sfc / modprod % g_mod[k + i]); + modprod *= g_mod[k + i]; + } + } + scf_partition += k; + scfsi = -16; + } + L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi); + + if (gr->n_short_sfb) + { + int sh = 3 - scf_shift; + for (i = 0; i < gr->n_short_sfb; i += 3) + { + iscf[gr->n_long_sfb + i + 0] += gr->subblock_gain[0] << sh; + iscf[gr->n_long_sfb + i + 1] += gr->subblock_gain[1] << sh; + iscf[gr->n_long_sfb + i + 2] += gr->subblock_gain[2] << sh; + } + } else if (gr->preflag) + { + static const uint8_t g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 }; + for (i = 0; i < 10; i++) + { + iscf[11 + i] += g_preamp[i]; + } + } + + gain_exp = gr->global_gain + BITS_DEQUANTIZER_OUT*4 - 210 - (HDR_IS_MS_STEREO(hdr) ? 2 : 0); + gain = L3_ldexp_q2(1 << (MAX_SCFI/4), MAX_SCFI - gain_exp); + for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++) + { + scf[i] = L3_ldexp_q2(gain, iscf[i] << scf_shift); + } +} + +static const float g_pow43[129 + 16] = { + 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, + 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f +}; + +static float L3_pow_43(int x) +{ + float frac; + int sign, mult = 256; + + if (x < 129) + { + return g_pow43[16 + x]; + } + + if (x < 1024) + { + mult = 16; + x <<= 3; + } + + sign = 2*x & 64; + frac = (float)((x & 63) - sign) / ((x & ~63) + sign); + return g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; +} + +static void L3_huffman(float *dst, bs_t *bs, const L3_gr_info_t *gr_info, const float *scf, int layer3gr_limit) +{ + static const int16_t tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256, + -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288, + -255,1313,1298,1282,769,769,769,769,529,529,529,529,529,529,529,529,528,528,528,528,528,528,528,528,512,512,512,512,512,512,512,512,290,288, + -253,-318,-351,-367,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258, + -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259, + -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258, + -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258, + -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259, + -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258, + -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290, + -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259, + -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258, + -250,-1179,-1579,-1836,-1996,-2124,-2253,-2333,-2413,-2477,-2542,-2574,-2607,-2622,-2655,1314,1313,1298,1312,1282,785,785,785,785,1040,1040,1025,1025,768,768,768,768,-766,-798,-830,-862,-895,-911,-927,-943,-959,-975,-991,-1007,-1023,-1039,-1055,-1070,1724,1647,-1103,-1119,1631,1767,1662,1738,1708,1723,-1135,1780,1615,1779,1599,1677,1646,1778,1583,-1151,1777,1567,1737,1692,1765,1722,1707,1630,1751,1661,1764,1614,1736,1676,1763,1750,1645,1598,1721,1691,1762,1706,1582,1761,1566,-1167,1749,1629,767,766,751,765,494,494,735,764,719,749,734,763,447,447,748,718,477,506,431,491,446,476,461,505,415,430,475,445,504,399,460,489,414,503,383,474,429,459,502,502,746,752,488,398,501,473,413,472,486,271,480,270,-1439,-1455,1357,-1471,-1487,-1503,1341,1325,-1519,1489,1463,1403,1309,-1535,1372,1448,1418,1476,1356,1462,1387,-1551,1475,1340,1447,1402,1386,-1567,1068,1068,1474,1461,455,380,468,440,395,425,410,454,364,467,466,464,453,269,409,448,268,432,1371,1473,1432,1417,1308,1460,1355,1446,1459,1431,1083,1083,1401,1416,1458,1445,1067,1067,1370,1457,1051,1051,1291,1430,1385,1444,1354,1415,1400,1443,1082,1082,1173,1113,1186,1066,1185,1050,-1967,1158,1128,1172,1097,1171,1081,-1983,1157,1112,416,266,375,400,1170,1142,1127,1065,793,793,1169,1033,1156,1096,1141,1111,1155,1080,1126,1140,898,898,808,808,897,897,792,792,1095,1152,1032,1125,1110,1139,1079,1124,882,807,838,881,853,791,-2319,867,368,263,822,852,837,866,806,865,-2399,851,352,262,534,534,821,836,594,594,549,549,593,593,533,533,848,773,579,579,564,578,548,563,276,276,577,576,306,291,516,560,305,305,275,259, + -251,-892,-2058,-2620,-2828,-2957,-3023,-3039,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,-559,1530,-575,-591,1528,1527,1407,1526,1391,1023,1023,1023,1023,1525,1375,1268,1268,1103,1103,1087,1087,1039,1039,1523,-604,815,815,815,815,510,495,509,479,508,463,507,447,431,505,415,399,-734,-782,1262,-815,1259,1244,-831,1258,1228,-847,-863,1196,-879,1253,987,987,748,-767,493,493,462,477,414,414,686,669,478,446,461,445,474,429,487,458,412,471,1266,1264,1009,1009,799,799,-1019,-1276,-1452,-1581,-1677,-1757,-1821,-1886,-1933,-1997,1257,1257,1483,1468,1512,1422,1497,1406,1467,1496,1421,1510,1134,1134,1225,1225,1466,1451,1374,1405,1252,1252,1358,1480,1164,1164,1251,1251,1238,1238,1389,1465,-1407,1054,1101,-1423,1207,-1439,830,830,1248,1038,1237,1117,1223,1148,1236,1208,411,426,395,410,379,269,1193,1222,1132,1235,1221,1116,976,976,1192,1162,1177,1220,1131,1191,963,963,-1647,961,780,-1663,558,558,994,993,437,408,393,407,829,978,813,797,947,-1743,721,721,377,392,844,950,828,890,706,706,812,859,796,960,948,843,934,874,571,571,-1919,690,555,689,421,346,539,539,944,779,918,873,932,842,903,888,570,570,931,917,674,674,-2575,1562,-2591,1609,-2607,1654,1322,1322,1441,1441,1696,1546,1683,1593,1669,1624,1426,1426,1321,1321,1639,1680,1425,1425,1305,1305,1545,1668,1608,1623,1667,1592,1638,1666,1320,1320,1652,1607,1409,1409,1304,1304,1288,1288,1664,1637,1395,1395,1335,1335,1622,1636,1394,1394,1319,1319,1606,1621,1392,1392,1137,1137,1137,1137,345,390,360,375,404,373,1047,-2751,-2767,-2783,1062,1121,1046,-2799,1077,-2815,1106,1061,789,789,1105,1104,263,355,310,340,325,354,352,262,339,324,1091,1076,1029,1090,1060,1075,833,833,788,788,1088,1028,818,818,803,803,561,561,531,531,816,771,546,546,289,274,288,258, + -253,-317,-381,-446,-478,-509,1279,1279,-811,-1179,-1451,-1756,-1900,-2028,-2189,-2253,-2333,-2414,-2445,-2511,-2526,1313,1298,-2559,1041,1041,1040,1040,1025,1025,1024,1024,1022,1007,1021,991,1020,975,1019,959,687,687,1018,1017,671,671,655,655,1016,1015,639,639,758,758,623,623,757,607,756,591,755,575,754,559,543,543,1009,783,-575,-621,-685,-749,496,-590,750,749,734,748,974,989,1003,958,988,973,1002,942,987,957,972,1001,926,986,941,971,956,1000,910,985,925,999,894,970,-1071,-1087,-1102,1390,-1135,1436,1509,1451,1374,-1151,1405,1358,1480,1420,-1167,1507,1494,1389,1342,1465,1435,1450,1326,1505,1310,1493,1373,1479,1404,1492,1464,1419,428,443,472,397,736,526,464,464,486,457,442,471,484,482,1357,1449,1434,1478,1388,1491,1341,1490,1325,1489,1463,1403,1309,1477,1372,1448,1418,1433,1476,1356,1462,1387,-1439,1475,1340,1447,1402,1474,1324,1461,1371,1473,269,448,1432,1417,1308,1460,-1711,1459,-1727,1441,1099,1099,1446,1386,1431,1401,-1743,1289,1083,1083,1160,1160,1458,1445,1067,1067,1370,1457,1307,1430,1129,1129,1098,1098,268,432,267,416,266,400,-1887,1144,1187,1082,1173,1113,1186,1066,1050,1158,1128,1143,1172,1097,1171,1081,420,391,1157,1112,1170,1142,1127,1065,1169,1049,1156,1096,1141,1111,1155,1080,1126,1154,1064,1153,1140,1095,1048,-2159,1125,1110,1137,-2175,823,823,1139,1138,807,807,384,264,368,263,868,838,853,791,867,822,852,837,866,806,865,790,-2319,851,821,836,352,262,850,805,849,-2399,533,533,835,820,336,261,578,548,563,577,532,532,832,772,562,562,547,547,305,275,560,515,290,290,288,258 }; + static const uint8_t tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205 }; + static const uint8_t tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 }; + static const int16_t tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; + static const uint8_t g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; + +#define PEEK_BITS(n) (bs_cache >> (32 - n)) +#define FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } +#define CHECK_BITS while (bs_sh >= 0) { bs_cache |= (uint32_t)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } +#define BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) + + float one = 0.0f; + int ireg = 0, big_val_cnt = gr_info->big_values; + const uint8_t *sfb = gr_info->sfbtab; + const uint8_t *bs_next_ptr = bs->buf + bs->pos/8; + uint32_t bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7); + int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8; + bs_next_ptr += 4; + + while (big_val_cnt > 0) + { + int tab_num = gr_info->table_select[ireg]; + int sfb_cnt = gr_info->region_count[ireg++]; + const int16_t *codebook = tabs + tabindex[tab_num]; + int linbits = g_linbits[tab_num]; + if (linbits) + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[PEEK_BITS(w)]; + while (leaf < 0) + { + FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; + } + FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + if (lsb == 15) + { + lsb += PEEK_BITS(linbits); + FLUSH_BITS(linbits); + CHECK_BITS; + *dst = one*L3_pow_43(lsb)*((int32_t)bs_cache < 0 ? -1: 1); + } else + { + *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + } + FLUSH_BITS(lsb ? 1 : 0); + } + CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } else + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[PEEK_BITS(w)]; + while (leaf < 0) + { + FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; + } + FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + FLUSH_BITS(lsb ? 1 : 0); + } + CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } + } + + for (np = 1 - big_val_cnt;; dst += 4) + { + const uint8_t *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32; + int leaf = codebook_count1[PEEK_BITS(4)]; + if (!(leaf & 8)) + { + leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))]; + } + FLUSH_BITS(leaf & 7); + if (BSPOS > layer3gr_limit) + { + break; + } +#define RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; } +#define DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((int32_t)bs_cache < 0) ? -one : one; FLUSH_BITS(1) } + RELOAD_SCALEFACTOR; + DEQ_COUNT1(0); + DEQ_COUNT1(1); + RELOAD_SCALEFACTOR; + DEQ_COUNT1(2); + DEQ_COUNT1(3); + CHECK_BITS; + } + + bs->pos = layer3gr_limit; +} + +static void L3_midside_stereo(float *left, int n) +{ + int i = 0; + float *right = left + 576; +#if HAVE_SIMD + if (have_simd()) + { + for (; i < n - 3; i += 4) + { + f4 vl = VLD(left + i); + f4 vr = VLD(right + i); + VSTORE(left + i, VADD(vl, vr)); + VSTORE(right + i, VSUB(vl, vr)); + } +#ifdef __GNUC__ + /* Workaround for spurious -Waggressive-loop-optimizations warning from gcc. + * For more info see: https://github.com/lieff/minimp3/issues/88 + */ + if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0) + return; +#endif + } +#endif /* HAVE_SIMD */ + for (; i < n; i++) + { + float a = left[i]; + float b = right[i]; + left[i] = a + b; + right[i] = a - b; + } +} + +static void L3_intensity_stereo_band(float *left, int n, float kl, float kr) +{ + int i; + for (i = 0; i < n; i++) + { + left[i + 576] = left[i]*kr; + left[i] = left[i]*kl; + } +} + +static void L3_stereo_top_band(const float *right, const uint8_t *sfb, int nbands, int max_band[3]) +{ + int i, k; + + max_band[0] = max_band[1] = max_band[2] = -1; + + for (i = 0; i < nbands; i++) + { + for (k = 0; k < sfb[i]; k += 2) + { + if (right[k] != 0 || right[k + 1] != 0) + { + max_band[i % 3] = i; + break; + } + } + right += sfb[i]; + } +} + +static void L3_stereo_process(float *left, const uint8_t *ist_pos, const uint8_t *sfb, const uint8_t *hdr, int max_band[3], int mpeg2_sh) +{ + static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 }; + unsigned i, max_pos = HDR_TEST_MPEG1(hdr) ? 7 : 64; + + for (i = 0; sfb[i]; i++) + { + unsigned ipos = ist_pos[i]; + if ((int)i > max_band[i % 3] && ipos < max_pos) + { + float kl, kr, s = HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1; + if (HDR_TEST_MPEG1(hdr)) + { + kl = g_pan[2*ipos]; + kr = g_pan[2*ipos + 1]; + } else + { + kl = 1; + kr = L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh); + if (ipos & 1) + { + kl = kr; + kr = 1; + } + } + L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s); + } else if (HDR_TEST_MS_STEREO(hdr)) + { + L3_midside_stereo(left, sfb[i]); + } + left += sfb[i]; + } +} + +static void L3_intensity_stereo(float *left, uint8_t *ist_pos, const L3_gr_info_t *gr, const uint8_t *hdr) +{ + int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb; + int i, max_blocks = gr->n_short_sfb ? 3 : 1; + + L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band); + if (gr->n_long_sfb) + { + max_band[0] = max_band[1] = max_band[2] = MINIMP3_MAX(MINIMP3_MAX(max_band[0], max_band[1]), max_band[2]); + } + for (i = 0; i < max_blocks; i++) + { + int default_pos = HDR_TEST_MPEG1(hdr) ? 3 : 0; + int itop = n_sfb - max_blocks + i; + int prev = itop - max_blocks; + ist_pos[itop] = max_band[i] >= prev ? default_pos : ist_pos[prev]; + } + L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1); +} + +static void L3_reorder(float *grbuf, float *scratch, const uint8_t *sfb) +{ + int i, len; + float *src = grbuf, *dst = scratch; + + for (;0 != (len = *sfb); sfb += 3, src += 2*len) + { + for (i = 0; i < len; i++, src++) + { + *dst++ = src[0*len]; + *dst++ = src[1*len]; + *dst++ = src[2*len]; + } + } + memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); +} + +static void L3_antialias(float *grbuf, int nbands) +{ + static const float g_aa[2][8] = { + {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f}, + {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f} + }; + + for (; nbands > 0; nbands--, grbuf += 18) + { + int i = 0; +#if HAVE_SIMD + if (have_simd()) for (; i < 8; i += 4) + { + f4 vu = VLD(grbuf + 18 + i); + f4 vd = VLD(grbuf + 14 - i); + f4 vc0 = VLD(g_aa[0] + i); + f4 vc1 = VLD(g_aa[1] + i); + vd = VREV(vd); + VSTORE(grbuf + 18 + i, VSUB(VMUL(vu, vc0), VMUL(vd, vc1))); + vd = VADD(VMUL(vu, vc1), VMUL(vd, vc0)); + VSTORE(grbuf + 14 - i, VREV(vd)); + } +#endif /* HAVE_SIMD */ +#ifndef MINIMP3_ONLY_SIMD + for(; i < 8; i++) + { + float u = grbuf[18 + i]; + float d = grbuf[17 - i]; + grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i]; + grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i]; + } +#endif /* MINIMP3_ONLY_SIMD */ + } +} + +static void L3_dct3_9(float *y) +{ + float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4; + + s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8]; + t0 = s0 + s6*0.5f; + s0 -= s6; + t4 = (s4 + s2)*0.93969262f; + t2 = (s8 + s2)*0.76604444f; + s6 = (s4 - s8)*0.17364818f; + s4 += s8 - s2; + + s2 = s0 - s4*0.5f; + y[4] = s4 + s0; + s8 = t0 - t2 + s6; + s0 = t0 - t4 + t2; + s4 = t0 + t4 - s6; + + s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7]; + + s3 *= 0.86602540f; + t0 = (s5 + s1)*0.98480775f; + t4 = (s5 - s7)*0.34202014f; + t2 = (s1 + s7)*0.64278761f; + s1 = (s1 - s5 - s7)*0.86602540f; + + s5 = t0 - s3 - t2; + s7 = t4 - s3 - t0; + s3 = t4 + s3 - t2; + + y[0] = s4 - s7; + y[1] = s2 + s1; + y[2] = s0 - s3; + y[3] = s8 + s5; + y[5] = s8 - s5; + y[6] = s0 + s3; + y[7] = s2 - s1; + y[8] = s4 + s7; +} + +static void L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands) +{ + int i, j; + static const float g_twid9[18] = { + 0.73727734f,0.79335334f,0.84339145f,0.88701083f,0.92387953f,0.95371695f,0.97629601f,0.99144486f,0.99904822f,0.67559021f,0.60876143f,0.53729961f,0.46174861f,0.38268343f,0.30070580f,0.21643961f,0.13052619f,0.04361938f + }; + + for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9) + { + float co[9], si[9]; + co[0] = -grbuf[0]; + si[0] = grbuf[17]; + for (i = 0; i < 4; i++) + { + si[8 - 2*i] = grbuf[4*i + 1] - grbuf[4*i + 2]; + co[1 + 2*i] = grbuf[4*i + 1] + grbuf[4*i + 2]; + si[7 - 2*i] = grbuf[4*i + 4] - grbuf[4*i + 3]; + co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]); + } + L3_dct3_9(co); + L3_dct3_9(si); + + si[1] = -si[1]; + si[3] = -si[3]; + si[5] = -si[5]; + si[7] = -si[7]; + + i = 0; + +#if HAVE_SIMD + if (have_simd()) for (; i < 8; i += 4) + { + f4 vovl = VLD(overlap + i); + f4 vc = VLD(co + i); + f4 vs = VLD(si + i); + f4 vr0 = VLD(g_twid9 + i); + f4 vr1 = VLD(g_twid9 + 9 + i); + f4 vw0 = VLD(window + i); + f4 vw1 = VLD(window + 9 + i); + f4 vsum = VADD(VMUL(vc, vr1), VMUL(vs, vr0)); + VSTORE(overlap + i, VSUB(VMUL(vc, vr0), VMUL(vs, vr1))); + VSTORE(grbuf + i, VSUB(VMUL(vovl, vw0), VMUL(vsum, vw1))); + vsum = VADD(VMUL(vovl, vw1), VMUL(vsum, vw0)); + VSTORE(grbuf + 14 - i, VREV(vsum)); + } +#endif /* HAVE_SIMD */ + for (; i < 9; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i]; + overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i]; + grbuf[i] = ovl*window[0 + i] - sum*window[9 + i]; + grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i]; + } + } +} + +static void L3_idct3(float x0, float x1, float x2, float *dst) +{ + float m1 = x1*0.86602540f; + float a1 = x0 - x2*0.5f; + dst[1] = x0 + x2; + dst[0] = a1 + m1; + dst[2] = a1 - m1; +} + +static void L3_imdct12(float *x, float *dst, float *overlap) +{ + static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f }; + float co[3], si[3]; + int i; + + L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co); + L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si); + si[1] = -si[1]; + + for (i = 0; i < 3; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i]; + overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i]; + dst[i] = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i]; + dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i]; + } +} + +static void L3_imdct_short(float *grbuf, float *overlap, int nbands) +{ + for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) + { + float tmp[18]; + memcpy(tmp, grbuf, sizeof(tmp)); + memcpy(grbuf, overlap, 6*sizeof(float)); + L3_imdct12(tmp, grbuf + 6, overlap + 6); + L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); + L3_imdct12(tmp + 2, overlap, overlap + 6); + } +} + +static void L3_change_sign(float *grbuf) +{ + int b, i; + for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36) + for (i = 1; i < 18; i += 2) + grbuf[i] = -grbuf[i]; +} + +static void L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands) +{ + static const float g_mdct_window[2][18] = { + { 0.99904822f,0.99144486f,0.97629601f,0.95371695f,0.92387953f,0.88701083f,0.84339145f,0.79335334f,0.73727734f,0.04361938f,0.13052619f,0.21643961f,0.30070580f,0.38268343f,0.46174861f,0.53729961f,0.60876143f,0.67559021f }, + { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f } + }; + if (n_long_bands) + { + L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands); + grbuf += 18*n_long_bands; + overlap += 9*n_long_bands; + } + if (block_type == SHORT_BLOCK_TYPE) + L3_imdct_short(grbuf, overlap, 32 - n_long_bands); + else + L3_imdct36(grbuf, overlap, g_mdct_window[block_type == STOP_BLOCK_TYPE], 32 - n_long_bands); +} + +static void L3_save_reservoir(mp3dec_t *h, mp3dec_scratch_t *s) +{ + int pos = (s->bs.pos + 7)/8u; + int remains = s->bs.limit/8u - pos; + if (remains > MAX_BITRESERVOIR_BYTES) + { + pos += remains - MAX_BITRESERVOIR_BYTES; + remains = MAX_BITRESERVOIR_BYTES; + } + if (remains > 0) + { + memmove(h->reserv_buf, s->maindata + pos, remains); + } + h->reserv = remains; +} + +static int L3_restore_reservoir(mp3dec_t *h, bs_t *bs, mp3dec_scratch_t *s, int main_data_begin) +{ + int frame_bytes = (bs->limit - bs->pos)/8; + int bytes_have = MINIMP3_MIN(h->reserv, main_data_begin); + memcpy(s->maindata, h->reserv_buf + MINIMP3_MAX(0, h->reserv - main_data_begin), MINIMP3_MIN(h->reserv, main_data_begin)); + memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); + bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); + return h->reserv >= main_data_begin; +} + +static void L3_decode(mp3dec_t *h, mp3dec_scratch_t *s, L3_gr_info_t *gr_info, int nch) +{ + int ch; + + for (ch = 0; ch < nch; ch++) + { + int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length; + L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch); + L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit); + } + + if (HDR_TEST_I_STEREO(h->header)) + { + L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header); + } else if (HDR_IS_MS_STEREO(h->header)) + { + L3_midside_stereo(s->grbuf[0], 576); + } + + for (ch = 0; ch < nch; ch++, gr_info++) + { + int aa_bands = 31; + int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(HDR_GET_MY_SAMPLE_RATE(h->header) == 2); + + if (gr_info->n_short_sfb) + { + aa_bands = n_long_bands - 1; + L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb); + } + + L3_antialias(s->grbuf[ch], aa_bands); + L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands); + L3_change_sign(s->grbuf[ch]); + } +} + +static void mp3d_DCT_II(float *grbuf, int n) +{ + static const float g_sec[24] = { + 10.19000816f,0.50060302f,0.50241929f,3.40760851f,0.50547093f,0.52249861f,2.05778098f,0.51544732f,0.56694406f,1.48416460f,0.53104258f,0.64682180f,1.16943991f,0.55310392f,0.78815460f,0.97256821f,0.58293498f,1.06067765f,0.83934963f,0.62250412f,1.72244716f,0.74453628f,0.67480832f,5.10114861f + }; + int i, k = 0; +#if HAVE_SIMD + if (have_simd()) for (; k < n; k += 4) + { + f4 t[4][8], *x; + float *y = grbuf + k; + + for (x = t[0], i = 0; i < 8; i++, x++) + { + f4 x0 = VLD(&y[i*18]); + f4 x1 = VLD(&y[(15 - i)*18]); + f4 x2 = VLD(&y[(16 + i)*18]); + f4 x3 = VLD(&y[(31 - i)*18]); + f4 t0 = VADD(x0, x3); + f4 t1 = VADD(x1, x2); + f4 t2 = VMUL_S(VSUB(x1, x2), g_sec[3*i + 0]); + f4 t3 = VMUL_S(VSUB(x0, x3), g_sec[3*i + 1]); + x[0] = VADD(t0, t1); + x[8] = VMUL_S(VSUB(t0, t1), g_sec[3*i + 2]); + x[16] = VADD(t3, t2); + x[24] = VMUL_S(VSUB(t3, t2), g_sec[3*i + 2]); + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = VSUB(x0, x7); x0 = VADD(x0, x7); + x7 = VSUB(x1, x6); x1 = VADD(x1, x6); + x6 = VSUB(x2, x5); x2 = VADD(x2, x5); + x5 = VSUB(x3, x4); x3 = VADD(x3, x4); + x4 = VSUB(x0, x3); x0 = VADD(x0, x3); + x3 = VSUB(x1, x2); x1 = VADD(x1, x2); + x[0] = VADD(x0, x1); + x[4] = VMUL_S(VSUB(x0, x1), 0.70710677f); + x5 = VADD(x5, x6); + x6 = VMUL_S(VADD(x6, x7), 0.70710677f); + x7 = VADD(x7, xt); + x3 = VMUL_S(VADD(x3, x4), 0.70710677f); + x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); /* rotate by PI/8 */ + x7 = VADD(x7, VMUL_S(x5, 0.382683432f)); + x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); + x0 = VSUB(xt, x6); xt = VADD(xt, x6); + x[1] = VMUL_S(VADD(xt, x7), 0.50979561f); + x[2] = VMUL_S(VADD(x4, x3), 0.54119611f); + x[3] = VMUL_S(VSUB(x0, x5), 0.60134488f); + x[5] = VMUL_S(VADD(x0, x5), 0.89997619f); + x[6] = VMUL_S(VSUB(x4, x3), 1.30656302f); + x[7] = VMUL_S(VSUB(xt, x7), 2.56291556f); + } + + if (k > n - 3) + { +#if HAVE_SSE +#define VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) +#else /* HAVE_SSE */ +#define VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v)) +#endif /* HAVE_SSE */ + for (i = 0; i < 7; i++, y += 4*18) + { + f4 s = VADD(t[3][i], t[3][i + 1]); + VSAVE2(0, t[0][i]); + VSAVE2(1, VADD(t[2][i], s)); + VSAVE2(2, VADD(t[1][i], t[1][i + 1])); + VSAVE2(3, VADD(t[2][1 + i], s)); + } + VSAVE2(0, t[0][7]); + VSAVE2(1, VADD(t[2][7], t[3][7])); + VSAVE2(2, t[1][7]); + VSAVE2(3, t[3][7]); + } else + { +#define VSAVE4(i, v) VSTORE(&y[i*18], v) + for (i = 0; i < 7; i++, y += 4*18) + { + f4 s = VADD(t[3][i], t[3][i + 1]); + VSAVE4(0, t[0][i]); + VSAVE4(1, VADD(t[2][i], s)); + VSAVE4(2, VADD(t[1][i], t[1][i + 1])); + VSAVE4(3, VADD(t[2][1 + i], s)); + } + VSAVE4(0, t[0][7]); + VSAVE4(1, VADD(t[2][7], t[3][7])); + VSAVE4(2, t[1][7]); + VSAVE4(3, t[3][7]); + } + } else +#endif /* HAVE_SIMD */ +#ifdef MINIMP3_ONLY_SIMD + {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ +#else /* MINIMP3_ONLY_SIMD */ + for (; k < n; k++) + { + float t[4][8], *x, *y = grbuf + k; + + for (x = t[0], i = 0; i < 8; i++, x++) + { + float x0 = y[i*18]; + float x1 = y[(15 - i)*18]; + float x2 = y[(16 + i)*18]; + float x3 = y[(31 - i)*18]; + float t0 = x0 + x3; + float t1 = x1 + x2; + float t2 = (x1 - x2)*g_sec[3*i + 0]; + float t3 = (x0 - x3)*g_sec[3*i + 1]; + x[0] = t0 + t1; + x[8] = (t0 - t1)*g_sec[3*i + 2]; + x[16] = t3 + t2; + x[24] = (t3 - t2)*g_sec[3*i + 2]; + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + float x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = x0 - x7; x0 += x7; + x7 = x1 - x6; x1 += x6; + x6 = x2 - x5; x2 += x5; + x5 = x3 - x4; x3 += x4; + x4 = x0 - x3; x0 += x3; + x3 = x1 - x2; x1 += x2; + x[0] = x0 + x1; + x[4] = (x0 - x1)*0.70710677f; + x5 = x5 + x6; + x6 = (x6 + x7)*0.70710677f; + x7 = x7 + xt; + x3 = (x3 + x4)*0.70710677f; + x5 -= x7*0.198912367f; /* rotate by PI/8 */ + x7 += x5*0.382683432f; + x5 -= x7*0.198912367f; + x0 = xt - x6; xt += x6; + x[1] = (xt + x7)*0.50979561f; + x[2] = (x4 + x3)*0.54119611f; + x[3] = (x0 - x5)*0.60134488f; + x[5] = (x0 + x5)*0.89997619f; + x[6] = (x4 - x3)*1.30656302f; + x[7] = (xt - x7)*2.56291556f; + + } + for (i = 0; i < 7; i++, y += 4*18) + { + y[0*18] = t[0][i]; + y[1*18] = t[2][i] + t[3][i] + t[3][i + 1]; + y[2*18] = t[1][i] + t[1][i + 1]; + y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1]; + } + y[0*18] = t[0][7]; + y[1*18] = t[2][7] + t[3][7]; + y[2*18] = t[1][7]; + y[3*18] = t[3][7]; + } +#endif /* MINIMP3_ONLY_SIMD */ +} + +#ifndef MINIMP3_FLOAT_OUTPUT +static int16_t mp3d_scale_pcm(float sample) +{ +#if HAVE_ARMV6 + int32_t s32 = (int32_t)(sample + .5f); + s32 -= (s32 < 0); + int16_t s = (int16_t)minimp3_clip_int16_arm(s32); +#else + if (sample >= 32766.5) return (int16_t) 32767; + if (sample <= -32767.5) return (int16_t)-32768; + int16_t s = (int16_t)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ +#endif + return s; +} +#else /* MINIMP3_FLOAT_OUTPUT */ +static float mp3d_scale_pcm(float sample) +{ + return sample*(1.f/32768.f); +} +#endif /* MINIMP3_FLOAT_OUTPUT */ + +static void mp3d_synth_pair(mp3d_sample_t *pcm, int nch, const float *z) +{ + float a; + a = (z[14*64] - z[ 0]) * 29; + a += (z[ 1*64] + z[13*64]) * 213; + a += (z[12*64] - z[ 2*64]) * 459; + a += (z[ 3*64] + z[11*64]) * 2037; + a += (z[10*64] - z[ 4*64]) * 5153; + a += (z[ 5*64] + z[ 9*64]) * 6574; + a += (z[ 8*64] - z[ 6*64]) * 37489; + a += z[ 7*64] * 75038; + pcm[0] = mp3d_scale_pcm(a); + + z += 2; + a = z[14*64] * 104; + a += z[12*64] * 1567; + a += z[10*64] * 9727; + a += z[ 8*64] * 64019; + a += z[ 6*64] * -9975; + a += z[ 4*64] * -45; + a += z[ 2*64] * 146; + a += z[ 0*64] * -5; + pcm[16*nch] = mp3d_scale_pcm(a); +} + +static void mp3d_synth(float *xl, mp3d_sample_t *dstl, int nch, float *lins) +{ + int i; + float *xr = xl + 576*(nch - 1); + mp3d_sample_t *dstr = dstl + (nch - 1); + + static const float g_win[] = { + -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992, + -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856, + -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630, + -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313, + -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908, + -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415, + -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835, + -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169, + -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420, + -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590, + -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679, + -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692, + -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629, + -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494, + -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290 + }; + float *zlin = lins + 15*64; + const float *w = g_win; + + zlin[4*15] = xl[18*16]; + zlin[4*15 + 1] = xr[18*16]; + zlin[4*15 + 2] = xl[0]; + zlin[4*15 + 3] = xr[0]; + + zlin[4*31] = xl[1 + 18*16]; + zlin[4*31 + 1] = xr[1 + 18*16]; + zlin[4*31 + 2] = xl[1]; + zlin[4*31 + 3] = xr[1]; + + mp3d_synth_pair(dstr, nch, lins + 4*15 + 1); + mp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1); + mp3d_synth_pair(dstl, nch, lins + 4*15); + mp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64); + +#if HAVE_SIMD + if (have_simd()) for (i = 14; i >= 0; i--) + { +#define VLOAD(k) f4 w0 = VSET(*w++); f4 w1 = VSET(*w++); f4 vz = VLD(&zlin[4*i - 64*k]); f4 vy = VLD(&zlin[4*i - 64*(15 - k)]); +#define V0(k) { VLOAD(k) b = VADD(VMUL(vz, w1), VMUL(vy, w0)) ; a = VSUB(VMUL(vz, w0), VMUL(vy, w1)); } +#define V1(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vz, w0), VMUL(vy, w1))); } +#define V2(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vy, w1), VMUL(vz, w0))); } + f4 a, b; + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*i + 64] = xl[1 + 18*(1 + i)]; + zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)]; + zlin[4*i - 64 + 2] = xl[18*(1 + i)]; + zlin[4*i - 64 + 3] = xr[18*(1 + i)]; + + V0(0) V2(1) V1(2) V2(3) V1(4) V2(5) V1(6) V2(7) + + { +#ifndef MINIMP3_FLOAT_OUTPUT +#if HAVE_SSE + static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + dstr[(15 - i)*nch] = _mm_extract_epi16(pcm8, 1); + dstr[(17 + i)*nch] = _mm_extract_epi16(pcm8, 5); + dstl[(15 - i)*nch] = _mm_extract_epi16(pcm8, 0); + dstl[(17 + i)*nch] = _mm_extract_epi16(pcm8, 4); + dstr[(47 - i)*nch] = _mm_extract_epi16(pcm8, 3); + dstr[(49 + i)*nch] = _mm_extract_epi16(pcm8, 7); + dstl[(47 - i)*nch] = _mm_extract_epi16(pcm8, 2); + dstl[(49 + i)*nch] = _mm_extract_epi16(pcm8, 6); +#else /* HAVE_SSE */ + int16x4_t pcma, pcmb; + a = VADD(a, VSET(0.5f)); + b = VADD(b, VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); + vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1); + vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1); + vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0); + vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0); + vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3); + vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3); + vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2); + vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); +#endif /* HAVE_SSE */ + +#else /* MINIMP3_FLOAT_OUTPUT */ + + static const f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; + a = VMUL(a, g_scale); + b = VMUL(b, g_scale); +#if HAVE_SSE + _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2))); + _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2))); +#else /* HAVE_SSE */ + vst1q_lane_f32(dstr + (15 - i)*nch, a, 1); + vst1q_lane_f32(dstr + (17 + i)*nch, b, 1); + vst1q_lane_f32(dstl + (15 - i)*nch, a, 0); + vst1q_lane_f32(dstl + (17 + i)*nch, b, 0); + vst1q_lane_f32(dstr + (47 - i)*nch, a, 3); + vst1q_lane_f32(dstr + (49 + i)*nch, b, 3); + vst1q_lane_f32(dstl + (47 - i)*nch, a, 2); + vst1q_lane_f32(dstl + (49 + i)*nch, b, 2); +#endif /* HAVE_SSE */ +#endif /* MINIMP3_FLOAT_OUTPUT */ + } + } else +#endif /* HAVE_SIMD */ +#ifdef MINIMP3_ONLY_SIMD + {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ +#else /* MINIMP3_ONLY_SIMD */ + for (i = 14; i >= 0; i--) + { +#define LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64]; +#define S0(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; } +#define S1(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; } +#define S2(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; } + float a[4], b[4]; + + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*(i + 16)] = xl[1 + 18*(1 + i)]; + zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)]; + zlin[4*(i - 16) + 2] = xl[18*(1 + i)]; + zlin[4*(i - 16) + 3] = xr[18*(1 + i)]; + + S0(0) S2(1) S1(2) S2(3) S1(4) S2(5) S1(6) S2(7) + + dstr[(15 - i)*nch] = mp3d_scale_pcm(a[1]); + dstr[(17 + i)*nch] = mp3d_scale_pcm(b[1]); + dstl[(15 - i)*nch] = mp3d_scale_pcm(a[0]); + dstl[(17 + i)*nch] = mp3d_scale_pcm(b[0]); + dstr[(47 - i)*nch] = mp3d_scale_pcm(a[3]); + dstr[(49 + i)*nch] = mp3d_scale_pcm(b[3]); + dstl[(47 - i)*nch] = mp3d_scale_pcm(a[2]); + dstl[(49 + i)*nch] = mp3d_scale_pcm(b[2]); + } +#endif /* MINIMP3_ONLY_SIMD */ +} + +static void mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, mp3d_sample_t *pcm, float *lins) +{ + int i; + for (i = 0; i < nch; i++) + { + mp3d_DCT_II(grbuf + 576*i, nbands); + } + + memcpy(lins, qmf_state, sizeof(float)*15*64); + + for (i = 0; i < nbands; i += 2) + { + mp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64); + } +#ifndef MINIMP3_NONSTANDARD_BUT_LOGICAL + if (nch == 1) + { + for (i = 0; i < 15*64; i += 2) + { + qmf_state[i] = lins[nbands*64 + i]; + } + } else +#endif /* MINIMP3_NONSTANDARD_BUT_LOGICAL */ + { + memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); + } +} + +static int mp3d_match_frame(const uint8_t *hdr, int mp3_bytes, int frame_bytes) +{ + int i, nmatch; + for (i = 0, nmatch = 0; nmatch < MAX_FRAME_SYNC_MATCHES; nmatch++) + { + i += hdr_frame_bytes(hdr + i, frame_bytes) + hdr_padding(hdr + i); + if (i + HDR_SIZE > mp3_bytes) + return nmatch > 0; + if (!hdr_compare(hdr, hdr + i)) + return 0; + } + return 1; +} + +static int mp3d_find_frame(const uint8_t *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes) +{ + int i, k; + for (i = 0; i < mp3_bytes - HDR_SIZE; i++, mp3++) + { + if (hdr_valid(mp3)) + { + int frame_bytes = hdr_frame_bytes(mp3, *free_format_bytes); + int frame_and_padding = frame_bytes + hdr_padding(mp3); + + for (k = HDR_SIZE; !frame_bytes && k < MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - HDR_SIZE; k++) + { + if (hdr_compare(mp3, mp3 + k)) + { + int fb = k - hdr_padding(mp3); + int nextfb = fb + hdr_padding(mp3 + k); + if (i + k + nextfb + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + k + nextfb)) + continue; + frame_and_padding = k; + frame_bytes = fb; + *free_format_bytes = fb; + } + } + if ((frame_bytes && i + frame_and_padding <= mp3_bytes && + mp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) || + (!i && frame_and_padding == mp3_bytes)) + { + *ptr_frame_bytes = frame_and_padding; + return i; + } + *free_format_bytes = 0; + } + } + *ptr_frame_bytes = 0; + return mp3_bytes; +} + +void mp3dec_init(mp3dec_t *dec) +{ + dec->header[0] = 0; +} + +int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info) +{ + int i = 0, igr, frame_size = 0, success = 1; + const uint8_t *hdr; + bs_t bs_frame[1]; + mp3dec_scratch_t scratch; + + if (mp3_bytes > 4 && dec->header[0] == 0xff && hdr_compare(dec->header, mp3)) + { + frame_size = hdr_frame_bytes(mp3, dec->free_format_bytes) + hdr_padding(mp3); + if (frame_size != mp3_bytes && (frame_size + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + frame_size))) + { + frame_size = 0; + } + } + if (!frame_size) + { + memset(dec, 0, sizeof(mp3dec_t)); + i = mp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); + if (!frame_size || i + frame_size > mp3_bytes) + { + info->frame_bytes = i; + return 0; + } + } + + hdr = mp3 + i; + memcpy(dec->header, hdr, HDR_SIZE); + info->frame_bytes = i + frame_size; + info->frame_offset = i; + info->channels = HDR_IS_MONO(hdr) ? 1 : 2; + info->hz = hdr_sample_rate_hz(hdr); + info->layer = 4 - HDR_GET_LAYER(hdr); + info->bitrate_kbps = hdr_bitrate_kbps(hdr); + + if (!pcm) + { + return hdr_frame_samples(hdr); + } + + bs_init(bs_frame, hdr + HDR_SIZE, frame_size - HDR_SIZE); + if (HDR_IS_CRC(hdr)) + { + get_bits(bs_frame, 16); + } + + if (info->layer == 3) + { + int main_data_begin = L3_read_side_info(bs_frame, scratch.gr_info, hdr); + if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit) + { + mp3dec_init(dec); + return 0; + } + success = L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); + if (success) + { + for (igr = 0; igr < (HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm += 576*info->channels) + { + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); + mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, pcm, scratch.syn[0]); + } + } + L3_save_reservoir(dec, &scratch); + } else + { +#ifdef MINIMP3_ONLY_MP3 + return 0; +#else /* MINIMP3_ONLY_MP3 */ + L12_scale_info sci[1]; + L12_read_scale_info(hdr, bs_frame, sci); + + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + for (i = 0, igr = 0; igr < 3; igr++) + { + if (12 == (i += L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) + { + i = 0; + L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); + mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, pcm, scratch.syn[0]); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + pcm += 384*info->channels; + } + if (bs_frame->pos > bs_frame->limit) + { + mp3dec_init(dec); + return 0; + } + } +#endif /* MINIMP3_ONLY_MP3 */ + } + return success*hdr_frame_samples(dec->header); +} + +#ifdef MINIMP3_FLOAT_OUTPUT +void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples) +{ + int i = 0; +#if HAVE_SIMD + int aligned_count = num_samples & ~7; + for(; i < aligned_count; i += 8) + { + static const f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f }; + f4 a = VMUL(VLD(&in[i ]), g_scale); + f4 b = VMUL(VLD(&in[i+4]), g_scale); +#if HAVE_SSE + static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + out[i ] = _mm_extract_epi16(pcm8, 0); + out[i+1] = _mm_extract_epi16(pcm8, 1); + out[i+2] = _mm_extract_epi16(pcm8, 2); + out[i+3] = _mm_extract_epi16(pcm8, 3); + out[i+4] = _mm_extract_epi16(pcm8, 4); + out[i+5] = _mm_extract_epi16(pcm8, 5); + out[i+6] = _mm_extract_epi16(pcm8, 6); + out[i+7] = _mm_extract_epi16(pcm8, 7); +#else /* HAVE_SSE */ + int16x4_t pcma, pcmb; + a = VADD(a, VSET(0.5f)); + b = VADD(b, VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); + vst1_lane_s16(out+i , pcma, 0); + vst1_lane_s16(out+i+1, pcma, 1); + vst1_lane_s16(out+i+2, pcma, 2); + vst1_lane_s16(out+i+3, pcma, 3); + vst1_lane_s16(out+i+4, pcmb, 0); + vst1_lane_s16(out+i+5, pcmb, 1); + vst1_lane_s16(out+i+6, pcmb, 2); + vst1_lane_s16(out+i+7, pcmb, 3); +#endif /* HAVE_SSE */ + } +#endif /* HAVE_SIMD */ + for(; i < num_samples; i++) + { + float sample = in[i] * 32768.0f; + if (sample >= 32766.5) + out[i] = (int16_t) 32767; + else if (sample <= -32767.5) + out[i] = (int16_t)-32768; + else + { + int16_t s = (int16_t)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ + out[i] = s; + } + } +} +#endif /* MINIMP3_FLOAT_OUTPUT */ +#endif /* MINIMP3_IMPLEMENTATION && !_MINIMP3_IMPLEMENTATION_GUARD */ diff --git a/ext/minimp3/minimp3_ex.h b/ext/minimp3/minimp3_ex.h new file mode 100644 index 0000000000..2871705df3 --- /dev/null +++ b/ext/minimp3/minimp3_ex.h @@ -0,0 +1,1397 @@ +#ifndef MINIMP3_EXT_H +#define MINIMP3_EXT_H +/* + https://github.com/lieff/minimp3 + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. + This software is distributed without any warranty. + See . +*/ +#include +#include "minimp3.h" + +/* flags for mp3dec_ex_open_* functions */ +#define MP3D_SEEK_TO_BYTE 0 /* mp3dec_ex_seek seeks to byte in stream */ +#define MP3D_SEEK_TO_SAMPLE 1 /* mp3dec_ex_seek precisely seeks to sample using index (created during duration calculation scan or when mp3dec_ex_seek called) */ +#define MP3D_DO_NOT_SCAN 2 /* do not scan whole stream for duration if vbrtag not found, mp3dec_ex_t::samples will be filled only if mp3dec_ex_t::vbr_tag_found == 1 */ +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION +#define MP3D_ALLOW_MONO_STEREO_TRANSITION 4 +#define MP3D_FLAGS_MASK 7 +#else +#define MP3D_FLAGS_MASK 3 +#endif + +/* compile-time config */ +#define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */ +/*#define MINIMP3_SEEK_IDX_LINEAR_SEARCH*/ /* define to use linear index search instead of binary search on seek */ +#define MINIMP3_IO_SIZE (128*1024) /* io buffer size for streaming functions, must be greater than MINIMP3_BUF_SIZE */ +#define MINIMP3_BUF_SIZE (16*1024) /* buffer which can hold minimum 10 consecutive mp3 frames (~16KB) worst case */ +/*#define MINIMP3_SCAN_LIMIT (256*1024)*/ /* how many bytes will be scanned to search first valid mp3 frame, to prevent stall on large non-mp3 files */ +#define MINIMP3_ENABLE_RING 0 /* WIP enable hardware magic ring buffer if available, to make less input buffer memmove(s) in callback IO mode */ + +/* return error codes */ +#define MP3D_E_PARAM -1 +#define MP3D_E_MEMORY -2 +#define MP3D_E_IOERROR -3 +#define MP3D_E_USER -4 /* can be used to stop processing from callbacks without indicating specific error */ +#define MP3D_E_DECODE -5 /* decode error which can't be safely skipped, such as sample rate, layer and channels change */ + +typedef struct +{ + mp3d_sample_t *buffer; + size_t samples; /* channels included, byte size = samples*sizeof(mp3d_sample_t) */ + int channels, hz, layer, avg_bitrate_kbps; +} mp3dec_file_info_t; + +typedef struct +{ + const uint8_t *buffer; + size_t size; +} mp3dec_map_info_t; + +typedef struct +{ + uint64_t sample; + uint64_t offset; +} mp3dec_frame_t; + +typedef struct +{ + mp3dec_frame_t *frames; + size_t num_frames, capacity; +} mp3dec_index_t; + +typedef size_t (*MP3D_READ_CB)(void *buf, size_t size, void *user_data); +typedef int (*MP3D_SEEK_CB)(uint64_t position, void *user_data); + +typedef struct +{ + MP3D_READ_CB read; + void *read_data; + MP3D_SEEK_CB seek; + void *seek_data; +} mp3dec_io_t; + +typedef struct +{ + mp3dec_t mp3d; + mp3dec_map_info_t file; + mp3dec_io_t *io; + mp3dec_index_t index; + uint64_t offset, samples, detected_samples, cur_sample, start_offset, end_offset; + mp3dec_frame_info_t info; + mp3d_sample_t buffer[MINIMP3_MAX_SAMPLES_PER_FRAME]; + size_t input_consumed, input_filled; + int is_file, flags, vbr_tag_found, indexes_built; + int free_format_bytes; + int buffer_samples, buffer_consumed, to_skip, start_delay; + int last_error; +} mp3dec_ex_t; + +typedef int (*MP3D_ITERATE_CB)(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info); +typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, uint64_t offset, mp3dec_frame_info_t *info); + +#ifdef __cplusplus +extern "C" { +#endif + +/* detect mp3/mpa format */ +int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size); +int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size); +/* decode whole buffer block */ +int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +/* iterate through frames */ +int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data); +/* streaming decoder with seeking capability */ +int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int flags); +int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int flags); +void mp3dec_ex_close(mp3dec_ex_t *dec); +int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position); +size_t mp3dec_ex_read_frame(mp3dec_ex_t *dec, mp3d_sample_t **buf, mp3dec_frame_info_t *frame_info, size_t max_samples); +size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples); +#ifndef MINIMP3_NO_STDIO +/* stdio versions of file detect, load, iterate and stream */ +int mp3dec_detect(const char *file_name); +int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int flags); +#ifdef _WIN32 +int mp3dec_detect_w(const wchar_t *file_name); +int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int flags); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif /*MINIMP3_EXT_H*/ + +#if defined(MINIMP3_IMPLEMENTATION) && !defined(_MINIMP3_EX_IMPLEMENTATION_GUARD) +#define _MINIMP3_EX_IMPLEMENTATION_GUARD +#include +#include "minimp3.h" + +static void mp3dec_skip_id3v1(const uint8_t *buf, size_t *pbuf_size) +{ + size_t buf_size = *pbuf_size; +#ifndef MINIMP3_NOSKIP_ID3V1 + if (buf_size >= 128 && !memcmp(buf + buf_size - 128, "TAG", 3)) + { + buf_size -= 128; + if (buf_size >= 227 && !memcmp(buf + buf_size - 227, "TAG+", 4)) + buf_size -= 227; + } +#endif +#ifndef MINIMP3_NOSKIP_APEV2 + if (buf_size > 32 && !memcmp(buf + buf_size - 32, "APETAGEX", 8)) + { + buf_size -= 32; + const uint8_t *tag = buf + buf_size + 8 + 4; + uint32_t tag_size = (uint32_t)(tag[3] << 24) | (tag[2] << 16) | (tag[1] << 8) | tag[0]; + if (buf_size >= tag_size) + buf_size -= tag_size; + } +#endif + *pbuf_size = buf_size; +} + +static size_t mp3dec_skip_id3v2(const uint8_t *buf, size_t buf_size) +{ +#define MINIMP3_ID3_DETECT_SIZE 10 +#ifndef MINIMP3_NOSKIP_ID3V2 + if (buf_size >= MINIMP3_ID3_DETECT_SIZE && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80))) + { + size_t id3v2size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10; + if ((buf[5] & 16)) + id3v2size += 10; /* footer */ + return id3v2size; + } +#endif + return 0; +} + +static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size) +{ + uint8_t *buf = (uint8_t *)(*pbuf); + size_t buf_size = *pbuf_size; + size_t id3v2size = mp3dec_skip_id3v2(buf, buf_size); + if (id3v2size) + { + if (id3v2size >= buf_size) + id3v2size = buf_size; + buf += id3v2size; + buf_size -= id3v2size; + } + mp3dec_skip_id3v1(buf, &buf_size); + *pbuf = (const uint8_t *)buf; + *pbuf_size = buf_size; +} + +static int mp3dec_check_vbrtag(const uint8_t *frame, int frame_size, uint32_t *frames, int *delay, int *padding) +{ + static const char g_xing_tag[4] = { 'X', 'i', 'n', 'g' }; + static const char g_info_tag[4] = { 'I', 'n', 'f', 'o' }; +#define FRAMES_FLAG 1 +#define BYTES_FLAG 2 +#define TOC_FLAG 4 +#define VBR_SCALE_FLAG 8 + /* Side info offsets after header: + / Mono Stereo + / MPEG1 17 32 + / MPEG2 & 2.5 9 17*/ + bs_t bs[1]; + L3_gr_info_t gr_info[4]; + bs_init(bs, frame + HDR_SIZE, frame_size - HDR_SIZE); + if (HDR_IS_CRC(frame)) + get_bits(bs, 16); + if (L3_read_side_info(bs, gr_info, frame) < 0) + return 0; /* side info corrupted */ + + const uint8_t *tag = frame + HDR_SIZE + bs->pos/8; + if (memcmp(g_xing_tag, tag, 4) && memcmp(g_info_tag, tag, 4)) + return 0; + int flags = tag[7]; + if (!((flags & FRAMES_FLAG))) + return -1; + tag += 8; + *frames = (uint32_t)(tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3]; + tag += 4; + if (flags & BYTES_FLAG) + tag += 4; + if (flags & TOC_FLAG) + tag += 100; + if (flags & VBR_SCALE_FLAG) + tag += 4; + *delay = *padding = 0; + if (*tag) + { /* extension, LAME, Lavc, etc. Should be the same structure. */ + tag += 21; + if (tag - frame + 14 >= frame_size) + return 0; + *delay = ((tag[0] << 4) | (tag[1] >> 4)) + (528 + 1); + *padding = (((tag[1] & 0xF) << 8) | tag[2]) - (528 + 1); + } + return 1; +} + +int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size) +{ + return mp3dec_detect_cb(0, (uint8_t *)buf, buf_size); +} + +int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size) +{ + if (!buf || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE)) + return MP3D_E_PARAM; + size_t filled = buf_size; + if (io) + { + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + } + if (filled < MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_USER; /* too small, can't be mp3/mpa */ + if (mp3dec_skip_id3v2(buf, filled)) + return 0; /* id3v2 tag is enough evidence */ + if (io) + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + } else + { + mp3dec_skip_id3v1(buf, &filled); + if (filled > MINIMP3_BUF_SIZE) + filled = MINIMP3_BUF_SIZE; + } + int free_format_bytes, frame_size; + mp3d_find_frame(buf, filled, &free_format_bytes, &frame_size); + if (frame_size) + return 0; /* MAX_FRAME_SYNC_MATCHES consecutive frames found */ + return MP3D_E_USER; +} + +int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + return mp3dec_load_cb(dec, 0, (uint8_t *)buf, buf_size, info, progress_cb, user_data); +} + +int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + if (!dec || !buf || !info || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE)) + return MP3D_E_PARAM; + uint64_t detected_samples = 0; + size_t orig_buf_size = buf_size; + int to_skip = 0; + mp3dec_frame_info_t frame_info; + memset(info, 0, sizeof(*info)); + memset(&frame_info, 0, sizeof(frame_info)); + + /* skip id3 */ + size_t filled = 0, consumed = 0; + int eof = 0, ret = 0; + if (io) + { + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + if (MINIMP3_ID3_DETECT_SIZE != filled) + return 0; + size_t id3v2size = mp3dec_skip_id3v2(buf, filled); + if (id3v2size) + { + if (io->seek(id3v2size, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, buf_size, io->read_data); + if (filled > buf_size) + return MP3D_E_IOERROR; + } else + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + } + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + } else + { + mp3dec_skip_id3((const uint8_t **)&buf, &buf_size); + if (!buf_size) + return 0; + } + /* try to make allocation size assumption by first frame or vbr tag */ + mp3dec_init(dec); + int samples; + do + { + uint32_t frames; + int i, delay, padding, free_format_bytes = 0, frame_size = 0; + const uint8_t *hdr; + if (io) + { + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed > (buf_size - filled)) + return MP3D_E_IOERROR; + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size); + consumed += i; + hdr = buf + consumed; + } else + { + i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); + buf += i; + buf_size -= i; + hdr = buf; + } + if (i && !frame_size) + continue; + if (!frame_size) + return 0; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + samples = hdr_frame_samples(hdr)*frame_info.channels; + if (3 != frame_info.layer) + break; + int ret = mp3dec_check_vbrtag(hdr, frame_size, &frames, &delay, &padding); + if (ret > 0) + { + padding *= frame_info.channels; + to_skip = delay*frame_info.channels; + detected_samples = samples*(uint64_t)frames; + if (detected_samples >= (uint64_t)to_skip) + detected_samples -= to_skip; + if (padding > 0 && detected_samples >= (uint64_t)padding) + detected_samples -= padding; + if (!detected_samples) + return 0; + } + if (ret) + { + if (io) + { + consumed += frame_size; + } else + { + buf += frame_size; + buf_size -= frame_size; + } + } + break; + } while(1); + size_t allocated = MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t); + if (detected_samples) + allocated += detected_samples*sizeof(mp3d_sample_t); + else + allocated += (buf_size/frame_info.frame_bytes)*samples*sizeof(mp3d_sample_t); + info->buffer = (mp3d_sample_t*)malloc(allocated); + if (!info->buffer) + return MP3D_E_MEMORY; + /* save info */ + info->channels = frame_info.channels; + info->hz = frame_info.hz; + info->layer = frame_info.layer; + /* decode all frames */ + size_t avg_bitrate_kbps = 0, frames = 0; + do + { + if ((allocated - info->samples*sizeof(mp3d_sample_t)) < MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t)) + { + allocated *= 2; + mp3d_sample_t *alloc_buf = (mp3d_sample_t*)realloc(info->buffer, allocated); + if (!alloc_buf) + return MP3D_E_MEMORY; + info->buffer = alloc_buf; + } + if (io) + { + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + samples = mp3dec_decode_frame(dec, buf + consumed, filled - consumed, info->buffer + info->samples, &frame_info); + consumed += frame_info.frame_bytes; + } else + { + samples = mp3dec_decode_frame(dec, buf, MINIMP3_MIN(buf_size, (size_t)INT_MAX), info->buffer + info->samples, &frame_info); + buf += frame_info.frame_bytes; + buf_size -= frame_info.frame_bytes; + } + if (samples) + { + if (info->hz != frame_info.hz || info->layer != frame_info.layer) + { + ret = MP3D_E_DECODE; + break; + } + if (info->channels && info->channels != frame_info.channels) + { +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION + info->channels = 0; /* mark file with mono-stereo transition */ +#else + ret = MP3D_E_DECODE; + break; +#endif + } + samples *= frame_info.channels; + if (to_skip) + { + size_t skip = MINIMP3_MIN(samples, to_skip); + to_skip -= skip; + samples -= skip; + memmove(info->buffer, info->buffer + skip, samples*sizeof(mp3d_sample_t)); + } + info->samples += samples; + avg_bitrate_kbps += frame_info.bitrate_kbps; + frames++; + if (progress_cb) + { + ret = progress_cb(user_data, orig_buf_size, orig_buf_size - buf_size, &frame_info); + if (ret) + break; + } + } + } while (frame_info.frame_bytes); + if (detected_samples && info->samples > detected_samples) + info->samples = detected_samples; /* cut padding */ + /* reallocate to normal buffer size */ + if (allocated != info->samples*sizeof(mp3d_sample_t)) + { + mp3d_sample_t *alloc_buf = (mp3d_sample_t*)realloc(info->buffer, info->samples*sizeof(mp3d_sample_t)); + if (!alloc_buf && info->samples) + return MP3D_E_MEMORY; + info->buffer = alloc_buf; + } + if (frames) + info->avg_bitrate_kbps = avg_bitrate_kbps/frames; + return ret; +} + +int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data) +{ + const uint8_t *orig_buf = buf; + if (!buf || (size_t)-1 == buf_size || !callback) + return MP3D_E_PARAM; + /* skip id3 */ + mp3dec_skip_id3(&buf, &buf_size); + if (!buf_size) + return 0; + mp3dec_frame_info_t frame_info; + memset(&frame_info, 0, sizeof(frame_info)); + do + { + int free_format_bytes = 0, frame_size = 0, ret; + int i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); + buf += i; + buf_size -= i; + if (i && !frame_size) + continue; + if (!frame_size) + break; + const uint8_t *hdr = buf; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + + if (callback) + { + if ((ret = callback(user_data, hdr, frame_size, free_format_bytes, buf_size, hdr - orig_buf, &frame_info))) + return ret; + } + buf += frame_size; + buf_size -= frame_size; + } while (1); + return 0; +} + +int mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data) +{ + if (!io || !buf || (size_t)-1 == buf_size || buf_size < MINIMP3_BUF_SIZE || !callback) + return MP3D_E_PARAM; + size_t filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data), consumed = 0; + uint64_t readed = 0; + mp3dec_frame_info_t frame_info; + int eof = 0; + memset(&frame_info, 0, sizeof(frame_info)); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + if (MINIMP3_ID3_DETECT_SIZE != filled) + return 0; + size_t id3v2size = mp3dec_skip_id3v2(buf, filled); + if (id3v2size) + { + if (io->seek(id3v2size, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, buf_size, io->read_data); + if (filled > buf_size) + return MP3D_E_IOERROR; + readed += id3v2size; + } else + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + } + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + do + { + int free_format_bytes = 0, frame_size = 0, ret; + int i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size); + if (i && !frame_size) + { + consumed += i; + continue; + } + if (!frame_size) + break; + const uint8_t *hdr = buf + consumed + i; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + + readed += i; + if (callback) + { + if ((ret = callback(user_data, hdr, frame_size, free_format_bytes, filled - consumed, readed, &frame_info))) + return ret; + } + readed += frame_size; + consumed += i + frame_size; + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed > (buf_size - filled)) + return MP3D_E_IOERROR; + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + } while (1); + return 0; +} + +static int mp3dec_load_index(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info) +{ + mp3dec_frame_t *idx_frame; + mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data; + if (!dec->index.frames && !dec->start_offset) + { /* detect VBR tag and try to avoid full scan */ + uint32_t frames; + int delay, padding; + dec->info = *info; + dec->start_offset = dec->offset = offset; + dec->end_offset = offset + buf_size; + dec->free_format_bytes = free_format_bytes; /* should not change */ + if (3 == dec->info.layer) + { + int ret = mp3dec_check_vbrtag(frame, frame_size, &frames, &delay, &padding); + if (ret) + dec->start_offset = dec->offset = offset + frame_size; + if (ret > 0) + { + padding *= info->channels; + dec->start_delay = dec->to_skip = delay*info->channels; + dec->samples = hdr_frame_samples(frame)*info->channels*(uint64_t)frames; + if (dec->samples >= (uint64_t)dec->start_delay) + dec->samples -= dec->start_delay; + if (padding > 0 && dec->samples >= (uint64_t)padding) + dec->samples -= padding; + dec->detected_samples = dec->samples; + dec->vbr_tag_found = 1; + return MP3D_E_USER; + } else if (ret < 0) + return 0; + } + } + if (dec->flags & MP3D_DO_NOT_SCAN) + return MP3D_E_USER; + if (dec->index.num_frames + 1 > dec->index.capacity) + { + if (!dec->index.capacity) + dec->index.capacity = 4096; + else + dec->index.capacity *= 2; + mp3dec_frame_t *alloc_buf = (mp3dec_frame_t *)realloc((void*)dec->index.frames, sizeof(mp3dec_frame_t)*dec->index.capacity); + if (!alloc_buf) + return MP3D_E_MEMORY; + dec->index.frames = alloc_buf; + } + idx_frame = &dec->index.frames[dec->index.num_frames++]; + idx_frame->offset = offset; + idx_frame->sample = dec->samples; + if (!dec->buffer_samples && dec->index.num_frames < 256) + { /* for some cutted mp3 frames, bit-reservoir not filled and decoding can't be started from first frames */ + /* try to decode up to 255 first frames till samples starts to decode */ + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, frame, MINIMP3_MIN(buf_size, (size_t)INT_MAX), dec->buffer, info); + dec->samples += dec->buffer_samples*info->channels; + } else + dec->samples += hdr_frame_samples(frame)*info->channels; + return 0; +} + +int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int flags) +{ + if (!dec || !buf || (size_t)-1 == buf_size || (flags & (~MP3D_FLAGS_MASK))) + return MP3D_E_PARAM; + memset(dec, 0, sizeof(*dec)); + dec->file.buffer = buf; + dec->file.size = buf_size; + dec->flags = flags; + mp3dec_init(&dec->mp3d); + int ret = mp3dec_iterate_buf(dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + mp3dec_init(&dec->mp3d); + dec->buffer_samples = 0; + dec->indexes_built = !(dec->vbr_tag_found || (flags & MP3D_DO_NOT_SCAN)); + dec->flags &= (~MP3D_DO_NOT_SCAN); + return 0; +} + +#ifndef MINIMP3_SEEK_IDX_LINEAR_SEARCH +static size_t mp3dec_idx_binary_search(mp3dec_index_t *idx, uint64_t position) +{ + size_t end = idx->num_frames, start = 0, index = 0; + while (start <= end) + { + size_t mid = (start + end) / 2; + if (idx->frames[mid].sample >= position) + { /* move left side. */ + if (idx->frames[mid].sample == position) + return mid; + end = mid - 1; + } else + { /* move to right side */ + index = mid; + start = mid + 1; + if (start == idx->num_frames) + break; + } + } + return index; +} +#endif + +int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position) +{ + size_t i; + if (!dec) + return MP3D_E_PARAM; + if (!(dec->flags & MP3D_SEEK_TO_SAMPLE)) + { + if (dec->io) + { + dec->offset = position; + } else + { + dec->offset = MINIMP3_MIN(position, dec->file.size); + } + dec->cur_sample = 0; + goto do_exit; + } + dec->cur_sample = position; + position += dec->start_delay; + if (0 == position) + { /* optimize seek to zero, no index needed */ +seek_zero: + dec->offset = dec->start_offset; + dec->to_skip = 0; + goto do_exit; + } + if (!dec->indexes_built) + { /* no index created yet (vbr tag used to calculate track length or MP3D_DO_NOT_SCAN open flag used) */ + dec->indexes_built = 1; + dec->samples = 0; + dec->buffer_samples = 0; + if (dec->io) + { + if (dec->io->seek(dec->start_offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + int ret = mp3dec_iterate_cb(dec->io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + } else + { + int ret = mp3dec_iterate_buf(dec->file.buffer + dec->start_offset, dec->file.size - dec->start_offset, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + } + for (i = 0; i < dec->index.num_frames; i++) + dec->index.frames[i].offset += dec->start_offset; + dec->samples = dec->detected_samples; + } + if (!dec->index.frames) + goto seek_zero; /* no frames in file - seek to zero */ +#ifdef MINIMP3_SEEK_IDX_LINEAR_SEARCH + for (i = 0; i < dec->index.num_frames; i++) + { + if (dec->index.frames[i].sample >= position) + break; + } +#else + i = mp3dec_idx_binary_search(&dec->index, position); +#endif + if (i) + { + int to_fill_bytes = 511; + int skip_frames = MINIMP3_PREDECODE_FRAMES +#ifdef MINIMP3_SEEK_IDX_LINEAR_SEARCH + + ((dec->index.frames[i].sample == position) ? 0 : 1) +#endif + ; + i -= MINIMP3_MIN(i, (size_t)skip_frames); + if (3 == dec->info.layer) + { + while (i && to_fill_bytes) + { /* make sure bit-reservoir is filled when we start decoding */ + bs_t bs[1]; + L3_gr_info_t gr_info[4]; + int frame_bytes, frame_size; + const uint8_t *hdr; + if (dec->io) + { + hdr = dec->file.buffer; + if (dec->io->seek(dec->index.frames[i - 1].offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data); + if (readed != HDR_SIZE) + return MP3D_E_IOERROR; + frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr); + readed = dec->io->read((uint8_t *)hdr + HDR_SIZE, frame_size - HDR_SIZE, dec->io->read_data); + if (readed != (size_t)(frame_size - HDR_SIZE)) + return MP3D_E_IOERROR; + bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE); + } else + { + hdr = dec->file.buffer + dec->index.frames[i - 1].offset; + frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr); + bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE); + } + if (HDR_IS_CRC(hdr)) + get_bits(bs, 16); + i--; + if (L3_read_side_info(bs, gr_info, hdr) < 0) + break; /* frame not decodable, we can start from here */ + frame_bytes = (bs->limit - bs->pos)/8; + to_fill_bytes -= MINIMP3_MIN(to_fill_bytes, frame_bytes); + } + } + } + dec->offset = dec->index.frames[i].offset; + dec->to_skip = position - dec->index.frames[i].sample; + while ((i + 1) < dec->index.num_frames && !dec->index.frames[i].sample && !dec->index.frames[i + 1].sample) + { /* skip not decodable first frames */ + const uint8_t *hdr; + if (dec->io) + { + hdr = dec->file.buffer; + if (dec->io->seek(dec->index.frames[i].offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data); + if (readed != HDR_SIZE) + return MP3D_E_IOERROR; + } else + hdr = dec->file.buffer + dec->index.frames[i].offset; + dec->to_skip += hdr_frame_samples(hdr)*dec->info.channels; + i++; + } +do_exit: + if (dec->io) + { + if (dec->io->seek(dec->offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + } + dec->buffer_samples = 0; + dec->buffer_consumed = 0; + dec->input_consumed = 0; + dec->input_filled = 0; + dec->last_error = 0; + mp3dec_init(&dec->mp3d); + return 0; +} + +size_t mp3dec_ex_read_frame(mp3dec_ex_t *dec, mp3d_sample_t **buf, mp3dec_frame_info_t *frame_info, size_t max_samples) +{ + if (!dec || !buf || !frame_info) + { + if (dec) + dec->last_error = MP3D_E_PARAM; + return 0; + } + if (dec->detected_samples && dec->cur_sample >= dec->detected_samples) + return 0; /* at end of stream */ + if (dec->last_error) + return 0; /* error eof state, seek can reset it */ + *buf = NULL; + uint64_t end_offset = dec->end_offset ? dec->end_offset : dec->file.size; + int eof = 0; + while (dec->buffer_consumed == dec->buffer_samples) + { + const uint8_t *dec_buf; + if (dec->io) + { + if (!eof && (dec->input_filled - dec->input_consumed) < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove((uint8_t*)dec->file.buffer, (uint8_t*)dec->file.buffer + dec->input_consumed, dec->input_filled - dec->input_consumed); + dec->input_filled -= dec->input_consumed; + dec->input_consumed = 0; + size_t readed = dec->io->read((uint8_t*)dec->file.buffer + dec->input_filled, dec->file.size - dec->input_filled, dec->io->read_data); + if (readed > (dec->file.size - dec->input_filled)) + { + dec->last_error = MP3D_E_IOERROR; + readed = 0; + } + if (readed != (dec->file.size - dec->input_filled)) + eof = 1; + dec->input_filled += readed; + if (eof) + mp3dec_skip_id3v1((uint8_t*)dec->file.buffer, &dec->input_filled); + } + dec_buf = dec->file.buffer + dec->input_consumed; + if (!(dec->input_filled - dec->input_consumed)) + return 0; + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, dec->input_filled - dec->input_consumed, dec->buffer, frame_info); + dec->input_consumed += frame_info->frame_bytes; + } else + { + dec_buf = dec->file.buffer + dec->offset; + uint64_t buf_size = end_offset - dec->offset; + if (!buf_size) + return 0; + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, MINIMP3_MIN(buf_size, (uint64_t)INT_MAX), dec->buffer, frame_info); + } + dec->buffer_consumed = 0; + if (dec->info.hz != frame_info->hz || dec->info.layer != frame_info->layer) + { +return_e_decode: + dec->last_error = MP3D_E_DECODE; + return 0; + } + if (dec->buffer_samples) + { + dec->buffer_samples *= frame_info->channels; + if (dec->to_skip) + { + size_t skip = MINIMP3_MIN(dec->buffer_samples, dec->to_skip); + dec->buffer_consumed += skip; + dec->to_skip -= skip; + } + if ( +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION + !(dec->flags & MP3D_ALLOW_MONO_STEREO_TRANSITION) && +#endif + dec->buffer_consumed != dec->buffer_samples && dec->info.channels != frame_info->channels) + { + goto return_e_decode; + } + } else if (dec->to_skip) + { /* In mp3 decoding not always can start decode from any frame because of bit reservoir, + count skip samples for such frames */ + int frame_samples = hdr_frame_samples(dec_buf)*frame_info->channels; + dec->to_skip -= MINIMP3_MIN(frame_samples, dec->to_skip); + } + dec->offset += frame_info->frame_bytes; + } + size_t out_samples = MINIMP3_MIN((size_t)(dec->buffer_samples - dec->buffer_consumed), max_samples); + if (dec->detected_samples) + { /* count decoded samples to properly cut padding */ + if (dec->cur_sample + out_samples >= dec->detected_samples) + out_samples = dec->detected_samples - dec->cur_sample; + } + dec->cur_sample += out_samples; + *buf = dec->buffer + dec->buffer_consumed; + dec->buffer_consumed += out_samples; + return out_samples; +} + +size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples) +{ + if (!dec || !buf) + { + if (dec) + dec->last_error = MP3D_E_PARAM; + return 0; + } + mp3dec_frame_info_t frame_info; + memset(&frame_info, 0, sizeof(frame_info)); + size_t samples_requested = samples; + while (samples) + { + mp3d_sample_t *buf_frame = NULL; + size_t read_samples = mp3dec_ex_read_frame(dec, &buf_frame, &frame_info, samples); + if (!read_samples) + { + break; + } + memcpy(buf, buf_frame, read_samples * sizeof(mp3d_sample_t)); + buf += read_samples; + samples -= read_samples; + } + return samples_requested - samples; +} + +int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int flags) +{ + if (!dec || !io || (flags & (~MP3D_FLAGS_MASK))) + return MP3D_E_PARAM; + memset(dec, 0, sizeof(*dec)); +#ifdef MINIMP3_HAVE_RING + int ret; + if (ret = mp3dec_open_ring(&dec->file, MINIMP3_IO_SIZE)) + return ret; +#else + dec->file.size = MINIMP3_IO_SIZE; + dec->file.buffer = (const uint8_t*)malloc(dec->file.size); + if (!dec->file.buffer) + return MP3D_E_MEMORY; +#endif + dec->flags = flags; + dec->io = io; + mp3dec_init(&dec->mp3d); + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + int ret = mp3dec_iterate_cb(io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + if (dec->io->seek(dec->start_offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + mp3dec_init(&dec->mp3d); + dec->buffer_samples = 0; + dec->indexes_built = !(dec->vbr_tag_found || (flags & MP3D_DO_NOT_SCAN)); + dec->flags &= (~MP3D_DO_NOT_SCAN); + return 0; +} + + +#ifndef MINIMP3_NO_STDIO + +#if defined(__linux__) || defined(__FreeBSD__) +#include +#include +#include +#include +#include +#include +#if !defined(_GNU_SOURCE) +#include +#include +#endif +#if !defined(MAP_POPULATE) && defined(__linux__) +#define MAP_POPULATE 0x08000 +#elif !defined(MAP_POPULATE) +#define MAP_POPULATE 0 +#endif + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer && MAP_FAILED != map_info->buffer) + munmap((void *)map_info->buffer, map_info->size); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + int file; + struct stat st; + memset(map_info, 0, sizeof(*map_info)); +retry_open: + file = open(file_name, O_RDONLY); + if (file < 0 && (errno == EAGAIN || errno == EINTR)) + goto retry_open; + if (file < 0 || fstat(file, &st) < 0) + { + close(file); + return MP3D_E_IOERROR; + } + + map_info->size = st.st_size; +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, file, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + close(file); + if (MAP_FAILED == map_info->buffer) + return MP3D_E_IOERROR; + return 0; +} + +#if MINIMP3_ENABLE_RING && defined(__linux__) && defined(_GNU_SOURCE) +#define MINIMP3_HAVE_RING +static void mp3dec_close_ring(mp3dec_map_info_t *map_info) +{ +#if defined(__linux__) && defined(_GNU_SOURCE) + if (map_info->buffer && MAP_FAILED != map_info->buffer) + munmap((void *)map_info->buffer, map_info->size*2); +#else + if (map_info->buffer) + { + shmdt(map_info->buffer); + shmdt(map_info->buffer + map_info->size); + } +#endif + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_ring(mp3dec_map_info_t *map_info, size_t size) +{ + int memfd, page_size; +#if defined(__linux__) && defined(_GNU_SOURCE) + void *buffer; + int res; +#endif + memset(map_info, 0, sizeof(*map_info)); + +#ifdef _SC_PAGESIZE + page_size = sysconf(_SC_PAGESIZE); +#else + page_size = getpagesize(); +#endif + map_info->size = (size + page_size - 1)/page_size*page_size; + +#if defined(__linux__) && defined(_GNU_SOURCE) + memfd = memfd_create("mp3_ring", 0); + if (memfd < 0) + return MP3D_E_MEMORY; + +retry_ftruncate: + res = ftruncate(memfd, map_info->size); + if (res && (errno == EAGAIN || errno == EINTR)) + goto retry_ftruncate; + if (res) + goto error; + +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + if (MAP_FAILED == map_info->buffer || !map_info->buffer) + goto error; +retry_mmap2: + buffer = mmap((void *)map_info->buffer, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap2; + if (MAP_FAILED == map_info->buffer || buffer != (void *)map_info->buffer) + goto error; +retry_mmap3: + buffer = mmap((void *)map_info->buffer + map_info->size, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap3; + if (MAP_FAILED == map_info->buffer || buffer != (void *)(map_info->buffer + map_info->size)) + goto error; + + close(memfd); + return 0; +error: + close(memfd); + mp3dec_close_ring(map_info); + return MP3D_E_MEMORY; +#else + memfd = shmget(IPC_PRIVATE, map_info->size, IPC_CREAT | 0700); + if (memfd < 0) + return MP3D_E_MEMORY; +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_PRIVATE, -1, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + if (MAP_FAILED == map_info->buffer) + goto error; + if (map_info->buffer != shmat(memfd, map_info->buffer, 0)) + goto error; + if ((map_info->buffer + map_info->size) != shmat(memfd, map_info->buffer + map_info->size, 0)) + goto error; + if (shmctl(memfd, IPC_RMID, NULL) < 0) + return MP3D_E_MEMORY; + return 0; +error: + shmctl(memfd, IPC_RMID, NULL); + mp3dec_close_ring(map_info); + return MP3D_E_MEMORY; +#endif +} +#endif /*MINIMP3_ENABLE_RING*/ +#elif defined(_WIN32) +#include + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer) + UnmapViewOfFile(map_info->buffer); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file_h(HANDLE file, mp3dec_map_info_t *map_info) +{ + memset(map_info, 0, sizeof(*map_info)); + + HANDLE mapping = NULL; + LARGE_INTEGER s; + s.LowPart = GetFileSize(file, (DWORD*)&s.HighPart); + if (s.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) + goto error; + map_info->size = s.QuadPart; + + mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); + if (!mapping) + goto error; + map_info->buffer = (const uint8_t*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, s.QuadPart); + CloseHandle(mapping); + if (!map_info->buffer) + goto error; + + CloseHandle(file); + return 0; +error: + mp3dec_close_file(map_info); + CloseHandle(file); + return MP3D_E_IOERROR; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + HANDLE file = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE == file) + return MP3D_E_IOERROR; + return mp3dec_open_file_h(file, map_info); +} + +static int mp3dec_open_file_w(const wchar_t *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + HANDLE file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE == file) + return MP3D_E_IOERROR; + return mp3dec_open_file_h(file, map_info); +} +#else +#include + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer) + free((void *)map_info->buffer); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + memset(map_info, 0, sizeof(*map_info)); + FILE *file = fopen(file_name, "rb"); + if (!file) + return MP3D_E_IOERROR; + int res = MP3D_E_IOERROR; + long size = -1; + if (fseek(file, 0, SEEK_END)) + goto error; + size = ftell(file); + if (size < 0) + goto error; + map_info->size = (size_t)size; + if (fseek(file, 0, SEEK_SET)) + goto error; + map_info->buffer = (uint8_t *)malloc(map_info->size); + if (!map_info->buffer) + { + res = MP3D_E_MEMORY; + goto error; + } + if (fread((void *)map_info->buffer, 1, map_info->size, file) != map_info->size) + goto error; + fclose(file); + return 0; +error: + mp3dec_close_file(map_info); + fclose(file); + return res; +} +#endif + +static int mp3dec_detect_mapinfo(mp3dec_map_info_t *map_info) +{ + int ret = mp3dec_detect_buf(map_info->buffer, map_info->size); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_load_mapinfo(mp3dec_t *dec, mp3dec_map_info_t *map_info, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret = mp3dec_load_buf(dec, map_info->buffer, map_info->size, info, progress_cb, user_data); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_iterate_mapinfo(mp3dec_map_info_t *map_info, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret = mp3dec_iterate_buf(map_info->buffer, map_info->size, callback, user_data); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_ex_open_mapinfo(mp3dec_ex_t *dec, int flags) +{ + int ret = mp3dec_ex_open_buf(dec, dec->file.buffer, dec->file.size, flags); + dec->is_file = 1; + if (ret) + mp3dec_ex_close(dec); + return ret; +} + +int mp3dec_detect(const char *file_name) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_detect_mapinfo(&map_info); +} + +int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data); +} + +int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_iterate_mapinfo(&map_info, callback, user_data); +} + +int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int flags) +{ + int ret; + if (!dec) + return MP3D_E_PARAM; + if ((ret = mp3dec_open_file(file_name, &dec->file))) + return ret; + return mp3dec_ex_open_mapinfo(dec, flags); +} + +void mp3dec_ex_close(mp3dec_ex_t *dec) +{ +#ifdef MINIMP3_HAVE_RING + if (dec->io) + mp3dec_close_ring(&dec->file); +#else + if (dec->io && dec->file.buffer) + free((void*)dec->file.buffer); +#endif + if (dec->is_file) + mp3dec_close_file(&dec->file); + if (dec->index.frames) + free(dec->index.frames); + memset(dec, 0, sizeof(*dec)); +} + +#ifdef _WIN32 +int mp3dec_detect_w(const wchar_t *file_name) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_detect_mapinfo(&map_info); +} + +int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data); +} + +int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_iterate_mapinfo(&map_info, callback, user_data); +} + +int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int flags) +{ + int ret; + if ((ret = mp3dec_open_file_w(file_name, &dec->file))) + return ret; + return mp3dec_ex_open_mapinfo(dec, flags); +} +#endif +#else /* MINIMP3_NO_STDIO */ +void mp3dec_ex_close(mp3dec_ex_t *dec) +{ +#ifdef MINIMP3_HAVE_RING + if (dec->io) + mp3dec_close_ring(&dec->file); +#else + if (dec->io && dec->file.buffer) + free((void*)dec->file.buffer); +#endif + if (dec->index.frames) + free(dec->index.frames); + memset(dec, 0, sizeof(*dec)); +} +#endif + +#endif /* MINIMP3_IMPLEMENTATION && !_MINIMP3_EX_IMPLEMENTATION_GUARD */ diff --git a/ext/miniupnp b/ext/miniupnp index 3a87be33e7..27d13ca9be 160000 --- a/ext/miniupnp +++ b/ext/miniupnp @@ -1 +1 @@ -Subproject commit 3a87be33e797ba947b2b2a5f8d087f6c3ff4d93e +Subproject commit 27d13ca9beeb5541f5fbf11959dced03dac39972 diff --git a/ext/miniupnp-build/Android.mk b/ext/miniupnp-build/Android.mk index de01487070..64e37da4b8 100644 --- a/ext/miniupnp-build/Android.mk +++ b/ext/miniupnp-build/Android.mk @@ -7,26 +7,26 @@ include $(CLEAR_VARS) LOCAL_MODULE := libminiupnp-build LOCAL_ARM_MODE := arm LOCAL_SRC_FILES := \ - ../miniupnp/miniupnpc/addr_is_reserved.c \ - ../miniupnp/miniupnpc/connecthostport.c \ - ../miniupnp/miniupnpc/igd_desc_parse.c \ - ../miniupnp/miniupnpc/minisoap.c \ - ../miniupnp/miniupnpc/minissdpc.c \ - ../miniupnp/miniupnpc/miniupnpc.c \ - ../miniupnp/miniupnpc/miniwget.c \ - ../miniupnp/miniupnpc/minixml.c \ - ../miniupnp/miniupnpc/minixmlvalid.c \ - ../miniupnp/miniupnpc/portlistingparse.c \ - ../miniupnp/miniupnpc/receivedata.c \ - ../miniupnp/miniupnpc/upnpcommands.c \ - ../miniupnp/miniupnpc/upnpdev.c \ - ../miniupnp/miniupnpc/upnperrors.c \ - ../miniupnp/miniupnpc/upnpreplyparse.c + ../miniupnp/miniupnpc/src/addr_is_reserved.c \ + ../miniupnp/miniupnpc/src/connecthostport.c \ + ../miniupnp/miniupnpc/src/igd_desc_parse.c \ + ../miniupnp/miniupnpc/src/minisoap.c \ + ../miniupnp/miniupnpc/src/minissdpc.c \ + ../miniupnp/miniupnpc/src/miniupnpc.c \ + ../miniupnp/miniupnpc/src/miniwget.c \ + ../miniupnp/miniupnpc/src/minixml.c \ + ../miniupnp/miniupnpc/src/minixmlvalid.c \ + ../miniupnp/miniupnpc/src/portlistingparse.c \ + ../miniupnp/miniupnpc/src/receivedata.c \ + ../miniupnp/miniupnpc/src/upnpcommands.c \ + ../miniupnp/miniupnpc/src/upnpdev.c \ + ../miniupnp/miniupnpc/src/upnperrors.c \ + ../miniupnp/miniupnpc/src/upnpreplyparse.c LOCAL_CFLAGS := -O3 -fsigned-char -fno-strict-aliasing -Wall -Wno-multichar -D__STDC_CONSTANT_MACROS LOCAL_CPPFLAGS := -fno-exceptions -std=gnu++11 -fno-rtti -Wno-reorder # Note: LOCAL_PATH is the directory this file is in. -LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. $(LOCAL_PATH)/../miniupnp .. +LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. $(LOCAL_PATH)/../miniupnp/miniupnpc/src $(LOCAL_PATH)/../miniupnp/miniupnpc/include .. ifeq ($(findstring armeabi-v7a,$(TARGET_ARCH_ABI)),armeabi-v7a) LOCAL_CFLAGS := $(LOCAL_CFLAGS) diff --git a/ext/miniupnpc.vcxproj b/ext/miniupnpc.vcxproj index f69e726242..f7a9e77562 100644 --- a/ext/miniupnpc.vcxproj +++ b/ext/miniupnpc.vcxproj @@ -35,44 +35,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16.0 {D8A71225-178B-424E-96C1-CC3BE2C1B047} @@ -228,6 +222,7 @@ ProgramDatabase true MultiThreadedDebug + miniupnp/miniupnpc/include;miniupnp-build Windows @@ -257,6 +252,7 @@ cd..\..\.. Default MultiThreadedDebug false + miniupnp/miniupnpc/include;miniupnp-build Windows @@ -288,6 +284,7 @@ cd..\..\.. false MultiThreaded StreamingSIMDExtensions2 + miniupnp/miniupnpc/include;miniupnp-build Windows @@ -322,6 +319,7 @@ cd..\..\.. false false false + miniupnp/miniupnpc/include;miniupnp-build Windows @@ -351,6 +349,7 @@ cd..\..\.. DEBUG;_DEBUG;WIN32;_LIB;MINIUPNP_STATICLIB;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) MultiThreadedDebug false + miniupnp/miniupnpc/include;miniupnp-build iphlpapi.lib @@ -369,6 +368,7 @@ cd..\..\.. DEBUG;_DEBUG;WIN32;_LIB;MINIUPNP_STATICLIB;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) MultiThreadedDebug false + miniupnp/miniupnpc/include;miniupnp-build iphlpapi.lib @@ -392,6 +392,7 @@ cd..\..\.. true false false + miniupnp/miniupnpc/include;miniupnp-build iphlpapi.lib @@ -415,6 +416,7 @@ cd..\..\.. false false true + miniupnp/miniupnpc/include;miniupnp-build iphlpapi.lib diff --git a/ext/miniupnpc.vcxproj.filters b/ext/miniupnpc.vcxproj.filters index 8ecbe2bfcf..b2ce7c117b 100644 --- a/ext/miniupnpc.vcxproj.filters +++ b/ext/miniupnpc.vcxproj.filters @@ -1,38 +1,5 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {c82edf03-bf88-478d-aaf5-2854df756cab} @@ -42,6 +9,33 @@ scripts - + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/native/tools/CMakeLists.txt b/ext/native/tools/CMakeLists.txt index 0547a25af7..2f939d89c1 100644 --- a/ext/native/tools/CMakeLists.txt +++ b/ext/native/tools/CMakeLists.txt @@ -1,44 +1,42 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.16)) +project(Tools) -project (Tools) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -add_definitions(-O2) -add_definitions(-Wall) -add_definitions(-DSDL) -add_definitions(-Wno-multichar) -add_definitions(-fno-strict-aliasing) -#add_definitions(-fopenmp) +add_compile_definitions(SDL MAX_LOGLEVEL=-1) +add_compile_options(-O2 -Wall -Wno-multichar -fno-strict-aliasing) +# Obsolete code? if(IOS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -DMAX_LOGLEVEL=-1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++") elseif(APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -mmacosx-version-min=10.7 -DMAX_LOGLEVEL=-1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -mmacosx-version-min=10.7") endif() -if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.0) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -DMAX_LOGLEVEL=-1") -else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DMAX_LOGLEVEL=-1") -endif() +# Find dependencies +find_package(Freetype REQUIRED) +find_package(ZLIB REQUIRED) +find_library(UTIL util REQUIRED) +find_library(ZSTD zstd REQUIRED) -# add_definitions(-fstrict-aliasing) - -include_directories(..) -include_directories(../..) -include_directories(../../..) - -link_directories(/opt/local/lib) - -# Horrible horrible hack -include_directories(/usr/include/freetype2) -include_directories(/usr/local/include/freetype2) -include_directories(/opt/local/include/freetype2) -include_directories(/opt/local/include) +include_directories(${FREETYPE_INCLUDE_DIRS} + ../ + ../../ + ../../../ +) add_subdirectory(../../libpng17 png17) -add_executable(build/atlastool atlastool.cpp ../../../Common/Data/Format/PNGLoad.cpp ../../../Common/Data/Encoding/Utf8.cpp ../../../Common/Data/Format/ZIMSave.cpp) -target_link_libraries(build/atlastool freetype util png17 z zstd) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build) -add_executable(build/zimtool zimtool.cpp ../../../Common/Data/Format/PNGLoad.cpp ../../../Common/Data/Format/ZIMSave.cpp) -target_link_libraries(build/zimtool freetype util png17 z zstd) +set(COMMON_FILES + ../../../Common/Data/Format/PNGLoad.cpp + ../../../Common/Data/Format/ZIMSave.cpp +) + +# Both executables are linked to the same libraries +link_libraries(${FREETYPE_LIBRARIES} ${UTIL} png17 ${ZLIB_LIBRARIES} ${ZSTD}) + +add_executable(atlastool atlastool.cpp ../../../Common/Data/Encoding/Utf8.cpp ${COMMON_FILES}) +add_executable(zimtool zimtool.cpp ${COMMON_FILES}) diff --git a/ext/rcheevos b/ext/rcheevos index a6cdbb4a52..563230b1c2 160000 --- a/ext/rcheevos +++ b/ext/rcheevos @@ -1 +1 @@ -Subproject commit a6cdbb4a529d85b74777597fcff037dde7bef66b +Subproject commit 563230b1c249774b4852c944dc7cdcb952c9e8e8 diff --git a/ext/rcheevos-build/rcheevos.vcxproj b/ext/rcheevos-build/rcheevos.vcxproj index 79b363f0d1..cf48da65c5 100644 --- a/ext/rcheevos-build/rcheevos.vcxproj +++ b/ext/rcheevos-build/rcheevos.vcxproj @@ -55,6 +55,7 @@ + @@ -174,7 +175,7 @@ Level3 - RC_DISABLE_LUA;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + RC_DISABLE_LUA;RC_CLIENT_SUPPORTS_RAINTEGRATION;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true pch.h ../rcheevos/include @@ -217,7 +218,7 @@ MaxSpeed true true - RC_DISABLE_LUA;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + RC_DISABLE_LUA;RC_CLIENT_SUPPORTS_RAINTEGRATION;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true pch.h ../rcheevos/include @@ -268,7 +269,7 @@ Level3 true - RC_DISABLE_LUA;_DEBUG;_LIB;%(PreprocessorDefinitions) + RC_DISABLE_LUA;RC_CLIENT_SUPPORTS_RAINTEGRATION;_DEBUG;_LIB;%(PreprocessorDefinitions) true pch.h ../rcheevos/include @@ -314,7 +315,7 @@ MaxSpeed true true - RC_DISABLE_LUA;NDEBUG;_LIB;%(PreprocessorDefinitions) + RC_DISABLE_LUA;RC_CLIENT_SUPPORTS_RAINTEGRATION;NDEBUG;_LIB;%(PreprocessorDefinitions) true pch.h ../rcheevos/include diff --git a/ext/rcheevos-build/rcheevos.vcxproj.filters b/ext/rcheevos-build/rcheevos.vcxproj.filters index ecfebb17c1..3428444b59 100644 --- a/ext/rcheevos-build/rcheevos.vcxproj.filters +++ b/ext/rcheevos-build/rcheevos.vcxproj.filters @@ -84,6 +84,9 @@ rhash + + rcheevos + diff --git a/ext/vma/vk_mem_alloc.h b/ext/vma/vk_mem_alloc.h index 90719c1615..41b1e466d5 100644 --- a/ext/vma/vk_mem_alloc.h +++ b/ext/vma/vk_mem_alloc.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2017-2024 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -43,14 +43,17 @@ /** \mainpage Vulkan Memory Allocator -Version 3.1.0-development +Version 3.1.0 -Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved. \n -License: MIT +Copyright (c) 2017-2024 Advanced Micro Devices, Inc. All rights reserved. \n +License: MIT \n +See also: [product page on GPUOpen](https://gpuopen.com/gaming-product/vulkan-memory-allocator/), +[repository on GitHub](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) -API documentation divided into groups: [Modules](modules.html) -\section main_table_of_contents Table of contents +API documentation divided into groups: [Topics](topics.html) + +General documentation chapters: - User guide - \subpage quick_start @@ -64,6 +67,7 @@ License: MIT - [Custom memory pools](@ref choosing_memory_type_custom_memory_pools) - [Dedicated allocations](@ref choosing_memory_type_dedicated_allocations) - \subpage memory_mapping + - [Copy functions](@ref memory_mapping_copy_functions) - [Mapping functions](@ref memory_mapping_mapping_functions) - [Persistently mapped memory](@ref memory_mapping_persistently_mapped_memory) - [Cache flush and invalidate](@ref memory_mapping_cache_control) @@ -73,6 +77,7 @@ License: MIT - \subpage resource_aliasing - \subpage custom_memory_pools - [Choosing memory type index](@ref custom_memory_pools_MemTypeIndex) + - [When not to use custom pools](@ref custom_memory_pools_when_not_use) - [Linear allocation algorithm](@ref linear_algorithm) - [Free-at-once](@ref linear_algorithm_free_at_once) - [Stack](@ref linear_algorithm_stack) @@ -90,7 +95,8 @@ License: MIT - [Memory initialization](@ref debugging_memory_usage_initialization) - [Margins](@ref debugging_memory_usage_margins) - [Corruption detection](@ref debugging_memory_usage_corruption_detection) - - \subpage opengl_interop + - [Leak detection features](@ref debugging_memory_usage_leak_detection) + - \subpage other_api_interop - \subpage usage_patterns - [GPU-only resource](@ref usage_patterns_gpu_only) - [Staging copy for upload](@ref usage_patterns_staging_copy_upload) @@ -114,11 +120,6 @@ License: MIT - [Allocation algorithm](@ref general_considerations_allocation_algorithm) - [Features not supported](@ref general_considerations_features_not_supported) -\section main_see_also See also - -- [**Product page on GPUOpen**](https://gpuopen.com/gaming-product/vulkan-memory-allocator/) -- [**Source repository on GitHub**](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) - \defgroup group_init Library initialization \brief API elements related to the initialization and management of the entire library, especially #VmaAllocator object. @@ -139,13 +140,12 @@ for user-defined purpose without allocating any real GPU memory. See documentation chapter: \ref statistics. */ - #ifdef __cplusplus extern "C" { #endif -#ifndef VULKAN_H_ - #include +#ifndef VULKAN_H_ // PPSSPP HACK +#include #endif #if !defined(VMA_VULKAN_VERSION) @@ -231,6 +231,25 @@ extern "C" { #endif #endif +// Defined to 1 when VK_KHR_maintenance4 device extension is defined in Vulkan headers. +#if !defined(VMA_KHR_MAINTENANCE4) + #if VK_KHR_maintenance4 + #define VMA_KHR_MAINTENANCE4 1 + #else + #define VMA_KHR_MAINTENANCE4 0 + #endif +#endif + +// Defined to 1 when VK_KHR_maintenance5 device extension is defined in Vulkan headers. +#if !defined(VMA_KHR_MAINTENANCE5) + #if VK_KHR_maintenance5 + #define VMA_KHR_MAINTENANCE5 1 + #else + #define VMA_KHR_MAINTENANCE5 0 + #endif +#endif + + // Defined to 1 when VK_KHR_external_memory device extension is defined in Vulkan headers. #if !defined(VMA_EXTERNAL_MEMORY) #if VK_KHR_external_memory @@ -252,6 +271,12 @@ extern "C" { #define VMA_CALL_POST #endif +// Define this macro to decorate pNext pointers with an attribute specifying the Vulkan +// structure that will be extended via the pNext chain. +#ifndef VMA_EXTENDS_VK_STRUCT + #define VMA_EXTENDS_VK_STRUCT(vkStruct) +#endif + // Define this macro to decorate pointers with an attribute specifying the // length of the array they point to if they are not null. // @@ -438,6 +463,20 @@ typedef enum VmaAllocatorCreateFlagBits For more details, see the documentation of the VK_EXT_memory_priority extension. */ VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT = 0x00000040, + /** + Enables usage of VK_KHR_maintenance4 extension in the library. + + You may set this flag only if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + */ + VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT = 0x00000080, + /** + Enables usage of VK_KHR_maintenance5 extension in the library. + + You should set this flag if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + */ + VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100, VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VmaAllocatorCreateFlagBits; @@ -539,6 +578,9 @@ typedef enum VmaAllocationCreateFlagBits /** \brief Set this flag if the allocation should have its own memory block. Use it for special, big resources, like fullscreen images used as attachments. + + If you use this flag while creating a buffer or an image, `VkMemoryDedicatedAllocateInfo` + structure is applied if possible. */ VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, @@ -620,7 +662,7 @@ typedef enum VmaAllocationCreateFlagBits This includes allocations created in \ref custom_memory_pools. Declares that mapped memory can be read, written, and accessed in random order, - so a `HOST_CACHED` memory type is required. + so a `HOST_CACHED` memory type is preferred. */ VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT = 0x00000800, /** @@ -902,7 +944,7 @@ Use it as a unique identifier to virtual allocation within the single block. Use value `VK_NULL_HANDLE` to represent a null/invalid allocation. */ -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaVirtualAllocation); +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaVirtualAllocation) /** @} */ @@ -1001,13 +1043,14 @@ typedef struct VmaVulkanFunctions PFN_vkBindImageMemory2KHR VMA_NULLABLE vkBindImageMemory2KHR; #endif #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 + /// Fetch from "vkGetPhysicalDeviceMemoryProperties2" on Vulkan >= 1.1, but you can also fetch it from "vkGetPhysicalDeviceMemoryProperties2KHR" if you enabled extension VK_KHR_get_physical_device_properties2. PFN_vkGetPhysicalDeviceMemoryProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties2KHR; #endif -#if VMA_VULKAN_VERSION >= 1003000 +#if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 /// Fetch from "vkGetDeviceBufferMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceBufferMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. - PFN_vkGetDeviceBufferMemoryRequirements VMA_NULLABLE vkGetDeviceBufferMemoryRequirements; + PFN_vkGetDeviceBufferMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceBufferMemoryRequirements; /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. - PFN_vkGetDeviceImageMemoryRequirements VMA_NULLABLE vkGetDeviceImageMemoryRequirements; + PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements; #endif } VmaVulkanFunctions; @@ -1067,13 +1110,15 @@ typedef struct VmaAllocatorCreateInfo Starting from version 3.0.0 this member is no longer optional, it must be set! */ VkInstance VMA_NOT_NULL instance; - /** \brief Optional. The highest version of Vulkan that the application is designed to use. + /** \brief Optional. Vulkan version that the application uses. It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. The patch version number specified is ignored. Only the major and minor versions are considered. - It must be less or equal (preferably equal) to value as passed to `vkCreateInstance` as `VkApplicationInfo::apiVersion`. Only versions 1.0, 1.1, 1.2, 1.3 are supported by the current implementation. Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. + It must match the Vulkan version used by the application and supported on the selected physical device, + so it must be no higher than `VkApplicationInfo::apiVersion` passed to `vkCreateInstance` + and no higher than `VkPhysicalDeviceProperties::apiVersion` found on the physical device used. */ uint32_t vulkanApiVersion; #if VMA_EXTERNAL_MEMORY @@ -1337,7 +1382,7 @@ typedef struct VmaPoolCreateInfo Please note that some structures, e.g. `VkMemoryPriorityAllocateInfoEXT`, `VkMemoryDedicatedAllocateInfoKHR`, can be attached automatically by this library when using other, more convenient of its features. */ - void* VMA_NULLABLE pMemoryAllocateNext; + void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkMemoryAllocateInfo) pMemoryAllocateNext; } VmaPoolCreateInfo; /** @} */ @@ -1347,7 +1392,11 @@ typedef struct VmaPoolCreateInfo @{ */ -/// Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). +/** +Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). + +There is also an extended version of this structure that carries additional parameters: #VmaAllocationInfo2. +*/ typedef struct VmaAllocationInfo { /** \brief Memory type index that this allocation was allocated from. @@ -1407,6 +1456,33 @@ typedef struct VmaAllocationInfo const char* VMA_NULLABLE pName; } VmaAllocationInfo; +/// Extended parameters of a #VmaAllocation object that can be retrieved using function vmaGetAllocationInfo2(). +typedef struct VmaAllocationInfo2 +{ + /** \brief Basic parameters of the allocation. + + If you need only these, you can use function vmaGetAllocationInfo() and structure #VmaAllocationInfo instead. + */ + VmaAllocationInfo allocationInfo; + /** \brief Size of the `VkDeviceMemory` block that the allocation belongs to. + + In case of an allocation with dedicated memory, it will be equal to `allocationInfo.size`. + */ + VkDeviceSize blockSize; + /** \brief `VK_TRUE` if the allocation has dedicated memory, `VK_FALSE` if it was placed as part of a larger memory block. + + When `VK_TRUE`, it also means `VkMemoryDedicatedAllocateInfo` was used when creating the allocation + (if VK_KHR_dedicated_allocation extension or Vulkan version >= 1.1 is enabled). + */ + VkBool32 dedicatedMemory; +} VmaAllocationInfo2; + +/** Callback function called during vmaBeginDefragmentation() to check custom criterion about ending current defragmentation pass. + +Should return true if the defragmentation needs to stop current pass. +*/ +typedef VkBool32 (VKAPI_PTR* PFN_vmaCheckDefragmentationBreakFunction)(void* VMA_NULLABLE pUserData); + /** \brief Parameters for defragmentation. To be used with function vmaBeginDefragmentation(). @@ -1430,6 +1506,13 @@ typedef struct VmaDefragmentationInfo `0` means no limit. */ uint32_t maxAllocationsPerPass; + /** \brief Optional custom callback for stopping vmaBeginDefragmentation(). + + Have to return true for breaking current defragmentation pass. + */ + PFN_vmaCheckDefragmentationBreakFunction VMA_NULLABLE pfnBreakCallback; + /// \brief Optional data to pass to custom callback for stopping pass of defragmentation. + void* VMA_NULLABLE pBreakCallbackUserData; } VmaDefragmentationInfo; /// Single move of an allocation to be done for defragmentation. @@ -1930,12 +2013,27 @@ you should avoid calling it too often. You can retrieve same VmaAllocationInfo structure while creating your resource, from function vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change (e.g. due to defragmentation). + +There is also a new function vmaGetAllocationInfo2() that offers extended information +about the allocation, returned using new structure #VmaAllocationInfo2. */ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( VmaAllocator VMA_NOT_NULL allocator, VmaAllocation VMA_NOT_NULL allocation, VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo); +/** \brief Returns extended information about specified allocation. + +Current parameters of given allocation are returned in `pAllocationInfo`. +Extended parameters in structure #VmaAllocationInfo2 include memory block size +and a flag telling whether the allocation has dedicated memory. +It can be useful e.g. for interop with OpenGL. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VmaAllocationInfo2* VMA_NOT_NULL pAllocationInfo); + /** \brief Sets pUserData in given allocation to new value. The value of pointer `pUserData` is copied to allocation's `pUserData`. @@ -2087,7 +2185,7 @@ For more information, see documentation of vmaFlushAllocation(). \param allocator \param allocationCount \param allocations -\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all ofsets are zero. +\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. \param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is @@ -2108,7 +2206,7 @@ For more information, see documentation of vmaInvalidateAllocation(). \param allocator \param allocationCount \param allocations -\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all ofsets are zero. +\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. \param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if it is @@ -2121,6 +2219,61 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); +/** \brief Maps the allocation temporarily if needed, copies data from specified host pointer to it, and flushes the memory from the host caches if needed. + +\param allocator +\param pSrcHostPointer Pointer to the host data that become source of the copy. +\param dstAllocation Handle to the allocation that becomes destination of the copy. +\param dstAllocationLocalOffset Offset within `dstAllocation` where to write copied data, in bytes. +\param size Number of bytes to copy. + +This is a convenience function that allows to copy data from a host pointer to an allocation easily. +Same behavior can be achieved by calling vmaMapMemory(), `memcpy()`, vmaUnmapMemory(), vmaFlushAllocation(). + +This function can be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. +It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or +#VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +Otherwise, the function will fail and generate a Validation Layers error. + +`dstAllocationLocalOffset` is relative to the contents of given `dstAllocation`. +If you mean whole allocation, you should pass 0. +Do not pass allocation's offset within device memory block this parameter! +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( + VmaAllocator VMA_NOT_NULL allocator, + const void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pSrcHostPointer, + VmaAllocation VMA_NOT_NULL dstAllocation, + VkDeviceSize dstAllocationLocalOffset, + VkDeviceSize size); + +/** \brief Invalidates memory in the host caches if needed, maps the allocation temporarily if needed, and copies data from it to a specified host pointer. + +\param allocator +\param srcAllocation Handle to the allocation that becomes source of the copy. +\param srcAllocationLocalOffset Offset within `srcAllocation` where to read copied data, in bytes. +\param pDstHostPointer Pointer to the host memory that become destination of the copy. +\param size Number of bytes to copy. + +This is a convenience function that allows to copy data from an allocation to a host pointer easily. +Same behavior can be achieved by calling vmaInvalidateAllocation(), vmaMapMemory(), `memcpy()`, vmaUnmapMemory(). + +This function should be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` +and `VK_MEMORY_PROPERTY_HOST_CACHED_BIT` flag. +It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +Otherwise, the function may fail and generate a Validation Layers error. +It may also work very slowly when reading from an uncached memory. + +`srcAllocationLocalOffset` is relative to the contents of given `srcAllocation`. +If you mean whole allocation, you should pass 0. +Do not pass allocation's offset within device memory block as this parameter! +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL srcAllocation, + VkDeviceSize srcAllocationLocalOffset, + void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pDstHostPointer, + VkDeviceSize size); + /** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. \param allocator @@ -2245,7 +2398,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( VmaAllocation VMA_NOT_NULL allocation, VkDeviceSize allocationLocalOffset, VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, - const void* VMA_NULLABLE pNext); + const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindBufferMemoryInfoKHR) pNext); /** \brief Binds image to allocation. @@ -2282,7 +2435,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( VmaAllocation VMA_NOT_NULL allocation, VkDeviceSize allocationLocalOffset, VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, - const void* VMA_NULLABLE pNext); + const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindImageMemoryInfoKHR) pNext); /** \brief Creates a new `VkBuffer`, allocates and binds memory for it. @@ -2622,15 +2775,27 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( #include #include #include +#include #include #include -#include + +#if !defined(VMA_CPP20) + #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 + #define VMA_CPP20 1 + #else + #define VMA_CPP20 0 + #endif +#endif #ifdef _MSC_VER #include // For functions like __popcnt, _BitScanForward etc. #endif -#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 - #include // For std::popcount +#if VMA_CPP20 + #include +#endif + +#if VMA_STATS_STRING_ENABLED + #include // For snprintf #endif /******************************************************************************* @@ -2666,8 +2831,7 @@ VmaAllocatorCreateInfo::pVulkanFunctions. Other members can be null. #endif #ifndef VMA_USE_STL_SHARED_MUTEX - // Compiler conforms to C++17. - #if __cplusplus >= 201703L + #if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 #define VMA_USE_STL_SHARED_MUTEX 1 // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus // Otherwise it is always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2. @@ -2701,7 +2865,7 @@ remove them if not needed. */ #if !defined(VMA_CONFIGURATION_USER_INCLUDES_H) #include // for assert - #include // for min, max + #include // for min, max, swap #include #else #include VMA_CONFIGURATION_USER_INCLUDES_H @@ -2712,6 +2876,43 @@ remove them if not needed. #define VMA_NULL nullptr #endif +#ifndef VMA_FALLTHROUGH + #if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 + #define VMA_FALLTHROUGH [[fallthrough]] + #else + #define VMA_FALLTHROUGH + #endif +#endif + +// Normal assert to check for programmer's errors, especially in Debug configuration. +#ifndef VMA_ASSERT + #ifdef NDEBUG + #define VMA_ASSERT(expr) + #else + #define VMA_ASSERT(expr) assert(expr) + #endif +#endif + +// Assert that will be called very often, like inside data structures e.g. operator[]. +// Making it non-empty can make program slow. +#ifndef VMA_HEAVY_ASSERT + #ifdef NDEBUG + #define VMA_HEAVY_ASSERT(expr) + #else + #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) + #endif +#endif + +// Assert used for reporting memory leaks - unfreed allocations. +#ifndef VMA_ASSERT_LEAK + #define VMA_ASSERT_LEAK(expr) VMA_ASSERT(expr) +#endif + +// If your compiler is not compatible with C++17 and definition of +// aligned_alloc() function is missing, uncommenting following line may help: + +//#include + #if defined(__ANDROID_API__) && (__ANDROID_API__ < 16) #include static void* vma_aligned_alloc(size_t alignment, size_t size) @@ -2764,11 +2965,17 @@ static void* vma_aligned_alloc(size_t alignment, size_t size) { return _aligned_malloc(size, alignment); } -#else +#elif __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 static void* vma_aligned_alloc(size_t alignment, size_t size) { return aligned_alloc(alignment, size); } +#else +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + VMA_ASSERT(0 && "Could not implement aligned_alloc automatically. Please enable C++17 or later in your compiler or provide custom implementation of macro VMA_SYSTEM_ALIGNED_MALLOC (and VMA_SYSTEM_ALIGNED_FREE if needed) using the API of your system."); + return VMA_NULL; +} #endif #if defined(_WIN32) @@ -2783,32 +2990,8 @@ static void vma_aligned_free(void* VMA_NULLABLE ptr) } #endif -// If your compiler is not compatible with C++11 and definition of -// aligned_alloc() function is missing, uncommeting following line may help: - -//#include - -// Normal assert to check for programmer's errors, especially in Debug configuration. -#ifndef VMA_ASSERT - #ifdef NDEBUG - #define VMA_ASSERT(expr) - #else - #define VMA_ASSERT(expr) assert(expr) - #endif -#endif - -// Assert that will be called very often, like inside data structures e.g. operator[]. -// Making it non-empty can make program slow. -#ifndef VMA_HEAVY_ASSERT - #ifdef NDEBUG - #define VMA_HEAVY_ASSERT(expr) - #else - #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) - #endif -#endif - #ifndef VMA_ALIGN_OF - #define VMA_ALIGN_OF(type) (__alignof(type)) + #define VMA_ALIGN_OF(type) (alignof(type)) #endif #ifndef VMA_SYSTEM_ALIGNED_MALLOC @@ -2847,33 +3030,52 @@ static void vma_aligned_free(void* VMA_NULLABLE ptr) #define VMA_MAX(v1, v2) ((std::max)((v1), (v2))) #endif -#ifndef VMA_SWAP - #define VMA_SWAP(v1, v2) std::swap((v1), (v2)) -#endif - #ifndef VMA_SORT #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) #endif -#ifndef VMA_DEBUG_LOG - #define VMA_DEBUG_LOG(format, ...) +#ifndef VMA_DEBUG_LOG_FORMAT + #define VMA_DEBUG_LOG_FORMAT(format, ...) /* - #define VMA_DEBUG_LOG(format, ...) do { \ - printf(format, __VA_ARGS__); \ + #define VMA_DEBUG_LOG_FORMAT(format, ...) do { \ + printf((format), __VA_ARGS__); \ printf("\n"); \ } while(false) */ #endif +#ifndef VMA_DEBUG_LOG + #define VMA_DEBUG_LOG(str) VMA_DEBUG_LOG_FORMAT("%s", (str)) +#endif + +#ifndef VMA_LEAK_LOG_FORMAT + #define VMA_LEAK_LOG_FORMAT(format, ...) VMA_DEBUG_LOG_FORMAT(format, __VA_ARGS__) +#endif + +#ifndef VMA_CLASS_NO_COPY + #define VMA_CLASS_NO_COPY(className) \ + private: \ + className(const className&) = delete; \ + className& operator=(const className&) = delete; +#endif +#ifndef VMA_CLASS_NO_COPY_NO_MOVE + #define VMA_CLASS_NO_COPY_NO_MOVE(className) \ + private: \ + className(const className&) = delete; \ + className(className&&) = delete; \ + className& operator=(const className&) = delete; \ + className& operator=(className&&) = delete; +#endif + // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString. #if VMA_STATS_STRING_ENABLED static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num) { - snprintf(outStr, strLen, "%u", static_cast(num)); + snprintf(outStr, strLen, "%" PRIu32, num); } static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num) { - snprintf(outStr, strLen, "%llu", static_cast(num)); + snprintf(outStr, strLen, "%" PRIu64, num); } static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr) { @@ -2884,7 +3086,9 @@ static void vma_aligned_free(void* VMA_NULLABLE ptr) #ifndef VMA_MUTEX class VmaMutex { + VMA_CLASS_NO_COPY_NO_MOVE(VmaMutex) public: + VmaMutex() { } void Lock() { m_Mutex.lock(); } void Unlock() { m_Mutex.unlock(); } bool TryLock() { return m_Mutex.try_lock(); } @@ -3044,19 +3248,12 @@ Mapping hysteresis is a logic that launches when vmaMapMemory/vmaUnmapMemory is or a persistently mapped allocation is created and destroyed several times in a row. It keeps additional +1 mapping of a device memory block to prevent calling actual vkMapMemory/vkUnmapMemory too many times, which may improve performance and help -tools like RenderDOc. +tools like RenderDoc. */ #ifndef VMA_MAPPING_HYSTERESIS_ENABLED #define VMA_MAPPING_HYSTERESIS_ENABLED 1 #endif -#ifndef VMA_CLASS_NO_COPY - #define VMA_CLASS_NO_COPY(className) \ - private: \ - className(const className&) = delete; \ - className& operator=(const className&) = delete; -#endif - #define VMA_VALIDATE(cond) do { if(!(cond)) { \ VMA_ASSERT(0 && "Validation failed: " #cond); \ return false; \ @@ -3172,17 +3369,6 @@ class VmaList; template class VmaIntrusiveLinkedList; -// Unused in this version -#if 0 -template -struct VmaPair; -template -struct VmaPairFirstLess; - -template -class VmaMap; -#endif - #if VMA_STATS_STRING_ENABLED class VmaStringBuilder; class VmaJsonWriter; @@ -3222,7 +3408,7 @@ class VmaAllocationObjectAllocator; /* Returns number of bits set to 1 in (v). -On specific platforms and compilers you can use instrinsics like: +On specific platforms and compilers you can use intrinsics like: Visual Studio: return __popcnt(v); @@ -3234,7 +3420,7 @@ But you need to check in runtime whether user's CPU supports these, as some old */ static inline uint32_t VmaCountBitsSet(uint32_t v) { -#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 +#if VMA_CPP20 return std::popcount(v); #else uint32_t c = v - ((v >> 1) & 0x55555555); @@ -3253,6 +3439,10 @@ static inline uint8_t VmaBitScanLSB(uint64_t mask) if (_BitScanForward64(&pos, mask)) return static_cast(pos); return UINT8_MAX; +#elif VMA_CPP20 + if(mask) + return static_cast(std::countr_zero(mask)); + return UINT8_MAX; #elif defined __GNUC__ || defined __clang__ return static_cast(__builtin_ffsll(mask)) - 1U; #else @@ -3275,6 +3465,10 @@ static inline uint8_t VmaBitScanLSB(uint32_t mask) if (_BitScanForward(&pos, mask)) return static_cast(pos); return UINT8_MAX; +#elif VMA_CPP20 + if(mask) + return static_cast(std::countr_zero(mask)); + return UINT8_MAX; #elif defined __GNUC__ || defined __clang__ return static_cast(__builtin_ffs(mask)) - 1U; #else @@ -3296,6 +3490,9 @@ static inline uint8_t VmaBitScanMSB(uint64_t mask) unsigned long pos; if (_BitScanReverse64(&pos, mask)) return static_cast(pos); +#elif VMA_CPP20 + if(mask) + return 63 - static_cast(std::countl_zero(mask)); #elif defined __GNUC__ || defined __clang__ if (mask) return 63 - static_cast(__builtin_clzll(mask)); @@ -3318,6 +3515,9 @@ static inline uint8_t VmaBitScanMSB(uint32_t mask) unsigned long pos; if (_BitScanReverse(&pos, mask)) return static_cast(pos); +#elif VMA_CPP20 + if(mask) + return 31 - static_cast(std::countl_zero(mask)); #elif defined __GNUC__ || defined __clang__ if (mask) return 31 - static_cast(__builtin_clz(mask)); @@ -3354,7 +3554,7 @@ static inline T VmaAlignUp(T val, T alignment) return (val + alignment - 1) & ~(alignment - 1); } -// Aligns given value down to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 8. +// Aligns given value down to nearest multiply of align value. For example: VmaAlignDown(11, 8) = 8. // Use types like uint32_t, uint64_t as T. template static inline T VmaAlignDown(T val, T alignment) @@ -3465,7 +3665,7 @@ static inline bool VmaIsBufferImageGranularityConflict( { if (suballocType1 > suballocType2) { - VMA_SWAP(suballocType1, suballocType2); + std::swap(suballocType1, suballocType2); } switch (suballocType1) @@ -3549,7 +3749,7 @@ new element with value (key) should be inserted. template static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp) { - size_t down = 0, up = (end - beg); + size_t down = 0, up = size_t(end - beg); while (down < up) { const size_t mid = down + (up - down) / 2; // Overflow-safe midpoint calculation @@ -3610,13 +3810,95 @@ static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct) newStruct->pNext = mainStruct->pNext; mainStruct->pNext = newStruct; } +// Finds structure with s->sType == sType in mainStruct->pNext chain. +// Returns pointer to it. If not found, returns null. +template +static inline const FindT* VmaPnextChainFind(const MainT* mainStruct, VkStructureType sType) +{ + for(const VkBaseInStructure* s = (const VkBaseInStructure*)mainStruct->pNext; + s != VMA_NULL; s = s->pNext) + { + if(s->sType == sType) + { + return (const FindT*)s; + } + } + return VMA_NULL; +} + +// An abstraction over buffer or image `usage` flags, depending on available extensions. +struct VmaBufferImageUsage +{ +#if VMA_KHR_MAINTENANCE5 + typedef uint64_t BaseType; // VkFlags64 +#else + typedef uint32_t BaseType; // VkFlags32 +#endif + + static const VmaBufferImageUsage UNKNOWN; + + BaseType Value; + + VmaBufferImageUsage() { *this = UNKNOWN; } + explicit VmaBufferImageUsage(BaseType usage) : Value(usage) { } + VmaBufferImageUsage(const VkBufferCreateInfo &createInfo, bool useKhrMaintenance5); + explicit VmaBufferImageUsage(const VkImageCreateInfo &createInfo); + + bool operator==(const VmaBufferImageUsage& rhs) const { return Value == rhs.Value; } + bool operator!=(const VmaBufferImageUsage& rhs) const { return Value != rhs.Value; } + + bool Contains(BaseType flag) const { return (Value & flag) != 0; } + bool ContainsDeviceAccess() const + { + // This relies on values of VK_IMAGE_USAGE_TRANSFER* being the same as VK_BUFFER_IMAGE_TRANSFER*. + return (Value & ~BaseType(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) != 0; + } +}; + +const VmaBufferImageUsage VmaBufferImageUsage::UNKNOWN = VmaBufferImageUsage(0); + +static void swap(VmaBufferImageUsage& lhs, VmaBufferImageUsage& rhs) noexcept +{ + using std::swap; + swap(lhs.Value, rhs.Value); +} + +VmaBufferImageUsage::VmaBufferImageUsage(const VkBufferCreateInfo &createInfo, + bool useKhrMaintenance5) +{ +#if VMA_KHR_MAINTENANCE5 + if(useKhrMaintenance5) + { + // If VkBufferCreateInfo::pNext chain contains VkBufferUsageFlags2CreateInfoKHR, + // take usage from it and ignore VkBufferCreateInfo::usage, per specification + // of the VK_KHR_maintenance5 extension. + const VkBufferUsageFlags2CreateInfoKHR* const usageFlags2 = + VmaPnextChainFind(&createInfo, VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR); + if(usageFlags2) + { + this->Value = usageFlags2->usage; + return; + } + } +#endif + + this->Value = (BaseType)createInfo.usage; +} + +VmaBufferImageUsage::VmaBufferImageUsage(const VkImageCreateInfo &createInfo) +{ + // Maybe in the future there will be VK_KHR_maintenanceN extension with structure + // VkImageUsageFlags2CreateInfoKHR, like the one for buffers... + + this->Value = (BaseType)createInfo.usage; +} // This is the main algorithm that guides the selection of a memory type best for an allocation - // converts usage to required/preferred/not preferred flags. static bool FindMemoryPreferences( bool isIntegratedGPU, const VmaAllocationCreateInfo& allocCreateInfo, - VkFlags bufImgUsage, // VkBufferCreateInfo::usage or VkImageCreateInfo::usage. UINT32_MAX if unknown. + VmaBufferImageUsage bufImgUsage, VkMemoryPropertyFlags& outRequiredFlags, VkMemoryPropertyFlags& outPreferredFlags, VkMemoryPropertyFlags& outNotPreferredFlags) @@ -3659,13 +3941,14 @@ static bool FindMemoryPreferences( case VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE: case VMA_MEMORY_USAGE_AUTO_PREFER_HOST: { - if(bufImgUsage == UINT32_MAX) + if(bufImgUsage == VmaBufferImageUsage::UNKNOWN) { - VMA_ASSERT(0 && "VMA_MEMORY_USAGE_AUTO* values can only be used with functions like vmaCreateBuffer, vmaCreateImage so that the details of the created resource are known."); + VMA_ASSERT(0 && "VMA_MEMORY_USAGE_AUTO* values can only be used with functions like vmaCreateBuffer, vmaCreateImage so that the details of the created resource are known." + " Maybe you use VkBufferUsageFlags2CreateInfoKHR but forgot to use VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT?" ); return false; } - // This relies on values of VK_IMAGE_USAGE_TRANSFER* being the same VK_BUFFER_IMAGE_TRANSFER*. - const bool deviceAccess = (bufImgUsage & ~(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) != 0; + + const bool deviceAccess = bufImgUsage.ContainsDeviceAccess(); const bool hostAccessSequentialWrite = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT) != 0; const bool hostAccessRandom = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT) != 0; const bool hostAccessAllowTransferInstead = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT) != 0; @@ -3675,18 +3958,21 @@ static bool FindMemoryPreferences( // CPU random access - e.g. a buffer written to or transferred from GPU to read back on CPU. if(hostAccessRandom) { - if(!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) + // Prefer cached. Cannot require it, because some platforms don't have it (e.g. Raspberry Pi - see #362)! + outPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + + if (!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) { // Nice if it will end up in HOST_VISIBLE, but more importantly prefer DEVICE_LOCAL. // Omitting HOST_VISIBLE here is intentional. // In case there is DEVICE_LOCAL | HOST_VISIBLE | HOST_CACHED, it will pick that one. // Otherwise, this will give same weight to DEVICE_LOCAL as HOST_VISIBLE | HOST_CACHED and select the former if occurs first on the list. - outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; } else { - // Always CPU memory, cached. - outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + // Always CPU memory. + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; } } // CPU sequential write - may be CPU or host-visible GPU memory, uncached and write-combined. @@ -3725,19 +4011,18 @@ static bool FindMemoryPreferences( // No CPU access else { - // GPU access, no CPU access (e.g. a color attachment image) - prefer GPU memory - if(deviceAccess) - { - // ...unless there is a clear preference from the user not to do so. - if(preferHost) - outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - else - outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } + // if(deviceAccess) + // + // GPU access, no CPU access (e.g. a color attachment image) - prefer GPU memory, + // unless there is a clear preference from the user not to do so. + // + // else: + // // No direct GPU access, no CPU access, just transfers. // It may be staging copy intended for e.g. preserving image for next frame (then better GPU memory) or // a "swap file" copy to free some GPU memory (then better CPU memory). // Up to the user to decide. If no preferece, assume the former and choose GPU memory. + if(preferHost) outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; else @@ -3956,7 +4241,7 @@ static void VmaAddDetailedStatistics(VmaDetailedStatistics& inoutStats, const Vm // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope). struct VmaMutexLock { - VMA_CLASS_NO_COPY(VmaMutexLock) + VMA_CLASS_NO_COPY_NO_MOVE(VmaMutexLock) public: VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) : m_pMutex(useMutex ? &mutex : VMA_NULL) @@ -3972,7 +4257,7 @@ private: // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading. struct VmaMutexLockRead { - VMA_CLASS_NO_COPY(VmaMutexLockRead) + VMA_CLASS_NO_COPY_NO_MOVE(VmaMutexLockRead) public: VmaMutexLockRead(VMA_RW_MUTEX& mutex, bool useMutex) : m_pMutex(useMutex ? &mutex : VMA_NULL) @@ -3988,7 +4273,7 @@ private: // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing. struct VmaMutexLockWrite { - VMA_CLASS_NO_COPY(VmaMutexLockWrite) + VMA_CLASS_NO_COPY_NO_MOVE(VmaMutexLockWrite) public: VmaMutexLockWrite(VMA_RW_MUTEX& mutex, bool useMutex) : m_pMutex(useMutex ? &mutex : VMA_NULL) @@ -4011,11 +4296,11 @@ private: #ifndef _VMA_ATOMIC_TRANSACTIONAL_INCREMENT // An object that increments given atomic but decrements it back in the destructor unless Commit() is called. -template +template struct AtomicTransactionalIncrement { public: - typedef std::atomic AtomicT; + using T = decltype(AtomicT().load()); ~AtomicTransactionalIncrement() { @@ -4023,7 +4308,7 @@ public: --(*m_Atomic); } - void Commit() { m_Atomic = nullptr; } + void Commit() { m_Atomic = VMA_NULL; } T Increment(AtomicT* atomic) { m_Atomic = atomic; @@ -4031,7 +4316,7 @@ public: } private: - AtomicT* m_Atomic = nullptr; + AtomicT* m_Atomic = VMA_NULL; }; #endif // _VMA_ATOMIC_TRANSACTIONAL_INCREMENT @@ -4443,7 +4728,7 @@ allocator can create multiple blocks. template class VmaPoolAllocator { - VMA_CLASS_NO_COPY(VmaPoolAllocator) + VMA_CLASS_NO_COPY_NO_MOVE(VmaPoolAllocator) public: VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity); ~VmaPoolAllocator(); @@ -4576,7 +4861,7 @@ struct VmaListItem template class VmaRawList { - VMA_CLASS_NO_COPY(VmaRawList) + VMA_CLASS_NO_COPY_NO_MOVE(VmaRawList) public: typedef VmaListItem ItemType; @@ -4839,7 +5124,7 @@ VmaListItem* VmaRawList::InsertAfter(ItemType* pItem, const T& value) template class VmaList { - VMA_CLASS_NO_COPY(VmaList) + VMA_CLASS_NO_COPY_NO_MOVE(VmaList) public: class reverse_iterator; class const_iterator; @@ -5298,99 +5583,6 @@ void VmaIntrusiveLinkedList::RemoveAll() #endif // _VMA_INTRUSIVE_LINKED_LIST_FUNCTIONS #endif // _VMA_INTRUSIVE_LINKED_LIST -// Unused in this version. -#if 0 - -#ifndef _VMA_PAIR -template -struct VmaPair -{ - T1 first; - T2 second; - - VmaPair() : first(), second() {} - VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) {} -}; - -template -struct VmaPairFirstLess -{ - bool operator()(const VmaPair& lhs, const VmaPair& rhs) const - { - return lhs.first < rhs.first; - } - bool operator()(const VmaPair& lhs, const FirstT& rhsFirst) const - { - return lhs.first < rhsFirst; - } -}; -#endif // _VMA_PAIR - -#ifndef _VMA_MAP -/* Class compatible with subset of interface of std::unordered_map. -KeyT, ValueT must be POD because they will be stored in VmaVector. -*/ -template -class VmaMap -{ -public: - typedef VmaPair PairType; - typedef PairType* iterator; - - VmaMap(const VmaStlAllocator& allocator) : m_Vector(allocator) {} - - iterator begin() { return m_Vector.begin(); } - iterator end() { return m_Vector.end(); } - size_t size() { return m_Vector.size(); } - - void insert(const PairType& pair); - iterator find(const KeyT& key); - void erase(iterator it); - -private: - VmaVector< PairType, VmaStlAllocator> m_Vector; -}; - -#ifndef _VMA_MAP_FUNCTIONS -template -void VmaMap::insert(const PairType& pair) -{ - const size_t indexToInsert = VmaBinaryFindFirstNotLess( - m_Vector.data(), - m_Vector.data() + m_Vector.size(), - pair, - VmaPairFirstLess()) - m_Vector.data(); - VmaVectorInsert(m_Vector, indexToInsert, pair); -} - -template -VmaPair* VmaMap::find(const KeyT& key) -{ - PairType* it = VmaBinaryFindFirstNotLess( - m_Vector.data(), - m_Vector.data() + m_Vector.size(), - key, - VmaPairFirstLess()); - if ((it != m_Vector.end()) && (it->first == key)) - { - return it; - } - else - { - return m_Vector.end(); - } -} - -template -void VmaMap::erase(iterator it) -{ - VmaVectorRemove(m_Vector, it - m_Vector.begin()); -} -#endif // _VMA_MAP_FUNCTIONS -#endif // _VMA_MAP - -#endif // #if 0 - #if !defined(_VMA_STRING_BUILDER) && VMA_STATS_STRING_ENABLED class VmaStringBuilder { @@ -5431,7 +5623,7 @@ void VmaStringBuilder::AddNumber(uint32_t num) char* p = &buf[10]; do { - *--p = '0' + (num % 10); + *--p = '0' + (char)(num % 10); num /= 10; } while (num); Add(p); @@ -5444,7 +5636,7 @@ void VmaStringBuilder::AddNumber(uint64_t num) char* p = &buf[20]; do { - *--p = '0' + (num % 10); + *--p = '0' + (char)(num % 10); num /= 10; } while (num); Add(p); @@ -5466,7 +5658,7 @@ VmaStringBuilder passed to the constructor. */ class VmaJsonWriter { - VMA_CLASS_NO_COPY(VmaJsonWriter) + VMA_CLASS_NO_COPY_NO_MOVE(VmaJsonWriter) public: // sb - string builder to write the document to. Must remain alive for the whole lifetime of this object. VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb); @@ -5500,7 +5692,6 @@ public: // Posts next part of an open string. The number is converted to decimal characters. void ContinueString(uint32_t n); void ContinueString(uint64_t n); - void ContinueString_Size(size_t n); // Posts next part of an open string. Pointer value is converted to characters // using "%p" formatting - shown as hexadecimal number, e.g.: 000000081276Ad00 void ContinueString_Pointer(const void* ptr); @@ -5510,7 +5701,6 @@ public: // Writes a number value. void WriteNumber(uint32_t n); void WriteNumber(uint64_t n); - void WriteSize(size_t n); // Writes a boolean value - false or true. void WriteBool(bool b); // Writes a null value. @@ -5535,11 +5725,6 @@ private: VmaVector< StackItem, VmaStlAllocator > m_Stack; bool m_InsideString; - // Write size_t for less than 64bits - void WriteSize(size_t n, std::integral_constant) { m_SB.AddNumber(static_cast(n)); } - // Write size_t for 64bits - void WriteSize(size_t n, std::integral_constant) { m_SB.AddNumber(static_cast(n)); } - void BeginValue(bool isString); void WriteIndent(bool oneLess = false); }; @@ -5642,7 +5827,7 @@ void VmaJsonWriter::ContinueString(const char* pStr) { m_SB.Add("\\\""); } - else if (ch >= 32) + else if ((uint8_t)ch >= 32) { m_SB.Add(ch); } @@ -5665,7 +5850,6 @@ void VmaJsonWriter::ContinueString(const char* pStr) break; default: VMA_ASSERT(0 && "Character not currently supported."); - break; } } } @@ -5682,14 +5866,6 @@ void VmaJsonWriter::ContinueString(uint64_t n) m_SB.AddNumber(n); } -void VmaJsonWriter::ContinueString_Size(size_t n) -{ - VMA_ASSERT(m_InsideString); - // Fix for AppleClang incorrect type casting - // TODO: Change to if constexpr when C++17 used as minimal standard - WriteSize(n, std::is_same{}); -} - void VmaJsonWriter::ContinueString_Pointer(const void* ptr) { VMA_ASSERT(m_InsideString); @@ -5721,15 +5897,6 @@ void VmaJsonWriter::WriteNumber(uint64_t n) m_SB.AddNumber(n); } -void VmaJsonWriter::WriteSize(size_t n) -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - // Fix for AppleClang incorrect type casting - // TODO: Change to if constexpr when C++17 used as minimal standard - WriteSize(n, std::is_same{}); -} - void VmaJsonWriter::WriteBool(bool b) { VMA_ASSERT(!m_InsideString); @@ -5829,7 +5996,7 @@ static void VmaPrintDetailedStatistics(VmaJsonWriter& json, const VmaDetailedSta class VmaMappingHysteresis { - VMA_CLASS_NO_COPY(VmaMappingHysteresis) + VMA_CLASS_NO_COPY_NO_MOVE(VmaMappingHysteresis) public: VmaMappingHysteresis() = default; @@ -5936,7 +6103,7 @@ Thread-safety: */ class VmaDeviceMemoryBlock { - VMA_CLASS_NO_COPY(VmaDeviceMemoryBlock) + VMA_CLASS_NO_COPY_NO_MOVE(VmaDeviceMemoryBlock) public: VmaBlockMetadata* m_pMetadata; @@ -6078,9 +6245,17 @@ public: void DedicatedAllocUnmap(VmaAllocator hAllocator); #if VMA_STATS_STRING_ENABLED - uint32_t GetBufferImageUsage() const { return m_BufferImageUsage; } - - void InitBufferImageUsage(uint32_t bufferImageUsage); + VmaBufferImageUsage GetBufferImageUsage() const { return m_BufferImageUsage; } + void InitBufferUsage(const VkBufferCreateInfo &createInfo, bool useKhrMaintenance5) + { + VMA_ASSERT(m_BufferImageUsage == VmaBufferImageUsage::UNKNOWN); + m_BufferImageUsage = VmaBufferImageUsage(createInfo, useKhrMaintenance5); + } + void InitImageUsage(const VkImageCreateInfo &createInfo) + { + VMA_ASSERT(m_BufferImageUsage == VmaBufferImageUsage::UNKNOWN); + m_BufferImageUsage = VmaBufferImageUsage(createInfo); + } void PrintParameters(class VmaJsonWriter& json) const; #endif @@ -6119,7 +6294,7 @@ private: uint8_t m_MapCount; uint8_t m_Flags; // enum FLAGS #if VMA_STATS_STRING_ENABLED - uint32_t m_BufferImageUsage; // 0 if unknown. + VmaBufferImageUsage m_BufferImageUsage; // 0 if unknown. #endif }; #endif // _VMA_ALLOCATION_T @@ -6159,6 +6334,7 @@ Thread-safe, synchronized internally. */ class VmaDedicatedAllocationList { + VMA_CLASS_NO_COPY_NO_MOVE(VmaDedicatedAllocationList) public: VmaDedicatedAllocationList() {} ~VmaDedicatedAllocationList(); @@ -6193,7 +6369,7 @@ VmaDedicatedAllocationList::~VmaDedicatedAllocationList() if (!m_AllocationList.IsEmpty()) { - VMA_ASSERT(false && "Unfreed dedicated allocations found!"); + VMA_ASSERT_LEAK(false && "Unfreed dedicated allocations found!"); } } @@ -6214,7 +6390,7 @@ bool VmaDedicatedAllocationList::Validate() void VmaDedicatedAllocationList::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) { - for(auto* item = m_AllocationList.Front(); item != nullptr; item = DedicatedAllocationLinkedList::GetNext(item)) + for(auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) { const VkDeviceSize size = item->GetSize(); inoutStats.statistics.blockCount++; @@ -6231,7 +6407,7 @@ void VmaDedicatedAllocationList::AddStatistics(VmaStatistics& inoutStats) inoutStats.blockCount += allocCount; inoutStats.allocationCount += allocCount; - for(auto* item = m_AllocationList.Front(); item != nullptr; item = DedicatedAllocationLinkedList::GetNext(item)) + for(auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) { const VkDeviceSize size = item->GetSize(); inoutStats.blockBytes += size; @@ -6344,6 +6520,7 @@ in a single VkDeviceMemory block. */ class VmaBlockMetadata { + VMA_CLASS_NO_COPY_NO_MOVE(VmaBlockMetadata) public: // pAllocationCallbacks, if not null, must be owned externally - alive and unchanged for the whole lifetime of this object. VmaBlockMetadata(const VkAllocationCallbacks* pAllocationCallbacks, @@ -6410,7 +6587,7 @@ public: protected: const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; } VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; } - VkDeviceSize GetDebugMargin() const { return IsVirtual() ? 0 : VMA_DEBUG_MARGIN; } + VkDeviceSize GetDebugMargin() const { return VkDeviceSize(IsVirtual() ? 0 : VMA_DEBUG_MARGIN); } void DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size, void* userData) const; #if VMA_STATS_STRING_ENABLED @@ -6446,7 +6623,7 @@ void VmaBlockMetadata::DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size { if (IsVirtual()) { - VMA_DEBUG_LOG("UNFREED VIRTUAL ALLOCATION; Offset: %llu; Size: %llu; UserData: %p", offset, size, userData); + VMA_LEAK_LOG_FORMAT("UNFREED VIRTUAL ALLOCATION; Offset: %" PRIu64 "; Size: %" PRIu64 "; UserData: %p", offset, size, userData); } else { @@ -6457,14 +6634,14 @@ void VmaBlockMetadata::DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size const char* name = allocation->GetName(); #if VMA_STATS_STRING_ENABLED - VMA_DEBUG_LOG("UNFREED ALLOCATION; Offset: %llu; Size: %llu; UserData: %p; Name: %s; Type: %s; Usage: %u", + VMA_LEAK_LOG_FORMAT("UNFREED ALLOCATION; Offset: %" PRIu64 "; Size: %" PRIu64 "; UserData: %p; Name: %s; Type: %s; Usage: %" PRIu64, offset, size, userData, name ? name : "vma_empty", VMA_SUBALLOCATION_TYPE_NAMES[allocation->GetSuballocationType()], - allocation->GetBufferImageUsage()); + (uint64_t)allocation->GetBufferImageUsage().Value); #else - VMA_DEBUG_LOG("UNFREED ALLOCATION; Offset: %llu; Size: %llu; UserData: %p; Name: %s; Type: %u", + VMA_LEAK_LOG_FORMAT("UNFREED ALLOCATION; Offset: %" PRIu64 "; Size: %" PRIu64 "; UserData: %p; Name: %s; Type: %u", offset, size, userData, name ? name : "vma_empty", - (uint32_t)allocation->GetSuballocationType()); + (unsigned)allocation->GetSuballocationType()); #endif // VMA_STATS_STRING_ENABLED } @@ -6478,13 +6655,13 @@ void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json, json.WriteNumber(GetSize()); json.WriteString("UnusedBytes"); - json.WriteSize(unusedBytes); + json.WriteNumber(unusedBytes); json.WriteString("Allocations"); - json.WriteSize(allocationCount); + json.WriteNumber((uint64_t)allocationCount); json.WriteString("UnusedRanges"); - json.WriteSize(unusedRangeCount); + json.WriteNumber((uint64_t)unusedRangeCount); json.WriteString("Suballocations"); json.BeginArray(); @@ -6778,770 +6955,6 @@ void VmaBlockBufferImageGranularity::AllocPage(RegionInfo& page, uint8_t allocTy #endif // _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY_FUNCTIONS #endif // _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY -#if 0 -#ifndef _VMA_BLOCK_METADATA_GENERIC -class VmaBlockMetadata_Generic : public VmaBlockMetadata -{ - friend class VmaDefragmentationAlgorithm_Generic; - friend class VmaDefragmentationAlgorithm_Fast; - VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic) -public: - VmaBlockMetadata_Generic(const VkAllocationCallbacks* pAllocationCallbacks, - VkDeviceSize bufferImageGranularity, bool isVirtual); - virtual ~VmaBlockMetadata_Generic() = default; - - size_t GetAllocationCount() const override { return m_Suballocations.size() - m_FreeCount; } - VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize; } - bool IsEmpty() const override { return (m_Suballocations.size() == 1) && (m_FreeCount == 1); } - void Free(VmaAllocHandle allocHandle) override { FreeSuballocation(FindAtOffset((VkDeviceSize)allocHandle - 1)); } - VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; }; - - void Init(VkDeviceSize size) override; - bool Validate() const override; - - void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; - void AddStatistics(VmaStatistics& inoutStats) const override; - -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const override; -#endif - - bool CreateAllocationRequest( - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) override; - - VkResult CheckCorruption(const void* pBlockData) override; - - void Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - void* userData) override; - - void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; - void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; - VmaAllocHandle GetAllocationListBegin() const override; - VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; - void Clear() override; - void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; - void DebugLogAllAllocations() const override; - -private: - uint32_t m_FreeCount; - VkDeviceSize m_SumFreeSize; - VmaSuballocationList m_Suballocations; - // Suballocations that are free. Sorted by size, ascending. - VmaVector> m_FreeSuballocationsBySize; - - VkDeviceSize AlignAllocationSize(VkDeviceSize size) const { return IsVirtual() ? size : VmaAlignUp(size, (VkDeviceSize)16); } - - VmaSuballocationList::iterator FindAtOffset(VkDeviceSize offset) const; - bool ValidateFreeSuballocationList() const; - - // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem. - // If yes, fills pOffset and returns true. If no, returns false. - bool CheckAllocation( - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - VmaSuballocationList::const_iterator suballocItem, - VmaAllocHandle* pAllocHandle) const; - - // Given free suballocation, it merges it with following one, which must also be free. - void MergeFreeWithNext(VmaSuballocationList::iterator item); - // Releases given suballocation, making it free. - // Merges it with adjacent free suballocations if applicable. - // Returns iterator to new free suballocation at this place. - VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem); - // Given free suballocation, it inserts it into sorted list of - // m_FreeSuballocationsBySize if it is suitable. - void RegisterFreeSuballocation(VmaSuballocationList::iterator item); - // Given free suballocation, it removes it from sorted list of - // m_FreeSuballocationsBySize if it is suitable. - void UnregisterFreeSuballocation(VmaSuballocationList::iterator item); -}; - -#ifndef _VMA_BLOCK_METADATA_GENERIC_FUNCTIONS -VmaBlockMetadata_Generic::VmaBlockMetadata_Generic(const VkAllocationCallbacks* pAllocationCallbacks, - VkDeviceSize bufferImageGranularity, bool isVirtual) - : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), - m_FreeCount(0), - m_SumFreeSize(0), - m_Suballocations(VmaStlAllocator(pAllocationCallbacks)), - m_FreeSuballocationsBySize(VmaStlAllocator(pAllocationCallbacks)) {} - -void VmaBlockMetadata_Generic::Init(VkDeviceSize size) -{ - VmaBlockMetadata::Init(size); - - m_FreeCount = 1; - m_SumFreeSize = size; - - VmaSuballocation suballoc = {}; - suballoc.offset = 0; - suballoc.size = size; - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - - m_Suballocations.push_back(suballoc); - m_FreeSuballocationsBySize.push_back(m_Suballocations.begin()); -} - -bool VmaBlockMetadata_Generic::Validate() const -{ - VMA_VALIDATE(!m_Suballocations.empty()); - - // Expected offset of new suballocation as calculated from previous ones. - VkDeviceSize calculatedOffset = 0; - // Expected number of free suballocations as calculated from traversing their list. - uint32_t calculatedFreeCount = 0; - // Expected sum size of free suballocations as calculated from traversing their list. - VkDeviceSize calculatedSumFreeSize = 0; - // Expected number of free suballocations that should be registered in - // m_FreeSuballocationsBySize calculated from traversing their list. - size_t freeSuballocationsToRegister = 0; - // True if previous visited suballocation was free. - bool prevFree = false; - - const VkDeviceSize debugMargin = GetDebugMargin(); - - for (const auto& subAlloc : m_Suballocations) - { - // Actual offset of this suballocation doesn't match expected one. - VMA_VALIDATE(subAlloc.offset == calculatedOffset); - - const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE); - // Two adjacent free suballocations are invalid. They should be merged. - VMA_VALIDATE(!prevFree || !currFree); - - VmaAllocation alloc = (VmaAllocation)subAlloc.userData; - if (!IsVirtual()) - { - VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); - } - - if (currFree) - { - calculatedSumFreeSize += subAlloc.size; - ++calculatedFreeCount; - ++freeSuballocationsToRegister; - - // Margin required between allocations - every free space must be at least that large. - VMA_VALIDATE(subAlloc.size >= debugMargin); - } - else - { - if (!IsVirtual()) - { - VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == subAlloc.offset + 1); - VMA_VALIDATE(alloc->GetSize() == subAlloc.size); - } - - // Margin required between allocations - previous allocation must be free. - VMA_VALIDATE(debugMargin == 0 || prevFree); - } - - calculatedOffset += subAlloc.size; - prevFree = currFree; - } - - // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't - // match expected one. - VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister); - - VkDeviceSize lastSize = 0; - for (size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i) - { - VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i]; - - // Only free suballocations can be registered in m_FreeSuballocationsBySize. - VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE); - // They must be sorted by size ascending. - VMA_VALIDATE(suballocItem->size >= lastSize); - - lastSize = suballocItem->size; - } - - // Check if totals match calculated values. - VMA_VALIDATE(ValidateFreeSuballocationList()); - VMA_VALIDATE(calculatedOffset == GetSize()); - VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize); - VMA_VALIDATE(calculatedFreeCount == m_FreeCount); - - return true; -} - -void VmaBlockMetadata_Generic::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const -{ - const uint32_t rangeCount = (uint32_t)m_Suballocations.size(); - inoutStats.statistics.blockCount++; - inoutStats.statistics.blockBytes += GetSize(); - - for (const auto& suballoc : m_Suballocations) - { - if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); - else - VmaAddDetailedStatisticsUnusedRange(inoutStats, suballoc.size); - } -} - -void VmaBlockMetadata_Generic::AddStatistics(VmaStatistics& inoutStats) const -{ - inoutStats.blockCount++; - inoutStats.allocationCount += (uint32_t)m_Suballocations.size() - m_FreeCount; - inoutStats.blockBytes += GetSize(); - inoutStats.allocationBytes += GetSize() - m_SumFreeSize; -} - -#if VMA_STATS_STRING_ENABLED -void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const -{ - PrintDetailedMap_Begin(json, - m_SumFreeSize, // unusedBytes - m_Suballocations.size() - (size_t)m_FreeCount, // allocationCount - m_FreeCount, // unusedRangeCount - mapRefCount); - - for (const auto& suballoc : m_Suballocations) - { - if (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE) - { - PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size); - } - else - { - PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); - } - } - - PrintDetailedMap_End(json); -} -#endif // VMA_STATS_STRING_ENABLED - -bool VmaBlockMetadata_Generic::CreateAllocationRequest( - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) -{ - VMA_ASSERT(allocSize > 0); - VMA_ASSERT(!upperAddress); - VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(pAllocationRequest != VMA_NULL); - VMA_HEAVY_ASSERT(Validate()); - - allocSize = AlignAllocationSize(allocSize); - - pAllocationRequest->type = VmaAllocationRequestType::Normal; - pAllocationRequest->size = allocSize; - - const VkDeviceSize debugMargin = GetDebugMargin(); - - // There is not enough total free space in this block to fulfill the request: Early return. - if (m_SumFreeSize < allocSize + debugMargin) - { - return false; - } - - // New algorithm, efficiently searching freeSuballocationsBySize. - const size_t freeSuballocCount = m_FreeSuballocationsBySize.size(); - if (freeSuballocCount > 0) - { - if (strategy == 0 || - strategy == VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT) - { - // Find first free suballocation with size not less than allocSize + debugMargin. - VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( - m_FreeSuballocationsBySize.data(), - m_FreeSuballocationsBySize.data() + freeSuballocCount, - allocSize + debugMargin, - VmaSuballocationItemSizeLess()); - size_t index = it - m_FreeSuballocationsBySize.data(); - for (; index < freeSuballocCount; ++index) - { - if (CheckAllocation( - allocSize, - allocAlignment, - allocType, - m_FreeSuballocationsBySize[index], - &pAllocationRequest->allocHandle)) - { - pAllocationRequest->item = m_FreeSuballocationsBySize[index]; - return true; - } - } - } - else if (strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET) - { - for (VmaSuballocationList::iterator it = m_Suballocations.begin(); - it != m_Suballocations.end(); - ++it) - { - if (it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation( - allocSize, - allocAlignment, - allocType, - it, - &pAllocationRequest->allocHandle)) - { - pAllocationRequest->item = it; - return true; - } - } - } - else - { - VMA_ASSERT(strategy & (VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT | VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT )); - // Search staring from biggest suballocations. - for (size_t index = freeSuballocCount; index--; ) - { - if (CheckAllocation( - allocSize, - allocAlignment, - allocType, - m_FreeSuballocationsBySize[index], - &pAllocationRequest->allocHandle)) - { - pAllocationRequest->item = m_FreeSuballocationsBySize[index]; - return true; - } - } - } - } - - return false; -} - -VkResult VmaBlockMetadata_Generic::CheckCorruption(const void* pBlockData) -{ - for (auto& suballoc : m_Suballocations) - { - if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - { - if (!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) - { - VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); - return VK_ERROR_UNKNOWN_COPY; - } - } - } - - return VK_SUCCESS; -} - -void VmaBlockMetadata_Generic::Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - void* userData) -{ - VMA_ASSERT(request.type == VmaAllocationRequestType::Normal); - VMA_ASSERT(request.item != m_Suballocations.end()); - VmaSuballocation& suballoc = *request.item; - // Given suballocation is a free block. - VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); - - // Given offset is inside this suballocation. - VMA_ASSERT((VkDeviceSize)request.allocHandle - 1 >= suballoc.offset); - const VkDeviceSize paddingBegin = (VkDeviceSize)request.allocHandle - suballoc.offset - 1; - VMA_ASSERT(suballoc.size >= paddingBegin + request.size); - const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - request.size; - - // Unregister this free suballocation from m_FreeSuballocationsBySize and update - // it to become used. - UnregisterFreeSuballocation(request.item); - - suballoc.offset = (VkDeviceSize)request.allocHandle - 1; - suballoc.size = request.size; - suballoc.type = type; - suballoc.userData = userData; - - // If there are any free bytes remaining at the end, insert new free suballocation after current one. - if (paddingEnd) - { - VmaSuballocation paddingSuballoc = {}; - paddingSuballoc.offset = suballoc.offset + suballoc.size; - paddingSuballoc.size = paddingEnd; - paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - VmaSuballocationList::iterator next = request.item; - ++next; - const VmaSuballocationList::iterator paddingEndItem = - m_Suballocations.insert(next, paddingSuballoc); - RegisterFreeSuballocation(paddingEndItem); - } - - // If there are any free bytes remaining at the beginning, insert new free suballocation before current one. - if (paddingBegin) - { - VmaSuballocation paddingSuballoc = {}; - paddingSuballoc.offset = suballoc.offset - paddingBegin; - paddingSuballoc.size = paddingBegin; - paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - const VmaSuballocationList::iterator paddingBeginItem = - m_Suballocations.insert(request.item, paddingSuballoc); - RegisterFreeSuballocation(paddingBeginItem); - } - - // Update totals. - m_FreeCount = m_FreeCount - 1; - if (paddingBegin > 0) - { - ++m_FreeCount; - } - if (paddingEnd > 0) - { - ++m_FreeCount; - } - m_SumFreeSize -= request.size; -} - -void VmaBlockMetadata_Generic::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) -{ - outInfo.offset = (VkDeviceSize)allocHandle - 1; - const VmaSuballocation& suballoc = *FindAtOffset(outInfo.offset); - outInfo.size = suballoc.size; - outInfo.pUserData = suballoc.userData; -} - -void* VmaBlockMetadata_Generic::GetAllocationUserData(VmaAllocHandle allocHandle) const -{ - return FindAtOffset((VkDeviceSize)allocHandle - 1)->userData; -} - -VmaAllocHandle VmaBlockMetadata_Generic::GetAllocationListBegin() const -{ - if (IsEmpty()) - return VK_NULL_HANDLE; - - for (const auto& suballoc : m_Suballocations) - { - if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - return (VmaAllocHandle)(suballoc.offset + 1); - } - VMA_ASSERT(false && "Should contain at least 1 allocation!"); - return VK_NULL_HANDLE; -} - -VmaAllocHandle VmaBlockMetadata_Generic::GetNextAllocation(VmaAllocHandle prevAlloc) const -{ - VmaSuballocationList::const_iterator prev = FindAtOffset((VkDeviceSize)prevAlloc - 1); - - for (VmaSuballocationList::const_iterator it = ++prev; it != m_Suballocations.end(); ++it) - { - if (it->type != VMA_SUBALLOCATION_TYPE_FREE) - return (VmaAllocHandle)(it->offset + 1); - } - return VK_NULL_HANDLE; -} - -void VmaBlockMetadata_Generic::Clear() -{ - const VkDeviceSize size = GetSize(); - - VMA_ASSERT(IsVirtual()); - m_FreeCount = 1; - m_SumFreeSize = size; - m_Suballocations.clear(); - m_FreeSuballocationsBySize.clear(); - - VmaSuballocation suballoc = {}; - suballoc.offset = 0; - suballoc.size = size; - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - m_Suballocations.push_back(suballoc); - - m_FreeSuballocationsBySize.push_back(m_Suballocations.begin()); -} - -void VmaBlockMetadata_Generic::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) -{ - VmaSuballocation& suballoc = *FindAtOffset((VkDeviceSize)allocHandle - 1); - suballoc.userData = userData; -} - -void VmaBlockMetadata_Generic::DebugLogAllAllocations() const -{ - for (const auto& suballoc : m_Suballocations) - { - if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - DebugLogAllocation(suballoc.offset, suballoc.size, suballoc.userData); - } -} - -VmaSuballocationList::iterator VmaBlockMetadata_Generic::FindAtOffset(VkDeviceSize offset) const -{ - VMA_HEAVY_ASSERT(!m_Suballocations.empty()); - const VkDeviceSize last = m_Suballocations.rbegin()->offset; - if (last == offset) - return m_Suballocations.rbegin().drop_const(); - const VkDeviceSize first = m_Suballocations.begin()->offset; - if (first == offset) - return m_Suballocations.begin().drop_const(); - - const size_t suballocCount = m_Suballocations.size(); - const VkDeviceSize step = (last - first + m_Suballocations.begin()->size) / suballocCount; - auto findSuballocation = [&](auto begin, auto end) -> VmaSuballocationList::iterator - { - for (auto suballocItem = begin; - suballocItem != end; - ++suballocItem) - { - if (suballocItem->offset == offset) - return suballocItem.drop_const(); - } - VMA_ASSERT(false && "Not found!"); - return m_Suballocations.end().drop_const(); - }; - // If requested offset is closer to the end of range, search from the end - if (offset - first > suballocCount * step / 2) - { - return findSuballocation(m_Suballocations.rbegin(), m_Suballocations.rend()); - } - return findSuballocation(m_Suballocations.begin(), m_Suballocations.end()); -} - -bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const -{ - VkDeviceSize lastSize = 0; - for (size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i) - { - const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i]; - - VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE); - VMA_VALIDATE(it->size >= lastSize); - lastSize = it->size; - } - return true; -} - -bool VmaBlockMetadata_Generic::CheckAllocation( - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - VmaSuballocationList::const_iterator suballocItem, - VmaAllocHandle* pAllocHandle) const -{ - VMA_ASSERT(allocSize > 0); - VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(suballocItem != m_Suballocations.cend()); - VMA_ASSERT(pAllocHandle != VMA_NULL); - - const VkDeviceSize debugMargin = GetDebugMargin(); - const VkDeviceSize bufferImageGranularity = GetBufferImageGranularity(); - - const VmaSuballocation& suballoc = *suballocItem; - VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); - - // Size of this suballocation is too small for this request: Early return. - if (suballoc.size < allocSize) - { - return false; - } - - // Start from offset equal to beginning of this suballocation. - VkDeviceSize offset = suballoc.offset + (suballocItem == m_Suballocations.cbegin() ? 0 : GetDebugMargin()); - - // Apply debugMargin from the end of previous alloc. - if (debugMargin > 0) - { - offset += debugMargin; - } - - // Apply alignment. - offset = VmaAlignUp(offset, allocAlignment); - - // Check previous suballocations for BufferImageGranularity conflicts. - // Make bigger alignment if necessary. - if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment) - { - bool bufferImageGranularityConflict = false; - VmaSuballocationList::const_iterator prevSuballocItem = suballocItem; - while (prevSuballocItem != m_Suballocations.cbegin()) - { - --prevSuballocItem; - const VmaSuballocation& prevSuballoc = *prevSuballocItem; - if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, offset, bufferImageGranularity)) - { - if (VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) - { - bufferImageGranularityConflict = true; - break; - } - } - else - // Already on previous page. - break; - } - if (bufferImageGranularityConflict) - { - offset = VmaAlignUp(offset, bufferImageGranularity); - } - } - - // Calculate padding at the beginning based on current offset. - const VkDeviceSize paddingBegin = offset - suballoc.offset; - - // Fail if requested size plus margin after is bigger than size of this suballocation. - if (paddingBegin + allocSize + debugMargin > suballoc.size) - { - return false; - } - - // Check next suballocations for BufferImageGranularity conflicts. - // If conflict exists, allocation cannot be made here. - if (allocSize % bufferImageGranularity || offset % bufferImageGranularity) - { - VmaSuballocationList::const_iterator nextSuballocItem = suballocItem; - ++nextSuballocItem; - while (nextSuballocItem != m_Suballocations.cend()) - { - const VmaSuballocation& nextSuballoc = *nextSuballocItem; - if (VmaBlocksOnSamePage(offset, allocSize, nextSuballoc.offset, bufferImageGranularity)) - { - if (VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) - { - return false; - } - } - else - { - // Already on next page. - break; - } - ++nextSuballocItem; - } - } - - *pAllocHandle = (VmaAllocHandle)(offset + 1); - // All tests passed: Success. pAllocHandle is already filled. - return true; -} - -void VmaBlockMetadata_Generic::MergeFreeWithNext(VmaSuballocationList::iterator item) -{ - VMA_ASSERT(item != m_Suballocations.end()); - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - - VmaSuballocationList::iterator nextItem = item; - ++nextItem; - VMA_ASSERT(nextItem != m_Suballocations.end()); - VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE); - - item->size += nextItem->size; - --m_FreeCount; - m_Suballocations.erase(nextItem); -} - -VmaSuballocationList::iterator VmaBlockMetadata_Generic::FreeSuballocation(VmaSuballocationList::iterator suballocItem) -{ - // Change this suballocation to be marked as free. - VmaSuballocation& suballoc = *suballocItem; - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - suballoc.userData = VMA_NULL; - - // Update totals. - ++m_FreeCount; - m_SumFreeSize += suballoc.size; - - // Merge with previous and/or next suballocation if it's also free. - bool mergeWithNext = false; - bool mergeWithPrev = false; - - VmaSuballocationList::iterator nextItem = suballocItem; - ++nextItem; - if ((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)) - { - mergeWithNext = true; - } - - VmaSuballocationList::iterator prevItem = suballocItem; - if (suballocItem != m_Suballocations.begin()) - { - --prevItem; - if (prevItem->type == VMA_SUBALLOCATION_TYPE_FREE) - { - mergeWithPrev = true; - } - } - - if (mergeWithNext) - { - UnregisterFreeSuballocation(nextItem); - MergeFreeWithNext(suballocItem); - } - - if (mergeWithPrev) - { - UnregisterFreeSuballocation(prevItem); - MergeFreeWithNext(prevItem); - RegisterFreeSuballocation(prevItem); - return prevItem; - } - else - { - RegisterFreeSuballocation(suballocItem); - return suballocItem; - } -} - -void VmaBlockMetadata_Generic::RegisterFreeSuballocation(VmaSuballocationList::iterator item) -{ - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(item->size > 0); - - // You may want to enable this validation at the beginning or at the end of - // this function, depending on what do you want to check. - VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); - - if (m_FreeSuballocationsBySize.empty()) - { - m_FreeSuballocationsBySize.push_back(item); - } - else - { - VmaVectorInsertSorted(m_FreeSuballocationsBySize, item); - } - - //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); -} - -void VmaBlockMetadata_Generic::UnregisterFreeSuballocation(VmaSuballocationList::iterator item) -{ - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(item->size > 0); - - // You may want to enable this validation at the beginning or at the end of - // this function, depending on what do you want to check. - VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); - - VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( - m_FreeSuballocationsBySize.data(), - m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(), - item, - VmaSuballocationItemSizeLess()); - for (size_t index = it - m_FreeSuballocationsBySize.data(); - index < m_FreeSuballocationsBySize.size(); - ++index) - { - if (m_FreeSuballocationsBySize[index] == item) - { - VmaVectorRemove(m_FreeSuballocationsBySize, index); - return; - } - VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found."); - } - VMA_ASSERT(0 && "Not found."); - - //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); -} -#endif // _VMA_BLOCK_METADATA_GENERIC_FUNCTIONS -#endif // _VMA_BLOCK_METADATA_GENERIC -#endif // #if 0 - #ifndef _VMA_BLOCK_METADATA_LINEAR /* Allocations and their references in internal data structure look like this: @@ -7623,7 +7036,7 @@ GetSize() +-------+ */ class VmaBlockMetadata_Linear : public VmaBlockMetadata { - VMA_CLASS_NO_COPY(VmaBlockMetadata_Linear) + VMA_CLASS_NO_COPY_NO_MOVE(VmaBlockMetadata_Linear) public: VmaBlockMetadata_Linear(const VkAllocationCallbacks* pAllocationCallbacks, VkDeviceSize bufferImageGranularity, bool isVirtual); @@ -7631,7 +7044,7 @@ public: VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize; } bool IsEmpty() const override { return GetAllocationCount() == 0; } - VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; }; + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; } void Init(VkDeviceSize size) override; bool Validate() const override; @@ -8104,30 +7517,17 @@ void VmaBlockMetadata_Linear::AddStatistics(VmaStatistics& inoutStats) const { const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - // 1. Process free space before this allocation. - if (lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - } - - // 2. Process this allocation. + // Process this allocation. // There is allocation with suballoc.offset, suballoc.size. ++inoutStats.allocationCount; - // 3. Prepare for next iteration. + // Prepare for next iteration. lastOffset = suballoc.offset + suballoc.size; ++nextAlloc2ndIndex; } // We are at the end. else { - if (lastOffset < freeSpace2ndTo1stEnd) - { - // There is free space from lastOffset to freeSpace2ndTo1stEnd. - const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; - } - // End of loop. lastOffset = freeSpace2ndTo1stEnd; } @@ -8151,30 +7551,17 @@ void VmaBlockMetadata_Linear::AddStatistics(VmaStatistics& inoutStats) const { const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; - // 1. Process free space before this allocation. - if (lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - } - - // 2. Process this allocation. + // Process this allocation. // There is allocation with suballoc.offset, suballoc.size. ++inoutStats.allocationCount; - // 3. Prepare for next iteration. + // Prepare for next iteration. lastOffset = suballoc.offset + suballoc.size; ++nextAlloc1stIndex; } // We are at the end. else { - if (lastOffset < freeSpace1stTo2ndEnd) - { - // There is free space from lastOffset to freeSpace1stTo2ndEnd. - const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; - } - // End of loop. lastOffset = freeSpace1stTo2ndEnd; } @@ -8197,30 +7584,17 @@ void VmaBlockMetadata_Linear::AddStatistics(VmaStatistics& inoutStats) const { const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; - // 1. Process free space before this allocation. - if (lastOffset < suballoc.offset) - { - // There is free space from lastOffset to suballoc.offset. - const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; - } - - // 2. Process this allocation. + // Process this allocation. // There is allocation with suballoc.offset, suballoc.size. ++inoutStats.allocationCount; - // 3. Prepare for next iteration. + // Prepare for next iteration. lastOffset = suballoc.offset + suballoc.size; --nextAlloc2ndIndex; } // We are at the end. else { - if (lastOffset < size) - { - // There is free space from lastOffset to size. - const VkDeviceSize unusedRangeSize = size - lastOffset; - } - // End of loop. lastOffset = size; } @@ -8331,7 +7705,7 @@ void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const // We are at the end. else { - if (lastOffset < size) + if (lastOffset < freeSpace1stTo2ndEnd) { // There is free space from lastOffset to freeSpace1stTo2ndEnd. ++unusedRangeCount; @@ -8557,6 +7931,10 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest( VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); VMA_ASSERT(pAllocationRequest != VMA_NULL); VMA_HEAVY_ASSERT(Validate()); + + if(allocSize > GetSize()) + return false; + pAllocationRequest->size = allocSize; return upperAddress ? CreateAllocationRequest_UpperAddress( @@ -9266,713 +8644,6 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest_UpperAddress( #endif // _VMA_BLOCK_METADATA_LINEAR_FUNCTIONS #endif // _VMA_BLOCK_METADATA_LINEAR -#if 0 -#ifndef _VMA_BLOCK_METADATA_BUDDY -/* -- GetSize() is the original size of allocated memory block. -- m_UsableSize is this size aligned down to a power of two. - All allocations and calculations happen relative to m_UsableSize. -- GetUnusableSize() is the difference between them. - It is reported as separate, unused range, not available for allocations. - -Node at level 0 has size = m_UsableSize. -Each next level contains nodes with size 2 times smaller than current level. -m_LevelCount is the maximum number of levels to use in the current object. -*/ -class VmaBlockMetadata_Buddy : public VmaBlockMetadata -{ - VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy) -public: - VmaBlockMetadata_Buddy(const VkAllocationCallbacks* pAllocationCallbacks, - VkDeviceSize bufferImageGranularity, bool isVirtual); - virtual ~VmaBlockMetadata_Buddy(); - - size_t GetAllocationCount() const override { return m_AllocationCount; } - VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize + GetUnusableSize(); } - bool IsEmpty() const override { return m_Root->type == Node::TYPE_FREE; } - VkResult CheckCorruption(const void* pBlockData) override { return VK_ERROR_FEATURE_NOT_PRESENT; } - VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; }; - void DebugLogAllAllocations() const override { DebugLogAllAllocationNode(m_Root, 0); } - - void Init(VkDeviceSize size) override; - bool Validate() const override; - - void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; - void AddStatistics(VmaStatistics& inoutStats) const override; - -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const override; -#endif - - bool CreateAllocationRequest( - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) override; - - void Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - void* userData) override; - - void Free(VmaAllocHandle allocHandle) override; - void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; - void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; - VmaAllocHandle GetAllocationListBegin() const override; - VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; - void Clear() override; - void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; - -private: - static const size_t MAX_LEVELS = 48; - - struct ValidationContext - { - size_t calculatedAllocationCount = 0; - size_t calculatedFreeCount = 0; - VkDeviceSize calculatedSumFreeSize = 0; - }; - struct Node - { - VkDeviceSize offset; - enum TYPE - { - TYPE_FREE, - TYPE_ALLOCATION, - TYPE_SPLIT, - TYPE_COUNT - } type; - Node* parent; - Node* buddy; - - union - { - struct - { - Node* prev; - Node* next; - } free; - struct - { - void* userData; - } allocation; - struct - { - Node* leftChild; - } split; - }; - }; - - // Size of the memory block aligned down to a power of two. - VkDeviceSize m_UsableSize; - uint32_t m_LevelCount; - VmaPoolAllocator m_NodeAllocator; - Node* m_Root; - struct - { - Node* front; - Node* back; - } m_FreeList[MAX_LEVELS]; - - // Number of nodes in the tree with type == TYPE_ALLOCATION. - size_t m_AllocationCount; - // Number of nodes in the tree with type == TYPE_FREE. - size_t m_FreeCount; - // Doesn't include space wasted due to internal fragmentation - allocation sizes are just aligned up to node sizes. - // Doesn't include unusable size. - VkDeviceSize m_SumFreeSize; - - VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; } - VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; } - - VkDeviceSize AlignAllocationSize(VkDeviceSize size) const - { - if (!IsVirtual()) - { - size = VmaAlignUp(size, (VkDeviceSize)16); - } - return VmaNextPow2(size); - } - Node* FindAllocationNode(VkDeviceSize offset, uint32_t& outLevel) const; - void DeleteNodeChildren(Node* node); - bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const; - uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const; - void AddNodeToDetailedStatistics(VmaDetailedStatistics& inoutStats, const Node* node, VkDeviceSize levelNodeSize) const; - // Adds node to the front of FreeList at given level. - // node->type must be FREE. - // node->free.prev, next can be undefined. - void AddToFreeListFront(uint32_t level, Node* node); - // Removes node from FreeList at given level. - // node->type must be FREE. - // node->free.prev, next stay untouched. - void RemoveFromFreeList(uint32_t level, Node* node); - void DebugLogAllAllocationNode(Node* node, uint32_t level) const; - -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const; -#endif -}; - -#ifndef _VMA_BLOCK_METADATA_BUDDY_FUNCTIONS -VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(const VkAllocationCallbacks* pAllocationCallbacks, - VkDeviceSize bufferImageGranularity, bool isVirtual) - : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), - m_NodeAllocator(pAllocationCallbacks, 32), // firstBlockCapacity - m_Root(VMA_NULL), - m_AllocationCount(0), - m_FreeCount(1), - m_SumFreeSize(0) -{ - memset(m_FreeList, 0, sizeof(m_FreeList)); -} - -VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy() -{ - DeleteNodeChildren(m_Root); - m_NodeAllocator.Free(m_Root); -} - -void VmaBlockMetadata_Buddy::Init(VkDeviceSize size) -{ - VmaBlockMetadata::Init(size); - - m_UsableSize = VmaPrevPow2(size); - m_SumFreeSize = m_UsableSize; - - // Calculate m_LevelCount. - const VkDeviceSize minNodeSize = IsVirtual() ? 1 : 16; - m_LevelCount = 1; - while (m_LevelCount < MAX_LEVELS && - LevelToNodeSize(m_LevelCount) >= minNodeSize) - { - ++m_LevelCount; - } - - Node* rootNode = m_NodeAllocator.Alloc(); - rootNode->offset = 0; - rootNode->type = Node::TYPE_FREE; - rootNode->parent = VMA_NULL; - rootNode->buddy = VMA_NULL; - - m_Root = rootNode; - AddToFreeListFront(0, rootNode); -} - -bool VmaBlockMetadata_Buddy::Validate() const -{ - // Validate tree. - ValidationContext ctx; - if (!ValidateNode(ctx, VMA_NULL, m_Root, 0, LevelToNodeSize(0))) - { - VMA_VALIDATE(false && "ValidateNode failed."); - } - VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount); - VMA_VALIDATE(m_SumFreeSize == ctx.calculatedSumFreeSize); - - // Validate free node lists. - for (uint32_t level = 0; level < m_LevelCount; ++level) - { - VMA_VALIDATE(m_FreeList[level].front == VMA_NULL || - m_FreeList[level].front->free.prev == VMA_NULL); - - for (Node* node = m_FreeList[level].front; - node != VMA_NULL; - node = node->free.next) - { - VMA_VALIDATE(node->type == Node::TYPE_FREE); - - if (node->free.next == VMA_NULL) - { - VMA_VALIDATE(m_FreeList[level].back == node); - } - else - { - VMA_VALIDATE(node->free.next->free.prev == node); - } - } - } - - // Validate that free lists ar higher levels are empty. - for (uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level) - { - VMA_VALIDATE(m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL); - } - - return true; -} - -void VmaBlockMetadata_Buddy::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const -{ - inoutStats.statistics.blockCount++; - inoutStats.statistics.blockBytes += GetSize(); - - AddNodeToDetailedStatistics(inoutStats, m_Root, LevelToNodeSize(0)); - - const VkDeviceSize unusableSize = GetUnusableSize(); - if (unusableSize > 0) - VmaAddDetailedStatisticsUnusedRange(inoutStats, unusableSize); -} - -void VmaBlockMetadata_Buddy::AddStatistics(VmaStatistics& inoutStats) const -{ - inoutStats.blockCount++; - inoutStats.allocationCount += (uint32_t)m_AllocationCount; - inoutStats.blockBytes += GetSize(); - inoutStats.allocationBytes += GetSize() - m_SumFreeSize; -} - -#if VMA_STATS_STRING_ENABLED -void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const -{ - VmaDetailedStatistics stats; - VmaClearDetailedStatistics(stats); - AddDetailedStatistics(stats); - - PrintDetailedMap_Begin( - json, - stats.statistics.blockBytes - stats.statistics.allocationBytes, - stats.statistics.allocationCount, - stats.unusedRangeCount, - mapRefCount); - - PrintDetailedMapNode(json, m_Root, LevelToNodeSize(0)); - - const VkDeviceSize unusableSize = GetUnusableSize(); - if (unusableSize > 0) - { - PrintDetailedMap_UnusedRange(json, - m_UsableSize, // offset - unusableSize); // size - } - - PrintDetailedMap_End(json); -} -#endif // VMA_STATS_STRING_ENABLED - -bool VmaBlockMetadata_Buddy::CreateAllocationRequest( - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - bool upperAddress, - VmaSuballocationType allocType, - uint32_t strategy, - VmaAllocationRequest* pAllocationRequest) -{ - VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm."); - - allocSize = AlignAllocationSize(allocSize); - - // Simple way to respect bufferImageGranularity. May be optimized some day. - // Whenever it might be an OPTIMAL image... - if (allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN || - allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || - allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL) - { - allocAlignment = VMA_MAX(allocAlignment, GetBufferImageGranularity()); - allocSize = VmaAlignUp(allocSize, GetBufferImageGranularity()); - } - - if (allocSize > m_UsableSize) - { - return false; - } - - const uint32_t targetLevel = AllocSizeToLevel(allocSize); - for (uint32_t level = targetLevel; level--; ) - { - for (Node* freeNode = m_FreeList[level].front; - freeNode != VMA_NULL; - freeNode = freeNode->free.next) - { - if (freeNode->offset % allocAlignment == 0) - { - pAllocationRequest->type = VmaAllocationRequestType::Normal; - pAllocationRequest->allocHandle = (VmaAllocHandle)(freeNode->offset + 1); - pAllocationRequest->size = allocSize; - pAllocationRequest->customData = (void*)(uintptr_t)level; - return true; - } - } - } - - return false; -} - -void VmaBlockMetadata_Buddy::Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - void* userData) -{ - VMA_ASSERT(request.type == VmaAllocationRequestType::Normal); - - const uint32_t targetLevel = AllocSizeToLevel(request.size); - uint32_t currLevel = (uint32_t)(uintptr_t)request.customData; - - Node* currNode = m_FreeList[currLevel].front; - VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); - const VkDeviceSize offset = (VkDeviceSize)request.allocHandle - 1; - while (currNode->offset != offset) - { - currNode = currNode->free.next; - VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); - } - - // Go down, splitting free nodes. - while (currLevel < targetLevel) - { - // currNode is already first free node at currLevel. - // Remove it from list of free nodes at this currLevel. - RemoveFromFreeList(currLevel, currNode); - - const uint32_t childrenLevel = currLevel + 1; - - // Create two free sub-nodes. - Node* leftChild = m_NodeAllocator.Alloc(); - Node* rightChild = m_NodeAllocator.Alloc(); - - leftChild->offset = currNode->offset; - leftChild->type = Node::TYPE_FREE; - leftChild->parent = currNode; - leftChild->buddy = rightChild; - - rightChild->offset = currNode->offset + LevelToNodeSize(childrenLevel); - rightChild->type = Node::TYPE_FREE; - rightChild->parent = currNode; - rightChild->buddy = leftChild; - - // Convert current currNode to split type. - currNode->type = Node::TYPE_SPLIT; - currNode->split.leftChild = leftChild; - - // Add child nodes to free list. Order is important! - AddToFreeListFront(childrenLevel, rightChild); - AddToFreeListFront(childrenLevel, leftChild); - - ++m_FreeCount; - ++currLevel; - currNode = m_FreeList[currLevel].front; - - /* - We can be sure that currNode, as left child of node previously split, - also fulfills the alignment requirement. - */ - } - - // Remove from free list. - VMA_ASSERT(currLevel == targetLevel && - currNode != VMA_NULL && - currNode->type == Node::TYPE_FREE); - RemoveFromFreeList(currLevel, currNode); - - // Convert to allocation node. - currNode->type = Node::TYPE_ALLOCATION; - currNode->allocation.userData = userData; - - ++m_AllocationCount; - --m_FreeCount; - m_SumFreeSize -= request.size; -} - -void VmaBlockMetadata_Buddy::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) -{ - uint32_t level = 0; - outInfo.offset = (VkDeviceSize)allocHandle - 1; - const Node* const node = FindAllocationNode(outInfo.offset, level); - outInfo.size = LevelToNodeSize(level); - outInfo.pUserData = node->allocation.userData; -} - -void* VmaBlockMetadata_Buddy::GetAllocationUserData(VmaAllocHandle allocHandle) const -{ - uint32_t level = 0; - const Node* const node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); - return node->allocation.userData; -} - -VmaAllocHandle VmaBlockMetadata_Buddy::GetAllocationListBegin() const -{ - // Function only used for defragmentation, which is disabled for this algorithm - return VK_NULL_HANDLE; -} - -VmaAllocHandle VmaBlockMetadata_Buddy::GetNextAllocation(VmaAllocHandle prevAlloc) const -{ - // Function only used for defragmentation, which is disabled for this algorithm - return VK_NULL_HANDLE; -} - -void VmaBlockMetadata_Buddy::DeleteNodeChildren(Node* node) -{ - if (node->type == Node::TYPE_SPLIT) - { - DeleteNodeChildren(node->split.leftChild->buddy); - DeleteNodeChildren(node->split.leftChild); - const VkAllocationCallbacks* allocationCallbacks = GetAllocationCallbacks(); - m_NodeAllocator.Free(node->split.leftChild->buddy); - m_NodeAllocator.Free(node->split.leftChild); - } -} - -void VmaBlockMetadata_Buddy::Clear() -{ - DeleteNodeChildren(m_Root); - m_Root->type = Node::TYPE_FREE; - m_AllocationCount = 0; - m_FreeCount = 1; - m_SumFreeSize = m_UsableSize; -} - -void VmaBlockMetadata_Buddy::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) -{ - uint32_t level = 0; - Node* const node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); - node->allocation.userData = userData; -} - -VmaBlockMetadata_Buddy::Node* VmaBlockMetadata_Buddy::FindAllocationNode(VkDeviceSize offset, uint32_t& outLevel) const -{ - Node* node = m_Root; - VkDeviceSize nodeOffset = 0; - outLevel = 0; - VkDeviceSize levelNodeSize = LevelToNodeSize(0); - while (node->type == Node::TYPE_SPLIT) - { - const VkDeviceSize nextLevelNodeSize = levelNodeSize >> 1; - if (offset < nodeOffset + nextLevelNodeSize) - { - node = node->split.leftChild; - } - else - { - node = node->split.leftChild->buddy; - nodeOffset += nextLevelNodeSize; - } - ++outLevel; - levelNodeSize = nextLevelNodeSize; - } - - VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION); - return node; -} - -bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const -{ - VMA_VALIDATE(level < m_LevelCount); - VMA_VALIDATE(curr->parent == parent); - VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL)); - VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr); - switch (curr->type) - { - case Node::TYPE_FREE: - // curr->free.prev, next are validated separately. - ctx.calculatedSumFreeSize += levelNodeSize; - ++ctx.calculatedFreeCount; - break; - case Node::TYPE_ALLOCATION: - ++ctx.calculatedAllocationCount; - if (!IsVirtual()) - { - VMA_VALIDATE(curr->allocation.userData != VMA_NULL); - } - break; - case Node::TYPE_SPLIT: - { - const uint32_t childrenLevel = level + 1; - const VkDeviceSize childrenLevelNodeSize = levelNodeSize >> 1; - const Node* const leftChild = curr->split.leftChild; - VMA_VALIDATE(leftChild != VMA_NULL); - VMA_VALIDATE(leftChild->offset == curr->offset); - if (!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize)) - { - VMA_VALIDATE(false && "ValidateNode for left child failed."); - } - const Node* const rightChild = leftChild->buddy; - VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize); - if (!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize)) - { - VMA_VALIDATE(false && "ValidateNode for right child failed."); - } - } - break; - default: - return false; - } - - return true; -} - -uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const -{ - // I know this could be optimized somehow e.g. by using std::log2p1 from C++20. - uint32_t level = 0; - VkDeviceSize currLevelNodeSize = m_UsableSize; - VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1; - while (allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount) - { - ++level; - currLevelNodeSize >>= 1; - nextLevelNodeSize >>= 1; - } - return level; -} - -void VmaBlockMetadata_Buddy::Free(VmaAllocHandle allocHandle) -{ - uint32_t level = 0; - Node* node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); - - ++m_FreeCount; - --m_AllocationCount; - m_SumFreeSize += LevelToNodeSize(level); - - node->type = Node::TYPE_FREE; - - // Join free nodes if possible. - while (level > 0 && node->buddy->type == Node::TYPE_FREE) - { - RemoveFromFreeList(level, node->buddy); - Node* const parent = node->parent; - - m_NodeAllocator.Free(node->buddy); - m_NodeAllocator.Free(node); - parent->type = Node::TYPE_FREE; - - node = parent; - --level; - --m_FreeCount; - } - - AddToFreeListFront(level, node); -} - -void VmaBlockMetadata_Buddy::AddNodeToDetailedStatistics(VmaDetailedStatistics& inoutStats, const Node* node, VkDeviceSize levelNodeSize) const -{ - switch (node->type) - { - case Node::TYPE_FREE: - VmaAddDetailedStatisticsUnusedRange(inoutStats, levelNodeSize); - break; - case Node::TYPE_ALLOCATION: - VmaAddDetailedStatisticsAllocation(inoutStats, levelNodeSize); - break; - case Node::TYPE_SPLIT: - { - const VkDeviceSize childrenNodeSize = levelNodeSize / 2; - const Node* const leftChild = node->split.leftChild; - AddNodeToDetailedStatistics(inoutStats, leftChild, childrenNodeSize); - const Node* const rightChild = leftChild->buddy; - AddNodeToDetailedStatistics(inoutStats, rightChild, childrenNodeSize); - } - break; - default: - VMA_ASSERT(0); - } -} - -void VmaBlockMetadata_Buddy::AddToFreeListFront(uint32_t level, Node* node) -{ - VMA_ASSERT(node->type == Node::TYPE_FREE); - - // List is empty. - Node* const frontNode = m_FreeList[level].front; - if (frontNode == VMA_NULL) - { - VMA_ASSERT(m_FreeList[level].back == VMA_NULL); - node->free.prev = node->free.next = VMA_NULL; - m_FreeList[level].front = m_FreeList[level].back = node; - } - else - { - VMA_ASSERT(frontNode->free.prev == VMA_NULL); - node->free.prev = VMA_NULL; - node->free.next = frontNode; - frontNode->free.prev = node; - m_FreeList[level].front = node; - } -} - -void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node) -{ - VMA_ASSERT(m_FreeList[level].front != VMA_NULL); - - // It is at the front. - if (node->free.prev == VMA_NULL) - { - VMA_ASSERT(m_FreeList[level].front == node); - m_FreeList[level].front = node->free.next; - } - else - { - Node* const prevFreeNode = node->free.prev; - VMA_ASSERT(prevFreeNode->free.next == node); - prevFreeNode->free.next = node->free.next; - } - - // It is at the back. - if (node->free.next == VMA_NULL) - { - VMA_ASSERT(m_FreeList[level].back == node); - m_FreeList[level].back = node->free.prev; - } - else - { - Node* const nextFreeNode = node->free.next; - VMA_ASSERT(nextFreeNode->free.prev == node); - nextFreeNode->free.prev = node->free.prev; - } -} - -void VmaBlockMetadata_Buddy::DebugLogAllAllocationNode(Node* node, uint32_t level) const -{ - switch (node->type) - { - case Node::TYPE_FREE: - break; - case Node::TYPE_ALLOCATION: - DebugLogAllocation(node->offset, LevelToNodeSize(level), node->allocation.userData); - break; - case Node::TYPE_SPLIT: - { - ++level; - DebugLogAllAllocationNode(node->split.leftChild, level); - DebugLogAllAllocationNode(node->split.leftChild->buddy, level); - } - break; - default: - VMA_ASSERT(0); - } -} - -#if VMA_STATS_STRING_ENABLED -void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const -{ - switch (node->type) - { - case Node::TYPE_FREE: - PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize); - break; - case Node::TYPE_ALLOCATION: - PrintDetailedMap_Allocation(json, node->offset, levelNodeSize, node->allocation.userData); - break; - case Node::TYPE_SPLIT: - { - const VkDeviceSize childrenNodeSize = levelNodeSize / 2; - const Node* const leftChild = node->split.leftChild; - PrintDetailedMapNode(json, leftChild, childrenNodeSize); - const Node* const rightChild = leftChild->buddy; - PrintDetailedMapNode(json, rightChild, childrenNodeSize); - } - break; - default: - VMA_ASSERT(0); - } -} -#endif // VMA_STATS_STRING_ENABLED -#endif // _VMA_BLOCK_METADATA_BUDDY_FUNCTIONS -#endif // _VMA_BLOCK_METADATA_BUDDY -#endif // #if 0 - #ifndef _VMA_BLOCK_METADATA_TLSF // To not search current larger region if first allocation won't succeed and skip to smaller range // use with VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT as strategy in CreateAllocationRequest(). @@ -9980,7 +8651,7 @@ void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, con // VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT for fastest alloc time possible. class VmaBlockMetadata_TLSF : public VmaBlockMetadata { - VMA_CLASS_NO_COPY(VmaBlockMetadata_TLSF) + VMA_CLASS_NO_COPY_NO_MOVE(VmaBlockMetadata_TLSF) public: VmaBlockMetadata_TLSF(const VkAllocationCallbacks* pAllocationCallbacks, VkDeviceSize bufferImageGranularity, bool isVirtual); @@ -9990,7 +8661,7 @@ public: size_t GetFreeRegionsCount() const override { return m_BlocksFreeCount + 1; } VkDeviceSize GetSumFreeSize() const override { return m_BlocksFreeSize + m_NullBlock->size; } bool IsEmpty() const override { return m_NullBlock->offset == 0; } - VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; }; + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; } void Init(VkDeviceSize size) override; bool Validate() const override; @@ -10142,7 +8813,7 @@ void VmaBlockMetadata_TLSF::Init(VkDeviceSize size) else m_ListsCount += 4; - m_MemoryClasses = memoryClass + 2; + m_MemoryClasses = memoryClass + uint8_t(2); memset(m_InnerIsFreeBitmap, 0, MAX_MEMORY_CLASSES * sizeof(uint32_t)); m_FreeList = vma_new_array(GetAllocationCallbacks(), Block*, m_ListsCount); @@ -10335,7 +9006,7 @@ bool VmaBlockMetadata_TLSF::CreateAllocationRequest( // Round up to the next block VkDeviceSize sizeForNextList = allocSize; - VkDeviceSize smallSizeStep = SMALL_BUFFER_SIZE / (IsVirtual() ? 1 << SECOND_LEVEL_INDEX : 4); + VkDeviceSize smallSizeStep = VkDeviceSize(SMALL_BUFFER_SIZE / (IsVirtual() ? 1 << SECOND_LEVEL_INDEX : 4)); if (allocSize > SMALL_BUFFER_SIZE) { sizeForNextList += (1ULL << (VMA_BITSCAN_MSB(allocSize) - SECOND_LEVEL_INDEX)); @@ -10345,8 +9016,8 @@ bool VmaBlockMetadata_TLSF::CreateAllocationRequest( else sizeForNextList += smallSizeStep; - uint32_t nextListIndex = 0; - uint32_t prevListIndex = 0; + uint32_t nextListIndex = m_ListsCount; + uint32_t prevListIndex = m_ListsCount; Block* nextListBlock = VMA_NULL; Block* prevListBlock = VMA_NULL; @@ -10744,7 +9415,7 @@ void VmaBlockMetadata_TLSF::DebugLogAllAllocations() const uint8_t VmaBlockMetadata_TLSF::SizeToMemoryClass(VkDeviceSize size) const { if (size > SMALL_BUFFER_SIZE) - return VMA_BITSCAN_MSB(size) - MEMORY_CLASS_SHIFT; + return uint8_t(VMA_BITSCAN_MSB(size) - MEMORY_CLASS_SHIFT); return 0; } @@ -10919,7 +9590,7 @@ Synchronized internally with a mutex. class VmaBlockVector { friend struct VmaDefragmentationContext_T; - VMA_CLASS_NO_COPY(VmaBlockVector) + VMA_CLASS_NO_COPY_NO_MOVE(VmaBlockVector) public: VmaBlockVector( VmaAllocator hAllocator, @@ -11038,7 +9709,7 @@ private: #ifndef _VMA_DEFRAGMENTATION_CONTEXT struct VmaDefragmentationContext_T { - VMA_CLASS_NO_COPY(VmaDefragmentationContext_T) + VMA_CLASS_NO_COPY_NO_MOVE(VmaDefragmentationContext_T) public: VmaDefragmentationContext_T( VmaAllocator hAllocator, @@ -11088,6 +9759,8 @@ private: const VkDeviceSize m_MaxPassBytes; const uint32_t m_MaxPassAllocations; + const PFN_vmaCheckDefragmentationBreakFunction m_BreakCallback; + void* m_BreakCallbackUserData; VmaStlAllocator m_MoveAllocator; VmaVector> m_Moves; @@ -11125,7 +9798,7 @@ private: struct VmaPool_T { friend struct VmaPoolListItemTraits; - VMA_CLASS_NO_COPY(VmaPool_T) + VMA_CLASS_NO_COPY_NO_MOVE(VmaPool_T) public: VmaBlockVector m_BlockVector; VmaDedicatedAllocationList m_DedicatedAllocations; @@ -11167,6 +9840,9 @@ struct VmaPoolListItemTraits #ifndef _VMA_CURRENT_BUDGET_DATA struct VmaCurrentBudgetData { + VMA_CLASS_NO_COPY_NO_MOVE(VmaCurrentBudgetData) +public: + VMA_ATOMIC_UINT32 m_BlockCount[VK_MAX_MEMORY_HEAPS]; VMA_ATOMIC_UINT32 m_AllocationCount[VK_MAX_MEMORY_HEAPS]; VMA_ATOMIC_UINT64 m_BlockBytes[VK_MAX_MEMORY_HEAPS]; @@ -11235,7 +9911,7 @@ Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAlloca */ class VmaAllocationObjectAllocator { - VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator) + VMA_CLASS_NO_COPY_NO_MOVE(VmaAllocationObjectAllocator) public: VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) : m_Allocator(pAllocationCallbacks, 1024) {} @@ -11265,7 +9941,7 @@ void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc) #ifndef _VMA_VIRTUAL_BLOCK_T struct VmaVirtualBlock_T { - VMA_CLASS_NO_COPY(VmaVirtualBlock_T) + VMA_CLASS_NO_COPY_NO_MOVE(VmaVirtualBlock_T) public: const bool m_AllocationCallbacksSpecified; const VkAllocationCallbacks m_AllocationCallbacks; @@ -11301,14 +9977,15 @@ VmaVirtualBlock_T::VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo const uint32_t algorithm = createInfo.flags & VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK; switch (algorithm) { - default: - VMA_ASSERT(0); case 0: m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_TLSF)(VK_NULL_HANDLE, 1, true); break; case VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT: m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_Linear)(VK_NULL_HANDLE, 1, true); break; + default: + VMA_ASSERT(0); + m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_TLSF)(VK_NULL_HANDLE, 1, true); } m_Metadata->Init(createInfo.size); @@ -11316,12 +9993,13 @@ VmaVirtualBlock_T::VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo VmaVirtualBlock_T::~VmaVirtualBlock_T() { - // Define macro VMA_DEBUG_LOG to receive the list of the unfreed allocations + // Define macro VMA_DEBUG_LOG_FORMAT or more specialized VMA_LEAK_LOG_FORMAT + // to receive the list of the unfreed allocations. if (!m_Metadata->IsEmpty()) m_Metadata->DebugLogAllAllocations(); // This is the most important assert in the entire library. // Hitting it means you have some memory leak - unreleased virtual allocations. - VMA_ASSERT(m_Metadata->IsEmpty() && "Some virtual allocations were not freed before destruction of this virtual block!"); + VMA_ASSERT_LEAK(m_Metadata->IsEmpty() && "Some virtual allocations were not freed before destruction of this virtual block!"); vma_delete(GetAllocationCallbacks(), m_Metadata); } @@ -11404,20 +10082,22 @@ void VmaVirtualBlock_T::BuildStatsString(bool detailedMap, VmaStringBuilder& sb) // Main allocator object. struct VmaAllocator_T { - VMA_CLASS_NO_COPY(VmaAllocator_T) + VMA_CLASS_NO_COPY_NO_MOVE(VmaAllocator_T) public: - bool m_UseMutex; - uint32_t m_VulkanApiVersion; + const bool m_UseMutex; + const uint32_t m_VulkanApiVersion; bool m_UseKhrDedicatedAllocation; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0). bool m_UseKhrBindMemory2; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0). bool m_UseExtMemoryBudget; bool m_UseAmdDeviceCoherentMemory; bool m_UseKhrBufferDeviceAddress; bool m_UseExtMemoryPriority; - VkDevice m_hDevice; - VkInstance m_hInstance; - bool m_AllocationCallbacksSpecified; - VkAllocationCallbacks m_AllocationCallbacks; + bool m_UseKhrMaintenance4; + bool m_UseKhrMaintenance5; + const VkDevice m_hDevice; + const VkInstance m_hInstance; + const bool m_AllocationCallbacksSpecified; + const VkAllocationCallbacks m_AllocationCallbacks; VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks; VmaAllocationObjectAllocator m_AllocationObjectAllocator; @@ -11498,7 +10178,7 @@ public: VkResult FindMemoryTypeIndex( uint32_t memoryTypeBits, const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkFlags bufImgUsage, // VkBufferCreateInfo::usage or VkImageCreateInfo::usage. UINT32_MAX if unknown. + VmaBufferImageUsage bufImgUsage, uint32_t* pMemoryTypeIndex) const; // Main allocation function. @@ -11508,7 +10188,7 @@ public: bool prefersDedicatedAllocation, VkBuffer dedicatedBuffer, VkImage dedicatedImage, - VkFlags dedicatedBufferImageUsage, // UINT32_MAX if unknown. + VmaBufferImageUsage dedicatedBufferImageUsage, const VmaAllocationCreateInfo& createInfo, VmaSuballocationType suballocType, size_t allocationCount, @@ -11529,6 +10209,7 @@ public: #endif void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo); + void GetAllocationInfo2(VmaAllocation hAllocation, VmaAllocationInfo2* pAllocationInfo); VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool); void DestroyPool(VmaPool pool); @@ -11582,6 +10263,17 @@ public: const VkDeviceSize* offsets, const VkDeviceSize* sizes, VMA_CACHE_OPERATION op); + VkResult CopyMemoryToAllocation( + const void* pSrcHostPointer, + VmaAllocation dstAllocation, + VkDeviceSize dstAllocationLocalOffset, + VkDeviceSize size); + VkResult CopyAllocationToMemory( + VmaAllocation srcAllocation, + VkDeviceSize srcAllocationLocalOffset, + void* pDstHostPointer, + VkDeviceSize size); + void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern); /* @@ -11641,7 +10333,7 @@ private: bool dedicatedPreferred, VkBuffer dedicatedBuffer, VkImage dedicatedImage, - VkFlags dedicatedBufferImageUsage, + VmaBufferImageUsage dedicatedBufferImageUsage, const VmaAllocationCreateInfo& createInfo, uint32_t memTypeIndex, VmaSuballocationType suballocType, @@ -11678,10 +10370,10 @@ private: float priority, VkBuffer dedicatedBuffer, VkImage dedicatedImage, - VkFlags dedicatedBufferImageUsage, + VmaBufferImageUsage dedicatedBufferImageUsage, size_t allocationCount, VmaAllocation* pAllocations, - const void* pNextChain = nullptr); + const void* pNextChain = VMA_NULL); void FreeDedicatedMemory(const VmaAllocation allocation); @@ -11769,8 +10461,8 @@ VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock() { - VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped."); - VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); + VMA_ASSERT_LEAK(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped."); + VMA_ASSERT_LEAK(m_hMemory == VK_NULL_HANDLE); } void VmaDeviceMemoryBlock::Init( @@ -11792,14 +10484,16 @@ void VmaDeviceMemoryBlock::Init( switch (algorithm) { + case 0: + m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_TLSF)(hAllocator->GetAllocationCallbacks(), + bufferImageGranularity, false); // isVirtual + break; case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT: m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator->GetAllocationCallbacks(), bufferImageGranularity, false); // isVirtual break; default: VMA_ASSERT(0); - // Fall-through. - case 0: m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_TLSF)(hAllocator->GetAllocationCallbacks(), bufferImageGranularity, false); // isVirtual } @@ -11808,14 +10502,15 @@ void VmaDeviceMemoryBlock::Init( void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator) { - // Define macro VMA_DEBUG_LOG to receive the list of the unfreed allocations + // Define macro VMA_DEBUG_LOG_FORMAT or more specialized VMA_LEAK_LOG_FORMAT + // to receive the list of the unfreed allocations. if (!m_pMetadata->IsEmpty()) m_pMetadata->DebugLogAllAllocations(); // This is the most important assert in the entire library. // Hitting it means you have some memory leak - unreleased VmaAllocation objects. - VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!"); + VMA_ASSERT_LEAK(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!"); - VMA_ASSERT(m_hMemory != VK_NULL_HANDLE); + VMA_ASSERT_LEAK(m_hMemory != VK_NULL_HANDLE); allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory); m_hMemory = VK_NULL_HANDLE; @@ -11853,7 +10548,7 @@ bool VmaDeviceMemoryBlock::Validate() const VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator) { - void* pData = nullptr; + void* pData = VMA_NULL; VkResult res = Map(hAllocator, 1, &pData); if (res != VK_SUCCESS) { @@ -11876,11 +10571,11 @@ VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); const uint32_t oldTotalMapCount = m_MapCount + m_MappingHysteresis.GetExtraMapping(); - m_MappingHysteresis.PostMap(); if (oldTotalMapCount != 0) { - m_MapCount += count; VMA_ASSERT(m_pMappedData != VMA_NULL); + m_MappingHysteresis.PostMap(); + m_MapCount += count; if (ppData != VMA_NULL) { *ppData = m_pMappedData; @@ -11898,11 +10593,13 @@ VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void &m_pMappedData); if (result == VK_SUCCESS) { + VMA_ASSERT(m_pMappedData != VMA_NULL); + m_MappingHysteresis.PostMap(); + m_MapCount = count; if (ppData != VMA_NULL) { *ppData = m_pMappedData; } - m_MapCount = count; } return result; } @@ -12019,15 +10716,11 @@ VmaAllocation_T::VmaAllocation_T(bool mappingAllowed) { if(mappingAllowed) m_Flags |= (uint8_t)FLAG_MAPPING_ALLOWED; - -#if VMA_STATS_STRING_ENABLED - m_BufferImageUsage = 0; -#endif } VmaAllocation_T::~VmaAllocation_T() { - VMA_ASSERT(m_MapCount == 0 && "Allocation was not unmapped before destruction."); + VMA_ASSERT_LEAK(m_MapCount == 0 && "Allocation was not unmapped before destruction."); // Check if owned string was freed. VMA_ASSERT(m_pName == VMA_NULL); @@ -12105,11 +10798,11 @@ uint8_t VmaAllocation_T::SwapBlockAllocation(VmaAllocator hAllocator, VmaAllocat m_BlockAllocation.m_Block->Unmap(hAllocator, m_MapCount); m_BlockAllocation.m_Block->m_pMetadata->SetAllocationUserData(m_BlockAllocation.m_AllocHandle, allocation); - VMA_SWAP(m_BlockAllocation, allocation->m_BlockAllocation); + std::swap(m_BlockAllocation, allocation->m_BlockAllocation); m_BlockAllocation.m_Block->m_pMetadata->SetAllocationUserData(m_BlockAllocation.m_AllocHandle, this); #if VMA_STATS_STRING_ENABLED - VMA_SWAP(m_BufferImageUsage, allocation->m_BufferImageUsage); + std::swap(m_BufferImageUsage, allocation->m_BufferImageUsage); #endif return m_MapCount; } @@ -12284,12 +10977,6 @@ void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator) } #if VMA_STATS_STRING_ENABLED -void VmaAllocation_T::InitBufferImageUsage(uint32_t bufferImageUsage) -{ - VMA_ASSERT(m_BufferImageUsage == 0); - m_BufferImageUsage = bufferImageUsage; -} - void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const { json.WriteString("Type"); @@ -12298,7 +10985,7 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const json.WriteString("Size"); json.WriteNumber(m_Size); json.WriteString("Usage"); - json.WriteNumber(m_BufferImageUsage); + json.WriteNumber(m_BufferImageUsage.Value); // It may be uint32_t or uint64_t. if (m_pUserData != VMA_NULL) { @@ -12516,7 +11203,7 @@ VkResult VmaBlockVector::AllocatePage( pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); if (res == VK_SUCCESS) { - VMA_DEBUG_LOG(" Returned from last block #%u", pCurrBlock->GetId()); + VMA_DEBUG_LOG_FORMAT(" Returned from last block #%" PRIu32, pCurrBlock->GetId()); IncrementallySortBlocks(); return VK_SUCCESS; } @@ -12552,7 +11239,7 @@ VkResult VmaBlockVector::AllocatePage( pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); if (res == VK_SUCCESS) { - VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId()); + VMA_DEBUG_LOG_FORMAT(" Returned from existing block #%" PRIu32, pCurrBlock->GetId()); IncrementallySortBlocks(); return VK_SUCCESS; } @@ -12571,7 +11258,7 @@ VkResult VmaBlockVector::AllocatePage( pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); if (res == VK_SUCCESS) { - VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId()); + VMA_DEBUG_LOG_FORMAT(" Returned from existing block #%" PRIu32, pCurrBlock->GetId()); IncrementallySortBlocks(); return VK_SUCCESS; } @@ -12588,7 +11275,7 @@ VkResult VmaBlockVector::AllocatePage( VkResult res = AllocateFromBlock(pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); if (res == VK_SUCCESS) { - VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId()); + VMA_DEBUG_LOG_FORMAT(" Returned from existing block #%" PRIu32, pCurrBlock->GetId()); IncrementallySortBlocks(); return VK_SUCCESS; } @@ -12655,7 +11342,7 @@ VkResult VmaBlockVector::AllocatePage( pBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); if (res == VK_SUCCESS) { - VMA_DEBUG_LOG(" Created new block #%u Size=%llu", pBlock->GetId(), newBlockSize); + VMA_DEBUG_LOG_FORMAT(" Created new block #%" PRIu32 " Size=%" PRIu64, pBlock->GetId(), newBlockSize); IncrementallySortBlocks(); return VK_SUCCESS; } @@ -12704,7 +11391,7 @@ void VmaBlockVector::Free(const VmaAllocation hAllocation) pBlock->PostFree(m_hAllocator); VMA_HEAVY_ASSERT(pBlock->Validate()); - VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex); + VMA_DEBUG_LOG_FORMAT(" Freed from MemoryTypeIndex=%" PRIu32, m_MemoryTypeIndex); const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount; // pBlock became empty after this deallocation. @@ -12737,7 +11424,7 @@ void VmaBlockVector::Free(const VmaAllocation hAllocation) // lock, for performance reason. if (pBlockToDelete != VMA_NULL) { - VMA_DEBUG_LOG(" Deleted empty block #%u", pBlockToDelete->GetId()); + VMA_DEBUG_LOG_FORMAT(" Deleted empty block #%" PRIu32, pBlockToDelete->GetId()); pBlockToDelete->Destroy(m_hAllocator); vma_delete(m_hAllocator, pBlockToDelete); } @@ -12784,7 +11471,7 @@ void VmaBlockVector::IncrementallySortBlocks() { if (m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize()) { - VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]); + std::swap(m_Blocks[i - 1], m_Blocks[i]); return; } } @@ -13012,6 +11699,8 @@ VmaDefragmentationContext_T::VmaDefragmentationContext_T( const VmaDefragmentationInfo& info) : m_MaxPassBytes(info.maxBytesPerPass == 0 ? VK_WHOLE_SIZE : info.maxBytesPerPass), m_MaxPassAllocations(info.maxAllocationsPerPass == 0 ? UINT32_MAX : info.maxAllocationsPerPass), + m_BreakCallback(info.pfnBreakCallback), + m_BreakCallbackUserData(info.pBreakCallbackUserData), m_MoveAllocator(hAllocator->GetAllocationCallbacks()), m_Moves(m_MoveAllocator) { @@ -13045,20 +11734,18 @@ VmaDefragmentationContext_T::VmaDefragmentationContext_T( { case 0: // Default algorithm m_Algorithm = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT; - case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: - { m_AlgorithmState = vma_new_array(hAllocator, StateBalanced, m_BlockVectorCount); break; - } + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: + m_AlgorithmState = vma_new_array(hAllocator, StateBalanced, m_BlockVectorCount); + break; case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: - { if (hAllocator->GetBufferImageGranularity() > 1) { m_AlgorithmState = vma_new_array(hAllocator, StateExtensive, m_BlockVectorCount); } break; } - } } VmaDefragmentationContext_T::~VmaDefragmentationContext_T() @@ -13268,29 +11955,24 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo m_PassStats.bytesFreed += freedBlockSize; } - switch (m_Algorithm) + if(m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT && + m_AlgorithmState != VMA_NULL) { - case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: - { - if (m_AlgorithmState != VMA_NULL) + // Avoid unnecessary tries to allocate when new free block is available + StateExtensive& state = reinterpret_cast(m_AlgorithmState)[vectorIndex]; + if (state.firstFreeBlock != SIZE_MAX) { - // Avoid unnecessary tries to allocate when new free block is available - StateExtensive& state = reinterpret_cast(m_AlgorithmState)[vectorIndex]; - if (state.firstFreeBlock != SIZE_MAX) + const size_t diff = prevCount - currentCount; + if (state.firstFreeBlock >= diff) { - const size_t diff = prevCount - currentCount; - if (state.firstFreeBlock >= diff) - { - state.firstFreeBlock -= diff; - if (state.firstFreeBlock != 0) - state.firstFreeBlock -= vector->GetBlock(state.firstFreeBlock - 1)->m_pMetadata->IsEmpty(); - } - else - state.firstFreeBlock = 0; + state.firstFreeBlock -= diff; + if (state.firstFreeBlock != 0) + state.firstFreeBlock -= vector->GetBlock(state.firstFreeBlock - 1)->m_pMetadata->IsEmpty(); } + else + state.firstFreeBlock = 0; } } - } } moveInfo.moveCount = 0; moveInfo.pMoves = VMA_NULL; @@ -13306,50 +11988,49 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo // Move blocks with immovable allocations according to algorithm if (immovableBlocks.size() > 0) { - switch (m_Algorithm) + do { - case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: - { - if (m_AlgorithmState != VMA_NULL) + if(m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT) { - bool swapped = false; - // Move to the start of free blocks range - for (const FragmentedBlock& block : immovableBlocks) + if (m_AlgorithmState != VMA_NULL) { - StateExtensive& state = reinterpret_cast(m_AlgorithmState)[block.data]; - if (state.operation != StateExtensive::Operation::Cleanup) + bool swapped = false; + // Move to the start of free blocks range + for (const FragmentedBlock& block : immovableBlocks) { - VmaBlockVector* vector = m_pBlockVectors[block.data]; - VmaMutexLockWrite lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); - - for (size_t i = 0, count = vector->GetBlockCount() - m_ImmovableBlockCount; i < count; ++i) + StateExtensive& state = reinterpret_cast(m_AlgorithmState)[block.data]; + if (state.operation != StateExtensive::Operation::Cleanup) { - if (vector->GetBlock(i) == block.block) + VmaBlockVector* vector = m_pBlockVectors[block.data]; + VmaMutexLockWrite lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + + for (size_t i = 0, count = vector->GetBlockCount() - m_ImmovableBlockCount; i < count; ++i) { - VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[vector->GetBlockCount() - ++m_ImmovableBlockCount]); - if (state.firstFreeBlock != SIZE_MAX) + if (vector->GetBlock(i) == block.block) { - if (i + 1 < state.firstFreeBlock) + std::swap(vector->m_Blocks[i], vector->m_Blocks[vector->GetBlockCount() - ++m_ImmovableBlockCount]); + if (state.firstFreeBlock != SIZE_MAX) { - if (state.firstFreeBlock > 1) - VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[--state.firstFreeBlock]); - else - --state.firstFreeBlock; + if (i + 1 < state.firstFreeBlock) + { + if (state.firstFreeBlock > 1) + std::swap(vector->m_Blocks[i], vector->m_Blocks[--state.firstFreeBlock]); + else + --state.firstFreeBlock; + } } + swapped = true; + break; } - swapped = true; - break; } } } + if (swapped) + result = VK_INCOMPLETE; + break; } - if (swapped) - result = VK_INCOMPLETE; - break; } - } - default: - { + // Move to the beginning for (const FragmentedBlock& block : immovableBlocks) { @@ -13360,14 +12041,12 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo { if (vector->GetBlock(i) == block.block) { - VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[m_ImmovableBlockCount++]); + std::swap(vector->m_Blocks[i], vector->m_Blocks[m_ImmovableBlockCount++]); break; } } } - break; - } - } + } while (false); } // Bulk-map destination blocks @@ -13385,14 +12064,15 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation(VmaBlockVector& vector, { case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT: return ComputeDefragmentation_Fast(vector); - default: - VMA_ASSERT(0); case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: return ComputeDefragmentation_Balanced(vector, index, true); case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT: return ComputeDefragmentation_Full(vector); case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: return ComputeDefragmentation_Extensive(vector, index); + default: + VMA_ASSERT(0); + return ComputeDefragmentation_Balanced(vector, index, true); } } @@ -13416,6 +12096,10 @@ VmaDefragmentationContext_T::MoveAllocationData VmaDefragmentationContext_T::Get VmaDefragmentationContext_T::CounterStatus VmaDefragmentationContext_T::CheckCounters(VkDeviceSize bytes) { + // Check custom criteria if exists + if (m_BreakCallback && m_BreakCallback(m_BreakCallbackUserData)) + return CounterStatus::End; + // Ignore allocation if will exceed max size for copy if (m_PassStats.bytesMoved + bytes > m_MaxPassBytes) { @@ -13424,6 +12108,8 @@ VmaDefragmentationContext_T::CounterStatus VmaDefragmentationContext_T::CheckCou else return CounterStatus::End; } + else + m_IgnoredAllocs = 0; return CounterStatus::Pass; } @@ -13433,8 +12119,8 @@ bool VmaDefragmentationContext_T::IncrementCounters(VkDeviceSize bytes) // Early return when max found if (++m_PassStats.allocationsMoved >= m_MaxPassAllocations || m_PassStats.bytesMoved >= m_MaxPassBytes) { - VMA_ASSERT(m_PassStats.allocationsMoved == m_MaxPassAllocations || - m_PassStats.bytesMoved == m_MaxPassBytes && "Exceeded maximal pass threshold!"); + VMA_ASSERT((m_PassStats.allocationsMoved == m_MaxPassAllocations || + m_PassStats.bytesMoved == m_MaxPassBytes) && "Exceeded maximal pass threshold!"); return true; } return false; @@ -13458,10 +12144,10 @@ bool VmaDefragmentationContext_T::ReallocWithinBlock(VmaBlockVector& vector, Vma continue; case CounterStatus::End: return true; - default: - VMA_ASSERT(0); case CounterStatus::Pass: break; + default: + VMA_ASSERT(0); } VkDeviceSize offset = moveData.move.srcAllocation->GetOffset(); @@ -13547,10 +12233,10 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation_Fast(VmaBlockVector& ve continue; case CounterStatus::End: return true; - default: - VMA_ASSERT(0); case CounterStatus::Pass: break; + default: + VMA_ASSERT(0); } // Check all previous blocks for free space @@ -13594,10 +12280,10 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation_Balanced(VmaBlockVector continue; case CounterStatus::End: return true; - default: - VMA_ASSERT(0); case CounterStatus::Pass: break; + default: + VMA_ASSERT(0); } // Check all previous blocks for free space @@ -13681,10 +12367,10 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation_Full(VmaBlockVector& ve continue; case CounterStatus::End: return true; - default: - VMA_ASSERT(0); case CounterStatus::Pass: break; + default: + VMA_ASSERT(0); } // Check all previous blocks for free space @@ -13772,10 +12458,10 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation_Extensive(VmaBlockVecto continue; case CounterStatus::End: return true; - default: - VMA_ASSERT(0); case CounterStatus::Pass: break; + default: + VMA_ASSERT(0); } // Check all previous blocks for free space @@ -13783,7 +12469,7 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation_Extensive(VmaBlockVecto { // Full clear performed already if (prevMoveCount != m_Moves.size() && freeMetadata->GetNextAllocation(handle) == VK_NULL_HANDLE) - reinterpret_cast(m_AlgorithmState)[index] = last; + vectorState.firstFreeBlock = last; return true; } } @@ -13813,14 +12499,15 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation_Extensive(VmaBlockVecto case StateExtensive::Operation::FindFreeBlockBuffer: vectorState.operation = StateExtensive::Operation::MoveBuffers; break; - default: - VMA_ASSERT(0); case StateExtensive::Operation::FindFreeBlockTexture: vectorState.operation = StateExtensive::Operation::MoveTextures; break; case StateExtensive::Operation::FindFreeBlockAll: vectorState.operation = StateExtensive::Operation::MoveAll; break; + default: + VMA_ASSERT(0); + vectorState.operation = StateExtensive::Operation::MoveTextures; } vectorState.firstFreeBlock = last; // Nothing done, block found without reallocations, can perform another reallocs in same pass @@ -13852,6 +12539,7 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation_Extensive(VmaBlockVecto } else break; + VMA_FALLTHROUGH; // Fallthrough } case StateExtensive::Operation::MoveBuffers: { @@ -13876,6 +12564,7 @@ bool VmaDefragmentationContext_T::ComputeDefragmentation_Extensive(VmaBlockVecto } else break; + VMA_FALLTHROUGH; // Fallthrough } case StateExtensive::Operation::MoveAll: { @@ -13958,10 +12647,10 @@ bool VmaDefragmentationContext_T::MoveDataToFreeBlocks(VmaSuballocationType curr continue; case CounterStatus::End: return true; - default: - VMA_ASSERT(0); case CounterStatus::Pass: break; + default: + VMA_ASSERT(0); } // Move only single type of resources at once @@ -14008,6 +12697,9 @@ VmaPool_T::VmaPool_T( VmaPool_T::~VmaPool_T() { VMA_ASSERT(m_PrevPool == VMA_NULL && m_NextPool == VMA_NULL); + + const VkAllocationCallbacks* allocs = m_BlockVector.GetAllocator()->GetAllocationCallbacks(); + VmaFreeString(allocs, m_Name); } void VmaPool_T::SetName(const char* pName) @@ -14036,6 +12728,8 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0), m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0), m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), + m_UseKhrMaintenance4((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0), + m_UseKhrMaintenance5((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT) != 0), m_hDevice(pCreateInfo->device), m_hInstance(pCreateInfo->instance), m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), @@ -14115,6 +12809,18 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif +#if !(VMA_KHR_MAINTENANCE4) + if(m_UseKhrMaintenance4) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); + } +#endif +#if !(VMA_KHR_MAINTENANCE5) + if(m_UseKhrMaintenance5) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); + } +#endif memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); @@ -14193,7 +12899,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : GetMemoryTypeMinAlignment(memTypeIndex), // minAllocationAlignment VMA_NULL); // // pMemoryAllocateNext // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here, - // becase minBlockCount is 0. + // because minBlockCount is 0. } } } @@ -14273,6 +12979,12 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2; m_VulkanFunctions.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)vkBindBufferMemory2; m_VulkanFunctions.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)vkBindImageMemory2; + } +#endif + +#if VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2; } #endif @@ -14325,11 +13037,11 @@ void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVul VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR); #endif -#if VMA_MEMORY_BUDGET +#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR); #endif -#if VMA_VULKAN_VERSION >= 1003000 +#if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 VMA_COPY_IF_NOT_NULL(vkGetDeviceBufferMemoryRequirements); VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements); #endif @@ -14380,7 +13092,17 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2"); VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2, "vkBindBufferMemory2"); VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2, "vkBindImageMemory2"); - VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2"); + } +#endif + +#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); + } + else if(m_UseExtMemoryBudget) + { + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); } #endif @@ -14400,8 +13122,12 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() } #endif // #if VMA_BIND_MEMORY2 -#if VMA_MEMORY_BUDGET - if(m_UseExtMemoryBudget) +#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); + } + else if(m_UseExtMemoryBudget) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); } @@ -14414,6 +13140,13 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirements, "vkGetDeviceImageMemoryRequirements"); } #endif +#if VMA_KHR_MAINTENANCE4 + if(m_UseKhrMaintenance4) + { + VMA_FETCH_DEVICE_FUNC(vkGetDeviceBufferMemoryRequirements, PFN_vkGetDeviceBufferMemoryRequirementsKHR, "vkGetDeviceBufferMemoryRequirementsKHR"); + VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR"); + } +#endif #undef VMA_FETCH_DEVICE_FUNC #undef VMA_FETCH_INSTANCE_FUNC @@ -14464,13 +13197,12 @@ void VmaAllocator_T::ValidateVulkanFunctions() } #endif -#if VMA_VULKAN_VERSION >= 1003000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) - { - VMA_ASSERT(m_VulkanFunctions.vkGetDeviceBufferMemoryRequirements != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetDeviceImageMemoryRequirements != VMA_NULL); - } -#endif + // Not validating these due to suspected driver bugs with these function + // pointers being null despite correct extension or Vulkan version is enabled. + // See issue #397. Their usage in VMA is optional anyway. + // + // VMA_ASSERT(m_VulkanFunctions.vkGetDeviceBufferMemoryRequirements != VMA_NULL); + // VMA_ASSERT(m_VulkanFunctions.vkGetDeviceImageMemoryRequirements != VMA_NULL); } VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex) @@ -14488,7 +13220,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( bool dedicatedPreferred, VkBuffer dedicatedBuffer, VkImage dedicatedImage, - VkFlags dedicatedBufferImageUsage, + VmaBufferImageUsage dedicatedBufferImageUsage, const VmaAllocationCreateInfo& createInfo, uint32_t memTypeIndex, VmaSuballocationType suballocType, @@ -14498,7 +13230,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( VmaAllocation* pAllocations) { VMA_ASSERT(pAllocations != VMA_NULL); - VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size); + VMA_DEBUG_LOG_FORMAT(" AllocateMemory: MemoryTypeIndex=%" PRIu32 ", AllocationCount=%zu, Size=%" PRIu64, memTypeIndex, allocationCount, size); VmaAllocationCreateInfo finalCreateInfo = createInfo; VkResult res = CalcMemTypeParams( @@ -14547,7 +13279,8 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( // Protection against creating each allocation as dedicated when we reach or exceed heap size/budget, // which can quickly deplete maxMemoryAllocationCount: Don't prefer dedicated allocations when above // 3/4 of the maximum allocation count. - if(m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4) + if(m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount < UINT32_MAX / 4 && + m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4) { dedicatedPreferred = false; } @@ -14576,7 +13309,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( if(res == VK_SUCCESS) { // Succeeded: AllocateDedicatedMemory function already filled pMemory, nothing more to do here. - VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); + VMA_DEBUG_LOG(Log::" Allocated as DedicatedMemory"); return VK_SUCCESS; } } @@ -14617,12 +13350,12 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( if(res == VK_SUCCESS) { // Succeeded: AllocateDedicatedMemory function already filled pMemory, nothing more to do here. - VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); + VMA_DEBUG_LOG(Log::" Allocated as DedicatedMemory"); return VK_SUCCESS; } } // Everything failed: Return error code. - VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); + VMA_DEBUG_LOG(Log::" vkAllocateMemory FAILED"); return res; } } @@ -14641,7 +13374,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( float priority, VkBuffer dedicatedBuffer, VkImage dedicatedImage, - VkFlags dedicatedBufferImageUsage, + VmaBufferImageUsage dedicatedBufferImageUsage, size_t allocationCount, VmaAllocation* pAllocations, const void* pNextChain) @@ -14681,8 +13414,8 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( bool canContainBufferWithDeviceAddress = true; if(dedicatedBuffer != VK_NULL_HANDLE) { - canContainBufferWithDeviceAddress = dedicatedBufferImageUsage == UINT32_MAX || // Usage flags unknown - (dedicatedBufferImageUsage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) != 0; + canContainBufferWithDeviceAddress = dedicatedBufferImageUsage == VmaBufferImageUsage::UNKNOWN || + dedicatedBufferImageUsage.Contains(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT); } else if(dedicatedImage != VK_NULL_HANDLE) { @@ -14743,7 +13476,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( { dedicatedAllocations.Register(pAllocations[allocIndex]); } - VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex); + VMA_DEBUG_LOG_FORMAT(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%" PRIu32, allocationCount, memTypeIndex); } else { @@ -14790,7 +13523,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory); if(res < 0) { - VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); + VMA_DEBUG_LOG(Log::" vkAllocateMemory FAILED"); return res; } @@ -14806,7 +13539,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( &pMappedData); if(res < 0) { - VMA_DEBUG_LOG(" vkMapMemory FAILED"); + VMA_DEBUG_LOG(Log::" vkMapMemory FAILED"); FreeVulkanMemory(memTypeIndex, size, hMemory); return res; } @@ -14894,7 +13627,7 @@ void VmaAllocator_T::GetImageMemoryRequirements( VkResult VmaAllocator_T::FindMemoryTypeIndex( uint32_t memoryTypeBits, const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkFlags bufImgUsage, + VmaBufferImageUsage bufImgUsage, uint32_t* pMemoryTypeIndex) const { memoryTypeBits &= GetGlobalMemoryTypeBits(); @@ -15049,7 +13782,7 @@ VkResult VmaAllocator_T::AllocateMemory( bool prefersDedicatedAllocation, VkBuffer dedicatedBuffer, VkImage dedicatedImage, - VkFlags dedicatedBufferImageUsage, + VmaBufferImageUsage dedicatedBufferImageUsage, const VmaAllocationCreateInfo& createInfo, VmaSuballocationType suballocType, size_t allocationCount, @@ -15299,9 +14032,28 @@ void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationI pAllocationInfo->pName = hAllocation->GetName(); } +void VmaAllocator_T::GetAllocationInfo2(VmaAllocation hAllocation, VmaAllocationInfo2* pAllocationInfo) +{ + GetAllocationInfo(hAllocation, &pAllocationInfo->allocationInfo); + + switch (hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + pAllocationInfo->blockSize = hAllocation->GetBlock()->m_pMetadata->GetSize(); + pAllocationInfo->dedicatedMemory = VK_FALSE; + break; + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + pAllocationInfo->blockSize = pAllocationInfo->allocationInfo.size; + pAllocationInfo->dedicatedMemory = VK_TRUE; + break; + default: + VMA_ASSERT(0); + } +} + VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool) { - VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags); + VMA_DEBUG_LOG_FORMAT(" CreatePool: MemoryTypeIndex=%" PRIu32 ", flags=%" PRIu32, pCreateInfo->memoryTypeIndex, pCreateInfo->flags); VmaPoolCreateInfo newCreateInfo = *pCreateInfo; @@ -15445,7 +14197,7 @@ VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits) VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory) { - AtomicTransactionalIncrement deviceMemoryCountIncrement; + AtomicTransactionalIncrement deviceMemoryCountIncrement; const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount); #if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount) @@ -15602,6 +14354,7 @@ VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) } return res; } + VMA_FALLTHROUGH; // Fallthrough case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: return hAllocation->DedicatedAllocMap(this, ppData); default: @@ -15635,7 +14388,7 @@ VkResult VmaAllocator_T::BindBufferMemory( VkBuffer hBuffer, const void* pNext) { - VkResult res = VK_SUCCESS; + VkResult res = VK_ERROR_UNKNOWN_COPY; switch(hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: @@ -15660,7 +14413,7 @@ VkResult VmaAllocator_T::BindImageMemory( VkImage hImage, const void* pNext) { - VkResult res = VK_SUCCESS; + VkResult res = VK_ERROR_UNKNOWN_COPY; switch(hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: @@ -15746,6 +14499,43 @@ VkResult VmaAllocator_T::FlushOrInvalidateAllocations( return res; } +VkResult VmaAllocator_T::CopyMemoryToAllocation( + const void* pSrcHostPointer, + VmaAllocation dstAllocation, + VkDeviceSize dstAllocationLocalOffset, + VkDeviceSize size) +{ + void* dstMappedData = VMA_NULL; + VkResult res = Map(dstAllocation, &dstMappedData); + if(res == VK_SUCCESS) + { + memcpy((char*)dstMappedData + dstAllocationLocalOffset, pSrcHostPointer, (size_t)size); + Unmap(dstAllocation); + res = FlushOrInvalidateAllocation(dstAllocation, dstAllocationLocalOffset, size, VMA_CACHE_FLUSH); + } + return res; +} + +VkResult VmaAllocator_T::CopyAllocationToMemory( + VmaAllocation srcAllocation, + VkDeviceSize srcAllocationLocalOffset, + void* pDstHostPointer, + VkDeviceSize size) +{ + void* srcMappedData = VMA_NULL; + VkResult res = Map(srcAllocation, &srcMappedData); + if(res == VK_SUCCESS) + { + res = FlushOrInvalidateAllocation(srcAllocation, srcAllocationLocalOffset, size, VMA_CACHE_INVALIDATE); + if(res == VK_SUCCESS) + { + memcpy(pDstHostPointer, (const char*)srcMappedData + srcAllocationLocalOffset, (size_t)size); + Unmap(srcAllocation); + } + } + return res; +} + void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation) { VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); @@ -15780,7 +14570,7 @@ void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation) m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize()); m_AllocationObjectAllocator.Free(allocation); - VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex); + VMA_DEBUG_LOG_FORMAT(" Freed DedicatedMemory MemoryTypeIndex=%" PRIu32, memTypeIndex); } uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const @@ -16025,7 +14815,7 @@ void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json) { json.WriteString("Name"); json.BeginString(); - json.ContinueString_Size(index++); + json.ContinueString((uint64_t)index++); if (pool->GetName()) { json.ContinueString(" - "); @@ -16065,7 +14855,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( VMA_ASSERT(pCreateInfo && pAllocator); VMA_ASSERT(pCreateInfo->vulkanApiVersion == 0 || (VK_VERSION_MAJOR(pCreateInfo->vulkanApiVersion) == 1 && VK_VERSION_MINOR(pCreateInfo->vulkanApiVersion) <= 3)); - VMA_DEBUG_LOG("vmaCreateAllocator"); + VMA_DEBUG_LOG(Log::"vmaCreateAllocator"); *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo); VkResult result = (*pAllocator)->Init(pCreateInfo); if(result < 0) @@ -16081,7 +14871,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( { if(allocator != VK_NULL_HANDLE) { - VMA_DEBUG_LOG("vmaDestroyAllocator"); + VMA_DEBUG_LOG(Log::"vmaDestroyAllocator"); VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks; // Have to copy the callbacks when destroying. vma_delete(&allocationCallbacks, allocator); } @@ -16182,11 +14972,11 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( json.WriteString("apiVersion"); json.BeginString(); - json.ContinueString(VK_API_VERSION_MAJOR(deviceProperties.apiVersion)); + json.ContinueString(VK_VERSION_MAJOR(deviceProperties.apiVersion)); json.ContinueString("."); - json.ContinueString(VK_API_VERSION_MINOR(deviceProperties.apiVersion)); + json.ContinueString(VK_VERSION_MINOR(deviceProperties.apiVersion)); json.ContinueString("."); - json.ContinueString(VK_API_VERSION_PATCH(deviceProperties.apiVersion)); + json.ContinueString(VK_VERSION_PATCH(deviceProperties.apiVersion)); json.EndString(); json.WriteString("GPU"); @@ -16365,7 +15155,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); - return allocator->FindMemoryTypeIndex(memoryTypeBits, pAllocationCreateInfo, UINT32_MAX, pMemoryTypeIndex); + return allocator->FindMemoryTypeIndex(memoryTypeBits, pAllocationCreateInfo, VmaBufferImageUsage::UNKNOWN, pMemoryTypeIndex); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( @@ -16383,21 +15173,22 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( const VmaVulkanFunctions* funcs = &allocator->GetVulkanFunctions(); VkResult res; -#if VMA_VULKAN_VERSION >= 1003000 +#if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 if(funcs->vkGetDeviceBufferMemoryRequirements) { // Can query straight from VkBufferCreateInfo :) - VkDeviceBufferMemoryRequirements devBufMemReq = {VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS}; + VkDeviceBufferMemoryRequirementsKHR devBufMemReq = {VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR}; devBufMemReq.pCreateInfo = pBufferCreateInfo; VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; (*funcs->vkGetDeviceBufferMemoryRequirements)(hDev, &devBufMemReq, &memReq); res = allocator->FindMemoryTypeIndex( - memReq.memoryRequirements.memoryTypeBits, pAllocationCreateInfo, pBufferCreateInfo->usage, pMemoryTypeIndex); + memReq.memoryRequirements.memoryTypeBits, pAllocationCreateInfo, + VmaBufferImageUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5), pMemoryTypeIndex); } else -#endif // #if VMA_VULKAN_VERSION >= 1003000 +#endif // VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 { // Must create a dummy buffer to query :( VkBuffer hBuffer = VK_NULL_HANDLE; @@ -16409,7 +15200,8 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( funcs->vkGetBufferMemoryRequirements(hDev, hBuffer, &memReq); res = allocator->FindMemoryTypeIndex( - memReq.memoryTypeBits, pAllocationCreateInfo, pBufferCreateInfo->usage, pMemoryTypeIndex); + memReq.memoryTypeBits, pAllocationCreateInfo, + VmaBufferImageUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5), pMemoryTypeIndex); funcs->vkDestroyBuffer( hDev, hBuffer, allocator->GetAllocationCallbacks()); @@ -16433,11 +15225,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( const VmaVulkanFunctions* funcs = &allocator->GetVulkanFunctions(); VkResult res; -#if VMA_VULKAN_VERSION >= 1003000 +#if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 if(funcs->vkGetDeviceImageMemoryRequirements) { // Can query straight from VkImageCreateInfo :) - VkDeviceImageMemoryRequirements devImgMemReq = {VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS}; + VkDeviceImageMemoryRequirementsKHR devImgMemReq = {VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR}; devImgMemReq.pCreateInfo = pImageCreateInfo; VMA_ASSERT(pImageCreateInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT_COPY && (pImageCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT_COPY) == 0 && "Cannot use this VkImageCreateInfo with vmaFindMemoryTypeIndexForImageInfo as I don't know what to pass as VkDeviceImageMemoryRequirements::planeAspect."); @@ -16446,10 +15238,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( (*funcs->vkGetDeviceImageMemoryRequirements)(hDev, &devImgMemReq, &memReq); res = allocator->FindMemoryTypeIndex( - memReq.memoryRequirements.memoryTypeBits, pAllocationCreateInfo, pImageCreateInfo->usage, pMemoryTypeIndex); + memReq.memoryRequirements.memoryTypeBits, pAllocationCreateInfo, + VmaBufferImageUsage(*pImageCreateInfo), pMemoryTypeIndex); } else -#endif // #if VMA_VULKAN_VERSION >= 1003000 +#endif // VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 { // Must create a dummy image to query :( VkImage hImage = VK_NULL_HANDLE; @@ -16461,7 +15254,8 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( funcs->vkGetImageMemoryRequirements(hDev, hImage, &memReq); res = allocator->FindMemoryTypeIndex( - memReq.memoryTypeBits, pAllocationCreateInfo, pImageCreateInfo->usage, pMemoryTypeIndex); + memReq.memoryTypeBits, pAllocationCreateInfo, + VmaBufferImageUsage(*pImageCreateInfo), pMemoryTypeIndex); funcs->vkDestroyImage( hDev, hImage, allocator->GetAllocationCallbacks()); @@ -16477,7 +15271,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( { VMA_ASSERT(allocator && pCreateInfo && pPool); - VMA_DEBUG_LOG("vmaCreatePool"); + VMA_DEBUG_LOG(Log::"vmaCreatePool"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16495,7 +15289,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( return; } - VMA_DEBUG_LOG("vmaDestroyPool"); + VMA_DEBUG_LOG(Log::"vmaDestroyPool"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16532,7 +15326,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocato VMA_DEBUG_GLOBAL_MUTEX_LOCK - VMA_DEBUG_LOG("vmaCheckPoolCorruption"); + VMA_DEBUG_LOG(Log::"vmaCheckPoolCorruption"); return allocator->CheckPoolCorruption(pool); } @@ -16544,7 +15338,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( { VMA_ASSERT(allocator && pool && ppName); - VMA_DEBUG_LOG("vmaGetPoolName"); + VMA_DEBUG_LOG(Log::"vmaGetPoolName"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16558,7 +15352,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( { VMA_ASSERT(allocator && pool); - VMA_DEBUG_LOG("vmaSetPoolName"); + VMA_DEBUG_LOG(Log::"vmaSetPoolName"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16574,7 +15368,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( { VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation); - VMA_DEBUG_LOG("vmaAllocateMemory"); + VMA_DEBUG_LOG(Log::"vmaAllocateMemory"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16584,7 +15378,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( false, // prefersDedicatedAllocation VK_NULL_HANDLE, // dedicatedBuffer VK_NULL_HANDLE, // dedicatedImage - UINT32_MAX, // dedicatedBufferImageUsage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage *pCreateInfo, VMA_SUBALLOCATION_TYPE_UNKNOWN, 1, // allocationCount @@ -16613,7 +15407,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations); - VMA_DEBUG_LOG("vmaAllocateMemoryPages"); + VMA_DEBUG_LOG(Log::"vmaAllocateMemoryPages"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16623,7 +15417,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( false, // prefersDedicatedAllocation VK_NULL_HANDLE, // dedicatedBuffer VK_NULL_HANDLE, // dedicatedImage - UINT32_MAX, // dedicatedBufferImageUsage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage *pCreateInfo, VMA_SUBALLOCATION_TYPE_UNKNOWN, allocationCount, @@ -16649,7 +15443,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( { VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation); - VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer"); + VMA_DEBUG_LOG(Log::"vmaAllocateMemoryForBuffer"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16666,7 +15460,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( prefersDedicatedAllocation, buffer, // dedicatedBuffer VK_NULL_HANDLE, // dedicatedImage - UINT32_MAX, // dedicatedBufferImageUsage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage *pCreateInfo, VMA_SUBALLOCATION_TYPE_BUFFER, 1, // allocationCount @@ -16689,7 +15483,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( { VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation); - VMA_DEBUG_LOG("vmaAllocateMemoryForImage"); + VMA_DEBUG_LOG(Log::"vmaAllocateMemoryForImage"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16705,7 +15499,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( prefersDedicatedAllocation, VK_NULL_HANDLE, // dedicatedBuffer image, // dedicatedImage - UINT32_MAX, // dedicatedBufferImageUsage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage *pCreateInfo, VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN, 1, // allocationCount @@ -16730,7 +15524,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( return; } - VMA_DEBUG_LOG("vmaFreeMemory"); + VMA_DEBUG_LOG(Log::"vmaFreeMemory"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16751,7 +15545,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( VMA_ASSERT(allocator); - VMA_DEBUG_LOG("vmaFreeMemoryPages"); + VMA_DEBUG_LOG(Log::"vmaFreeMemoryPages"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16770,6 +15564,18 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( allocator->GetAllocationInfo(allocation, pAllocationInfo); } +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( + VmaAllocator allocator, + VmaAllocation allocation, + VmaAllocationInfo2* pAllocationInfo) +{ + VMA_ASSERT(allocator && allocation && pAllocationInfo); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->GetAllocationInfo2(allocation, pAllocationInfo); +} + VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( VmaAllocator allocator, VmaAllocation allocation, @@ -16831,13 +15637,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( { VMA_ASSERT(allocator && allocation); - VMA_DEBUG_LOG("vmaFlushAllocation"); + VMA_DEBUG_LOG(Log::"vmaFlushAllocation"); VMA_DEBUG_GLOBAL_MUTEX_LOCK - const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); - - return res; + return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( @@ -16848,13 +15652,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( { VMA_ASSERT(allocator && allocation); - VMA_DEBUG_LOG("vmaInvalidateAllocation"); + VMA_DEBUG_LOG(Log::"vmaInvalidateAllocation"); VMA_DEBUG_GLOBAL_MUTEX_LOCK - const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); - - return res; + return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( @@ -16873,13 +15675,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( VMA_ASSERT(allocations); - VMA_DEBUG_LOG("vmaFlushAllocations"); + VMA_DEBUG_LOG(Log::"vmaFlushAllocations"); VMA_DEBUG_GLOBAL_MUTEX_LOCK - const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH); - - return res; + return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( @@ -16898,13 +15698,53 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( VMA_ASSERT(allocations); - VMA_DEBUG_LOG("vmaInvalidateAllocations"); + VMA_DEBUG_LOG(Log::"vmaInvalidateAllocations"); VMA_DEBUG_GLOBAL_MUTEX_LOCK - const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE); + return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE); +} - return res; +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( + VmaAllocator allocator, + const void* pSrcHostPointer, + VmaAllocation dstAllocation, + VkDeviceSize dstAllocationLocalOffset, + VkDeviceSize size) +{ + VMA_ASSERT(allocator && pSrcHostPointer && dstAllocation); + + if(size == 0) + { + return VK_SUCCESS; + } + + VMA_DEBUG_LOG(Log::"vmaCopyMemoryToAllocation"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->CopyMemoryToAllocation(pSrcHostPointer, dstAllocation, dstAllocationLocalOffset, size); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( + VmaAllocator allocator, + VmaAllocation srcAllocation, + VkDeviceSize srcAllocationLocalOffset, + void* pDstHostPointer, + VkDeviceSize size) +{ + VMA_ASSERT(allocator && srcAllocation && pDstHostPointer); + + if(size == 0) + { + return VK_SUCCESS; + } + + VMA_DEBUG_LOG(Log::"vmaCopyAllocationToMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->CopyAllocationToMemory(srcAllocation, srcAllocationLocalOffset, pDstHostPointer, size); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( @@ -16913,7 +15753,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( { VMA_ASSERT(allocator); - VMA_DEBUG_LOG("vmaCheckCorruption"); + VMA_DEBUG_LOG(Log::"vmaCheckCorruption"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16927,7 +15767,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( { VMA_ASSERT(allocator && pInfo && pContext); - VMA_DEBUG_LOG("vmaBeginDefragmentation"); + VMA_DEBUG_LOG(Log::"vmaBeginDefragmentation"); if (pInfo->pool != VMA_NULL) { @@ -16949,7 +15789,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( { VMA_ASSERT(allocator && context); - VMA_DEBUG_LOG("vmaEndDefragmentation"); + VMA_DEBUG_LOG(Log::"vmaEndDefragmentation"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16965,7 +15805,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( { VMA_ASSERT(context && pPassInfo); - VMA_DEBUG_LOG("vmaBeginDefragmentationPass"); + VMA_DEBUG_LOG(Log::"vmaBeginDefragmentationPass"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16979,7 +15819,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( { VMA_ASSERT(context && pPassInfo); - VMA_DEBUG_LOG("vmaEndDefragmentationPass"); + VMA_DEBUG_LOG(Log::"vmaEndDefragmentationPass"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -16993,7 +15833,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( { VMA_ASSERT(allocator && allocation && buffer); - VMA_DEBUG_LOG("vmaBindBufferMemory"); + VMA_DEBUG_LOG(Log::"vmaBindBufferMemory"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17009,7 +15849,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( { VMA_ASSERT(allocator && allocation && buffer); - VMA_DEBUG_LOG("vmaBindBufferMemory2"); + VMA_DEBUG_LOG(Log::"vmaBindBufferMemory2"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17023,7 +15863,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( { VMA_ASSERT(allocator && allocation && image); - VMA_DEBUG_LOG("vmaBindImageMemory"); + VMA_DEBUG_LOG(Log::"vmaBindImageMemory"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17039,7 +15879,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( { VMA_ASSERT(allocator && allocation && image); - VMA_DEBUG_LOG("vmaBindImageMemory2"); + VMA_DEBUG_LOG(Log::"vmaBindImageMemory2"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17067,7 +15907,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( return VK_ERROR_INITIALIZATION_FAILED; } - VMA_DEBUG_LOG("vmaCreateBuffer"); + VMA_DEBUG_LOG(Log::"vmaCreateBuffer"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17096,7 +15936,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( prefersDedicatedAllocation, *pBuffer, // dedicatedBuffer VK_NULL_HANDLE, // dedicatedImage - pBufferCreateInfo->usage, // dedicatedBufferImageUsage + VmaBufferImageUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5), // dedicatedBufferImageUsage *pAllocationCreateInfo, VMA_SUBALLOCATION_TYPE_BUFFER, 1, // allocationCount @@ -17113,7 +15953,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( { // All steps succeeded. #if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage); + (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); #endif if(pAllocationInfo != VMA_NULL) { @@ -17159,7 +15999,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( return VK_ERROR_INITIALIZATION_FAILED; } - VMA_DEBUG_LOG("vmaCreateBufferWithAlignment"); + VMA_DEBUG_LOG(Log::"vmaCreateBufferWithAlignment"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17191,7 +16031,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( prefersDedicatedAllocation, *pBuffer, // dedicatedBuffer VK_NULL_HANDLE, // dedicatedImage - pBufferCreateInfo->usage, // dedicatedBufferImageUsage + VmaBufferImageUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5), // dedicatedBufferImageUsage *pAllocationCreateInfo, VMA_SUBALLOCATION_TYPE_BUFFER, 1, // allocationCount @@ -17208,7 +16048,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( { // All steps succeeded. #if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage); + (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); #endif if(pAllocationInfo != VMA_NULL) { @@ -17251,7 +16091,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( VMA_ASSERT(allocator && pBufferCreateInfo && pBuffer && allocation); VMA_ASSERT(allocationLocalOffset + pBufferCreateInfo->size <= allocation->GetSize()); - VMA_DEBUG_LOG("vmaCreateAliasingBuffer2"); + VMA_DEBUG_LOG(Log::"vmaCreateAliasingBuffer2"); *pBuffer = VK_NULL_HANDLE; @@ -17299,7 +16139,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( return; } - VMA_DEBUG_LOG("vmaDestroyBuffer"); + VMA_DEBUG_LOG(Log::"vmaDestroyBuffer"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17335,7 +16175,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( return VK_ERROR_INITIALIZATION_FAILED; } - VMA_DEBUG_LOG("vmaCreateImage"); + VMA_DEBUG_LOG(Log::"vmaCreateImage"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17367,7 +16207,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( prefersDedicatedAllocation, VK_NULL_HANDLE, // dedicatedBuffer *pImage, // dedicatedImage - pImageCreateInfo->usage, // dedicatedBufferImageUsage + VmaBufferImageUsage(*pImageCreateInfo), // dedicatedBufferImageUsage *pAllocationCreateInfo, suballocType, 1, // allocationCount @@ -17384,7 +16224,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( { // All steps succeeded. #if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferImageUsage(pImageCreateInfo->usage); + (*pAllocation)->InitImageUsage(*pImageCreateInfo); #endif if(pAllocationInfo != VMA_NULL) { @@ -17428,7 +16268,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( *pImage = VK_NULL_HANDLE; - VMA_DEBUG_LOG("vmaCreateImage2"); + VMA_DEBUG_LOG(Log::"vmaCreateImage2"); if (pImageCreateInfo->extent.width == 0 || pImageCreateInfo->extent.height == 0 || @@ -17472,7 +16312,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( return; } - VMA_DEBUG_LOG("vmaDestroyImage"); + VMA_DEBUG_LOG(Log::"vmaDestroyImage"); VMA_DEBUG_GLOBAL_MUTEX_LOCK @@ -17494,7 +16334,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( { VMA_ASSERT(pCreateInfo && pVirtualBlock); VMA_ASSERT(pCreateInfo->size > 0); - VMA_DEBUG_LOG("vmaCreateVirtualBlock"); + VMA_DEBUG_LOG(Log::"vmaCreateVirtualBlock"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; *pVirtualBlock = vma_new(pCreateInfo->pAllocationCallbacks, VmaVirtualBlock_T)(*pCreateInfo); VkResult res = (*pVirtualBlock)->Init(); @@ -17510,7 +16350,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock(VmaVirtualBlock VMA_NULLA { if(virtualBlock != VK_NULL_HANDLE) { - VMA_DEBUG_LOG("vmaDestroyVirtualBlock"); + VMA_DEBUG_LOG(Log::"vmaDestroyVirtualBlock"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; VkAllocationCallbacks allocationCallbacks = virtualBlock->m_AllocationCallbacks; // Have to copy the callbacks when destroying. vma_delete(&allocationCallbacks, virtualBlock); @@ -17520,7 +16360,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock(VmaVirtualBlock VMA_NULLA VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty(VmaVirtualBlock VMA_NOT_NULL virtualBlock) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); - VMA_DEBUG_LOG("vmaIsVirtualBlockEmpty"); + VMA_DEBUG_LOG(Log::"vmaIsVirtualBlockEmpty"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; return virtualBlock->IsEmpty() ? VK_TRUE : VK_FALSE; } @@ -17529,7 +16369,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo(VmaVirtualBlock VMA_ VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pVirtualAllocInfo != VMA_NULL); - VMA_DEBUG_LOG("vmaGetVirtualAllocationInfo"); + VMA_DEBUG_LOG(Log::"vmaGetVirtualAllocationInfo"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; virtualBlock->GetAllocationInfo(allocation, *pVirtualAllocInfo); } @@ -17539,7 +16379,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate(VmaVirtualBlock VMA_NOT_N VkDeviceSize* VMA_NULLABLE pOffset) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pCreateInfo != VMA_NULL && pAllocation != VMA_NULL); - VMA_DEBUG_LOG("vmaVirtualAllocate"); + VMA_DEBUG_LOG(Log::"vmaVirtualAllocate"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; return virtualBlock->Allocate(*pCreateInfo, *pAllocation, pOffset); } @@ -17549,7 +16389,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(VmaVirtualBlock VMA_NOT_NULL virt if(allocation != VK_NULL_HANDLE) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); - VMA_DEBUG_LOG("vmaVirtualFree"); + VMA_DEBUG_LOG(Log::"vmaVirtualFree"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; virtualBlock->Free(allocation); } @@ -17558,7 +16398,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(VmaVirtualBlock VMA_NOT_NULL virt VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock(VmaVirtualBlock VMA_NOT_NULL virtualBlock) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); - VMA_DEBUG_LOG("vmaClearVirtualBlock"); + VMA_DEBUG_LOG(Log::"vmaClearVirtualBlock"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; virtualBlock->Clear(); } @@ -17567,7 +16407,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData(VmaVirtualBlock VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, void* VMA_NULLABLE pUserData) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); - VMA_DEBUG_LOG("vmaSetVirtualAllocationUserData"); + VMA_DEBUG_LOG(Log::"vmaSetVirtualAllocationUserData"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; virtualBlock->SetAllocationUserData(allocation, pUserData); } @@ -17576,7 +16416,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics(VmaVirtualBlock VMA VmaStatistics* VMA_NOT_NULL pStats) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pStats != VMA_NULL); - VMA_DEBUG_LOG("vmaGetVirtualBlockStatistics"); + VMA_DEBUG_LOG(Log::"vmaGetVirtualBlockStatistics"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; virtualBlock->GetStatistics(*pStats); } @@ -17585,7 +16425,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics(VmaVirtualBlo VmaDetailedStatistics* VMA_NOT_NULL pStats) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pStats != VMA_NULL); - VMA_DEBUG_LOG("vmaCalculateVirtualBlockStatistics"); + VMA_DEBUG_LOG(Log::"vmaCalculateVirtualBlockStatistics"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; virtualBlock->CalculateDetailedStatistics(*pStats); } @@ -17623,13 +16463,14 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock V \section quick_start_project_setup Project setup Vulkan Memory Allocator comes in form of a "stb-style" single header file. -You don't need to build it as a separate library project. -You can add this file directly to your project and submit it to code repository next to your other source files. +While you can pull the entire repository e.g. as Git module, there is also Cmake script provided, +you don't need to build it as a separate library project. +You can add file "vk_mem_alloc.h" directly to your project and submit it to code repository next to your other source files. "Single header" doesn't mean that everything is contained in C/C++ declarations, like it tends to be in case of inline functions or C++ templates. It means that implementation is bundled with interface in a single file and needs to be extracted using preprocessor macro. -If you don't do it properly, you will get linker errors. +If you don't do it properly, it will result in linker errors. To do it properly: @@ -17643,33 +16484,46 @@ To do it properly: #include "vk_mem_alloc.h" \endcode -It may be a good idea to create dedicated CPP file just for this purpose. +It may be a good idea to create dedicated CPP file just for this purpose, e.g. "VmaUsage.cpp". This library includes header ``, which in turn includes `` on Windows. If you need some specific macros defined before including these headers (like `WIN32_LEAN_AND_MEAN` or `WINVER` for Windows, `VK_USE_PLATFORM_WIN32_KHR` for Vulkan), you must define them before every `#include` of this library. +It may be a good idea to create a dedicate header file for this purpose, e.g. "VmaUsage.h", +that will be included in other source files instead of VMA header directly. This library is written in C++, but has C-compatible interface. -Thus you can include and use vk_mem_alloc.h in C or C++ code, but full +Thus, you can include and use "vk_mem_alloc.h" in C or C++ code, but full implementation with `VMA_IMPLEMENTATION` macro must be compiled as C++, NOT as C. -Some features of C++14 are used. STL containers, RTTI, or C++ exceptions are not used. +Some features of C++14 are used and required. Features of C++20 are used optionally when available. +Some headers of standard C and C++ library are used, but STL containers, RTTI, or C++ exceptions are not used. \section quick_start_initialization Initialization +VMA offers library interface in a style similar to Vulkan, with object handles like #VmaAllocation, +structures describing parameters of objects to be created like #VmaAllocationCreateInfo, +and errors codes returned from functions using `VkResult` type. + +The first and the main object that needs to be created is #VmaAllocator. +It represents the initialization of the entire library. +Only one such object should be created per `VkDevice`. +You should create it at program startup, after `VkDevice` was created, and before any device memory allocator needs to be made. +It must be destroyed before `VkDevice` is destroyed. + At program startup: --# Initialize Vulkan to have `VkPhysicalDevice`, `VkDevice` and `VkInstance` object. --# Fill VmaAllocatorCreateInfo structure and create #VmaAllocator object by - calling vmaCreateAllocator(). +-# Initialize Vulkan to have `VkInstance`, `VkPhysicalDevice`, `VkDevice` object. +-# Fill VmaAllocatorCreateInfo structure and call vmaCreateAllocator() to create #VmaAllocator object. Only members `physicalDevice`, `device`, `instance` are required. However, you should inform the library which Vulkan version do you use by setting VmaAllocatorCreateInfo::vulkanApiVersion and which extensions did you enable -by setting VmaAllocatorCreateInfo::flags (like #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT for VK_KHR_buffer_device_address). +by setting VmaAllocatorCreateInfo::flags. Otherwise, VMA would use only features of Vulkan 1.0 core with no extensions. +See below for details. \subsection quick_start_initialization_selecting_vulkan_version Selecting Vulkan version @@ -17715,7 +16569,25 @@ You may need to configure importing Vulkan functions. There are 3 ways to do thi - Define `VMA_STATIC_VULKAN_FUNCTIONS` and `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 0. - Pass these pointers via structure #VmaVulkanFunctions. -Example for case 2: +\subsection quick_start_initialization_enabling_extensions Enabling extensions + +VMA can automatically use following Vulkan extensions. +If you found them available on the selected physical device and you enabled them +while creating `VkInstance` / `VkDevice` object, inform VMA about their availability +by setting appropriate flags in VmaAllocatorCreateInfo::flags. + +Vulkan extension | VMA flag +------------------------------|----------------------------------------------------- +VK_KHR_dedicated_allocation | #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT +VK_KHR_bind_memory2 | #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT +VK_KHR_maintenance4 | #VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT +VK_KHR_maintenance5 | #VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT +VK_EXT_memory_budget | #VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT +VK_KHR_buffer_device_address | #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT +VK_EXT_memory_priority | #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT +VK_AMD_device_coherent_memory | #VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT + +Example with fetching pointers to Vulkan functions dynamically: \code #define VMA_STATIC_VULKAN_FUNCTIONS 0 @@ -17729,6 +16601,7 @@ vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr; vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr; VmaAllocatorCreateInfo allocatorCreateInfo = {}; +allocatorCreateInfo.flags = VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2; allocatorCreateInfo.physicalDevice = physicalDevice; allocatorCreateInfo.device = device; @@ -17737,9 +16610,24 @@ allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; VmaAllocator allocator; vmaCreateAllocator(&allocatorCreateInfo, &allocator); + +// Entire program... + +// At the end, don't forget to: +vmaDestroyAllocator(allocator); \endcode +\subsection quick_start_initialization_other_config Other configuration options + +There are additional configuration options available through preprocessor macros that you can define +before including VMA header and through parameters passed in #VmaAllocatorCreateInfo. +They include a possibility to use your own callbacks for host memory allocations (`VkAllocationCallbacks`), +callbacks for device memory allocations (instead of `vkAllocateMemory`, `vkFreeMemory`), +or your custom `VMA_ASSERT` macro, among others. +For more information, see: @ref configuration. + + \section quick_start_resource_allocation Resource allocation When you want to create a buffer or image: @@ -17762,13 +16650,19 @@ VmaAllocation allocation; vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); \endcode -Don't forget to destroy your objects when no longer needed: +Don't forget to destroy your buffer and allocation objects when no longer needed: \code vmaDestroyBuffer(allocator, buffer, allocation); -vmaDestroyAllocator(allocator); \endcode +If you need to map the buffer, you must set flag +#VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT +in VmaAllocationCreateInfo::flags. +There are many additional parameters that can control the choice of memory type to be used for the allocation +and other features. +For more information, see documentation chapters: @ref choosing_memory_type, @ref memory_mapping. + \page choosing_memory_type Choosing memory type @@ -17791,10 +16685,10 @@ You can also combine multiple methods. vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(). For binding you should use functions: vmaBindBufferMemory(), vmaBindImageMemory() or their extended versions: vmaBindBufferMemory2(), vmaBindImageMemory2(). --# **This is the easiest and recommended way to use this library:** - If you want to create a buffer or an image, allocate memory for it and bind +-# If you want to create a buffer or an image, allocate memory for it, and bind them together, all in one call, you can use function vmaCreateBuffer(), vmaCreateImage(). + This is the easiest and recommended way to use this library! When using 3. or 4., the library internally queries Vulkan for memory types supported for that buffer or image (function `vkGetBufferMemoryRequirements()`) @@ -17844,7 +16738,7 @@ so you can map it. For example, a staging buffer that will be filled via mapped pointer and then used as a source of transfer to the buffer described previously can be created like this. -It will likely and up in a memory type that is `HOST_VISIBLE` and `HOST_COHERENT` +It will likely end up in a memory type that is `HOST_VISIBLE` and `HOST_COHERENT` but not `HOST_CACHED` (meaning uncached, write-combined) and not `DEVICE_LOCAL` (meaning system RAM). \code @@ -17862,6 +16756,7 @@ vmaCreateBuffer(allocator, &stagingBufferInfo, &stagingAllocInfo, &stagingBuffer \endcode For more examples of creating different kinds of resources, see chapter \ref usage_patterns. +See also: @ref memory_mapping. Usage values `VMA_MEMORY_USAGE_AUTO*` are legal to use only when the library knows about the resource being created by having `VkBufferCreateInfo` / `VkImageCreateInfo` passed, @@ -17873,7 +16768,7 @@ memory type, as described below. Old usage values (`VMA_MEMORY_USAGE_GPU_ONLY`, `VMA_MEMORY_USAGE_CPU_ONLY`, `VMA_MEMORY_USAGE_CPU_TO_GPU`, `VMA_MEMORY_USAGE_GPU_TO_CPU`, `VMA_MEMORY_USAGE_CPU_COPY`) are still available and work same way as in previous versions of the library -for backward compatibility, but they are not recommended. +for backward compatibility, but they are deprecated. \section choosing_memory_type_required_preferred_flags Required and preferred flags @@ -17903,8 +16798,8 @@ plus some extra "magic" (heuristics). \section choosing_memory_type_explicit_memory_types Explicit memory types -If you inspected memory types available on the physical device and you have -a preference for memory types that you want to use, you can fill member +If you inspected memory types available on the physical device and you have +a preference for memory types that you want to use, you can fill member VmaAllocationCreateInfo::memoryTypeBits. It is a bit mask, where each bit set means that a memory type with that index is allowed to be used for the allocation. Special value 0, just like `UINT32_MAX`, means there are no @@ -17926,6 +16821,21 @@ VmaAllocation allocation; vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); \endcode +You can also use this parameter to exclude some memory types. +If you inspect memory heaps and types available on the current physical device and +you determine that for some reason you don't want to use a specific memory type for the allocation, +you can enable automatic memory type selection but exclude certain memory type or types +by setting all bits of `memoryTypeBits` to 1 except the ones you choose. + +\code +// ... +uint32_t excludedMemoryTypeIndex = 2; +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocInfo.memoryTypeBits = ~(1u << excludedMemoryTypeIndex); +// ... +\endcode + \section choosing_memory_type_custom_memory_pools Custom memory pools @@ -17964,6 +16874,7 @@ You can use them directly with memory allocated by this library, but it is not recommended because of following issue: Mapping the same `VkDeviceMemory` block multiple times is illegal - only one mapping at a time is allowed. This includes mapping disjoint regions. Mapping is not reference-counted internally by Vulkan. +It is also not thread-safe. Because of this, Vulkan Memory Allocator provides following facilities: \note If you want to be able to map an allocation, you need to specify one of the flags @@ -17971,11 +16882,44 @@ Because of this, Vulkan Memory Allocator provides following facilities: in VmaAllocationCreateInfo::flags. These flags are required for an allocation to be mappable when using #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` enum values. For other usage values they are ignored and every such allocation made in `HOST_VISIBLE` memory type is mappable, -but they can still be used for consistency. +but these flags can still be used for consistency. + +\section memory_mapping_copy_functions Copy functions + +The easiest way to copy data from a host pointer to an allocation is to use convenience function vmaCopyMemoryToAllocation(). +It automatically maps the Vulkan memory temporarily (if not already mapped), performs `memcpy`, +and calls `vkFlushMappedMemoryRanges` (if required - if memory type is not `HOST_COHERENT`). + +It is also the safest one, because using `memcpy` avoids a risk of accidentally introducing memory reads +(e.g. by doing `pMappedVectors[i] += v`), which may be very slow on memory types that are not `HOST_CACHED`. + +\code +struct ConstantBuffer +{ + ... +}; +ConstantBuffer constantBufferData = ... + +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = sizeof(ConstantBuffer); +bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + +VkBuffer buf; +VmaAllocation alloc; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, nullptr); + +vmaCopyMemoryToAllocation(allocator, &constantBufferData, alloc, 0, sizeof(ConstantBuffer)); +\endcode + +Copy in the other direction - from an allocation to a host pointer can be performed the same way using function vmaCopyAllocationToMemory(). \section memory_mapping_mapping_functions Mapping functions -The library provides following functions for mapping of a specific #VmaAllocation: vmaMapMemory(), vmaUnmapMemory(). +The library provides following functions for mapping of a specific allocation: vmaMapMemory(), vmaUnmapMemory(). They are safer and more convenient to use than standard Vulkan functions. You can map an allocation multiple times simultaneously - mapping is reference-counted internally. You can also map different allocations simultaneously regardless of whether they use the same `VkDeviceMemory` block. @@ -18236,6 +17180,12 @@ vkDestroyImage(allocator, img2, nullptr); vkDestroyImage(allocator, img1, nullptr); \endcode +VMA also provides convenience functions that create a buffer or image and bind it to memory +represented by an existing #VmaAllocation: +vmaCreateAliasingBuffer(), vmaCreateAliasingBuffer2(), +vmaCreateAliasingImage(), vmaCreateAliasingImage2(). +Versions with "2" offer additional parameter `allocationLocalOffset`. + Remember that using resources that alias in memory requires proper synchronization. You need to issue a memory barrier to make sure commands that use `img1` and `img2` don't overlap on GPU timeline. @@ -18265,6 +17215,7 @@ A memory pool contains a number of `VkDeviceMemory` blocks. The library automatically creates and manages default pool for each memory type available on the device. Default memory pool automatically grows in size. Size of allocated blocks is also variable and managed automatically. +You are using default pools whenever you leave VmaAllocationCreateInfo::pool = null. You can create custom pool and allocate memory out of it. It can be useful if you want to: @@ -18336,13 +17287,6 @@ It is supported only when VmaPoolCreateInfo::blockSize = 0. To use this feature, set VmaAllocationCreateInfo::pool to the pointer to your custom pool and VmaAllocationCreateInfo::flags to #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. -\note Excessive use of custom pools is a common mistake when using this library. -Custom pools may be useful for special purposes - when you want to -keep certain type of resources separate e.g. to reserve minimum amount of memory -for them or limit maximum amount of memory they can occupy. For most -resources this is not needed and so it is not recommended to create #VmaPool -objects and allocations out of them. Allocating from the default pool is sufficient. - \section custom_memory_pools_MemTypeIndex Choosing memory type index @@ -18377,6 +17321,51 @@ When creating buffers/images allocated in that pool, provide following parameter - VmaAllocationCreateInfo: You don't need to pass same parameters. Fill only `pool` member. Other members are ignored anyway. + +\section custom_memory_pools_when_not_use When not to use custom pools + +Custom pools are commonly overused by VMA users. +While it may feel natural to keep some logical groups of resources separate in memory, +in most cases it does more harm than good. +Using custom pool shouldn't be your first choice. +Instead, please make all allocations from default pools first and only use custom pools +if you can prove and measure that it is beneficial in some way, +e.g. it results in lower memory usage, better performance, etc. + +Using custom pools has disadvantages: + +- Each pool has its own collection of `VkDeviceMemory` blocks. + Some of them may be partially or even completely empty. + Spreading allocations across multiple pools increases the amount of wasted (allocated but unbound) memory. +- You must manually choose specific memory type to be used by a custom pool (set as VmaPoolCreateInfo::memoryTypeIndex). + When using default pools, best memory type for each of your allocations can be selected automatically + using a carefully design algorithm that works across all kinds of GPUs. +- If an allocation from a custom pool at specific memory type fails, entire allocation operation returns failure. + When using default pools, VMA tries another compatible memory type. +- If you set VmaPoolCreateInfo::blockSize != 0, each memory block has the same size, + while default pools start from small blocks and only allocate next blocks larger and larger + up to the preferred block size. + +Many of the common concerns can be addressed in a different way than using custom pools: + +- If you want to keep your allocations of certain size (small versus large) or certain lifetime (transient versus long lived) + separate, you likely don't need to. + VMA uses a high quality allocation algorithm that manages memory well in various cases. + Please measure and check if using custom pools provides a benefit. +- If you want to keep your images and buffers separate, you don't need to. + VMA respects `bufferImageGranularity` limit automatically. +- If you want to keep your mapped and not mapped allocations separate, you don't need to. + VMA respects `nonCoherentAtomSize` limit automatically. + It also maps only those `VkDeviceMemory` blocks that need to map any allocation. + It even tries to keep mappable and non-mappable allocations in separate blocks to minimize the amount of mapped memory. +- If you want to choose a custom size for the default memory block, you can set it globally instead + using VmaAllocatorCreateInfo::preferredLargeHeapBlockSize. +- If you want to select specific memory type for your allocation, + you can set VmaAllocationCreateInfo::memoryTypeBits to `(1u << myMemoryTypeIndex)` instead. +- If you need to create a buffer with certain minimum alignment, you can still do it + using default pools with dedicated function vmaCreateBufferWithAlignment(). + + \section linear_algorithm Linear allocation algorithm Each Vulkan memory block managed by this library has accompanying metadata that @@ -18500,7 +17489,7 @@ for(;;) { // Inspect pass.pMoves[i].srcAllocation, identify what buffer/image it represents. VmaAllocationInfo allocInfo; - vmaGetAllocationInfo(allocator, pMoves[i].srcAllocation, &allocInfo); + vmaGetAllocationInfo(allocator, pass.pMoves[i].srcAllocation, &allocInfo); MyEngineResourceData* resData = (MyEngineResourceData*)allocInfo.pUserData; // Recreate and bind this buffer/image at: pass.pMoves[i].dstMemory, pass.pMoves[i].dstOffset. @@ -18508,7 +17497,7 @@ for(;;) VkImage newImg; res = vkCreateImage(device, &imgCreateInfo, nullptr, &newImg); // Check res... - res = vmaBindImageMemory(allocator, pMoves[i].dstTmpAllocation, newImg); + res = vmaBindImageMemory(allocator, pass.pMoves[i].dstTmpAllocation, newImg); // Check res... // Issue a vkCmdCopyBuffer/vkCmdCopyImage to copy its content to the new place. @@ -18987,22 +17976,35 @@ Margin validation (corruption detection) works only for memory types that are `HOST_VISIBLE` and `HOST_COHERENT`. -\page opengl_interop OpenGL Interop +\section debugging_memory_usage_leak_detection Leak detection features -VMA provides some features that help with interoperability with OpenGL. +At allocation and allocator destruction time VMA checks for unfreed and unmapped blocks using +`VMA_ASSERT_LEAK()`. This macro defaults to an assertion, triggering a typically fatal error in Debug +builds, and doing nothing in Release builds. You can provide your own definition of `VMA_ASSERT_LEAK()` +to change this behavior. + +At memory block destruction time VMA lists out all unfreed allocations using the `VMA_LEAK_LOG_FORMAT()` +macro, which defaults to `VMA_DEBUG_LOG_FORMAT`, which in turn defaults to a no-op. +If you're having trouble with leaks - for example, the aforementioned assertion triggers, but you don't +quite know \em why -, overriding this macro to print out the the leaking blocks, combined with assigning +individual names to allocations using vmaSetAllocationName(), can greatly aid in fixing them. + +\page other_api_interop Interop with other graphics APIs + +VMA provides some features that help with interoperability with other graphics APIs, e.g. OpenGL. \section opengl_interop_exporting_memory Exporting memory -If you want to attach `VkExportMemoryAllocateInfoKHR` structure to `pNext` chain of memory allocations made by the library: +If you want to attach `VkExportMemoryAllocateInfoKHR` or other structure to `pNext` chain of memory allocations made by the library: -It is recommended to create \ref custom_memory_pools for such allocations. +You can create \ref custom_memory_pools for such allocations. Define and fill in your `VkExportMemoryAllocateInfoKHR` structure and attach it to VmaPoolCreateInfo::pMemoryAllocateNext while creating the custom pool. Please note that the structure must remain alive and unchanged for the whole lifetime of the #VmaPool, not only while creating it, as no copy of the structure is made, but its original pointer is used for each allocation instead. -If you want to export all memory allocated by the library from certain memory types, +If you want to export all memory allocated by VMA from certain memory types, also dedicated allocations or other allocations made from default pools, an alternative solution is to fill in VmaAllocatorCreateInfo::pTypeExternalMemoryHandleTypes. It should point to an array with `VkExternalMemoryHandleTypeFlagsKHR` to be automatically passed by the library @@ -19019,7 +18021,7 @@ Buffers or images exported to a different API like OpenGL may require a differen higher than the one used by the library automatically, queried from functions like `vkGetBufferMemoryRequirements`. To impose such alignment: -It is recommended to create \ref custom_memory_pools for such allocations. +You can create \ref custom_memory_pools for such allocations. Set VmaPoolCreateInfo::minAllocationAlignment member to the minimum alignment required for each allocation to be made out of this pool. The alignment actually used will be the maximum of this member and the alignment returned for the specific buffer or image @@ -19030,8 +18032,17 @@ use special function vmaCreateBufferWithAlignment(), which takes additional para Note the problem of alignment affects only resources placed inside bigger `VkDeviceMemory` blocks and not dedicated allocations, as these, by definition, always have alignment = 0 because the resource is bound to the beginning of its dedicated block. +You can ensure that an allocation is created as dedicated by using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. Contrary to Direct3D 12, Vulkan doesn't have a concept of alignment of the entire memory block passed on its allocation. +\section opengl_interop_extended_allocation_information Extended allocation information + +If you want to rely on VMA to allocate your buffers and images inside larger memory blocks, +but you need to know the size of the entire block and whether the allocation was made +with its own dedicated memory, use function vmaGetAllocationInfo2() to retrieve +extended allocation information in structure #VmaAllocationInfo2. + + \page usage_patterns Recommended usage patterns @@ -19087,7 +18098,7 @@ to decrease chances to be evicted to system memory by the operating system. \section usage_patterns_staging_copy_upload Staging copy for upload When: -A "staging" buffer than you want to map and fill from CPU code, then use as a source od transfer +A "staging" buffer than you want to map and fill from CPU code, then use as a source of transfer to some GPU resource. What to do: @@ -19154,7 +18165,7 @@ const float* downloadedData = (const float*)allocInfo.pMappedData; \section usage_patterns_advanced_data_uploading Advanced data uploading For resources that you frequently write on CPU via mapped pointer and -freqnently read on GPU e.g. as a uniform buffer (also called "dynamic"), multiple options are possible: +frequently read on GPU e.g. as a uniform buffer (also called "dynamic"), multiple options are possible: -# Easiest solution is to have one copy of the resource in `HOST_VISIBLE` memory, even if it means system RAM (not `DEVICE_LOCAL`) on systems with a discrete graphics card, @@ -19233,6 +18244,7 @@ else // [Executed in runtime]: memcpy(stagingAllocInfo.pMappedData, myData, myDataSize); + vmaFlushAllocation(allocator, stagingAlloc, 0, VK_WHOLE_SIZE); //vkCmdPipelineBarrier: VK_ACCESS_HOST_WRITE_BIT --> VK_ACCESS_TRANSFER_READ_BIT VkBufferCopy bufCopy = { 0, // srcOffset @@ -19471,7 +18483,7 @@ vmaCreateImage(allocator, &imgCreateInfo, &allocCreateInfo, &img, &alloc, nullpt `priority` member is ignored in the following situations: - Allocations created in custom pools: They inherit the priority, along with all other allocation parameters - from the parametrs passed in #VmaPoolCreateInfo when the pool was created. + from the parameters passed in #VmaPoolCreateInfo when the pool was created. - Allocations created in default pools: They inherit the priority from the parameters VMA used when creating default pools, which means `priority == 0.5f`. diff --git a/ext/vulkan/vk_platform.h b/ext/vulkan/vk_platform.h index ed67a6004a..0ecd4f6471 100644 --- a/ext/vulkan/vk_platform.h +++ b/ext/vulkan/vk_platform.h @@ -2,7 +2,7 @@ // File: vk_platform.h // /* -** Copyright 2014-2023 The Khronos Group Inc. +** Copyright 2014-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vk_sdk_platform.h b/ext/vulkan/vk_sdk_platform.h deleted file mode 100644 index 3bdf5057bf..0000000000 --- a/ext/vulkan/vk_sdk_platform.h +++ /dev/null @@ -1,81 +0,0 @@ -// -// File: vk_sdk_platform.h -// -/* - * Copyright (c) 2015-2023 LunarG, Inc. - * Copyright (c) 2015-2023 The Khronos Group Inc. - * Copyright (c) 2015-2023 Valve Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -// Allow users to suppress warnings generated by this header file by defining VK_SDK_PLATFORM_SUPRRESS_DEPRECATION_WARNING -#ifndef VK_SDK_PLATFORM_SUPRRESS_DEPRECATION_WARNING - -#if defined(__GNUC__) && __GNUC__ >= 4 -#warning "vk_sdk_platform.h is deprecated and will be removed in future release! Use VK_SDK_PLATFORM_SUPRRESS_DEPRECATION_WARNING to suppress warning!" -#endif - -// MSVC doesn't support warning directive -#if defined(_MSC_VER) -#pragma message("vk_sdk_platform.h is deprecated and will be removed in future release! Use VK_SDK_PLATFORM_SUPRRESS_DEPRECATION_WARNING to suppress warning!") -#endif - -#endif - -#if defined(_WIN32) -#ifndef NOMINMAX -#define NOMINMAX -#endif -#ifndef __cplusplus -#undef inline -#define inline __inline -#endif // __cplusplus - -#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) -// C99: -// Microsoft didn't implement C99 in Visual Studio; but started adding it with -// VS2013. However, VS2013 still didn't have snprintf(). The following is a -// work-around (Note: The _CRT_SECURE_NO_WARNINGS macro must be set in the -// "CMakeLists.txt" file). -// NOTE: This is fixed in Visual Studio 2015. -#define snprintf _snprintf -#endif - -#define strdup _strdup - -#endif // _WIN32 - -// Check for noexcept support using clang, with fallback to Windows or GCC version numbers -#ifndef NOEXCEPT -#if defined(__clang__) -#if __has_feature(cxx_noexcept) -#define HAS_NOEXCEPT -#endif -#else -#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 -#define HAS_NOEXCEPT -#else -#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 && defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS -#define HAS_NOEXCEPT -#endif -#endif -#endif - -#ifdef HAS_NOEXCEPT -#define NOEXCEPT noexcept -#else -#define NOEXCEPT -#endif -#endif diff --git a/ext/vulkan/vk_video/vulkan_video_codec_av1std.h b/ext/vulkan/vk_video/vulkan_video_codec_av1std.h new file mode 100644 index 0000000000..8ce283e8a8 --- /dev/null +++ b/ext/vulkan/vk_video/vulkan_video_codec_av1std.h @@ -0,0 +1,392 @@ +#ifndef VULKAN_VIDEO_CODEC_AV1STD_H_ +#define VULKAN_VIDEO_CODEC_AV1STD_H_ 1 + +/* +** Copyright 2015-2024 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_av1std is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_av1std 1 +#include "vulkan_video_codecs_common.h" +#define STD_VIDEO_AV1_NUM_REF_FRAMES 8 +#define STD_VIDEO_AV1_REFS_PER_FRAME 7 +#define STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME 8 +#define STD_VIDEO_AV1_MAX_TILE_COLS 64 +#define STD_VIDEO_AV1_MAX_TILE_ROWS 64 +#define STD_VIDEO_AV1_MAX_SEGMENTS 8 +#define STD_VIDEO_AV1_SEG_LVL_MAX 8 +#define STD_VIDEO_AV1_PRIMARY_REF_NONE 7 +#define STD_VIDEO_AV1_SELECT_INTEGER_MV 2 +#define STD_VIDEO_AV1_SELECT_SCREEN_CONTENT_TOOLS 2 +#define STD_VIDEO_AV1_SKIP_MODE_FRAMES 2 +#define STD_VIDEO_AV1_MAX_LOOP_FILTER_STRENGTHS 4 +#define STD_VIDEO_AV1_LOOP_FILTER_ADJUSTMENTS 2 +#define STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS 8 +#define STD_VIDEO_AV1_MAX_NUM_PLANES 3 +#define STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS 6 +#define STD_VIDEO_AV1_MAX_NUM_Y_POINTS 14 +#define STD_VIDEO_AV1_MAX_NUM_CB_POINTS 10 +#define STD_VIDEO_AV1_MAX_NUM_CR_POINTS 10 +#define STD_VIDEO_AV1_MAX_NUM_POS_LUMA 24 +#define STD_VIDEO_AV1_MAX_NUM_POS_CHROMA 25 + +typedef enum StdVideoAV1Profile { + STD_VIDEO_AV1_PROFILE_MAIN = 0, + STD_VIDEO_AV1_PROFILE_HIGH = 1, + STD_VIDEO_AV1_PROFILE_PROFESSIONAL = 2, + STD_VIDEO_AV1_PROFILE_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_PROFILE_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1Profile; + +typedef enum StdVideoAV1Level { + STD_VIDEO_AV1_LEVEL_2_0 = 0, + STD_VIDEO_AV1_LEVEL_2_1 = 1, + STD_VIDEO_AV1_LEVEL_2_2 = 2, + STD_VIDEO_AV1_LEVEL_2_3 = 3, + STD_VIDEO_AV1_LEVEL_3_0 = 4, + STD_VIDEO_AV1_LEVEL_3_1 = 5, + STD_VIDEO_AV1_LEVEL_3_2 = 6, + STD_VIDEO_AV1_LEVEL_3_3 = 7, + STD_VIDEO_AV1_LEVEL_4_0 = 8, + STD_VIDEO_AV1_LEVEL_4_1 = 9, + STD_VIDEO_AV1_LEVEL_4_2 = 10, + STD_VIDEO_AV1_LEVEL_4_3 = 11, + STD_VIDEO_AV1_LEVEL_5_0 = 12, + STD_VIDEO_AV1_LEVEL_5_1 = 13, + STD_VIDEO_AV1_LEVEL_5_2 = 14, + STD_VIDEO_AV1_LEVEL_5_3 = 15, + STD_VIDEO_AV1_LEVEL_6_0 = 16, + STD_VIDEO_AV1_LEVEL_6_1 = 17, + STD_VIDEO_AV1_LEVEL_6_2 = 18, + STD_VIDEO_AV1_LEVEL_6_3 = 19, + STD_VIDEO_AV1_LEVEL_7_0 = 20, + STD_VIDEO_AV1_LEVEL_7_1 = 21, + STD_VIDEO_AV1_LEVEL_7_2 = 22, + STD_VIDEO_AV1_LEVEL_7_3 = 23, + STD_VIDEO_AV1_LEVEL_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_LEVEL_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1Level; + +typedef enum StdVideoAV1FrameType { + STD_VIDEO_AV1_FRAME_TYPE_KEY = 0, + STD_VIDEO_AV1_FRAME_TYPE_INTER = 1, + STD_VIDEO_AV1_FRAME_TYPE_INTRA_ONLY = 2, + STD_VIDEO_AV1_FRAME_TYPE_SWITCH = 3, + STD_VIDEO_AV1_FRAME_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_FRAME_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1FrameType; + +typedef enum StdVideoAV1ReferenceName { + STD_VIDEO_AV1_REFERENCE_NAME_INTRA_FRAME = 0, + STD_VIDEO_AV1_REFERENCE_NAME_LAST_FRAME = 1, + STD_VIDEO_AV1_REFERENCE_NAME_LAST2_FRAME = 2, + STD_VIDEO_AV1_REFERENCE_NAME_LAST3_FRAME = 3, + STD_VIDEO_AV1_REFERENCE_NAME_GOLDEN_FRAME = 4, + STD_VIDEO_AV1_REFERENCE_NAME_BWDREF_FRAME = 5, + STD_VIDEO_AV1_REFERENCE_NAME_ALTREF2_FRAME = 6, + STD_VIDEO_AV1_REFERENCE_NAME_ALTREF_FRAME = 7, + STD_VIDEO_AV1_REFERENCE_NAME_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_REFERENCE_NAME_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1ReferenceName; + +typedef enum StdVideoAV1InterpolationFilter { + STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP = 0, + STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH = 1, + STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP = 2, + STD_VIDEO_AV1_INTERPOLATION_FILTER_BILINEAR = 3, + STD_VIDEO_AV1_INTERPOLATION_FILTER_SWITCHABLE = 4, + STD_VIDEO_AV1_INTERPOLATION_FILTER_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_INTERPOLATION_FILTER_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1InterpolationFilter; + +typedef enum StdVideoAV1TxMode { + STD_VIDEO_AV1_TX_MODE_ONLY_4X4 = 0, + STD_VIDEO_AV1_TX_MODE_LARGEST = 1, + STD_VIDEO_AV1_TX_MODE_SELECT = 2, + STD_VIDEO_AV1_TX_MODE_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_TX_MODE_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1TxMode; + +typedef enum StdVideoAV1FrameRestorationType { + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE = 0, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_WIENER = 1, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SGRPROJ = 2, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SWITCHABLE = 3, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1FrameRestorationType; + +typedef enum StdVideoAV1ColorPrimaries { + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_709 = 1, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_UNSPECIFIED = 2, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_470_M = 4, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_470_B_G = 5, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_601 = 6, + STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_240 = 7, + STD_VIDEO_AV1_COLOR_PRIMARIES_GENERIC_FILM = 8, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_2020 = 9, + STD_VIDEO_AV1_COLOR_PRIMARIES_XYZ = 10, + STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_431 = 11, + STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_432 = 12, + STD_VIDEO_AV1_COLOR_PRIMARIES_EBU_3213 = 22, + STD_VIDEO_AV1_COLOR_PRIMARIES_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_COLOR_PRIMARIES_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1ColorPrimaries; + +typedef enum StdVideoAV1TransferCharacteristics { + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_RESERVED_0 = 0, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_709 = 1, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_UNSPECIFIED = 2, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_RESERVED_3 = 3, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_470_M = 4, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_470_B_G = 5, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_601 = 6, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_240 = 7, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LINEAR = 8, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LOG_100 = 9, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LOG_100_SQRT10 = 10, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_IEC_61966 = 11, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_1361 = 12, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SRGB = 13, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_2020_10_BIT = 14, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_2020_12_BIT = 15, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_2084 = 16, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_428 = 17, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_HLG = 18, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1TransferCharacteristics; + +typedef enum StdVideoAV1MatrixCoefficients { + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_IDENTITY = 0, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_709 = 1, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_UNSPECIFIED = 2, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_RESERVED_3 = 3, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_FCC = 4, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_470_B_G = 5, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_601 = 6, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_240 = 7, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_YCGCO = 8, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_2020_NCL = 9, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_2020_CL = 10, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_2085 = 11, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_CHROMAT_NCL = 12, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_CHROMAT_CL = 13, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_ICTCP = 14, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1MatrixCoefficients; + +typedef enum StdVideoAV1ChromaSamplePosition { + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_UNKNOWN = 0, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_VERTICAL = 1, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_COLOCATED = 2, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_RESERVED = 3, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1ChromaSamplePosition; +typedef struct StdVideoAV1ColorConfigFlags { + uint32_t mono_chrome : 1; + uint32_t color_range : 1; + uint32_t separate_uv_delta_q : 1; + uint32_t color_description_present_flag : 1; + uint32_t reserved : 28; +} StdVideoAV1ColorConfigFlags; + +typedef struct StdVideoAV1ColorConfig { + StdVideoAV1ColorConfigFlags flags; + uint8_t BitDepth; + uint8_t subsampling_x; + uint8_t subsampling_y; + uint8_t reserved1; + StdVideoAV1ColorPrimaries color_primaries; + StdVideoAV1TransferCharacteristics transfer_characteristics; + StdVideoAV1MatrixCoefficients matrix_coefficients; + StdVideoAV1ChromaSamplePosition chroma_sample_position; +} StdVideoAV1ColorConfig; + +typedef struct StdVideoAV1TimingInfoFlags { + uint32_t equal_picture_interval : 1; + uint32_t reserved : 31; +} StdVideoAV1TimingInfoFlags; + +typedef struct StdVideoAV1TimingInfo { + StdVideoAV1TimingInfoFlags flags; + uint32_t num_units_in_display_tick; + uint32_t time_scale; + uint32_t num_ticks_per_picture_minus_1; +} StdVideoAV1TimingInfo; + +typedef struct StdVideoAV1LoopFilterFlags { + uint32_t loop_filter_delta_enabled : 1; + uint32_t loop_filter_delta_update : 1; + uint32_t reserved : 30; +} StdVideoAV1LoopFilterFlags; + +typedef struct StdVideoAV1LoopFilter { + StdVideoAV1LoopFilterFlags flags; + uint8_t loop_filter_level[STD_VIDEO_AV1_MAX_LOOP_FILTER_STRENGTHS]; + uint8_t loop_filter_sharpness; + uint8_t update_ref_delta; + int8_t loop_filter_ref_deltas[STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME]; + uint8_t update_mode_delta; + int8_t loop_filter_mode_deltas[STD_VIDEO_AV1_LOOP_FILTER_ADJUSTMENTS]; +} StdVideoAV1LoopFilter; + +typedef struct StdVideoAV1QuantizationFlags { + uint32_t using_qmatrix : 1; + uint32_t diff_uv_delta : 1; + uint32_t reserved : 30; +} StdVideoAV1QuantizationFlags; + +typedef struct StdVideoAV1Quantization { + StdVideoAV1QuantizationFlags flags; + uint8_t base_q_idx; + int8_t DeltaQYDc; + int8_t DeltaQUDc; + int8_t DeltaQUAc; + int8_t DeltaQVDc; + int8_t DeltaQVAc; + uint8_t qm_y; + uint8_t qm_u; + uint8_t qm_v; +} StdVideoAV1Quantization; + +typedef struct StdVideoAV1Segmentation { + uint8_t FeatureEnabled[STD_VIDEO_AV1_MAX_SEGMENTS]; + int16_t FeatureData[STD_VIDEO_AV1_MAX_SEGMENTS][STD_VIDEO_AV1_SEG_LVL_MAX]; +} StdVideoAV1Segmentation; + +typedef struct StdVideoAV1TileInfoFlags { + uint32_t uniform_tile_spacing_flag : 1; + uint32_t reserved : 31; +} StdVideoAV1TileInfoFlags; + +typedef struct StdVideoAV1TileInfo { + StdVideoAV1TileInfoFlags flags; + uint8_t TileCols; + uint8_t TileRows; + uint16_t context_update_tile_id; + uint8_t tile_size_bytes_minus_1; + uint8_t reserved1[7]; + const uint16_t* pMiColStarts; + const uint16_t* pMiRowStarts; + const uint16_t* pWidthInSbsMinus1; + const uint16_t* pHeightInSbsMinus1; +} StdVideoAV1TileInfo; + +typedef struct StdVideoAV1CDEF { + uint8_t cdef_damping_minus_3; + uint8_t cdef_bits; + uint8_t cdef_y_pri_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; + uint8_t cdef_y_sec_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; + uint8_t cdef_uv_pri_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; + uint8_t cdef_uv_sec_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; +} StdVideoAV1CDEF; + +typedef struct StdVideoAV1LoopRestoration { + StdVideoAV1FrameRestorationType FrameRestorationType[STD_VIDEO_AV1_MAX_NUM_PLANES]; + uint16_t LoopRestorationSize[STD_VIDEO_AV1_MAX_NUM_PLANES]; +} StdVideoAV1LoopRestoration; + +typedef struct StdVideoAV1GlobalMotion { + uint8_t GmType[STD_VIDEO_AV1_NUM_REF_FRAMES]; + int32_t gm_params[STD_VIDEO_AV1_NUM_REF_FRAMES][STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS]; +} StdVideoAV1GlobalMotion; + +typedef struct StdVideoAV1FilmGrainFlags { + uint32_t chroma_scaling_from_luma : 1; + uint32_t overlap_flag : 1; + uint32_t clip_to_restricted_range : 1; + uint32_t update_grain : 1; + uint32_t reserved : 28; +} StdVideoAV1FilmGrainFlags; + +typedef struct StdVideoAV1FilmGrain { + StdVideoAV1FilmGrainFlags flags; + uint8_t grain_scaling_minus_8; + uint8_t ar_coeff_lag; + uint8_t ar_coeff_shift_minus_6; + uint8_t grain_scale_shift; + uint16_t grain_seed; + uint8_t film_grain_params_ref_idx; + uint8_t num_y_points; + uint8_t point_y_value[STD_VIDEO_AV1_MAX_NUM_Y_POINTS]; + uint8_t point_y_scaling[STD_VIDEO_AV1_MAX_NUM_Y_POINTS]; + uint8_t num_cb_points; + uint8_t point_cb_value[STD_VIDEO_AV1_MAX_NUM_CB_POINTS]; + uint8_t point_cb_scaling[STD_VIDEO_AV1_MAX_NUM_CB_POINTS]; + uint8_t num_cr_points; + uint8_t point_cr_value[STD_VIDEO_AV1_MAX_NUM_CR_POINTS]; + uint8_t point_cr_scaling[STD_VIDEO_AV1_MAX_NUM_CR_POINTS]; + int8_t ar_coeffs_y_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_LUMA]; + int8_t ar_coeffs_cb_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_CHROMA]; + int8_t ar_coeffs_cr_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_CHROMA]; + uint8_t cb_mult; + uint8_t cb_luma_mult; + uint16_t cb_offset; + uint8_t cr_mult; + uint8_t cr_luma_mult; + uint16_t cr_offset; +} StdVideoAV1FilmGrain; + +typedef struct StdVideoAV1SequenceHeaderFlags { + uint32_t still_picture : 1; + uint32_t reduced_still_picture_header : 1; + uint32_t use_128x128_superblock : 1; + uint32_t enable_filter_intra : 1; + uint32_t enable_intra_edge_filter : 1; + uint32_t enable_interintra_compound : 1; + uint32_t enable_masked_compound : 1; + uint32_t enable_warped_motion : 1; + uint32_t enable_dual_filter : 1; + uint32_t enable_order_hint : 1; + uint32_t enable_jnt_comp : 1; + uint32_t enable_ref_frame_mvs : 1; + uint32_t frame_id_numbers_present_flag : 1; + uint32_t enable_superres : 1; + uint32_t enable_cdef : 1; + uint32_t enable_restoration : 1; + uint32_t film_grain_params_present : 1; + uint32_t timing_info_present_flag : 1; + uint32_t initial_display_delay_present_flag : 1; + uint32_t reserved : 13; +} StdVideoAV1SequenceHeaderFlags; + +typedef struct StdVideoAV1SequenceHeader { + StdVideoAV1SequenceHeaderFlags flags; + StdVideoAV1Profile seq_profile; + uint8_t frame_width_bits_minus_1; + uint8_t frame_height_bits_minus_1; + uint16_t max_frame_width_minus_1; + uint16_t max_frame_height_minus_1; + uint8_t delta_frame_id_length_minus_2; + uint8_t additional_frame_id_length_minus_1; + uint8_t order_hint_bits_minus_1; + uint8_t seq_force_integer_mv; + uint8_t seq_force_screen_content_tools; + uint8_t reserved1[5]; + const StdVideoAV1ColorConfig* pColorConfig; + const StdVideoAV1TimingInfo* pTimingInfo; +} StdVideoAV1SequenceHeader; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/vulkan/vk_video/vulkan_video_codec_av1std_decode.h b/ext/vulkan/vk_video/vulkan_video_codec_av1std_decode.h new file mode 100644 index 0000000000..6b8130cd9f --- /dev/null +++ b/ext/vulkan/vk_video/vulkan_video_codec_av1std_decode.h @@ -0,0 +1,109 @@ +#ifndef VULKAN_VIDEO_CODEC_AV1STD_DECODE_H_ +#define VULKAN_VIDEO_CODEC_AV1STD_DECODE_H_ 1 + +/* +** Copyright 2015-2024 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_av1std_decode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_av1std_decode 1 +#include "vulkan_video_codec_av1std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_av1_decode" +typedef struct StdVideoDecodeAV1PictureInfoFlags { + uint32_t error_resilient_mode : 1; + uint32_t disable_cdf_update : 1; + uint32_t use_superres : 1; + uint32_t render_and_frame_size_different : 1; + uint32_t allow_screen_content_tools : 1; + uint32_t is_filter_switchable : 1; + uint32_t force_integer_mv : 1; + uint32_t frame_size_override_flag : 1; + uint32_t buffer_removal_time_present_flag : 1; + uint32_t allow_intrabc : 1; + uint32_t frame_refs_short_signaling : 1; + uint32_t allow_high_precision_mv : 1; + uint32_t is_motion_mode_switchable : 1; + uint32_t use_ref_frame_mvs : 1; + uint32_t disable_frame_end_update_cdf : 1; + uint32_t allow_warped_motion : 1; + uint32_t reduced_tx_set : 1; + uint32_t reference_select : 1; + uint32_t skip_mode_present : 1; + uint32_t delta_q_present : 1; + uint32_t delta_lf_present : 1; + uint32_t delta_lf_multi : 1; + uint32_t segmentation_enabled : 1; + uint32_t segmentation_update_map : 1; + uint32_t segmentation_temporal_update : 1; + uint32_t segmentation_update_data : 1; + uint32_t UsesLr : 1; + uint32_t usesChromaLr : 1; + uint32_t apply_grain : 1; + uint32_t reserved : 3; +} StdVideoDecodeAV1PictureInfoFlags; + +typedef struct StdVideoDecodeAV1PictureInfo { + StdVideoDecodeAV1PictureInfoFlags flags; + StdVideoAV1FrameType frame_type; + uint32_t current_frame_id; + uint8_t OrderHint; + uint8_t primary_ref_frame; + uint8_t refresh_frame_flags; + uint8_t reserved1; + StdVideoAV1InterpolationFilter interpolation_filter; + StdVideoAV1TxMode TxMode; + uint8_t delta_q_res; + uint8_t delta_lf_res; + uint8_t SkipModeFrame[STD_VIDEO_AV1_SKIP_MODE_FRAMES]; + uint8_t coded_denom; + uint8_t reserved2[3]; + uint8_t OrderHints[STD_VIDEO_AV1_NUM_REF_FRAMES]; + uint32_t expectedFrameId[STD_VIDEO_AV1_NUM_REF_FRAMES]; + const StdVideoAV1TileInfo* pTileInfo; + const StdVideoAV1Quantization* pQuantization; + const StdVideoAV1Segmentation* pSegmentation; + const StdVideoAV1LoopFilter* pLoopFilter; + const StdVideoAV1CDEF* pCDEF; + const StdVideoAV1LoopRestoration* pLoopRestoration; + const StdVideoAV1GlobalMotion* pGlobalMotion; + const StdVideoAV1FilmGrain* pFilmGrain; +} StdVideoDecodeAV1PictureInfo; + +typedef struct StdVideoDecodeAV1ReferenceInfoFlags { + uint32_t disable_frame_end_update_cdf : 1; + uint32_t segmentation_enabled : 1; + uint32_t reserved : 30; +} StdVideoDecodeAV1ReferenceInfoFlags; + +typedef struct StdVideoDecodeAV1ReferenceInfo { + StdVideoDecodeAV1ReferenceInfoFlags flags; + uint8_t frame_type; + uint8_t RefFrameSignBias; + uint8_t OrderHint; + uint8_t SavedOrderHints[STD_VIDEO_AV1_NUM_REF_FRAMES]; +} StdVideoDecodeAV1ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/vulkan/vk_video/vulkan_video_codec_h264std.h b/ext/vulkan/vk_video/vulkan_video_codec_h264std.h index a23789c68a..6d27af37b7 100644 --- a/ext/vulkan/vk_video/vulkan_video_codec_h264std.h +++ b/ext/vulkan/vk_video/vulkan_video_codec_h264std.h @@ -2,7 +2,7 @@ #define VULKAN_VIDEO_CODEC_H264STD_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -29,6 +29,7 @@ extern "C" { #define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS 64 #define STD_VIDEO_H264_MAX_NUM_LIST_REF 32 #define STD_VIDEO_H264_MAX_CHROMA_PLANES 2 +#define STD_VIDEO_H264_NO_REFERENCE_PICTURE 0xFF typedef enum StdVideoH264ChromaFormatIdc { STD_VIDEO_H264_CHROMA_FORMAT_IDC_MONOCHROME = 0, diff --git a/ext/vulkan/vk_video/vulkan_video_codec_h264std_decode.h b/ext/vulkan/vk_video/vulkan_video_codec_h264std_decode.h index dd24112e2c..439cb885e7 100644 --- a/ext/vulkan/vk_video/vulkan_video_codec_h264std_decode.h +++ b/ext/vulkan/vk_video/vulkan_video_codec_h264std_decode.h @@ -2,7 +2,7 @@ #define VULKAN_VIDEO_CODEC_H264STD_DECODE_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vk_video/vulkan_video_codec_h264std_encode.h b/ext/vulkan/vk_video/vulkan_video_codec_h264std_encode.h index 2e0d706f6c..9e24aa5d99 100644 --- a/ext/vulkan/vk_video/vulkan_video_codec_h264std_encode.h +++ b/ext/vulkan/vk_video/vulkan_video_codec_h264std_encode.h @@ -2,7 +2,7 @@ #define VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -22,10 +22,10 @@ extern "C" { // vulkan_video_codec_h264std_encode is a preprocessor guard. Do not pass it to API calls. #define vulkan_video_codec_h264std_encode 1 #include "vulkan_video_codec_h264std.h" -// Vulkan 0.9 provisional Vulkan video H.264 encode std specification version number -#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_0_9_10 VK_MAKE_VIDEO_STD_VERSION(0, 9, 10) -#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_0_9_10 +#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0 #define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_encode" typedef struct StdVideoEncodeH264WeightTableFlags { uint32_t luma_weight_l0_flag; @@ -81,7 +81,7 @@ typedef struct StdVideoEncodeH264RefListModEntry { } StdVideoEncodeH264RefListModEntry; typedef struct StdVideoEncodeH264RefPicMarkingEntry { - StdVideoH264MemMgmtControlOp operation; + StdVideoH264MemMgmtControlOp memory_management_control_operation; uint16_t difference_of_pic_nums_minus1; uint16_t long_term_pic_num; uint16_t long_term_frame_idx; @@ -132,7 +132,8 @@ typedef struct StdVideoEncodeH264SliceHeader { StdVideoH264SliceType slice_type; int8_t slice_alpha_c0_offset_div2; int8_t slice_beta_offset_div2; - uint16_t reserved1; + int8_t slice_qp_delta; + uint8_t reserved1; StdVideoH264CabacInitIdc cabac_init_idc; StdVideoH264DisableDeblockingFilterIdc disable_deblocking_filter_idc; const StdVideoEncodeH264WeightTable* pWeightTable; diff --git a/ext/vulkan/vk_video/vulkan_video_codec_h265std.h b/ext/vulkan/vk_video/vulkan_video_codec_h265std.h index 793bdbcff9..d0a1bacbea 100644 --- a/ext/vulkan/vk_video/vulkan_video_codec_h265std.h +++ b/ext/vulkan/vk_video/vulkan_video_codec_h265std.h @@ -2,7 +2,7 @@ #define VULKAN_VIDEO_CODEC_H265STD_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -44,6 +44,7 @@ extern "C" { #define STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS 32 #define STD_VIDEO_H265_MAX_LONG_TERM_PICS 16 #define STD_VIDEO_H265_MAX_DELTA_POC 48 +#define STD_VIDEO_H265_NO_REFERENCE_PICTURE 0xFF typedef enum StdVideoH265ChromaFormatIdc { STD_VIDEO_H265_CHROMA_FORMAT_IDC_MONOCHROME = 0, diff --git a/ext/vulkan/vk_video/vulkan_video_codec_h265std_decode.h b/ext/vulkan/vk_video/vulkan_video_codec_h265std_decode.h index 75cf4d0946..0178793e51 100644 --- a/ext/vulkan/vk_video/vulkan_video_codec_h265std_decode.h +++ b/ext/vulkan/vk_video/vulkan_video_codec_h265std_decode.h @@ -2,7 +2,7 @@ #define VULKAN_VIDEO_CODEC_H265STD_DECODE_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vk_video/vulkan_video_codec_h265std_encode.h b/ext/vulkan/vk_video/vulkan_video_codec_h265std_encode.h index 25740398a4..ee34491f4e 100644 --- a/ext/vulkan/vk_video/vulkan_video_codec_h265std_encode.h +++ b/ext/vulkan/vk_video/vulkan_video_codec_h265std_encode.h @@ -2,7 +2,7 @@ #define VULKAN_VIDEO_CODEC_H265STD_ENCODE_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -22,10 +22,10 @@ extern "C" { // vulkan_video_codec_h265std_encode is a preprocessor guard. Do not pass it to API calls. #define vulkan_video_codec_h265std_encode 1 #include "vulkan_video_codec_h265std.h" -// Vulkan 0.9 provisional Vulkan video H.265 encode std specification version number -#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_0_9_11 VK_MAKE_VIDEO_STD_VERSION(0, 9, 11) -#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_0_9_11 +#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0 #define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_encode" typedef struct StdVideoEncodeH265WeightTableFlags { uint16_t luma_weight_l0_flag; @@ -77,7 +77,8 @@ typedef struct StdVideoEncodeH265SliceSegmentHeader { int8_t slice_act_y_qp_offset; int8_t slice_act_cb_qp_offset; int8_t slice_act_cr_qp_offset; - uint8_t reserved1[3]; + int8_t slice_qp_delta; + uint16_t reserved1; const StdVideoEncodeH265WeightTable* pWeightTable; } StdVideoEncodeH265SliceSegmentHeader; @@ -110,7 +111,7 @@ typedef struct StdVideoEncodeH265PictureInfoFlags { uint32_t reserved : 23; } StdVideoEncodeH265PictureInfoFlags; -typedef struct StdVideoEncodeH265SliceSegmentLongTermRefPics { +typedef struct StdVideoEncodeH265LongTermRefPics { uint8_t num_long_term_sps; uint8_t num_long_term_pics; uint8_t lt_idx_sps[STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS]; @@ -118,21 +119,21 @@ typedef struct StdVideoEncodeH265SliceSegmentLongTermRefPics { uint16_t used_by_curr_pic_lt_flag; uint8_t delta_poc_msb_present_flag[STD_VIDEO_H265_MAX_DELTA_POC]; uint8_t delta_poc_msb_cycle_lt[STD_VIDEO_H265_MAX_DELTA_POC]; -} StdVideoEncodeH265SliceSegmentLongTermRefPics; +} StdVideoEncodeH265LongTermRefPics; typedef struct StdVideoEncodeH265PictureInfo { - StdVideoEncodeH265PictureInfoFlags flags; - StdVideoH265PictureType pic_type; - uint8_t sps_video_parameter_set_id; - uint8_t pps_seq_parameter_set_id; - uint8_t pps_pic_parameter_set_id; - uint8_t short_term_ref_pic_set_idx; - int32_t PicOrderCntVal; - uint8_t TemporalId; - uint8_t reserved1[7]; - const StdVideoEncodeH265ReferenceListsInfo* pRefLists; - const StdVideoH265ShortTermRefPicSet* pShortTermRefPicSet; - const StdVideoEncodeH265SliceSegmentLongTermRefPics* pLongTermRefPics; + StdVideoEncodeH265PictureInfoFlags flags; + StdVideoH265PictureType pic_type; + uint8_t sps_video_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + uint8_t pps_pic_parameter_set_id; + uint8_t short_term_ref_pic_set_idx; + int32_t PicOrderCntVal; + uint8_t TemporalId; + uint8_t reserved1[7]; + const StdVideoEncodeH265ReferenceListsInfo* pRefLists; + const StdVideoH265ShortTermRefPicSet* pShortTermRefPicSet; + const StdVideoEncodeH265LongTermRefPics* pLongTermRefPics; } StdVideoEncodeH265PictureInfo; typedef struct StdVideoEncodeH265ReferenceInfoFlags { diff --git a/ext/vulkan/vk_video/vulkan_video_codecs_common.h b/ext/vulkan/vk_video/vulkan_video_codecs_common.h index 6568975ee3..5e6ef1db48 100644 --- a/ext/vulkan/vk_video/vulkan_video_codecs_common.h +++ b/ext/vulkan/vk_video/vulkan_video_codecs_common.h @@ -2,7 +2,7 @@ #define VULKAN_VIDEO_CODECS_COMMON_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan.h b/ext/vulkan/vulkan.h index 426cff58d7..ef94006bb3 100644 --- a/ext/vulkan/vulkan.h +++ b/ext/vulkan/vulkan.h @@ -2,7 +2,7 @@ #define VULKAN_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_android.h b/ext/vulkan/vulkan_android.h index d86f43f2d2..61ff40ba8c 100644 --- a/ext/vulkan/vulkan_android.h +++ b/ext/vulkan/vulkan_android.h @@ -2,7 +2,7 @@ #define VULKAN_ANDROID_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -120,6 +120,32 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID( struct AHardwareBuffer** pBuffer); #endif + +// VK_ANDROID_external_format_resolve is a preprocessor guard. Do not pass it to API calls. +#define VK_ANDROID_external_format_resolve 1 +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_SPEC_VERSION 1 +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_EXTENSION_NAME "VK_ANDROID_external_format_resolve" +typedef struct VkPhysicalDeviceExternalFormatResolveFeaturesANDROID { + VkStructureType sType; + void* pNext; + VkBool32 externalFormatResolve; +} VkPhysicalDeviceExternalFormatResolveFeaturesANDROID; + +typedef struct VkPhysicalDeviceExternalFormatResolvePropertiesANDROID { + VkStructureType sType; + void* pNext; + VkBool32 nullColorAttachmentWithExternalFormatResolve; + VkChromaLocation externalFormatResolveChromaOffsetX; + VkChromaLocation externalFormatResolveChromaOffsetY; +} VkPhysicalDeviceExternalFormatResolvePropertiesANDROID; + +typedef struct VkAndroidHardwareBufferFormatResolvePropertiesANDROID { + VkStructureType sType; + void* pNext; + VkFormat colorAttachmentFormat; +} VkAndroidHardwareBufferFormatResolvePropertiesANDROID; + + #ifdef __cplusplus } #endif diff --git a/ext/vulkan/vulkan_beta.h b/ext/vulkan/vulkan_beta.h index f00ed3ff1f..df18b4042b 100644 --- a/ext/vulkan/vulkan_beta.h +++ b/ext/vulkan/vulkan_beta.h @@ -2,7 +2,7 @@ #define VULKAN_BETA_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -51,598 +51,6 @@ typedef struct VkPhysicalDevicePortabilitySubsetPropertiesKHR { -// VK_KHR_video_encode_queue is a preprocessor guard. Do not pass it to API calls. -#define VK_KHR_video_encode_queue 1 -#define VK_KHR_VIDEO_ENCODE_QUEUE_SPEC_VERSION 9 -#define VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME "VK_KHR_video_encode_queue" - -typedef enum VkVideoEncodeTuningModeKHR { - VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR = 0, - VK_VIDEO_ENCODE_TUNING_MODE_HIGH_QUALITY_KHR = 1, - VK_VIDEO_ENCODE_TUNING_MODE_LOW_LATENCY_KHR = 2, - VK_VIDEO_ENCODE_TUNING_MODE_ULTRA_LOW_LATENCY_KHR = 3, - VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR = 4, - VK_VIDEO_ENCODE_TUNING_MODE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkVideoEncodeTuningModeKHR; -typedef VkFlags VkVideoEncodeFlagsKHR; - -typedef enum VkVideoEncodeCapabilityFlagBitsKHR { - VK_VIDEO_ENCODE_CAPABILITY_PRECEDING_EXTERNALLY_ENCODED_BYTES_BIT_KHR = 0x00000001, - VK_VIDEO_ENCODE_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkVideoEncodeCapabilityFlagBitsKHR; -typedef VkFlags VkVideoEncodeCapabilityFlagsKHR; - -typedef enum VkVideoEncodeRateControlModeFlagBitsKHR { - VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR = 0, - VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR = 0x00000001, - VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR = 0x00000002, - VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR = 0x00000004, - VK_VIDEO_ENCODE_RATE_CONTROL_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkVideoEncodeRateControlModeFlagBitsKHR; -typedef VkFlags VkVideoEncodeRateControlModeFlagsKHR; - -typedef enum VkVideoEncodeFeedbackFlagBitsKHR { - VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR = 0x00000001, - VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR = 0x00000002, - VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_HAS_OVERRIDES_BIT_KHR = 0x00000004, - VK_VIDEO_ENCODE_FEEDBACK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkVideoEncodeFeedbackFlagBitsKHR; -typedef VkFlags VkVideoEncodeFeedbackFlagsKHR; - -typedef enum VkVideoEncodeUsageFlagBitsKHR { - VK_VIDEO_ENCODE_USAGE_DEFAULT_KHR = 0, - VK_VIDEO_ENCODE_USAGE_TRANSCODING_BIT_KHR = 0x00000001, - VK_VIDEO_ENCODE_USAGE_STREAMING_BIT_KHR = 0x00000002, - VK_VIDEO_ENCODE_USAGE_RECORDING_BIT_KHR = 0x00000004, - VK_VIDEO_ENCODE_USAGE_CONFERENCING_BIT_KHR = 0x00000008, - VK_VIDEO_ENCODE_USAGE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkVideoEncodeUsageFlagBitsKHR; -typedef VkFlags VkVideoEncodeUsageFlagsKHR; - -typedef enum VkVideoEncodeContentFlagBitsKHR { - VK_VIDEO_ENCODE_CONTENT_DEFAULT_KHR = 0, - VK_VIDEO_ENCODE_CONTENT_CAMERA_BIT_KHR = 0x00000001, - VK_VIDEO_ENCODE_CONTENT_DESKTOP_BIT_KHR = 0x00000002, - VK_VIDEO_ENCODE_CONTENT_RENDERED_BIT_KHR = 0x00000004, - VK_VIDEO_ENCODE_CONTENT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkVideoEncodeContentFlagBitsKHR; -typedef VkFlags VkVideoEncodeContentFlagsKHR; -typedef VkFlags VkVideoEncodeRateControlFlagsKHR; -typedef struct VkVideoEncodeInfoKHR { - VkStructureType sType; - const void* pNext; - VkVideoEncodeFlagsKHR flags; - VkBuffer dstBuffer; - VkDeviceSize dstBufferOffset; - VkDeviceSize dstBufferRange; - VkVideoPictureResourceInfoKHR srcPictureResource; - const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot; - uint32_t referenceSlotCount; - const VkVideoReferenceSlotInfoKHR* pReferenceSlots; - uint32_t precedingExternallyEncodedBytes; -} VkVideoEncodeInfoKHR; - -typedef struct VkVideoEncodeCapabilitiesKHR { - VkStructureType sType; - void* pNext; - VkVideoEncodeCapabilityFlagsKHR flags; - VkVideoEncodeRateControlModeFlagsKHR rateControlModes; - uint32_t maxRateControlLayers; - uint64_t maxBitrate; - uint32_t maxQualityLevels; - VkExtent2D encodeInputPictureGranularity; - VkVideoEncodeFeedbackFlagsKHR supportedEncodeFeedbackFlags; -} VkVideoEncodeCapabilitiesKHR; - -typedef struct VkQueryPoolVideoEncodeFeedbackCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkVideoEncodeFeedbackFlagsKHR encodeFeedbackFlags; -} VkQueryPoolVideoEncodeFeedbackCreateInfoKHR; - -typedef struct VkVideoEncodeUsageInfoKHR { - VkStructureType sType; - const void* pNext; - VkVideoEncodeUsageFlagsKHR videoUsageHints; - VkVideoEncodeContentFlagsKHR videoContentHints; - VkVideoEncodeTuningModeKHR tuningMode; -} VkVideoEncodeUsageInfoKHR; - -typedef struct VkVideoEncodeRateControlLayerInfoKHR { - VkStructureType sType; - const void* pNext; - uint64_t averageBitrate; - uint64_t maxBitrate; - uint32_t frameRateNumerator; - uint32_t frameRateDenominator; -} VkVideoEncodeRateControlLayerInfoKHR; - -typedef struct VkVideoEncodeRateControlInfoKHR { - VkStructureType sType; - const void* pNext; - VkVideoEncodeRateControlFlagsKHR flags; - VkVideoEncodeRateControlModeFlagBitsKHR rateControlMode; - uint32_t layerCount; - const VkVideoEncodeRateControlLayerInfoKHR* pLayers; - uint32_t virtualBufferSizeInMs; - uint32_t initialVirtualBufferSizeInMs; -} VkVideoEncodeRateControlInfoKHR; - -typedef struct VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR { - VkStructureType sType; - const void* pNext; - const VkVideoProfileInfoKHR* pVideoProfile; - uint32_t qualityLevel; -} VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR; - -typedef struct VkVideoEncodeQualityLevelPropertiesKHR { - VkStructureType sType; - void* pNext; - VkVideoEncodeRateControlModeFlagBitsKHR preferredRateControlMode; - uint32_t preferredRateControlLayerCount; -} VkVideoEncodeQualityLevelPropertiesKHR; - -typedef struct VkVideoEncodeQualityLevelInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t qualityLevel; -} VkVideoEncodeQualityLevelInfoKHR; - -typedef struct VkVideoEncodeSessionParametersGetInfoKHR { - VkStructureType sType; - const void* pNext; - VkVideoSessionParametersKHR videoSessionParameters; -} VkVideoEncodeSessionParametersGetInfoKHR; - -typedef struct VkVideoEncodeSessionParametersFeedbackInfoKHR { - VkStructureType sType; - void* pNext; - VkBool32 hasOverrides; -} VkVideoEncodeSessionParametersFeedbackInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo, VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetEncodedVideoSessionParametersKHR)(VkDevice device, const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo, VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo, size_t* pDataSize, void* pData); -typedef void (VKAPI_PTR *PFN_vkCmdEncodeVideoKHR)(VkCommandBuffer commandBuffer, const VkVideoEncodeInfoKHR* pEncodeInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo, - VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetEncodedVideoSessionParametersKHR( - VkDevice device, - const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo, - VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo, - size_t* pDataSize, - void* pData); - -VKAPI_ATTR void VKAPI_CALL vkCmdEncodeVideoKHR( - VkCommandBuffer commandBuffer, - const VkVideoEncodeInfoKHR* pEncodeInfo); -#endif - - -// VK_EXT_video_encode_h264 is a preprocessor guard. Do not pass it to API calls. -#define VK_EXT_video_encode_h264 1 -#include "vk_video/vulkan_video_codec_h264std.h" -#include "vk_video/vulkan_video_codec_h264std_encode.h" -#define VK_EXT_VIDEO_ENCODE_H264_SPEC_VERSION 11 -#define VK_EXT_VIDEO_ENCODE_H264_EXTENSION_NAME "VK_EXT_video_encode_h264" - -typedef enum VkVideoEncodeH264CapabilityFlagBitsEXT { - VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_EXT = 0x00000001, - VK_VIDEO_ENCODE_H264_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_EXT = 0x00000002, - VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_EXT = 0x00000004, - VK_VIDEO_ENCODE_H264_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_EXT = 0x00000008, - VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_EXT = 0x00000010, - VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_EXT = 0x00000020, - VK_VIDEO_ENCODE_H264_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_EXT = 0x00000040, - VK_VIDEO_ENCODE_H264_CAPABILITY_PER_SLICE_CONSTANT_QP_BIT_EXT = 0x00000080, - VK_VIDEO_ENCODE_H264_CAPABILITY_GENERATE_PREFIX_NALU_BIT_EXT = 0x00000100, - VK_VIDEO_ENCODE_H264_CAPABILITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkVideoEncodeH264CapabilityFlagBitsEXT; -typedef VkFlags VkVideoEncodeH264CapabilityFlagsEXT; - -typedef enum VkVideoEncodeH264StdFlagBitsEXT { - VK_VIDEO_ENCODE_H264_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_EXT = 0x00000001, - VK_VIDEO_ENCODE_H264_STD_QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG_SET_BIT_EXT = 0x00000002, - VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_EXT = 0x00000004, - VK_VIDEO_ENCODE_H264_STD_CHROMA_QP_INDEX_OFFSET_BIT_EXT = 0x00000008, - VK_VIDEO_ENCODE_H264_STD_SECOND_CHROMA_QP_INDEX_OFFSET_BIT_EXT = 0x00000010, - VK_VIDEO_ENCODE_H264_STD_PIC_INIT_QP_MINUS26_BIT_EXT = 0x00000020, - VK_VIDEO_ENCODE_H264_STD_WEIGHTED_PRED_FLAG_SET_BIT_EXT = 0x00000040, - VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_EXPLICIT_BIT_EXT = 0x00000080, - VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_IMPLICIT_BIT_EXT = 0x00000100, - VK_VIDEO_ENCODE_H264_STD_TRANSFORM_8X8_MODE_FLAG_SET_BIT_EXT = 0x00000200, - VK_VIDEO_ENCODE_H264_STD_DIRECT_SPATIAL_MV_PRED_FLAG_UNSET_BIT_EXT = 0x00000400, - VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_UNSET_BIT_EXT = 0x00000800, - VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_SET_BIT_EXT = 0x00001000, - VK_VIDEO_ENCODE_H264_STD_DIRECT_8X8_INFERENCE_FLAG_UNSET_BIT_EXT = 0x00002000, - VK_VIDEO_ENCODE_H264_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_EXT = 0x00004000, - VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_DISABLED_BIT_EXT = 0x00008000, - VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_ENABLED_BIT_EXT = 0x00010000, - VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_PARTIAL_BIT_EXT = 0x00020000, - VK_VIDEO_ENCODE_H264_STD_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkVideoEncodeH264StdFlagBitsEXT; -typedef VkFlags VkVideoEncodeH264StdFlagsEXT; - -typedef enum VkVideoEncodeH264RateControlFlagBitsEXT { - VK_VIDEO_ENCODE_H264_RATE_CONTROL_ATTEMPT_HRD_COMPLIANCE_BIT_EXT = 0x00000001, - VK_VIDEO_ENCODE_H264_RATE_CONTROL_REGULAR_GOP_BIT_EXT = 0x00000002, - VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_EXT = 0x00000004, - VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_EXT = 0x00000008, - VK_VIDEO_ENCODE_H264_RATE_CONTROL_TEMPORAL_LAYER_PATTERN_DYADIC_BIT_EXT = 0x00000010, - VK_VIDEO_ENCODE_H264_RATE_CONTROL_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkVideoEncodeH264RateControlFlagBitsEXT; -typedef VkFlags VkVideoEncodeH264RateControlFlagsEXT; -typedef struct VkVideoEncodeH264CapabilitiesEXT { - VkStructureType sType; - void* pNext; - VkVideoEncodeH264CapabilityFlagsEXT flags; - StdVideoH264LevelIdc maxLevelIdc; - uint32_t maxSliceCount; - uint32_t maxPPictureL0ReferenceCount; - uint32_t maxBPictureL0ReferenceCount; - uint32_t maxL1ReferenceCount; - uint32_t maxTemporalLayerCount; - VkBool32 expectDyadicTemporalLayerPattern; - int32_t minQp; - int32_t maxQp; - VkBool32 prefersGopRemainingFrames; - VkBool32 requiresGopRemainingFrames; - VkVideoEncodeH264StdFlagsEXT stdSyntaxFlags; -} VkVideoEncodeH264CapabilitiesEXT; - -typedef struct VkVideoEncodeH264QpEXT { - int32_t qpI; - int32_t qpP; - int32_t qpB; -} VkVideoEncodeH264QpEXT; - -typedef struct VkVideoEncodeH264QualityLevelPropertiesEXT { - VkStructureType sType; - void* pNext; - VkVideoEncodeH264RateControlFlagsEXT preferredRateControlFlags; - uint32_t preferredGopFrameCount; - uint32_t preferredIdrPeriod; - uint32_t preferredConsecutiveBFrameCount; - uint32_t preferredTemporalLayerCount; - VkVideoEncodeH264QpEXT preferredConstantQp; - uint32_t preferredMaxL0ReferenceCount; - uint32_t preferredMaxL1ReferenceCount; - VkBool32 preferredStdEntropyCodingModeFlag; -} VkVideoEncodeH264QualityLevelPropertiesEXT; - -typedef struct VkVideoEncodeH264SessionCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 useMaxLevelIdc; - StdVideoH264LevelIdc maxLevelIdc; -} VkVideoEncodeH264SessionCreateInfoEXT; - -typedef struct VkVideoEncodeH264SessionParametersAddInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t stdSPSCount; - const StdVideoH264SequenceParameterSet* pStdSPSs; - uint32_t stdPPSCount; - const StdVideoH264PictureParameterSet* pStdPPSs; -} VkVideoEncodeH264SessionParametersAddInfoEXT; - -typedef struct VkVideoEncodeH264SessionParametersCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t maxStdSPSCount; - uint32_t maxStdPPSCount; - const VkVideoEncodeH264SessionParametersAddInfoEXT* pParametersAddInfo; -} VkVideoEncodeH264SessionParametersCreateInfoEXT; - -typedef struct VkVideoEncodeH264SessionParametersGetInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 writeStdSPS; - VkBool32 writeStdPPS; - uint32_t stdSPSId; - uint32_t stdPPSId; -} VkVideoEncodeH264SessionParametersGetInfoEXT; - -typedef struct VkVideoEncodeH264SessionParametersFeedbackInfoEXT { - VkStructureType sType; - void* pNext; - VkBool32 hasStdSPSOverrides; - VkBool32 hasStdPPSOverrides; -} VkVideoEncodeH264SessionParametersFeedbackInfoEXT; - -typedef struct VkVideoEncodeH264NaluSliceInfoEXT { - VkStructureType sType; - const void* pNext; - int32_t constantQp; - const StdVideoEncodeH264SliceHeader* pStdSliceHeader; -} VkVideoEncodeH264NaluSliceInfoEXT; - -typedef struct VkVideoEncodeH264PictureInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t naluSliceEntryCount; - const VkVideoEncodeH264NaluSliceInfoEXT* pNaluSliceEntries; - const StdVideoEncodeH264PictureInfo* pStdPictureInfo; - VkBool32 generatePrefixNalu; -} VkVideoEncodeH264PictureInfoEXT; - -typedef struct VkVideoEncodeH264DpbSlotInfoEXT { - VkStructureType sType; - const void* pNext; - const StdVideoEncodeH264ReferenceInfo* pStdReferenceInfo; -} VkVideoEncodeH264DpbSlotInfoEXT; - -typedef struct VkVideoEncodeH264ProfileInfoEXT { - VkStructureType sType; - const void* pNext; - StdVideoH264ProfileIdc stdProfileIdc; -} VkVideoEncodeH264ProfileInfoEXT; - -typedef struct VkVideoEncodeH264RateControlInfoEXT { - VkStructureType sType; - const void* pNext; - VkVideoEncodeH264RateControlFlagsEXT flags; - uint32_t gopFrameCount; - uint32_t idrPeriod; - uint32_t consecutiveBFrameCount; - uint32_t temporalLayerCount; -} VkVideoEncodeH264RateControlInfoEXT; - -typedef struct VkVideoEncodeH264FrameSizeEXT { - uint32_t frameISize; - uint32_t framePSize; - uint32_t frameBSize; -} VkVideoEncodeH264FrameSizeEXT; - -typedef struct VkVideoEncodeH264RateControlLayerInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 useMinQp; - VkVideoEncodeH264QpEXT minQp; - VkBool32 useMaxQp; - VkVideoEncodeH264QpEXT maxQp; - VkBool32 useMaxFrameSize; - VkVideoEncodeH264FrameSizeEXT maxFrameSize; -} VkVideoEncodeH264RateControlLayerInfoEXT; - -typedef struct VkVideoEncodeH264GopRemainingFrameInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 useGopRemainingFrames; - uint32_t gopRemainingI; - uint32_t gopRemainingP; - uint32_t gopRemainingB; -} VkVideoEncodeH264GopRemainingFrameInfoEXT; - - - -// VK_EXT_video_encode_h265 is a preprocessor guard. Do not pass it to API calls. -#define VK_EXT_video_encode_h265 1 -#include "vk_video/vulkan_video_codec_h265std.h" -#include "vk_video/vulkan_video_codec_h265std_encode.h" -#define VK_EXT_VIDEO_ENCODE_H265_SPEC_VERSION 11 -#define VK_EXT_VIDEO_ENCODE_H265_EXTENSION_NAME "VK_EXT_video_encode_h265" - -typedef enum VkVideoEncodeH265CapabilityFlagBitsEXT { - VK_VIDEO_ENCODE_H265_CAPABILITY_HRD_COMPLIANCE_BIT_EXT = 0x00000001, - VK_VIDEO_ENCODE_H265_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_EXT = 0x00000002, - VK_VIDEO_ENCODE_H265_CAPABILITY_ROW_UNALIGNED_SLICE_SEGMENT_BIT_EXT = 0x00000004, - VK_VIDEO_ENCODE_H265_CAPABILITY_DIFFERENT_SLICE_SEGMENT_TYPE_BIT_EXT = 0x00000008, - VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_EXT = 0x00000010, - VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_EXT = 0x00000020, - VK_VIDEO_ENCODE_H265_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_EXT = 0x00000040, - VK_VIDEO_ENCODE_H265_CAPABILITY_PER_SLICE_SEGMENT_CONSTANT_QP_BIT_EXT = 0x00000080, - VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_TILES_PER_SLICE_SEGMENT_BIT_EXT = 0x00000100, - VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_SLICE_SEGMENTS_PER_TILE_BIT_EXT = 0x00000200, - VK_VIDEO_ENCODE_H265_CAPABILITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkVideoEncodeH265CapabilityFlagBitsEXT; -typedef VkFlags VkVideoEncodeH265CapabilityFlagsEXT; - -typedef enum VkVideoEncodeH265StdFlagBitsEXT { - VK_VIDEO_ENCODE_H265_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_EXT = 0x00000001, - VK_VIDEO_ENCODE_H265_STD_SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG_SET_BIT_EXT = 0x00000002, - VK_VIDEO_ENCODE_H265_STD_SCALING_LIST_DATA_PRESENT_FLAG_SET_BIT_EXT = 0x00000004, - VK_VIDEO_ENCODE_H265_STD_PCM_ENABLED_FLAG_SET_BIT_EXT = 0x00000008, - VK_VIDEO_ENCODE_H265_STD_SPS_TEMPORAL_MVP_ENABLED_FLAG_SET_BIT_EXT = 0x00000010, - VK_VIDEO_ENCODE_H265_STD_INIT_QP_MINUS26_BIT_EXT = 0x00000020, - VK_VIDEO_ENCODE_H265_STD_WEIGHTED_PRED_FLAG_SET_BIT_EXT = 0x00000040, - VK_VIDEO_ENCODE_H265_STD_WEIGHTED_BIPRED_FLAG_SET_BIT_EXT = 0x00000080, - VK_VIDEO_ENCODE_H265_STD_LOG2_PARALLEL_MERGE_LEVEL_MINUS2_BIT_EXT = 0x00000100, - VK_VIDEO_ENCODE_H265_STD_SIGN_DATA_HIDING_ENABLED_FLAG_SET_BIT_EXT = 0x00000200, - VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_SET_BIT_EXT = 0x00000400, - VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_UNSET_BIT_EXT = 0x00000800, - VK_VIDEO_ENCODE_H265_STD_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG_SET_BIT_EXT = 0x00001000, - VK_VIDEO_ENCODE_H265_STD_TRANSQUANT_BYPASS_ENABLED_FLAG_SET_BIT_EXT = 0x00002000, - VK_VIDEO_ENCODE_H265_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_EXT = 0x00004000, - VK_VIDEO_ENCODE_H265_STD_ENTROPY_CODING_SYNC_ENABLED_FLAG_SET_BIT_EXT = 0x00008000, - VK_VIDEO_ENCODE_H265_STD_DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_SET_BIT_EXT = 0x00010000, - VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG_SET_BIT_EXT = 0x00020000, - VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENT_FLAG_SET_BIT_EXT = 0x00040000, - VK_VIDEO_ENCODE_H265_STD_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkVideoEncodeH265StdFlagBitsEXT; -typedef VkFlags VkVideoEncodeH265StdFlagsEXT; - -typedef enum VkVideoEncodeH265CtbSizeFlagBitsEXT { - VK_VIDEO_ENCODE_H265_CTB_SIZE_16_BIT_EXT = 0x00000001, - VK_VIDEO_ENCODE_H265_CTB_SIZE_32_BIT_EXT = 0x00000002, - VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_EXT = 0x00000004, - VK_VIDEO_ENCODE_H265_CTB_SIZE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkVideoEncodeH265CtbSizeFlagBitsEXT; -typedef VkFlags VkVideoEncodeH265CtbSizeFlagsEXT; - -typedef enum VkVideoEncodeH265TransformBlockSizeFlagBitsEXT { - VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_EXT = 0x00000001, - VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_8_BIT_EXT = 0x00000002, - VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_16_BIT_EXT = 0x00000004, - VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_32_BIT_EXT = 0x00000008, - VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkVideoEncodeH265TransformBlockSizeFlagBitsEXT; -typedef VkFlags VkVideoEncodeH265TransformBlockSizeFlagsEXT; - -typedef enum VkVideoEncodeH265RateControlFlagBitsEXT { - VK_VIDEO_ENCODE_H265_RATE_CONTROL_ATTEMPT_HRD_COMPLIANCE_BIT_EXT = 0x00000001, - VK_VIDEO_ENCODE_H265_RATE_CONTROL_REGULAR_GOP_BIT_EXT = 0x00000002, - VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_EXT = 0x00000004, - VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_EXT = 0x00000008, - VK_VIDEO_ENCODE_H265_RATE_CONTROL_TEMPORAL_SUB_LAYER_PATTERN_DYADIC_BIT_EXT = 0x00000010, - VK_VIDEO_ENCODE_H265_RATE_CONTROL_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkVideoEncodeH265RateControlFlagBitsEXT; -typedef VkFlags VkVideoEncodeH265RateControlFlagsEXT; -typedef struct VkVideoEncodeH265CapabilitiesEXT { - VkStructureType sType; - void* pNext; - VkVideoEncodeH265CapabilityFlagsEXT flags; - StdVideoH265LevelIdc maxLevelIdc; - uint32_t maxSliceSegmentCount; - VkExtent2D maxTiles; - VkVideoEncodeH265CtbSizeFlagsEXT ctbSizes; - VkVideoEncodeH265TransformBlockSizeFlagsEXT transformBlockSizes; - uint32_t maxPPictureL0ReferenceCount; - uint32_t maxBPictureL0ReferenceCount; - uint32_t maxL1ReferenceCount; - uint32_t maxSubLayerCount; - VkBool32 expectDyadicTemporalSubLayerPattern; - int32_t minQp; - int32_t maxQp; - VkBool32 prefersGopRemainingFrames; - VkBool32 requiresGopRemainingFrames; - VkVideoEncodeH265StdFlagsEXT stdSyntaxFlags; -} VkVideoEncodeH265CapabilitiesEXT; - -typedef struct VkVideoEncodeH265SessionCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 useMaxLevelIdc; - StdVideoH265LevelIdc maxLevelIdc; -} VkVideoEncodeH265SessionCreateInfoEXT; - -typedef struct VkVideoEncodeH265QpEXT { - int32_t qpI; - int32_t qpP; - int32_t qpB; -} VkVideoEncodeH265QpEXT; - -typedef struct VkVideoEncodeH265QualityLevelPropertiesEXT { - VkStructureType sType; - void* pNext; - VkVideoEncodeH265RateControlFlagsEXT preferredRateControlFlags; - uint32_t preferredGopFrameCount; - uint32_t preferredIdrPeriod; - uint32_t preferredConsecutiveBFrameCount; - uint32_t preferredSubLayerCount; - VkVideoEncodeH265QpEXT preferredConstantQp; - uint32_t preferredMaxL0ReferenceCount; - uint32_t preferredMaxL1ReferenceCount; -} VkVideoEncodeH265QualityLevelPropertiesEXT; - -typedef struct VkVideoEncodeH265SessionParametersAddInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t stdVPSCount; - const StdVideoH265VideoParameterSet* pStdVPSs; - uint32_t stdSPSCount; - const StdVideoH265SequenceParameterSet* pStdSPSs; - uint32_t stdPPSCount; - const StdVideoH265PictureParameterSet* pStdPPSs; -} VkVideoEncodeH265SessionParametersAddInfoEXT; - -typedef struct VkVideoEncodeH265SessionParametersCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t maxStdVPSCount; - uint32_t maxStdSPSCount; - uint32_t maxStdPPSCount; - const VkVideoEncodeH265SessionParametersAddInfoEXT* pParametersAddInfo; -} VkVideoEncodeH265SessionParametersCreateInfoEXT; - -typedef struct VkVideoEncodeH265SessionParametersGetInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 writeStdVPS; - VkBool32 writeStdSPS; - VkBool32 writeStdPPS; - uint32_t stdVPSId; - uint32_t stdSPSId; - uint32_t stdPPSId; -} VkVideoEncodeH265SessionParametersGetInfoEXT; - -typedef struct VkVideoEncodeH265SessionParametersFeedbackInfoEXT { - VkStructureType sType; - void* pNext; - VkBool32 hasStdVPSOverrides; - VkBool32 hasStdSPSOverrides; - VkBool32 hasStdPPSOverrides; -} VkVideoEncodeH265SessionParametersFeedbackInfoEXT; - -typedef struct VkVideoEncodeH265NaluSliceSegmentInfoEXT { - VkStructureType sType; - const void* pNext; - int32_t constantQp; - const StdVideoEncodeH265SliceSegmentHeader* pStdSliceSegmentHeader; -} VkVideoEncodeH265NaluSliceSegmentInfoEXT; - -typedef struct VkVideoEncodeH265PictureInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t naluSliceSegmentEntryCount; - const VkVideoEncodeH265NaluSliceSegmentInfoEXT* pNaluSliceSegmentEntries; - const StdVideoEncodeH265PictureInfo* pStdPictureInfo; -} VkVideoEncodeH265PictureInfoEXT; - -typedef struct VkVideoEncodeH265DpbSlotInfoEXT { - VkStructureType sType; - const void* pNext; - const StdVideoEncodeH265ReferenceInfo* pStdReferenceInfo; -} VkVideoEncodeH265DpbSlotInfoEXT; - -typedef struct VkVideoEncodeH265ProfileInfoEXT { - VkStructureType sType; - const void* pNext; - StdVideoH265ProfileIdc stdProfileIdc; -} VkVideoEncodeH265ProfileInfoEXT; - -typedef struct VkVideoEncodeH265RateControlInfoEXT { - VkStructureType sType; - const void* pNext; - VkVideoEncodeH265RateControlFlagsEXT flags; - uint32_t gopFrameCount; - uint32_t idrPeriod; - uint32_t consecutiveBFrameCount; - uint32_t subLayerCount; -} VkVideoEncodeH265RateControlInfoEXT; - -typedef struct VkVideoEncodeH265FrameSizeEXT { - uint32_t frameISize; - uint32_t framePSize; - uint32_t frameBSize; -} VkVideoEncodeH265FrameSizeEXT; - -typedef struct VkVideoEncodeH265RateControlLayerInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 useMinQp; - VkVideoEncodeH265QpEXT minQp; - VkBool32 useMaxQp; - VkVideoEncodeH265QpEXT maxQp; - VkBool32 useMaxFrameSize; - VkVideoEncodeH265FrameSizeEXT maxFrameSize; -} VkVideoEncodeH265RateControlLayerInfoEXT; - -typedef struct VkVideoEncodeH265GopRemainingFrameInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 useGopRemainingFrames; - uint32_t gopRemainingI; - uint32_t gopRemainingP; - uint32_t gopRemainingB; -} VkVideoEncodeH265GopRemainingFrameInfoEXT; - - - // VK_AMDX_shader_enqueue is a preprocessor guard. Do not pass it to API calls. #define VK_AMDX_shader_enqueue 1 #define VK_AMDX_SHADER_ENQUEUE_SPEC_VERSION 1 diff --git a/ext/vulkan/vulkan_core.h b/ext/vulkan/vulkan_core.h index c574858134..7e6b040971 100644 --- a/ext/vulkan/vulkan_core.h +++ b/ext/vulkan/vulkan_core.h @@ -2,7 +2,7 @@ #define VULKAN_CORE_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -27,7 +27,7 @@ extern "C" { #ifndef VK_USE_64_BIT_PTR_DEFINES - #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64) #define VK_USE_64_BIT_PTR_DEFINES 1 #else #define VK_USE_64_BIT_PTR_DEFINES 0 @@ -69,7 +69,7 @@ extern "C" { #define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0 // Version of this file -#define VK_HEADER_VERSION 261 +#define VK_HEADER_VERSION 278 // Complete version of this file #define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION) @@ -182,11 +182,9 @@ typedef enum VkResult { VK_THREAD_DONE_KHR = 1000268001, VK_OPERATION_DEFERRED_KHR = 1000268002, VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR = -1000299000, -#endif VK_ERROR_COMPRESSION_EXHAUSTED_EXT = -1000338000, - VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT = 1000482000, + VK_INCOMPATIBLE_SHADER_BINARY_EXT = 1000482000, VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, @@ -195,6 +193,7 @@ typedef enum VkResult { VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, VK_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT = VK_INCOMPATIBLE_SHADER_BINARY_EXT, VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; @@ -467,90 +466,34 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX = 1000029002, VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT = 1000038000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038001, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038002, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PICTURE_INFO_EXT = 1000038003, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038004, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_INFO_EXT = 1000038005, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_GOP_REMAINING_FRAME_INFO_EXT = 1000038006, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_EXT = 1000038007, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_EXT = 1000038008, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT = 1000038009, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT = 1000038010, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_QUALITY_LEVEL_PROPERTIES_EXT = 1000038011, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_EXT = 1000038012, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_FEEDBACK_INFO_EXT = 1000038013, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_EXT = 1000039000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000039001, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000039002, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PICTURE_INFO_EXT = 1000039003, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_EXT = 1000039004, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_INFO_EXT = 1000039005, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_GOP_REMAINING_FRAME_INFO_EXT = 1000039006, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_EXT = 1000039007, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_EXT = 1000039009, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_EXT = 1000039010, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_CREATE_INFO_EXT = 1000039011, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_QUALITY_LEVEL_PROPERTIES_EXT = 1000039012, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_GET_INFO_EXT = 1000039013, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_FEEDBACK_INFO_EXT = 1000039014, -#endif + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_KHR = 1000038000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000038001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR = 1000038002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PICTURE_INFO_KHR = 1000038003, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_KHR = 1000038004, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_INFO_KHR = 1000038005, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_GOP_REMAINING_FRAME_INFO_KHR = 1000038006, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_KHR = 1000038007, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_KHR = 1000038008, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_KHR = 1000038009, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_KHR = 1000038010, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_QUALITY_LEVEL_PROPERTIES_KHR = 1000038011, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_KHR = 1000038012, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_FEEDBACK_INFO_KHR = 1000038013, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_KHR = 1000039000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000039001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR = 1000039002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PICTURE_INFO_KHR = 1000039003, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_KHR = 1000039004, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_INFO_KHR = 1000039005, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_GOP_REMAINING_FRAME_INFO_KHR = 1000039006, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_KHR = 1000039007, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_KHR = 1000039009, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_KHR = 1000039010, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_CREATE_INFO_KHR = 1000039011, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_QUALITY_LEVEL_PROPERTIES_KHR = 1000039012, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_GET_INFO_KHR = 1000039013, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_FEEDBACK_INFO_KHR = 1000039014, VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_KHR = 1000040000, VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR = 1000040001, VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR = 1000040003, @@ -611,6 +554,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RELAXED_LINE_RASTERIZATION_FEATURES_IMG = 1000110000, VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, @@ -732,7 +676,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR = 1000181000, VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, - VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR = 1000187000, VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000187001, @@ -745,8 +688,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR = 1000388001, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, @@ -778,7 +719,11 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR = 1000232000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR = 1000232001, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR = 1000232002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_QUAD_CONTROL_FEATURES_KHR = 1000235000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, @@ -803,11 +748,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR = 1000269001, @@ -827,6 +768,9 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT = 1000270009, VK_STRUCTURE_TYPE_MEMORY_MAP_INFO_KHR = 1000271000, VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR = 1000271001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_FEATURES_EXT = 1000272000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_PROPERTIES_EXT = 1000272001, + VK_STRUCTURE_TYPE_MEMORY_MAP_PLACED_INFO_EXT = 1000272002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT = 1000274000, VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT = 1000274001, @@ -867,41 +811,24 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV = 1000292002, VK_STRUCTURE_TYPE_PRESENT_ID_KHR = 1000294000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR = 1000299000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR = 1000299001, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR = 1000299002, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR = 1000299003, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_USAGE_INFO_KHR = 1000299004, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_QUERY_POOL_VIDEO_ENCODE_FEEDBACK_CREATE_INFO_KHR = 1000299005, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR = 1000299006, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_PROPERTIES_KHR = 1000299007, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR = 1000299008, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_GET_INFO_KHR = 1000299009, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_FEEDBACK_INFO_KHR = 1000299010, -#endif VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, + VK_STRUCTURE_TYPE_CUDA_MODULE_CREATE_INFO_NV = 1000307000, + VK_STRUCTURE_TYPE_CUDA_FUNCTION_CREATE_INFO_NV = 1000307001, + VK_STRUCTURE_TYPE_CUDA_LAUNCH_INFO_NV = 1000307002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_FEATURES_NV = 1000307003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_PROPERTIES_NV = 1000307004, VK_STRUCTURE_TYPE_QUERY_LOW_LATENCY_SUPPORT_NV = 1000310000, VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT = 1000311000, VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT = 1000311001, @@ -992,6 +919,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV = 1000371001, VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT = 1000372000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT = 1000372001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT = 1000375000, + VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT = 1000375001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT = 1000376000, VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT = 1000376001, VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT = 1000376002, @@ -1029,10 +958,15 @@ typedef enum VkStructureType { #endif VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_FEATURES_HUAWEI = 1000404000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI = 1000404001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_VRS_FEATURES_HUAWEI = 1000404002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000, VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM = 1000415000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR = 1000416000, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_SHADER_CORE_CONTROL_CREATE_INFO_ARM = 1000417000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_FEATURES_ARM = 1000417001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM = 1000417002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_SLICED_VIEW_OF_3D_FEATURES_EXT = 1000418000, VK_STRUCTURE_TYPE_IMAGE_VIEW_SLICED_CREATE_INFO_EXT = 1000418001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000, @@ -1040,6 +974,11 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT = 1000421000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT = 1000422000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_FEATURES_ARM = 1000424000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM = 1000424001, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_BEGIN_INFO_ARM = 1000424002, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_INFO_ARM = 1000424003, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_SUBMIT_INFO_ARM = 1000424004, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = 1000425000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = 1000425001, VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = 1000425002, @@ -1051,10 +990,13 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_INDIRECT_BUFFER_INFO_NV = 1000428001, VK_STRUCTURE_TYPE_PIPELINE_INDIRECT_DEVICE_ADDRESS_INFO_NV = 1000428002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MAXIMAL_RECONVERGENCE_FEATURES_KHR = 1000434000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT = 1000437000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM = 1000440000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM = 1000440001, VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM = 1000440002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_FEATURES_EXT = 1000451000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT = 1000451001, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXT = 1000453000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT = 1000455000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT = 1000455001, @@ -1078,6 +1020,9 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV = 1000464010, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT = 1000465000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT = 1000466000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_FEATURES_ANDROID = 1000468000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR = 1000470000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR = 1000470001, VK_STRUCTURE_TYPE_RENDERING_AREA_INFO_KHR = 1000470003, @@ -1097,23 +1042,74 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM = 1000488000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV = 1000490000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV = 1000490001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_FEATURES_NV = 1000492000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV = 1000492001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT = 1000351000, VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT = 1000351002, + VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT = 1000496000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM = 1000497000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM = 1000497001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_LIBRARY_GROUP_HANDLES_FEATURES_EXT = 1000498000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT = 1000499000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV = 1000505000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_INFO_NV = 1000505001, + VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV = 1000505002, + VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV = 1000505003, + VK_STRUCTURE_TYPE_LATENCY_TIMINGS_FRAME_REPORT_NV = 1000505004, + VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV = 1000505005, + VK_STRUCTURE_TYPE_OUT_OF_BAND_QUEUE_TYPE_INFO_NV = 1000505006, + VK_STRUCTURE_TYPE_SWAPCHAIN_LATENCY_CREATE_INFO_NV = 1000505007, + VK_STRUCTURE_TYPE_LATENCY_SURFACE_CAPABILITIES_NV = 1000505008, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR = 1000506000, VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_RENDER_AREAS_FEATURES_QCOM = 1000510000, VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_RENDER_AREAS_RENDER_PASS_BEGIN_INFO_QCOM = 1000510001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_CAPABILITIES_KHR = 1000512000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PICTURE_INFO_KHR = 1000512001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR = 1000512003, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000512004, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_DPB_SLOT_INFO_KHR = 1000512005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR = 1000515000, + VK_STRUCTURE_TYPE_VIDEO_INLINE_QUERY_INFO_KHR = 1000515001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PER_STAGE_DESCRIPTOR_SET_FEATURES_NV = 1000516000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_FEATURES_QCOM = 1000518000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM = 1000518001, + VK_STRUCTURE_TYPE_SAMPLER_BLOCK_MATCH_WINDOW_CREATE_INFO_QCOM = 1000518002, + VK_STRUCTURE_TYPE_SAMPLER_CUBIC_WEIGHTS_CREATE_INFO_QCOM = 1000519000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_WEIGHTS_FEATURES_QCOM = 1000519001, + VK_STRUCTURE_TYPE_BLIT_IMAGE_CUBIC_WEIGHTS_INFO_QCOM = 1000519002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_DEGAMMA_FEATURES_QCOM = 1000520000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_YCBCR_DEGAMMA_CREATE_INFO_QCOM = 1000520001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_CLAMP_FEATURES_QCOM = 1000521000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_FEATURES_EXT = 1000524000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_KHR = 1000525000, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_KHR = 1000190001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_KHR = 1000190002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES_KHR = 1000528000, VK_STRUCTURE_TYPE_SCREEN_BUFFER_PROPERTIES_QNX = 1000529000, VK_STRUCTURE_TYPE_SCREEN_BUFFER_FORMAT_PROPERTIES_QNX = 1000529001, VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX = 1000529002, VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_QNX = 1000529003, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX = 1000529004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT = 1000530000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_KHR = 1000265000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_KHR = 1000259000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_KHR = 1000259001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_KHR = 1000259002, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_KHR = 1000184000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR = 1000544000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES_KHR = 1000545000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES_KHR = 1000545001, + VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS_KHR = 1000545002, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO_KHR = 1000545003, + VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO_KHR = 1000545004, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO_KHR = 1000545005, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO_KHR = 1000545006, + VK_STRUCTURE_TYPE_SET_DESCRIPTOR_BUFFER_OFFSETS_INFO_EXT = 1000545007, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_BUFFER_EMBEDDED_SAMPLERS_INFO_EXT = 1000545008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV = 1000546000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV = 1000563000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, @@ -1214,6 +1210,9 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_KHR, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_KHR, VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, @@ -1246,7 +1245,11 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_KHR, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_KHR, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_KHR, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, @@ -1323,15 +1326,10 @@ typedef enum VkImageLayout { VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR = 1000164003, -#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR = 1000232000, VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR = 1000299000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR = 1000299001, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR = 1000299002, -#endif VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT = 1000339000, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, @@ -1391,6 +1389,8 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, + VK_OBJECT_TYPE_CUDA_MODULE_NV = 1000307000, + VK_OBJECT_TYPE_CUDA_FUNCTION_NV = 1000307001, VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA = 1000366000, VK_OBJECT_TYPE_MICROMAP_EXT = 1000396000, VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV = 1000464000, @@ -1768,9 +1768,7 @@ typedef enum VkQueryType { VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150001, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR = 1000299000, -#endif VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT = 1000328000, VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT = 1000382000, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR = 1000386000, @@ -1934,12 +1932,10 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_ENABLE_NV = 1000205000, VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR = 1000226000, - VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = 1000259000, VK_DYNAMIC_STATE_VERTEX_INPUT_EXT = 1000352000, VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT = 1000377000, VK_DYNAMIC_STATE_LOGIC_OP_EXT = 1000377003, VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT = 1000381000, - VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT = 1000455002, VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT = 1000455003, VK_DYNAMIC_STATE_POLYGON_MODE_EXT = 1000455004, VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT = 1000455005, @@ -1950,6 +1946,7 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT = 1000455010, VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT = 1000455011, VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT = 1000455012, + VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT = 1000455002, VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT = 1000455013, VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT = 1000455014, VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT = 1000455015, @@ -1971,6 +1968,8 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV = 1000455031, VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV = 1000455032, VK_DYNAMIC_STATE_ATTACHMENT_FEEDBACK_LOOP_ENABLE_EXT = 1000524000, + VK_DYNAMIC_STATE_LINE_STIPPLE_KHR = 1000259000, + VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = VK_DYNAMIC_STATE_LINE_STIPPLE_KHR, VK_DYNAMIC_STATE_CULL_MODE_EXT = VK_DYNAMIC_STATE_CULL_MODE, VK_DYNAMIC_STATE_FRONT_FACE_EXT = VK_DYNAMIC_STATE_FRONT_FACE, VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, @@ -2119,7 +2118,8 @@ typedef enum VkAttachmentLoadOp { VK_ATTACHMENT_LOAD_OP_LOAD = 0, VK_ATTACHMENT_LOAD_OP_CLEAR = 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, - VK_ATTACHMENT_LOAD_OP_NONE_EXT = 1000400000, + VK_ATTACHMENT_LOAD_OP_NONE_KHR = 1000400000, + VK_ATTACHMENT_LOAD_OP_NONE_EXT = VK_ATTACHMENT_LOAD_OP_NONE_KHR, VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentLoadOp; @@ -2155,14 +2155,16 @@ typedef enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0, VK_INDEX_TYPE_UINT32 = 1, VK_INDEX_TYPE_NONE_KHR = 1000165000, - VK_INDEX_TYPE_UINT8_EXT = 1000265000, + VK_INDEX_TYPE_UINT8_KHR = 1000265000, VK_INDEX_TYPE_NONE_NV = VK_INDEX_TYPE_NONE_KHR, + VK_INDEX_TYPE_UINT8_EXT = VK_INDEX_TYPE_UINT8_KHR, VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF } VkIndexType; typedef enum VkSubpassContents { VK_SUBPASS_CONTENTS_INLINE = 0, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, + VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_EXT = 1000451000, VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF } VkSubpassContents; @@ -2255,12 +2257,8 @@ typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000, VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000, VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_FORMAT_FEATURE_VIDEO_ENCODE_INPUT_BIT_KHR = 0x08000000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_FORMAT_FEATURE_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000, -#endif VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, @@ -2296,6 +2294,7 @@ typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 0x00040000, VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT = 0x00020000, VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM = 0x00008000, + VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR = 0x00100000, VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, @@ -2333,15 +2332,9 @@ typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200, VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00000100, VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT = 0x00400000, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00002000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00004000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR = 0x00008000, -#endif VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x00080000, VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI = 0x00040000, VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM = 0x00100000, @@ -2386,9 +2379,7 @@ typedef enum VkQueueFlagBits { VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, VK_QUEUE_PROTECTED_BIT = 0x00000010, VK_QUEUE_VIDEO_DECODE_BIT_KHR = 0x00000020, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_QUEUE_VIDEO_ENCODE_BIT_KHR = 0x00000040, -#endif VK_QUEUE_OPTICAL_FLOW_BIT_NV = 0x00000100, VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueueFlagBits; @@ -2438,6 +2429,11 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineStageFlagBits; typedef VkFlags VkPipelineStageFlags; + +typedef enum VkMemoryMapFlagBits { + VK_MEMORY_MAP_PLACED_BIT_EXT = 0x00000001, + VK_MEMORY_MAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryMapFlagBits; typedef VkFlags VkMemoryMapFlags; typedef enum VkSparseMemoryBindFlagBits { @@ -2505,6 +2501,7 @@ typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000010, VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000020, + VK_BUFFER_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR = 0x00000040, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF @@ -2533,12 +2530,8 @@ typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 0x00080000, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 0x00100000, VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00008000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00010000, -#endif VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 0x00200000, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00400000, VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 0x04000000, @@ -2714,6 +2707,8 @@ typedef enum VkDescriptorPoolCreateFlagBits { VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 0x00000002, VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT = 0x00000004, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV = 0x00000008, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV = 0x00000010, VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT, VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF @@ -2728,6 +2723,7 @@ typedef enum VkDescriptorSetLayoutCreateFlagBits { VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT = 0x00000020, VK_DESCRIPTOR_SET_LAYOUT_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00000080, VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT = 0x00000004, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PER_STAGE_BIT_NV = 0x00000040, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT, VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF @@ -4957,6 +4953,8 @@ typedef enum VkSubgroupFeatureFlagBits { VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_ROTATE_BIT_KHR = 0x00000200, + VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT_KHR = 0x00000400, VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSubgroupFeatureFlagBits; typedef VkFlags VkSubgroupFeatureFlags; @@ -5784,6 +5782,7 @@ typedef enum VkDriverId { VK_DRIVER_ID_MESA_DOZEN = 23, VK_DRIVER_ID_MESA_NVK = 24, VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA = 25, + VK_DRIVER_ID_MESA_AGXV = 26, VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, @@ -5813,6 +5812,7 @@ typedef enum VkSamplerReductionMode { VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE = 0, VK_SAMPLER_REDUCTION_MODE_MIN = 1, VK_SAMPLER_REDUCTION_MODE_MAX = 2, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_RANGECLAMP_QCOM = 1000521000, VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, VK_SAMPLER_REDUCTION_MODE_MIN_EXT = VK_SAMPLER_REDUCTION_MODE_MIN, VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX, @@ -5833,6 +5833,7 @@ typedef enum VkResolveModeFlagBits { VK_RESOLVE_MODE_AVERAGE_BIT = 0x00000002, VK_RESOLVE_MODE_MIN_BIT = 0x00000004, VK_RESOLVE_MODE_MAX_BIT = 0x00000008, + VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID = 0x00000010, VK_RESOLVE_MODE_NONE_KHR = VK_RESOLVE_MODE_NONE, VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, VK_RESOLVE_MODE_AVERAGE_BIT_KHR = VK_RESOLVE_MODE_AVERAGE_BIT, @@ -6598,9 +6599,7 @@ static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT = 0x4000000000ULL; static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 0x4000000000ULL; static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR = 0x04000000ULL; -#ifdef VK_ENABLE_BETA_EXTENSIONS static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR = 0x08000000ULL; -#endif static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000ULL; static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000ULL; static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 0x00020000ULL; @@ -6671,12 +6670,8 @@ static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 0x40000000 static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 0x400000000ULL; static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR = 0x800000000ULL; static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR = 0x1000000000ULL; -#ifdef VK_ENABLE_BETA_EXTENSIONS static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR = 0x2000000000ULL; -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR = 0x4000000000ULL; -#endif static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000ULL; static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000ULL; static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000ULL; @@ -6711,6 +6706,7 @@ typedef enum VkRenderingFlagBits { VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 0x00000001, VK_RENDERING_SUSPENDING_BIT = 0x00000002, VK_RENDERING_RESUMING_BIT = 0x00000004, + VK_RENDERING_CONTENTS_INLINE_BIT_EXT = 0x00000010, VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000008, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT, @@ -6782,12 +6778,8 @@ static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000ULL; static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000ULL; static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT = 0x400000000000ULL; -#ifdef VK_ENABLE_BETA_EXTENSIONS static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR = 0x08000000ULL; -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000ULL; -#endif static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV = 0x4000000000ULL; static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM = 0x400000000ULL; static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM = 0x800000000ULL; @@ -7992,19 +7984,17 @@ typedef enum VkQueryResultStatusKHR { VK_QUERY_RESULT_STATUS_ERROR_KHR = -1, VK_QUERY_RESULT_STATUS_NOT_READY_KHR = 0, VK_QUERY_RESULT_STATUS_COMPLETE_KHR = 1, + VK_QUERY_RESULT_STATUS_INSUFFICIENT_BITSTREAM_BUFFER_RANGE_KHR = -1000299000, VK_QUERY_RESULT_STATUS_MAX_ENUM_KHR = 0x7FFFFFFF } VkQueryResultStatusKHR; typedef enum VkVideoCodecOperationFlagBitsKHR { VK_VIDEO_CODEC_OPERATION_NONE_KHR = 0, -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT = 0x00010000, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS - VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_EXT = 0x00020000, -#endif + VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR = 0x00010000, + VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR = 0x00020000, VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR = 0x00000001, VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR = 0x00000002, + VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR = 0x00000004, VK_VIDEO_CODEC_OPERATION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkVideoCodecOperationFlagBitsKHR; typedef VkFlags VkVideoCodecOperationFlagsKHR; @@ -8037,9 +8027,8 @@ typedef VkFlags VkVideoCapabilityFlagsKHR; typedef enum VkVideoSessionCreateFlagBitsKHR { VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR = 0x00000001, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_PARAMETER_OPTIMIZATIONS_BIT_KHR = 0x00000002, -#endif + VK_VIDEO_SESSION_CREATE_INLINE_QUERIES_BIT_KHR = 0x00000004, VK_VIDEO_SESSION_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkVideoSessionCreateFlagBitsKHR; typedef VkFlags VkVideoSessionCreateFlagsKHR; @@ -8049,12 +8038,8 @@ typedef VkFlags VkVideoEndCodingFlagsKHR; typedef enum VkVideoCodingControlFlagBitsKHR { VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR = 0x00000001, -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_VIDEO_CODING_CONTROL_ENCODE_RATE_CONTROL_BIT_KHR = 0x00000002, -#endif -#ifdef VK_ENABLE_BETA_EXTENSIONS VK_VIDEO_CODING_CONTROL_ENCODE_QUALITY_LEVEL_BIT_KHR = 0x00000004, -#endif VK_VIDEO_CODING_CONTROL_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkVideoCodingControlFlagBitsKHR; typedef VkFlags VkVideoCodingControlFlagsKHR; @@ -8279,7 +8264,7 @@ VKAPI_ATTR void VKAPI_CALL vkCmdControlVideoCodingKHR( // VK_KHR_video_decode_queue is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_video_decode_queue 1 -#define VK_KHR_VIDEO_DECODE_QUEUE_SPEC_VERSION 7 +#define VK_KHR_VIDEO_DECODE_QUEUE_SPEC_VERSION 8 #define VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME "VK_KHR_video_decode_queue" typedef enum VkVideoDecodeCapabilityFlagBitsKHR { @@ -8332,11 +8317,434 @@ VKAPI_ATTR void VKAPI_CALL vkCmdDecodeVideoKHR( #endif +// VK_KHR_video_encode_h264 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_h264 1 +#include "vk_video/vulkan_video_codec_h264std.h" +#include "vk_video/vulkan_video_codec_h264std_encode.h" +#define VK_KHR_VIDEO_ENCODE_H264_SPEC_VERSION 14 +#define VK_KHR_VIDEO_ENCODE_H264_EXTENSION_NAME "VK_KHR_video_encode_h264" + +typedef enum VkVideoEncodeH264CapabilityFlagBitsKHR { + VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H264_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H264_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_H264_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_H264_CAPABILITY_PER_SLICE_CONSTANT_QP_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_H264_CAPABILITY_GENERATE_PREFIX_NALU_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_H264_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH264CapabilityFlagBitsKHR; +typedef VkFlags VkVideoEncodeH264CapabilityFlagsKHR; + +typedef enum VkVideoEncodeH264StdFlagBitsKHR { + VK_VIDEO_ENCODE_H264_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H264_STD_QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG_SET_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H264_STD_CHROMA_QP_INDEX_OFFSET_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H264_STD_SECOND_CHROMA_QP_INDEX_OFFSET_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H264_STD_PIC_INIT_QP_MINUS26_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_PRED_FLAG_SET_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_EXPLICIT_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_IMPLICIT_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_H264_STD_TRANSFORM_8X8_MODE_FLAG_SET_BIT_KHR = 0x00000200, + VK_VIDEO_ENCODE_H264_STD_DIRECT_SPATIAL_MV_PRED_FLAG_UNSET_BIT_KHR = 0x00000400, + VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_UNSET_BIT_KHR = 0x00000800, + VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_SET_BIT_KHR = 0x00001000, + VK_VIDEO_ENCODE_H264_STD_DIRECT_8X8_INFERENCE_FLAG_UNSET_BIT_KHR = 0x00002000, + VK_VIDEO_ENCODE_H264_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR = 0x00004000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_DISABLED_BIT_KHR = 0x00008000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_ENABLED_BIT_KHR = 0x00010000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_PARTIAL_BIT_KHR = 0x00020000, + VK_VIDEO_ENCODE_H264_STD_SLICE_QP_DELTA_BIT_KHR = 0x00080000, + VK_VIDEO_ENCODE_H264_STD_DIFFERENT_SLICE_QP_DELTA_BIT_KHR = 0x00100000, + VK_VIDEO_ENCODE_H264_STD_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH264StdFlagBitsKHR; +typedef VkFlags VkVideoEncodeH264StdFlagsKHR; + +typedef enum VkVideoEncodeH264RateControlFlagBitsKHR { + VK_VIDEO_ENCODE_H264_RATE_CONTROL_ATTEMPT_HRD_COMPLIANCE_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REGULAR_GOP_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_TEMPORAL_LAYER_PATTERN_DYADIC_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH264RateControlFlagBitsKHR; +typedef VkFlags VkVideoEncodeH264RateControlFlagsKHR; +typedef struct VkVideoEncodeH264CapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH264CapabilityFlagsKHR flags; + StdVideoH264LevelIdc maxLevelIdc; + uint32_t maxSliceCount; + uint32_t maxPPictureL0ReferenceCount; + uint32_t maxBPictureL0ReferenceCount; + uint32_t maxL1ReferenceCount; + uint32_t maxTemporalLayerCount; + VkBool32 expectDyadicTemporalLayerPattern; + int32_t minQp; + int32_t maxQp; + VkBool32 prefersGopRemainingFrames; + VkBool32 requiresGopRemainingFrames; + VkVideoEncodeH264StdFlagsKHR stdSyntaxFlags; +} VkVideoEncodeH264CapabilitiesKHR; + +typedef struct VkVideoEncodeH264QpKHR { + int32_t qpI; + int32_t qpP; + int32_t qpB; +} VkVideoEncodeH264QpKHR; + +typedef struct VkVideoEncodeH264QualityLevelPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH264RateControlFlagsKHR preferredRateControlFlags; + uint32_t preferredGopFrameCount; + uint32_t preferredIdrPeriod; + uint32_t preferredConsecutiveBFrameCount; + uint32_t preferredTemporalLayerCount; + VkVideoEncodeH264QpKHR preferredConstantQp; + uint32_t preferredMaxL0ReferenceCount; + uint32_t preferredMaxL1ReferenceCount; + VkBool32 preferredStdEntropyCodingModeFlag; +} VkVideoEncodeH264QualityLevelPropertiesKHR; + +typedef struct VkVideoEncodeH264SessionCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMaxLevelIdc; + StdVideoH264LevelIdc maxLevelIdc; +} VkVideoEncodeH264SessionCreateInfoKHR; + +typedef struct VkVideoEncodeH264SessionParametersAddInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t stdSPSCount; + const StdVideoH264SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH264PictureParameterSet* pStdPPSs; +} VkVideoEncodeH264SessionParametersAddInfoKHR; + +typedef struct VkVideoEncodeH264SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoEncodeH264SessionParametersAddInfoKHR* pParametersAddInfo; +} VkVideoEncodeH264SessionParametersCreateInfoKHR; + +typedef struct VkVideoEncodeH264SessionParametersGetInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 writeStdSPS; + VkBool32 writeStdPPS; + uint32_t stdSPSId; + uint32_t stdPPSId; +} VkVideoEncodeH264SessionParametersGetInfoKHR; + +typedef struct VkVideoEncodeH264SessionParametersFeedbackInfoKHR { + VkStructureType sType; + void* pNext; + VkBool32 hasStdSPSOverrides; + VkBool32 hasStdPPSOverrides; +} VkVideoEncodeH264SessionParametersFeedbackInfoKHR; + +typedef struct VkVideoEncodeH264NaluSliceInfoKHR { + VkStructureType sType; + const void* pNext; + int32_t constantQp; + const StdVideoEncodeH264SliceHeader* pStdSliceHeader; +} VkVideoEncodeH264NaluSliceInfoKHR; + +typedef struct VkVideoEncodeH264PictureInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t naluSliceEntryCount; + const VkVideoEncodeH264NaluSliceInfoKHR* pNaluSliceEntries; + const StdVideoEncodeH264PictureInfo* pStdPictureInfo; + VkBool32 generatePrefixNalu; +} VkVideoEncodeH264PictureInfoKHR; + +typedef struct VkVideoEncodeH264DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoEncodeH264ReferenceInfo* pStdReferenceInfo; +} VkVideoEncodeH264DpbSlotInfoKHR; + +typedef struct VkVideoEncodeH264ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoH264ProfileIdc stdProfileIdc; +} VkVideoEncodeH264ProfileInfoKHR; + +typedef struct VkVideoEncodeH264RateControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeH264RateControlFlagsKHR flags; + uint32_t gopFrameCount; + uint32_t idrPeriod; + uint32_t consecutiveBFrameCount; + uint32_t temporalLayerCount; +} VkVideoEncodeH264RateControlInfoKHR; + +typedef struct VkVideoEncodeH264FrameSizeKHR { + uint32_t frameISize; + uint32_t framePSize; + uint32_t frameBSize; +} VkVideoEncodeH264FrameSizeKHR; + +typedef struct VkVideoEncodeH264RateControlLayerInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMinQp; + VkVideoEncodeH264QpKHR minQp; + VkBool32 useMaxQp; + VkVideoEncodeH264QpKHR maxQp; + VkBool32 useMaxFrameSize; + VkVideoEncodeH264FrameSizeKHR maxFrameSize; +} VkVideoEncodeH264RateControlLayerInfoKHR; + +typedef struct VkVideoEncodeH264GopRemainingFrameInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useGopRemainingFrames; + uint32_t gopRemainingI; + uint32_t gopRemainingP; + uint32_t gopRemainingB; +} VkVideoEncodeH264GopRemainingFrameInfoKHR; + + + +// VK_KHR_video_encode_h265 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_h265 1 +#include "vk_video/vulkan_video_codec_h265std.h" +#include "vk_video/vulkan_video_codec_h265std_encode.h" +#define VK_KHR_VIDEO_ENCODE_H265_SPEC_VERSION 14 +#define VK_KHR_VIDEO_ENCODE_H265_EXTENSION_NAME "VK_KHR_video_encode_h265" + +typedef enum VkVideoEncodeH265CapabilityFlagBitsKHR { + VK_VIDEO_ENCODE_H265_CAPABILITY_HRD_COMPLIANCE_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_CAPABILITY_ROW_UNALIGNED_SLICE_SEGMENT_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_CAPABILITY_DIFFERENT_SLICE_SEGMENT_TYPE_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_H265_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_H265_CAPABILITY_PER_SLICE_SEGMENT_CONSTANT_QP_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_TILES_PER_SLICE_SEGMENT_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_SLICE_SEGMENTS_PER_TILE_BIT_KHR = 0x00000200, + VK_VIDEO_ENCODE_H265_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265CapabilityFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265CapabilityFlagsKHR; + +typedef enum VkVideoEncodeH265StdFlagBitsKHR { + VK_VIDEO_ENCODE_H265_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_STD_SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG_SET_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_STD_SCALING_LIST_DATA_PRESENT_FLAG_SET_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_STD_PCM_ENABLED_FLAG_SET_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H265_STD_SPS_TEMPORAL_MVP_ENABLED_FLAG_SET_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H265_STD_INIT_QP_MINUS26_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_H265_STD_WEIGHTED_PRED_FLAG_SET_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_H265_STD_WEIGHTED_BIPRED_FLAG_SET_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_H265_STD_LOG2_PARALLEL_MERGE_LEVEL_MINUS2_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_H265_STD_SIGN_DATA_HIDING_ENABLED_FLAG_SET_BIT_KHR = 0x00000200, + VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_SET_BIT_KHR = 0x00000400, + VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_UNSET_BIT_KHR = 0x00000800, + VK_VIDEO_ENCODE_H265_STD_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG_SET_BIT_KHR = 0x00001000, + VK_VIDEO_ENCODE_H265_STD_TRANSQUANT_BYPASS_ENABLED_FLAG_SET_BIT_KHR = 0x00002000, + VK_VIDEO_ENCODE_H265_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR = 0x00004000, + VK_VIDEO_ENCODE_H265_STD_ENTROPY_CODING_SYNC_ENABLED_FLAG_SET_BIT_KHR = 0x00008000, + VK_VIDEO_ENCODE_H265_STD_DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_SET_BIT_KHR = 0x00010000, + VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG_SET_BIT_KHR = 0x00020000, + VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENT_FLAG_SET_BIT_KHR = 0x00040000, + VK_VIDEO_ENCODE_H265_STD_SLICE_QP_DELTA_BIT_KHR = 0x00080000, + VK_VIDEO_ENCODE_H265_STD_DIFFERENT_SLICE_QP_DELTA_BIT_KHR = 0x00100000, + VK_VIDEO_ENCODE_H265_STD_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265StdFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265StdFlagsKHR; + +typedef enum VkVideoEncodeH265CtbSizeFlagBitsKHR { + VK_VIDEO_ENCODE_H265_CTB_SIZE_16_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_CTB_SIZE_32_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_CTB_SIZE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265CtbSizeFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265CtbSizeFlagsKHR; + +typedef enum VkVideoEncodeH265TransformBlockSizeFlagBitsKHR { + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_8_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_16_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_32_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265TransformBlockSizeFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265TransformBlockSizeFlagsKHR; + +typedef enum VkVideoEncodeH265RateControlFlagBitsKHR { + VK_VIDEO_ENCODE_H265_RATE_CONTROL_ATTEMPT_HRD_COMPLIANCE_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REGULAR_GOP_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_TEMPORAL_SUB_LAYER_PATTERN_DYADIC_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265RateControlFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265RateControlFlagsKHR; +typedef struct VkVideoEncodeH265CapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH265CapabilityFlagsKHR flags; + StdVideoH265LevelIdc maxLevelIdc; + uint32_t maxSliceSegmentCount; + VkExtent2D maxTiles; + VkVideoEncodeH265CtbSizeFlagsKHR ctbSizes; + VkVideoEncodeH265TransformBlockSizeFlagsKHR transformBlockSizes; + uint32_t maxPPictureL0ReferenceCount; + uint32_t maxBPictureL0ReferenceCount; + uint32_t maxL1ReferenceCount; + uint32_t maxSubLayerCount; + VkBool32 expectDyadicTemporalSubLayerPattern; + int32_t minQp; + int32_t maxQp; + VkBool32 prefersGopRemainingFrames; + VkBool32 requiresGopRemainingFrames; + VkVideoEncodeH265StdFlagsKHR stdSyntaxFlags; +} VkVideoEncodeH265CapabilitiesKHR; + +typedef struct VkVideoEncodeH265SessionCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMaxLevelIdc; + StdVideoH265LevelIdc maxLevelIdc; +} VkVideoEncodeH265SessionCreateInfoKHR; + +typedef struct VkVideoEncodeH265QpKHR { + int32_t qpI; + int32_t qpP; + int32_t qpB; +} VkVideoEncodeH265QpKHR; + +typedef struct VkVideoEncodeH265QualityLevelPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH265RateControlFlagsKHR preferredRateControlFlags; + uint32_t preferredGopFrameCount; + uint32_t preferredIdrPeriod; + uint32_t preferredConsecutiveBFrameCount; + uint32_t preferredSubLayerCount; + VkVideoEncodeH265QpKHR preferredConstantQp; + uint32_t preferredMaxL0ReferenceCount; + uint32_t preferredMaxL1ReferenceCount; +} VkVideoEncodeH265QualityLevelPropertiesKHR; + +typedef struct VkVideoEncodeH265SessionParametersAddInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t stdVPSCount; + const StdVideoH265VideoParameterSet* pStdVPSs; + uint32_t stdSPSCount; + const StdVideoH265SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH265PictureParameterSet* pStdPPSs; +} VkVideoEncodeH265SessionParametersAddInfoKHR; + +typedef struct VkVideoEncodeH265SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxStdVPSCount; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoEncodeH265SessionParametersAddInfoKHR* pParametersAddInfo; +} VkVideoEncodeH265SessionParametersCreateInfoKHR; + +typedef struct VkVideoEncodeH265SessionParametersGetInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 writeStdVPS; + VkBool32 writeStdSPS; + VkBool32 writeStdPPS; + uint32_t stdVPSId; + uint32_t stdSPSId; + uint32_t stdPPSId; +} VkVideoEncodeH265SessionParametersGetInfoKHR; + +typedef struct VkVideoEncodeH265SessionParametersFeedbackInfoKHR { + VkStructureType sType; + void* pNext; + VkBool32 hasStdVPSOverrides; + VkBool32 hasStdSPSOverrides; + VkBool32 hasStdPPSOverrides; +} VkVideoEncodeH265SessionParametersFeedbackInfoKHR; + +typedef struct VkVideoEncodeH265NaluSliceSegmentInfoKHR { + VkStructureType sType; + const void* pNext; + int32_t constantQp; + const StdVideoEncodeH265SliceSegmentHeader* pStdSliceSegmentHeader; +} VkVideoEncodeH265NaluSliceSegmentInfoKHR; + +typedef struct VkVideoEncodeH265PictureInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t naluSliceSegmentEntryCount; + const VkVideoEncodeH265NaluSliceSegmentInfoKHR* pNaluSliceSegmentEntries; + const StdVideoEncodeH265PictureInfo* pStdPictureInfo; +} VkVideoEncodeH265PictureInfoKHR; + +typedef struct VkVideoEncodeH265DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoEncodeH265ReferenceInfo* pStdReferenceInfo; +} VkVideoEncodeH265DpbSlotInfoKHR; + +typedef struct VkVideoEncodeH265ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoH265ProfileIdc stdProfileIdc; +} VkVideoEncodeH265ProfileInfoKHR; + +typedef struct VkVideoEncodeH265RateControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeH265RateControlFlagsKHR flags; + uint32_t gopFrameCount; + uint32_t idrPeriod; + uint32_t consecutiveBFrameCount; + uint32_t subLayerCount; +} VkVideoEncodeH265RateControlInfoKHR; + +typedef struct VkVideoEncodeH265FrameSizeKHR { + uint32_t frameISize; + uint32_t framePSize; + uint32_t frameBSize; +} VkVideoEncodeH265FrameSizeKHR; + +typedef struct VkVideoEncodeH265RateControlLayerInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMinQp; + VkVideoEncodeH265QpKHR minQp; + VkBool32 useMaxQp; + VkVideoEncodeH265QpKHR maxQp; + VkBool32 useMaxFrameSize; + VkVideoEncodeH265FrameSizeKHR maxFrameSize; +} VkVideoEncodeH265RateControlLayerInfoKHR; + +typedef struct VkVideoEncodeH265GopRemainingFrameInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useGopRemainingFrames; + uint32_t gopRemainingI; + uint32_t gopRemainingP; + uint32_t gopRemainingB; +} VkVideoEncodeH265GopRemainingFrameInfoKHR; + + + // VK_KHR_video_decode_h264 is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_video_decode_h264 1 -#include "vk_video/vulkan_video_codec_h264std.h" #include "vk_video/vulkan_video_codec_h264std_decode.h" -#define VK_KHR_VIDEO_DECODE_H264_SPEC_VERSION 8 +#define VK_KHR_VIDEO_DECODE_H264_SPEC_VERSION 9 #define VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME "VK_KHR_video_decode_h264" typedef enum VkVideoDecodeH264PictureLayoutFlagBitsKHR { @@ -9550,9 +9958,8 @@ typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { // VK_KHR_video_decode_h265 is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_video_decode_h265 1 -#include "vk_video/vulkan_video_codec_h265std.h" #include "vk_video/vulkan_video_codec_h265std_decode.h" -#define VK_KHR_VIDEO_DECODE_H265_SPEC_VERSION 7 +#define VK_KHR_VIDEO_DECODE_H265_SPEC_VERSION 8 #define VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME "VK_KHR_video_decode_h265" typedef struct VkVideoDecodeH265ProfileInfoKHR { VkStructureType sType; @@ -9823,6 +10230,58 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetFragmentShadingRateKHR( #endif +// VK_KHR_dynamic_rendering_local_read is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_dynamic_rendering_local_read 1 +#define VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME "VK_KHR_dynamic_rendering_local_read" +typedef struct VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 dynamicRenderingLocalRead; +} VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR; + +typedef struct VkRenderingAttachmentLocationInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t colorAttachmentCount; + const uint32_t* pColorAttachmentLocations; +} VkRenderingAttachmentLocationInfoKHR; + +typedef struct VkRenderingInputAttachmentIndexInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t colorAttachmentCount; + const uint32_t* pColorAttachmentInputIndices; + const uint32_t* pDepthInputAttachmentIndex; + const uint32_t* pStencilInputAttachmentIndex; +} VkRenderingInputAttachmentIndexInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdSetRenderingAttachmentLocationsKHR)(VkCommandBuffer commandBuffer, const VkRenderingAttachmentLocationInfoKHR* pLocationInfo); +typedef void (VKAPI_PTR *PFN_vkCmdSetRenderingInputAttachmentIndicesKHR)(VkCommandBuffer commandBuffer, const VkRenderingInputAttachmentIndexInfoKHR* pLocationInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetRenderingAttachmentLocationsKHR( + VkCommandBuffer commandBuffer, + const VkRenderingAttachmentLocationInfoKHR* pLocationInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRenderingInputAttachmentIndicesKHR( + VkCommandBuffer commandBuffer, + const VkRenderingInputAttachmentIndexInfoKHR* pLocationInfo); +#endif + + +// VK_KHR_shader_quad_control is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_quad_control 1 +#define VK_KHR_SHADER_QUAD_CONTROL_SPEC_VERSION 1 +#define VK_KHR_SHADER_QUAD_CONTROL_EXTENSION_NAME "VK_KHR_shader_quad_control" +typedef struct VkPhysicalDeviceShaderQuadControlFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderQuadControl; +} VkPhysicalDeviceShaderQuadControlFeaturesKHR; + + + // VK_KHR_spirv_1_4 is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_spirv_1_4 1 #define VK_KHR_SPIRV_1_4_SPEC_VERSION 1 @@ -10046,6 +10505,11 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableInternalRepresentationsKHR #define VK_KHR_map_memory2 1 #define VK_KHR_MAP_MEMORY_2_SPEC_VERSION 1 #define VK_KHR_MAP_MEMORY_2_EXTENSION_NAME "VK_KHR_map_memory2" + +typedef enum VkMemoryUnmapFlagBitsKHR { + VK_MEMORY_UNMAP_RESERVE_BIT_EXT = 0x00000001, + VK_MEMORY_UNMAP_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkMemoryUnmapFlagBitsKHR; typedef VkFlags VkMemoryUnmapFlagsKHR; typedef struct VkMemoryMapInfoKHR { VkStructureType sType; @@ -10126,6 +10590,183 @@ typedef struct VkPhysicalDevicePresentIdFeaturesKHR { +// VK_KHR_video_encode_queue is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_queue 1 +#define VK_KHR_VIDEO_ENCODE_QUEUE_SPEC_VERSION 12 +#define VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME "VK_KHR_video_encode_queue" + +typedef enum VkVideoEncodeTuningModeKHR { + VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_TUNING_MODE_HIGH_QUALITY_KHR = 1, + VK_VIDEO_ENCODE_TUNING_MODE_LOW_LATENCY_KHR = 2, + VK_VIDEO_ENCODE_TUNING_MODE_ULTRA_LOW_LATENCY_KHR = 3, + VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR = 4, + VK_VIDEO_ENCODE_TUNING_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeTuningModeKHR; + +typedef enum VkVideoEncodeFlagBitsKHR { + VK_VIDEO_ENCODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeFlagBitsKHR; +typedef VkFlags VkVideoEncodeFlagsKHR; + +typedef enum VkVideoEncodeCapabilityFlagBitsKHR { + VK_VIDEO_ENCODE_CAPABILITY_PRECEDING_EXTERNALLY_ENCODED_BYTES_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_CAPABILITY_INSUFFICIENT_BITSTREAM_BUFFER_RANGE_DETECTION_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeCapabilityFlagBitsKHR; +typedef VkFlags VkVideoEncodeCapabilityFlagsKHR; + +typedef enum VkVideoEncodeRateControlModeFlagBitsKHR { + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeRateControlModeFlagBitsKHR; +typedef VkFlags VkVideoEncodeRateControlModeFlagsKHR; + +typedef enum VkVideoEncodeFeedbackFlagBitsKHR { + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_HAS_OVERRIDES_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_FEEDBACK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeFeedbackFlagBitsKHR; +typedef VkFlags VkVideoEncodeFeedbackFlagsKHR; + +typedef enum VkVideoEncodeUsageFlagBitsKHR { + VK_VIDEO_ENCODE_USAGE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_USAGE_TRANSCODING_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_USAGE_STREAMING_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_USAGE_RECORDING_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_USAGE_CONFERENCING_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_USAGE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeUsageFlagBitsKHR; +typedef VkFlags VkVideoEncodeUsageFlagsKHR; + +typedef enum VkVideoEncodeContentFlagBitsKHR { + VK_VIDEO_ENCODE_CONTENT_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_CONTENT_CAMERA_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_CONTENT_DESKTOP_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_CONTENT_RENDERED_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_CONTENT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeContentFlagBitsKHR; +typedef VkFlags VkVideoEncodeContentFlagsKHR; +typedef VkFlags VkVideoEncodeRateControlFlagsKHR; +typedef struct VkVideoEncodeInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeFlagsKHR flags; + VkBuffer dstBuffer; + VkDeviceSize dstBufferOffset; + VkDeviceSize dstBufferRange; + VkVideoPictureResourceInfoKHR srcPictureResource; + const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot; + uint32_t referenceSlotCount; + const VkVideoReferenceSlotInfoKHR* pReferenceSlots; + uint32_t precedingExternallyEncodedBytes; +} VkVideoEncodeInfoKHR; + +typedef struct VkVideoEncodeCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeCapabilityFlagsKHR flags; + VkVideoEncodeRateControlModeFlagsKHR rateControlModes; + uint32_t maxRateControlLayers; + uint64_t maxBitrate; + uint32_t maxQualityLevels; + VkExtent2D encodeInputPictureGranularity; + VkVideoEncodeFeedbackFlagsKHR supportedEncodeFeedbackFlags; +} VkVideoEncodeCapabilitiesKHR; + +typedef struct VkQueryPoolVideoEncodeFeedbackCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeFeedbackFlagsKHR encodeFeedbackFlags; +} VkQueryPoolVideoEncodeFeedbackCreateInfoKHR; + +typedef struct VkVideoEncodeUsageInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeUsageFlagsKHR videoUsageHints; + VkVideoEncodeContentFlagsKHR videoContentHints; + VkVideoEncodeTuningModeKHR tuningMode; +} VkVideoEncodeUsageInfoKHR; + +typedef struct VkVideoEncodeRateControlLayerInfoKHR { + VkStructureType sType; + const void* pNext; + uint64_t averageBitrate; + uint64_t maxBitrate; + uint32_t frameRateNumerator; + uint32_t frameRateDenominator; +} VkVideoEncodeRateControlLayerInfoKHR; + +typedef struct VkVideoEncodeRateControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeRateControlFlagsKHR flags; + VkVideoEncodeRateControlModeFlagBitsKHR rateControlMode; + uint32_t layerCount; + const VkVideoEncodeRateControlLayerInfoKHR* pLayers; + uint32_t virtualBufferSizeInMs; + uint32_t initialVirtualBufferSizeInMs; +} VkVideoEncodeRateControlInfoKHR; + +typedef struct VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR { + VkStructureType sType; + const void* pNext; + const VkVideoProfileInfoKHR* pVideoProfile; + uint32_t qualityLevel; +} VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR; + +typedef struct VkVideoEncodeQualityLevelPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeRateControlModeFlagBitsKHR preferredRateControlMode; + uint32_t preferredRateControlLayerCount; +} VkVideoEncodeQualityLevelPropertiesKHR; + +typedef struct VkVideoEncodeQualityLevelInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t qualityLevel; +} VkVideoEncodeQualityLevelInfoKHR; + +typedef struct VkVideoEncodeSessionParametersGetInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoSessionParametersKHR videoSessionParameters; +} VkVideoEncodeSessionParametersGetInfoKHR; + +typedef struct VkVideoEncodeSessionParametersFeedbackInfoKHR { + VkStructureType sType; + void* pNext; + VkBool32 hasOverrides; +} VkVideoEncodeSessionParametersFeedbackInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo, VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetEncodedVideoSessionParametersKHR)(VkDevice device, const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo, VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo, size_t* pDataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdEncodeVideoKHR)(VkCommandBuffer commandBuffer, const VkVideoEncodeInfoKHR* pEncodeInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo, + VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetEncodedVideoSessionParametersKHR( + VkDevice device, + const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo, + VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo, + size_t* pDataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdEncodeVideoKHR( + VkCommandBuffer commandBuffer, + const VkVideoEncodeInfoKHR* pEncodeInfo); +#endif + + // VK_KHR_synchronization2 is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_synchronization2 1 #define VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION 1 @@ -10430,6 +11071,31 @@ VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirementsKHR( #endif +// VK_KHR_shader_subgroup_rotate is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_subgroup_rotate 1 +#define VK_KHR_SHADER_SUBGROUP_ROTATE_SPEC_VERSION 2 +#define VK_KHR_SHADER_SUBGROUP_ROTATE_EXTENSION_NAME "VK_KHR_shader_subgroup_rotate" +typedef struct VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupRotate; + VkBool32 shaderSubgroupRotateClustered; +} VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR; + + + +// VK_KHR_shader_maximal_reconvergence is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_maximal_reconvergence 1 +#define VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_SPEC_VERSION 1 +#define VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_EXTENSION_NAME "VK_KHR_shader_maximal_reconvergence" +typedef struct VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderMaximalReconvergence; +} VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR; + + + // VK_KHR_maintenance5 is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_maintenance5 1 #define VK_KHR_MAINTENANCE_5_SPEC_VERSION 1 @@ -10686,6 +11352,355 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR #endif +// VK_KHR_video_decode_av1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_av1 1 +#include "vk_video/vulkan_video_codec_av1std.h" +#include "vk_video/vulkan_video_codec_av1std_decode.h" +#define VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR 7U +#define VK_KHR_VIDEO_DECODE_AV1_SPEC_VERSION 1 +#define VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME "VK_KHR_video_decode_av1" +typedef struct VkVideoDecodeAV1ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoAV1Profile stdProfile; + VkBool32 filmGrainSupport; +} VkVideoDecodeAV1ProfileInfoKHR; + +typedef struct VkVideoDecodeAV1CapabilitiesKHR { + VkStructureType sType; + void* pNext; + StdVideoAV1Level maxLevel; +} VkVideoDecodeAV1CapabilitiesKHR; + +typedef struct VkVideoDecodeAV1SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoAV1SequenceHeader* pStdSequenceHeader; +} VkVideoDecodeAV1SessionParametersCreateInfoKHR; + +typedef struct VkVideoDecodeAV1PictureInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeAV1PictureInfo* pStdPictureInfo; + int32_t referenceNameSlotIndices[VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR]; + uint32_t frameHeaderOffset; + uint32_t tileCount; + const uint32_t* pTileOffsets; + const uint32_t* pTileSizes; +} VkVideoDecodeAV1PictureInfoKHR; + +typedef struct VkVideoDecodeAV1DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeAV1ReferenceInfo* pStdReferenceInfo; +} VkVideoDecodeAV1DpbSlotInfoKHR; + + + +// VK_KHR_video_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_maintenance1 1 +#define VK_KHR_VIDEO_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_video_maintenance1" +typedef struct VkPhysicalDeviceVideoMaintenance1FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 videoMaintenance1; +} VkPhysicalDeviceVideoMaintenance1FeaturesKHR; + +typedef struct VkVideoInlineQueryInfoKHR { + VkStructureType sType; + const void* pNext; + VkQueryPool queryPool; + uint32_t firstQuery; + uint32_t queryCount; +} VkVideoInlineQueryInfoKHR; + + + +// VK_KHR_vertex_attribute_divisor is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_vertex_attribute_divisor 1 +#define VK_KHR_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 1 +#define VK_KHR_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_KHR_vertex_attribute_divisor" +typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t maxVertexAttribDivisor; + VkBool32 supportsNonZeroFirstInstance; +} VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR; + +typedef struct VkVertexInputBindingDivisorDescriptionKHR { + uint32_t binding; + uint32_t divisor; +} VkVertexInputBindingDivisorDescriptionKHR; + +typedef struct VkPipelineVertexInputDivisorStateCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t vertexBindingDivisorCount; + const VkVertexInputBindingDivisorDescriptionKHR* pVertexBindingDivisors; +} VkPipelineVertexInputDivisorStateCreateInfoKHR; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; +} VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR; + + + +// VK_KHR_load_store_op_none is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_load_store_op_none 1 +#define VK_KHR_LOAD_STORE_OP_NONE_SPEC_VERSION 1 +#define VK_KHR_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_KHR_load_store_op_none" + + +// VK_KHR_shader_float_controls2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_float_controls2 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_2_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_2_EXTENSION_NAME "VK_KHR_shader_float_controls2" +typedef struct VkPhysicalDeviceShaderFloatControls2FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloatControls2; +} VkPhysicalDeviceShaderFloatControls2FeaturesKHR; + + + +// VK_KHR_index_type_uint8 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_index_type_uint8 1 +#define VK_KHR_INDEX_TYPE_UINT8_SPEC_VERSION 1 +#define VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_KHR_index_type_uint8" +typedef struct VkPhysicalDeviceIndexTypeUint8FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 indexTypeUint8; +} VkPhysicalDeviceIndexTypeUint8FeaturesKHR; + + + +// VK_KHR_line_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_line_rasterization 1 +#define VK_KHR_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_KHR_LINE_RASTERIZATION_EXTENSION_NAME "VK_KHR_line_rasterization" + +typedef enum VkLineRasterizationModeKHR { + VK_LINE_RASTERIZATION_MODE_DEFAULT_KHR = 0, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_KHR = 1, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_KHR = 2, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_KHR = 3, + VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = VK_LINE_RASTERIZATION_MODE_DEFAULT_KHR, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_KHR, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = VK_LINE_RASTERIZATION_MODE_BRESENHAM_KHR, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_KHR, + VK_LINE_RASTERIZATION_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkLineRasterizationModeKHR; +typedef struct VkPhysicalDeviceLineRasterizationFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; +} VkPhysicalDeviceLineRasterizationFeaturesKHR; + +typedef struct VkPhysicalDeviceLineRasterizationPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t lineSubPixelPrecisionBits; +} VkPhysicalDeviceLineRasterizationPropertiesKHR; + +typedef struct VkPipelineRasterizationLineStateCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkLineRasterizationModeKHR lineRasterizationMode; + VkBool32 stippledLineEnable; + uint32_t lineStippleFactor; + uint16_t lineStipplePattern; +} VkPipelineRasterizationLineStateCreateInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleKHR)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleKHR( + VkCommandBuffer commandBuffer, + uint32_t lineStippleFactor, + uint16_t lineStipplePattern); +#endif + + +// VK_KHR_calibrated_timestamps is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_calibrated_timestamps 1 +#define VK_KHR_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 +#define VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_KHR_calibrated_timestamps" + +typedef enum VkTimeDomainKHR { + VK_TIME_DOMAIN_DEVICE_KHR = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR = 3, + VK_TIME_DOMAIN_DEVICE_EXT = VK_TIME_DOMAIN_DEVICE_KHR, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR, + VK_TIME_DOMAIN_MAX_ENUM_KHR = 0x7FFFFFFF +} VkTimeDomainKHR; +typedef struct VkCalibratedTimestampInfoKHR { + VkStructureType sType; + const void* pNext; + VkTimeDomainKHR timeDomain; +} VkCalibratedTimestampInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainKHR* pTimeDomains); +typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsKHR)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pTimeDomainCount, + VkTimeDomainKHR* pTimeDomains); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsKHR( + VkDevice device, + uint32_t timestampCount, + const VkCalibratedTimestampInfoKHR* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation); +#endif + + +// VK_KHR_shader_expect_assume is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_expect_assume 1 +#define VK_KHR_SHADER_EXPECT_ASSUME_SPEC_VERSION 1 +#define VK_KHR_SHADER_EXPECT_ASSUME_EXTENSION_NAME "VK_KHR_shader_expect_assume" +typedef struct VkPhysicalDeviceShaderExpectAssumeFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderExpectAssume; +} VkPhysicalDeviceShaderExpectAssumeFeaturesKHR; + + + +// VK_KHR_maintenance6 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance6 1 +#define VK_KHR_MAINTENANCE_6_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_6_EXTENSION_NAME "VK_KHR_maintenance6" +typedef struct VkPhysicalDeviceMaintenance6FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 maintenance6; +} VkPhysicalDeviceMaintenance6FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance6PropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 blockTexelViewCompatibleMultipleLayers; + uint32_t maxCombinedImageSamplerDescriptorCount; + VkBool32 fragmentShadingRateClampCombinerInputs; +} VkPhysicalDeviceMaintenance6PropertiesKHR; + +typedef struct VkBindMemoryStatusKHR { + VkStructureType sType; + const void* pNext; + VkResult* pResult; +} VkBindMemoryStatusKHR; + +typedef struct VkBindDescriptorSetsInfoKHR { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t descriptorSetCount; + const VkDescriptorSet* pDescriptorSets; + uint32_t dynamicOffsetCount; + const uint32_t* pDynamicOffsets; +} VkBindDescriptorSetsInfoKHR; + +typedef struct VkPushConstantsInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipelineLayout layout; + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; + const void* pValues; +} VkPushConstantsInfoKHR; + +typedef struct VkPushDescriptorSetInfoKHR { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t set; + uint32_t descriptorWriteCount; + const VkWriteDescriptorSet* pDescriptorWrites; +} VkPushDescriptorSetInfoKHR; + +typedef struct VkPushDescriptorSetWithTemplateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDescriptorUpdateTemplate descriptorUpdateTemplate; + VkPipelineLayout layout; + uint32_t set; + const void* pData; +} VkPushDescriptorSetWithTemplateInfoKHR; + +typedef struct VkSetDescriptorBufferOffsetsInfoEXT { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t setCount; + const uint32_t* pBufferIndices; + const VkDeviceSize* pOffsets; +} VkSetDescriptorBufferOffsetsInfoEXT; + +typedef struct VkBindDescriptorBufferEmbeddedSamplersInfoEXT { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t set; +} VkBindDescriptorBufferEmbeddedSamplersInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets2KHR)(VkCommandBuffer commandBuffer, const VkBindDescriptorSetsInfoKHR* pBindDescriptorSetsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushConstants2KHR)(VkCommandBuffer commandBuffer, const VkPushConstantsInfoKHR* pPushConstantsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSet2KHR)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetInfoKHR* pPushDescriptorSetInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplate2KHR)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetWithTemplateInfoKHR* pPushDescriptorSetWithTemplateInfo); +typedef void (VKAPI_PTR *PFN_vkCmdSetDescriptorBufferOffsets2EXT)(VkCommandBuffer commandBuffer, const VkSetDescriptorBufferOffsetsInfoEXT* pSetDescriptorBufferOffsetsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT)(VkCommandBuffer commandBuffer, const VkBindDescriptorBufferEmbeddedSamplersInfoEXT* pBindDescriptorBufferEmbeddedSamplersInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets2KHR( + VkCommandBuffer commandBuffer, + const VkBindDescriptorSetsInfoKHR* pBindDescriptorSetsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants2KHR( + VkCommandBuffer commandBuffer, + const VkPushConstantsInfoKHR* pPushConstantsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSet2KHR( + VkCommandBuffer commandBuffer, + const VkPushDescriptorSetInfoKHR* pPushDescriptorSetInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplate2KHR( + VkCommandBuffer commandBuffer, + const VkPushDescriptorSetWithTemplateInfoKHR* pPushDescriptorSetWithTemplateInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDescriptorBufferOffsets2EXT( + VkCommandBuffer commandBuffer, + const VkSetDescriptorBufferOffsetsInfoEXT* pSetDescriptorBufferOffsetsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorBufferEmbeddedSamplers2EXT( + VkCommandBuffer commandBuffer, + const VkBindDescriptorBufferEmbeddedSamplersInfoEXT* pBindDescriptorBufferEmbeddedSamplersInfo); +#endif + + // VK_EXT_debug_report is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_debug_report 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) @@ -10731,6 +11746,8 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT = 1000029001, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000150000, VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_MODULE_NV_EXT = 1000307000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_FUNCTION_NV_EXT = 1000307001, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT = 1000366000, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, @@ -11311,7 +12328,7 @@ typedef struct VkExportMemoryAllocateInfoNV { // VK_EXT_validation_flags is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_validation_flags 1 -#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 2 +#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 3 #define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" typedef enum VkValidationCheckEXT { @@ -11864,6 +12881,18 @@ VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT( #endif +// VK_IMG_relaxed_line_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_IMG_relaxed_line_rasterization 1 +#define VK_IMG_RELAXED_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_IMG_RELAXED_LINE_RASTERIZATION_EXTENSION_NAME "VK_IMG_relaxed_line_rasterization" +typedef struct VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG { + VkStructureType sType; + void* pNext; + VkBool32 relaxedLineRasterization; +} VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG; + + + // VK_EXT_external_memory_dma_buf is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_external_memory_dma_buf 1 #define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 @@ -13010,33 +14039,23 @@ typedef struct VkPipelineCompilerControlCreateInfoAMD { #define VK_EXT_calibrated_timestamps 1 #define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 2 #define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" +typedef VkTimeDomainKHR VkTimeDomainEXT; -typedef enum VkTimeDomainEXT { - VK_TIME_DOMAIN_DEVICE_EXT = 0, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, - VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, - VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF -} VkTimeDomainEXT; -typedef struct VkCalibratedTimestampInfoEXT { - VkStructureType sType; - const void* pNext; - VkTimeDomainEXT timeDomain; -} VkCalibratedTimestampInfoEXT; +typedef VkCalibratedTimestampInfoKHR VkCalibratedTimestampInfoEXT; -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains); -typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainKHR* pTimeDomains); +typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, - VkTimeDomainEXT* pTimeDomains); + VkTimeDomainKHR* pTimeDomains); VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT( VkDevice device, uint32_t timestampCount, - const VkCalibratedTimestampInfoEXT* pTimestampInfos, + const VkCalibratedTimestampInfoKHR* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); #endif @@ -13096,24 +14115,11 @@ typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { uint32_t maxVertexAttribDivisor; } VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT; -typedef struct VkVertexInputBindingDivisorDescriptionEXT { - uint32_t binding; - uint32_t divisor; -} VkVertexInputBindingDivisorDescriptionEXT; +typedef VkVertexInputBindingDivisorDescriptionKHR VkVertexInputBindingDivisorDescriptionEXT; -typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t vertexBindingDivisorCount; - const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors; -} VkPipelineVertexInputDivisorStateCreateInfoEXT; +typedef VkPipelineVertexInputDivisorStateCreateInfoKHR VkPipelineVertexInputDivisorStateCreateInfoEXT; -typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 vertexAttributeInstanceRateDivisor; - VkBool32 vertexAttributeInstanceRateZeroDivisor; -} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; +typedef VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; @@ -13700,7 +14706,7 @@ typedef VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; // VK_EXT_validation_features is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_validation_features 1 -#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 5 +#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 6 #define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" typedef enum VkValidationFeatureEnableEXT { @@ -13905,39 +14911,13 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateHeadlessSurfaceEXT( #define VK_EXT_line_rasterization 1 #define VK_EXT_LINE_RASTERIZATION_SPEC_VERSION 1 #define VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME "VK_EXT_line_rasterization" +typedef VkLineRasterizationModeKHR VkLineRasterizationModeEXT; -typedef enum VkLineRasterizationModeEXT { - VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = 0, - VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = 1, - VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = 2, - VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = 3, - VK_LINE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkLineRasterizationModeEXT; -typedef struct VkPhysicalDeviceLineRasterizationFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 rectangularLines; - VkBool32 bresenhamLines; - VkBool32 smoothLines; - VkBool32 stippledRectangularLines; - VkBool32 stippledBresenhamLines; - VkBool32 stippledSmoothLines; -} VkPhysicalDeviceLineRasterizationFeaturesEXT; +typedef VkPhysicalDeviceLineRasterizationFeaturesKHR VkPhysicalDeviceLineRasterizationFeaturesEXT; -typedef struct VkPhysicalDeviceLineRasterizationPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t lineSubPixelPrecisionBits; -} VkPhysicalDeviceLineRasterizationPropertiesEXT; +typedef VkPhysicalDeviceLineRasterizationPropertiesKHR VkPhysicalDeviceLineRasterizationPropertiesEXT; -typedef struct VkPipelineRasterizationLineStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkLineRasterizationModeEXT lineRasterizationMode; - VkBool32 stippledLineEnable; - uint32_t lineStippleFactor; - uint16_t lineStipplePattern; -} VkPipelineRasterizationLineStateCreateInfoEXT; +typedef VkPipelineRasterizationLineStateCreateInfoKHR VkPipelineRasterizationLineStateCreateInfoEXT; typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleEXT)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); @@ -13993,11 +14973,7 @@ VKAPI_ATTR void VKAPI_CALL vkResetQueryPoolEXT( #define VK_EXT_index_type_uint8 1 #define VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION 1 #define VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_EXT_index_type_uint8" -typedef struct VkPhysicalDeviceIndexTypeUint8FeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 indexTypeUint8; -} VkPhysicalDeviceIndexTypeUint8FeaturesEXT; +typedef VkPhysicalDeviceIndexTypeUint8FeaturesKHR VkPhysicalDeviceIndexTypeUint8FeaturesEXT; @@ -14225,6 +15201,32 @@ VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout2EXT( #endif +// VK_EXT_map_memory_placed is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_map_memory_placed 1 +#define VK_EXT_MAP_MEMORY_PLACED_SPEC_VERSION 1 +#define VK_EXT_MAP_MEMORY_PLACED_EXTENSION_NAME "VK_EXT_map_memory_placed" +typedef struct VkPhysicalDeviceMapMemoryPlacedFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 memoryMapPlaced; + VkBool32 memoryMapRangePlaced; + VkBool32 memoryUnmapReserve; +} VkPhysicalDeviceMapMemoryPlacedFeaturesEXT; + +typedef struct VkPhysicalDeviceMapMemoryPlacedPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize minPlacedMemoryMapAlignment; +} VkPhysicalDeviceMapMemoryPlacedPropertiesEXT; + +typedef struct VkMemoryMapPlacedInfoEXT { + VkStructureType sType; + const void* pNext; + void* pPlacedAddress; +} VkMemoryMapPlacedInfoEXT; + + + // VK_EXT_shader_atomic_float2 is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_shader_atomic_float2 1 #define VK_EXT_SHADER_ATOMIC_FLOAT_2_SPEC_VERSION 1 @@ -14587,7 +15589,7 @@ typedef VkPhysicalDeviceTexelBufferAlignmentProperties VkPhysicalDeviceTexelBuff // VK_QCOM_render_pass_transform is a preprocessor guard. Do not pass it to API calls. #define VK_QCOM_render_pass_transform 1 -#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 3 +#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 4 #define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform" typedef struct VkRenderPassTransformBeginInfoQCOM { VkStructureType sType; @@ -14880,6 +15882,98 @@ typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { #define VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" +// VK_NV_cuda_kernel_launch is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cuda_kernel_launch 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaModuleNV) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaFunctionNV) +#define VK_NV_CUDA_KERNEL_LAUNCH_SPEC_VERSION 2 +#define VK_NV_CUDA_KERNEL_LAUNCH_EXTENSION_NAME "VK_NV_cuda_kernel_launch" +typedef struct VkCudaModuleCreateInfoNV { + VkStructureType sType; + const void* pNext; + size_t dataSize; + const void* pData; +} VkCudaModuleCreateInfoNV; + +typedef struct VkCudaFunctionCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkCudaModuleNV module; + const char* pName; +} VkCudaFunctionCreateInfoNV; + +typedef struct VkCudaLaunchInfoNV { + VkStructureType sType; + const void* pNext; + VkCudaFunctionNV function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void* const * pParams; + size_t extraCount; + const void* const * pExtras; +} VkCudaLaunchInfoNV; + +typedef struct VkPhysicalDeviceCudaKernelLaunchFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cudaKernelLaunchFeatures; +} VkPhysicalDeviceCudaKernelLaunchFeaturesNV; + +typedef struct VkPhysicalDeviceCudaKernelLaunchPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t computeCapabilityMinor; + uint32_t computeCapabilityMajor; +} VkPhysicalDeviceCudaKernelLaunchPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateCudaModuleNV)(VkDevice device, const VkCudaModuleCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCudaModuleNV* pModule); +typedef VkResult (VKAPI_PTR *PFN_vkGetCudaModuleCacheNV)(VkDevice device, VkCudaModuleNV module, size_t* pCacheSize, void* pCacheData); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCudaFunctionNV)(VkDevice device, const VkCudaFunctionCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCudaFunctionNV* pFunction); +typedef void (VKAPI_PTR *PFN_vkDestroyCudaModuleNV)(VkDevice device, VkCudaModuleNV module, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDestroyCudaFunctionNV)(VkDevice device, VkCudaFunctionNV function, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdCudaLaunchKernelNV)(VkCommandBuffer commandBuffer, const VkCudaLaunchInfoNV* pLaunchInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCudaModuleNV( + VkDevice device, + const VkCudaModuleCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCudaModuleNV* pModule); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetCudaModuleCacheNV( + VkDevice device, + VkCudaModuleNV module, + size_t* pCacheSize, + void* pCacheData); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCudaFunctionNV( + VkDevice device, + const VkCudaFunctionCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCudaFunctionNV* pFunction); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCudaModuleNV( + VkDevice device, + VkCudaModuleNV module, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCudaFunctionNV( + VkDevice device, + VkCudaFunctionNV function, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkCmdCudaLaunchKernelNV( + VkCommandBuffer commandBuffer, + const VkCudaLaunchInfoNV* pLaunchInfo); +#endif + + // VK_NV_low_latency is a preprocessor guard. Do not pass it to API calls. #define VK_NV_low_latency 1 #define VK_NV_LOW_LATENCY_SPEC_VERSION 1 @@ -15335,7 +16429,7 @@ typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT { // VK_QCOM_rotated_copy_commands is a preprocessor guard. Do not pass it to API calls. #define VK_QCOM_rotated_copy_commands 1 -#define VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION 1 +#define VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION 2 #define VK_QCOM_ROTATED_COPY_COMMANDS_EXTENSION_NAME "VK_QCOM_rotated_copy_commands" typedef struct VkCopyCommandTransformInfoQCOM { VkStructureType sType; @@ -15816,6 +16910,38 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelinePropertiesEXT( #endif +// VK_EXT_frame_boundary is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_frame_boundary 1 +#define VK_EXT_FRAME_BOUNDARY_SPEC_VERSION 1 +#define VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME "VK_EXT_frame_boundary" + +typedef enum VkFrameBoundaryFlagBitsEXT { + VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT = 0x00000001, + VK_FRAME_BOUNDARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkFrameBoundaryFlagBitsEXT; +typedef VkFlags VkFrameBoundaryFlagsEXT; +typedef struct VkPhysicalDeviceFrameBoundaryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 frameBoundary; +} VkPhysicalDeviceFrameBoundaryFeaturesEXT; + +typedef struct VkFrameBoundaryEXT { + VkStructureType sType; + const void* pNext; + VkFrameBoundaryFlagsEXT flags; + uint64_t frameID; + uint32_t imageCount; + const VkImage* pImages; + uint32_t bufferCount; + const VkBuffer* pBuffers; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkFrameBoundaryEXT; + + + // VK_EXT_multisampled_render_to_single_sampled is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_multisampled_render_to_single_sampled 1 #define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_SPEC_VERSION 1 @@ -16317,7 +17443,7 @@ VKAPI_ATTR void VKAPI_CALL vkGetMicromapBuildSizesEXT( // VK_HUAWEI_cluster_culling_shader is a preprocessor guard. Do not pass it to API calls. #define VK_HUAWEI_cluster_culling_shader 1 -#define VK_HUAWEI_CLUSTER_CULLING_SHADER_SPEC_VERSION 2 +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_SPEC_VERSION 3 #define VK_HUAWEI_CLUSTER_CULLING_SHADER_EXTENSION_NAME "VK_HUAWEI_cluster_culling_shader" typedef struct VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI { VkStructureType sType; @@ -16335,6 +17461,12 @@ typedef struct VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI { VkDeviceSize indirectBufferOffsetAlignment; } VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI; +typedef struct VkPhysicalDeviceClusterCullingShaderVrsFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 clusterShadingRate; +} VkPhysicalDeviceClusterCullingShaderVrsFeaturesHUAWEI; + typedef void (VKAPI_PTR *PFN_vkCmdDrawClusterHUAWEI)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); typedef void (VKAPI_PTR *PFN_vkCmdDrawClusterIndirectHUAWEI)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); @@ -16406,6 +17538,36 @@ typedef struct VkPhysicalDeviceShaderCorePropertiesARM { +// VK_ARM_scheduling_controls is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_scheduling_controls 1 +#define VK_ARM_SCHEDULING_CONTROLS_SPEC_VERSION 1 +#define VK_ARM_SCHEDULING_CONTROLS_EXTENSION_NAME "VK_ARM_scheduling_controls" +typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; + +// Flag bits for VkPhysicalDeviceSchedulingControlsFlagBitsARM +typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagBitsARM; +static const VkPhysicalDeviceSchedulingControlsFlagBitsARM VK_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_SHADER_CORE_COUNT_ARM = 0x00000001ULL; + +typedef struct VkDeviceQueueShaderCoreControlCreateInfoARM { + VkStructureType sType; + void* pNext; + uint32_t shaderCoreCount; +} VkDeviceQueueShaderCoreControlCreateInfoARM; + +typedef struct VkPhysicalDeviceSchedulingControlsFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 schedulingControls; +} VkPhysicalDeviceSchedulingControlsFeaturesARM; + +typedef struct VkPhysicalDeviceSchedulingControlsPropertiesARM { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceSchedulingControlsFlagsARM schedulingControlsFlags; +} VkPhysicalDeviceSchedulingControlsPropertiesARM; + + + // VK_EXT_image_sliced_view_of_3d is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_image_sliced_view_of_3d 1 #define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_SPEC_VERSION 1 @@ -16490,6 +17652,45 @@ typedef struct VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT { +// VK_ARM_render_pass_striped is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_render_pass_striped 1 +#define VK_ARM_RENDER_PASS_STRIPED_SPEC_VERSION 1 +#define VK_ARM_RENDER_PASS_STRIPED_EXTENSION_NAME "VK_ARM_render_pass_striped" +typedef struct VkPhysicalDeviceRenderPassStripedFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 renderPassStriped; +} VkPhysicalDeviceRenderPassStripedFeaturesARM; + +typedef struct VkPhysicalDeviceRenderPassStripedPropertiesARM { + VkStructureType sType; + void* pNext; + VkExtent2D renderPassStripeGranularity; + uint32_t maxRenderPassStripes; +} VkPhysicalDeviceRenderPassStripedPropertiesARM; + +typedef struct VkRenderPassStripeInfoARM { + VkStructureType sType; + const void* pNext; + VkRect2D stripeArea; +} VkRenderPassStripeInfoARM; + +typedef struct VkRenderPassStripeBeginInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t stripeInfoCount; + const VkRenderPassStripeInfoARM* pStripeInfos; +} VkRenderPassStripeBeginInfoARM; + +typedef struct VkRenderPassStripeSubmitInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t stripeSemaphoreInfoCount; + const VkSemaphoreSubmitInfo* pStripeSemaphoreInfos; +} VkRenderPassStripeSubmitInfoARM; + + + // VK_QCOM_fragment_density_map_offset is a preprocessor guard. Do not pass it to API calls. #define VK_QCOM_fragment_density_map_offset 1 #define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 1 @@ -16728,6 +17929,26 @@ typedef struct VkPhysicalDeviceImageProcessingPropertiesQCOM { +// VK_EXT_nested_command_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_nested_command_buffer 1 +#define VK_EXT_NESTED_COMMAND_BUFFER_SPEC_VERSION 1 +#define VK_EXT_NESTED_COMMAND_BUFFER_EXTENSION_NAME "VK_EXT_nested_command_buffer" +typedef struct VkPhysicalDeviceNestedCommandBufferFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 nestedCommandBuffer; + VkBool32 nestedCommandBufferRendering; + VkBool32 nestedCommandBufferSimultaneousUse; +} VkPhysicalDeviceNestedCommandBufferFeaturesEXT; + +typedef struct VkPhysicalDeviceNestedCommandBufferPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxCommandBufferNestingLevel; +} VkPhysicalDeviceNestedCommandBufferPropertiesEXT; + + + // VK_EXT_external_memory_acquire_unmodified is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_external_memory_acquire_unmodified 1 #define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_SPEC_VERSION 1 @@ -16803,7 +18024,6 @@ typedef struct VkColorBlendAdvancedEXT { VkBool32 clampResults; } VkColorBlendAdvancedEXT; -typedef void (VKAPI_PTR *PFN_vkCmdSetTessellationDomainOriginEXT)(VkCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin); typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClampEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable); typedef void (VKAPI_PTR *PFN_vkCmdSetPolygonModeEXT)(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode); typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizationSamplesEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples); @@ -16814,6 +18034,7 @@ typedef void (VKAPI_PTR *PFN_vkCmdSetLogicOpEnableEXT)(VkCommandBuffer commandBu typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendEnableEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkBool32* pColorBlendEnables); typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendEquationEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendEquationEXT* pColorBlendEquations); typedef void (VKAPI_PTR *PFN_vkCmdSetColorWriteMaskEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorComponentFlags* pColorWriteMasks); +typedef void (VKAPI_PTR *PFN_vkCmdSetTessellationDomainOriginEXT)(VkCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin); typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizationStreamEXT)(VkCommandBuffer commandBuffer, uint32_t rasterizationStream); typedef void (VKAPI_PTR *PFN_vkCmdSetConservativeRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkConservativeRasterizationModeEXT conservativeRasterizationMode); typedef void (VKAPI_PTR *PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT)(VkCommandBuffer commandBuffer, float extraPrimitiveOverestimationSize); @@ -16836,10 +18057,6 @@ typedef void (VKAPI_PTR *PFN_vkCmdSetRepresentativeFragmentTestEnableNV)(VkComma typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageReductionModeNV)(VkCommandBuffer commandBuffer, VkCoverageReductionModeNV coverageReductionMode); #ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetTessellationDomainOriginEXT( - VkCommandBuffer commandBuffer, - VkTessellationDomainOrigin domainOrigin); - VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthClampEnableEXT( VkCommandBuffer commandBuffer, VkBool32 depthClampEnable); @@ -16887,6 +18104,10 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetColorWriteMaskEXT( uint32_t attachmentCount, const VkColorComponentFlags* pColorWriteMasks); +VKAPI_ATTR void VKAPI_CALL vkCmdSetTessellationDomainOriginEXT( + VkCommandBuffer commandBuffer, + VkTessellationDomainOrigin domainOrigin); + VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizationStreamEXT( VkCommandBuffer commandBuffer, uint32_t rasterizationStream); @@ -17055,7 +18276,7 @@ typedef struct VkDirectDriverLoadingInfoLUNARG { typedef struct VkDirectDriverLoadingListLUNARG { VkStructureType sType; - void* pNext; + const void* pNext; VkDirectDriverLoadingModeLUNARG mode; uint32_t driverCount; const VkDirectDriverLoadingInfoLUNARG* pDrivers; @@ -17482,12 +18703,65 @@ typedef struct VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV { +// VK_NV_extended_sparse_address_space is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_extended_sparse_address_space 1 +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_SPEC_VERSION 1 +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_EXTENSION_NAME "VK_NV_extended_sparse_address_space" +typedef struct VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 extendedSparseAddressSpace; +} VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV; + +typedef struct VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV { + VkStructureType sType; + void* pNext; + VkDeviceSize extendedSparseAddressSpaceSize; + VkImageUsageFlags extendedSparseImageUsageFlags; + VkBufferUsageFlags extendedSparseBufferUsageFlags; +} VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV; + + + // VK_EXT_mutable_descriptor_type is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_mutable_descriptor_type 1 #define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 #define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_EXT_mutable_descriptor_type" +// VK_EXT_layer_settings is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_layer_settings 1 +#define VK_EXT_LAYER_SETTINGS_SPEC_VERSION 2 +#define VK_EXT_LAYER_SETTINGS_EXTENSION_NAME "VK_EXT_layer_settings" + +typedef enum VkLayerSettingTypeEXT { + VK_LAYER_SETTING_TYPE_BOOL32_EXT = 0, + VK_LAYER_SETTING_TYPE_INT32_EXT = 1, + VK_LAYER_SETTING_TYPE_INT64_EXT = 2, + VK_LAYER_SETTING_TYPE_UINT32_EXT = 3, + VK_LAYER_SETTING_TYPE_UINT64_EXT = 4, + VK_LAYER_SETTING_TYPE_FLOAT32_EXT = 5, + VK_LAYER_SETTING_TYPE_FLOAT64_EXT = 6, + VK_LAYER_SETTING_TYPE_STRING_EXT = 7, + VK_LAYER_SETTING_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkLayerSettingTypeEXT; +typedef struct VkLayerSettingEXT { + const char* pLayerName; + const char* pSettingName; + VkLayerSettingTypeEXT type; + uint32_t valueCount; + const void* pValues; +} VkLayerSettingEXT; + +typedef struct VkLayerSettingsCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t settingCount; + const VkLayerSettingEXT* pSettings; +} VkLayerSettingsCreateInfoEXT; + + + // VK_ARM_shader_core_builtins is a preprocessor guard. Do not pass it to API calls. #define VK_ARM_shader_core_builtins 1 #define VK_ARM_SHADER_CORE_BUILTINS_SPEC_VERSION 2 @@ -17532,6 +18806,138 @@ typedef struct VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT { +// VK_NV_low_latency2 is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_low_latency2 1 +#define VK_NV_LOW_LATENCY_2_SPEC_VERSION 2 +#define VK_NV_LOW_LATENCY_2_EXTENSION_NAME "VK_NV_low_latency2" + +typedef enum VkLatencyMarkerNV { + VK_LATENCY_MARKER_SIMULATION_START_NV = 0, + VK_LATENCY_MARKER_SIMULATION_END_NV = 1, + VK_LATENCY_MARKER_RENDERSUBMIT_START_NV = 2, + VK_LATENCY_MARKER_RENDERSUBMIT_END_NV = 3, + VK_LATENCY_MARKER_PRESENT_START_NV = 4, + VK_LATENCY_MARKER_PRESENT_END_NV = 5, + VK_LATENCY_MARKER_INPUT_SAMPLE_NV = 6, + VK_LATENCY_MARKER_TRIGGER_FLASH_NV = 7, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_START_NV = 8, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_END_NV = 9, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_START_NV = 10, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_END_NV = 11, + VK_LATENCY_MARKER_MAX_ENUM_NV = 0x7FFFFFFF +} VkLatencyMarkerNV; + +typedef enum VkOutOfBandQueueTypeNV { + VK_OUT_OF_BAND_QUEUE_TYPE_RENDER_NV = 0, + VK_OUT_OF_BAND_QUEUE_TYPE_PRESENT_NV = 1, + VK_OUT_OF_BAND_QUEUE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkOutOfBandQueueTypeNV; +typedef struct VkLatencySleepModeInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 lowLatencyMode; + VkBool32 lowLatencyBoost; + uint32_t minimumIntervalUs; +} VkLatencySleepModeInfoNV; + +typedef struct VkLatencySleepInfoNV { + VkStructureType sType; + const void* pNext; + VkSemaphore signalSemaphore; + uint64_t value; +} VkLatencySleepInfoNV; + +typedef struct VkSetLatencyMarkerInfoNV { + VkStructureType sType; + const void* pNext; + uint64_t presentID; + VkLatencyMarkerNV marker; +} VkSetLatencyMarkerInfoNV; + +typedef struct VkLatencyTimingsFrameReportNV { + VkStructureType sType; + const void* pNext; + uint64_t presentID; + uint64_t inputSampleTimeUs; + uint64_t simStartTimeUs; + uint64_t simEndTimeUs; + uint64_t renderSubmitStartTimeUs; + uint64_t renderSubmitEndTimeUs; + uint64_t presentStartTimeUs; + uint64_t presentEndTimeUs; + uint64_t driverStartTimeUs; + uint64_t driverEndTimeUs; + uint64_t osRenderQueueStartTimeUs; + uint64_t osRenderQueueEndTimeUs; + uint64_t gpuRenderStartTimeUs; + uint64_t gpuRenderEndTimeUs; +} VkLatencyTimingsFrameReportNV; + +typedef struct VkGetLatencyMarkerInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t timingCount; + VkLatencyTimingsFrameReportNV* pTimings; +} VkGetLatencyMarkerInfoNV; + +typedef struct VkLatencySubmissionPresentIdNV { + VkStructureType sType; + const void* pNext; + uint64_t presentID; +} VkLatencySubmissionPresentIdNV; + +typedef struct VkSwapchainLatencyCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 latencyModeEnable; +} VkSwapchainLatencyCreateInfoNV; + +typedef struct VkOutOfBandQueueTypeInfoNV { + VkStructureType sType; + const void* pNext; + VkOutOfBandQueueTypeNV queueType; +} VkOutOfBandQueueTypeInfoNV; + +typedef struct VkLatencySurfaceCapabilitiesNV { + VkStructureType sType; + const void* pNext; + uint32_t presentModeCount; + VkPresentModeKHR* pPresentModes; +} VkLatencySurfaceCapabilitiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkSetLatencySleepModeNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV* pSleepModeInfo); +typedef VkResult (VKAPI_PTR *PFN_vkLatencySleepNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV* pSleepInfo); +typedef void (VKAPI_PTR *PFN_vkSetLatencyMarkerNV)(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV* pLatencyMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkGetLatencyTimingsNV)(VkDevice device, VkSwapchainKHR swapchain, VkGetLatencyMarkerInfoNV* pLatencyMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkQueueNotifyOutOfBandNV)(VkQueue queue, const VkOutOfBandQueueTypeInfoNV* pQueueTypeInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetLatencySleepModeNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkLatencySleepModeInfoNV* pSleepModeInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkLatencySleepNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkLatencySleepInfoNV* pSleepInfo); + +VKAPI_ATTR void VKAPI_CALL vkSetLatencyMarkerNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkSetLatencyMarkerInfoNV* pLatencyMarkerInfo); + +VKAPI_ATTR void VKAPI_CALL vkGetLatencyTimingsNV( + VkDevice device, + VkSwapchainKHR swapchain, + VkGetLatencyMarkerInfoNV* pLatencyMarkerInfo); + +VKAPI_ATTR void VKAPI_CALL vkQueueNotifyOutOfBandNV( + VkQueue queue, + const VkOutOfBandQueueTypeInfoNV* pQueueTypeInfo); +#endif + + // VK_QCOM_multiview_per_view_render_areas is a preprocessor guard. Do not pass it to API calls. #define VK_QCOM_multiview_per_view_render_areas 1 #define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_SPEC_VERSION 1 @@ -17551,6 +18957,113 @@ typedef struct VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM { +// VK_NV_per_stage_descriptor_set is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_per_stage_descriptor_set 1 +#define VK_NV_PER_STAGE_DESCRIPTOR_SET_SPEC_VERSION 1 +#define VK_NV_PER_STAGE_DESCRIPTOR_SET_EXTENSION_NAME "VK_NV_per_stage_descriptor_set" +typedef struct VkPhysicalDevicePerStageDescriptorSetFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 perStageDescriptorSet; + VkBool32 dynamicPipelineLayout; +} VkPhysicalDevicePerStageDescriptorSetFeaturesNV; + + + +// VK_QCOM_image_processing2 is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_image_processing2 1 +#define VK_QCOM_IMAGE_PROCESSING_2_SPEC_VERSION 1 +#define VK_QCOM_IMAGE_PROCESSING_2_EXTENSION_NAME "VK_QCOM_image_processing2" + +typedef enum VkBlockMatchWindowCompareModeQCOM { + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MIN_QCOM = 0, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_QCOM = 1, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkBlockMatchWindowCompareModeQCOM; +typedef struct VkPhysicalDeviceImageProcessing2FeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 textureBlockMatch2; +} VkPhysicalDeviceImageProcessing2FeaturesQCOM; + +typedef struct VkPhysicalDeviceImageProcessing2PropertiesQCOM { + VkStructureType sType; + void* pNext; + VkExtent2D maxBlockMatchWindow; +} VkPhysicalDeviceImageProcessing2PropertiesQCOM; + +typedef struct VkSamplerBlockMatchWindowCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkExtent2D windowExtent; + VkBlockMatchWindowCompareModeQCOM windowCompareMode; +} VkSamplerBlockMatchWindowCreateInfoQCOM; + + + +// VK_QCOM_filter_cubic_weights is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_filter_cubic_weights 1 +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_SPEC_VERSION 1 +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_EXTENSION_NAME "VK_QCOM_filter_cubic_weights" + +typedef enum VkCubicFilterWeightsQCOM { + VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM = 0, + VK_CUBIC_FILTER_WEIGHTS_ZERO_TANGENT_CARDINAL_QCOM = 1, + VK_CUBIC_FILTER_WEIGHTS_B_SPLINE_QCOM = 2, + VK_CUBIC_FILTER_WEIGHTS_MITCHELL_NETRAVALI_QCOM = 3, + VK_CUBIC_FILTER_WEIGHTS_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkCubicFilterWeightsQCOM; +typedef struct VkPhysicalDeviceCubicWeightsFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 selectableCubicWeights; +} VkPhysicalDeviceCubicWeightsFeaturesQCOM; + +typedef struct VkSamplerCubicWeightsCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkSamplerCubicWeightsCreateInfoQCOM; + +typedef struct VkBlitImageCubicWeightsInfoQCOM { + VkStructureType sType; + const void* pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkBlitImageCubicWeightsInfoQCOM; + + + +// VK_QCOM_ycbcr_degamma is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_ycbcr_degamma 1 +#define VK_QCOM_YCBCR_DEGAMMA_SPEC_VERSION 1 +#define VK_QCOM_YCBCR_DEGAMMA_EXTENSION_NAME "VK_QCOM_ycbcr_degamma" +typedef struct VkPhysicalDeviceYcbcrDegammaFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 ycbcrDegamma; +} VkPhysicalDeviceYcbcrDegammaFeaturesQCOM; + +typedef struct VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM { + VkStructureType sType; + void* pNext; + VkBool32 enableYDegamma; + VkBool32 enableCbCrDegamma; +} VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM; + + + +// VK_QCOM_filter_cubic_clamp is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_filter_cubic_clamp 1 +#define VK_QCOM_FILTER_CUBIC_CLAMP_SPEC_VERSION 1 +#define VK_QCOM_FILTER_CUBIC_CLAMP_EXTENSION_NAME "VK_QCOM_filter_cubic_clamp" +typedef struct VkPhysicalDeviceCubicClampFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 cubicRangeClamp; +} VkPhysicalDeviceCubicClampFeaturesQCOM; + + + // VK_EXT_attachment_feedback_loop_dynamic_state is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_attachment_feedback_loop_dynamic_state 1 #define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_SPEC_VERSION 1 @@ -17570,6 +19083,48 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetAttachmentFeedbackLoopEnableEXT( #endif +// VK_MSFT_layered_driver is a preprocessor guard. Do not pass it to API calls. +#define VK_MSFT_layered_driver 1 +#define VK_MSFT_LAYERED_DRIVER_SPEC_VERSION 1 +#define VK_MSFT_LAYERED_DRIVER_EXTENSION_NAME "VK_MSFT_layered_driver" + +typedef enum VkLayeredDriverUnderlyingApiMSFT { + VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT = 0, + VK_LAYERED_DRIVER_UNDERLYING_API_D3D12_MSFT = 1, + VK_LAYERED_DRIVER_UNDERLYING_API_MAX_ENUM_MSFT = 0x7FFFFFFF +} VkLayeredDriverUnderlyingApiMSFT; +typedef struct VkPhysicalDeviceLayeredDriverPropertiesMSFT { + VkStructureType sType; + void* pNext; + VkLayeredDriverUnderlyingApiMSFT underlyingAPI; +} VkPhysicalDeviceLayeredDriverPropertiesMSFT; + + + +// VK_NV_descriptor_pool_overallocation is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_descriptor_pool_overallocation 1 +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_SPEC_VERSION 1 +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME "VK_NV_descriptor_pool_overallocation" +typedef struct VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 descriptorPoolOverallocation; +} VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV; + + + +// VK_NV_shader_atomic_float16_vector is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shader_atomic_float16_vector 1 +#define VK_NV_SHADER_ATOMIC_FLOAT16_VECTOR_SPEC_VERSION 1 +#define VK_NV_SHADER_ATOMIC_FLOAT16_VECTOR_EXTENSION_NAME "VK_NV_shader_atomic_float16_vector" +typedef struct VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16VectorAtomics; +} VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV; + + + // VK_KHR_acceleration_structure is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_acceleration_structure 1 #define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 13 diff --git a/ext/vulkan/vulkan_directfb.h b/ext/vulkan/vulkan_directfb.h index 1f11a08273..f06f80b70e 100644 --- a/ext/vulkan/vulkan_directfb.h +++ b/ext/vulkan/vulkan_directfb.h @@ -2,7 +2,7 @@ #define VULKAN_DIRECTFB_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_fuchsia.h b/ext/vulkan/vulkan_fuchsia.h index 76e1564832..f60907d10b 100644 --- a/ext/vulkan/vulkan_fuchsia.h +++ b/ext/vulkan/vulkan_fuchsia.h @@ -2,7 +2,7 @@ #define VULKAN_FUCHSIA_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_ggp.h b/ext/vulkan/vulkan_ggp.h index 9783aa3b38..0a8863a14b 100644 --- a/ext/vulkan/vulkan_ggp.h +++ b/ext/vulkan/vulkan_ggp.h @@ -2,7 +2,7 @@ #define VULKAN_GGP_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_ios.h b/ext/vulkan/vulkan_ios.h index 211429ff45..22ed2c039a 100644 --- a/ext/vulkan/vulkan_ios.h +++ b/ext/vulkan/vulkan_ios.h @@ -2,7 +2,7 @@ #define VULKAN_IOS_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_macos.h b/ext/vulkan/vulkan_macos.h index c6509cc8cf..a7f5613a05 100644 --- a/ext/vulkan/vulkan_macos.h +++ b/ext/vulkan/vulkan_macos.h @@ -2,7 +2,7 @@ #define VULKAN_MACOS_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_metal.h b/ext/vulkan/vulkan_metal.h index 94563a003a..e6f7bf7a70 100644 --- a/ext/vulkan/vulkan_metal.h +++ b/ext/vulkan/vulkan_metal.h @@ -2,7 +2,7 @@ #define VULKAN_METAL_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_screen.h b/ext/vulkan/vulkan_screen.h index 981738f738..7e84d4d965 100644 --- a/ext/vulkan/vulkan_screen.h +++ b/ext/vulkan/vulkan_screen.h @@ -2,7 +2,7 @@ #define VULKAN_SCREEN_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_vi.h b/ext/vulkan/vulkan_vi.h index c9227e8226..c145f4a800 100644 --- a/ext/vulkan/vulkan_vi.h +++ b/ext/vulkan/vulkan_vi.h @@ -2,7 +2,7 @@ #define VULKAN_VI_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_wayland.h b/ext/vulkan/vulkan_wayland.h index c93b217872..ec706a114b 100644 --- a/ext/vulkan/vulkan_wayland.h +++ b/ext/vulkan/vulkan_wayland.h @@ -2,7 +2,7 @@ #define VULKAN_WAYLAND_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_win32.h b/ext/vulkan/vulkan_win32.h index fae3b8532c..d7a0b2bab4 100644 --- a/ext/vulkan/vulkan_win32.h +++ b/ext/vulkan/vulkan_win32.h @@ -2,7 +2,7 @@ #define VULKAN_WIN32_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_xcb.h b/ext/vulkan/vulkan_xcb.h index de7405524a..cdf6b5269f 100644 --- a/ext/vulkan/vulkan_xcb.h +++ b/ext/vulkan/vulkan_xcb.h @@ -2,7 +2,7 @@ #define VULKAN_XCB_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_xlib.h b/ext/vulkan/vulkan_xlib.h index 1aa632f2ef..b3c3e27d77 100644 --- a/ext/vulkan/vulkan_xlib.h +++ b/ext/vulkan/vulkan_xlib.h @@ -2,7 +2,7 @@ #define VULKAN_XLIB_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/vulkan/vulkan_xlib_xrandr.h b/ext/vulkan/vulkan_xlib_xrandr.h index e164ffc91e..8e99190b4f 100644 --- a/ext/vulkan/vulkan_xlib_xrandr.h +++ b/ext/vulkan/vulkan_xlib_xrandr.h @@ -2,7 +2,7 @@ #define VULKAN_XLIB_XRANDR_H_ 1 /* -** Copyright 2015-2023 The Khronos Group Inc. +** Copyright 2015-2024 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ diff --git a/ext/zlib/gzlib.c b/ext/zlib/gzlib.c index fae202ef89..04093e0a80 100644 --- a/ext/zlib/gzlib.c +++ b/ext/zlib/gzlib.c @@ -5,6 +5,10 @@ #include "gzguts.h" +#ifndef _WIN32 +#include +#endif + #if defined(_WIN32) && !defined(__BORLANDC__) # define LSEEK _lseeki64 #else diff --git a/ext/zlib/gzread.c b/ext/zlib/gzread.c index d65c0b8293..808215f65e 100644 --- a/ext/zlib/gzread.c +++ b/ext/zlib/gzread.c @@ -5,6 +5,10 @@ #include "gzguts.h" +#ifndef _WIN32 +#include +#endif + /* Local functions */ local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); local int gz_avail OF((gz_statep)); diff --git a/ext/zlib/gzwrite.c b/ext/zlib/gzwrite.c index aa767fbf63..e805c04a80 100644 --- a/ext/zlib/gzwrite.c +++ b/ext/zlib/gzwrite.c @@ -5,6 +5,10 @@ #include "gzguts.h" +#ifndef _WIN32 +#include +#endif + /* Local functions */ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); diff --git a/ext/zstd b/ext/zstd index 63779c7982..794ea1b0af 160000 --- a/ext/zstd +++ b/ext/zstd @@ -1 +1 @@ -Subproject commit 63779c798237346c2b245c546c40b72a5a5913fe +Subproject commit 794ea1b0afca0f020f4e57b6732332231fb23c70 diff --git a/ext/zstd-build/CMakeLists.txt b/ext/zstd-build/CMakeLists.txt new file mode 100644 index 0000000000..c295da5461 --- /dev/null +++ b/ext/zstd-build/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required (VERSION 3.2.0) +project (libzstd_static) + +set(SRC_DIR ../zstd/lib) +message(${SRC_DIR}) + +set(ALL_SOURCE_FILES + ${SRC_DIR}/common/debug.c + ${SRC_DIR}/common/entropy_common.c + ${SRC_DIR}/common/error_private.c + ${SRC_DIR}/common/fse_decompress.c + ${SRC_DIR}/common/pool.c + ${SRC_DIR}/common/threading.c + ${SRC_DIR}/common/xxhash.c + ${SRC_DIR}/common/zstd_common.c + ${SRC_DIR}/compress/fse_compress.c + ${SRC_DIR}/compress/hist.c + ${SRC_DIR}/compress/huf_compress.c + ${SRC_DIR}/compress/zstd_compress.c + ${SRC_DIR}/compress/zstd_compress_literals.c + ${SRC_DIR}/compress/zstd_compress_sequences.c + ${SRC_DIR}/compress/zstd_compress_superblock.c + ${SRC_DIR}/compress/zstd_double_fast.c + ${SRC_DIR}/compress/zstd_fast.c + ${SRC_DIR}/compress/zstd_lazy.c + ${SRC_DIR}/compress/zstd_ldm.c + ${SRC_DIR}/compress/zstd_opt.c + ${SRC_DIR}/compress/zstdmt_compress.c + ${SRC_DIR}/decompress/huf_decompress.c + ${SRC_DIR}/decompress/zstd_ddict.c + ${SRC_DIR}/decompress/zstd_decompress.c + ${SRC_DIR}/decompress/zstd_decompress_block.c + ${SRC_DIR}/dictBuilder/cover.c + ${SRC_DIR}/dictBuilder/divsufsort.c + ${SRC_DIR}/dictBuilder/fastcover.c + ${SRC_DIR}/dictBuilder/zdict.c +) + +if (MSVC) + add_compile_options(-DZSTD_DISABLE_ASM) +else () + if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|AMD64.*|x86_64.*|X86_64.*") + set(ALL_SOURCE_FILES ${ALL_SOURCE_FILES} ${SRC_DIR}/decompress/huf_decompress_amd64.S) + else() + add_compile_options(-DZSTD_DISABLE_ASM) + endif() +endif () + +add_library(libzstd_static STATIC ${ALL_SOURCE_FILES}) + +target_include_directories(libzstd_static PUBLIC ../zstd/lib) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 71ed9af82b..1285ff4bb4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,6 +3,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip android.useAndroidX=true android.enableJetifier=true diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 815d1d622e..59be04616f 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -40,8 +40,8 @@ #include "Core/HLE/sceUtility.h" #include "Core/SaveState.h" #include "GPU/Common/FramebufferManagerCommon.h" -#include "Log.h" -#include "LogManager.h" +#include "Common/Log.h" +#include "Common/Log/LogManager.h" #include "Compare.h" #include "HeadlessHost.h" @@ -99,7 +99,7 @@ void NativeResized() { } std::string System_GetProperty(SystemProperty prop) { return ""; } std::vector System_GetPropertyStringVec(SystemProperty prop) { return std::vector(); } -int System_GetPropertyInt(SystemProperty prop) { +int64_t System_GetPropertyInt(SystemProperty prop) { if (prop == SYSPROP_SYSTEMVERSION) return 31; return -1; @@ -117,7 +117,7 @@ bool System_GetPropertyBool(SystemProperty prop) { } void System_Notify(SystemNotification notification) {} void System_PostUIMessage(UIMessage message, const std::string ¶m) {} -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { switch (type) { case SystemRequestType::SEND_DEBUG_OUTPUT: if (g_headlessHost) { @@ -318,8 +318,9 @@ std::vector ReadFromListFile(const std::string &listFilename) { int main(int argc, const char* argv[]) { PROFILE_INIT(); + TimeInit(); #if PPSSPP_PLATFORM(WINDOWS) - timeBeginPeriod(1); + SetCleanExitOnAssert(); #else // Ignore sigpipe. if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { @@ -338,6 +339,7 @@ int main(int argc, const char* argv[]) GPUCore gpuCore = GPUCORE_SOFTWARE; CPUCore cpuCore = CPUCore::JIT; int debuggerPort = -1; + bool newAtrac = false; std::vector testFilenames; const char *mountIso = nullptr; @@ -374,6 +376,8 @@ int main(int argc, const char* argv[]) testOptions.bench = true; else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) testOptions.verbose = true; + else if (!strcmp(argv[i], "--new-atrac")) + newAtrac = true; else if (!strncmp(argv[i], "--graphics=", strlen("--graphics=")) && strlen(argv[i]) > strlen("--graphics=")) { const char *gpuName = argv[i] + strlen("--graphics="); @@ -427,8 +431,8 @@ int main(int argc, const char* argv[]) PrintfLogger *printfLogger = new PrintfLogger(); - for (int i = 0; i < (int)LogType::NUMBER_OF_LOGS; i++) { - LogType type = (LogType)i; + for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) { + Log type = (Log)i; logman->SetEnabled(type, fullLog); logman->SetLogLevel(type, LogLevel::LDEBUG); } @@ -497,6 +501,7 @@ int main(int argc, const char* argv[]) g_Config.iGlobalVolume = VOLUME_FULL; g_Config.iReverbVolume = VOLUME_FULL; g_Config.internalDataDirectory.clear(); + g_Config.bUseNewAtrac = newAtrac; Path exePath = File::GetExeDirectory(); g_Config.flash0Directory = exePath / "assets/flash0"; diff --git a/headless/headless.txt b/headless/headless.txt index ddc43e4cfc..194a14ca98 100644 --- a/headless/headless.txt +++ b/headless/headless.txt @@ -1,7 +1,6 @@ -Plan: +TODO: This documentation is outdated and needs updating. - -This is intended to be a port that does not have graphics, it just starts up the system without a display, prints all debug output (as configured) to the console using printf(), and exits when the emulated binary exits. +This is a build of PPSSPP that does not have graphics, it just starts up the system without a display, prints all debug output (as configured) to the console using printf(), and exits when the emulated binary exits. Usage: diff --git a/ios/AppDelegate.h b/ios/AppDelegate.h index feb65efbf4..06ab74d32a 100644 --- a/ios/AppDelegate.h +++ b/ios/AppDelegate.h @@ -2,13 +2,16 @@ #import -@class ViewController; +@protocol PPSSPPViewController; @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UIScreen *screen; -@property (strong, nonatomic) ViewController *viewController; +@property (strong, nonatomic) id viewController; + +- (void)restart:(const char *)args; +- (BOOL)launchPPSSPP:(int)argc argv:(char**)argv; @end diff --git a/ios/AppDelegate.mm b/ios/AppDelegate.mm index 5308edfeb2..1d348ab568 100644 --- a/ios/AppDelegate.mm +++ b/ios/AppDelegate.mm @@ -1,5 +1,7 @@ #import "AppDelegate.h" +#import "ViewControllerCommon.h" #import "ViewController.h" +#import "ViewControllerMetal.h" #import "iOSCoreAudio.h" #import "Common/System/System.h" #import "Common/System/NativeApp.h" @@ -25,14 +27,14 @@ switch ([interruptionType unsignedIntegerValue]) { case AVAudioSessionInterruptionTypeBegan: - INFO_LOG(SYSTEM, "ios audio session interruption beginning"); + INFO_LOG(Log::System, "ios audio session interruption beginning"); if (g_Config.bEnableSound) { iOSCoreAudioShutdown(); } break; case AVAudioSessionInterruptionTypeEnded: - INFO_LOG(SYSTEM, "ios audio session interruption ending"); + INFO_LOG(Log::System, "ios audio session interruption ending"); if (g_Config.bEnableSound) { /* * Only try to reinit audio if in the foreground, otherwise @@ -54,7 +56,7 @@ // Registered in application:didFinishLaunchingWithOptions: // for AVAudioSessionMediaServicesWereResetNotification -(void) handleMediaServicesWereReset:(NSNotification *)notification { - INFO_LOG(SYSTEM, "ios media services were reset - reinitializing audio"); + INFO_LOG(Log::System, "ios media services were reset - reinitializing audio"); /* When media services were reset, Apple recommends: @@ -74,10 +76,9 @@ } -(BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - int argc = 1; - char *argv[3] = { 0 }; - NSURL* nsUrl = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]; + char *argv[5]{}; + NSURL *nsUrl = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]; if (nsUrl != nullptr && nsUrl.isFileURL) { NSString *nsString = nsUrl.path; @@ -85,29 +86,66 @@ argv[argc++] = (char*)string; } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioSessionInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMediaServicesWereReset:) name:AVAudioSessionMediaServicesWereResetNotification object:nil]; + + return [self launchPPSSPP:argc argv:argv]; +} + +- (BOOL)launchPPSSPP:(int)argc argv:(char**)argv; +{ NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/assets/"]; NativeInit(argc, (const char**)argv, documentsPath.UTF8String, bundlePath.UTF8String, NULL); - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - self.viewController = [[ViewController alloc] init]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioSessionInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; + // Choose viewcontroller depending on backend. + if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { + PPSSPPViewControllerMetal *vc = [[PPSSPPViewControllerMetal alloc] init]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMediaServicesWereReset:) name:AVAudioSessionMediaServicesWereResetNotification object:nil]; + self.viewController = vc; + self.window.rootViewController = vc; + + } else { + PPSSPPViewControllerGL *vc = [[PPSSPPViewControllerGL alloc] init]; + // Here we can switch viewcontroller depending on backend. + self.viewController = vc; + self.window.rootViewController = vc; + } - self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } --(void) dealloc { +- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } --(void) applicationWillResignActive:(UIApplication *)application { +- (void)restart:(const char*)restartArgs { + INFO_LOG(Log::G3D, "Restart requested: %s", restartArgs); + [self.viewController willResignActive]; + [self.viewController shutdown]; + self.window.rootViewController = nil; + self.viewController = nil; + + // App was requested to restart, probably. + INFO_LOG(Log::G3D, "viewController nilled"); + + NativeShutdown(); + + // TODO: Ignoring the command line for now. + // Hoping that overwriting the viewController works as expected... + [self launchPPSSPP:0 argv:nullptr]; + [self.viewController didBecomeActive]; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + INFO_LOG(Log::G3D, "willResignActive"); + + [self.viewController willResignActive]; + if (g_Config.bEnableSound) { iOSCoreAudioShutdown(); } @@ -115,16 +153,19 @@ System_PostUIMessage(UIMessage::LOST_FOCUS); } --(void) applicationDidBecomeActive:(UIApplication *)application { +- (void)applicationDidBecomeActive:(UIApplication *)application { + INFO_LOG(Log::G3D, "didBecomeActive"); if (g_Config.bEnableSound) { iOSCoreAudioInit(); } System_PostUIMessage(UIMessage::GOT_FOCUS); + [self.viewController didBecomeActive]; } - (void)applicationWillTerminate:(UIApplication *)application { - exit(0); + // Seems like a bad idea. + // exit(0); } @end diff --git a/ios/CameraHelper.h b/ios/CameraHelper.h index 45de67d5d9..4690a5ff5f 100644 --- a/ios/CameraHelper.h +++ b/ios/CameraHelper.h @@ -10,8 +10,7 @@ @property (nonatomic, strong) id delegate; -- (void) setCameraSize:(int)width h:(int)height; -- (void) startVideo; +- (void) startVideo:(int)width h:(int)height; - (void) stopVideo; @end diff --git a/ios/CameraHelper.mm b/ios/CameraHelper.mm index 86dc9f1aec..ffdb282365 100644 --- a/ios/CameraHelper.mm +++ b/ios/CameraHelper.mm @@ -37,7 +37,7 @@ NSString *getSelectedCamera() { if (granted) { NSLog(@"camera permission granted"); dispatch_async(dispatch_get_main_queue(), ^{ - [self startVideo]; + [self startVideo:mWidth h:mHeight]; }); } else { NSLog(@"camera permission denied"); @@ -56,14 +56,10 @@ NSString *getSelectedCamera() { } } --(void) setCameraSize: (int)width h:(int)height { - NSLog(@"CameraHelper::setCameraSize %dx%d", width, height); +-(void) startVideo: (int)width h:(int)height { + NSLog(@"CameraHelper::startVideo %dx%d", width, height); mWidth = width; mHeight = height; -} - --(void) startVideo { - NSLog(@"CameraHelper::startVideo"); if ([self checkPermission]) { return; } diff --git a/ios/Controls.h b/ios/Controls.h new file mode 100644 index 0000000000..1e48ce1b61 --- /dev/null +++ b/ios/Controls.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#import +#import + +#include "iCade/iCadeState.h" +#include "Common/Input/InputState.h" + +// Code extracted from ViewController.mm, in order to modularize +// and share it between multiple view controllers. + +bool InitController(GCController *controller); +void ShutdownController(GCController *controller); + +struct TouchTracker { +public: + void Began(NSSet *touches, UIView *view); + void Moved(NSSet *touches, UIView *view); + void Ended(NSSet *touches, UIView *view); + void Cancelled(NSSet *touches, UIView *view); +private: + void SendTouchEvent(float x, float y, int code, int pointerId); + int ToTouchID(UITouch *uiTouch, bool allowAllocate); + UITouch *touches_[10]{}; +}; + +// Can probably get rid of this, but let's keep it for now. +struct ICadeTracker { +public: + void ButtonDown(iCadeState button); + void ButtonUp(iCadeState button); + void InitKeyMap(); +private: + bool simulateAnalog = false; + bool iCadeConnectNotified = false; + + std::map iCadeToKeyMap; + + double lastSelectPress = 0.0f; + double lastStartPress = 0.0f; +}; + +void ProcessAccelerometerData(CMAccelerometerData *accData); +InputKeyCode HIDUsageToInputKeyCode(UIKeyboardHIDUsage usage); + +void KeyboardPressesBegan(NSSet *presses, UIPressesEvent *event); +void KeyboardPressesEnded(NSSet *presses, UIPressesEvent *event); +void SendKeyboardChars(std::string_view str); \ No newline at end of file diff --git a/ios/Controls.mm b/ios/Controls.mm new file mode 100644 index 0000000000..6683a00781 --- /dev/null +++ b/ios/Controls.mm @@ -0,0 +1,547 @@ +#include "Controls.h" + +#include "Common/Data/Encoding/Utf8.h" +#include "Common/Log.h" +#include "Common/TimeUtil.h" +#include "Common/Input/InputState.h" +#include "Common/System/NativeApp.h" +#include "Common/System/Display.h" +#include "Core/KeyMap.h" + +static void controllerButtonPressed(BOOL pressed, InputKeyCode keyCode) { + KeyInput key; + key.deviceId = DEVICE_ID_PAD_0; + key.flags = pressed ? KEY_DOWN : KEY_UP; + key.keyCode = keyCode; + NativeKey(key); +} + +static void analogTriggerPressed(InputAxis axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = axis; + axisInput.value = value; + NativeAxis(&axisInput, 1); +} + +bool InitController(GCController *controller) { + GCExtendedGamepad *extendedProfile = controller.extendedGamepad; + if (extendedProfile == nil) { + return false; + } + + if (@available(iOS 14.0, tvOS 14.0, *)) { + for (GCControllerElement* element in controller.physicalInputProfile.allElements) { + element.preferredSystemGestureState = GCSystemGestureStateDisabled; + } + } + + extendedProfile.buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_2); // Cross + }; + + extendedProfile.buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_3); // Circle + }; + + extendedProfile.buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_4); // Square + }; + + extendedProfile.buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_1); // Triangle + }; + + extendedProfile.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_L1); // LTrigger + }; + + extendedProfile.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_R1); // RTrigger + }; + + extendedProfile.dpad.up.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_DPAD_UP); + }; + + extendedProfile.dpad.down.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_DPAD_DOWN); + }; + + extendedProfile.dpad.left.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_DPAD_LEFT); + }; + + extendedProfile.dpad.right.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_DPAD_RIGHT); + }; + + extendedProfile.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + INFO_LOG(Log::System, "ltrigger: %f %d", value, (int)pressed); + analogTriggerPressed(JOYSTICK_AXIS_LTRIGGER, value); + }; + + extendedProfile.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + INFO_LOG(Log::System, "rtrigger: %f %d", value, (int)pressed); + analogTriggerPressed(JOYSTICK_AXIS_RTRIGGER, value); + }; + +#if defined(__IPHONE_12_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_1 + if ([extendedProfile respondsToSelector:@selector(leftThumbstickButton)] && extendedProfile.leftThumbstickButton != nil) { + extendedProfile.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_THUMBL); + }; + } + if ([extendedProfile respondsToSelector:@selector(rightThumbstickButton)] && extendedProfile.rightThumbstickButton != nil) { + extendedProfile.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_THUMBR); + }; + } +#endif +#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 + if ([extendedProfile respondsToSelector:@selector(buttonOptions)] && extendedProfile.buttonOptions != nil) { + extendedProfile.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_SELECT); + }; + } + if ([extendedProfile respondsToSelector:@selector(buttonMenu)] && extendedProfile.buttonMenu != nil) { + extendedProfile.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_START); + }; + } +#endif +#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 + if ([extendedProfile respondsToSelector:@selector(buttonHome)] && extendedProfile.buttonHome != nil) { + extendedProfile.buttonHome.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_HOME); + }; + } +#endif + + extendedProfile.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = JOYSTICK_AXIS_X; + axisInput.value = value; + NativeAxis(&axisInput, 1); + }; + + extendedProfile.leftThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = JOYSTICK_AXIS_Y; + axisInput.value = -value; + NativeAxis(&axisInput, 1); + }; + + // Map right thumbstick as another analog stick, particularly useful for controllers + // like the DualShock 3/4 when connected to an iOS device + extendedProfile.rightThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = JOYSTICK_AXIS_Z; + axisInput.value = value; + NativeAxis(&axisInput, 1); + }; + + extendedProfile.rightThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = JOYSTICK_AXIS_RZ; + axisInput.value = -value; + NativeAxis(&axisInput, 1); + }; + + return true; +} + +void ShutdownController(GCController *controller) { + if (@available(iOS 14.0, tvOS 14.0, *)) { + for (GCControllerElement* element in controller.physicalInputProfile.allElements) { + element.preferredSystemGestureState = GCSystemGestureStateEnabled; + } + } +} + +void TouchTracker::SendTouchEvent(float x, float y, int code, int pointerId) { + float scale = [UIScreen mainScreen].scale; + if ([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)]) { + scale = [UIScreen mainScreen].nativeScale; + } + + float dp_xscale = (float)g_display.dp_xres / (float)g_display.pixel_xres; + float dp_yscale = (float)g_display.dp_yres / (float)g_display.pixel_yres; + + float scaledX = (int)(x * dp_xscale) * scale; + float scaledY = (int)(y * dp_yscale) * scale; + + TouchInput input; + input.x = scaledX; + input.y = scaledY; + switch (code) { + case 1: input.flags = TOUCH_DOWN; break; + case 2: input.flags = TOUCH_UP; break; + default: input.flags = TOUCH_MOVE; break; + } + input.id = pointerId; + NativeTouch(input); +} + +int TouchTracker::ToTouchID(UITouch *uiTouch, bool allowAllocate) { + // Find the id for the touch. + for (int localId = 0; localId < (int)ARRAY_SIZE(touches_); ++localId) { + if (touches_[localId] == uiTouch) { + return localId; + } + } + + // Allocate a new one, perhaps? + if (allowAllocate) { + for (int localId = 0; localId < (int)ARRAY_SIZE(touches_); ++localId) { + if (touches_[localId] == 0) { + touches_[localId] = uiTouch; + return localId; + } + } + + // None were free. Ignore? + return 0; + } + + return -1; +} + +void TouchTracker::Began(NSSet *touches, UIView *view) { + for (UITouch* touch in touches) { + CGPoint point = [touch locationInView:view]; + int touchId = ToTouchID(touch, true); + SendTouchEvent(point.x, point.y, 1, touchId); + } +} + +void TouchTracker::Moved(NSSet *touches, UIView *view) { + for (UITouch* touch in touches) { + CGPoint point = [touch locationInView:view]; + int touchId = ToTouchID(touch, true); + SendTouchEvent(point.x, point.y, 0, touchId); + } +} + +void TouchTracker::Ended(NSSet *touches, UIView *view) { + for (UITouch* touch in touches) { + CGPoint point = [touch locationInView:view]; + int touchId = ToTouchID(touch, false); + if (touchId >= 0) { + SendTouchEvent(point.x, point.y, 2, touchId); + touches_[touchId] = nullptr; + } + } +} + +void TouchTracker::Cancelled(NSSet *touches, UIView *view) { + for (UITouch* touch in touches) { + CGPoint point = [touch locationInView:view]; + int touchId = ToTouchID(touch, false); + if (touchId >= 0) { + SendTouchEvent(point.x, point.y, 2, touchId); + touches_[touchId] = nullptr; + } + } +} + +void ICadeTracker::InitKeyMap() { + iCadeToKeyMap[iCadeJoystickUp] = NKCODE_DPAD_UP; + iCadeToKeyMap[iCadeJoystickRight] = NKCODE_DPAD_RIGHT; + iCadeToKeyMap[iCadeJoystickDown] = NKCODE_DPAD_DOWN; + iCadeToKeyMap[iCadeJoystickLeft] = NKCODE_DPAD_LEFT; + iCadeToKeyMap[iCadeButtonA] = NKCODE_BUTTON_9; // Select + iCadeToKeyMap[iCadeButtonB] = NKCODE_BUTTON_7; // LTrigger + iCadeToKeyMap[iCadeButtonC] = NKCODE_BUTTON_10; // Start + iCadeToKeyMap[iCadeButtonD] = NKCODE_BUTTON_8; // RTrigger + iCadeToKeyMap[iCadeButtonE] = NKCODE_BUTTON_4; // Square + iCadeToKeyMap[iCadeButtonF] = NKCODE_BUTTON_2; // Cross + iCadeToKeyMap[iCadeButtonG] = NKCODE_BUTTON_1; // Triangle + iCadeToKeyMap[iCadeButtonH] = NKCODE_BUTTON_3; // Circle +} + +void ICadeTracker::ButtonDown(iCadeState button) { + if (simulateAnalog && + ((button == iCadeJoystickUp) || + (button == iCadeJoystickDown) || + (button == iCadeJoystickLeft) || + (button == iCadeJoystickRight))) { + AxisInput axis; + switch (button) { + case iCadeJoystickUp : + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = -1.0f; + break; + + case iCadeJoystickDown : + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = 1.0f; + break; + + case iCadeJoystickLeft : + axis.axisId = JOYSTICK_AXIS_X; + axis.value = -1.0f; + break; + + case iCadeJoystickRight : + axis.axisId = JOYSTICK_AXIS_X; + axis.value = 1.0f; + break; + + default: + break; + } + axis.deviceId = DEVICE_ID_PAD_0; + NativeAxis(&axis, 1); + } else { + KeyInput key; + key.flags = KEY_DOWN; + key.keyCode = iCadeToKeyMap[button]; + key.deviceId = DEVICE_ID_PAD_0; + NativeKey(key); + } +} + +void ICadeTracker::ButtonUp(iCadeState button) { + if (!iCadeConnectNotified) { + iCadeConnectNotified = true; + KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0, "iCade"); + } + + if (button == iCadeButtonA) { + // Pressing Select twice within 1 second toggles the DPad between + // normal operation and simulating the Analog stick. + if ((lastSelectPress + 1.0f) > time_now_d()) + simulateAnalog = !simulateAnalog; + lastSelectPress = time_now_d(); + } + + if (button == iCadeButtonC) { + // Pressing Start twice within 1 second will take to the Emu menu + if ((lastStartPress + 1.0f) > time_now_d()) { + KeyInput key; + key.flags = KEY_DOWN; + key.keyCode = NKCODE_ESCAPE; + key.deviceId = DEVICE_ID_KEYBOARD; + NativeKey(key); + return; + } + lastStartPress = time_now_d(); + } + + if (simulateAnalog && + ((button == iCadeJoystickUp) || + (button == iCadeJoystickDown) || + (button == iCadeJoystickLeft) || + (button == iCadeJoystickRight))) { + AxisInput axis; + switch (button) { + case iCadeJoystickUp : + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = 0.0f; + break; + + case iCadeJoystickDown : + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = 0.0f; + break; + + case iCadeJoystickLeft : + axis.axisId = JOYSTICK_AXIS_X; + axis.value = 0.0f; + break; + + case iCadeJoystickRight : + axis.axisId = JOYSTICK_AXIS_X; + axis.value = 0.0f; + break; + + default: + break; + } + axis.deviceId = DEVICE_ID_PAD_0; + NativeAxis(&axis, 1); + } else { + KeyInput key; + key.flags = KEY_UP; + key.keyCode = iCadeToKeyMap[button]; + key.deviceId = DEVICE_ID_PAD_0; + NativeKey(key); + } +} + +void ProcessAccelerometerData(CMAccelerometerData *accData) { + CMAcceleration acc = accData.acceleration; + // INFO_LOG(SYSTEM, "%f %f %f", acc.x, acc.y, acc.z); + + // Might need to change these for portrait or inverse landscape + NativeAccelerometer(-acc.x, -acc.y, -acc.z); +} + +void SendKeyboardChars(std::string_view str) { + UTF8 chars(str); + while (!chars.end()) { + uint32_t codePoint = chars.next(); + KeyInput input{}; + input.deviceId = DEVICE_ID_KEYBOARD; + input.flags = KEY_CHAR; + input.unicodeChar = codePoint; + NativeKey(input); + } +} + +void KeyboardPressesBegan(NSSet *presses, UIPressesEvent *event) { + for (UIPress *press in presses) { + if (!press.key) { + // I guess we could support remotes and stuff. + continue; + } + if (@available(iOS 13.0, *)) { + InputKeyCode code = HIDUsageToInputKeyCode(press.key.keyCode); + if (code != NKCODE_UNKNOWN) { + KeyInput input{}; + input.deviceId = DEVICE_ID_KEYBOARD; + input.keyCode = code; + input.flags = KEY_DOWN; + NativeKey(input); + INFO_LOG(Log::System, "pressesBegan %d", code); + } + } + if (press.key.characters) { + std::string chars([press.key.characters UTF8String]); + SendKeyboardChars(chars); + } + } +} + +void KeyboardPressesEnded(NSSet *presses, UIPressesEvent *event) { + for (UIPress *press in presses) { + if (!press.key) { + // I guess we could support remotes and stuff. + continue; + } + if (@available(iOS 13.0, *)) { + InputKeyCode code = HIDUsageToInputKeyCode(press.key.keyCode); + if (code != NKCODE_UNKNOWN) { + KeyInput input{}; + input.deviceId = DEVICE_ID_KEYBOARD; + input.keyCode = code; + input.flags = KEY_UP; + NativeKey(input); + INFO_LOG(Log::System, "pressesEnded %d", code); + } + } + } +} + +InputKeyCode HIDUsageToInputKeyCode(UIKeyboardHIDUsage usage) { + switch (usage) { + case UIKeyboardHIDUsageKeyboardA: return NKCODE_A; + case UIKeyboardHIDUsageKeyboardB: return NKCODE_B; + case UIKeyboardHIDUsageKeyboardC: return NKCODE_C; + case UIKeyboardHIDUsageKeyboardD: return NKCODE_D; + case UIKeyboardHIDUsageKeyboardE: return NKCODE_E; + case UIKeyboardHIDUsageKeyboardF: return NKCODE_F; + case UIKeyboardHIDUsageKeyboardG: return NKCODE_G; + case UIKeyboardHIDUsageKeyboardH: return NKCODE_H; + case UIKeyboardHIDUsageKeyboardI: return NKCODE_I; + case UIKeyboardHIDUsageKeyboardJ: return NKCODE_J; + case UIKeyboardHIDUsageKeyboardK: return NKCODE_K; + case UIKeyboardHIDUsageKeyboardL: return NKCODE_L; + case UIKeyboardHIDUsageKeyboardM: return NKCODE_M; + case UIKeyboardHIDUsageKeyboardN: return NKCODE_N; + case UIKeyboardHIDUsageKeyboardO: return NKCODE_O; + case UIKeyboardHIDUsageKeyboardP: return NKCODE_P; + case UIKeyboardHIDUsageKeyboardQ: return NKCODE_Q; + case UIKeyboardHIDUsageKeyboardR: return NKCODE_R; + case UIKeyboardHIDUsageKeyboardS: return NKCODE_S; + case UIKeyboardHIDUsageKeyboardT: return NKCODE_T; + case UIKeyboardHIDUsageKeyboardU: return NKCODE_U; + case UIKeyboardHIDUsageKeyboardV: return NKCODE_V; + case UIKeyboardHIDUsageKeyboardW: return NKCODE_W; + case UIKeyboardHIDUsageKeyboardX: return NKCODE_X; + case UIKeyboardHIDUsageKeyboardY: return NKCODE_Y; + case UIKeyboardHIDUsageKeyboardZ: return NKCODE_Z; + case UIKeyboardHIDUsageKeyboard1: return NKCODE_1; + case UIKeyboardHIDUsageKeyboard2: return NKCODE_2; + case UIKeyboardHIDUsageKeyboard3: return NKCODE_3; + case UIKeyboardHIDUsageKeyboard4: return NKCODE_4; + case UIKeyboardHIDUsageKeyboard5: return NKCODE_5; + case UIKeyboardHIDUsageKeyboard6: return NKCODE_6; + case UIKeyboardHIDUsageKeyboard7: return NKCODE_7; + case UIKeyboardHIDUsageKeyboard8: return NKCODE_8; + case UIKeyboardHIDUsageKeyboard9: return NKCODE_9; + case UIKeyboardHIDUsageKeyboard0: return NKCODE_0; + case UIKeyboardHIDUsageKeyboardReturnOrEnter: return NKCODE_NUMPAD_ENTER; + case UIKeyboardHIDUsageKeyboardEscape: return NKCODE_ESCAPE; + case UIKeyboardHIDUsageKeyboardDeleteOrBackspace: return NKCODE_DEL; // really. + case UIKeyboardHIDUsageKeyboardTab: return NKCODE_TAB; + case UIKeyboardHIDUsageKeyboardSpacebar: return NKCODE_SPACE; + case UIKeyboardHIDUsageKeyboardHyphen: return NKCODE_MINUS; + case UIKeyboardHIDUsageKeyboardEqualSign: return NKCODE_EQUALS; + case UIKeyboardHIDUsageKeyboardOpenBracket: return NKCODE_LEFT_BRACKET; + case UIKeyboardHIDUsageKeyboardCloseBracket: return NKCODE_RIGHT_BRACKET; + case UIKeyboardHIDUsageKeyboardBackslash: return NKCODE_BACKSLASH; + case UIKeyboardHIDUsageKeyboardNonUSPound: return NKCODE_POUND; + case UIKeyboardHIDUsageKeyboardSemicolon: return NKCODE_SEMICOLON; + case UIKeyboardHIDUsageKeyboardQuote: return NKCODE_APOSTROPHE; + case UIKeyboardHIDUsageKeyboardGraveAccentAndTilde: return NKCODE_GRAVE; + case UIKeyboardHIDUsageKeyboardComma: return NKCODE_COMMA; + case UIKeyboardHIDUsageKeyboardPeriod: return NKCODE_PERIOD; + case UIKeyboardHIDUsageKeyboardSlash: return NKCODE_SLASH; + case UIKeyboardHIDUsageKeyboardCapsLock: return NKCODE_CAPS_LOCK; + case UIKeyboardHIDUsageKeyboardF1: return NKCODE_F1; + case UIKeyboardHIDUsageKeyboardF2: return NKCODE_F2; + case UIKeyboardHIDUsageKeyboardF3: return NKCODE_F3; + case UIKeyboardHIDUsageKeyboardF4: return NKCODE_F4; + case UIKeyboardHIDUsageKeyboardF5: return NKCODE_F5; + case UIKeyboardHIDUsageKeyboardF6: return NKCODE_F6; + case UIKeyboardHIDUsageKeyboardF7: return NKCODE_F7; + case UIKeyboardHIDUsageKeyboardF8: return NKCODE_F8; + case UIKeyboardHIDUsageKeyboardF9: return NKCODE_F9; + case UIKeyboardHIDUsageKeyboardF10: return NKCODE_F10; + case UIKeyboardHIDUsageKeyboardF11: return NKCODE_F11; + case UIKeyboardHIDUsageKeyboardF12: return NKCODE_F12; + case UIKeyboardHIDUsageKeyboardScrollLock: return NKCODE_SCROLL_LOCK; + case UIKeyboardHIDUsageKeyboardInsert: return NKCODE_INSERT; + case UIKeyboardHIDUsageKeyboardHome: return NKCODE_HOME; + case UIKeyboardHIDUsageKeyboardPageUp: return NKCODE_PAGE_UP; + case UIKeyboardHIDUsageKeyboardDeleteForward: return NKCODE_DEL; + case UIKeyboardHIDUsageKeyboardEnd: return NKCODE_MOVE_END; + case UIKeyboardHIDUsageKeyboardPageDown: return NKCODE_PAGE_DOWN; + case UIKeyboardHIDUsageKeyboardRightArrow: return NKCODE_DPAD_RIGHT; + case UIKeyboardHIDUsageKeyboardLeftArrow: return NKCODE_DPAD_LEFT; + case UIKeyboardHIDUsageKeyboardDownArrow: return NKCODE_DPAD_DOWN; + case UIKeyboardHIDUsageKeyboardUpArrow: return NKCODE_DPAD_UP; + case UIKeyboardHIDUsageKeypadNumLock: return NKCODE_NUM_LOCK; + case UIKeyboardHIDUsageKeypadSlash: return NKCODE_NUMPAD_DIVIDE; + case UIKeyboardHIDUsageKeypadAsterisk: return NKCODE_NUMPAD_MULTIPLY; + case UIKeyboardHIDUsageKeypadHyphen: return NKCODE_NUMPAD_SUBTRACT; + case UIKeyboardHIDUsageKeypadPlus: return NKCODE_NUMPAD_ADD; + case UIKeyboardHIDUsageKeypadEnter: return NKCODE_NUMPAD_ENTER; + case UIKeyboardHIDUsageKeypad1: return NKCODE_NUMPAD_1; + case UIKeyboardHIDUsageKeypad2: return NKCODE_NUMPAD_2; + case UIKeyboardHIDUsageKeypad3: return NKCODE_NUMPAD_3; + case UIKeyboardHIDUsageKeypad4: return NKCODE_NUMPAD_4; + case UIKeyboardHIDUsageKeypad5: return NKCODE_NUMPAD_5; + case UIKeyboardHIDUsageKeypad6: return NKCODE_NUMPAD_6; + case UIKeyboardHIDUsageKeypad7: return NKCODE_NUMPAD_7; + case UIKeyboardHIDUsageKeypad8: return NKCODE_NUMPAD_8; + case UIKeyboardHIDUsageKeypad9: return NKCODE_NUMPAD_9; + case UIKeyboardHIDUsageKeypad0: return NKCODE_NUMPAD_0; + case UIKeyboardHIDUsageKeypadPeriod: return NKCODE_NUMPAD_COMMA; + case UIKeyboardHIDUsageKeyboardNonUSBackslash: return NKCODE_BACKSLASH; + case UIKeyboardHIDUsageKeyboardApplication: return NKCODE_APP_SWITCH; + case UIKeyboardHIDUsageKeyboardPower: return NKCODE_POWER; + case UIKeyboardHIDUsageKeypadEqualSign: return NKCODE_NUMPAD_EQUALS; + case UIKeyboardHIDUsageKeyboardMenu: return NKCODE_MENU; + case UIKeyboardHIDUsageKeyboardMute: return NKCODE_MUTE; + case UIKeyboardHIDUsageKeyboardVolumeUp: return NKCODE_VOLUME_UP; + case UIKeyboardHIDUsageKeypadComma: return NKCODE_NUMPAD_COMMA; + default: return NKCODE_UNKNOWN; + } +} diff --git a/ios/DisplayManager.mm b/ios/DisplayManager.mm index ba369e64e1..782332ee28 100644 --- a/ios/DisplayManager.mm +++ b/ios/DisplayManager.mm @@ -6,6 +6,7 @@ // #import "DisplayManager.h" +#import "iOSCoreAudio.h" #import "ViewController.h" #import "AppDelegate.h" #include "Common/System/Display.h" @@ -64,6 +65,9 @@ [self setOriginalFrame: [gameWindow frame]]; [self setOriginalBounds:[gameWindow bounds]]; [self setOriginalTransform:[gameWindow transform]]; + + // TODO: From iOS 13, should use UIScreenDidConnectNotification instead of the below. + // Display connected [[NSNotificationCenter defaultCenter] addObserverForName:UIScreenDidConnectNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull notification) { UIScreen *screen = (UIScreen *) notification.object; @@ -74,8 +78,7 @@ return; } // Ignore mute switch when connected to external display - NSError *error = nil; - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]; + iOSCoreAudioSetDisplayConnected(true); [self updateScreen:screen]; }]; // Display disconnected @@ -89,8 +92,7 @@ UIScreen *newScreen = [[self extDisplays] lastObject]; [self updateScreen:newScreen]; } else { - NSError *error = nil; - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error]; + iOSCoreAudioSetDisplayConnected(false); [self updateScreen:[UIScreen mainScreen]]; } }]; @@ -133,20 +135,13 @@ } - (void)updateResolution:(UIScreen *)screen { - float scale = screen.scale; - - if ([screen respondsToSelector:@selector(nativeScale)]) { - scale = screen.nativeScale; - } - - CGSize size = screen.applicationFrame.size; + float scale = screen.nativeScale; + CGSize size = screen.bounds.size; if (size.height > size.width) { - float h = size.height; - size.height = size.width; - size.width = h; + std::swap(size.height, size.width); } - + if (screen == [UIScreen mainScreen]) { g_display.dpi = (IS_IPAD() ? 200.0f : 150.0f) * scale; } else { @@ -159,19 +154,19 @@ g_display.dpi_scale_real_y = g_display.dpi_scale_y; g_display.pixel_xres = size.width * scale; g_display.pixel_yres = size.height * scale; - + g_display.dp_xres = g_display.pixel_xres * g_display.dpi_scale_x; g_display.dp_yres = g_display.pixel_yres * g_display.dpi_scale_y; - + g_display.pixel_in_dps_x = (float)g_display.pixel_xres / (float)g_display.dp_xres; g_display.pixel_in_dps_y = (float)g_display.pixel_yres / (float)g_display.dp_yres; - [[sharedViewController view] setContentScaleFactor:scale]; + [[sharedViewController getView] setContentScaleFactor:scale]; // PSP native resize PSP_CoreParameter().pixelWidth = g_display.pixel_xres; PSP_CoreParameter().pixelHeight = g_display.pixel_yres; - + NativeResized(); NSLog(@"Updated display resolution: (%d, %d) @%.1fx", g_display.pixel_xres, g_display.pixel_yres, scale); diff --git a/ios/Export.plist b/ios/Export.plist new file mode 100644 index 0000000000..f27da5cd5e --- /dev/null +++ b/ios/Export.plist @@ -0,0 +1,7 @@ + + + + method + app-store-connect + + diff --git a/ios/Launch Screen.storyboard b/ios/Launch Screen.storyboard index 513011ac21..78a1ea3758 100644 --- a/ios/Launch Screen.storyboard +++ b/ios/Launch Screen.storyboard @@ -25,35 +25,6 @@ - - - - - - - - - - - diff --git a/ios/MoltenVK b/ios/MoltenVK new file mode 160000 index 0000000000..0bf904d2d1 --- /dev/null +++ b/ios/MoltenVK @@ -0,0 +1 @@ +Subproject commit 0bf904d2d1d159eb95bdefcd8432eee79ee1da14 diff --git a/ios/PPSSPP-Info.plist b/ios/PPSSPP-Info.plist index 6e72de13ff..1692e65f16 100644 --- a/ios/PPSSPP-Info.plist +++ b/ios/PPSSPP-Info.plist @@ -10,6 +10,8 @@ Your camera may be used to emulate Go!Cam, a camera accessory NSMicrophoneUsageDescription Your microphone may be used to emulate Go!Cam/Talkman, a microphone accessory + NSLocalNetworkUsageDescription + Your local network needs to be accessed by PPSSPP for network multiplayer support. CFBundleDisplayName PPSSPP CFBundleExecutable @@ -28,14 +30,30 @@ ???? CFBundleVersion 1.0 + CFBundleIcons + + CFBundlePrimaryIcon + + CFBundleIconFiles + + assets + + + LSRequiresIPhoneOS UIViewControllerBasedStatusBarAppearance + UIRequiresFullScreen + UIRequiredDeviceCapabilities arm64 + LSApplicationCategoryType + public.app-category.games + GCSupportsGameMode + UIStatusBarHidden UISupportedInterfaceOrientations @@ -48,22 +66,10 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CFBundleIconFiles - - assets/Icon-72.png - assets/Icon-72@2x.png - assets/Icon.png - assets/Icon@2x.png - UILaunchImageFile Default.png UIFileSharingEnabled - UIDeviceFamily - - 1 - 2 - UILaunchStoryboardName Launch Screen CFBundleDocumentTypes diff --git a/ios/PPSSPPUIApplication.mm b/ios/PPSSPPUIApplication.mm index 1a25db20e1..b5df31df32 100644 --- a/ios/PPSSPPUIApplication.mm +++ b/ios/PPSSPPUIApplication.mm @@ -35,6 +35,8 @@ #include #include +// This stuff reads directly from _gsEvent which is not allowed on the App Store. + #ifndef IS_IOS7 #define IS_IOS7 ([[UIDevice currentDevice].systemVersion floatValue]>=7.0) #endif @@ -63,6 +65,8 @@ @implementation PPSSPPUIApplication +#if !PPSSPP_PLATFORM(IOS_APP_STORE) + - (void)decodeKeyEvent:(NSInteger *)eventMem { NSInteger eventType = eventMem[GSEVENT_TYPE]; NSInteger eventScanCode = eventMem[GSEVENTKEY_KEYCODE]; @@ -108,4 +112,6 @@ } } +#endif // IOS_APP_STORE + @end diff --git a/ios/README.md b/ios/README.md index f451fb5c1c..26096a6d60 100644 --- a/ios/README.md +++ b/ios/README.md @@ -1,5 +1,15 @@ -iOS Build Instructions -====================== +Updating with a self-built MoltenVK +=================================== +cp -r ../dev/build-molten/MoltenVK/Package/Release/MoltenVK/static/MoltenVK.xcframework ios/MoltenVK + +The Old iOS Build Instructions +============================== + +Important Notes +--------------- + +These instructions have not been updated for a long time and may be outdated. + Prerequisites: -------------- diff --git a/ios/ViewController.h b/ios/ViewController.h index d64d973c77..a6eaabeb70 100644 --- a/ios/ViewController.h +++ b/ios/ViewController.h @@ -2,24 +2,15 @@ #import #import -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 #import -#endif + #import "iCade/iCadeReaderView.h" #import "CameraHelper.h" #import "LocationHelper.h" -@interface ViewController : GLKViewController - -- (void)shareText:(NSString *)text; -- (void)shutdown; +#include "ViewControllerCommon.h" +@interface PPSSPPViewControllerGL : GLKViewController < + iCadeEventDelegate, LocationHandlerDelegate, CameraFrameDelegate, + UIGestureRecognizerDelegate, UIKeyInput, PPSSPPViewController> @end - -extern __unsafe_unretained ViewController* sharedViewController; -void setCameraSize(int width, int height); -void startVideo(); -void stopVideo(); -void startLocation(); -void stopLocation(); diff --git a/ios/ViewController.mm b/ios/ViewController.mm index c85b8b5eff..abcf5f19ea 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -8,6 +8,7 @@ #import "AppDelegate.h" #import "ViewController.h" #import "DisplayManager.h" +#include "Controls.h" #import "iOSCoreAudio.h" #import @@ -19,12 +20,12 @@ #include "Common/GPU/thin3d_create.h" #include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/GPU/OpenGL/GLFeatures.h" - #include "Common/System/Display.h" #include "Common/System/System.h" #include "Common/System/OSD.h" #include "Common/System/NativeApp.h" #include "Common/File/VFS/VFS.h" +#include "Common/Thread/ThreadUtil.h" #include "Common/Log.h" #include "Common/TimeUtil.h" #include "Common/Input/InputState.h" @@ -38,16 +39,13 @@ #include "Core/HLE/sceUsbCam.h" #include "Core/HLE/sceUsbGps.h" -#include -#include -#include +#if !__has_feature(objc_arc) +#error Must be built with ARC, please revise the flags for ViewController.mm to include -fobjc-arc. +#endif -#define IS_IPAD() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) -#define IS_IPHONE() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) - -class IOSGraphicsContext : public GraphicsContext { +class IOSGLESContext : public GraphicsContext { public: - IOSGraphicsContext() { + IOSGLESContext() { CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(false); renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); @@ -56,7 +54,7 @@ public: bool success = draw_->CreatePresets(); _assert_msg_(success, "Failed to compile preset shaders"); } - ~IOSGraphicsContext() { + ~IOSGLESContext() { delete draw_; } Draw::DrawContext *GetDrawContext() override { @@ -78,6 +76,10 @@ public: renderManager_->ThreadEnd(); } + void StartThread() { + renderManager_->StartThread(); + } + void StopThread() override { renderManager_->StopThread(); } @@ -87,71 +89,61 @@ private: GLRenderManager *renderManager_; }; -static float dp_xscale = 1.0f; -static float dp_yscale = 1.0f; +static std::atomic exitRenderLoop; +static std::atomic renderLoopRunning; +static std::thread g_renderLoopThread; -static double lastSelectPress = 0.0f; -static double lastStartPress = 0.0f; -static bool simulateAnalog = false; -static bool iCadeConnectNotified = false; -static bool threadEnabled = true; -static bool threadStopped = false; -static UITouch *g_touches[10]; +id sharedViewController; -__unsafe_unretained ViewController* sharedViewController; -static GraphicsContext *graphicsContext; -static CameraHelper *cameraHelper; -static LocationHelper *locationHelper; +@interface PPSSPPViewControllerGL () { + ICadeTracker g_iCadeTracker; + TouchTracker g_touchTracker; -@interface ViewController () { - std::map iCadeToKeyMap; + IOSGLESContext *graphicsContext; + LocationHelper *locationHelper; + CameraHelper *cameraHelper; } @property (nonatomic, strong) EAGLContext* context; //@property (nonatomic) iCadeReaderView* iCadeView; -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 @property (nonatomic) GCController *gameController __attribute__((weak_import)); -#endif +@property (strong, nonatomic) CMMotionManager *motionManager; +@property (strong, nonatomic) NSOperationQueue *accelerometerQueue; @end -@implementation ViewController +@implementation PPSSPPViewControllerGL { + UIScreenEdgePanGestureRecognizer *mBackGestureRecognizer; +} -(id) init { self = [super init]; if (self) { sharedViewController = self; - memset(g_touches, 0, sizeof(g_touches)); - - iCadeToKeyMap[iCadeJoystickUp] = NKCODE_DPAD_UP; - iCadeToKeyMap[iCadeJoystickRight] = NKCODE_DPAD_RIGHT; - iCadeToKeyMap[iCadeJoystickDown] = NKCODE_DPAD_DOWN; - iCadeToKeyMap[iCadeJoystickLeft] = NKCODE_DPAD_LEFT; - iCadeToKeyMap[iCadeButtonA] = NKCODE_BUTTON_9; // Select - iCadeToKeyMap[iCadeButtonB] = NKCODE_BUTTON_7; // LTrigger - iCadeToKeyMap[iCadeButtonC] = NKCODE_BUTTON_10; // Start - iCadeToKeyMap[iCadeButtonD] = NKCODE_BUTTON_8; // RTrigger - iCadeToKeyMap[iCadeButtonE] = NKCODE_BUTTON_4; // Square - iCadeToKeyMap[iCadeButtonF] = NKCODE_BUTTON_2; // Cross - iCadeToKeyMap[iCadeButtonG] = NKCODE_BUTTON_1; // Triangle - iCadeToKeyMap[iCadeButtonH] = NKCODE_BUTTON_3; // Circle + g_iCadeTracker.InitKeyMap(); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; - -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 - if ([GCController class]) // Checking the availability of a GameController framework - { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil]; - } -#endif + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil]; } + self.accelerometerQueue = [[NSOperationQueue alloc] init]; + self.accelerometerQueue.name = @"AccelerometerQueue"; + self.accelerometerQueue.maxConcurrentOperationCount = 1; return self; } - (BOOL)prefersHomeIndicatorAutoHidden { - return YES; + if (g_Config.iAppSwitchMode == (int)AppSwitchMode::DOUBLE_SWIPE_INDICATOR) { + return NO; + } else { + return YES; + } +} + +- (void)appSwitchModeChanged +{ + [self setNeedsUpdateOfHomeIndicatorAutoHidden]; } - (void)shareText:(NSString *)text { @@ -170,7 +162,6 @@ extern float g_safeInsetBottom; - (void)viewSafeAreaInsetsDidChange { if (@available(iOS 11.0, *)) { [super viewSafeAreaInsetsDidChange]; - char safeArea[100]; // we use 0.0f instead of safeAreaInsets.bottom because the bottom overlay isn't disturbing (for now) g_safeInsetLeft = self.view.safeAreaInsets.left; g_safeInsetRight = self.view.safeAreaInsets.right; @@ -179,6 +170,71 @@ extern float g_safeInsetBottom; } } +// The actual rendering is NOT on this thread, this is the emu thread +// that runs game logic. +void GLRenderLoop(IOSGLESContext *graphicsContext) { + SetCurrentThreadName("EmuThreadGL"); + renderLoopRunning = true; + + NativeInitGraphics(graphicsContext); + + INFO_LOG(Log::System, "Emulation thread starting\n"); + while (!exitRenderLoop) { + NativeFrame(graphicsContext); + } + + INFO_LOG(Log::System, "Emulation thread shutting down\n"); + NativeShutdownGraphics(); + + // Also ask the main thread to stop, so it doesn't hang waiting for a new frame. + INFO_LOG(Log::System, "Emulation thread stopping\n"); + + exitRenderLoop = false; + renderLoopRunning = false; +} + +- (bool)runGLRenderLoop { + if (!graphicsContext) { + ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context."); + return false; + } + + if (g_renderLoopThread.joinable()) { + ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Already running"); + return false; + } + + _dbg_assert_(!renderLoopRunning); + _dbg_assert_(!exitRenderLoop); + + graphicsContext->StartThread(); + + g_renderLoopThread = std::thread(GLRenderLoop, graphicsContext); + return true; +} + +- (void)requestExitGLRenderLoop { + if (!renderLoopRunning) { + ERROR_LOG(Log::System, "Render loop already exited"); + return; + } + _assert_(g_renderLoopThread.joinable()); + exitRenderLoop = true; + graphicsContext->StopThread(); + while (graphicsContext->ThreadFrame()) { + continue; + } + g_renderLoopThread.join(); + _assert_(!g_renderLoopThread.joinable()); +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + INFO_LOG(Log::G3D, "viewDidAppear"); + [self hideKeyboard]; + [self updateGesture]; +} + - (void)viewDidLoad { [super viewDidLoad]; [[DisplayManager shared] setupDisplayListener]; @@ -197,11 +253,11 @@ extern float g_safeInsetBottom; view.drawableDepthFormat = GLKViewDrawableDepthFormat24; view.drawableStencilFormat = GLKViewDrawableStencilFormat8; [EAGLContext setCurrentContext:self.context]; - self.preferredFramesPerSecond = 60; + self.preferredFramesPerSecond = 60; // NOTE: We don't yet take advantage of 120hz screens [[DisplayManager shared] updateResolution:[UIScreen mainScreen]]; - graphicsContext = new IOSGraphicsContext(); + graphicsContext = new IOSGLESContext(); graphicsContext->GetDrawContext()->SetErrorCallback([](const char *shortDesc, const char *details, void *userdata) { g_OSD.Show(OSDType::MESSAGE_ERROR, details, 0.0f, "error_callback"); @@ -209,21 +265,14 @@ extern float g_safeInsetBottom; graphicsContext->ThreadStart(); - dp_xscale = (float)g_display.dp_xres / (float)g_display.pixel_xres; - dp_yscale = (float)g_display.dp_yres / (float)g_display.pixel_yres; - /*self.iCadeView = [[iCadeReaderView alloc] init]; [self.view addSubview:self.iCadeView]; self.iCadeView.delegate = self; self.iCadeView.active = YES;*/ -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 - if ([GCController class]) { - if ([[GCController controllers] count] > 0) { - [self setupController:[[GCController controllers] firstObject]]; - } + if ([[GCController controllers] count] > 0) { + [self setupController:[[GCController controllers] firstObject]]; } -#endif cameraHelper = [[CameraHelper alloc] init]; [cameraHelper setDelegate:self]; @@ -231,24 +280,23 @@ extern float g_safeInsetBottom; locationHelper = [[LocationHelper alloc] init]; [locationHelper setDelegate:self]; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - NativeInitGraphics(graphicsContext); + [self hideKeyboard]; - INFO_LOG(SYSTEM, "Emulation thread starting\n"); - while (threadEnabled) { - NativeFrame(graphicsContext); - } + // Initialize the motion manager for accelerometer control. + self.motionManager = [[CMMotionManager alloc] init]; + INFO_LOG(Log::G3D, "Done with viewDidLoad."); +} - - INFO_LOG(SYSTEM, "Emulation thread shutting down\n"); - NativeShutdownGraphics(); - - // Also ask the main thread to stop, so it doesn't hang waiting for a new frame. - INFO_LOG(SYSTEM, "Emulation thread stopping\n"); - graphicsContext->StopThread(); - - threadStopped = true; - }); +- (void)handleSwipeFrom:(UIScreenEdgePanGestureRecognizer *)recognizer +{ + if (recognizer.state == UIGestureRecognizerStateEnded) { + KeyInput key; + key.flags = KEY_DOWN | KEY_UP; + key.keyCode = NKCODE_BACK; + key.deviceId = DEVICE_ID_TOUCH; + NativeKey(key); + INFO_LOG(Log::System, "Detected back swipe"); + } } - (void)appWillTerminate:(NSNotification *)notification @@ -256,23 +304,47 @@ extern float g_safeInsetBottom; [self shutdown]; } +- (void)didBecomeActive { + INFO_LOG(Log::System, "didBecomeActive begin"); + if (self.motionManager.accelerometerAvailable) { + self.motionManager.accelerometerUpdateInterval = 1.0 / 60.0; + INFO_LOG(Log::G3D, "Starting accelerometer updates."); + + [self.motionManager startAccelerometerUpdatesToQueue:self.accelerometerQueue + withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { + if (error) { + NSLog(@"Accelerometer error: %@", error); + return; + } + ProcessAccelerometerData(accelerometerData); + }]; + } else { + INFO_LOG(Log::G3D, "No accelerometer available, not starting updates."); + } + [self runGLRenderLoop]; + INFO_LOG(Log::System, "didBecomeActive end"); +} + +- (void)willResignActive { + INFO_LOG(Log::System, "willResignActive begin"); + [self requestExitGLRenderLoop]; + + // Stop accelerometer updates + if (self.motionManager.accelerometerActive) { + INFO_LOG(Log::G3D, "Stopping accelerometer updates"); + [self.motionManager stopAccelerometerUpdates]; + } + INFO_LOG(Log::System, "willResignActive end"); +} + - (void)shutdown { - if (sharedViewController == nil) { - return; - } + INFO_LOG(Log::System, "shutdown GL"); - iOSCoreAudioShutdown(); - - if (threadEnabled) { - threadEnabled = false; - while (graphicsContext->ThreadFrame()) { - continue; - } - while (!threadStopped) {} - graphicsContext->ThreadEnd(); - } + g_Config.Save("shutdown GL"); + _dbg_assert_(graphicsContext); + _dbg_assert_(sharedViewController != nil); sharedViewController = nil; if (self.context) { @@ -284,33 +356,24 @@ extern float g_safeInsetBottom; [[NSNotificationCenter defaultCenter] removeObserver:self]; -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 - if ([GCController class]) { - self.gameController = nil; - } -#endif + self.gameController = nil; - if (graphicsContext) { - graphicsContext->Shutdown(); - delete graphicsContext; - graphicsContext = NULL; + graphicsContext->StopThread(); + // Skipping GL calls here because the old context is lost. + while (graphicsContext->ThreadFrame()) { + continue; } - - NativeShutdown(); + graphicsContext->Shutdown(); + delete graphicsContext; + graphicsContext = nullptr; + INFO_LOG(Log::System, "Done shutting down GL"); } - (void)dealloc { - [self shutdown]; + INFO_LOG(Log::System, "dealloc GL"); } -// For iOS before 6.0 -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation -{ - return UIInterfaceOrientationIsLandscape(toInterfaceOrientation); -} - -// For iOS 6.0 and up - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; @@ -318,110 +381,33 @@ extern float g_safeInsetBottom; - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { - if (sharedViewController) + if (!renderLoopRunning) { + INFO_LOG(Log::G3D, "Ignoring drawInRect"); + return; + } + if (sharedViewController) { graphicsContext->ThreadFrame(); + } } -- (void)touchX:(float)x y:(float)y code:(int)code pointerId:(int)pointerId -{ - float scale = [UIScreen mainScreen].scale; - - if ([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)]) { - scale = [UIScreen mainScreen].nativeScale; - } - - float scaledX = (int)(x * dp_xscale) * scale; - float scaledY = (int)(y * dp_yscale) * scale; - - TouchInput input; - input.x = scaledX; - input.y = scaledY; - switch (code) { - case 1 : - input.flags = TOUCH_DOWN; - break; - - case 2 : - input.flags = TOUCH_UP; - break; - - default : - input.flags = TOUCH_MOVE; - break; - } - input.id = pointerId; - NativeTouch(input); -} - -int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - // Find the id for the touch. - for (int localId = 0; localId < (int)ARRAY_SIZE(g_touches); ++localId) { - if (g_touches[localId] == uiTouch) { - return localId; - } - } - - // Allocate a new one, perhaps? - if (allowAllocate) { - for (int localId = 0; localId < (int)ARRAY_SIZE(g_touches); ++localId) { - if (g_touches[localId] == 0) { - g_touches[localId] = uiTouch; - return localId; - } - } - - // None were free. Ignore? - return 0; - } - - return -1; -} - - - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - for(UITouch* touch in touches) - { - CGPoint point = [touch locationInView:self.view]; - int touchId = ToTouchID(touch, true); - [self touchX:point.x y:point.y code:1 pointerId:touchId]; - } + g_touchTracker.Began(touches, self.view); } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - for(UITouch* touch in touches) - { - CGPoint point = [touch locationInView:self.view]; - int touchId = ToTouchID(touch, true); - [self touchX:point.x y:point.y code:0 pointerId: touchId]; - } + g_touchTracker.Moved(touches, self.view); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - for(UITouch* touch in touches) - { - CGPoint point = [touch locationInView:self.view]; - int touchId = ToTouchID(touch, false); - if (touchId >= 0) { - [self touchX:point.x y:point.y code:2 pointerId: touchId]; - g_touches[touchId] = nullptr; - } - } + g_touchTracker.Ended(touches, self.view); } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - for(UITouch* touch in touches) - { - CGPoint point = [touch locationInView:self.view]; - int touchId = ToTouchID(touch, false); - if (touchId >= 0) { - [self touchX:point.x y:point.y code:2 pointerId: touchId]; - g_touches[touchId] = nullptr; - } - } + g_touchTracker.Cancelled(touches, self.view); } - (void)bindDefaultFBO @@ -431,118 +417,14 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - (void)buttonDown:(iCadeState)button { - if (simulateAnalog && - ((button == iCadeJoystickUp) || - (button == iCadeJoystickDown) || - (button == iCadeJoystickLeft) || - (button == iCadeJoystickRight))) { - AxisInput axis; - switch (button) { - case iCadeJoystickUp : - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = -1.0f; - break; - - case iCadeJoystickDown : - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = 1.0f; - break; - - case iCadeJoystickLeft : - axis.axisId = JOYSTICK_AXIS_X; - axis.value = -1.0f; - break; - - case iCadeJoystickRight : - axis.axisId = JOYSTICK_AXIS_X; - axis.value = 1.0f; - break; - - default: - break; - } - axis.deviceId = DEVICE_ID_PAD_0; - NativeAxis(&axis, 1); - } else { - KeyInput key; - key.flags = KEY_DOWN; - key.keyCode = iCadeToKeyMap[button]; - key.deviceId = DEVICE_ID_PAD_0; - NativeKey(key); - } + g_iCadeTracker.ButtonDown(button); } - (void)buttonUp:(iCadeState)button { - if (!iCadeConnectNotified) { - iCadeConnectNotified = true; - KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0, "iCade"); - } - - if (button == iCadeButtonA) { - // Pressing Select twice within 1 second toggles the DPad between - // normal operation and simulating the Analog stick. - if ((lastSelectPress + 1.0f) > time_now_d()) - simulateAnalog = !simulateAnalog; - lastSelectPress = time_now_d(); - } - - if (button == iCadeButtonC) { - // Pressing Start twice within 1 second will take to the Emu menu - if ((lastStartPress + 1.0f) > time_now_d()) { - KeyInput key; - key.flags = KEY_DOWN; - key.keyCode = NKCODE_ESCAPE; - key.deviceId = DEVICE_ID_KEYBOARD; - NativeKey(key); - return; - } - lastStartPress = time_now_d(); - } - - if (simulateAnalog && - ((button == iCadeJoystickUp) || - (button == iCadeJoystickDown) || - (button == iCadeJoystickLeft) || - (button == iCadeJoystickRight))) { - AxisInput axis; - switch (button) { - case iCadeJoystickUp : - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = 0.0f; - break; - - case iCadeJoystickDown : - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = 0.0f; - break; - - case iCadeJoystickLeft : - axis.axisId = JOYSTICK_AXIS_X; - axis.value = 0.0f; - break; - - case iCadeJoystickRight : - axis.axisId = JOYSTICK_AXIS_X; - axis.value = 0.0f; - break; - - default: - break; - } - axis.deviceId = DEVICE_ID_PAD_0; - NativeAxis(&axis, 1); - } else { - KeyInput key; - key.flags = KEY_UP; - key.keyCode = iCadeToKeyMap[button]; - key.deviceId = DEVICE_ID_PAD_0; - NativeKey(key); - } - + g_iCadeTracker.ButtonUp(button); } -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 - (void)controllerDidConnect:(NSNotification *)note { if (![[GCController controllers] containsObject:self.gameController]) self.gameController = nil; @@ -559,191 +441,83 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { if ([[GCController controllers] count] > 0) { [self setupController:[[GCController controllers] firstObject]]; - } else { - [[UIApplication sharedApplication] setIdleTimerDisabled:NO]; } } } -- (void)controllerButtonPressed:(BOOL)pressed keyCode:(InputKeyCode)keyCode -{ - KeyInput key; - key.deviceId = DEVICE_ID_PAD_0; - key.flags = pressed ? KEY_DOWN : KEY_UP; - key.keyCode = keyCode; - NativeKey(key); -} - // Enables tapping for edge area. -(UIRectEdge)preferredScreenEdgesDeferringSystemGestures { - return UIRectEdgeAll; + if (GetUIState() == UISTATE_INGAME) { + // In-game, we need all the control we can get. Though, we could possibly + // allow the top edge? + INFO_LOG(Log::System, "Defer system gestures on all edges"); + return UIRectEdgeAll; + } else { + INFO_LOG(Log::System, "Allow system gestures on the bottom"); + // Allow task switching gestures to take precedence, without causing + // scroll events in the UI. Otherwise, we get "ghost" scrolls when switching tasks. + return UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeRight; + } +} + +- (void)uiStateChanged +{ + [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; + [self hideKeyboard]; + [self updateGesture]; +} + +- (void)updateGesture { + INFO_LOG(Log::System, "Updating swipe gesture."); + + if (mBackGestureRecognizer) { + INFO_LOG(Log::System, "Removing swipe gesture."); + [[self view] removeGestureRecognizer:mBackGestureRecognizer]; + mBackGestureRecognizer = nil; + } + + if (GetUIState() != UISTATE_INGAME) { + INFO_LOG(Log::System, "Adding swipe gesture."); + mBackGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:) ]; + [mBackGestureRecognizer setEdges:UIRectEdgeLeft]; + [[self view] addGestureRecognizer:mBackGestureRecognizer]; + } +} + +- (UIView *)getView { + return [self view]; } - (void)setupController:(GCController *)controller { self.gameController = controller; - - GCGamepad *baseProfile = self.gameController.gamepad; - if (baseProfile == nil) { + if (!InitController(controller)) { self.gameController = nil; - return; } - - [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; // prevent auto-lock - - self.gameController.controllerPausedHandler = ^(GCController *controller) { - KeyInput key; - key.flags = KEY_DOWN; - key.keyCode = NKCODE_ESCAPE; - key.deviceId = DEVICE_ID_KEYBOARD; - NativeKey(key); - }; - - baseProfile.buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_2]; // Cross - }; - - baseProfile.buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_3]; // Circle - }; - - baseProfile.buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_4]; // Square - }; - - baseProfile.buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_1]; // Triangle - }; - - baseProfile.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_7]; // LTrigger - }; - - baseProfile.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_8]; // RTrigger - }; - - baseProfile.dpad.up.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_UP]; - }; - - baseProfile.dpad.down.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_DOWN]; - }; - - baseProfile.dpad.left.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_LEFT]; - }; - - baseProfile.dpad.right.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_RIGHT]; - }; - - GCExtendedGamepad *extendedProfile = self.gameController.extendedGamepad; - if (extendedProfile == nil) - return; // controller doesn't support extendedGamepad profile - - extendedProfile.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_9]; // Select - }; - - extendedProfile.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_10]; // Start - }; - -#if defined(__IPHONE_12_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_1 - if ([extendedProfile respondsToSelector:@selector(leftThumbstickButton)] && extendedProfile.leftThumbstickButton != nil) { - extendedProfile.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_11]; - }; - } - if ([extendedProfile respondsToSelector:@selector(rightThumbstickButton)] && extendedProfile.rightThumbstickButton != nil) { - extendedProfile.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_12]; - }; - } -#endif -#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 - if ([extendedProfile respondsToSelector:@selector(buttonOptions)] && extendedProfile.buttonOptions != nil) { - extendedProfile.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_13]; - }; - } - if ([extendedProfile respondsToSelector:@selector(buttonMenu)] && extendedProfile.buttonMenu != nil) { - extendedProfile.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_14]; - }; - } -#endif -#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 - if ([extendedProfile respondsToSelector:@selector(buttonHome)] && extendedProfile.buttonHome != nil) { - extendedProfile.buttonHome.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_15]; - }; - } -#endif - - extendedProfile.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { - AxisInput axisInput; - axisInput.deviceId = DEVICE_ID_PAD_0; - axisInput.axisId = JOYSTICK_AXIS_X; - axisInput.value = value; - NativeAxis(&axisInput, 1); - }; - - extendedProfile.leftThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { - AxisInput axisInput; - axisInput.deviceId = DEVICE_ID_PAD_0; - axisInput.axisId = JOYSTICK_AXIS_Y; - axisInput.value = -value; - NativeAxis(&axisInput, 1); - }; - - // Map right thumbstick as another analog stick, particularly useful for controllers like the DualShock 3/4 when connected to an iOS device - extendedProfile.rightThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { - AxisInput axisInput; - axisInput.deviceId = DEVICE_ID_PAD_0; - axisInput.axisId = JOYSTICK_AXIS_Z; - axisInput.value = value; - NativeAxis(&axisInput, 1); - }; - - extendedProfile.rightThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { - AxisInput axisInput; - axisInput.deviceId = DEVICE_ID_PAD_0; - axisInput.axisId = JOYSTICK_AXIS_RZ; - axisInput.value = -value; - NativeAxis(&axisInput, 1); - }; -} -#endif - -void setCameraSize(int width, int height) { - [cameraHelper setCameraSize: width h:height]; } -void startVideo() { - [cameraHelper startVideo]; +- (void)startVideo:(int)width height:(int)height { + [cameraHelper startVideo:width h:height]; } -void stopVideo() { +- (void)stopVideo { [cameraHelper stopVideo]; } --(void) PushCameraImageIOS:(long long)len buffer:(unsigned char*)data { +- (void)PushCameraImageIOS:(long long)len buffer:(unsigned char*)data { Camera::pushCameraImage(len, data); } -void startLocation() { +- (void)startLocation { [locationHelper startLocationUpdates]; } -void stopLocation() { +- (void)stopLocation { [locationHelper stopLocationUpdates]; } --(void) SetGpsDataIOS:(CLLocation *)newLocation { +- (void)SetGpsDataIOS:(CLLocation *)newLocation { GPS::setGpsData((long long)newLocation.timestamp.timeIntervalSince1970, newLocation.horizontalAccuracy/5.0, newLocation.coordinate.latitude, newLocation.coordinate.longitude, @@ -752,13 +526,68 @@ void stopLocation() { 0 /* bearing */); } -@end +// See PPSSPPUIApplication.mm for the other method +#if PPSSPP_PLATFORM(IOS_APP_STORE) -void System_LaunchUrl(LaunchUrlType urlType, char const* url) -{ - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]]; +- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesBegan(presses, event); } +- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesEnded(presses, event); +} + +- (void)pressesCancelled:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesEnded(presses, event); +} + +#endif + +// The below is inspired by https://stackoverflow.com/questions/7253477/how-to-display-the-iphone-ipad-keyboard-over-a-full-screen-opengl-es-app +// It's a bit limited but good enough. + +-(void) deleteBackward { + KeyInput input{}; + input.deviceId = DEVICE_ID_KEYBOARD; + input.flags = KEY_DOWN | KEY_UP; + input.keyCode = NKCODE_DEL; + NativeKey(input); + INFO_LOG(Log::System, "Backspace"); +} + +-(void) insertText:(NSString *)text +{ + std::string str([text UTF8String]); + INFO_LOG(Log::System, "Chars: %s", str.c_str()); + SendKeyboardChars(str); +} + +-(BOOL) canBecomeFirstResponder +{ + return true; +} + +-(BOOL) hasText +{ + return true; +} + +-(void) showKeyboard { + dispatch_async(dispatch_get_main_queue(), ^{ + INFO_LOG(Log::System, "becomeFirstResponder"); + [self becomeFirstResponder]; + }); +} + +-(void) hideKeyboard { + dispatch_async(dispatch_get_main_queue(), ^{ + INFO_LOG(Log::System, "resignFirstResponder"); + [self resignFirstResponder]; + }); +} + +@end + void bindDefaultFBO() { [sharedViewController bindDefaultFBO]; diff --git a/ios/ViewControllerCommon.h b/ios/ViewControllerCommon.h new file mode 100644 index 0000000000..47e2c03028 --- /dev/null +++ b/ios/ViewControllerCommon.h @@ -0,0 +1,31 @@ +#pragma once + +#import + +@protocol PPSSPPViewController +@optional + +- (void)hideKeyboard; +- (void)showKeyboard; +- (void)shareText:(NSString *)text; +- (void)shutdown; +- (void)bindDefaultFBO; +- (UIView *)getView; +- (void)startLocation; +- (void)stopLocation; +- (void)startVideo:(int)width height:(int)height; +- (void)stopVideo; +- (void)appSwitchModeChanged; + +// Forwarded from the AppDelegate +- (void)didBecomeActive; +- (void)willResignActive; + +- (void)uiStateChanged; + +@end + +extern id sharedViewController; + +#define IS_IPAD() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) +#define IS_IPHONE() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) diff --git a/ios/ViewControllerMetal.h b/ios/ViewControllerMetal.h new file mode 100644 index 0000000000..bb236e4195 --- /dev/null +++ b/ios/ViewControllerMetal.h @@ -0,0 +1,18 @@ +// ViewControllerMetal +// Used by both Vulkan/MoltenVK and the future Metal backend. + +#pragma once +#include "ViewControllerCommon.h" + +#import "iCade/iCadeReaderView.h" +#import "CameraHelper.h" +#import "LocationHelper.h" + +@interface PPSSPPViewControllerMetal : UIViewController< + iCadeEventDelegate, LocationHandlerDelegate, CameraFrameDelegate, + UIGestureRecognizerDelegate, UIKeyInput, PPSSPPViewController> +@end + +/** The Metal-compatibile view. */ +@interface PPSSPPMetalView : UIView +@end \ No newline at end of file diff --git a/ios/ViewControllerMetal.mm b/ios/ViewControllerMetal.mm new file mode 100644 index 0000000000..f45c2cc43e --- /dev/null +++ b/ios/ViewControllerMetal.mm @@ -0,0 +1,733 @@ +#import "AppDelegate.h" +#import "ViewControllerMetal.h" +#import "DisplayManager.h" +#include "Controls.h" +#import "iOSCoreAudio.h" + +#include "Common/Log.h" + +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "Common/GPU/Vulkan/VulkanContext.h" +#include "Common/GPU/Vulkan/VulkanRenderManager.h" +#include "Common/GPU/thin3d.h" +#include "Common/GPU/thin3d_create.h" +#include "Common/Data/Text/Parsers.h" +#include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Common/System/OSD.h" +#include "Common/System/NativeApp.h" +#include "Common/GraphicsContext.h" +#include "Common/Thread/ThreadUtil.h" + +#include "Core/Config.h" +#include "Core/ConfigValues.h" +#include "Core/System.h" +#include "Core/HLE/sceUsbCam.h" +#include "Core/HLE/sceUsbGps.h" + +// ViewController lifecycle: +// https://www.progressconcepts.com/blog/ios-appdelegate-viewcontroller-method-order/ + +// TODO: Share this between backends. +static uint32_t FlagsFromConfig() { + uint32_t flags; + if (g_Config.bVSync) { + flags = VULKAN_FLAG_PRESENT_FIFO; + } else { + flags = VULKAN_FLAG_PRESENT_MAILBOX | VULKAN_FLAG_PRESENT_IMMEDIATE; + } + return flags; +} + +enum class GraphicsContextState { + PENDING, + INITIALIZED, + FAILED_INIT, + SHUTDOWN, +}; + +class IOSVulkanContext : public GraphicsContext { +public: + IOSVulkanContext(); + ~IOSVulkanContext() { + delete g_Vulkan; + g_Vulkan = nullptr; + } + + bool InitAPI(); + + bool InitFromRenderThread(CAMetalLayer *layer, int desiredBackbufferSizeX, int desiredBackbufferSizeY); + void ShutdownFromRenderThread(); // Inverses InitFromRenderThread. + + void Shutdown(); + void Resize(); + + void *GetAPIContext() { return g_Vulkan; } + Draw::DrawContext *GetDrawContext() { return draw_; } + +private: + VulkanContext *g_Vulkan = nullptr; + Draw::DrawContext *draw_ = nullptr; + GraphicsContextState state_ = GraphicsContextState::PENDING; +}; + +IOSVulkanContext::IOSVulkanContext() {} + +bool IOSVulkanContext::InitFromRenderThread(CAMetalLayer *layer, int desiredBackbufferSizeX, int desiredBackbufferSizeY) { + INFO_LOG(Log::G3D, "IOSVulkanContext::InitFromRenderThread: desiredwidth=%d desiredheight=%d", desiredBackbufferSizeX, desiredBackbufferSizeY); + if (!g_Vulkan) { + ERROR_LOG(Log::G3D, "IOSVulkanContext::InitFromRenderThread: No Vulkan context"); + return false; + } + + VkResult res = g_Vulkan->InitSurface(WINDOWSYSTEM_METAL_EXT, (__bridge void *)layer, nullptr); + if (res != VK_SUCCESS) { + ERROR_LOG(Log::G3D, "g_Vulkan->InitSurface failed: '%s'", VulkanResultToString(res)); + return false; + } + + bool success = true; + if (g_Vulkan->InitSwapchain()) { + bool useMultiThreading = g_Config.bRenderMultiThreading; + if (g_Config.iInflightFrames == 1) { + useMultiThreading = false; + } + draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, useMultiThreading); + SetGPUBackend(GPUBackend::VULKAN); + success = draw_->CreatePresets(); // Doesn't fail, we ship the compiler. + _assert_msg_(success, "Failed to compile preset shaders"); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + renderManager->SetInflightFrames(g_Config.iInflightFrames); + success = renderManager->HasBackbuffers(); + } else { + success = false; + } + + INFO_LOG(Log::G3D, "IOSVulkanContext::Init completed, %s", success ? "successfully" : "but failed"); + if (!success) { + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); + g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyInstance(); + } + return success; +} + +void IOSVulkanContext::ShutdownFromRenderThread() { + INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown"); + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + delete draw_; + draw_ = nullptr; + g_Vulkan->WaitUntilQueueIdle(); + g_Vulkan->PerformPendingDeletes(); + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); + INFO_LOG(Log::G3D, "Done with ShutdownFromRenderThread"); +} + +void IOSVulkanContext::Shutdown() { + INFO_LOG(Log::G3D, "Calling NativeShutdownGraphics"); + g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyInstance(); + // We keep the g_Vulkan context around to avoid invalidating a ton of pointers around the app. + finalize_glslang(); + INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown completed"); +} + +void IOSVulkanContext::Resize() { + INFO_LOG(Log::G3D, "IOSVulkanContext::Resize begin (oldsize: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); + + g_Vulkan->UpdateFlags(FlagsFromConfig()); + + g_Vulkan->ReinitSurface(); + g_Vulkan->InitSwapchain(); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + INFO_LOG(Log::G3D, "IOSVulkanContext::Resize end (final size: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); +} + +bool IOSVulkanContext::InitAPI() { + INFO_LOG(Log::G3D, "IOSVulkanContext::Init"); + init_glslang(); + + g_LogOptions.breakOnError = true; + g_LogOptions.breakOnWarning = true; + g_LogOptions.msgBoxOnError = false; + + INFO_LOG(Log::G3D, "Creating Vulkan context"); + Version gitVer(PPSSPP_GIT_VERSION); + + std::string errorStr; + if (!VulkanLoad(&errorStr)) { + ERROR_LOG(Log::G3D, "Failed to load Vulkan driver library: %s", errorStr.c_str()); + state_ = GraphicsContextState::FAILED_INIT; + return false; + } + + if (!g_Vulkan) { + // TODO: Assert if g_Vulkan already exists here? + g_Vulkan = new VulkanContext(); + } + + VulkanContext::CreateInfo info{}; + info.app_name = "PPSSPP"; + info.app_ver = gitVer.ToInteger(); + info.flags = FlagsFromConfig(); + if (!g_Vulkan->CreateInstanceAndDevice(info)) { + delete g_Vulkan; + g_Vulkan = nullptr; + state_ = GraphicsContextState::FAILED_INIT; + return false; + } + + g_Vulkan->SetCbGetDrawSize([]() { + return VkExtent2D {(uint32_t)g_display.pixel_xres, (uint32_t)g_display.pixel_yres}; + }); + + INFO_LOG(Log::G3D, "Vulkan device created!"); + state_ = GraphicsContextState::INITIALIZED; + return true; +} + + +#pragma mark - +#pragma mark PPSSPPViewControllerMetal + +static std::atomic exitRenderLoop; +static std::atomic renderLoopRunning; +static std::thread g_renderLoopThread; + +@interface PPSSPPViewControllerMetal () { + ICadeTracker g_iCadeTracker; + TouchTracker g_touchTracker; + + IOSVulkanContext *graphicsContext; + LocationHelper *locationHelper; + CameraHelper *cameraHelper; +} + +@property (nonatomic) GCController *gameController __attribute__((weak_import)); +@property (strong, nonatomic) CMMotionManager *motionManager; +@property (strong, nonatomic) NSOperationQueue *accelerometerQueue; + +@end // @interface + +@implementation PPSSPPViewControllerMetal { + UIScreenEdgePanGestureRecognizer *mBackGestureRecognizer; +} + +- (id)init { + self = [super init]; + if (self) { + sharedViewController = self; + g_iCadeTracker.InitKeyMap(); + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil]; + } + self.accelerometerQueue = [[NSOperationQueue alloc] init]; + self.accelerometerQueue.name = @"AccelerometerQueue"; + self.accelerometerQueue.maxConcurrentOperationCount = 1; + return self; +} + +- (void)appWillTerminate:(NSNotification *)notification +{ + [self shutdown]; +} + +// Should be very similar to the Android one, probably mergeable. +void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLayer) { + SetCurrentThreadName("EmuThreadVulkan"); + INFO_LOG(Log::G3D, "Entering EmuThreadVulkan"); + + if (!graphicsContext) { + ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context."); + renderLoopRunning = false; + exitRenderLoop = false; + return; + } + + if (exitRenderLoop) { + WARN_LOG(Log::G3D, "runVulkanRenderLoop: ExitRenderLoop requested at start, skipping the whole thing."); + renderLoopRunning = false; + exitRenderLoop = false; + return; + } + + // This is up here to prevent race conditions, in case we pause during init. + renderLoopRunning = true; + + int desiredBackbufferSizeX = g_display.pixel_xres; + int desiredBackbufferSizeY = g_display.pixel_yres; + + //WARN_LOG(G3D, "runVulkanRenderLoop. desiredBackbufferSizeX=%d desiredBackbufferSizeY=%d", + // desiredBackbufferSizeX, desiredBackbufferSizeY); + + if (!graphicsContext->InitFromRenderThread(metalLayer, desiredBackbufferSizeX, desiredBackbufferSizeY)) { + // On Android, if we get here, really no point in continuing. + // The UI is supposed to render on any device both on OpenGL and Vulkan. If either of those don't work + // on a device, we blacklist it. Hopefully we should have already failed in InitAPI anyway and reverted to GL back then. + ERROR_LOG(Log::G3D, "Failed to initialize graphics context."); + System_Toast("Failed to initialize graphics context."); + + delete graphicsContext; + graphicsContext = nullptr; + renderLoopRunning = false; + return; + } + + if (!exitRenderLoop) { + if (!NativeInitGraphics(graphicsContext)) { + ERROR_LOG(Log::G3D, "Failed to initialize graphics."); + // Gonna be in a weird state here.. + } + graphicsContext->ThreadStart(); + while (!exitRenderLoop) { + NativeFrame(graphicsContext); + } + INFO_LOG(Log::G3D, "Leaving Vulkan main loop."); + } else { + INFO_LOG(Log::G3D, "Not entering main loop."); + } + + NativeShutdownGraphics(); + + graphicsContext->ThreadEnd(); + + // Shut the graphics context down to the same state it was in when we entered the render thread. + INFO_LOG(Log::G3D, "Shutting down graphics context..."); + graphicsContext->ShutdownFromRenderThread(); + renderLoopRunning = false; + exitRenderLoop = false; + + WARN_LOG(Log::G3D, "Render loop function exited."); +} + +- (bool)runVulkanRenderLoop { + INFO_LOG(Log::G3D, "runVulkanRenderLoop"); + + if (!graphicsContext) { + ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context."); + return false; + } + + if (g_renderLoopThread.joinable()) { + ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Already running"); + return false; + } + + CAMetalLayer *metalLayer = (CAMetalLayer *)self.view.layer; + g_renderLoopThread = std::thread(VulkanRenderLoop, graphicsContext, metalLayer); + return true; +} + +- (void)requestExitVulkanRenderLoop { + INFO_LOG(Log::G3D, "requestExitVulkanRenderLoop"); + + if (!renderLoopRunning) { + ERROR_LOG(Log::System, "Render loop already exited"); + return; + } + _assert_(g_renderLoopThread.joinable()); + exitRenderLoop = true; + g_renderLoopThread.join(); + _assert_(!g_renderLoopThread.joinable()); +} + +// These two are forwarded from the appDelegate +- (void)didBecomeActive { + INFO_LOG(Log::G3D, "didBecomeActive GL"); + if (self.motionManager.accelerometerAvailable) { + self.motionManager.accelerometerUpdateInterval = 1.0 / 60.0; + INFO_LOG(Log::G3D, "Starting accelerometer updates."); + + [self.motionManager startAccelerometerUpdatesToQueue:self.accelerometerQueue + withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { + if (error) { + NSLog(@"Accelerometer error: %@", error); + return; + } + ProcessAccelerometerData(accelerometerData); + }]; + } else { + INFO_LOG(Log::G3D, "No accelerometer available, not starting updates."); + } + // Spin up the emu thread. It will in turn spin up the Vulkan render thread + // on its own. + [self runVulkanRenderLoop]; +} + +- (void)willResignActive { + INFO_LOG(Log::G3D, "willResignActive GL"); + [self requestExitVulkanRenderLoop]; + + // Stop accelerometer updates + if (self.motionManager.accelerometerActive) { + INFO_LOG(Log::G3D, "Stopping accelerometer updates"); + [self.motionManager stopAccelerometerUpdates]; + } +} + +- (void)shutdown +{ + INFO_LOG(Log::System, "shutdown VK"); + + g_Config.Save("shutdown vk"); + + _dbg_assert_(sharedViewController != nil); + sharedViewController = nil; + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + self.gameController = nil; + + if (graphicsContext) { + graphicsContext->Shutdown(); + delete graphicsContext; + graphicsContext = NULL; + } +} + +- (void)dealloc +{ + INFO_LOG(Log::System, "dealloc VK"); +} + +- (void)loadView { + INFO_LOG(Log::G3D, "Creating metal view"); + + CGRect screenRect = [[UIScreen mainScreen] bounds]; + CGFloat screenWidth = screenRect.size.width; + CGFloat screenHeight = screenRect.size.height; + + PPSSPPMetalView *metalView = [[PPSSPPMetalView alloc] initWithFrame:CGRectMake(0, 0, screenWidth,screenHeight)]; + self.view = metalView; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + [self hideKeyboard]; + + [[DisplayManager shared] setupDisplayListener]; + + INFO_LOG(Log::System, "Metal viewDidLoad"); + + UIScreen* screen = [(AppDelegate*)[UIApplication sharedApplication].delegate screen]; + self.view.frame = [screen bounds]; + self.view.multipleTouchEnabled = YES; + graphicsContext = new IOSVulkanContext(); + + [[DisplayManager shared] updateResolution:[UIScreen mainScreen]]; + + if (!graphicsContext->InitAPI()) { + _assert_msg_(false, "Failed to init Vulkan"); + } + + if ([[GCController controllers] count] > 0) { + [self setupController:[[GCController controllers] firstObject]]; + } + + INFO_LOG(Log::G3D, "Detected size: %dx%d", g_display.pixel_xres, g_display.pixel_yres); + + cameraHelper = [[CameraHelper alloc] init]; + [cameraHelper setDelegate:self]; + + locationHelper = [[LocationHelper alloc] init]; + [locationHelper setDelegate:self]; + + // Initialize the motion manager for accelerometer control. + self.motionManager = [[CMMotionManager alloc] init]; +} + +// Allow device rotation to resize the swapchain +-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + // TODO: Handle resizing properly. +} + +- (UIView *)getView { + return [self view]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + INFO_LOG(Log::G3D, "viewWillAppear"); + self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + INFO_LOG(Log::G3D, "viewWillDisappear"); +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear: animated]; + INFO_LOG(Log::G3D, "viewWillDisappear"); +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + INFO_LOG(Log::G3D, "viewDidAppear"); + [self hideKeyboard]; + [self updateGesture]; + +} + +- (BOOL)prefersHomeIndicatorAutoHidden { + if (g_Config.iAppSwitchMode == (int)AppSwitchMode::DOUBLE_SWIPE_INDICATOR) { + return NO; + } else { + return YES; + } +} + +- (void)appSwitchModeChanged +{ + [self setNeedsUpdateOfHomeIndicatorAutoHidden]; +} + +- (void)shareText:(NSString *)text { + NSArray *items = @[text]; + UIActivityViewController * viewController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:viewController animated:YES completion:nil]; + }); +} + +extern float g_safeInsetLeft; +extern float g_safeInsetRight; +extern float g_safeInsetTop; +extern float g_safeInsetBottom; + +- (void)viewSafeAreaInsetsDidChange { + if (@available(iOS 11.0, *)) { + [super viewSafeAreaInsetsDidChange]; + // we use 0.0f instead of safeAreaInsets.bottom because the bottom overlay isn't disturbing (for now) + g_safeInsetLeft = self.view.safeAreaInsets.left; + g_safeInsetRight = self.view.safeAreaInsets.right; + g_safeInsetTop = self.view.safeAreaInsets.top; + g_safeInsetBottom = 0.0f; + } +} + +// Enables tapping for edge area. +-(UIRectEdge)preferredScreenEdgesDeferringSystemGestures +{ + if (GetUIState() == UISTATE_INGAME) { + // In-game, we need all the control we can get. Though, we could possibly + // allow the top edge? + INFO_LOG(Log::System, "Defer system gestures on all edges"); + return UIRectEdgeAll; + } else { + INFO_LOG(Log::System, "Allow system gestures on the bottom"); + // Allow task switching gestures to take precedence, without causing + // scroll events in the UI. + return UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeRight; + } +} + +- (void)uiStateChanged +{ + [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; + [self hideKeyboard]; + [self updateGesture]; +} + +- (void)updateGesture { + INFO_LOG(Log::System, "Updating swipe gesture."); + + if (mBackGestureRecognizer) { + INFO_LOG(Log::System, "Removing swipe gesture."); + [[self view] removeGestureRecognizer:mBackGestureRecognizer]; + mBackGestureRecognizer = nil; + } + + if (GetUIState() != UISTATE_INGAME) { + INFO_LOG(Log::System, "Adding swipe gesture."); + mBackGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:) ]; + [mBackGestureRecognizer setEdges:UIRectEdgeLeft]; + [[self view] addGestureRecognizer:mBackGestureRecognizer]; + } +} + +- (void)bindDefaultFBO +{ + // Do nothing +} + +- (NSUInteger)supportedInterfaceOrientations +{ + return UIInterfaceOrientationMaskLandscape; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + g_touchTracker.Began(touches, self.view); +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + g_touchTracker.Moved(touches, self.view); +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + g_touchTracker.Ended(touches, self.view); +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ + g_touchTracker.Cancelled(touches, self.view); +} + +- (void)buttonDown:(iCadeState)button +{ + g_iCadeTracker.ButtonDown(button); +} + +- (void)buttonUp:(iCadeState)button +{ + g_iCadeTracker.ButtonUp(button); +} + +// See PPSSPPUIApplication.mm for the other method +#if PPSSPP_PLATFORM(IOS_APP_STORE) + +- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesBegan(presses, event); +} + +- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesEnded(presses, event); +} + +- (void)pressesCancelled:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesEnded(presses, event); +} + +#endif + +- (void)controllerDidConnect:(NSNotification *)note +{ + if (![[GCController controllers] containsObject:self.gameController]) self.gameController = nil; + + if (self.gameController != nil) return; // already have a connected controller + + [self setupController:(GCController *)note.object]; +} + +- (void)controllerDidDisconnect:(NSNotification *)note +{ + if (self.gameController == note.object) { + self.gameController = nil; + + if ([[GCController controllers] count] > 0) { + [self setupController:[[GCController controllers] firstObject]]; + } + } +} + +- (void)setupController:(GCController *)controller +{ + self.gameController = controller; + if (!InitController(controller)) { + self.gameController = nil; + } +} + +- (void)startVideo:(int)width height:(int)height { + [cameraHelper startVideo:width h:height]; +} + +- (void)stopVideo { + [cameraHelper stopVideo]; +} + +- (void)PushCameraImageIOS:(long long)len buffer:(unsigned char*)data { + Camera::pushCameraImage(len, data); +} + +- (void)startLocation { + [locationHelper startLocationUpdates]; +} + +- (void)stopLocation { + [locationHelper stopLocationUpdates]; +} + +- (void)SetGpsDataIOS:(CLLocation *)newLocation { + GPS::setGpsData((long long)newLocation.timestamp.timeIntervalSince1970, + newLocation.horizontalAccuracy/5.0, + newLocation.coordinate.latitude, newLocation.coordinate.longitude, + newLocation.altitude, + MAX(newLocation.speed * 3.6, 0.0), /* m/s to km/h */ + 0 /* bearing */); +} + +- (void)handleSwipeFrom:(UIScreenEdgePanGestureRecognizer *)recognizer +{ + if (recognizer.state == UIGestureRecognizerStateEnded) { + KeyInput key; + key.flags = KEY_DOWN | KEY_UP; + key.keyCode = NKCODE_BACK; + key.deviceId = DEVICE_ID_TOUCH; + NativeKey(key); + INFO_LOG(Log::System, "Detected back swipe"); + } +} +// The below is inspired by https://stackoverflow.com/questions/7253477/how-to-display-the-iphone-ipad-keyboard-over-a-full-screen-opengl-es-app +// It's a bit limited but good enough. + +-(void) deleteBackward { + KeyInput input{}; + input.deviceId = DEVICE_ID_KEYBOARD; + input.flags = KEY_DOWN | KEY_UP; + input.keyCode = NKCODE_DEL; + NativeKey(input); + INFO_LOG(Log::System, "Backspace"); +} + +-(BOOL) hasText +{ + return YES; +} + +-(void) insertText:(NSString *)text +{ + std::string str([text UTF8String]); + INFO_LOG(Log::System, "Chars: %s", str.c_str()); + SendKeyboardChars(str); +} + +-(BOOL) canBecomeFirstResponder +{ + return YES; +} + +-(void) showKeyboard { + dispatch_async(dispatch_get_main_queue(), ^{ + [self becomeFirstResponder]; + }); +} + +-(void) hideKeyboard { + dispatch_async(dispatch_get_main_queue(), ^{ + [self resignFirstResponder]; + }); +} + +@end + +@implementation PPSSPPMetalView + +/** Returns a Metal-compatible layer. */ ++(Class) layerClass { return [CAMetalLayer class]; } + +@end diff --git a/ios/assets.xcassets/AppIcon.appiconset/Contents.json b/ios/assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..d4884cbc70 --- /dev/null +++ b/ios/assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "icon_backfill_1024.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/assets.xcassets/AppIcon.appiconset/icon_backfill_1024.png b/ios/assets.xcassets/AppIcon.appiconset/icon_backfill_1024.png new file mode 100644 index 0000000000..376d4eba79 Binary files /dev/null and b/ios/assets.xcassets/AppIcon.appiconset/icon_backfill_1024.png differ diff --git a/ios/assets.xcassets/AppIconGold.appiconset/Contents.json b/ios/assets.xcassets/AppIconGold.appiconset/Contents.json new file mode 100644 index 0000000000..bfce343b0b --- /dev/null +++ b/ios/assets.xcassets/AppIconGold.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "icon_gold_backfill_1024.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/assets.xcassets/AppIconGold.appiconset/icon_gold_backfill_1024.png b/ios/assets.xcassets/AppIconGold.appiconset/icon_gold_backfill_1024.png new file mode 100644 index 0000000000..8c87813b12 Binary files /dev/null and b/ios/assets.xcassets/AppIconGold.appiconset/icon_gold_backfill_1024.png differ diff --git a/ios/assets.xcassets/Contents.json b/ios/assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/ios/assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/assets/Icon-72.png b/ios/assets/Icon-72.png deleted file mode 100644 index 7d7eca138c..0000000000 Binary files a/ios/assets/Icon-72.png and /dev/null differ diff --git a/ios/assets/Icon-72@2x.png b/ios/assets/Icon-72@2x.png deleted file mode 100644 index c9d9095aec..0000000000 Binary files a/ios/assets/Icon-72@2x.png and /dev/null differ diff --git a/ios/assets/Icon-72@3x.png b/ios/assets/Icon-72@3x.png deleted file mode 100644 index efdde28b01..0000000000 Binary files a/ios/assets/Icon-72@3x.png and /dev/null differ diff --git a/ios/assets/Icon.png b/ios/assets/Icon.png deleted file mode 100644 index 44625336c5..0000000000 Binary files a/ios/assets/Icon.png and /dev/null differ diff --git a/ios/assets/Icon@2x.png b/ios/assets/Icon@2x.png deleted file mode 100644 index 9bcb28cc3d..0000000000 Binary files a/ios/assets/Icon@2x.png and /dev/null differ diff --git a/ios/assets/Icon@3x.png b/ios/assets/Icon@3x.png deleted file mode 100644 index 227eccb081..0000000000 Binary files a/ios/assets/Icon@3x.png and /dev/null differ diff --git a/ios/iOSCoreAudio.h b/ios/iOSCoreAudio.h index a3c70ccbfc..944e0e81dc 100644 --- a/ios/iOSCoreAudio.h +++ b/ios/iOSCoreAudio.h @@ -19,4 +19,9 @@ // Originally written by jtraynham void iOSCoreAudioInit(); -void iOSCoreAudioShutdown(); \ No newline at end of file +void iOSCoreAudioShutdown(); + +// Ignore mute switch when connected to external display. +// Also, obey other settings. +void iOSCoreAudioUpdateSession(); +void iOSCoreAudioSetDisplayConnected(bool connected); \ No newline at end of file diff --git a/ios/iOSCoreAudio.mm b/ios/iOSCoreAudio.mm index 8743ab7953..fb1ea97f1c 100644 --- a/ios/iOSCoreAudio.mm +++ b/ios/iOSCoreAudio.mm @@ -21,14 +21,58 @@ #include "iOSCoreAudio.h" #include "Common/Log.h" +#include "Core/Config.h" #include #import - #define SAMPLE_RATE 44100 -AudioComponentInstance audioInstance = nil; +static AudioComponentInstance audioInstance = nil; +static bool g_displayConnected = false; + +void iOSCoreAudioUpdateSession() { + NSError *error = nil; + if (g_displayConnected) { + INFO_LOG(Log::Audio, "Display connected, setting Playback mode"); + // Special handling when a display is connected. Always exclusive. + // Let's revisit this later. + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]; + return; + } + + INFO_LOG(Log::Audio, "RespectSilentMode: %d MixWithOthers: %d", g_Config.bAudioRespectSilentMode, g_Config.bAudioMixWithOthers); + + // Hacky hack to force iOS to re-evaluate. + // Switching from CatogoryPlayback to CategoryPlayback with an option otherwise does nothing. + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAudioProcessing error:&error]; + + // Here, we apply the settings. + const bool mixWithOthers = g_Config.bAudioMixWithOthers; + if (g_Config.bAudioMixWithOthers) { + if (g_Config.bAudioRespectSilentMode) { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error]; + } else { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error]; + } + } else { + if (g_Config.bAudioRespectSilentMode) { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategorySoloAmbient error:&error]; + } else { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:0 error:&error]; + } + // Can't achieve exclusive + respect silent mode + } + + if (error) { + NSLog(@"%@", error); + } +} + +void iOSCoreAudioSetDisplayConnected(bool connected) { + g_displayConnected = connected; + iOSCoreAudioUpdateSession(); +} int NativeMix(short *audio, int numSamples, int sampleRate); @@ -65,10 +109,12 @@ OSStatus iOSCoreAudioCallback(void *inRefCon, void iOSCoreAudioInit() { + iOSCoreAudioUpdateSession(); + NSError *error = nil; AVAudioSession *session = [AVAudioSession sharedInstance]; if (![session setActive:YES error:&error]) { - ERROR_LOG(SYSTEM, "Failed to activate AVFoundation audio session"); + ERROR_LOG(Log::System, "Failed to activate AVFoundation audio session"); if (error.localizedDescription) { NSLog(@"%@", error.localizedDescription); } @@ -76,84 +122,86 @@ void iOSCoreAudioInit() NSLog(@"%@", error.localizedFailureReason); } } - - if (!audioInstance) { - OSErr err; - - // first, grab the default output - AudioComponentDescription defaultOutputDescription; - defaultOutputDescription.componentType = kAudioUnitType_Output; - defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO; - defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple; - defaultOutputDescription.componentFlags = 0; - defaultOutputDescription.componentFlagsMask = 0; - AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription); - - // create our instance - err = AudioComponentInstanceNew(defaultOutput, &audioInstance); - if (err != noErr) { - audioInstance = nil; - return; - } - - // create our callback so we can give it the audio data - AURenderCallbackStruct input; - input.inputProc = iOSCoreAudioCallback; - input.inputProcRefCon = NULL; - err = AudioUnitSetProperty(audioInstance, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, - 0, - &input, - sizeof(input)); - if (err != noErr) { - AudioComponentInstanceDispose(audioInstance); - audioInstance = nil; - return; - } - - // setup the audio format we'll be using (stereo pcm) - AudioStreamBasicDescription streamFormat; - memset(&streamFormat, 0, sizeof(streamFormat)); - streamFormat.mSampleRate = SAMPLE_RATE; - streamFormat.mFormatID = kAudioFormatLinearPCM; - streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; - streamFormat.mBitsPerChannel = sizeof(short) * 8; - streamFormat.mChannelsPerFrame = 2; - streamFormat.mFramesPerPacket = 1; - streamFormat.mBytesPerFrame = (streamFormat.mBitsPerChannel / 8) * streamFormat.mChannelsPerFrame; - streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket; - err = AudioUnitSetProperty(audioInstance, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 0, - &streamFormat, - sizeof(AudioStreamBasicDescription)); - if (err != noErr) { - AudioComponentInstanceDispose(audioInstance); - audioInstance = nil; - return; - } - - // k, all setup, so init - err = AudioUnitInitialize(audioInstance); - if (err != noErr) { - AudioComponentInstanceDispose(audioInstance); - audioInstance = nil; - return; - } - - // finally start playback - err = AudioOutputUnitStart(audioInstance); - if (err != noErr) { - AudioUnitUninitialize(audioInstance); - AudioComponentInstanceDispose(audioInstance); - audioInstance = nil; - return; - } - - // we're good to go + + if (audioInstance) { + // Already running + return; } + OSErr err; + + // first, grab the default output + AudioComponentDescription defaultOutputDescription; + defaultOutputDescription.componentType = kAudioUnitType_Output; + defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO; + defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple; + defaultOutputDescription.componentFlags = 0; + defaultOutputDescription.componentFlagsMask = 0; + AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription); + + // create our instance + err = AudioComponentInstanceNew(defaultOutput, &audioInstance); + if (err != noErr) { + audioInstance = nil; + return; + } + + // create our callback so we can give it the audio data + AURenderCallbackStruct input; + input.inputProc = iOSCoreAudioCallback; + input.inputProcRefCon = NULL; + err = AudioUnitSetProperty(audioInstance, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + &input, + sizeof(input)); + if (err != noErr) { + AudioComponentInstanceDispose(audioInstance); + audioInstance = nil; + return; + } + + // setup the audio format we'll be using (stereo pcm) + AudioStreamBasicDescription streamFormat; + memset(&streamFormat, 0, sizeof(streamFormat)); + streamFormat.mSampleRate = SAMPLE_RATE; + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + streamFormat.mBitsPerChannel = sizeof(short) * 8; + streamFormat.mChannelsPerFrame = 2; + streamFormat.mFramesPerPacket = 1; + streamFormat.mBytesPerFrame = (streamFormat.mBitsPerChannel / 8) * streamFormat.mChannelsPerFrame; + streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket; + err = AudioUnitSetProperty(audioInstance, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &streamFormat, + sizeof(AudioStreamBasicDescription)); + if (err != noErr) { + AudioComponentInstanceDispose(audioInstance); + audioInstance = nil; + return; + } + + // k, all setup, so init + err = AudioUnitInitialize(audioInstance); + if (err != noErr) { + AudioComponentInstanceDispose(audioInstance); + audioInstance = nil; + return; + } + + // finally start playback + err = AudioOutputUnitStart(audioInstance); + if (err != noErr) { + AudioUnitUninitialize(audioInstance); + AudioComponentInstanceDispose(audioInstance); + audioInstance = nil; + return; + } + + // we're good to go } void iOSCoreAudioShutdown() diff --git a/ios/iosbundle.sh b/ios/iosbundle.sh new file mode 100755 index 0000000000..822263a07f --- /dev/null +++ b/ios/iosbundle.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +echo "iosbundle.sh params 0: ${0} 1: ${1} 2: ${2}" +echo $(pwd) + +PPSSPP="${1}" + +GIT_VERSION_FILE="${2}/git-version.cpp" +if [ ! -f "${GIT_VERSION_FILE}" ]; then + echo "iosbundle.sh: No git-version.cpp file: ${GIT_VERSION_FILE}" + exit 0 +fi +echo "GIT_VERSION_FILE: ${GIT_VERSION_FILE}" + +GIT_VERSION_LINE=$(grep "PPSSPP_GIT_VERSION = " $GIT_VERSION_FILE) + +SHORT_VERSION_MATCH='.*"v([0-9\.]+(-[0-9]+)?).*";' +LONG_VERSION_MATCH='.*"v(.*)";' +FULL_VERSION=$(echo ${GIT_VERSION_LINE} | perl -pe "s/${LONG_VERSION_MATCH}/\$1/g") + +echo "Full version string: $FULL_VERSION" + +# Crunches to version number to something that XCode will validate. +SHORT_VERSION=$(perl $2/../ios/version-transform.pl $FULL_VERSION) +#LONG_VERSION=$FULL_VERSION + +# Turns out we can't have anything except numbers or dots, or XCode will crash +# during validation. So for now, let's set them to the same thing. Not really sure +# why you'd differentiate. +LONG_VERSION=$SHORT_VERSION + +echo "Writing versions to Info.plist. Short: $SHORT_VERSION Long: $LONG_VERSION" + +if [[ "${GIT_VERSION_LINE}" =~ ^${SHORT_VERSION_MATCH}$ ]]; then + plutil -replace CFBundleShortVersionString -string $SHORT_VERSION ${PPSSPP}/Info.plist + plutil -replace CFBundleVersion -string $LONG_VERSION ${PPSSPP}/Info.plist +else + plutil -replace CFBundleShortVersionString -string "" ${PPSSPP}/Info.plist + plutil -replace CFBundleVersion -string "" ${PPSSPP}/Info.plist +fi + +echo "iosbundle.sh: Updated ${PPSSPP}/Info.plist" diff --git a/ios/macbundle.sh b/ios/macbundle.sh index eed70114e9..dbb7412638 100644 --- a/ios/macbundle.sh +++ b/ios/macbundle.sh @@ -4,7 +4,7 @@ PPSSPP="${1}" PPSSPPiOS="${PPSSPP}/PPSSPP" if [ ! -f "${PPSSPPiOS}" ]; then - echo "No such file: ${PPSSPPiOS}!" + echo "macbundle.sh: No such file: ${PPSSPPiOS}!" exit 0 fi @@ -18,3 +18,5 @@ else plutil -replace CFBundleShortVersionString -string "" ${PPSSPP}/Info.plist plutil -replace CFBundleVersion -string "" ${PPSSPP}/Info.plist fi + +echo "macbundle.sh: Updated ${PPSSPP}/Info.plist" \ No newline at end of file diff --git a/ios/main.mm b/ios/main.mm index f9c0c11430..6477c6b0c3 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -1,4 +1,10 @@ // main.mm boilerplate +// +// Overview +// +// main.mm: JIT enablement, starting the next step +// AppDelegate.mm: Runs NativeInit, launches the main ViewController +// ViewController.mm: The main application window #import #import @@ -18,6 +24,7 @@ #import "AppDelegate.h" #import "PPSSPPUIApplication.h" #import "ViewController.h" +#import "iOSCoreAudio.h" #include "Common/MemoryUtil.h" #include "Common/System/NativeApp.h" @@ -25,10 +32,14 @@ #include "Common/System/Request.h" #include "Common/StringUtils.h" #include "Common/Profiler/Profiler.h" +#include "Common/Thread/ThreadUtil.h" #include "Core/Config.h" #include "Common/Log.h" #include "UI/DarwinFileSystemServices.h" +// Compile out all the hackery in app store builds. +#if !PPSSPP_PLATFORM(IOS_APP_STORE) + struct cs_blob_index { uint32_t type; uint32_t offset; @@ -269,6 +280,7 @@ bool jb_enable_ptrace_hack(void) { return true; } +#endif float g_safeInsetLeft = 0.0; float g_safeInsetRight = 0.0; @@ -303,7 +315,7 @@ std::vector System_GetPropertyStringVec(SystemProperty prop) { } } -int System_GetPropertyInt(SystemProperty prop) { +int64_t System_GetPropertyInt(SystemProperty prop) { switch (prop) { case SYSPROP_AUDIO_SAMPLE_RATE: return 44100; @@ -335,12 +347,21 @@ float System_GetPropertyFloat(SystemProperty prop) { bool System_GetPropertyBool(SystemProperty prop) { switch (prop) { + case SYSPROP_HAS_FILE_BROWSER: + return true; + case SYSPROP_HAS_FOLDER_BROWSER: + return true; case SYSPROP_HAS_OPEN_DIRECTORY: return false; case SYSPROP_HAS_BACK_BUTTON: return false; case SYSPROP_HAS_ACCELEROMETER: return true; + case SYSPROP_HAS_KEYBOARD: + return true; + case SYSPROP_KEYBOARD_IS_SOFT: + // If a hardware keyboard is connected, and we add support, we could return false here. + return true; case SYSPROP_APP_GOLD: #ifdef GOLD return true; @@ -349,6 +370,12 @@ bool System_GetPropertyBool(SystemProperty prop) { #endif case SYSPROP_CAN_JIT: return g_jitAvailable; + case SYSPROP_LIMITED_FILE_BROWSING: +#if PPSSPP_PLATFORM(IOS_APP_STORE) + return true; +#else + return false; // But will return true in app store builds. +#endif #ifndef HTTPS_NOT_AVAILABLE case SYSPROP_SUPPORTS_HTTPS: return true; @@ -360,12 +387,40 @@ bool System_GetPropertyBool(SystemProperty prop) { void System_Notify(SystemNotification notification) { switch (notification) { + case SystemNotification::APP_SWITCH_MODE_CHANGED: + dispatch_async(dispatch_get_main_queue(), ^{ + if (sharedViewController) { + [sharedViewController appSwitchModeChanged]; + } + }); + break; + case SystemNotification::UI_STATE_CHANGED: + dispatch_async(dispatch_get_main_queue(), ^{ + if (sharedViewController) { + [sharedViewController uiStateChanged]; + } + }); + break; + case SystemNotification::AUDIO_MODE_CHANGED: + dispatch_async(dispatch_get_main_queue(), ^{ + iOSCoreAudioUpdateSession(); + }); + break; + default: + break; } } -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { switch (type) { + case SystemRequestType::RESTART_APP: + dispatch_async(dispatch_get_main_queue(), ^{ + [(AppDelegate *)[[UIApplication sharedApplication] delegate] restart:param1.c_str()]; + }); + break; + case SystemRequestType::EXIT_APP: + // NOTE: on iOS, this is considered a crash and not a valid way to exit. exit(0); // The below seems right, but causes hangs. See #12140. // dispatch_async(dispatch_get_main_queue(), ^{ @@ -382,8 +437,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string g_requestManager.PostSystemFailure(requestId); } }; - DarwinFileSystemServices services; - services.presentDirectoryPanel(callback, /* allowFiles = */ true, /* allowDirectories = */ false); + DarwinFileSystemServices::presentDirectoryPanel(callback, /* allowFiles = */ true, /* allowDirectories = */ false); return true; } case SystemRequestType::BROWSE_FOR_FOLDER: @@ -395,25 +449,23 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string g_requestManager.PostSystemFailure(requestId); } }; - DarwinFileSystemServices services; - services.presentDirectoryPanel(callback, /* allowFiles = */ false, /* allowDirectories = */ true); + DarwinFileSystemServices::presentDirectoryPanel(callback, /* allowFiles = */ false, /* allowDirectories = */ true); return true; } case SystemRequestType::CAMERA_COMMAND: if (!strncmp(param1.c_str(), "startVideo", 10)) { int width = 0, height = 0; sscanf(param1.c_str(), "startVideo_%dx%d", &width, &height); - setCameraSize(width, height); - startVideo(); + [sharedViewController startVideo:width height:height]; } else if (!strcmp(param1.c_str(), "stopVideo")) { - stopVideo(); + [sharedViewController stopVideo]; } return true; case SystemRequestType::GPS_COMMAND: if (param1 == "open") { - startLocation(); + [sharedViewController startLocation]; } else if (param1 == "close") { - stopLocation(); + [sharedViewController stopLocation]; } return true; case SystemRequestType::SHARE_TEXT: @@ -422,6 +474,39 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string [sharedViewController shareText:text]; return true; } + case SystemRequestType::NOTIFY_UI_EVENT: + { + switch ((UIEventNotification)param3) { + case UIEventNotification::POPUP_CLOSED: + [sharedViewController hideKeyboard]; + break; + case UIEventNotification::TEXT_GOTFOCUS: + [sharedViewController showKeyboard]; + break; + case UIEventNotification::TEXT_LOSTFOCUS: + [sharedViewController hideKeyboard]; + break; + default: + break; + } + return true; + } +/* + // Not 100% sure the threading is right + case SystemRequestType::COPY_TO_CLIPBOARD: + { + @autoreleasepool { + [UIPasteboard generalPasteboard].string = @(param1.c_str()); + return 0; + } + } +*/ + case SystemRequestType::SET_KEEP_SCREEN_BRIGHT: + dispatch_async(dispatch_get_main_queue(), ^{ + INFO_LOG(Log::System, "SET_KEEP_SCREEN_BRIGHT: %d", (int)param3); + [[UIApplication sharedApplication] setIdleTimerDisabled: (param3 ? YES : NO)]; + }); + return true; default: return false; } @@ -430,9 +515,21 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string void System_Toast(std::string_view text) {} void System_AskForPermission(SystemPermission permission) {} -PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } +void System_LaunchUrl(LaunchUrlType urlType, const char *url) +{ + NSURL *nsUrl = [NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]; + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIApplication sharedApplication] openURL:nsUrl options:@{} completionHandler:nil]; + }); +} +PermissionStatus System_GetPermissionStatus(SystemPermission permission) { + return PERMISSION_STATUS_GRANTED; +} + +#if !PPSSPP_PLATFORM(IOS_APP_STORE) FOUNDATION_EXTERN void AudioServicesPlaySystemSoundWithVibration(unsigned long, objc_object*, NSDictionary*); +#endif BOOL SupportsTaptic() { // we're on an iOS version that cannot instantiate UISelectionFeedbackGenerator, so no. @@ -459,6 +556,7 @@ void System_Vibrate(int mode) { } [app.feedbackGenerator selectionChanged]; } else { +#if !PPSSPP_PLATFORM(IOS_APP_STORE) NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; NSArray *pattern = @[@YES, @30, @NO, @2]; @@ -466,43 +564,48 @@ void System_Vibrate(int mode) { dictionary[@"Intensity"] = @2; AudioServicesPlaySystemSoundWithVibration(kSystemSoundID_Vibrate, nil, dictionary); +#endif } } int main(int argc, char *argv[]) { + // SetCurrentThreadName("MainThread"); + version = [[[UIDevice currentDevice] systemVersion] UTF8String]; + if (1 != sscanf(version.c_str(), "%d", &g_iosVersionMajor)) { + // Just set it to 14.0 if the parsing fails for whatever reason. + g_iosVersionMajor = 14; + } + +#if PPSSPP_PLATFORM(IOS_APP_STORE) + g_jitAvailable = false; +#else // Hacky hacks to try to enable JIT by pretending to be a debugger. csops = reinterpret_cast(dlsym(dlopen(nullptr, RTLD_LAZY), "csops")); exc_server = reinterpret_cast(dlsym(dlopen(NULL, RTLD_LAZY), "exc_server")); ptrace = reinterpret_cast(dlsym(dlopen(NULL, RTLD_LAZY), "ptrace")); // see https://github.com/hrydgard/ppsspp/issues/11905 + if (jb_spawn_ptrace_child(argc, argv)) { + INFO_LOG(Log::System, "JIT: ptrace() child spawn trick\n"); + } else if (jb_has_jit_entitlement()) { + INFO_LOG(Log::System, "JIT: found entitlement\n"); + } else if (jb_has_cs_disabled()) { + INFO_LOG(Log::System, "JIT: CS_KILL disabled\n"); + } else if (jb_has_cs_execseg_allow_unsigned()) { + INFO_LOG(Log::System, "JIT: CS_EXECSEG_ALLOW_UNSIGNED set\n"); + } else if (jb_enable_ptrace_hack()) { + INFO_LOG(Log::System, "JIT: ptrace() hack supported\n"); + } else { + INFO_LOG(Log::System, "JIT: ptrace() hack failed\n"); + g_jitAvailable = false; + } + // Tried checking for JIT support here with AllocateExecutableMemory and ProtectMemoryPages, // but it just succeeds, and then fails when you try to execute from it. // So, we'll just resort to a version check. - - version = [[[UIDevice currentDevice] systemVersion] UTF8String]; - if (2 != sscanf(version.c_str(), "%d", &g_iosVersionMajor)) { - // Just set it to 14.0 if the parsing fails for whatever reason. - g_iosVersionMajor = 14; - } - - if (jb_spawn_ptrace_child(argc, argv)) { - INFO_LOG(SYSTEM, "JIT: ptrace() child spawn trick\n"); - } else if (jb_has_jit_entitlement()) { - INFO_LOG(SYSTEM, "JIT: found entitlement\n"); - } else if (jb_has_cs_disabled()) { - INFO_LOG(SYSTEM, "JIT: CS_KILL disabled\n"); - } else if (jb_has_cs_execseg_allow_unsigned()) { - INFO_LOG(SYSTEM, "JIT: CS_EXECSEG_ALLOW_UNSIGNED set\n"); - } else if (jb_enable_ptrace_hack()) { - INFO_LOG(SYSTEM, "JIT: ptrace() hack supported\n"); - } else { - INFO_LOG(SYSTEM, "JIT: ptrace() hack failed\n"); - g_jitAvailable = false; - } - + // TODO: This seems outdated. /* if (g_iosVersionMajor > 14 || (g_iosVersionMajor == 14 && g_iosVersionMinor >= 4)) { g_jitAvailable = false; @@ -510,15 +613,16 @@ int main(int argc, char *argv[]) g_jitAvailable = true; } */ - - PROFILE_INIT(); +#endif // Ignore sigpipe. if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { perror("Unable to ignore SIGPIPE"); } + PROFILE_INIT(); @autoreleasepool { return UIApplicationMain(argc, argv, NSStringFromClass([PPSSPPUIApplication class]), NSStringFromClass([AppDelegate class])); } } + diff --git a/ios/version-transform.pl b/ios/version-transform.pl new file mode 100644 index 0000000000..9a4ad23de1 --- /dev/null +++ b/ios/version-transform.pl @@ -0,0 +1,36 @@ +# Used to convert git describe strings like 1.17.1-421-g0100c6b32b +# to three dot-separated integers, as iOS wants for the short version. + +$version = $ARGV[0]; + +# Strip a "v" if the version starts with it. +$version =~ s/^v//; + +# Use multiple regexes to parse the various formats we may encounter. +# I don't know perl better than this. + +if ($version =~ /^(\d+)\.(\d+)\.(\d+)-(\d+)/) { + my $major = $1 * 10000 + $2; + my $minor = $3; + my $rev = $4; + print $major . "." . $minor . "." . $rev . "\n"; # Output: 1017.1.421 + exit +} + +if ($version =~ /^(\d+)\.(\d+)\.(\d+)/) { + my $major = $1 * 10000 + $2; + my $minor = $3; + my $rev = "0"; + print $major . "." . $minor . "." . $rev . "\n"; # Output: 1017.0.0 + exit +} + +if ($version =~ /^(\d+)\.(\d+)/) { + my $major = $1 * 10000 + $2; + my $minor = "0"; + my $rev = "0"; + print $major . "." . $minor . "." . $rev . "\n"; # Output: 1017.0.0 + exit +} + +die($version) \ No newline at end of file diff --git a/libretro/LibretroD3D11Context.cpp b/libretro/LibretroD3D11Context.cpp index 2a9da24dc4..5e1c6ab953 100644 --- a/libretro/LibretroD3D11Context.cpp +++ b/libretro/LibretroD3D11Context.cpp @@ -23,18 +23,18 @@ void LibretroD3D11Context::CreateDrawContext() { std::vector adapterNames; if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&d3d11_) || !d3d11_) { - ERROR_LOG(G3D, "Failed to get HW rendering interface!\n"); + ERROR_LOG(Log::G3D, "Failed to get HW rendering interface!\n"); return; } if (d3d11_->interface_version != RETRO_HW_RENDER_INTERFACE_D3D11_VERSION) { - ERROR_LOG(G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_D3D11_VERSION, d3d11_->interface_version); + ERROR_LOG(Log::G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_D3D11_VERSION, d3d11_->interface_version); return; } // Reject lower feature levels. We have D3D9 for these ancient GPUs. if (d3d11_->featureLevel < D3D_FEATURE_LEVEL_10_0) { - ERROR_LOG(G3D, "D3D11 featureLevel not high enough - rejecting!\n"); + ERROR_LOG(Log::G3D, "D3D11 featureLevel not high enough - rejecting!\n"); return; } diff --git a/libretro/LibretroGLContext.cpp b/libretro/LibretroGLContext.cpp index 240b3e1e1a..45a33eb69b 100644 --- a/libretro/LibretroGLContext.cpp +++ b/libretro/LibretroGLContext.cpp @@ -8,7 +8,7 @@ #include "libretro/LibretroGLContext.h" bool LibretroGLContext::Init() { - if (!LibretroHWRenderContext::Init(true)) + if (!LibretroHWRenderContext::Init(false)) return false; g_Config.iGPUBackend = (int)GPUBackend::OPENGL; diff --git a/libretro/LibretroGLCoreContext.cpp b/libretro/LibretroGLCoreContext.cpp index 54e324c4c7..f2c9306744 100644 --- a/libretro/LibretroGLCoreContext.cpp +++ b/libretro/LibretroGLCoreContext.cpp @@ -8,7 +8,7 @@ #include "libretro/LibretroGLCoreContext.h" bool LibretroGLCoreContext::Init() { - if (!LibretroHWRenderContext::Init(true)) + if (!LibretroHWRenderContext::Init(false)) return false; g_Config.iGPUBackend = (int)GPUBackend::OPENGL; @@ -19,7 +19,7 @@ void LibretroGLCoreContext::CreateDrawContext() { if (!glewInitDone) { #if !PPSSPP_PLATFORM(IOS) && !defined(USING_GLES2) if (glewInit() != GLEW_OK) { - ERROR_LOG(G3D, "glewInit() failed.\n"); + ERROR_LOG(Log::G3D, "glewInit() failed.\n"); return; } #endif diff --git a/libretro/LibretroGraphicsContext.cpp b/libretro/LibretroGraphicsContext.cpp index afd93be889..91d953b13c 100644 --- a/libretro/LibretroGraphicsContext.cpp +++ b/libretro/LibretroGraphicsContext.cpp @@ -2,7 +2,6 @@ #include "libretro/LibretroGraphicsContext.h" #include "libretro/LibretroGLContext.h" #include "libretro/LibretroGLCoreContext.h" -#include "libretro/libretro.h" #include "libretro/LibretroVulkanContext.h" #ifdef _WIN32 #include "libretro/LibretroD3D11Context.h" @@ -26,9 +25,9 @@ static void context_destroy() { ((LibretroHWRenderContext *)Libretro::ctx)->Cont bool LibretroHWRenderContext::Init(bool cache_context) { hw_render_.cache_context = cache_context; if (!Libretro::environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render_)) - return false; - libretro_get_proc_address = hw_render_.get_proc_address; - return true; + return false; + libretro_get_proc_address = hw_render_.get_proc_address; + return true; } LibretroHWRenderContext::LibretroHWRenderContext(retro_hw_context_type context_type, unsigned version_major, unsigned version_minor) { @@ -41,12 +40,14 @@ LibretroHWRenderContext::LibretroHWRenderContext(retro_hw_context_type context_t } void LibretroHWRenderContext::ContextReset() { - INFO_LOG(G3D, "Context reset"); + INFO_LOG(Log::G3D, "Context reset"); - // needed to restart the thread - // TODO: find a way to move this to ContextDestroy. - if (!hw_render_.cache_context && Libretro::useEmuThread && draw_ && Libretro::emuThreadState != Libretro::EmuThreadState::PAUSED) { - DestroyDrawContext(); + if (gpu && Libretro::useEmuThread) { + Libretro::EmuThreadPause(); + } + + if (gpu) { + gpu->DeviceLost(); } if (!draw_) { @@ -60,17 +61,25 @@ void LibretroHWRenderContext::ContextReset() { if (gpu) { gpu->DeviceRestore(draw_); } + + if (gpu && Libretro::useEmuThread) { + Libretro::EmuThreadStart(); + } } void LibretroHWRenderContext::ContextDestroy() { - INFO_LOG(G3D, "Context destroy"); + INFO_LOG(Log::G3D, "Context destroy"); if (Libretro::useEmuThread) { -#if 0 - Libretro::EmuThreadPause(); -#else Libretro::EmuThreadStop(); -#endif + } + + if (gpu) { + gpu->DeviceLost(); + } + + if (!hw_render_.cache_context && Libretro::useEmuThread && draw_ && Libretro::emuThreadState != Libretro::EmuThreadState::PAUSED) { + DestroyDrawContext(); } if (!hw_render_.cache_context && !Libretro::useEmuThread) { @@ -89,6 +98,9 @@ LibretroGraphicsContext *LibretroGraphicsContext::CreateGraphicsContext() { if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER, &preferred)) preferred = RETRO_HW_CONTEXT_DUMMY; + if (Libretro::backend != RETRO_HW_CONTEXT_DUMMY) + preferred = Libretro::backend; + #ifndef USING_GLES2 if (preferred == RETRO_HW_CONTEXT_DUMMY || preferred == RETRO_HW_CONTEXT_OPENGL_CORE) { ctx = new LibretroGLCoreContext(); @@ -130,7 +142,6 @@ LibretroGraphicsContext *LibretroGraphicsContext::CreateGraphicsContext() { delete ctx; ctx = new LibretroD3D9Context(); - if (ctx->Init()) { return ctx; } @@ -139,6 +150,64 @@ LibretroGraphicsContext *LibretroGraphicsContext::CreateGraphicsContext() { #endif ctx = new LibretroSoftwareContext(); - ctx->Init(); - return ctx; + ctx->Init(); + return ctx; +} + +std::vector TranslateDebugBufferToCompare(const GPUDebugBuffer *buffer, u32 stride, u32 h) { + // If the output was small, act like everything outside was 0. + // This can happen depending on viewport parameters. + u32 safeW = std::min(stride, buffer->GetStride()); + u32 safeH = std::min(h, buffer->GetHeight()); + + std::vector data; + data.resize(stride * h, 0); + + const u32 *pixels32 = (const u32 *)buffer->GetData(); + const u16 *pixels16 = (const u16 *)buffer->GetData(); + int outStride = buffer->GetStride(); +#if 0 + if (!buffer->GetFlipped()) { + // Bitmaps are flipped, so we have to compare backwards in this case. + int toLastRow = outStride * (h > buffer->GetHeight() ? buffer->GetHeight() - 1 : h - 1); + pixels32 += toLastRow; + pixels16 += toLastRow; + outStride = -outStride; + } +#endif + // Skip the bottom of the image in the buffer was smaller. Remember, we're flipped. + u32 *dst = &data[0]; + if (safeH < h) { + dst += (h - safeH) * stride; + } + + for (u32 y = 0; y < safeH; ++y) { + switch (buffer->GetFormat()) { + case GPU_DBG_FORMAT_8888: + ConvertBGRA8888ToRGBA8888(&dst[y * stride], pixels32, safeW); + break; + case GPU_DBG_FORMAT_8888_BGRA: + memcpy(&dst[y * stride], pixels32, safeW * sizeof(u32)); + break; + + case GPU_DBG_FORMAT_565: + ConvertRGB565ToBGRA8888(&dst[y * stride], pixels16, safeW); + break; + case GPU_DBG_FORMAT_5551: + ConvertRGBA5551ToBGRA8888(&dst[y * stride], pixels16, safeW); + break; + case GPU_DBG_FORMAT_4444: + ConvertRGBA4444ToBGRA8888(&dst[y * stride], pixels16, safeW); + break; + + default: + data.resize(0); + return data; + } + + pixels32 += outStride; + pixels16 += outStride; + } + + return data; } diff --git a/libretro/LibretroGraphicsContext.h b/libretro/LibretroGraphicsContext.h index 958c5218a1..96e7bbd69a 100644 --- a/libretro/LibretroGraphicsContext.h +++ b/libretro/LibretroGraphicsContext.h @@ -5,8 +5,16 @@ #include "Common/GraphicsContext.h" #include "Common/GPU/thin3d_create.h" +#include "Core/Config.h" #include "Core/System.h" #include "GPU/GPUState.h" +#include "GPU/Software/SoftGpu.h" +#include "headless/Compare.h" +#include "Common/Data/Convert/ColorConv.h" + +#define NATIVEWIDTH 480 +#define NATIVEHEIGHT 272 +#define SOFT_BMP_SIZE NATIVEWIDTH * NATIVEHEIGHT * 4 class LibretroGraphicsContext : public GraphicsContext { public: @@ -51,7 +59,7 @@ public: bool Init(bool cache_context); void SetRenderTarget() override {} void SwapBuffers() override { - video_cb(RETRO_HW_FRAME_BUFFER_VALID, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, 0); + video_cb(RETRO_HW_FRAME_BUFFER_VALID, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, 0); } virtual void ContextReset(); virtual void ContextDestroy(); @@ -80,14 +88,27 @@ class LibretroSoftwareContext : public LibretroGraphicsContext { public: LibretroSoftwareContext() {} bool Init() override { return true; } - void SwapBuffers() override { video_cb(NULL, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, 0); } + void SwapBuffers() override { + GPUDebugBuffer buf; + u16 w = NATIVEWIDTH; + u16 h = NATIVEHEIGHT; + gpuDebug->GetOutputFramebuffer(buf); + const std::vector pixels = TranslateDebugBufferToCompare(&buf, w, h); + memcpy(soft_bmp, pixels.data(), SOFT_BMP_SIZE); + u32 offset = g_Config.bDisplayCropTo16x9 ? w << 1 : 0; + h -= g_Config.bDisplayCropTo16x9 ? 2 : 0; + video_cb(soft_bmp + offset, w, h, w << 2); + } GPUCore GetGPUCore() override { return GPUCORE_SOFTWARE; } const char *Ident() override { return "Software"; } + + u16 soft_bmp[SOFT_BMP_SIZE] = {0}; }; namespace Libretro { extern LibretroGraphicsContext *ctx; extern retro_environment_t environ_cb; +extern retro_hw_context_type backend; enum class EmuThreadState { DISABLED, diff --git a/libretro/LibretroVulkanContext.cpp b/libretro/LibretroVulkanContext.cpp index 125563f0e3..1249f10086 100644 --- a/libretro/LibretroVulkanContext.cpp +++ b/libretro/LibretroVulkanContext.cpp @@ -31,17 +31,9 @@ void LibretroVulkanContext::SwapBuffers() { static bool create_device(retro_vulkan_context *context, VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, PFN_vkGetInstanceProcAddr get_instance_proc_addr, const char **required_device_extensions, unsigned num_required_device_extensions, const char **required_device_layers, unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features) { init_glslang(); - std::string errorStr; - if (!VulkanLoad(&errorStr)) { - // TODO: In the context of RetroArch, someone has already loaded the functions. - // But grabbing the pointers for ourselves can't really be a bad thing. - ERROR_LOG(G3D, "RetroArch called the Vulkan entry point without Vulkan available??? %s", errorStr.c_str()); - return false; - } - vk = new VulkanContext(); - vk_libretro_init(instance, gpu, surface, get_instance_proc_addr, required_device_extensions, num_required_device_extensions, required_device_layers, num_required_device_layers, required_features); + vk_libretro_init(instance, gpu, surface, get_instance_proc_addr, required_device_extensions, num_required_device_extensions, required_device_layers, num_required_device_layers, required_features); // TODO: Here we'll inject the instance and all of the stuff into the VulkanContext. @@ -56,8 +48,7 @@ static bool create_device(retro_vulkan_context *context, VkInstance instance, Vk physical_device = vk->GetBestPhysicalDevice(); } - vk->ChooseDevice(physical_device); - vk->CreateDevice(); + vk->CreateDevice(physical_device); #ifdef _WIN32 vk->InitSurface(WINDOWSYSTEM_WIN32, nullptr, nullptr); #elif defined(__ANDROID__) @@ -97,17 +88,17 @@ static const VkApplicationInfo *GetApplicationInfo(void) { } bool LibretroVulkanContext::Init() { - if (!LibretroHWRenderContext::Init(false)) { + if (!LibretroHWRenderContext::Init(true)) { return false; } static const struct retro_hw_render_context_negotiation_interface_vulkan iface = { - RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN, - RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION, - GetApplicationInfo, - create_device, // Callback above. - nullptr, - }; + RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN, + RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION, + GetApplicationInfo, + create_device, // Callback above. + nullptr, + }; Libretro::environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, (void *)&iface); g_Config.iGPUBackend = (int)GPUBackend::VULKAN; @@ -117,11 +108,11 @@ bool LibretroVulkanContext::Init() { void LibretroVulkanContext::ContextReset() { retro_hw_render_interface *vulkan; if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&vulkan) || !vulkan) { - ERROR_LOG(G3D, "Failed to get HW rendering interface!\n"); + ERROR_LOG(Log::G3D, "Failed to get HW rendering interface!\n"); return; } if (vulkan->interface_version != RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION) { - ERROR_LOG(G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION, vulkan->interface_version); + ERROR_LOG(Log::G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION, vulkan->interface_version); return; } vk_libretro_set_hwrender_interface(vulkan); @@ -130,7 +121,9 @@ void LibretroVulkanContext::ContextReset() { } void LibretroVulkanContext::ContextDestroy() { - INFO_LOG(G3D, "LibretroVulkanContext::ContextDestroy()"); + INFO_LOG(Log::G3D, "LibretroVulkanContext::ContextDestroy()"); + vk->WaitUntilQueueIdle(); + LibretroHWRenderContext::ContextDestroy(); } void LibretroVulkanContext::CreateDrawContext() { diff --git a/libretro/LibretroVulkanContext.h b/libretro/LibretroVulkanContext.h index c6d3ea4ac6..49227f6b3a 100644 --- a/libretro/LibretroVulkanContext.h +++ b/libretro/LibretroVulkanContext.h @@ -13,8 +13,8 @@ public: void *GetAPIContext() override; void CreateDrawContext() override; - void ContextReset() override; - void ContextDestroy() override; + void ContextReset() override; + void ContextDestroy() override; GPUCore GetGPUCore() override { return GPUCORE_VULKAN; } const char *Ident() override { return "Vulkan"; } diff --git a/libretro/Makefile b/libretro/Makefile index 4625c9da0f..a1d87a82e2 100644 --- a/libretro/Makefile +++ b/libretro/Makefile @@ -1,4 +1,4 @@ -DEBUG=0 +DEBUG := 0 WITH_DYNAREC := 1 DYNAFLAGS := diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 117846e66e..eb771382c4 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -23,6 +23,7 @@ INCFLAGS += \ -I$(EXTDIR)/glslang \ -I$(EXTDIR)/glslang-build \ -I$(EXTDIR)/native \ + -I$(EXTDIR)/minimp3 \ -I$(EXTDIR)/zlib \ -I$(EXTDIR)/cpu_features/include \ -I$(ZSTDDIR) \ @@ -171,6 +172,9 @@ endif SOURCES_C += $(LIBRETRODIR)/ext/glew/glew.c +SOURCES_CXX += \ + $(EXTDIR)/minimp3/minimp3.cpp + SOURCES_C += \ $(EXTDIR)/libkirk/AES.c \ $(EXTDIR)/libkirk/amctrl.c \ @@ -256,6 +260,19 @@ SOURCES_C += \ $(EXTDIR)/libchdr/src/libchdr_flac.c \ $(EXTDIR)/libchdr/src/libchdr_huffman.c +INCFLAGS += -I$(EXTDIR)/at3_standalone + +SOURCES_CXX += \ + ${EXTDIR}/at3_standalone/atrac.cpp \ + ${EXTDIR}/at3_standalone/atrac3.cpp \ + ${EXTDIR}/at3_standalone/atrac3plus.cpp \ + ${EXTDIR}/at3_standalone/atrac3plusdec.cpp \ + ${EXTDIR}/at3_standalone/atrac3plusdsp.cpp \ + ${EXTDIR}/at3_standalone/get_bits.cpp \ + ${EXTDIR}/at3_standalone/compat.cpp \ + ${EXTDIR}/at3_standalone/fft.cpp \ + ${EXTDIR}/at3_standalone/mem.cpp + ifeq ($(PLATFORM_EXT), android) COREFLAGS += -DHAVE_DLFCN_H else ifneq ($(PLATFORM_EXT), win32) @@ -416,11 +433,12 @@ SOURCES_CXX += \ $(COMMONDIR)/ArmCPUDetect.cpp \ $(COMMONDIR)/CPUDetect.cpp \ $(COMMONDIR)/Buffer.cpp \ - $(COMMONDIR)/ConsoleListener.cpp \ + $(COMMONDIR)/Log/ConsoleListener.cpp \ + $(COMMONDIR)/Log/StdioListener.cpp \ $(COMMONDIR)/ExceptionHandlerSetup.cpp \ $(COMMONDIR)/FakeCPUDetect.cpp \ $(COMMONDIR)/Log.cpp \ - $(COMMONDIR)/LogManager.cpp \ + $(COMMONDIR)/Log/LogManager.cpp \ $(COMMONDIR)/OSVersion.cpp \ $(COMMONDIR)/MemoryUtil.cpp \ $(COMMONDIR)/MipsCPUDetect.cpp \ @@ -446,6 +464,7 @@ SOURCES_C +=\ SOURCES_CXX += \ $(GPUCOMMONDIR)/Draw2D.cpp \ $(GPUCOMMONDIR)/VertexDecoderCommon.cpp \ + $(GPUCOMMONDIR)/VertexDecoderHandwritten.cpp \ $(GPUCOMMONDIR)/GPUStateUtils.cpp \ $(GPUCOMMONDIR)/DrawEngineCommon.cpp \ $(GPUCOMMONDIR)/SplineCommon.cpp \ @@ -631,6 +650,8 @@ SOURCES_CXX += \ $(COREDIR)/HLE/ReplaceTables.cpp \ $(COREDIR)/HLE/HLEHelperThread.cpp \ $(COREDIR)/HLE/HLETables.cpp \ + $(COREDIR)/HLE/AtracCtx.cpp \ + $(COREDIR)/HLE/AtracCtx2.cpp \ $(COREDIR)/HLE/sceAdler.cpp \ $(COREDIR)/HLE/sceAtrac.cpp \ $(COREDIR)/HLE/sceAudio.cpp \ @@ -699,13 +720,13 @@ SOURCES_CXX += \ $(COREDIR)/HW/Camera.cpp \ $(COREDIR)/HW/Display.cpp \ $(COREDIR)/HW/SimpleAudioDec.cpp \ + $(COREDIR)/HW/Atrac3Standalone.cpp \ $(COREDIR)/HW/AsyncIOManager.cpp \ $(COREDIR)/HW/MediaEngine.cpp \ $(COREDIR)/HW/MpegDemux.cpp \ $(COREDIR)/HW/MemoryStick.cpp \ $(COREDIR)/HW/SasAudio.cpp \ $(COREDIR)/HW/SasReverb.cpp \ - $(COREDIR)/HW/StereoResampler.cpp \ $(COREDIR)/Compatibility.cpp \ $(COREDIR)/FrameTiming.cpp \ $(COREDIR)/Loaders.cpp \ @@ -737,6 +758,7 @@ SOURCES_CXX += \ $(COREDIR)/MIPS/MIPSStackWalk.cpp \ $(COREDIR)/MIPS/MIPSVFPUUtils.cpp \ $(COREDIR)/MIPS/MIPSVFPUFallbacks.cpp \ + $(COREDIR)/MIPS/MIPSTracer.cpp \ $(COREDIR)/MemFault.cpp \ $(COREDIR)/MemMap.cpp \ $(COREDIR)/MemMapFunctions.cpp \ @@ -873,23 +895,23 @@ SOURCES_C += $(EXTDIR)/udis86/decode.c \ $(EXTDIR)/udis86/syn.c \ $(EXTDIR)/udis86/udis86.c -INCFLAGS += -I$(EXTDIR)/miniupnp-build +INCFLAGS += -I$(EXTDIR)/miniupnp-build -I$(EXTDIR)/miniupnp/miniupnpc/include -I$(EXTDIR)/miniupnp/miniupnpc/src SOURCES_C += \ - $(EXTDIR)/miniupnp/miniupnpc/addr_is_reserved.c \ - $(EXTDIR)/miniupnp/miniupnpc/connecthostport.c \ - $(EXTDIR)/miniupnp/miniupnpc/igd_desc_parse.c \ - $(EXTDIR)/miniupnp/miniupnpc/minisoap.c \ - $(EXTDIR)/miniupnp/miniupnpc/minissdpc.c \ - $(EXTDIR)/miniupnp/miniupnpc/miniupnpc.c \ - $(EXTDIR)/miniupnp/miniupnpc/miniwget.c \ - $(EXTDIR)/miniupnp/miniupnpc/minixml.c \ - $(EXTDIR)/miniupnp/miniupnpc/minixmlvalid.c \ - $(EXTDIR)/miniupnp/miniupnpc/portlistingparse.c \ - $(EXTDIR)/miniupnp/miniupnpc/receivedata.c \ - $(EXTDIR)/miniupnp/miniupnpc/upnpcommands.c \ - $(EXTDIR)/miniupnp/miniupnpc/upnpdev.c \ - $(EXTDIR)/miniupnp/miniupnpc/upnperrors.c \ - $(EXTDIR)/miniupnp/miniupnpc/upnpreplyparse.c + $(EXTDIR)/miniupnp/miniupnpc/src/addr_is_reserved.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/connecthostport.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/igd_desc_parse.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/minisoap.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/minissdpc.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/miniupnpc.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/miniwget.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/minixml.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/minixmlvalid.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/portlistingparse.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/receivedata.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/upnpcommands.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/upnpdev.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/upnperrors.c \ + $(EXTDIR)/miniupnp/miniupnpc/src/upnpreplyparse.c SOURCES_CXX += \ $(GPUDIR)/Vulkan/DrawEngineVulkan.cpp \ diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 9ec91fc3ce..11007d5c5d 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -9,14 +9,14 @@ #include "Common/CPUDetect.h" #include "Common/Log.h" -#include "Common/LogManager.h" +#include "Common/Log/LogManager.h" #include "Common/System/Display.h" #include "Common/System/NativeApp.h" #include "Common/System/System.h" #include "Common/TimeUtil.h" #include "Common/File/FileUtil.h" #include "Common/Serialize/Serializer.h" -#include "Common/ConsoleListener.h" +#include "Common/Log/StdioListener.h" #include "Common/Input/InputState.h" #include "Common/Thread/ThreadUtil.h" #include "Common/Thread/ThreadManager.h" @@ -32,7 +32,6 @@ #include "Core/HLE/sceUtility.h" #include "Core/HLE/__sceAudio.h" #include "Core/HW/MemoryStick.h" -#include "Core/HW/StereoResampler.h" #include "Core/MemMap.h" #include "Core/System.h" #include "Core/CoreTiming.h" @@ -69,6 +68,13 @@ #define SAMPLERATE 44100 +/* AUDIO output buffer */ +static struct { + int16_t *data; + int32_t size; + int32_t capacity; +} output_audio_buffer = {NULL, 0, 0}; + // Calculated swap interval is 'stable' if the same // value is recorded for a number of retro_run() // calls equal to VSYNC_SWAP_INTERVAL_FRAMES @@ -94,12 +100,15 @@ namespace Libretro { LibretroGraphicsContext *ctx; retro_environment_t environ_cb; + retro_hw_context_type backend = RETRO_HW_CONTEXT_DUMMY; static retro_audio_sample_batch_t audio_batch_cb; static retro_input_poll_t input_poll_cb; static retro_input_state_t input_state_cb; + static retro_log_printf_t log_cb; static bool detectVsyncSwapInterval = false; static bool detectVsyncSwapIntervalOptShown = true; + static bool softwareRenderInitHack = false; static s64 expectedTimeUsPerRun = 0; static uint32_t vsyncSwapInterval = 1; @@ -110,6 +119,59 @@ namespace Libretro static float runSpeed = 0.0f; static s64 runTicksLast = 0; + static void ensure_output_audio_buffer_capacity(int32_t capacity) + { + if (capacity <= output_audio_buffer.capacity) { + return; + } + + output_audio_buffer.data = (int16_t*)realloc(output_audio_buffer.data, capacity * sizeof(*output_audio_buffer.data)); + output_audio_buffer.capacity = capacity; + log_cb(RETRO_LOG_DEBUG, "Output audio buffer capacity set to %d\n", capacity); + } + + static void init_output_audio_buffer(int32_t capacity) + { + output_audio_buffer.data = NULL; + output_audio_buffer.size = 0; + output_audio_buffer.capacity = 0; + ensure_output_audio_buffer_capacity(capacity); + } + + static void free_output_audio_buffer() + { + free(output_audio_buffer.data); + output_audio_buffer.data = NULL; + output_audio_buffer.size = 0; + output_audio_buffer.capacity = 0; + } + + static void upload_output_audio_buffer() + { + audio_batch_cb(output_audio_buffer.data, output_audio_buffer.size / 2); + output_audio_buffer.size = 0; + } + + + /** + * Clamp a value to a given range. + * + * This implementation was taken from `RGBAUtil.cpp` to allow building when `std::clamp()` is unavailable. + * + * @param f The value to clamp. + * @param low The lower bound of the range. + * @param high The upper bound of the range. + * @return The clamped value. + */ + template + static T clamp(T f, T low, T high) { + if (f < low) + return low; + if (f > high) + return high; + return f; + } + static void VsyncSwapIntervalReset() { expectedTimeUsPerRun = (s64)(1000000.0f / (60.0f / 1.001f)); @@ -425,9 +487,12 @@ static std::string map_psp_language_to_i18n_locale(int val) static void check_variables(CoreParameter &coreParam) { - bool isFastForwarding; - if (environ_cb(RETRO_ENVIRONMENT_GET_FASTFORWARDING, &isFastForwarding)) - coreParam.fastForward = isFastForwarding; + if (g_Config.bForceLagSync) + { + bool isFastForwarding; + if (environ_cb(RETRO_ENVIRONMENT_GET_FASTFORWARDING, &isFastForwarding)) + coreParam.fastForward = isFastForwarding; + } bool updated = false; @@ -442,6 +507,7 @@ static void check_variables(CoreParameter &coreParam) int iTexScalingType_prev; int iTexScalingLevel_prev; int iMultiSampleLevel_prev; + bool bDisplayCropTo16x9_prev; var.key = "ppsspp_language"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) @@ -619,6 +685,26 @@ static void check_variables(CoreParameter &coreParam) g_Config.iInternalResolution = 9; else if (!strcmp(var.value, "4800x2720")) g_Config.iInternalResolution = 10; + + // Force resolution to 1x without hardware context + if (backend == RETRO_HW_CONTEXT_NONE) + g_Config.iInternalResolution = 1; + } + + var.key = "ppsspp_software_rendering"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!PSP_IsInited()) + { + if (!strcmp(var.value, "disabled") && backend != RETRO_HW_CONTEXT_NONE) + g_Config.bSoftwareRendering = false; + else + g_Config.bSoftwareRendering = true; + } + + // Force resolution to 1x with software rendering + if (g_Config.bSoftwareRendering) + g_Config.iInternalResolution = 1; } #if 0 // see issue #16786 @@ -638,13 +724,15 @@ static void check_variables(CoreParameter &coreParam) } #endif - var.key = "ppsspp_skip_gpu_readbacks"; + var.key = "ppsspp_cropto16x9"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + bDisplayCropTo16x9_prev = g_Config.bDisplayCropTo16x9; + if (!strcmp(var.value, "disabled")) - g_Config.iSkipGPUReadbackMode = (int)SkipGPUReadbackMode::NO_SKIP; + g_Config.bDisplayCropTo16x9 = false; else - g_Config.iSkipGPUReadbackMode = (int)SkipGPUReadbackMode::SKIP; + g_Config.bDisplayCropTo16x9 = true; } var.key = "ppsspp_frameskip"; @@ -698,22 +786,31 @@ static void check_variables(CoreParameter &coreParam) g_Config.iInflightFrames = 2; } - var.key = "ppsspp_gpu_hardware_transform"; + var.key = "ppsspp_skip_buffer_effects"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "disabled")) - g_Config.bHardwareTransform = false; + g_Config.bSkipBufferEffects = false; else - g_Config.bHardwareTransform = true; + g_Config.bSkipBufferEffects = true; } - var.key = "ppsspp_software_skinning"; + var.key = "ppsspp_disable_range_culling"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "disabled")) - g_Config.bSoftwareSkinning = false; + g_Config.bDisableRangeCulling = false; else - g_Config.bSoftwareSkinning = true; + g_Config.bDisableRangeCulling = true; + } + + var.key = "ppsspp_skip_gpu_readbacks"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.iSkipGPUReadbackMode = (int)SkipGPUReadbackMode::NO_SKIP; + else + g_Config.iSkipGPUReadbackMode = (int)SkipGPUReadbackMode::SKIP; } var.key = "ppsspp_lazy_texture_caching"; @@ -736,6 +833,24 @@ static void check_variables(CoreParameter &coreParam) g_Config.iSplineBezierQuality = 2; } + var.key = "ppsspp_gpu_hardware_transform"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bHardwareTransform = false; + else + g_Config.bHardwareTransform = true; + } + + var.key = "ppsspp_software_skinning"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bSoftwareSkinning = false; + else + g_Config.bSoftwareSkinning = true; + } + var.key = "ppsspp_hardware_tesselation"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { @@ -842,6 +957,15 @@ static void check_variables(CoreParameter &coreParam) g_Config.iTexFiltering = 4; } + var.key = "ppsspp_smart_2d_texture_filtering"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "disabled")) + g_Config.bSmart2DTexFiltering = false; + else + g_Config.bSmart2DTexFiltering = true; + } + var.key = "ppsspp_texture_replacement"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { @@ -996,16 +1120,18 @@ static void check_variables(CoreParameter &coreParam) !g_Config.bRenderDuplicateFrames; bool updateAvInfo = false; + bool updateGeometry = false; + if (!detectVsyncSwapInterval && (vsyncSwapInterval != 1)) { vsyncSwapInterval = 1; updateAvInfo = true; } - if (g_Config.iInternalResolution != iInternalResolution_prev && !PSP_IsInited()) + if (g_Config.iInternalResolution != iInternalResolution_prev && backend != RETRO_HW_CONTEXT_NONE) { - coreParam.pixelWidth = coreParam.renderWidth = g_Config.iInternalResolution * 480; - coreParam.pixelHeight = coreParam.renderHeight = g_Config.iInternalResolution * 272; + coreParam.pixelWidth = coreParam.renderWidth = g_Config.iInternalResolution * NATIVEWIDTH; + coreParam.pixelHeight = coreParam.renderHeight = g_Config.iInternalResolution * NATIVEHEIGHT; if (gpu) { @@ -1017,6 +1143,13 @@ static void check_variables(CoreParameter &coreParam) } } + if (g_Config.bDisplayCropTo16x9 != bDisplayCropTo16x9_prev && PSP_IsInited()) + { + updateGeometry = true; + if (gpu) + gpu->NotifyDisplayResized(); + } + #if 0 // see issue #16786 if (g_Config.iMultiSampleLevel != iMultiSampleLevel_prev && PSP_IsInited()) { @@ -1033,6 +1166,12 @@ static void check_variables(CoreParameter &coreParam) retro_get_system_av_info(&avInfo); environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avInfo); } + else if (updateGeometry) + { + retro_system_av_info avInfo; + retro_get_system_av_info(&avInfo); + environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &avInfo); + } set_variable_visibility(); } @@ -1042,11 +1181,36 @@ void retro_set_audio_sample(retro_audio_sample_t cb) { (void)cb; } void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; } void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; } +static const struct retro_controller_description psp_controllers[] = +{ + { "PSP", RETRO_DEVICE_JOYPAD }, + { NULL, 0 } +}; + +static const struct retro_controller_info ports[] = +{ + { psp_controllers, 1 }, + { NULL, 0 } +}; + void retro_init(void) { - VsyncSwapIntervalReset(); + TimeInit(); - g_threadManager.Init(cpu_info.num_cores, cpu_info.logical_cpu_count); + struct retro_log_callback log; + if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) + { + log_cb = log.log; + LogManager::Init(&g_Config.bEnableLogging); + printfLogger = new PrintfLogger(log); + LogManager* logman = LogManager::GetInstance(); + logman->RemoveListener(logman->GetStdioListener()); + logman->RemoveListener(logman->GetDebuggerListener()); + logman->ChangeFileLog(nullptr); + logman->AddListener(printfLogger); + } + + VsyncSwapIntervalReset(); struct retro_input_descriptor desc[] = { { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, @@ -1068,26 +1232,17 @@ void retro_init(void) { 0 }, }; environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); + environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL)) libretro_supports_bitmasks = true; - struct retro_log_callback log; - if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) - { - LogManager::Init(&g_Config.bEnableLogging); - printfLogger = new PrintfLogger(log); - LogManager* logman = LogManager::GetInstance(); - logman->RemoveListener(logman->GetConsoleListener()); - logman->RemoveListener(logman->GetDebuggerListener()); - logman->ChangeFileLog(nullptr); - logman->AddListener(printfLogger); - logman->SetAllLogLevels(LogLevel::LINFO); - } - g_Config.Load("", ""); g_Config.iInternalResolution = 0; + // Log levels must be set after g_Config.Load + LogManager::GetInstance()->SetAllLogLevels(LogLevel::LINFO); + const char* nickname = NULL; if (environ_cb(RETRO_ENVIRONMENT_GET_USERNAME, &nickname) && nickname) g_Config.sNickName = std::string(nickname); @@ -1112,12 +1267,17 @@ void retro_init(void) g_Config.bDiscordPresence = false; g_VFS.Register("", new DirectoryReader(retro_base_dir)); + + g_threadManager.Init(cpu_info.num_cores, cpu_info.logical_cpu_count); + + init_output_audio_buffer(2048); } void retro_deinit(void) { g_threadManager.Teardown(); LogManager::Shutdown(); + log_cb = NULL; delete printfLogger; printfLogger = nullptr; @@ -1126,6 +1286,8 @@ void retro_deinit(void) libretro_supports_option_categories = false; VsyncSwapIntervalReset(); + + free_output_audio_buffer(); } void retro_set_controller_port_device(unsigned port, unsigned device) @@ -1140,7 +1302,7 @@ void retro_get_system_info(struct retro_system_info *info) info->library_name = "PPSSPP"; info->library_version = PPSSPP_GIT_VERSION; info->need_fullpath = true; - info->valid_extensions = "elf|iso|cso|prx|pbp"; + info->valid_extensions = "elf|iso|cso|prx|pbp|chd"; } void retro_get_system_av_info(struct retro_system_av_info *info) @@ -1149,11 +1311,23 @@ void retro_get_system_av_info(struct retro_system_av_info *info) info->timing.fps = (60.0 / 1.001) / (double)vsyncSwapInterval; info->timing.sample_rate = SAMPLERATE; - info->geometry.base_width = g_Config.iInternalResolution * 480; - info->geometry.base_height = g_Config.iInternalResolution * 272; - info->geometry.max_width = g_Config.iInternalResolution * 480; - info->geometry.max_height = g_Config.iInternalResolution * 272; - info->geometry.aspect_ratio = 480.0 / 272.0; // Not 16:9! But very, very close. + info->geometry.base_width = g_Config.iInternalResolution * NATIVEWIDTH; + info->geometry.base_height = g_Config.iInternalResolution * NATIVEHEIGHT; + info->geometry.max_width = g_Config.iInternalResolution * NATIVEWIDTH; + info->geometry.max_height = g_Config.iInternalResolution * NATIVEHEIGHT; + + if (g_Config.bDisplayCropTo16x9) + info->geometry.base_height -= g_Config.iInternalResolution * 2; + + info->geometry.aspect_ratio = (float)info->geometry.base_width / (float)info->geometry.base_height; + + PSP_CoreParameter().pixelWidth = PSP_CoreParameter().renderWidth = info->geometry.base_width; + PSP_CoreParameter().pixelHeight = PSP_CoreParameter().renderHeight = info->geometry.base_height; + + /* Must reset context to resize render area properly while running, + * but not necessary with software, and not working with Vulkan.. (TODO) */ + if (PSP_IsInited() && ctx && backend != RETRO_HW_CONTEXT_NONE && ctx->GetGPUCore() != GPUCORE_VULKAN) + ((LibretroHWRenderContext *)Libretro::ctx)->ContextReset(); } unsigned retro_api_version(void) { return RETRO_API_VERSION; } @@ -1255,18 +1429,40 @@ namespace Libretro } // namespace Libretro +static void retro_check_backend(void) +{ + struct retro_variable var = {0}; + + var.key = "ppsspp_backend"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "auto")) + backend = RETRO_HW_CONTEXT_DUMMY; + else if (!strcmp(var.value, "opengl")) + backend = RETRO_HW_CONTEXT_OPENGL; + else if (!strcmp(var.value, "vulkan")) + backend = RETRO_HW_CONTEXT_VULKAN; + else if (!strcmp(var.value, "d3d11")) + backend = RETRO_HW_CONTEXT_DIRECT3D; + else if (!strcmp(var.value, "none")) + backend = RETRO_HW_CONTEXT_NONE; + } +} + bool retro_load_game(const struct retro_game_info *game) { retro_pixel_format fmt = retro_pixel_format::RETRO_PIXEL_FORMAT_XRGB8888; if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) { - ERROR_LOG(SYSTEM, "XRGB8888 is not supported.\n"); + ERROR_LOG(Log::System, "XRGB8888 is not supported.\n"); return false; } + retro_check_backend(); + coreState = CORE_POWERUP; ctx = LibretroGraphicsContext::CreateGraphicsContext(); - INFO_LOG(SYSTEM, "Using %s backend", ctx->Ident()); + INFO_LOG(Log::System, "Using %s backend", ctx->Ident()); Core_SetGraphicsContext(ctx); SetGPUBackend((GPUBackend)g_Config.iGPUBackend); @@ -1286,13 +1482,19 @@ bool retro_load_game(const struct retro_game_info *game) coreParam.gpuCore = ctx->GetGPUCore(); check_variables(coreParam); + // TODO: OpenGL goes black when inited with software rendering, + // therefore start without, set back after init, and reset. + softwareRenderInitHack = ctx->GetGPUCore() == GPUCORE_GLES && g_Config.bSoftwareRendering; + if (softwareRenderInitHack) + g_Config.bSoftwareRendering = false; + // set cpuCore from libretro setting variable coreParam.cpuCore = (CPUCore)g_Config.iCpuCore; std::string error_string; if (!PSP_InitStart(coreParam, &error_string)) { - ERROR_LOG(BOOT, "%s", error_string.c_str()); + ERROR_LOG(Log::Boot, "%s", error_string.c_str()); return false; } @@ -1339,7 +1541,7 @@ void retro_reset(void) if (!PSP_Init(PSP_CoreParameter(), &error_string)) { - ERROR_LOG(BOOT, "%s", error_string.c_str()); + ERROR_LOG(Log::Boot, "%s", error_string.c_str()); environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, nullptr); } } @@ -1421,8 +1623,8 @@ static void retro_input(void) } float mappedNorm = norm; - x_left = std::clamp(x_left / norm * mappedNorm, -1.0f, 1.0f); - y_left = std::clamp(y_left / norm * mappedNorm, -1.0f, 1.0f); + x_left = Libretro::clamp(x_left / norm * mappedNorm, -1.0f, 1.0f); + y_left = Libretro::clamp(y_left / norm * mappedNorm, -1.0f, 1.0f); __CtrlSetAnalogXY(CTRL_STICK_LEFT, x_left, y_left); __CtrlSetAnalogXY(CTRL_STICK_RIGHT, x_right, y_right); @@ -1438,10 +1640,18 @@ void retro_run(void) if (!PSP_IsInited()) { - ERROR_LOG(BOOT, "%s", error_string.c_str()); + ERROR_LOG(Log::Boot, "%s", error_string.c_str()); environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, nullptr); return; } + + if (softwareRenderInitHack) + { + log_cb(RETRO_LOG_DEBUG, "Software rendering init hack for opengl triggered.\n"); + softwareRenderInitHack = false; + g_Config.bSoftwareRendering = true; + retro_reset(); + } } check_variables(PSP_CoreParameter()); @@ -1450,7 +1660,7 @@ void retro_run(void) if (useEmuThread) { - if( emuThreadState == EmuThreadState::PAUSED || + if ( emuThreadState == EmuThreadState::PAUSED || emuThreadState == EmuThreadState::PAUSE_REQUESTED) { VsyncSwapIntervalDetect(); @@ -1472,6 +1682,7 @@ void retro_run(void) VsyncSwapIntervalDetect(); ctx->SwapBuffers(); + upload_output_audio_buffer(); } unsigned retro_get_region(void) { return RETRO_REGION_NTSC; } @@ -1488,9 +1699,8 @@ namespace SaveState size_t retro_serialize_size(void) { - if(!gpu) { // The HW renderer isn't ready on first pass. + if (!gpu) // The HW renderer isn't ready on first pass. return 134217728; // 128MB ought to be enough for anybody. - } SaveState::SaveStart state; // TODO: Libretro API extension to use the savestate queue @@ -1503,9 +1713,8 @@ size_t retro_serialize_size(void) bool retro_serialize(void *data, size_t size) { - if(!gpu) { // The HW renderer isn't ready on first pass. + if (!gpu) // The HW renderer isn't ready on first pass. return false; - } // TODO: Libretro API extension to use the savestate queue if (useEmuThread) @@ -1527,6 +1736,9 @@ bool retro_serialize(void *data, size_t size) bool retro_unserialize(const void *data, size_t size) { + if (!gpu) // The HW renderer isn't ready on first pass. + return false; + // TODO: Libretro API extension to use the savestate queue if (useEmuThread) EmuThreadPause(); // Does nothing if already paused @@ -1640,7 +1852,7 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code) { } } -int System_GetPropertyInt(SystemProperty prop) +int64_t System_GetPropertyInt(SystemProperty prop) { switch (prop) { @@ -1667,11 +1879,7 @@ float System_GetPropertyFloat(SystemProperty prop) switch (prop) { case SYSPROP_DISPLAY_REFRESH_RATE: - // Have to lie here and report 60 Hz instead - // of (60.0 / 1.001), otherwise the internal - // stereo resampler will output at the wrong - // frequency... - return 60.0f; + return 60.0f / 1.001f; case SYSPROP_DISPLAY_SAFE_INSET_LEFT: case SYSPROP_DISPLAY_SAFE_INSET_RIGHT: case SYSPROP_DISPLAY_SAFE_INSET_TOP: @@ -1709,7 +1917,7 @@ void System_Notify(SystemNotification notification) { break; } } -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { return false; } +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { return false; } void System_PostUIMessage(UIMessage message, const std::string ¶m) {} void NativeFrame(GraphicsContext *graphicsContext) {} void NativeResized() {} @@ -1725,6 +1933,8 @@ inline int16_t Clamp16(int32_t sample) { void System_AudioPushSamples(const int32_t *audio, int numSamples) { // Convert to 16-bit audio for further processing. int16_t buffer[1024 * 2]; + int origSamples = numSamples * 2; + while (numSamples > 0) { int blockSize = std::min(1024, numSamples); for (int i = 0; i < blockSize; i++) { @@ -1732,14 +1942,13 @@ void System_AudioPushSamples(const int32_t *audio, int numSamples) { buffer[i * 2 + 1] = Clamp16(audio[i * 2 + 1]); } - int framesToWrite = blockSize; - uint32_t framesWritten = audio_batch_cb(buffer, framesToWrite); - if (framesWritten != framesToWrite) { - // Let's just stop, and eat any left-over samples. - break; - } numSamples -= blockSize; } + + if (output_audio_buffer.capacity - output_audio_buffer.size < origSamples) + ensure_output_audio_buffer_capacity((output_audio_buffer.capacity + origSamples) * 1.5); + memcpy(output_audio_buffer.data + output_audio_buffer.size, buffer, origSamples * sizeof(*output_audio_buffer.data)); + output_audio_buffer.size += origSamples; } void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; } diff --git a/libretro/libretro.h b/libretro/libretro.h index fe020d64ab..5068ca107a 100644 --- a/libretro/libretro.h +++ b/libretro/libretro.h @@ -1054,9 +1054,9 @@ enum retro_mod * so the core may decide to skip generating a frame or generating audio. * This is mainly used for increasing performance. * Bit 0 (value 1): Enable Video - * Bit 1 (value 2): Enable Audio + * Bit 1 (value 2): Enable AUDIO * Bit 2 (value 4): Use Fast Savestates. - * Bit 3 (value 8): Hard Disable Audio + * Bit 3 (value 8): Hard Disable AUDIO * Other bits are reserved for future use and will default to zero. * If video is disabled: * * The frontend wants the core to not generate any video, @@ -1079,14 +1079,14 @@ enum retro_mod * * Suggest that the core skips clearing memory. * * Suggest that the core skips resetting the system. * * Suggest that the core may skip validation steps. - * Hard Disable Audio: + * Hard Disable AUDIO: * * Used for a secondary core when running ahead. * * Indicates that the frontend will never need audio from the core. * * Suggests that the core may stop synthesizing audio, but this should not * compromise emulation accuracy. - * * Audio output for the next frame does not matter, and the frontend will + * * AUDIO output for the next frame does not matter, and the frontend will * never need an accurate audio state in the future. - * * State will never be saved when using Hard Disable Audio. + * * State will never be saved when using Hard Disable AUDIO. */ #define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* struct retro_midi_interface ** -- @@ -2653,10 +2653,10 @@ struct retro_rumble_interface /* Notifies libretro that audio data should be written. */ typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void); -/* True: Audio driver in frontend is active, and callback is +/* True: AUDIO driver in frontend is active, and callback is * expected to be called regularily. - * False: Audio driver in frontend is paused or inactive. - * Audio callback will not be called until set_state has been + * False: AUDIO driver in frontend is paused or inactive. + * AUDIO callback will not be called until set_state has been * called with true. * Initial state is false (inactive). */ diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index e572242b5a..ec7873b115 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -103,6 +103,16 @@ struct retro_core_option_v2_category option_cats_us[] = { "Video", "Configure video options." }, + { + "input", + "Input", + "Configure input options." + }, + { + "hacks", + "Hacks", + "Configure speed and emulation hacks. Can cause rendering errors!" + }, { "network", "Network", @@ -112,31 +122,6 @@ struct retro_core_option_v2_category option_cats_us[] = { }; struct retro_core_option_v2_definition option_defs_us[] = { - { - "ppsspp_language", - "Language", - NULL, - "Choose language, 'Automatic' will use the frontend language.", - NULL, - "system", - { - { "Automatic", NULL }, - { "English", NULL }, - { "Japanese", NULL }, - { "French", NULL }, - { "Spanish", NULL }, - { "German", NULL }, - { "Italian", NULL }, - { "Dutch", NULL }, - { "Portuguese", NULL }, - { "Russian", NULL }, - { "Korean", NULL }, - { "Chinese Traditional", NULL }, - { "Chinese Simplified", NULL }, - { NULL, NULL }, - }, - "Automatic" - }, { "ppsspp_cpu_core", "CPU Core", @@ -156,7 +141,7 @@ struct retro_core_option_v2_definition option_defs_us[] = { "ppsspp_fast_memory", "Fast Memory", NULL, - NULL, + "Unstable.", NULL, "system", BOOL_OPTIONS, @@ -189,9 +174,9 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, { "ppsspp_force_lag_sync", - "Force Real Clock Sync (Slower, less lag)", - NULL, + "Force Real Clock Sync", NULL, + "Slower, less lag.", NULL, "system", BOOL_OPTIONS, @@ -209,10 +194,26 @@ struct retro_core_option_v2_definition option_defs_us[] = { { "222MHz", NULL }, { "266MHz", NULL }, { "333MHz", NULL }, + { "444MHz", NULL }, + { "555MHz", NULL }, + { "666MHz", NULL }, + { "777MHz", NULL }, + { "888MHz", NULL }, + { "999MHz", NULL }, { NULL, NULL }, }, "disabled" }, + { + "ppsspp_memstick_inserted", + "Memory Stick Inserted", + NULL, + "Some games require ejecting/inserting the Memory Stick.", + NULL, + "system", + BOOL_OPTIONS, + "enabled" + }, { "ppsspp_cache_iso", "Cache Full ISO in RAM", @@ -233,6 +234,31 @@ struct retro_core_option_v2_definition option_defs_us[] = { BOOL_OPTIONS, "disabled" }, + { + "ppsspp_language", + "Game Language", + NULL, + "'Automatic' will use the frontend language.", + NULL, + "system", + { + { "Automatic", NULL }, + { "English", NULL }, + { "Japanese", NULL }, + { "French", NULL }, + { "Spanish", NULL }, + { "German", NULL }, + { "Italian", NULL }, + { "Dutch", NULL }, + { "Portuguese", NULL }, + { "Russian", NULL }, + { "Korean", NULL }, + { "Chinese Traditional", NULL }, + { "Chinese Simplified", NULL }, + { NULL, NULL }, + }, + "Automatic" + }, { "ppsspp_psp_model", "PSP Model", @@ -248,57 +274,54 @@ struct retro_core_option_v2_definition option_defs_us[] = { "psp_2000_3000" }, { - "ppsspp_button_preference", - "Confirmation Button", + "ppsspp_backend", + "Backend", NULL, + "'Automatic' will use the frontend video driver. Core restart required.", NULL, - NULL, - "system", + "video", { - { "Cross", NULL }, - { "Circle", NULL }, + { "auto", "Automatic" }, + { "opengl", "OpenGL" }, +#ifndef HAVE_LIBNX + { "vulkan", "Vulkan" }, +#endif +#ifdef _WIN32 + { "d3d11", "D3D11" }, +#endif + { "none", "None" }, { NULL, NULL }, }, - "Cross" + "auto" }, { - "ppsspp_analog_is_circular", - "Analog Circle vs Square Gate Compensation", + "ppsspp_software_rendering", + "Software Rendering", NULL, + "Slow, accurate. Core restart required.", NULL, - NULL, - "system", + "video", BOOL_OPTIONS, "disabled" }, - { - "ppsspp_memstick_inserted", - "Memory Stick inserted", - NULL, - "Some games require ejecting/inserting the Memory Stick.", - NULL, - "system", - BOOL_OPTIONS, - "enabled" - }, { "ppsspp_internal_resolution", - "Internal Resolution (Restart)", - NULL, + "Rendering Resolution", NULL, + "Core restart required with Vulkan.", NULL, "video", { - { "480x272", NULL }, - { "960x544", NULL }, - { "1440x816", NULL }, - { "1920x1088", NULL }, - { "2400x1360", NULL }, - { "2880x1632", NULL }, - { "3360x1904", NULL }, - { "3840x2176", NULL }, - { "4320x2448", NULL }, - { "4800x2720", NULL }, + { "480x272", "1x (480x272)" }, + { "960x544", "2x (960x544)" }, + { "1440x816", "3x (1440x816)" }, + { "1920x1088", "4x (1920x1088)" }, + { "2400x1360", "5x (2400x1360)" }, + { "2880x1632", "6x (2880x1632)" }, + { "3360x1904", "7x (3360x1904)" }, + { "3840x2176", "8x (3840x2176)" }, + { "4320x2448", "9x (4320x2448)" }, + { "4800x2720", "10x (4800x2720)" }, { NULL, NULL }, }, "480x272" @@ -322,14 +345,14 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, #endif { - "ppsspp_skip_gpu_readbacks", - "Skip GPU Readbacks", + "ppsspp_cropto16x9", + "Crop to 16x9", NULL, - "Some games require GPU readbacks, so be careful.", + "Remove one line from top and bottom to get exact 16:9. Core restart required with Vulkan.", NULL, "video", BOOL_OPTIONS, - "disabled" + "enabled" }, { "ppsspp_frameskip", @@ -378,19 +401,19 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, { "ppsspp_frame_duplication", - "Duplicate Frames in 30 Hz Games", + "Render Duplicate Frames to 60 Hz", NULL, "Can make framerate smoother in games that run at lower framerates.", NULL, "video", BOOL_OPTIONS, - "disabled" + "enabled" }, { "ppsspp_detect_vsync_swap_interval", - "Detect Frame Rate Changes (Notify frontend)", - NULL, + "Detect Frame Rate Changes", NULL, + "Notify frontend.", NULL, "video", BOOL_OPTIONS, @@ -398,9 +421,9 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, { "ppsspp_inflight_frames", - "Buffered Frames (GL/Vulkan only, slower, less lag, restart)", - NULL, + "Buffer Graphics Commands", NULL, + "GL/Vulkan only, slower, less lag, restart.", NULL, "video", { @@ -411,6 +434,101 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, "Up to 2" }, + { + "ppsspp_button_preference", + "Confirmation Button", + NULL, + NULL, + NULL, + "input", + { + { "Cross", NULL }, + { "Circle", NULL }, + { NULL, NULL }, + }, + "Cross" + }, + { + "ppsspp_analog_is_circular", + "Analog Circle vs Square Gate Compensation", + NULL, + NULL, + NULL, + "input", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_skip_buffer_effects", + "Skip Buffer Effects", + NULL, + "Faster, but nothing may draw in some games.", + NULL, + "hacks", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_disable_range_culling", + "Disable Culling", + NULL, + "", + NULL, + "hacks", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_skip_gpu_readbacks", + "Skip GPU Readbacks", + NULL, + "Some games require GPU readbacks, so be careful.", + NULL, + "hacks", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_lazy_texture_caching", + "Lazy Texture Caching (Speedup)", + NULL, + "Faster, but can cause text problems in a few games.", + NULL, + "hacks", + BOOL_OPTIONS, + "disabled" + }, + { + "ppsspp_spline_quality", + "Spline/Bezier Curves Quality", + NULL, + "Only used by some games, controls smoothness of curves.", + NULL, + "hacks", + { + { "Low", NULL }, + { "Medium", NULL }, + { "High", NULL }, + { NULL, NULL }, + }, + "High" + }, + { + "ppsspp_lower_resolution_for_effects", + "Lower Resolution for Effects", + NULL, + "Reduces artifacts.", + NULL, + "hacks", + { + { "disabled", NULL }, + { "Safe", NULL }, + { "Balanced", NULL }, + { "Aggressive", NULL }, + { NULL, NULL }, + }, + "disabled" + }, { "ppsspp_gpu_hardware_transform", "Hardware Transform", @@ -431,41 +549,6 @@ struct retro_core_option_v2_definition option_defs_us[] = { BOOL_OPTIONS, "enabled" }, - { - "ppsspp_vertex_cache", - "Vertex Cache", - NULL, - "Faster, but may cause temporary flicker.", - NULL, - "video", - BOOL_OPTIONS, - "disabled" - }, - { - "ppsspp_lazy_texture_caching", - "Lazy Texture Caching (Speedup)", - NULL, - "Faster, but can cause text problems in a few games.", - NULL, - "video", - BOOL_OPTIONS, - "disabled" - }, - { - "ppsspp_spline_quality", - "Spline/Bezier Curves Quality", - NULL, - "Only used by some games, controls smoothness of curves.", - NULL, - "video", - { - { "Low", NULL }, - { "Medium", NULL }, - { "High", NULL }, - { NULL, NULL }, - }, - "High" - }, { "ppsspp_hardware_tesselation", "Hardware Tesselation", @@ -477,24 +560,18 @@ struct retro_core_option_v2_definition option_defs_us[] = { "disabled" }, { - "ppsspp_lower_resolution_for_effects", - "Lower Resolution for Effects", - NULL, + "ppsspp_vertex_cache", + "Vertex Cache", NULL, + "Faster, but may cause temporary flicker.", NULL, "video", - { - { "disabled", NULL }, - { "Safe", NULL }, - { "Balanced", NULL }, - { "Aggressive", NULL }, - { NULL, NULL }, - }, + BOOL_OPTIONS, "disabled" }, { "ppsspp_texture_scaling_type", - "Texture Scaling Type", + "Texture Upscale Type", NULL, NULL, NULL, @@ -510,7 +587,7 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, { "ppsspp_texture_scaling_level", - "Texture Scaling Level", + "Texture Upscaling Level", NULL, "CPU heavy, some scaling may be delayed to avoid stutter.", NULL, @@ -537,9 +614,9 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, { "ppsspp_texture_shader", - "Texture Shader (Vulkan only, overrides 'Texture Scaling Type')", - NULL, + "Texture Shader", NULL, + "Vulkan only, overrides 'Texture Scaling Type'.", NULL, "video", { @@ -584,6 +661,16 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, "Auto" }, + { + "ppsspp_smart_2d_texture_filtering", + "Smart 2D Texture Filtering", + NULL, + "Gets rid of some visual artifacts caused by unnecessary texture filtering in some 2D games, by switching to nearest filtering.", + NULL, + "video", + BOOL_OPTIONS, + "disabled" + }, { "ppsspp_texture_replacement", "Texture Replacement", diff --git a/libretro/libretro_vulkan.cpp b/libretro/libretro_vulkan.cpp index 0f091afdb8..cdd4b56221 100644 --- a/libretro/libretro_vulkan.cpp +++ b/libretro/libretro_vulkan.cpp @@ -125,14 +125,17 @@ static VKAPI_ATTR VkResult VKAPI_CALL vkCreateLibretroSurfaceKHR(VkInstance inst VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR_libretro(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) { VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR_org(physicalDevice, surface, pSurfaceCapabilities); if (res == VK_SUCCESS) { - int w = g_Config.iInternalResolution * 480; - int h = g_Config.iInternalResolution * 272; + int w = g_Config.iInternalResolution * NATIVEWIDTH; + int h = g_Config.iInternalResolution * NATIVEHEIGHT; - pSurfaceCapabilities->minImageExtent.width = w; - pSurfaceCapabilities->minImageExtent.height = h; - pSurfaceCapabilities->maxImageExtent.width = w; - pSurfaceCapabilities->maxImageExtent.height = h; - pSurfaceCapabilities->currentExtent.width = w; + if (g_Config.bDisplayCropTo16x9) + h -= g_Config.iInternalResolution * 2; + + pSurfaceCapabilities->minImageExtent.width = w; + pSurfaceCapabilities->minImageExtent.height = h; + pSurfaceCapabilities->maxImageExtent.width = w; + pSurfaceCapabilities->maxImageExtent.height = h; + pSurfaceCapabilities->currentExtent.width = w; pSurfaceCapabilities->currentExtent.height = h; } return res; @@ -373,9 +376,9 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr_libretro(VkInstan return (PFN_vkVoidFunction)vkCreateLibretroSurfaceKHR; } - PFN_vkVoidFunction fptr = vkGetInstanceProcAddr_org(instance, pName); + PFN_vkVoidFunction fptr = vk_init_info.get_instance_proc_addr(instance, pName); if (!fptr) { - ERROR_LOG(G3D, "Failed to load VK instance function: %s", pName); + ERROR_LOG(Log::G3D, "Failed to load VK instance function: %s", pName); return fptr; } @@ -409,9 +412,13 @@ void vk_libretro_init(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR su vkGetInstanceProcAddr_org = vkGetInstanceProcAddr; vkGetInstanceProcAddr = vkGetInstanceProcAddr_libretro; - vkGetDeviceProcAddr_org = vkGetDeviceProcAddr; + vkGetDeviceProcAddr_org = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr");; vkGetDeviceProcAddr = vkGetDeviceProcAddr_libretro; vkCreateInstance = vkCreateInstance_libretro; + + vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion"); + vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); + vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceLayerProperties"); } void vk_libretro_set_hwrender_interface(retro_hw_render_interface *hw_render_interface) { diff --git a/libretro/libretro_vulkan.h b/libretro/libretro_vulkan.h index 9d9aa44775..3f10da9f6c 100644 --- a/libretro/libretro_vulkan.h +++ b/libretro/libretro_vulkan.h @@ -29,6 +29,7 @@ #include "ext/vulkan/vulkan.h" #include "libretro.h" +#include "LibretroGraphicsContext.h" #define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 5 #define RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION 1 diff --git a/macOS/Info.plist b/macOS/Info.plist index 03a318124a..3e996cfdbf 100644 --- a/macOS/Info.plist +++ b/macOS/Info.plist @@ -94,6 +94,10 @@ NSHumanReadableCopyright + LSApplicationCategoryType + public.app-category.games + GCSupportsGameMode + UTExportedTypeDeclarations diff --git a/macOS/InfoGold.plist b/macOS/InfoGold.plist index 2bec2d6606..00d7b774c8 100644 --- a/macOS/InfoGold.plist +++ b/macOS/InfoGold.plist @@ -94,6 +94,10 @@ NSHumanReadableCopyright + LSApplicationCategoryType + public.app-category.games + GCSupportsGameMode + UTExportedTypeDeclarations diff --git a/scripts/makeappimage_32-bit.sh b/scripts/makeappimage_32-bit.sh new file mode 100644 index 0000000000..5361366f4b --- /dev/null +++ b/scripts/makeappimage_32-bit.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +if [ ! -f appimagetool-i686.AppImage ]; then + APPIMAGETOOL=$(wget -q https://api.github.com/repos/probonopd/go-appimage/releases -O - | sed 's/"/ /g; s/ /\n/g' | grep -o 'https.*continuous.*tool.*i686.*mage$') + wget -q "$APPIMAGETOOL" -O ./appimagetool-i686.AppImage + chmod +x appimagetool-i686.AppImage +fi + +if [ ! -f linuxdeploy-i386.AppImage ]; then + wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-i386.AppImage + chmod +x linuxdeploy-i386.AppImage +fi + +mkdir ./AppDir/ +mkdir ./AppDir/usr/ +mkdir ./AppDir/usr/bin/ +mkdir ./AppDir/usr/share/ +mkdir ./AppDir/usr/share/applications/ +mkdir ./AppDir/usr/share/icons/ +mkdir ./AppDir/usr/share/icons/hicolor/ +mkdir ./AppDir/usr/share/icons/hicolor/256x256/ +mkdir ./AppDir/usr/share/icons/hicolor/256x256/apps/ + +cp ~/ppsspp/SDL/PPSSPPSDL.desktop ./AppDir/ +cp ~/ppsspp/SDL/PPSSPPSDL.desktop ./AppDir/usr/share/applications/ +cp ~/ppsspp/build/PPSSPPSDL ./AppDir/usr/bin/ +cp -R ~/ppsspp/build/assets ./AppDir/usr/bin/ +cp ~/ppsspp/icons/hicolor/256x256/apps/ppsspp.png ./AppDir/usr/share/icons/hicolor/256x256/apps/ + +DESTDIR=AppDir make install +./linuxdeploy-i386.AppImage --appimage-extract-and-run --appdir=AppDir \ + --exclude-library="libX*" \ + --exclude-library="libglib*" \ + --exclude-library="libgobject*" \ + --exclude-library="libgdk_pixbuf*" \ + --exclude-library="libwayland*" \ + --exclude-library="libgmodule*" \ + --exclude-library="libgio*" \ + --exclude-library="libxcb*" \ + --exclude-library="libxkbcommon*" \ + --exclude-library="libdb*" + +rm AppDir/ppsspp.png +pushd AppDir +ln -s usr/share/icons/hicolor/256x256/apps/ppsspp.png +chmod +x AppRun +popd +ARCH=i386 +VERSION=$(./AppDir/AppRun --version) ./appimagetool-i686.AppImage --appimage-extract-and-run AppDir diff --git a/scripts/makeappimage_64-bit.sh b/scripts/makeappimage_64-bit.sh new file mode 100644 index 0000000000..56ed7891d6 --- /dev/null +++ b/scripts/makeappimage_64-bit.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +if [ ! -f appimagetool-x86_64.AppImage ]; then + APPIMAGETOOL=$(wget -q https://api.github.com/repos/probonopd/go-appimage/releases -O - | sed 's/"/ /g; s/ /\n/g' | grep -o 'https.*continuous.*tool.*86_64.*mage$') + wget -q "$APPIMAGETOOL" -O ./appimagetool-x86_64.AppImage + chmod +x appimagetool-x86_64.AppImage +fi + +if [ ! -f linuxdeploy-x86_64.AppImage ]; then + wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage + chmod +x linuxdeploy-x86_64.AppImage +fi + +mkdir ./AppDir/ +mkdir ./AppDir/usr/ +mkdir ./AppDir/usr/bin/ +mkdir ./AppDir/usr/share/ +mkdir ./AppDir/usr/share/applications/ +mkdir ./AppDir/usr/share/icons/ +mkdir ./AppDir/usr/share/icons/hicolor/ +mkdir ./AppDir/usr/share/icons/hicolor/256x256/ +mkdir ./AppDir/usr/share/icons/hicolor/256x256/apps/ + +cp ~/ppsspp/SDL/PPSSPPSDL.desktop ./AppDir/ +cp ~/ppsspp/SDL/PPSSPPSDL.desktop ./AppDir/usr/share/applications/ +cp ~/ppsspp/build/PPSSPPSDL ./AppDir/usr/bin/ +cp -R ~/ppsspp/build/assets ./AppDir/usr/bin/ +cp ~/ppsspp/icons/hicolor/256x256/apps/ppsspp.png ./AppDir/usr/share/icons/hicolor/256x256/apps/ + +DESTDIR=AppDir make install +./linuxdeploy-x86_64.AppImage --appimage-extract-and-run --appdir=AppDir \ + --exclude-library="libX*" \ + --exclude-library="libglib*" \ + --exclude-library="libgobject*" \ + --exclude-library="libgdk_pixbuf*" \ + --exclude-library="libwayland*" \ + --exclude-library="libgmodule*" \ + --exclude-library="libgio*" \ + --exclude-library="libxcb*" \ + --exclude-library="libxkbcommon*" \ + --exclude-library="libdb*" + +rm AppDir/ppsspp.png +pushd AppDir +ln -s usr/share/icons/hicolor/256x256/apps/ppsspp.png +chmod +x AppRun +popd +ARCH=x86_64 +VERSION=$(./AppDir/AppRun --version) ./appimagetool-x86_64.AppImage --appimage-extract-and-run AppDir diff --git a/test.py b/test.py index 7b55c8a692..a992913b9c 100755 --- a/test.py +++ b/test.py @@ -196,7 +196,7 @@ tests_good = [ "gpu/transfer/overlap", "gpu/vertices/colors", "gpu/vertices/morph", - "gpu/vertices/texcoords", + # "gpu/vertices/texcoords", # See issue #19093 "hash/hash", "hle/check_not_used_uids", "intr/intr", diff --git a/unittest/JitHarness.cpp b/unittest/JitHarness.cpp index 088416e2bc..3640a96357 100644 --- a/unittest/JitHarness.cpp +++ b/unittest/JitHarness.cpp @@ -41,7 +41,7 @@ void NativeFrame(GraphicsContext *graphicsContext) { } void NativeResized() { } -bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int param3) { return false; } +bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { return false; } void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { cb(false, ""); } void System_AskForPermission(SystemPermission permission) {} PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } @@ -84,7 +84,7 @@ double ExecCPUTest(bool clearCache = true) { JitBlockCacheDebugInterface *cache = MIPSComp::jit->GetBlockCacheDebugInterface(); if (cache) { JitBlockDebugInfo block = cache->GetBlockDebugInfo(0); - WARN_LOG(JIT, "Executed %d target instrs, %d IR, for %d orig", (int)block.targetDisasm.size(), (int)block.irDisasm.size(), (int)block.origDisasm.size()); + WARN_LOG(Log::JIT, "Executed %d target instrs, %d IR, for %d orig", (int)block.targetDisasm.size(), (int)block.irDisasm.size(), (int)block.origDisasm.size()); } if (clearCache) @@ -197,8 +197,10 @@ bool TestJit() { ir_speed = ExecCPUTest(); mipsr4k.UpdateCore(CPUCore::JIT); jit_speed = ExecCPUTest(); +#if !PPSSPP_PLATFORM(MAC) mipsr4k.UpdateCore(CPUCore::JIT_IR); jit_ir_speed = ExecCPUTest(false); +#endif // Disassemble JitBlockCacheDebugInterface *cache = MIPSComp::jit->GetBlockCacheDebugInterface(); diff --git a/unittest/TestArm64Emitter.cpp b/unittest/TestArm64Emitter.cpp index a795cfbb2f..66d373f16b 100644 --- a/unittest/TestArm64Emitter.cpp +++ b/unittest/TestArm64Emitter.cpp @@ -282,7 +282,7 @@ bool TestArm64Emitter() { emitter.EORI2R(X1, X3, 0x3F0000003F0, INVALID_REG); RET(CheckLast(emitter, "d21c1461 eor x1, x3, #0x3f0000003f0")); - printf("yay!\n"); + printf("ARM64 emitter test completed!\n"); //emitter.ANDI2R(W1, W3, 0xFF00FF00FF00FF00ULL, INVALID_REG); //RET(CheckLast(emitter, "00000000 and x1, x3, 0xFF00FF00FF00FF00")); diff --git a/unittest/TestSoftwareGPUJit.cpp b/unittest/TestSoftwareGPUJit.cpp index 5d7c6946d4..ab2f5ff73c 100644 --- a/unittest/TestSoftwareGPUJit.cpp +++ b/unittest/TestSoftwareGPUJit.cpp @@ -24,6 +24,7 @@ #include "GPU/Software/SoftGpu.h" static bool TestSamplerJit() { +#if PPSSPP_ARCH(AMD64) using namespace Sampler; SamplerJitCache *cache = new SamplerJitCache(); BinManager binner; @@ -108,9 +109,14 @@ static bool TestSamplerJit() { delete cache; return successes == count && !HitAnyAsserts(); +#else + // Don't test sampler jit, not supported. + return true; +#endif } static bool TestPixelJit() { +#if PPSSPP_ARCH(AMD64) using namespace Rasterizer; PixelJitCache *cache = new PixelJitCache(); BinManager binner; @@ -159,6 +165,10 @@ static bool TestPixelJit() { delete [] zb_data; delete cache; return successes == count && !HitAnyAsserts(); +#else + // Not yet supported + return true; +#endif } bool TestSoftwareGPUJit() { diff --git a/unittest/TestThreadManager.cpp b/unittest/TestThreadManager.cpp index 10a8b581b7..ff15044ffb 100644 --- a/unittest/TestThreadManager.cpp +++ b/unittest/TestThreadManager.cpp @@ -119,7 +119,7 @@ bool TestMultithreadedScheduling() { threads.clear(); - printf("Stress test elapsed: %0.2f", start.Elapsed()); + printf("Stress test elapsed: %0.2f", start.ElapsedSeconds()); return true; } diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index 8cea9a5329..b68e5e43ae 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -60,6 +60,7 @@ #include "Common/System/System.h" #include "Common/Thread/ThreadUtil.h" #include "Common/Data/Format/IniFile.h" +#include "Common/TimeUtil.h" #include "Common/ArmEmitter.h" #include "Common/BitScan.h" @@ -67,6 +68,7 @@ #include "Common/Log.h" #include "Common/StringUtils.h" #include "Core/Config.h" +#include "Common/Data/Convert/ColorConv.h" #include "Common/File/VFS/VFS.h" #include "Common/File/VFS/DirectoryReader.h" #include "Core/FileSystems/ISOFileSystem.h" @@ -85,7 +87,7 @@ std::string System_GetProperty(SystemProperty prop) { return ""; } std::vector System_GetPropertyStringVec(SystemProperty prop) { return std::vector(); } -int System_GetPropertyInt(SystemProperty prop) { +int64_t System_GetPropertyInt(SystemProperty prop) { return -1; } float System_GetPropertyFloat(SystemProperty prop) { @@ -478,7 +480,7 @@ bool TestMatrixTranspose() { } void TestGetMatrix(int matrix, MatrixSize sz) { - INFO_LOG(SYSTEM, "Testing matrix %s", GetMatrixNotation(matrix, sz).c_str()); + INFO_LOG(Log::System, "Testing matrix %s", GetMatrixNotation(matrix, sz).c_str()); u8 fullMatrix[16]; u8 cols[4]; @@ -496,8 +498,8 @@ void TestGetMatrix(int matrix, MatrixSize sz) { // int rowName = GetRowName(matrix, sz, i, 0); int colName = cols[i]; int rowName = rows[i]; - INFO_LOG(SYSTEM, "Column %i: %s", i, GetVectorNotation(colName, vsz).c_str()); - INFO_LOG(SYSTEM, "Row %i: %s", i, GetVectorNotation(rowName, vsz).c_str()); + INFO_LOG(Log::System, "Column %i: %s", i, GetVectorNotation(colName, vsz).c_str()); + INFO_LOG(Log::System, "Row %i: %s", i, GetVectorNotation(rowName, vsz).c_str()); u8 colRegs[4]; u8 rowRegs[4]; @@ -518,12 +520,12 @@ void TestGetMatrix(int matrix, MatrixSize sz) { c << (int)fullMatrix[j * 4 + i] << " "; d << (int)rowRegs[j] << " "; } - INFO_LOG(SYSTEM, "Col: %s vs %s", a.str().c_str(), b.str().c_str()); + INFO_LOG(Log::System, "Col: %s vs %s", a.str().c_str(), b.str().c_str()); if (a.str() != b.str()) - INFO_LOG(SYSTEM, "WRONG!"); - INFO_LOG(SYSTEM, "Row: %s vs %s", c.str().c_str(), d.str().c_str()); + INFO_LOG(Log::System, "WRONG!"); + INFO_LOG(Log::System, "Row: %s vs %s", c.str().c_str(), d.str().c_str()); if (c.str() != d.str()) - INFO_LOG(SYSTEM, "WRONG!"); + INFO_LOG(Log::System, "WRONG!"); } } @@ -788,15 +790,15 @@ static bool TestAndroidContentURI() { class UnitTestWordWrapper : public WordWrapper { public: - UnitTestWordWrapper(const char *str, float maxW, int flags) + UnitTestWordWrapper(std::string_view str, float maxW, int flags) : WordWrapper(str, maxW, flags) { } protected: - float MeasureWidth(const char *str, size_t bytes) override { + float MeasureWidth(std::string_view str) override { // Simple case for unit testing. int w = 0; - for (UTF8 utf(str); !utf.end() && (size_t)utf.byteIndex() < bytes; ) { + for (UTF8 utf(str); !utf.end(); ) { uint32_t c = utf.next(); switch (c) { case ' ': @@ -997,6 +999,40 @@ bool TestIniFile() { return true; } +inline u32 ReferenceRGBA5551ToRGBA8888(u16 src) { + u8 r = Convert5To8((src >> 0) & 0x1F); + u8 g = Convert5To8((src >> 5) & 0x1F); + u8 b = Convert5To8((src >> 10) & 0x1F); + u8 a = (src >> 15) & 0x1; + a = (a) ? 0xff : 0; + return (a << 24) | (b << 16) | (g << 8) | r; +} + +inline u32 ReferenceRGB565ToRGBA8888(u16 src) { + u8 r = Convert5To8((src >> 0) & 0x1F); + u8 g = Convert6To8((src >> 5) & 0x3F); + u8 b = Convert5To8((src >> 11) & 0x1F); + u8 a = 0xFF; + return (a << 24) | (b << 16) | (g << 8) | r; +} + +bool TestColorConv() { + // Can exhaustively test the 16->32 conversions. + for (int i = 0; i < 65536; i++) { + u16 col16 = i; + + u32 reference = ReferenceRGBA5551ToRGBA8888(col16); + u32 value = RGBA5551ToRGBA8888(col16); + EXPECT_EQ_INT(reference, value); + + reference = ReferenceRGB565ToRGBA8888(col16); + value = RGB565ToRGBA8888(col16); + EXPECT_EQ_INT(reference, value); + } + + return true; +} + typedef bool (*TestFunc)(); struct TestItem { const char *name; @@ -1056,11 +1092,17 @@ TestItem availableTests[] = { TEST_ITEM(VFS), TEST_ITEM(Substitutions), TEST_ITEM(IniFile), + TEST_ITEM(ColorConv), }; int main(int argc, const char *argv[]) { SetCurrentThreadName("UnitTest"); + TimeInit(); + printf("CPU name: %s\n", cpu_info.cpu_string); + printf("ABI: %s\n", GetCompilerABI()); + + // In case we're on ARM, assume these are available. cpu_info.bNEON = true; cpu_info.bVFP = true; cpu_info.bVFPv3 = true; @@ -1096,10 +1138,11 @@ int main(int argc, const char *argv[]) { printf("%d tests passed.\n", passes); } if (fails > 0) { + printf("%d tests failed!\n", fails); return 2; } } else if (testFunc == nullptr) { - fprintf(stderr, "You may select a test to run by passing an argument.\n"); + fprintf(stderr, "You may select a test to run by passing an argument, either \"all\" or one or more of the below.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Available tests:\n"); for (auto f : availableTests) {