diff --git a/.ci/android.sh b/.ci/android.sh index db3dac419..fc945e243 100755 --- a/.ci/android.sh +++ b/.ci/android.sh @@ -9,8 +9,14 @@ fi cd src/android chmod +x ./gradlew -./gradlew assembleRelease -./gradlew bundleRelease + +if [[ "$TARGET" == "googleplay" ]]; then + ./gradlew assembleGooglePlayRelease + ./gradlew bundleGooglePlayRelease +else + ./gradlew assembleVanillaRelease + ./gradlew bundleVanillaRelease +fi ccache -s -v diff --git a/.ci/docker.sh b/.ci/docker.sh new file mode 100755 index 000000000..d4df835c4 --- /dev/null +++ b/.ci/docker.sh @@ -0,0 +1,17 @@ +#!/bin/bash -ex + +GITREV="`git show -s --format='%h'`" || true + +if [ "$GITHUB_REF_TYPE" = "tag" ]; then + TAG_NAME=$GITHUB_REF_NAME +elif [[ -n $GITREV ]]; then + TAG_NAME=$GITREV +else + TAG_NAME=unknown +fi + +echo "Tag name is: $TAG_NAME" + +docker build -f docker/azahar-room/Dockerfile -t azahar-room:$TAG_NAME . +mkdir -p build +docker save azahar-room:$TAG_NAME > build/azahar-room-$TAG_NAME.dockerimage diff --git a/.ci/linux.sh b/.ci/linux.sh index 5b3521681..8cdf33abf 100755 --- a/.ci/linux.sh +++ b/.ci/linux.sh @@ -1,14 +1,16 @@ #!/bin/bash -ex -if [ "$TARGET" = "appimage" ]; then +if [[ "$TARGET" == "appimage"* ]]; then # Compile the AppImage we distribute with Clang. export EXTRA_CMAKE_FLAGS=(-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_LINKER=/etc/bin/ld.lld -DENABLE_ROOM_STANDALONE=OFF) - # Bundle required QT wayland libraries - export EXTRA_QT_PLUGINS="waylandcompositor" - export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" + if [ "$TARGET" = "appimage-wayland" ]; then + # Bundle required QT wayland libraries + export EXTRA_QT_PLUGINS="waylandcompositor" + export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" + fi else # For the linux-fresh verification target, verify compilation without PCH as well. export EXTRA_CMAKE_FLAGS=(-DCITRA_USE_PRECOMPILED_HEADERS=OFF) @@ -30,7 +32,7 @@ cmake .. -G Ninja \ ninja strip -s bin/Release/* -if [ "$TARGET" = "appimage" ]; then +if [[ "$TARGET" == "appimage"* ]]; then ninja bundle # TODO: Our AppImage environment currently uses an older ccache version without the verbose flag. ccache -s diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..d23923c94 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +--- + + +![Ignore Until Your PR has been created!](../blob/master/.github/ignore_unless_human.png?raw=true) +--- diff --git a/.github/ignore_unless_human.png b/.github/ignore_unless_human.png new file mode 100644 index 000000000..da29dd66a Binary files /dev/null and b/.github/ignore_unless_human.png differ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf4a49f31..1fdd627e6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,11 +22,13 @@ jobs: with: name: source path: artifacts/ + linux: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - target: ["appimage", "fresh"] + target: ["appimage", "appimage-wayland", "fresh"] container: image: opensauce04/azahar-build-environment:latest options: -u 1001 @@ -36,11 +38,14 @@ jobs: CCACHE_SLOPPINESS: time_macros OS: linux TARGET: ${{ matrix.target }} + SHOULD_RUN: ${{ (matrix.target != 'appimage-wayland' || github.ref_type == 'tag') }} steps: - uses: actions/checkout@v4 + if: ${{ env.SHOULD_RUN == 'true' }} with: submodules: recursive - name: Set up cache + if: ${{ env.SHOULD_RUN == 'true' }} uses: actions/cache@v4 with: path: ${{ env.CCACHE_DIR }} @@ -48,21 +53,28 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.target }}- - name: Build + if: ${{ env.SHOULD_RUN == 'true' }} run: ./.ci/linux.sh - name: Move AppImage to artifacts directory - if: ${{ matrix.target == 'appimage' }} + if: ${{ contains(matrix.target, 'appimage') && env.SHOULD_RUN == 'true' }} run: | mkdir -p artifacts mv build/bundle/*.AppImage artifacts/ + - name: Rename AppImage + if: ${{ matrix.target == 'appimage-wayland' && env.SHOULD_RUN == 'true' }} + run: | + mv artifacts/azahar.AppImage artifacts/azahar-wayland.AppImage - name: Upload - if: ${{ matrix.target == 'appimage' }} + if: ${{ contains(matrix.target, 'appimage') && env.SHOULD_RUN == 'true' }} uses: actions/upload-artifact@v4 with: name: ${{ env.OS }}-${{ env.TARGET }} path: artifacts/ + macos: - runs-on: ${{ (matrix.target == 'x86_64' && 'macos-13') || 'macos-14' }} + runs-on: ${{ (matrix.target == 'x86_64' && 'macos-15-intel') || 'macos-26' }} strategy: + fail-fast: false matrix: target: ["x86_64", "arm64"] env: @@ -87,14 +99,22 @@ jobs: - name: Build run: ./.ci/macos.sh - name: Prepare outputs for caching - run: mv build/bundle $OS-$TARGET + run: cp -R build/bundle $OS-$TARGET - name: Cache outputs for universal build uses: actions/cache/save@v4 with: path: ${{ env.OS }}-${{ env.TARGET }} key: ${{ runner.os }}-${{ matrix.target }}-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }} + - name: Pack + run: ./.ci/pack.sh + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: ${{ env.OS }}-${{ env.TARGET }} + path: artifacts/ + macos-universal: - runs-on: macos-14 + runs-on: macos-26 needs: macos env: OS: macos @@ -124,9 +144,11 @@ jobs: with: name: ${{ env.OS }}-${{ env.TARGET }} path: artifacts/ + windows: runs-on: windows-latest strategy: + fail-fast: false matrix: target: ["msvc", "msys2"] defaults: @@ -200,79 +222,92 @@ jobs: with: name: ${{ env.OS }}-${{ env.TARGET }} path: artifacts/ + android: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: ["vanilla", "googleplay"] env: CCACHE_DIR: ${{ github.workspace }}/.ccache CCACHE_COMPILERCHECK: content CCACHE_SLOPPINESS: time_macros OS: android - TARGET: universal + TARGET: ${{ matrix.target }} + SHOULD_RUN: ${{ (matrix.target == 'vanilla' || github.ref_type == 'tag') }} steps: - uses: actions/checkout@v4 + if: ${{ env.SHOULD_RUN == 'true' }} with: submodules: recursive - name: Set up cache + if: ${{ env.SHOULD_RUN == 'true' }} uses: actions/cache@v4 with: path: | ~/.gradle/caches ~/.gradle/wrapper ${{ env.CCACHE_DIR }} - key: ${{ runner.os }}-android-${{ github.sha }} + key: ${{ runner.os }}-${{ env.OS }}-${{ matrix.target }}-${{ github.sha }} restore-keys: | - ${{ runner.os }}-android- + ${{ runner.os }}-${{ env.OS }}-${{ matrix.target }}- - name: Set tag name + if: ${{ env.SHOULD_RUN == 'true' }} run: | if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then echo "GIT_TAG_NAME=$GITHUB_REF_NAME" >> $GITHUB_ENV fi echo $GIT_TAG_NAME - - name: Deps + - name: Install tools + if: ${{ env.SHOULD_RUN == 'true' }} run: | sudo apt-get update -y sudo apt-get install ccache apksigner -y - name: Update Android SDK CMake version + if: ${{ env.SHOULD_RUN == 'true' }} run: | echo "y" | ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "cmake;3.30.3" - name: Build + if: ${{ env.SHOULD_RUN == 'true' }} run: JAVA_HOME=$JAVA_HOME_17_X64 ./.ci/android.sh env: ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }} ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }} - name: Pack + if: ${{ env.SHOULD_RUN == 'true' }} run: ../../../.ci/pack.sh working-directory: src/android/app env: UNPACKED: 1 - name: Upload + if: ${{ env.SHOULD_RUN == 'true' }} uses: actions/upload-artifact@v4 with: name: ${{ env.OS }}-${{ env.TARGET }} path: src/android/app/artifacts/ - ios: - if: ${{ !startsWith(github.ref, 'refs/tags/') }} - runs-on: macos-14 - env: - CCACHE_DIR: ${{ github.workspace }}/.ccache - CCACHE_COMPILERCHECK: content - CCACHE_SLOPPINESS: time_macros - OS: ios - TARGET: arm64 + + docker: + runs-on: ubuntu-latest + container: + image: docker:dind steps: - uses: actions/checkout@v4 with: submodules: recursive - - name: Set up cache - uses: actions/cache@v4 - with: - path: ${{ env.CCACHE_DIR }} - key: ${{ runner.os }}-ios-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-ios- - name: Install tools - run: brew install ccache ninja - - name: Build - run: ./.ci/ios.sh - + run: apk add bash + - name: Fix git ownership + run: git config --global --add safe.directory . + - name: Build Docker image + run: ./.ci/docker.sh + - name: Move Docker image to artifacts directory + run: | + mkdir -p artifacts + mv build/*.dockerimage artifacts/ + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: docker + path: artifacts/ \ No newline at end of file diff --git a/.github/workflows/first_time_contributor_detect.yml b/.github/workflows/first_time_contributor_detect.yml new file mode 100644 index 000000000..da8c8bb68 --- /dev/null +++ b/.github/workflows/first_time_contributor_detect.yml @@ -0,0 +1,51 @@ +name: Detect first-time contributors + +on: + pull_request_target: + types: [opened] + +permissions: + pull-requests: write + issues: write + +jobs: + detect: + runs-on: ubuntu-latest + if: >- + (github.repository == 'azahar-emu/azahar') && + (github.event.pull_request.author_association != 'COLLABORATOR') && + (github.event.pull_request.author_association != 'CONTRIBUTOR') && + (github.event.pull_request.author_association != 'MANNEQUIN') && + (github.event.pull_request.author_association != 'MEMBER') && + (github.event.pull_request.author_association != 'OWNER') + steps: + - name: Detect PR if author is first-time contributor + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const pr = context.payload.pull_request; + + // Add needs verification label so that the reopen action runs on comment. + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: pr.number, + labels: ['needs verification'], + }); + + // Close the pull request and wait for verification. + await github.rest.pulls.update({ + owner, + repo, + pull_number: pr.number, + state: 'closed', + }); + + // Show the new contributor how to verify (they need to write a short poem about the Wii and 3DS being lovers) + await github.rest.issues.createComment({ + owner, + repo, + issue_number: pr.number, + body: 'Welcome to the Azahar Emulator repository! Due to the surge of AI bots we have decided to add an extra verification step to new contributors. Please follow the exact instructions in your own written Pull Request description to reopen it.', + }); diff --git a/.github/workflows/first_time_contributor_reopen.yml b/.github/workflows/first_time_contributor_reopen.yml new file mode 100644 index 000000000..e8c7eea15 --- /dev/null +++ b/.github/workflows/first_time_contributor_reopen.yml @@ -0,0 +1,79 @@ +name: Verify first-time contributors + +on: + issue_comment: + types: [created] + +permissions: + pull-requests: write + issues: write + +jobs: + verify: + runs-on: ubuntu-latest + if: github.event.issue.pull_request && contains(github.event.issue.labels.*.name, 'needs verification') + steps: + - name: Verify and reopen PR + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const issue = context.payload.issue; + const comment = context.payload.comment; + const { data: pr } = await github.rest.pulls.get({ + owner, + repo, + pull_number: issue.number, + }); + + // Only allow verification of the comment user is the author + if (comment.user.login !== pr.user.login) { + return; + } + + // Fetch user display and login names (lowercase) + const { data: user } = await github.rest.users.getByUsername({ + username: pr.user.login, + }); + const username = pr.user.login.toLowerCase(); + const displayName = (user.name || '').toLowerCase(); + + // Make comment body lowercase and split words + const body = comment.body.toLowerCase().trim().replace(/[^a-z0-9_\-\s]/g, '').split(/\s+/); + + // Check that the user verified themselves by writing a song about the NES and the SNES. + const verified = + (body.includes(username) || + (displayName && body.includes(displayName))) && + body.includes('azahar'); + + // Only reopen the PR and remove the label if verification succeeded + if (verified) { + await github.rest.pulls.update({ + owner, + repo, + pull_number: issue.number, + state: 'open', + }); + await github.rest.issues.createComment({ + owner, + repo, + issue_number: issue.number, + body: 'Verification successful! Pull request has been reopened. Please also edit your PR description to remove the block of text between `---` to make the description easier to read.', + }); + try { + await github.rest.issues.removeLabel({ + owner, + repo, + issue_number: issue.number, + name: 'needs verification', + }); + } catch {} + } else { + await github.rest.issues.createComment({ + owner, + repo, + issue_number: issue.number, + body: 'Verification failed! Pull request will remain closed.', + }); + } diff --git a/.gitignore b/.gitignore index 3651c93be..6000a682d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,9 @@ src/installer/*.exe src/common/scm_rev.cpp .travis.descriptor.json +# Docker image files +*.dockerimage + # Project/editor files *.swp *.kdev4 diff --git a/.gitmodules b/.gitmodules index ed5d9f0f9..cb600a64c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -100,3 +100,6 @@ [submodule "spirv-headers"] path = externals/spirv-headers url = https://github.com/KhronosGroup/SPIRV-Headers +[submodule "externals/xxHash"] + path = externals/xxHash + url = https://github.com/Cyan4973/xxHash.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a736eaac..6a3635988 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,15 @@ if (APPLE) else() # Minimum macOS 13 set(CMAKE_OSX_DEPLOYMENT_TARGET "13.4") + + # Catch compiler issue on AppleClang versions below 15.0 + # TODO: Remove this check when we drop macOS 13 Ventura + if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND + CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0) + message(FATAL_ERROR "AppleClang 15.0 or later is required due to a compiler bug in earlier versions.\n" + "Current version: ${CMAKE_CXX_COMPILER_VERSION}\n" + "After updating, delete 'CMakeCache.txt' in the build directory.") + endif() endif() endif() @@ -112,6 +121,8 @@ option(ENABLE_MICROPROFILE "Enables microprofile capabilities" OFF) option(ENABLE_SSE42 "Enable SSE4.2 optimizations on x86_64" ON) +option(ENABLE_DEVELOPER_OPTIONS "Enable functionality targeted at emulator developers" OFF) + # Compile options CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ${IS_DEBUG_BUILD} "MINGW" OFF) option(ENABLE_LTO "Enable link time optimization" ${DEFAULT_ENABLE_LTO}) @@ -212,7 +223,7 @@ function(check_submodules_present) foreach(module ${gitmodules}) string(REGEX REPLACE "path *= *" "" module ${module}) if (NOT EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git") - message(SEND_ERROR "Git submodule ${module} not found." + message(SEND_ERROR "Git submodule ${module} not found.\n" "Please run: git submodule update --init --recursive") endif() endforeach() @@ -299,7 +310,7 @@ find_package(Threads REQUIRED) if (ENABLE_QT) if (NOT USE_SYSTEM_QT) - download_qt(6.7.2) + download_qt(6.9.3) endif() find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent) diff --git a/CMakeModules/BuildInstaller.cmake b/CMakeModules/BuildInstaller.cmake deleted file mode 100644 index ce9cadc65..000000000 --- a/CMakeModules/BuildInstaller.cmake +++ /dev/null @@ -1,26 +0,0 @@ -# To use this as a script, make sure you pass in the variables BASE_DIR, SRC_DIR, BUILD_DIR, and TARGET_FILE -cmake_minimum_required(VERSION 3.15) - -if(WIN32) - set(PLATFORM "windows") -elseif(APPLE) - set(PLATFORM "mac") -elseif(UNIX) - set(PLATFORM "linux") -else() - message(FATAL_ERROR "Cannot build installer for this unsupported platform") -endif() - -list(APPEND CMAKE_MODULE_PATH "${BASE_DIR}/CMakeModules") -include(DownloadExternals) -download_qt(tools_ifw) -get_external_prefix(qt QT_PREFIX) - -file(GLOB_RECURSE INSTALLER_BASE "${QT_PREFIX}/**/installerbase*") -file(GLOB_RECURSE BINARY_CREATOR "${QT_PREFIX}/**/binarycreator*") - -set(CONFIG_FILE "${SRC_DIR}/config/config_${PLATFORM}.xml") -set(PACKAGES_DIR "${BUILD_DIR}/packages") -file(MAKE_DIRECTORY ${PACKAGES_DIR}) - -execute_process(COMMAND ${BINARY_CREATOR} -t ${INSTALLER_BASE} -n -c ${CONFIG_FILE} -p ${PACKAGES_DIR} ${TARGET_FILE}) diff --git a/CMakeModules/BundleTarget.cmake b/CMakeModules/BundleTarget.cmake index bd30faf91..fead41acf 100644 --- a/CMakeModules/BundleTarget.cmake +++ b/CMakeModules/BundleTarget.cmake @@ -130,25 +130,10 @@ if (BUNDLE_TARGET_EXECUTE) --icon-file "${CMAKE_BINARY_DIR}/dist/org.azahar_emu.Azahar.svg" --desktop-file "${source_path}/dist/${executable_name}.desktop" --appdir "${appdir_path}" - RESULT_VARIABLE linuxdeploy_appdir_result) + RESULT_VARIABLE linuxdeploy_appdir_result + ERROR_VARIABLE linuxdeploy_appdir_error) if (NOT linuxdeploy_appdir_result EQUAL "0") - message(FATAL_ERROR "linuxdeploy failed to create AppDir: ${linuxdeploy_appdir_result}") - endif() - - if (enable_qt) - set(qt_hook_file "${appdir_path}/apprun-hooks/linuxdeploy-plugin-qt-hook.sh") - file(READ "${qt_hook_file}" qt_hook_contents) - # Add Cinnamon to list of DEs for GTK3 theming. - string(REPLACE - "*XFCE*" - "*X-Cinnamon*|*XFCE*" - qt_hook_contents "${qt_hook_contents}") - # Wayland backend crashes due to changed schemas in Gnome 40. - string(REPLACE - "export QT_QPA_PLATFORMTHEME=gtk3" - "export QT_QPA_PLATFORMTHEME=gtk3; export GDK_BACKEND=x11" - qt_hook_contents "${qt_hook_contents}") - file(WRITE "${qt_hook_file}" "${qt_hook_contents}") + message(FATAL_ERROR "linuxdeploy failed to create AppDir w/ exit code ${linuxdeploy_appdir_result}:\n${linuxdeploy_appdir_error}") endif() message(STATUS "Creating AppImage for executable ${executable_path}") diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake index fc8ec6089..a76d95ae1 100644 --- a/CMakeModules/DownloadExternals.cmake +++ b/CMakeModules/DownloadExternals.cmake @@ -20,9 +20,9 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out set(arch_path "mingw_64") elseif (MSVC) if ("arm64" IN_LIST ARCHITECTURE) - set(arch_path "msvc2019_arm64") + set(arch_path "msvc2022_arm64") elseif ("x86_64" IN_LIST ARCHITECTURE) - set(arch_path "msvc2019_64") + set(arch_path "msvc2022_64") else() message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.") endif() @@ -30,12 +30,13 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out # In case we're cross-compiling, prepare to also fetch the correct host Qt tools. if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") - set(host_arch_path "msvc2019_64") + set(host_arch_path "msvc2022_64") elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64") # TODO: msvc2019_arm64 doesn't include some of the required tools for some reason, # TODO: so until it does, just use msvc2019_64 under x86_64 emulation. + # TODO: ^ Is this still true with msvc2022? # set(host_arch_path "msvc2019_arm64") - set(host_arch_path "msvc2019_64") + set(host_arch_path "msvc2022_64") endif() set(host_arch "win64_${host_arch_path}") else() @@ -105,7 +106,7 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba if (NOT EXISTS "${prefix}") message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}") - set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.1.18") + set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0") if (WIN32) set(aqt_path "${base_path}/aqt.exe") if (NOT EXISTS "${aqt_path}") diff --git a/CMakeModules/GenerateBuildInfo.cmake b/CMakeModules/GenerateBuildInfo.cmake index 0b0334059..b3f4556ab 100644 --- a/CMakeModules/GenerateBuildInfo.cmake +++ b/CMakeModules/GenerateBuildInfo.cmake @@ -1,49 +1,51 @@ -# Gets a UTC timstamp and sets the provided variable to it -function(get_timestamp _var) - string(TIMESTAMP timestamp UTC) - set(${_var} "${timestamp}" PARENT_SCOPE) -endfunction() -get_timestamp(BUILD_DATE) +macro(generate_build_info) + # Gets a UTC timstamp and sets the provided variable to it + function(get_timestamp _var) + string(TIMESTAMP timestamp UTC) + set(${_var} "${timestamp}" PARENT_SCOPE) + endfunction() + get_timestamp(BUILD_DATE) -list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/externals/cmake-modules") + list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/externals/cmake-modules") -if (EXISTS "${SRC_DIR}/.git/objects") - # Find the package here with the known path so that the GetGit commands can find it as well - find_package(Git QUIET PATHS "${GIT_EXECUTABLE}") + if (EXISTS "${SRC_DIR}/.git/objects") + # Find the package here with the known path so that the GetGit commands can find it as well + find_package(Git QUIET PATHS "${GIT_EXECUTABLE}") - # only use Git to check revision info when source is obtained via Git - include(GetGitRevisionDescription) - get_git_head_revision(GIT_REF_SPEC GIT_REV) - git_describe(GIT_DESC --always --long --dirty) - git_branch_name(GIT_BRANCH) -elseif (EXISTS "${SRC_DIR}/GIT-COMMIT" AND EXISTS "${SRC_DIR}/GIT-TAG") - # unified source archive - file(READ "${SRC_DIR}/GIT-COMMIT" GIT_REV_RAW LIMIT 64) - string(STRIP "${GIT_REV_RAW}" GIT_REV) - string(SUBSTRING "${GIT_REV_RAW}" 0 9 GIT_DESC) - set(GIT_BRANCH "HEAD") -else() - # self-packed archive? - set(GIT_REV "UNKNOWN") - set(GIT_DESC "UNKNOWN") - set(GIT_BRANCH "UNKNOWN") -endif() -string(SUBSTRING "${GIT_REV}" 0 7 GIT_SHORT_REV) - -# Set build version -set(REPO_NAME "") -set(BUILD_VERSION "0") -set(BUILD_FULLNAME "${GIT_SHORT_REV}") -if (DEFINED ENV{CI} AND DEFINED ENV{GITHUB_ACTIONS}) - if ($ENV{GITHUB_REF_TYPE} STREQUAL "tag") - set(GIT_TAG $ENV{GITHUB_REF_NAME}) + # only use Git to check revision info when source is obtained via Git + include(GetGitRevisionDescription) + get_git_head_revision(GIT_REF_SPEC GIT_REV) + git_describe(GIT_DESC --always --long --dirty) + git_branch_name(GIT_BRANCH) + elseif (EXISTS "${SRC_DIR}/GIT-COMMIT" AND EXISTS "${SRC_DIR}/GIT-TAG") + # unified source archive + file(READ "${SRC_DIR}/GIT-COMMIT" GIT_REV_RAW LIMIT 64) + string(STRIP "${GIT_REV_RAW}" GIT_REV) + string(SUBSTRING "${GIT_REV_RAW}" 0 9 GIT_DESC) + set(GIT_BRANCH "HEAD") + else() + # self-packed archive? + set(GIT_REV "UNKNOWN") + set(GIT_DESC "UNKNOWN") + set(GIT_BRANCH "UNKNOWN") endif() -elseif (EXISTS "${SRC_DIR}/GIT-COMMIT" AND EXISTS "${SRC_DIR}/GIT-TAG") - file(READ "${SRC_DIR}/GIT-TAG" GIT_TAG) - string(STRIP ${GIT_TAG} GIT_TAG) -endif() + string(SUBSTRING "${GIT_REV}" 0 7 GIT_SHORT_REV) -if (DEFINED GIT_TAG AND NOT "${GIT_TAG}" STREQUAL "unknown") - set(BUILD_VERSION "${GIT_TAG}") - set(BUILD_FULLNAME "${BUILD_VERSION}") -endif() \ No newline at end of file + # Set build version + set(REPO_NAME "") + set(BUILD_VERSION "0") + set(BUILD_FULLNAME "${GIT_SHORT_REV}") + if (DEFINED ENV{CI} AND DEFINED ENV{GITHUB_ACTIONS}) + if ($ENV{GITHUB_REF_TYPE} STREQUAL "tag") + set(GIT_TAG $ENV{GITHUB_REF_NAME}) + endif() + elseif (EXISTS "${SRC_DIR}/GIT-COMMIT" AND EXISTS "${SRC_DIR}/GIT-TAG") + file(READ "${SRC_DIR}/GIT-TAG" GIT_TAG) + string(STRIP ${GIT_TAG} GIT_TAG) + endif() + + if (DEFINED GIT_TAG AND NOT "${GIT_TAG}" STREQUAL "unknown") + set(BUILD_VERSION "${GIT_TAG}") + set(BUILD_FULLNAME "${BUILD_VERSION}") + endif() +endmacro() diff --git a/CMakeModules/GenerateSCMRev.cmake b/CMakeModules/GenerateSCMRev.cmake index ad85ae0b7..377ca9693 100644 --- a/CMakeModules/GenerateSCMRev.cmake +++ b/CMakeModules/GenerateSCMRev.cmake @@ -1,5 +1,6 @@ list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/CMakeModules") include(GenerateBuildInfo) +generate_build_info() # The variable SRC_DIR must be passed into the script (since it uses the current build directory for all values of CMAKE_*_DIR) set(VIDEO_CORE "${SRC_DIR}/src/video_core") @@ -10,6 +11,10 @@ set(HASH_FILES "${VIDEO_CORE}/renderer_opengl/gl_shader_util.h" "${VIDEO_CORE}/renderer_vulkan/vk_shader_util.cpp" "${VIDEO_CORE}/renderer_vulkan/vk_shader_util.h" + "${VIDEO_CORE}/renderer_vulkan/vk_shader_disk_cache.cpp" + "${VIDEO_CORE}/renderer_vulkan/vk_shader_disk_cache.h" + "${VIDEO_CORE}/renderer_vulkan/vk_pipeline_cache.cpp" + "${VIDEO_CORE}/renderer_vulkan/vk_pipeline_cache.h" "${VIDEO_CORE}/shader/generator/glsl_fs_shader_gen.cpp" "${VIDEO_CORE}/shader/generator/glsl_fs_shader_gen.h" "${VIDEO_CORE}/shader/generator/glsl_shader_decompiler.cpp" @@ -18,6 +23,7 @@ set(HASH_FILES "${VIDEO_CORE}/shader/generator/glsl_shader_gen.h" "${VIDEO_CORE}/shader/generator/pica_fs_config.cpp" "${VIDEO_CORE}/shader/generator/pica_fs_config.h" + "${VIDEO_CORE}/shader/generator/profile.h" "${VIDEO_CORE}/shader/generator/shader_gen.cpp" "${VIDEO_CORE}/shader/generator/shader_gen.h" "${VIDEO_CORE}/shader/generator/shader_uniforms.cpp" diff --git a/README.md b/README.md index 964494b18..35616e343 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ ![Azahar Emulator](https://azahar-emu.org/resources/images/logo/azahar-name-and-logo.svg) ![GitHub Release](https://img.shields.io/github/v/release/azahar-emu/azahar?label=Current%20Release) -![GitHub Downloads](https://img.shields.io/github/downloads/azahar-emu/azahar/total?logo=github&label=GitHub%20Downloads) +![GitHub Downloads](https://img.shields.io/github/downloads/azahar-emu/azahar/total?logo=github&label=GitHub%20Downloads) +![Google Play Downloads](https://playbadges.pavi2410.com/badge/downloads?id=io.github.lime3ds.android&pretty&label=Play%20Store%20Downloads) +![Flathub Downloads](https://img.shields.io/flathub/downloads/org.azahar_emu.Azahar?logo=flathub&label=Flathub%20Downloads) ![CI Build Status](https://github.com/azahar-emu/azahar/actions/workflows/build.yml/badge.svg) Azahar is an open-source 3DS emulator project based on Citra. @@ -14,36 +16,48 @@ The goal of this project is to be the de-facto platform for future development. ### Windows -Download the latest release from [Releases](https://github.com/azahar-emu/azahar/releases). +Azahar is available as both an installer and a zip archive. -If you are unsure of whether you want to use MSYS2 or MSVC, use MSYS2. +Download the latest release in your preferred format from the [Releases](https://github.com/azahar-emu/azahar/releases) page. + +If you are unsure of whether you want to use MSVC or MSYS2, use MSYS2. --- ### MacOS -Download the latest release from [Releases](https://github.com/azahar-emu/azahar/releases). +To download a build that will work on all Macs, you can download the `macos-universal` build on the [Releases](https://github.com/azahar-emu/azahar/releases) page. -The `macos-universal` download will work on both Intel and Apple Silicon Macs. +Alternatively, if you wish to download a build specifically for your Mac, you can choose either: + +- `macos-arm64` for Apple Silicon Macs +- `macos-x86_64` for Intel Macs --- + ### Android -The recommended method of downloading Azahar on Android is via the Google Play store: + +There are two variants of Azahar available on Android, those being the Vanilla and Google Play builds. + +The Vanilla build is technically superior, as it uses an alternative method of file management which is faster, but isn't permitted on the Google Play store. + +For most users, we currently recommended downloading Azahar on Android via the Google Play Store for ease of accessibility: Get it on Google Play -Alternatively, you can install the app using Obtainium: +Alternatively, you can install the app using Obtainium, allowing you to use the Vanilla variant: 1. Download and install Obtainium from [here](https://github.com/ImranR98/Obtainium/releases) (use the file named `app-release.apk`) 2. Open Obtainium and click 'Add App' 3. Type `https://github.com/azahar-emu/azahar` into the 'App Source URL' section 4. Click 'Add' -5. Click 'Install' +5. Click 'Install', and select the preferred variant If you wish, you can also simply install the latest APK from the [Releases](https://github.com/azahar-emu/azahar/releases) page. Keep in mind that you will not recieve automatic updates when installing via the APK. --- + ### Linux The recommended format for using Azahar on Linux is the Flatpak available on Flathub: @@ -52,6 +66,13 @@ The recommended format for using Azahar on Linux is the Flatpak available on Fla Azahar is also available as an AppImage on the [Releases](https://github.com/azahar-emu/azahar/releases) page. +There are two variants of the AppImage available, those being `azahar.AppImage` and `azahar-wayland.AppImage`. + +If you are unsure of which variant to use, we recommend using the default `azahar.AppImage`. This is because of upstream issues in the Wayland ecosystem which may cause problems when running the emulator (e.g. [#1162](https://github.com/azahar-emu/azahar/issues/1162)). + +Unless you explicitly require native Wayland support (e.g. you are running a system with no Xwayland), the non-Wayland variant is recommended. + +The Flatpak build of Azahar also has native Wayland support disabled by default. If you require native Wayland support, it can be enabled using [Flatseal](https://flathub.org/en/apps/com.github.tchx84.Flatseal). # Build instructions @@ -83,18 +104,23 @@ To do so, simply read https://github.com/azahar-emu/compatibility-list/blob/mast Contributing compatibility data helps more accurately reflect the current capabilities of the emulator, so it would be highly appreciated if you could go through the reporting process after completing a game. # Minimum requirements + Below are the minimum requirements to run Azahar: ### Desktop + ``` Operating System: Windows 10 (64-bit), MacOS 13.4 (Ventura), or modern 64-bit Linux -CPU: x86-64/ARM64 CPU (Windows for ARM not supported). Single core performance higher than 1,800 on Passmark +CPU: x86-64/ARM64 CPU (Windows for ARM not supported). + Single core performance higher than 1,800 on Passmark. + SSE4.2 required on x86_64. GPU: OpenGL 4.3 or Vulkan 1.1 support Memory: 2GB of RAM. 4GB is recommended ``` ### Android + ``` -Operating System: Android 9.0+ (64-bit) +Operating System: Android 10.0+ (64-bit) CPU: Snapdragon 835 SoC or better GPU: OpenGL ES 3.2 or Vulkan 1.1 support Memory: 2GB of RAM. 4GB is recommended @@ -107,6 +133,7 @@ We share public roadmaps for upcoming releases in the form of GitHub milestones. You can find these at https://github.com/azahar-emu/azahar/milestones. # Join the conversation + We have a community Discord server where you can chat about the project, keep up to date with the latest announcements, or coordinate emulator development. -[![](https://dcbadge.vercel.app/api/server/4ZjMpAp3M6)](https://discord.gg/4ZjMpAp3M6) +Join at https://discord.gg/4ZjMpAp3M6 diff --git a/dist/apple/Info.plist.in b/dist/apple/Info.plist.in index d12a21f8e..6330613d3 100644 --- a/dist/apple/Info.plist.in +++ b/dist/apple/Info.plist.in @@ -35,6 +35,7 @@ cci cxi cia + 3ds CFBundleTypeName Nintendo 3DS File @@ -75,6 +76,9 @@ NSHighResolutionCapable True + UIDesignRequiresCompatibility + UIFileSharingEnabled UILaunchStoryboardName diff --git a/dist/compatibility_list b/dist/compatibility_list index 31c122991..eadcdfb84 160000 --- a/dist/compatibility_list +++ b/dist/compatibility_list @@ -1 +1 @@ -Subproject commit 31c12299126baf892b965defc6ba7810b9c42ccf +Subproject commit eadcdfb84b6f3b95734e867d99fe16a9e8db717f diff --git a/dist/languages/ca_ES_valencia.ts b/dist/languages/ca_ES_valencia.ts index a3106139f..9e0466c40 100644 --- a/dist/languages/ca_ES_valencia.ts +++ b/dist/languages/ca_ES_valencia.ts @@ -26,8 +26,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -296,8 +296,8 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - Emulation: - Emulació: + Emulation + @@ -326,8 +326,8 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Este efecte de post-processat ajusta la velocitat de l'àudio per a igualar-la a la de l'emulador i ajuda a previndre aturades d'àudio, però augmenta la latència d'este. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -336,8 +336,8 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Ajusta la velocitat de reproducció d'àudio per a compensar les caigudes en la velocitat d'emulació. Això significa que l'àudio es reproduirà a velocitat completa fins i tot quan la velocitat de quadres del joc siga baixa. Pot causar problemes de desincronització d'àudio. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + @@ -401,6 +401,7 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. + Camera Càmera @@ -412,8 +413,8 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - Camera to configure: - Configurar la càmera: + Camera to Configure + @@ -433,8 +434,8 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - Camera mode: - Mode de càmera: + Camera mode + @@ -454,8 +455,8 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - Camera position: - Posició de càmera: + Camera position + @@ -475,13 +476,13 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Selecciona el lloc d'on prové la imatge de la càmera emulada. Pot ser una imatge o una càmera real. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Font de la imatge de la càmera: + Camera Image Source + @@ -500,8 +501,8 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - File: - Fitxer: + File + @@ -514,11 +515,6 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP.Select the system camera to use Seleccione la cambra del sistema que serà usada - - - Camera: - Càmera: - <Default> @@ -532,8 +528,8 @@ Aixó banejarà el seu nom d'usuari de fòrum i la seua adreça IP. - Flip: - Rotació: + Flip + @@ -725,7 +721,7 @@ Desitja ignorar l'error i continuar? Show log output in console - + Mostrar l'eixida del registre en la consola @@ -1022,7 +1018,7 @@ Desitja ignorar l'error i continuar? Enable Linear Filtering - Activar filtre linear + @@ -1086,8 +1082,8 @@ Desitja ignorar l'error i continuar? - Reverse Side by Side - De costat a costat invers + Side by Side Full Width + @@ -1137,7 +1133,7 @@ Desitja ignorar l'error i continuar? Disable Right Eye Rendering - Desactivar Renderitzat d'Ull Dret + @@ -1145,49 +1141,54 @@ Desitja ignorar l'error i continuar? <html><head/><body><p>Desactivar Dibuixat d'Ull Dret</p><p>Desactiva el dibuixat de la imatge de l'ull dret quan no s'utilitza el mode estereoscòpic. Millora significativament el rendiment en alguns jocs, però pot causar parpelleig en uns altres.</p></body></html> - + + Swap Eyes + + + + Utility Utilitat - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Canvia les textures per fitxers PNG.</p><p>Les textures són carregades des de load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures - Usar textures personalitzades + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Bolca les textures a fitxers PNG.</p><p>Les textures són bolcades a load/textures/[Title ID]/.</p></body></html> - - Dump Textures - Bolcar Textures + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>Càrrega totes les textures personalitzades en memòria en iniciar, en comptes de carregar-les quan l'aplicació les necessite.</p></body></html> - - Preload Custom Textures - Precarregar Textures Personalitzades + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Càrrega les textures personalitzades de manera asíncrona amb els fils de fons per a reduir les aturades de càrrega</p></body></html> - - Async Custom Texture Loading - Càrrega de Textures Personalitzades Asíncrona + + Async custom texture loading + @@ -1199,91 +1200,111 @@ Desitja ignorar l'error i continuar? - General - General + Updates + - Confirm exit while emulation is running - Confirmar eixida durant l'emulació - - - - Pause emulation when in background - Pausar emulació en estar en segon pla - - - - Mute audio when in background - Silenciar àudio en estar en segon pla - - - - Hide mouse on inactivity - Ocultar ratolí mentres estiga inactiu - - - - Enable Gamemode - Activar Gamemode - - - Check for updates Buscar actualitzacions - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + General + + + + Confirm exit while emulation is running + Confirmar eixida durant l'emulació + + + + Pause emulation when in background + Pausar emulació en estar en segon pla + + + + Mute audio when in background + Silenciar àudio en estar en segon pla + + + + Hide mouse on inactivity + Ocultar ratolí mentres estiga inactiu + + + + Enable Gamemode + Activar Gamemode + + + Emulation Emulació - + Use global emulation speed Usar la velocitat d'emulació global - - Set emulation speed: - Establir la velocitat d'emulació: + + Set emulation speed + - - Emulation Speed: - Velocitat d'Emulació: + + Emulation Speed + - + Turbo Speed Limit: Límit de Velocitat Turbo: - + Screenshots Captures de pantalla - + Use global screenshot path Usar ruta de captura de pantalla global - + Set screenshot path: Establir ruta de captura de pantalla: - + Save Screenshots To Guardar captures a - + ... ... - + Reset All Settings Reiniciar Tota la Configuració @@ -1291,8 +1312,8 @@ Desitja ignorar l'error i continuar? - - + + unthrottled Il·limitada @@ -1302,12 +1323,12 @@ Desitja ignorar l'error i continuar? Seleccione el directori de captures de pantalla - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? Desitja de veritat<b>reiniciar la teua configuració</b> y tancar Azahar? @@ -1361,13 +1382,13 @@ Desitja ignorar l'error i continuar? - SPIR-V Shader Generation - Generació de Ombrejats SPIR-V + SPIR-V shader generation + - Disable GLSL -> SPIR-V Optimizer - Desativar optimitzador GLSL -> SPIR-V + Disable GLSL -> SPIR-V optimizer + @@ -1386,8 +1407,8 @@ Desitja ignorar l'error i continuar? - Enable Hardware Shader - Activar Ombrejador de Hardware + Enable hardware shader + @@ -1396,8 +1417,8 @@ Desitja ignorar l'error i continuar? - Accurate Multiplication - Multiplicació Precisa + Accurate multiplication + @@ -1406,8 +1427,8 @@ Desitja ignorar l'error i continuar? - Enable Shader JIT - Activar Ombreig JIT + Enable shader JIT + @@ -1416,18 +1437,18 @@ Desitja ignorar l'error i continuar? - Enable Async Shader Compilation - Activar compilació de ombrejadors asíncrona + Enable async shader compilation + - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Presentar en fils diferents. Millora el rendiment quan s'usa Vulkan en molts jocs.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + - Enable Async Presentation - Activar Presentació Asíncrona + Enable async presentation + @@ -1466,13 +1487,13 @@ Desitja ignorar l'error i continuar? - Use Disk Shader Cache - Usar Caché Emmagatzemada d'Ombrejadors + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - La Sincronització Vertical impedix el tearing de la imatge, però algunes targetes gràfiques tenen pitjor rendiment quan este està activat. Mantingues-ho activat si no notes cap diferència en el rendiment. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1480,22 +1501,32 @@ Desitja ignorar l'error i continuar? Activar Sincronització Vertical - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global Usar global - + Use per-application Usar configuració de l'aplicació - - Delay application render thread: - Endarrerir fil de renderitzat: + + Delay Application Render Thread + - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>Demora el fil emulat de renderitzat del joc una determinada quantitat de mil·lisegons cada vegada que envie comandos de renderitzat a la GPU.</p><p>Ajusta esta característica en els (pocs) jocs amb FPS dinàmics per a arreglar problemes de rendiment.</p></body></html> @@ -1980,13 +2011,13 @@ Desitja ignorar l'error i continuar? - Swap Screens - Intercanviar Pantalles + Swap screens + - Rotate Screens Upright - Girar pantalles en vertical + Rotate screens upright + @@ -2102,8 +2133,8 @@ Desitja ignorar l'error i continuar? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Percentatge d'Opacitat de la Pantalla Inferior (només OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + @@ -2274,8 +2305,8 @@ Desitja ignorar l'error i continuar? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Més Informació</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Més Informació</span></a> @@ -2450,8 +2481,8 @@ Desitja ignorar l'error i continuar? - Use Virtual SD - Usar SD Virtual + Use virtual SD card + @@ -2460,8 +2491,8 @@ Desitja ignorar l'error i continuar? - Use Custom Storage - Usar emmagatzematge personalitzat + Use custom storage location + @@ -2491,6 +2522,16 @@ Desitja ignorar l'error i continuar? SDMC Directory Directori SDMC + + + Compress installed CIA content + Comprimir el contingut de CIAs instal·lats + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2538,8 +2579,8 @@ les funcions en línia (si estan instal·lats) - Region: - Regió: + Region + @@ -2547,326 +2588,337 @@ les funcions en línia (si estan instal·lats) Auto-elegir - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Nom d'usuari/a - + Birthday Aniversari - + January Gener - + February Febrer - + March Març - + April Abril - + May Maig - + June Juny - + July Juliol - + August Agost - + September Setembre - + October Octubre - + November Novembre - + December Decembre - + Language Idioma - + Note: this can be overridden when region setting is auto-select Nota: pot ser sobreescrit quan la regió és seleccionada automàticament - + Japanese (日本語) Japonés (日本語) - + English Anglés (English) - + French (français) Francés (Français) - + German (Deutsch) Alemany (Deutsch) - + Italian (italiano) Italià (Italiano) - + Spanish (español) Espanyol (Español) - + Simplified Chinese (简体中文) Xinés Simplificat (简体中文) - + Korean (한국어) Coreà (한국어) - + Dutch (Nederlands) Neerlandés (Nederlands) - + Portuguese (português) Portugués (Português) - + Russian (Русский) Rus (Русский) - + Traditional Chinese (正體中文) Xinés Tradicional (正體中文) - + Sound output mode Mode d'eixida de l'àudio - + Mono Mono - + Stereo Estéreo - + Surround Envolvent - + Country País - + Clock Rellotge - + System Clock Rellotge del Sistema - + Fixed Time Temps Fixat - + Startup time Temps de l'Inici - + yyyy-MM-ddTHH:mm:ss aaaa-mm-ddTHH:mm:ss - + Offset time Temps de compensació - + days dies - + HH:mm:ss HH:mm:ss - + Initial System Ticks Ticks de Sistema Inicials - + Random Aleatoris - + Fixed Fixades - + Initial System Ticks Override Sobreescriure Ticks de Sistema Inicials - + Play Coins Monedes de Joc - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>Nombre de passos per hora reportats pel podòmetro. Rang de 0 a 65.535.</p></body></html> - + Pedometer Steps per Hour Passos per hora del podòmetre - + Run System Setup when Home Menu is launched Executar la Configuració de la consola quan s'execute el Menú HOME - + Console ID: ID de Consola - - + + Regenerate Regenerar - + MAC: MAC: - - 3GX Plugin Loader: - Carregador de complements 3GX: + + 3GX Plugin Loader + - + Enable 3GX plugin loader Habilitar el carregador de complements 3GX - + Allow applications to change plugin loader state Permetre que les aplicacions canvien l'estat del carregador de plugins - + Real Console Unique Data Dades úniques de la consola real - + Your real console is linked to Azahar. La teua consola real està enllaçada a Azahar. - + Unlink Desenllaçar - + OTP OTP - - - - + + + + Choose Triar - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. La configuració del sistema només està disponible quan l'aplicació no s'està executant. @@ -3576,76 +3628,76 @@ les funcions en línia (si estan instal·lats) Fitxer Sed (*.sed);;Tots els fitxers (*.*) - - + + Console ID: 0x%1 ID de Consola: 0x%1 - - + + MAC: %1 MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? Substituirà la teua ID de consola 3DS actual per una nova. La teua ID actual no es podrà recuperar. Pot tenir efectes inesperats dins de les aplicacions. Podria fallar si utilitzes un fitxer de configuració obsolet. Continuar? - - - + + + Warning Advertència - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? Això reemplaçarà la teua adreça MAC actual per una nova. No es recomana fer-ho si vas obtindre la direcció MAC de la teua consola real amb la ferramenta de configuració. Continuar? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? Esta acció desvincularà la teua consola real d'Azahar, amb les següents conseqüències:<ul><li>OTP, SecureInfo i LocalFriendCodeSeed seran eliminats de Azahar.</li><li>La teua llista d'amics es restablirà i es tancarà la sessió del teu compte NNID/PNID.</li><li>Els fitxers del sistema i els títols de la eshop obtinguts a través d'Azahar es tornaran inaccessibles fins que la mateixa consola es vincule novament mitjançant la ferramenta de configuració (les dades guardades no es perdran).</li></ul><br>Continuar? - + Invalid country for configured region País incorrecte per a la regió configurada - + Invalid country for console unique data País incorrecte per a les dades de consola únics - + Status: Loaded Estat: Carregat - + Status: Loaded (Invalid Signature) Estat: Carregat (Firma Invàlida) - + Status: Loaded (Region Changed) Estat: Carregat (Canviat de Regió) - + Status: Not Found Estat: No Trobat - + Status: Invalid Estat: Invàlid - + Status: IO Error Estat: Error Entrada/Eixida @@ -3761,13 +3813,13 @@ Mou els punts per a canviar la posició, o fes doble clic en les cel·les de la - Interface language: - Idioma de la Interfície + Interface Language + - Theme: - Tema: + Theme + @@ -3776,8 +3828,8 @@ Mou els punts per a canviar la posició, o fes doble clic en les cel·les de la - Icon Size: - Grandària d'Icona: + Icon Size + @@ -3797,8 +3849,8 @@ Mou els punts per a canviar la posició, o fes doble clic en les cel·les de la - Row 1 Text: - Text de Fila 1: + Row 1 Text + @@ -3832,18 +3884,18 @@ Mou els punts per a canviar la posició, o fes doble clic en les cel·les de la - Row 2 Text: - Text de Fila 2: + Row 2 Text + - Hide Titles without Icon - Ocultar Títols sense Icona + Hide titles without icon + - Single Line Mode - Mode Una Línia + Single line mode + @@ -3852,8 +3904,8 @@ Mou els punts per a canviar la posició, o fes doble clic en les cel·les de la - Show Advanced Frame Time Info - Mostrar informació de fotogrames avançada + Show advanced frame time info + @@ -3935,12 +3987,12 @@ Mou els punts per a canviar la posició, o fes doble clic en les cel·les de la DirectConnectWindow - + Connecting Connectant - + Connect Connectar @@ -4060,471 +4112,511 @@ Per favor, comprove la instal·lació de FFmpeg usada per a la compilació. GMainWindow - + No Suitable Vulkan Devices Detected Dispositius compatibles amb Vulkan no trobats. - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. L'inici de Vulkan va fallar durant l'inici.<br/>El teu GPU, o no suporta Vulkan 1.1, o no té els últims drivers gràfics. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. Velocitat actual del trànsit Artic. Valors més alts indiquen major càrrega de transferència. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. La velocitat d'emulació actual. Valors majors o menors de 100% indiquen que la velocitat d'emulació funciona més ràpida o lentament que en una 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. Els fotogrames per segon que està mostrant el joc. Variaran d'aplicació en aplicació i d'escena a escena. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. El temps que porta emular un fotograma de 3DS, sense tindre en compte el limitador de fotogrames, ni la sincronització vertical. Per a una emulació òptima, este valor no ha de superar els 16.67 ms. - + MicroProfile (unavailable) MicroProfile (no disponible) - + Clear Recent Files Netejar Fitxers Recents - + &Continue &Continuar - + &Pause &Pausar - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar està executant una aplicació - - + + Invalid App Format Format d'aplicació invàlid - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. El teu format d'aplicació no és vàlid.<br/>Per favor, seguix les instruccions per a tornar a bolcar les teues <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>cartutxos de joc</a> i/o <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>títols instal·lats</a>. - + App Corrupted Aplicació corrupta - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. La teua aplicació està corrupta. <br/>Per favor, seguix les instruccions per a tornar a bolcar les teues <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>cartutxos de joc</a> i/o <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>títols instal·lats</a>. - + App Encrypted Aplicació encriptada - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> La teua aplicació està encriptada. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Per favor visita el nostre blog per a més informació.</a> - + Unsupported App Aplicació no suportada - + GBA Virtual Console is not supported by Azahar. Consola Virtual de GBA no està suportada per Azahar. - - + + Artic Server Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! Error en carregar l'aplicació! - + An unknown error occurred. Please see the log for more details. Un error desconegut ha ocorregut. Per favor, mira el log per a més detalls. - + CIA must be installed before usage El CIA ha d'estar instal·lat abans d'usar-se - + Before using this CIA, you must install it. Do you want to install it now? Abans d'usar este CIA, has d'instal·lar-ho. Vols instal·lar-ho ara? - + Quick Load Càrrega Ràpida - + Quick Save Guardat Ràpid - - + + Slot %1 Ranura %1 - + %2 %3 %2 %3 - + Quick Save - %1 Guardat Ràpid - %1 - + Quick Load - %1 Càrrega Ràpida - %1 - + Slot %1 - %2 %3 Ranura %1 - %2 %3 - + Error Opening %1 Folder Error en obrir la carpeta %1 - - + + Folder does not exist! La carpeta no existix! - + Remove Play Time Data Llevar Dades de Temps de Joc - + Reset play time? Reiniciar temps de joc? - - - - + + + + Create Shortcut Crear drecera - + Do you want to launch the application in fullscreen? Desitja llançar esta aplicació en pantalla completa? - + Successfully created a shortcut to %1 Drecera a %1 creat amb èxit - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Aixó crearà una drecera a la AppImage actual. Pot no funcionar bé si actualitzes. Continuar? - + Failed to create a shortcut to %1 Fallada en crear una drecera a %1 - + Create Icon Crear icona - + Cannot create icon file. Path "%1" does not exist and cannot be created. No es va poder crear un arxiu d'icona. La ruta "%1" no existix i no pot ser creada. - + Dumping... Bolcant... - - + + Cancel Cancel·lar - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. No es va poder bolcar el RomFS base. Comprove el registre per a més detalls. - + Error Opening %1 Error en obrir %1 - + Select Directory Seleccionar directori - + Properties Propietats - + The application properties could not be loaded. Les propietats de l'aplicació no han pogut ser carregades. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Executable 3DS(%1);;Tots els arxius(*.*) - + Load File Carregar Fitxer - - + + Set Up System Files Configurar Fitxers del Sistema - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> <p>Azahar necessita fitxers d'una consola real per poder utilitzar algunes de les seues funcions.<br>Pots obtindre els fitxers amb la <a href=https://github.com/azahar-emu/ArticSetupTool>ferramenta de configuració Azahar</a><br>Notes:<ul><li><b>Aquesta operació instal·larà fitxers únics de la consola a Azahar, no compartisques les teues carpetes d'usuari o nand<br>després de completar el procés de configuració!</b></li><li>Després de la configuració, Azahar s'enllaçarà a la consola que ha executat la ferramenta de configuració. Pots desvincular la<br>consola més tard des de la pestanya "Fitxers de sistema" del menú d'opcions de l'emulador.</li><li>No et connectes en línia amb Azahar i la consola 3DS al mateix temps després de configurar els arxius del sistema,<br>ja que això podria causar problemes.</li><li>La configuració de Old 3DS és necessària perquè funcione la configuració de New 3DS (configurar els dos modes és recomanat).</li><li>Els dos modes de configuració funcionaran independentment del model de la consola que execute la ferramenta de configuració.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: Introduïx la direcció de la ferramenta de configuració: - + <br>Choose setup mode: <br>Tria mode de configuració: - + (ℹ️) Old 3DS setup (ℹ️) Configuració Old 3DS - - + + Setup is possible. La configuració és possible. - + (⚠) New 3DS setup (⚠) Configuració New 3DS - + Old 3DS setup is required first. La configuració Old 3DS es neccessaria abans. - + (✅) Old 3DS setup (✅) Configuració Old 3DS - - + + Setup completed. Configuració completada. - + (ℹ️) New 3DS setup (ℹ️) Configuració New 3DS - + (✅) New 3DS setup (✅) Configuració New 3DS - + The system files for the selected mode are already set up. Reinstall the files anyway? Els fitxers de sistema per al mode seleccionat ja estan configurats. Vols reinstal·lar els arxius de totes maneres? - + Load Files Carregar Fitxers - - 3DS Installation File (*.CIA*) - Arxiu d'Instal·lació de 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + Fitxers d'Instalació de 3DS (*.cia *.zcia) - + + + All Files (*.*) Tots els fitxers (*.*) - + Connect to Artic Base Connectar amb Artic Base - + Enter Artic Base server address: Introduïx la direcció del servidor Artic Base - + %1 has been installed successfully. %1 s'ha instal·lat amb èxit. - + Unable to open File No es va poder obrir el Fitxer - + Could not open %1 No es va poder obrir %1 - + Installation aborted Instal·lació interrompuda - + The installation of %1 was aborted. Please see the log for more details La instal·lació de %1 ha sigut avortada.\n Per favor, mira el log per a més informació. - + Invalid File Fitxer no vàlid - + %1 is not a valid CIA %1 no és un CIA vàlid. - + CIA Encrypted CIA encriptat - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> El teu fitxer CIA està encriptat. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Per favor visita el nostre blog per a més informació.</a> - + Unable to find File No es pot trobar el Fitxer - + Could not find %1 No es va poder trobar %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... Desinstal·lant '%1'... - + Failed to uninstall '%1'. Va fallar la desinstal·lació de '%1'. - + Successfully uninstalled '%1'. '%1' desinstal·lat amb èxit. - + File not found Fitxer no trobat - + File "%1" not found Fitxer "%1" no trobat - + Savestates Estats - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! @@ -4533,86 +4625,86 @@ Use at your own risk! Usa'ls sota el teu propi risc! - - - + + + Error opening amiibo data file Error en obrir els fitxers de dades de l'Amiibo - + A tag is already in use. Ja està en ús una etiqueta. - + Application is not looking for amiibos. L'aplicació no està buscant amiibos. - + Amiibo File (%1);; All Files (*.*) Fitxer d'Amiibo (%1);; Tots els arxius (*.*) - + Load Amiibo Carregar Amiibo - + Unable to open amiibo file "%1" for reading. No es va poder obrir el fitxer amiibo "%1" per a la seua lectura. - + Record Movie Gravar Pel·lícula - + Movie recording cancelled. Gravació de pel·lícula cancel·lada. - - + + Movie Saved Pel·lícula Guardada - - + + The movie is successfully saved. Pel·lícula guardada amb èxit. - + Application will unpause L'aplicació es resumirà - + The application will be unpaused, and the next frame will be captured. Is this okay? L'aplicació es resumirà, i el següent fotograma serà capturat. Estàs d'acord? - + Invalid Screenshot Directory Directori de captures de pantalla no vàlid - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. No es pot crear el directori de captures de pantalla. La ruta de captures de pantalla torna al seu valor per omissió. - + Could not load video dumper No es va poder carregar el bolcador de vídeo - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4625,215 +4717,265 @@ Per a instal·lar FFmpeg en Azahar, polsa Obrir i tria el directori de FFmpeg. Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda. - + + Load 3DS ROM Files + + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + Fitxer ROM 3DS comprimit (*.%1) + + + + Save 3DS Compressed ROM File + Desar fitxer 3DS comprimit + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + Fitxer ROM 3DS comprimit (*.zcia *zcci *z3dsx *zcxi) + + + + 3DS ROM File (*.%1) + Fitxer ROM 3DS (*.%1) + + + + Save 3DS ROM File + Desar fitxer ROM 3DS + + + + Select Output 3DS ROM Folder + + + + Select FFmpeg Directory Seleccionar Directori FFmpeg - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. Al directori de FFmpeg indicat li falta %1. Per favor, assegura't d'haver seleccionat el directori correcte. - + FFmpeg has been sucessfully installed. FFmpeg ha sigut instal·lat amb èxit. - + Installation of FFmpeg failed. Check the log file for details. La instal·lació de FFmpeg ha fallat. Comprova l'arxiu del registre per a més detalls. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. No es va poder començar a gravar vídeo.<br>Assegura't que el codificador de vídeo està configurat correctament.<br>Per a més detalls, observa el registre. - + Recording %1 Gravant %1 - + Playing %1 / %2 Reproduint %1 / %2 - + Movie Finished Pel·lícula acabada - + (Accessing SharedExtData) (Accedint al SharedExtData) - + (Accessing SystemSaveData) (Accedint al SystemSaveData) - + (Accessing BossExtData) (Accedint al BossExtData) - + (Accessing ExtData) (Accedint al ExtData) - + (Accessing SaveData) (Accedint al SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 Tràfic Artic: %1 %2%3 - + Speed: %1% Velocitat: %1% - + Speed: %1% / %2% Velocitat: %1% / %2% - + App: %1 FPS App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Frame: %1 ms - + VOLUME: MUTE VOLUM: SILENCI - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUM: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - Falta %1 . Per favor, <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>bolca els teus arxius de sistema</a>.<br/>Continuar l'emulació pot resultar en penges i errors. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + Falta %1 . Per favor,<a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>bolca els teus arxius de sistema</a>.<br/>Continuar l'emulació pot resultar en penges i errors. - + A system archive Un fitxer del sistema - + System Archive Not Found El fitxer del sistema no s'ha trobat - + System Archive Missing Falta un Fitxer de Sistema - + Save/load Error Error de guardat/càrrega - + Fatal Error Error Fatal - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Error fatal. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Mira el log</a> per a més detalls.<br/>Continuar l'emulació pot resultar en penges i errors. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + Error fatal.<a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Mira el log</a>per a més detalls.<br/>Continuar l'emulació pot resultar en penges i errors. - + Fatal Error encountered Error Fatal trobat - + Continue Continuar - + Quit Application Tancar aplicació - + OK Aceptar - + Would you like to exit now? Vols eixir ara? - + The application is still running. Would you like to stop emulation? L'aplicació seguix en execució. Vols parar l'emulació? - + Playback Completed Reproducció Completada - + Movie playback completed. Reproducció de pel·lícula completada. - + Update Available Actualització disponible - + Update %1 for Azahar is available. Would you like to download it? L'actualització %1 d'Azahar ja està disponible. Vols descarregar-la? - + Primary Window Finestra Primària - + Secondary Window Finestra Secundària @@ -4896,42 +5038,42 @@ Vols descarregar-la? GRenderWindow - + OpenGL not available! OpenGL no disponible! - + OpenGL shared contexts are not supported. Els contextos compartits de OpenGL no estan suportats. - + Error while initializing OpenGL! Error en iniciar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. El teu GPU, o no suporta OpenGL, o no tens els últims drivers de la targeta gràfica. - + Error while initializing OpenGL 4.3! Error en iniciar OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 El teu GPU, o no suporta OpenGL 4.3, o no tens els últims drivers de la targeta gràfica.<br><br>Renderitzador GL:<br>%1 - + Error while initializing OpenGL ES 3.2! Error en iniciar OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 El teu GPU, o no suporta OpenGL ES 3.2, o no tens els últims drivers de la targeta gràfica.<br><br>Renderitzador GL:<br>%1 @@ -4939,175 +5081,185 @@ Vols descarregar-la? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - IMPORTANT: Els fitxers encriptats .3ds ja no són compatibles. Pot ser que siga necessari desencriptar-los o canviar-los de nom a .cci. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Més Informació.</a> - - - - Don't show again - No tornar a mostrar - - - - + + Compatibility Compatibilitad - - + + Region Regió - - + + File type Tipus de Fitxer - - + + Size Grandària - - + + Play time Temps de joc - + Favorite Favorit - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open Obrir - + Application Location Localització d'aplicacions - + Save Data Location Localització de dades de guardat - + Extra Data Location Localització de Dades Extra - + Update Data Location Localització de dades d'actualització - + DLC Data Location Localització de dades de DLC - + Texture Dump Location Localització del bolcat de textures - + Custom Texture Location Localització de les textures personalitzades - + Mods Location Localització dels mods - + Dump RomFS Bolcar RomFS - + Disk Shader Cache Caché de ombrejador de disc - + Open Shader Cache Location Obrir ubicació de cache de ombrejador - + Delete OpenGL Shader Cache Eliminar cache d'ombreig de OpenGL - + + Delete Vulkan Shader Cache + + + + Uninstall Desinstal·lar - + Everything Tot - + Application Aplicació - + Update Actualitzar - + DLC DLC - + Remove Play Time Data Llevar Dades de Temps de Joc - + Create Shortcut Crear drecera - + Add to Desktop Afegir a l'escriptori - + Add to Applications Menu Afegir al Menú d'Aplicacions - + + Stress Test: App Launch + + + + Properties Propietats - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. @@ -5116,64 +5268,64 @@ This will delete the application if installed, as well as any installed updates Aixó eliminarà l'aplicació si està instal·lada, així com també les actualitzacions i DLC instal·lades. - - + + %1 (Update) %1 (Actualització) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? Estàs segur de voler desinstal·lar '%1'? - + Are you sure you want to uninstall the update for '%1'? Estàs segur de voler desinstal·lar l'actualització de '%1'? - + Are you sure you want to uninstall all DLC for '%1'? Estàs segur de voler desinstal·lar tot el DLC de '%1'? - + Scan Subfolders Escanejar subdirectoris - + Remove Application Directory Eliminar directori d'aplicacions - + Move Up Moure a dalt - + Move Down Moure avall - + Open Directory Location Obrir ubicació del directori - + Clear Reiniciar - + Name Nom @@ -5181,77 +5333,77 @@ Aixó eliminarà l'aplicació si està instal·lada, així com també les a GameListItemCompat - + Perfect Perfecte - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. L'aplicació funciona impecablement, sense falles d'àudio ni gràfiques; totes les funcions provades funcionen com s'espera, sense necessitat de solucions alternatives. - + Great Excel·lent - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. L'aplicació funciona amb xicotetes fallades gràfiques o d'àudio i es pot jugar de principi a fi. Pot requerir algunes solucions alternatives. - + Okay - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. L'aplicació funciona amb importants fallades gràfiques o d'àudio, però es pot jugar de principi a fi amb solucions alternatives. - + Bad Mal - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. L'aplicació funciona, però presenta importants fallades gràfiques o d'àudio. No es pot avançar en unes certes àrees a causa de fallades, fins i tot amb solucions alternatives. - + Intro/Menu Intro/Menú - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. L'aplicació no es pot jugar per complet a causa d'importants fallades gràfiques o d'àudio. No es pot avançar més enllà de la pantalla d'inici. - + Won't Boot No inicia - + The app crashes when attempting to startup. L'aplicació es bloqueja en intentar iniciar-se. - + Not Tested Sense provar - + The app has not yet been tested. L'aplicació no s'ha provat encara. @@ -5259,7 +5411,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list Faça doble clic per a agregar una nova carpeta a la llista d'aplicacions @@ -5267,27 +5419,27 @@ Screen. GameListSearchField - + of de - + result resultat - + results resultats - + Filter: Filtre: - + Enter pattern to filter Introduïx un patró per a filtrar @@ -5295,47 +5447,47 @@ Screen. GameRegion - + Japan Japó - + North America Amèrica del Nord - + Europe Europa - + Australia Austràlia - + China Xina - + Korea Corea - + Taiwan Taiwan - + Invalid region Regió no vàlida - + Region free Regió lliure @@ -5615,87 +5767,87 @@ Screen. Índex de Cicle: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Registres d'Adreça: %1, %2 - + Compare Result: %1, %2 Comparar Resultats: %1, %2 - + Static Condition: %1 Condició Estàtica: %1 - + Dynamic Conditions: %1, %2 Condicions Dinàmiques: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Paràmetres de Bucle: %1 (repeticions), %2 (inicialitzador), %3 (incremental), %4 - + Instruction offset: 0x%1 Instrucció offset: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (última instrucció) @@ -5920,24 +6072,24 @@ Missatge de depuració: Preparant ombrejadors %1 / %2 - - Loading Shaders %1 / %2 - Carregant ombrejadors %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Iniciant... - + Now Loading %1 Carregant %1 - + Estimated Time %1 Temps Estimat %1 @@ -5996,32 +6148,32 @@ Missatge de depuració: Contrasenya: - + Room Name Nom de la Sala - + Preferred Application Aplicació preferida - + Host Host - + Players Jugadors - + Refreshing Actualitzant - + Refresh List Actualitzar Llista @@ -6104,342 +6256,352 @@ Missatge de depuració: Pel·lícula - + Help Ajuda - + Load File... Carregar Fitxer... - + Install CIA... Instal·lar CIA... - + Connect to Artic Base... Connectar amb Artic Base... - + Set Up System Files... Configurar Fitxers del Sistema - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit Eixir - + Pause Pausar - + Stop Parar - + Save Guardar - + Load Carregar - + FAQ FAQ - + About Azahar Sobre Azahar - + Single Window Mode Mode Finestra Única - + Save to Oldest Slot Guardar en la ranura més antiga - + Quick Save Guardat Ràpid - + Load from Newest Slot Carregar des de la ranura més recent - + Quick Load Càrrega Ràpida - + Configure... Configurar... - + Display Dock Widget Headers Mostrar Títols de Widgets del Dock - + Show Filter Bar Mostrar Barra de Filtre - + Show Status Bar Mostrar Barra d'Estat - + Create Pica Surface Viewer Crear Observador de Superfície de Pica - + Record... Gravar... - + Play... Reproduïr... - + Close Tancar - + Save without Closing Guardar sense tancar - + Read-Only Mode Mode només lectura - + Advance Frame Avançar Fotograma - + Capture Screenshot Fer Captura de Pantalla - + Dump Video Bolcar Vídeo + Compress ROM File... + Comprimir fitxer ROM... + + + + Decompress ROM File... + Descomprimir fitxer ROM... + + + Browse Public Rooms Buscar sales públiques - + Create Room Crear Sala - + Leave Room Abandonar la Sala - + Direct Connect to Room Conexió Directa a la Sala - + Show Current Room Mostrar Sala Actual - + Fullscreen Pantalla Completa - + Open Log Folder Obrir Carpeta de Registres - + Opens the Azahar Log folder Obrir directori de logs d'Azahar - + Default Per omissió - + Single Screen Pantalla Única - + Large Screen Pantalla amplia - + Side by Side Conjunta - + Separate Windows Ventanes Separades - + Hybrid Screen Pantalla Híbrida - + Custom Layout Estil Personalitzat - + Top Right Amunt a la dreta - + Middle Right Centre a la dreta - + Bottom Right Abaix a la dreta - + Top Left Abaix a l'esquerra - + Middle Left Centre a l'esquerra - + Bottom Left Abaix a l'esquerra - + Above Damunt - + Below Davall - + Swap Screens Intercanviar Pantalles - + Rotate Upright Girar en Vertical - + Report Compatibility Informar de compatibilitat - + Restart Reiniciar - + Load... Carregar... - + Remove Quitar - + Open Azahar Folder Obrir directori d'Azahar - + Configure Current Application... Configurar aplicació actual... @@ -7013,32 +7175,32 @@ Pot ser que haja deixat la sala. %1 (0x%2) - + Unsupported encrypted application Aplicació cifrada no suportada - + Invalid region Regió no vàlida - + Installed Titles Títols Instal·lats - + System Titles Títols de Sistema - + Add New Application Directory Agregar nova carpeta d'aplicacions - + Favorites Favorits diff --git a/dist/languages/da_DK.ts b/dist/languages/da_DK.ts index 350304275..516f627b4 100644 --- a/dist/languages/da_DK.ts +++ b/dist/languages/da_DK.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,8 +298,8 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - Emulation: - Emulering: + Emulation + Emulering @@ -328,8 +328,8 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Denne efterbehandling justerer lydens hastighed så den passer emuleringens og hjælper med at undgå hak i lyden. Denne effekt skaber større forsinkelse af lyden. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -338,8 +338,8 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Skalerer lydafspilningshastigheden for at tage højde for fald i emuleringens billedhastighed. Dette betyder, at lyden afspilles med fuld hastighed, selvom spillets billedhastighed er lav. Kan give problemer med synkroniseringen af lyd. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + @@ -403,6 +403,7 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. + Camera Kamera @@ -414,8 +415,8 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - Camera to configure: - Konfigurer kamera: + Camera to Configure + Konfigurer kamera @@ -435,8 +436,8 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - Camera mode: - Kameratilstand: + Camera mode + Kameratilstand @@ -456,8 +457,8 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - Camera position: - Kameraposition: + Camera position + Kameraposition @@ -477,13 +478,13 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Vælg hvor billedet til det emulerede kamera kommer fra. Det kan være et billede eller et rigtigt kamera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Kilde til kameraets billede + Camera Image Source + @@ -502,8 +503,8 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - File: - Fil: + File + @@ -516,11 +517,6 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. Select the system camera to use Vælg kamera fra systemet, der skal bruges - - - Camera: - Kamera: - <Default> @@ -534,8 +530,8 @@ Dette vil udelukke både deres forum-brugernavn og IP-adresse. - Flip: - Vending: + Flip + @@ -1024,7 +1020,7 @@ Vil du ignorere fejlen og fortsætte? Enable Linear Filtering - Aktiverer lineær filtrering + @@ -1088,8 +1084,8 @@ Vil du ignorere fejlen og fortsætte? - Reverse Side by Side - Omvendt side om side + Side by Side Full Width + @@ -1139,7 +1135,7 @@ Vil du ignorere fejlen og fortsætte? Disable Right Eye Rendering - Deaktiver højre øje-gengivelse + @@ -1147,48 +1143,53 @@ Vil du ignorere fejlen og fortsætte? <html><head/><body><p>Deaktiver højre øje-gengivelse</p><p>Deaktiverer gengivelse af højre øje billede, når der ikke bruges stereoskopisk tilstand. Forbedrer ydeevnen betydeligt i nogle applikationer, men kan forårsage flimren i andre.</p></body></html> - + + Swap Eyes + + + + Utility Værktøj - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Erstat teksturer med PNG-filer.</p><p>Teksturer indlæses fra load/textures/[Titel ID]/.</p></body></html> - - Use Custom Textures - Brug brugerdefinerede teksturer + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures + + Preload custom textures - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading @@ -1201,91 +1202,111 @@ Vil du ignorere fejlen og fortsætte? - General - Generelt + Updates + - Confirm exit while emulation is running - Bekræft afslutning når emulatoren kører - - - - Pause emulation when in background - - - - - Mute audio when in background - - - - - Hide mouse on inactivity - - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Generelt + + + + Confirm exit while emulation is running + Bekræft afslutning når emulatoren kører + + + + Pause emulation when in background + + + + + Mute audio when in background + + + + + Hide mouse on inactivity + + + + + Enable Gamemode + + + + Emulation Emulering - + Use global emulation speed - - Set emulation speed: + + Set emulation speed - - Emulation Speed: + + Emulation Speed - + Turbo Speed Limit: - + Screenshots - + Use global screenshot path - + Set screenshot path: - + Save Screenshots To - + ... - + Reset All Settings Nulstil alle indstillinger @@ -1293,8 +1314,8 @@ Vil du ignorere fejlen og fortsætte? - - + + unthrottled @@ -1304,12 +1325,12 @@ Vil du ignorere fejlen og fortsætte? - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1363,12 +1384,12 @@ Vil du ignorere fejlen og fortsætte? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1388,8 +1409,8 @@ Vil du ignorere fejlen og fortsætte? - Enable Hardware Shader - Aktiver hardware-shader + Enable hardware shader + @@ -1398,8 +1419,8 @@ Vil du ignorere fejlen og fortsætte? - Accurate Multiplication - Akkurat multiplikation + Accurate multiplication + @@ -1408,8 +1429,8 @@ Vil du ignorere fejlen og fortsætte? - Enable Shader JIT - Aktiver shader-JIT + Enable shader JIT + @@ -1418,17 +1439,17 @@ Vil du ignorere fejlen og fortsætte? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1468,12 +1489,12 @@ Vil du ignorere fejlen og fortsætte? - Use Disk Shader Cache + Use disk shader cache - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> @@ -1482,22 +1503,32 @@ Vil du ignorere fejlen og fortsætte? - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1982,12 +2013,12 @@ Vil du ignorere fejlen og fortsætte? - Swap Screens - Byt om på skærme + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2104,7 +2135,7 @@ Vil du ignorere fejlen og fortsætte? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2276,7 +2307,7 @@ Vil du ignorere fejlen og fortsætte? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2452,7 +2483,7 @@ Vil du ignorere fejlen og fortsætte? - Use Virtual SD + Use virtual SD card @@ -2462,7 +2493,7 @@ Vil du ignorere fejlen og fortsætte? - Use Custom Storage + Use custom storage location @@ -2493,6 +2524,16 @@ Vil du ignorere fejlen og fortsætte? SDMC Directory + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2539,8 +2580,8 @@ online features (if installed) - Region: - + Region + Region @@ -2548,326 +2589,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Brugernavn - + Birthday Fødselsdag - + January Januar - + February Februar - + March Marts - + April April - + May Maj - + June Juni - + July Juli - + August August - + September September - + October Oktober - + November November - + December December - + Language Sprog - + Note: this can be overridden when region setting is auto-select Bemærk: Dette kan bliver overstyret når regionsindstillingen er sat til automatisk at vælge - + Japanese (日本語) Japansk (日本語) - + English Engelsk - + French (français) Fransk (français) - + German (Deutsch) Tysk (Deutsch) - + Italian (italiano) Italiensk (italiano) - + Spanish (español) Spansk (español) - + Simplified Chinese (简体中文) Forenklet kinesisk (简体中文) - + Korean (한국어) Koreansk (한국어) - + Dutch (Nederlands) Hollandsk (Nederlands) - + Portuguese (português) Portugisisk (português) - + Russian (Русский) Russisk (Русский) - + Traditional Chinese (正體中文) Traditionel kinesisk (正體中文) - + Sound output mode Tilstand til lydoutput - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Land - + Clock Tid - + System Clock Systemtid - + Fixed Time Fast tid - + Startup time Opstartstid - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: Konsol-id: - - + + Regenerate Generer nyt - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3577,76 +3629,76 @@ online features (if installed) - - + + Console ID: 0x%1 Konsol-id: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Advarsel - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3761,13 +3813,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Grænsefladesprog: + Interface Language + - Theme: - Tema: + Theme + @@ -3776,8 +3828,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - Ikonstørrelse + Icon Size + @@ -3797,8 +3849,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - Tekst på række 1: + Row 1 Text + @@ -3832,17 +3884,17 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - Tekst på række 2: + Row 2 Text + - Hide Titles without Icon - Skjul titler uden ikon + Hide titles without icon + - Single Line Mode + Single line mode @@ -3852,7 +3904,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3935,12 +3987,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Forbinder - + Connect Forbind @@ -4059,555 +4111,595 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Nuværende emuleringshastighed. Værdier højere eller lavere end 100% indikerer at emuleringen kører hurtigere eller langsommere end en 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tid det tog at emulere en 3DS-skærmbillede, hastighedsbegrænsning og v-sync er tille talt med. For emulering med fuld hastighed skal dette højest være 16,67ms. - + MicroProfile (unavailable) - + Clear Recent Files Ryd seneste filer - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage CIA skal installeres før brug - + Before using this CIA, you must install it. Do you want to install it now? Før du kan bruge denne CIA, skal den være installeret. Vil du installere den nu? - + Quick Load - + Quick Save - - + + Slot %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder Fejl ved åbning af %1-mappen - - + + Folder does not exist! Mappen findes ikke! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... - - + + Cancel Annuller - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. - + Error Opening %1 Fejl ved åbning af %1 - + Select Directory Vælg mappe - + Properties - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS-program (%1);;Alle filer (*.*) - + Load File Indlæs fil - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Indlæs filer - - 3DS Installation File (*.CIA*) - 3DS-installationsfil (*.CIA) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Alle filer (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1 blev succesfuldt installeret. - + Unable to open File Kunne ikke åbne filen - + Could not open %1 Kunne ikke åbne %1 - + Installation aborted Installation afbrudt - + The installation of %1 was aborted. Please see the log for more details Installationen af %1 blev afbrudt. Se logfilen for flere detaljer. - + Invalid File Ugyldig fil - + %1 is not a valid CIA %1 er ikke en gyldig CIA - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. - + File not found Filen blev ikke fundet - + File "%1" not found Filen "%1" blev ikke fundet - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo-fil (%1);;Alle filer (*.*) - + Load Amiibo Indlæs Amiibo - + Unable to open amiibo file "%1" for reading. - + Record Movie Optag film - + Movie recording cancelled. Filmoptagelse afbrudt - - + + Movie Saved Film gemt - - + + The movie is successfully saved. Filmen er succesfuldt blevet gemt. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4616,214 +4708,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Hastighed: %1% - + Speed: %1% / %2% Hastighed: %1%/%2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Billede: %1ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive - + System Archive Not Found Systemarkiver blev ikke fundet - + System Archive Missing - + Save/load Error - + Fatal Error Alvorlig fejl - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered - + Continue Fortsæt - + Quit Application - + OK OK - + Would you like to exit now? Vil du afslutte nu? - + The application is still running. Would you like to stop emulation? - + Playback Completed Afspilning færdig - + Movie playback completed. Afspilning af filmen er færdig. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4886,42 +5028,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4929,239 +5071,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Kompatibilitet - - + + Region Region - - + + File type Filtype - - + + Size Størrelse - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders Skan undermapper - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location Åbn mappens placering - + Clear Ryd - + Name Navn @@ -5169,77 +5321,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Perfekt - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great God - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Okay - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Dårlig - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Intro/menu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Kører ikke - + The app crashes when attempting to startup. - + Not Tested Ikke testet - + The app has not yet been tested. @@ -5247,7 +5399,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5255,27 +5407,27 @@ Screen. GameListSearchField - + of af - + result resultat - + results resultater - + Filter: Filter: - + Enter pattern to filter Indtast mønster til filtrering @@ -5283,47 +5435,47 @@ Screen. GameRegion - + Japan Japan - + North America - + Europe - + Australia - + China - + Korea - + Taiwan - + Invalid region Ugyldig region - + Region free @@ -5603,87 +5755,87 @@ Screen. Cycle-indeks: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Adresseregistre: %1, %2 - + Compare Result: %1, %2 Sammenlign resultat: %1, %2 - + Static Condition: %1 Statisk betingelse: %1 - + Dynamic Conditions: %1, %2 Dynamisk betingelse: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Loopparametre: %1 (gentager), %2 (initialisering), %3 (interval), %4 - + Instruction offset: 0x%1 Instruktionsoffset: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (sidste instruktion) @@ -5907,23 +6059,23 @@ Debug Message: - - Loading Shaders %1 / %2 + + Loading %3 %1 / %2 - + Launching... - + Now Loading %1 - + Estimated Time %1 @@ -5982,32 +6134,32 @@ Debug Message: Adgangskode: - + Room Name Rumnavn - + Preferred Application - + Host Vært - + Players Spillere - + Refreshing Genopfrisker - + Refresh List Genopfrisk liste @@ -6090,342 +6242,352 @@ Debug Message: Film - + Help - + Load File... Indlæs fil… - + Install CIA... Installer CIA… - + Connect to Artic Base... - + Set Up System Files... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit - + Pause Pause - + Stop Stop - + Save Gem - + Load Indlæs - + FAQ FAQ - + About Azahar Om Azahar - + Single Window Mode Tilstand med enkelt vindue - + Save to Oldest Slot - + Quick Save - + Load from Newest Slot - + Quick Load - + Configure... Konfigurer… - + Display Dock Widget Headers Vis titler på dokbare widgets - + Show Filter Bar Vis filterlinje - + Show Status Bar Vis statuslinje - + Create Pica Surface Viewer Opret Pica-overfladeviser - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame Næste frame - + Capture Screenshot Tag skærmbillede - + Dump Video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Opret rum - + Leave Room Forlad rum - + Direct Connect to Room Forbind direkte til rum - + Show Current Room Vis nuværende rum - + Fullscreen Fuld skærm - + Open Log Folder - + Opens the Azahar Log folder - + Default Standard - + Single Screen Enkelt skærm - + Large Screen Stor skærm - + Side by Side Side om side - + Separate Windows - + Hybrid Screen - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Byt om på skærme - + Rotate Upright - + Report Compatibility Rapporter kompatibilitet - + Restart Genstart - + Load... Indlæs... - + Remove Fjern - + Open Azahar Folder - + Configure Current Application... @@ -6498,7 +6660,7 @@ Debug Message: File: - Fil: + @@ -6590,7 +6752,7 @@ Debug Message: File: - Fil: + @@ -6996,32 +7158,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Ugyldig region - + Installed Titles - + System Titles - + Add New Application Directory - + Favorites diff --git a/dist/languages/de.ts b/dist/languages/de.ts index 328bd1110..d53dc207f 100644 --- a/dist/languages/de.ts +++ b/dist/languages/de.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + @@ -211,7 +211,7 @@ p, li { white-space: pre-wrap; } When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? - Wenn du einen Spieler blockierst, kannst du keine Nachrichten mehr von diesem empfangen.<br><br> Bist du sicher, dass du %1 blockieren möchten? + Wenn du einen Spieler blockierst, kannst du keine Nachrichten mehr von diesem empfangen.<br><br> Bist du sicher, dass du %1 blockieren möchtest? @@ -221,7 +221,7 @@ p, li { white-space: pre-wrap; } Ban - Bann + Bannen @@ -298,8 +298,8 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - Emulation: - Emulation: + Emulation + Emulation @@ -328,8 +328,8 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Dieser Nachbearbeitungseffekt passt die Audiogeschwindigkeit an die Emulationsgeschwindigkeit an und hilft, Audiostottern zu vermeiden. Dabei wird allerdings die Audiolatenz erhöht. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -338,8 +338,8 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Skaliert die Audiowiedergabegeschwindigkeit, um Einbrüche in der Emulations-Framerate auszugleichen. Dies bedeutet, dass Audio mit voller Geschwindigkeit wiedergegeben wird, auch wenn die Anwendungs-Framerate niedriger ist. Kann zu Audio-Fehlsynchronisierungsproblemen führen. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + @@ -403,6 +403,7 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. + Camera Kamera @@ -414,8 +415,8 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - Camera to configure: - Zu konfigurierende Kamera: + Camera to Configure + @@ -435,8 +436,8 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - Camera mode: - Kameramodus: + Camera mode + @@ -456,8 +457,8 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - Camera position: - Kameraposition: + Camera position + @@ -477,13 +478,13 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Wähle eine Quelle für das emulierte Kamerabild. Dies kann ein Bild oder eine echte Kamera sein. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Kamera-Bildquelle: + Camera Image Source + @@ -502,8 +503,8 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - File: - Datei: + File + Datei @@ -516,11 +517,6 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. Select the system camera to use Wähle die zu nutzende Systemkamera aus - - - Camera: - Kamera: - <Default> @@ -534,8 +530,8 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. - Flip: - Spiegelung: + Flip + @@ -560,7 +556,7 @@ Dies bannt sowohl den Forum-Nutzernamen, als auch die IP-Adresse. Select an image file every time before the camera is loaded - Wähle jedes Mal, bevor die Kamera eine Bilddatei lädt + Wähle jedes Mal eine Bilddatei, bevor die Kamera lädt @@ -727,7 +723,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Show log output in console - + Zeige Protokoll-Ausgabe in Konsole @@ -742,7 +738,7 @@ Möchtest du den Fehler ignorieren und fortfahren? <html><body>Immediately commits the debug log to file. Use this if Azahar crashes and the log output is being cut.<br>Enabling this feature will decrease performance, only use it for debugging purposes.</body></html> - <html><body>Überträgt das Debug Protokoll sofort in eine Datei. Verwende dies wenn Azahar abstürtzt und die Protokollausgabe abgeschnitten wird.<br> Das Aktivieren dieser Funktion verringert die Leistung, verwende sie nur zu Debugzwecken</body></html> + <html><body>Überträgt das Debug Protokoll sofort in eine Datei. Verwende dies, wenn Azahar abstürzt und die Protokollausgabe abgeschnitten wird.<br> Das Aktivieren dieser Funktion verringert die Leistung, verwende sie nur zu Debugzwecken.</body></html> @@ -767,7 +763,7 @@ Möchtest du den Fehler ignorieren und fortfahren? <html><body>Changes the emulated CPU clock frequency.<br>Underclocking can increase performance but may cause the application to freeze.<br>Overclocking may reduce application lag but also might cause freezes</body></html> - <html><body>Ändert die emulierte CPU-Taktfrequenz<br>Untertakten kann die Leistung steigern, kann aber zum Einfrieren der Anwendung führen. <br>Übertakten kann die Anwendungsverzögerung verringern, kann aber auch zum Einfrieren führen </body></html> + <html><body>Ändert die emulierte CPU-Taktfrequenz<br>Untertakten kann die Leistung steigern, kann aber zum Einfrieren der Anwendung führen. <br>Übertakten kann Lags in Anwendungen verringern, kann aber auch zum Einfrieren führen </body></html> @@ -802,7 +798,7 @@ Möchtest du den Fehler ignorieren und fortfahren? <html><head/><body><p>Introduces a delay to the first ever launched app thread if LLE modules are enabled, to allow them to initialize.</p></body></html> - <html><head/><body><p>Führt eine Verzögerung für den ersten gestarteten App-Thread ein, wenn LLE-Module aktiviert sind, um ihnen die Möglichkeit zu geben, sich zu initialisieren.</p></body></html> + <html><head/><body><p>Führt eine Verzögerung für den allerersten gestarteten App-Thread ein, wenn LLE-Module aktiviert sind, damit diese sich initialisieren können.</p></body></html> @@ -832,7 +828,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Validation layer not available - Validierungsschicht (Validation-Layer) nicht verfügbar + Validierungsebene nicht verfügbar @@ -847,7 +843,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Unable to enable command buffer dumping because the layer <strong>VK_LAYER_LUNARG_api_dump</strong> is missing. Please install the Vulkan SDK or the appropriate package of your distribution - Befehlspuffer kann nicht gedumpt werden, weil <strong>VK_LAYER_LUNARG_api_dump</strong> fehlt. Bitte installiere das Vulkan SDK oder das passende Paket für deine Distribution. + Befehlspuffer kann nicht gedumpt werden, weil <strong>VK_LAYER_LUNARG_api_dump</strong> fehlt. Bitte installiere das Vulkan SDK oder das passende Paket für deine Distribution. @@ -969,7 +965,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Auto (Window Size) - Auto (Fenstergröße) + Automatisch (Fenstergröße) @@ -1024,7 +1020,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Enable Linear Filtering - Aktiviere lineare Filterung + @@ -1088,8 +1084,8 @@ Möchtest du den Fehler ignorieren und fortfahren? - Reverse Side by Side - Invers Nebeneinander + Side by Side Full Width + @@ -1119,7 +1115,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Note: Depth values over 100% are not possible on real hardware and may cause graphical issues - Hinweis: Tiefenwerte über 100% sind auf echter Hardware nicht möglich und könnten grafischen Problemen verursachen + Hinweis: Tiefenwerte über 100% sind auf echter Hardware nicht möglich und könnten grafische Probleme verursachen @@ -1139,7 +1135,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Disable Right Eye Rendering - Rendering für das rechte Auge deaktivieren + @@ -1147,49 +1143,54 @@ Möchtest du den Fehler ignorieren und fortfahren? <html><head/><body><p>Deaktiviert die Darstellung des Bildes für das rechte Auge</p><p>Deaktiviert die Darstellung des Bildes für das rechte Auge, wenn der stereoskopische Modus nicht verwendet wird. Verbessert die Leistung in einigen Anwendungen erheblich, kann aber bei anderen Flackern verursachen. </p></body></html> - + + Swap Eyes + + + + Utility Dienstprogramm - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Ersetze Texturen mit PNG-Dateien.</p><p>Texturen werden von „load/textures/[Title-ID]/“ geladen.</p></body></html> - - Use Custom Textures - Benutzerdefinierte Texturen nutzen + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Dumpe Texturen als PNG-Datei.</p><p>Texturen werden unter „dump/textures/[Title-ID]/“ gedumpt.</p></body></html> - - - Dump Textures - Texturen dumpen - - <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - <html><head/><body><p>Lädt alle benutzerdefinierten Texturen beim Start in den Speicher, anstatt sie zu laden wenn die Anwendung sie benötigt.</p></body></html> + Dump textures + - - Preload Custom Textures - Benutzerdefinierte Texturen im Voraus laden + + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> + <html><head/><body><p>Lädt alle benutzerdefinierten Texturen beim Start in den Speicher, anstatt sie erst zu laden wenn die Anwendung sie benötigt.</p></body></html> + Preload custom textures + + + + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Lädt alle benutzerdefinierten Texturen asynchron mit Hintergrund-Threads, um das Stottern beim Laden zu reduzieren</p></body></html> - - Async Custom Texture Loading - Benutzerdefinierte Texturen asynchron laden + + Async custom texture loading + @@ -1201,91 +1202,111 @@ Möchtest du den Fehler ignorieren und fortfahren? - General - Allgemein + Updates + - Confirm exit while emulation is running - Zum Verlassen bestätigen, während Emulation läuft - - - - Pause emulation when in background - Emulation im Hintergrund pausieren - - - - Mute audio when in background - Ton stummschalten, wenn im Hintergrund - - - - Hide mouse on inactivity - Maus bei Inaktivität ausblenden - - - - Enable Gamemode - Spielmodus aktivieren - - - Check for updates Nach Aktualisierungen prüfen - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Allgemein + + + + Confirm exit while emulation is running + Zum Verlassen bestätigen, während Emulation läuft + + + + Pause emulation when in background + Emulation im Hintergrund pausieren + + + + Mute audio when in background + Ton stummschalten, wenn im Hintergrund + + + + Hide mouse on inactivity + Maus bei Inaktivität ausblenden + + + + Enable Gamemode + Spielmodus aktivieren + + + Emulation Emulation - + Use global emulation speed Globale Emulationsgeschwindigkeit nutzen - - Set emulation speed: - Emulationsgeschwindigkeit festlegen: + + Set emulation speed + - - Emulation Speed: - Emulationsgeschwindigkeit: + + Emulation Speed + - + Turbo Speed Limit: Turbogeschwindigkeitslimit: - + Screenshots Bildschirmfotos - + Use global screenshot path Globalen Bildschirmfotopfad nutzen - + Set screenshot path: Bildschirmfotopfad festlegen: - + Save Screenshots To Bildschirmfotos speichern in - + ... ... - + Reset All Settings Alle Einstellungen zurücksetzen @@ -1293,8 +1314,8 @@ Möchtest du den Fehler ignorieren und fortfahren? - - + + unthrottled ungedrosselt @@ -1304,12 +1325,12 @@ Möchtest du den Fehler ignorieren und fortfahren? Wähle Bildschirmfoto-Verzeichnis - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? Bist du sicher, dass du deine <b>Einstellungen zurücksetzen</b> und Azahar schließen möchtest? @@ -1363,18 +1384,18 @@ Möchtest du den Fehler ignorieren und fortfahren? - SPIR-V Shader Generation - SPIR-V-Shader-Erzeugung + SPIR-V shader generation + - Disable GLSL -> SPIR-V Optimizer - Deaktiviere GLSL -> SPIR-V Optimierer + Disable GLSL -> SPIR-V optimizer + <html><head/><body><p>Disables the SPIR-V optimization pass, reducing stuttering considerably while barely affecting performance.</p></body></html> - <html><head/><body><p>Deaktiviert den SPIR-V Optimierungs-schritt, was stottern reduziert und nur einen minimalen Einfluss auf die Leistung hat.</p></body></html> + <html><head/><body><p>Deaktiviert den SPIR-V Optimization Pass, was Stottern reduziert und die Leistung kaum beeinträchtigt.</p></body></html> @@ -1384,12 +1405,12 @@ Möchtest du den Fehler ignorieren und fortfahren? <html><head/><body><p>Use the selected graphics API to accelerate shader emulation.</p><p>Requires a relatively powerful GPU for better performance.</p></body></html> - <html><head/><body><p>Nutze die ausgewählte Grafik-API, um die Shader-Emulation zu beschleunigen.</p><p>Benötigt eine relativ starke GPU, für bessere Leistungen.</p></body></html> + <html><head/><body><p>Nutze die ausgewählte Grafik-API, um die Shader-Emulation zu beschleunigen.</p><p>Benötigt eine relativ starke GPU für bessere Leistungen.</p></body></html> - Enable Hardware Shader - Hardware-Shader aktivieren + Enable hardware shader + @@ -1398,8 +1419,8 @@ Möchtest du den Fehler ignorieren und fortfahren? - Accurate Multiplication - Genaue Multiplikation + Accurate multiplication + @@ -1408,8 +1429,8 @@ Möchtest du den Fehler ignorieren und fortfahren? - Enable Shader JIT - JIT-Shader aktivieren + Enable shader JIT + @@ -1418,18 +1439,18 @@ Möchtest du den Fehler ignorieren und fortfahren? - Enable Async Shader Compilation - Aktiviere asynchrone Shader-Kompilierung + Enable async shader compilation + - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Präsentation auf separaten Threads durchführen. Verbessert die Leistung bei Verwendung von Vulkan in den meisten Anwendungen.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + - Enable Async Presentation - Aktiviere asynchrone Präsentation + Enable async presentation + @@ -1439,7 +1460,7 @@ Möchtest du den Fehler ignorieren und fortfahren? <html><head/><body><p>Overrides the sampling filter used by applications. This can be useful in certain cases with poorly behaved applications when upscaling. If unsure, set this to Application Controlled</p></body></html> - <html><head/><body><p>Überschreibt die Sampling-Filter welche von Anwendungen benutzt werden. Dies kann in bestimmten Fällen bei schlecht funktionierenden Anwendungen beim Hochskalieren nützlich sein. Wenn Sie sich nicht sicher sind, setzen Sie diese Anwendung auf kkntrolliert</p></body></html> + <html><head/><body><p>Überschreibt die von Anwendungen benutzten Sampling-Filter. Dies kann in bestimmten Fällen bei schlecht funktionierenden Anwendungen beim Hochskalieren nützlich sein. Wenn du dir unsicher bist, setze dies auf „Anwendungsgesteuert“</p></body></html> @@ -1468,13 +1489,13 @@ Möchtest du den Fehler ignorieren und fortfahren? - Use Disk Shader Cache - Shader-Cache nutzen + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync verhindert Bildschirmzerrung, allerdings haben manche Grafikkarten eine schlechtere Leistung, wenn VSync aktiv ist. Lass es aktiviert, wenn du keinen Leistungsunterschied bemerkst. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1482,24 +1503,34 @@ Möchtest du den Fehler ignorieren und fortfahren? V-Sync aktivieren - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global Global nutzen - + Use per-application - Benutzung pro Anwendung + Anwendungsspezifisch benutzen - - Delay application render thread: - Verzögere Anwendungsrender-Thread: + + Delay Application Render Thread + - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> - <html><head/><body><p>Verzögert den emulierten Anwendungs-Render-Thread jedes Mal um die angegebene Anzahl von Millisekunden, wenn er Render-Befehle an die GPU sendet.</p><p> Passen Sie diese Funktion in den (sehr wenigen) Anwendungen mit dynamischer Framerate an, um Leistungsprobleme zu beheben.</p></body></html> + <html><head/><body><p>Verzögert den emulierten Anwendungs-Render-Thread jedes Mal um die angegebene Anzahl von Millisekunden, wenn er Render-Befehle an die GPU sendet.</p><p> Passe diese Funktion in den (sehr wenigen) Anwendungen mit dynamischer Framerate an, um Leistungsprobleme zu beheben.</p></body></html> @@ -1556,12 +1587,12 @@ Möchtest du den Fehler ignorieren und fortfahren? The per-application speed and turbo speed hotkeys cannot be bound at the same time. - Der Pro-Anwendungsgeschwindigkeits- und der Turbigeschwindigkeits-Hotkey kann nicht zur selben Zeit gebunden werden. + Die Hotkeys für Anwendungsspezifische Geschwindigkeit und Turbogeschwindigkeit können nicht gleichzeitig zugewiesen werden. The entered key sequence is already assigned to: %1 - Die eingegebene Tastenfolge ist bereits für: %1 zugewiesen + Die eingegebene Tastenfolge ist bereits zugewiesen für: %1 @@ -1581,7 +1612,7 @@ Möchtest du den Fehler ignorieren und fortfahren? The default key sequence is already assigned to: %1 - Die Standard-Tastenfolge ist bereits für: %1 zugewiesen + Die Standard-Tastenfolge ist bereits zugewiesen für: %1 @@ -1614,7 +1645,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Shoulder Buttons - Schulterknöpfe + Schultertasten @@ -1842,7 +1873,7 @@ Möchtest du den Fehler ignorieren und fortfahren? After pressing OK, first move your joystick horizontally, and then vertically. - Drücken Sie OK und bewegen Sie den Joystick zuerst horizontal, dann vertikal. + Drücke OK und bewege dann den Joystick zuerst horizontal, dann vertikal. @@ -1864,12 +1895,12 @@ Möchtest du den Fehler ignorieren und fortfahren? Auto mapping failed. Your controller may not have a corresponding mapping - Automatische Belegung fehlgeschlagen. Dein Controller könnte keine übereinstimmende Belegung haben + Automatische Belegung fehlgeschlagen. Deinem Controller könnte eine entsprechende Belegung fehlen After pressing OK, press any button on your joystick - Nachdem du auf „O.K.“ klickst, drücke eine Taste auf deinen Controller + Nachdem du auf „O.K.“ klickst, drücke eine Taste auf deinem Controller @@ -1982,13 +2013,13 @@ Möchtest du den Fehler ignorieren und fortfahren? - Swap Screens - Bildschirme tauschen + Swap screens + - Rotate Screens Upright - Bildschirme aufrecht rotieren + Rotate screens upright + @@ -2104,8 +2135,8 @@ Möchtest du den Fehler ignorieren und fortfahren? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Untere Bildschirmdeckkraft % (Nur OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + @@ -2276,8 +2307,8 @@ Möchtest du den Fehler ignorieren und fortfahren? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Mehr erfahren</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + @@ -2287,7 +2318,7 @@ Möchtest du den Fehler ignorieren und fortfahren? After pressing OK, press a button on the controller whose motion you want to track. - Nachdem du auf „O.K.“ geklickt hast, drücke eine Taste auf den Controller, dessen Bewegung erfasst werden soll. + Nachdem du auf „O.K.“ geklickt hast, drücke eine Taste auf dem Controller, dessen Bewegung erfasst werden soll. @@ -2435,7 +2466,7 @@ Möchtest du den Fehler ignorieren und fortfahren? Are you sure you want to <b>reset your settings for this application</b>? - Möchten sie Ihre <b>Einstellungen für diese Anwendung wirklich zurücksetzen? + Bist du sicher, dass du deine <b>Einstellungen für diese Anwendung zurücksetzen</b> möchtest? @@ -2452,8 +2483,8 @@ Möchtest du den Fehler ignorieren und fortfahren? - Use Virtual SD - Virtuelle SD-Karte benutzen + Use virtual SD card + @@ -2462,8 +2493,8 @@ Möchtest du den Fehler ignorieren und fortfahren? - Use Custom Storage - Benutzerdefinierten Speicher nutzen + Use custom storage location + @@ -2493,6 +2524,16 @@ Möchtest du den Fehler ignorieren und fortfahren? SDMC Directory SDMC-Verzeichnis + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2540,8 +2581,8 @@ Online-Funktionen (sofern installiert) - Region: - Region: + Region + Region @@ -2549,326 +2590,337 @@ Online-Funktionen (sofern installiert) Automatisch auswählen - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Nutzername - + Birthday Geburtstag - + January Januar - + February Februar - + March März - + April April - + May Mai - + June Juni - + July Juli - + August August - + September September - + October Oktober - + November November - + December Dezember - + Language Sprache - + Note: this can be overridden when region setting is auto-select Hinweis: Dies kann überschrieben werden, wenn als Region „Automatisch auswählen“ eingestellt wurde. - + Japanese (日本語) Japanisch (日本語) - + English Englisch - + French (français) Französisch (français) - + German (Deutsch) Deutsch (German) - + Italian (italiano) Italienisch (italiano) - + Spanish (español) Spanisch (español) - + Simplified Chinese (简体中文) Vereinfachtes Chinesisch (简体中文) - + Korean (한국어) Koreanisch (한국어) - + Dutch (Nederlands) Niederländisch (Nederlands) - + Portuguese (português) Portugiesisch (português) - + Russian (Русский) Russisch (Русский) - + Traditional Chinese (正體中文) Traditionelles Chinesisch (正體中文) - + Sound output mode Tonausgabemodus - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Land - + Clock Uhr - + System Clock Systemuhr - + Fixed Time Feste Zeit - + Startup time Zum Start benötigte Zeit - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time Versetzte Zeit - + days Tage - + HH:mm:ss HH:mm:ss - + Initial System Ticks Anfängliche System-Ticks - + Random Zufall - + Fixed Festgelegt - + Initial System Ticks Override Anfängliche System-Ticks überschreiben - + Play Coins Spielemünzen - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>Die Anzahl der Schritte pro Stunde, die vom Schrittzähler gemeldet wird, liegt im Bereich von 0 bis 65.535</p></body></html> - + Pedometer Steps per Hour Schrittzähler-Schritte pro Stunde - + Run System Setup when Home Menu is launched Systemeinrichtung ausführen, wenn das HOME-Menü gestartet wird - + Console ID: Konsolen-ID: - - + + Regenerate Wiederherstellen - + MAC: MAC: - - 3GX Plugin Loader: - 3GX-Plugin-Lader: + + 3GX Plugin Loader + - + Enable 3GX plugin loader 3GX-Plugin-Loader aktivieren - + Allow applications to change plugin loader state - Erlauben Sie Anwendungen, den Status des Plug-In-Loaders zu ändern + Erlaube Anwendungen, den Status des Plug-In-Loaders zu ändern - + Real Console Unique Data Einzigartige, echte Konsolendaten - + Your real console is linked to Azahar. - Ihre echte Konsole ist mit Azahar verknüpft. + Deine echte Konsole ist mit Azahar verknüpft. - + Unlink Verknüpfung aufheben - + OTP OTP - - - - + + + + Choose Auswählen - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. Systemeinstellungen sind nur verfügbar, wenn Anwendungen nicht ausgeführt werden. @@ -3560,7 +3612,7 @@ Online-Funktionen (sofern installiert) Select encrypted OTP file - Wähle die verschlüsselte OTP Datei + Wähle die verschlüsselte OTP-Datei @@ -3578,76 +3630,76 @@ Online-Funktionen (sofern installiert) Sed-Datei (*.sed)::Alle Dateien (*.*) - - + + Console ID: 0x%1 Konsolen-ID: 0x%1 - - + + MAC: %1 MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - Dadurch wird Ihre aktuelle virtuelle 3DS-Konsolen-ID durch eine neue ersetzt. Ihre aktuelle virtuelle 3DS-Konsolen-ID kann nicht wiederhergestellt werden. Dies kann unerwartete Auswirkungen auf Anwendungen haben. Dies kann fehlschlagen, wenn Sie eine veraltete Konfigurationsspeicherung verwenden. Weitermachen? + Dadurch wird deine aktuelle virtuelle 3DS-Konsolen-ID durch eine neue ersetzt. Deine aktuelle virtuelle 3DS-Konsolen-ID kann nicht wiederhergestellt werden. Dies kann unerwartete Auswirkungen auf Anwendungen haben. Dies kann fehlschlagen, wenn du eine veraltete Konfigurationsspeicherung verwendest. Fortfahren? - - - + + + Warning Warnung - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - Dadurch wird Ihre aktuelle MAC-Adresse durch eine neue ersetzt. Dies wird nicht empfohlen, wenn Sie die MAC-Adresse mithilfe des Setup-Tools von Ihrer echten Konsole erhalten haben. Weitermachen? + Dadurch wird deine aktuelle MAC-Adresse durch eine neue ersetzt. Dies wird nicht empfohlen, wenn du die MAC-Adresse mithilfe des Setup-Tools von deiner echten Konsole erhalten hast. Fortfahren? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - Dadurch wird die Verknüpfung zwischen Azahar und deiner echten Konsole getrennt, was folgendes mitsichbringt:<br><ul><li>Dein OTP, SecureInfo und LocalFriendCodeSeed werden von Azahar entfernt.</li><li>Deine Freundesliste wird zurückgesetzt und du wirst aus deinem NNID/PNID Account abgemeldet.</li><li>Systemdateien und eShop-Titel, die durch Azahar erhalten wurden, werden unzugänglich, bis die Konsole wieder verknüpft wird (Speicherdaten gehen nicht verloren).</li></ul><br>Forfahren? + Dadurch wird die Verknüpfung zwischen Azahar und deiner echten Konsole getrennt, was folgendes bedeutet:<br><ul><li>Dein OTP, SecureInfo und LocalFriendCodeSeed werden von Azahar entfernt.</li><li>Deine Freundesliste wird zurückgesetzt und du wirst aus deinem NNID/PNID Account abgemeldet.</li><li>Systemdateien und eShop-Titel, die durch Azahar erhalten wurden, werden unzugänglich, bis die Konsole wieder verknüpft wird (Speicherdaten gehen nicht verloren).</li></ul><br>Forfahren? - + Invalid country for configured region Ungültiges Land für die eingestellte Region - + Invalid country for console unique data - Ungültiges Land für die einzigartigen Konsolendaten + Ungültiges Land für die konsolenspezifischen Daten - + Status: Loaded Status: Geladen - + Status: Loaded (Invalid Signature) Status: Geladen (Ungültige Signatur) - + Status: Loaded (Region Changed) Status: Geladen (Region geändert) - + Status: Not Found Status: Nicht gefunden - + Status: Invalid Status: Ungültig - + Status: IO Error Status: I/O-Fehler @@ -3763,23 +3815,23 @@ Ziehe Punkte, um ihre Position zu verändern, oder doppelklicke auf Zellen in de - Interface language: - Oberflächensprache + Interface Language + - Theme: - Design: + Theme + Application List - App Liste + Anwendungsliste - Icon Size: - Icongröße: + Icon Size + @@ -3799,8 +3851,8 @@ Ziehe Punkte, um ihre Position zu verändern, oder doppelklicke auf Zellen in de - Row 1 Text: - Zeile 1-Text: + Row 1 Text + @@ -3834,18 +3886,18 @@ Ziehe Punkte, um ihre Position zu verändern, oder doppelklicke auf Zellen in de - Row 2 Text: - Zeile 2-Text: + Row 2 Text + - Hide Titles without Icon - Titel ohne Icon verbergen + Hide titles without icon + - Single Line Mode - Einzeiliger Modus + Single line mode + @@ -3854,8 +3906,8 @@ Ziehe Punkte, um ihre Position zu verändern, oder doppelklicke auf Zellen in de - Show Advanced Frame Time Info - Zeige detaillierte Frame-Zeit Info + Show advanced frame time info + @@ -3937,12 +3989,12 @@ Ziehe Punkte, um ihre Position zu verändern, oder doppelklicke auf Zellen in de DirectConnectWindow - + Connecting Verbindevorgang... - + Connect Verbunden @@ -4062,780 +4114,870 @@ Bitte überprüfe deine FFmpeg-Installation, die für die Kompilierung verwendet GMainWindow - + No Suitable Vulkan Devices Detected Keine geeigneten Vulkan-Geräte gefunden - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - Vulkan-Initialisierung beim Starten fehlgeschlagen.<br/>Deine Grafikkarte unterstützt möglicherweise „Vulkan 1.1“ nicht, oder ist nicht auf den aktuellsten Stand. + Vulkan-Initialisierung beim Starten fehlgeschlagen.<br/>Deine Grafikkarte unterstützt möglicherweise „Vulkan 1.1“ nicht, oder ist nicht auf dem aktuellsten Stand. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - Aktuelle Artic Daten Verkehrsgeschwindigkeit. Höhere Werte weisen auf größere Übertragungslasten hin + Aktuelle Artic Daten-Verkehrsgeschwindigkeit. Höhere Werte weisen auf größere Übertragungslasten hin. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Derzeitige Emulationsgeschwindigkeit. Werte höher oder niedriger als 100% zeigen, dass die Emulation schneller oder langsamer läuft als auf einem 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. Wie viele Bilder pro Sekunde die App aktuell anzeigt. Dies ist von App zu App und von Szene zu Szene unterschiedlich. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - Die benötigte Zeit um ein 3DS-Einzelbild zu emulieren (V-Sync oder Bildratenbegrenzung nicht mitgezählt). Bei Echtzeitemulation sollte dieser Wert 16,67ms betragen. + Die benötigte Zeit um ein 3DS-Einzelbild zu emulieren (V-Sync oder Bildratenbegrenzung nicht mitgezählt). Bei Echtzeitemulation sollte dieser Wert höchstens 16,67ms betragen. - + MicroProfile (unavailable) MicroProfile (Nicht verfügbar) - + Clear Recent Files Zuletzt verwendete Dateien zurücksetzen - + &Continue &Fortsetzen - + &Pause &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar führt eine Anwendung aus - - + + Invalid App Format Falsches App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - Ihr App format ist nicht unterstützt. <br/>Bitte folgen Sie den Anleitungen um Ihre <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>Spielkarten</a> oder <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>Ihre installierten Titel zu redumpen</a>. + Dein App-Format wird nicht unterstützt. <br/>Bitte folge den Anleitungen um deine <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>Spielkarten</a> oder <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installierten Titel</a> erneut zu dumpen. - + App Corrupted - App beschädigt - - - - Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - Ihre App ist beschädigt. <br/>Folgen Sie bitte den Anleitungen um Ihre <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>Spielkarten</a> oder <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>Ihre installierten Titel erneut zu dumpen</a>. - - - - App Encrypted - App versclüsselt - - - - Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - Ihre App ist verschlüsselt. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Bitte lesen Sie unseren Blog für weitere Informationen.</a> + Anwendung beschädigt - Unsupported App - Nicht unterstützte App + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. + Deine App ist beschädigt. <br/>Folge bitte den Anleitungen um deine <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>Spielkarten</a> oder <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installierten Titel</a> erneut zu dumpen. - + + App Encrypted + Anwendung verschlüsselt + + + + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> + Deine App ist verschlüsselt. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Bitte lies unseren Blog für weitere Informationen.</a> + + + + Unsupported App + Nicht unterstützte Anwendung + + + GBA Virtual Console is not supported by Azahar. GBA Virtual Console wird nicht von Azahar unterstützt - - + + Artic Server Artic Server - - Error while loading App! - Fehler beim laden der App + + Invalid system mode + - + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + + Error while loading App! + Fehler beim Laden der Anwendung! + + + An unknown error occurred. Please see the log for more details. Ein unbekannter Fehler ist aufgetreten. Mehr Details im Protokoll. - + CIA must be installed before usage CIA muss vor der Benutzung installiert sein - + Before using this CIA, you must install it. Do you want to install it now? Vor dem Nutzen dieser CIA muss sie installiert werden. Soll dies jetzt getan werden? - + Quick Load Schnellladen - + Quick Save Schnellspeichern - - + + Slot %1 Speicherplatz %1 - + %2 %3 %2 %3 - + Quick Save - %1 Schnellspeichern - %1 - + Quick Load - %1 Schnellladen - %1 - + Slot %1 - %2 %3 Speicherplatz %1 - %2 %3 - + Error Opening %1 Folder Fehler beim Öffnen des Ordners %1 - - + + Folder does not exist! Ordner existiert nicht! - + Remove Play Time Data Spielzeitdaten löschen - + Reset play time? Spielzeit zurücksetzen - - - - + + + + Create Shortcut Verknüpfung erstellen - + Do you want to launch the application in fullscreen? Möchtest du die Anwendung in Vollbild starten? - + Successfully created a shortcut to %1 Es wurde erfolgreich eine Verknüpfung für %1 erstellt - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - Dadurch wird eine Verknüpfung mit dem aktuellen AppImage erstellt. Dies funktioniert möglicherweise nicht mehr, wenn du aktualisierst. Möchtest du fortfahren? + Dadurch wird eine Verknüpfung zum aktuellen AppImage erstellt. Dies funktioniert möglicherweise nicht mehr richtig, wenn du aktualisierst. Möchtest du fortfahren? - + Failed to create a shortcut to %1 Es konnte keine Verknüpfung für %1 erstellt werden - + Create Icon Icon erstellen - + Cannot create icon file. Path "%1" does not exist and cannot be created. Es konnte kein Icon-Pfad erstellt werden. „%1“ existiert nicht, oder kann nicht erstellt werden. - + Dumping... Dumpvorgang... - - + + Cancel Abbrechen - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. Konnte Base-RomFS nicht dumpen. Schau im Protokoll für weitere Informationen nach. - + Error Opening %1 Fehler beim Öffnen von %1 - + Select Directory Verzeichnis auswählen - + Properties Eigenschaften - + The application properties could not be loaded. Die Anwendungseigenschaften konnten nicht geladen werden. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS Programmdatei (%1);;Alle Dateien (*.*) - + Load File Datei laden - - + + Set Up System Files Systemdateien einrichten - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - <p>Azahar benötigt Dateien von einer echten Konsole, um einige seiner Funktionen nutzen zu können. <br>Du kannst diese Dateien mit dem <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Einrichtung-Tool</a> bekommen.<br>Hinweise:<ul><li><b>Bei diesem Vorgang werden konsolenspezifische Dateien in Azahar installiert. Gib deine Benutzer- oder NAND-Ordner nicht frei, <br>nachdem der Einrichtungsvorgang durchgeführt wurde!</b></li><li>Während des Einrichtungsvorgangs, verknüpft Azahar deine Konsole mit dem Einrichtungstool. Du kannst die Verknüpfung <br>jederzeit im „Systemdateien“-Reiter in den Emulatoreinstellungen trennen.</li><li>Gehe nicht zeitgleich mit deinem eigenen 3DS und Azahr online, <br>da dies sonst zu Probleme führen könnte.</li><li>Damit die New 3DS-Einrichtung funktioniert, ist zuerst eine Old 3DS-Einrichtung erforderlich (Es wird empfohlen beides einzurichten).</li><li>Beide Setup-Modi funktionieren unabhängig vom Modell der Konsole, auf dem das Setup-Tool ausgeführt wird.</li></ul><hr></p> + <p>Azahar benötigt Konsolendaten und Firmware-Dateien von einer echten Konsole, um einige Funktionen nutzen zu können. <br>Du kannst solche Dateien mit dem <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Einrichtungs-Tool</a> einrichten.<br>Hinweise:<ul><li><b>Bei diesem Vorgang werden konsolenspezifische Dateien in Azahar installiert. Gib deine Benutzer- oder NAND-Ordner nicht frei, <br>nachdem der Einrichtungsvorgang durchgeführt wurde!</b></li><li>Während des Einrichtungsvorgangs verknüpft Azahar deine Konsole mit dem Einrichtungstool. Du kannst die Verknüpfung <br>jederzeit im „Systemdateien“-Reiter in den Emulatoreinstellungen trennen.</li><li>Gehe nicht zeitgleich mit deinem eigenen 3DS und Azahar online, <br>da dies sonst zu Problemen führen könnte.</li><li>Damit die New 3DS-Einrichtung funktioniert, ist zuerst eine Old 3DS-Einrichtung erforderlich (Es wird empfohlen, beides einzurichten).</li><li>Beide Setup-Modi funktionieren unabhängig vom Modell der Konsole, auf dem das Setup-Tool ausgeführt wird.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: Gib die Adresse des Azahar Artic Einrichtung-Tools ein: - + <br>Choose setup mode: <br>Wähle den Einrichtungsmodus: - + (ℹ️) Old 3DS setup (ℹ️) Old 3DS-Einrichtung - - + + Setup is possible. Einrichtung ist möglich. - + (⚠) New 3DS setup (⚠) New 3DS-Einrichtung - + Old 3DS setup is required first. Du musst zuerst die Old 3DS-Einrichtung abschließen. - + (✅) Old 3DS setup (✅) Old 3DS-Einrichtung - - + + Setup completed. Einrichtung abgeschlossen - + (ℹ️) New 3DS setup (ℹ️) New 3DS-Einrichtung - + (✅) New 3DS setup (✅) New 3DS-Einrichtung - + The system files for the selected mode are already set up. Reinstall the files anyway? Die Systemdateien für den ausgewählten Modus sind bereits eingerichtet. Die Dateien trotzdem neu installieren? - + Load Files Dateien laden - - 3DS Installation File (*.CIA*) - 3DS-Installationsdatei (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Alle Dateien (*.*) - + Connect to Artic Base Verbinde dich mit Artic-Base - + Enter Artic Base server address: Gib die Artic-Base-Serveradresse ein - + %1 has been installed successfully. %1 wurde erfolgreich installiert. - + Unable to open File Datei konnte nicht geöffnet werden - + Could not open %1 Konnte %1 nicht öffnen - + Installation aborted Installation abgebrochen - + The installation of %1 was aborted. Please see the log for more details Die Installation von %1 wurde abgebrochen. Schaue im Protokoll für weitere Informationen nach - + Invalid File Ungültige Datei - + %1 is not a valid CIA %1 ist keine gültige CIA - + CIA Encrypted CIA verschlüsselt - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Deine CIA Datei ist verschlüsselt. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Bitte lese unseren Blog für mehr Info.</a> - + Unable to find File Datei konnte nicht gefunden werden - + Could not find %1 %1 konnte nicht gefunden werden - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... '%1' wird deinstalliert… - + Failed to uninstall '%1'. Deinstallation von '%1' fehlgeschlagen. - + Successfully uninstalled '%1'. '%1' erfolgreich deinstalliert. - + File not found Datei nicht gefunden - + File "%1" not found Datei "%1" nicht gefunden - + Savestates Speicherstände - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - Warnung: Speicherstände sind kein Ersatz für In-App-Speicherungen, und sind nicht als zuverlässig gedacht + Warnung: Speicherstände sind kein Ersatz für In-App-Speicherungen, und sind nicht als zuverlässig gedacht. Nutzung auf eigene Gefahr! - - - + + + Error opening amiibo data file Fehler beim Öffnen der Amiibo-Datei - + A tag is already in use. Eine Markierung wird schon genutzt. - + Application is not looking for amiibos. - Rie Anwendung sucht keine Amiibos. + Die Anwendung sucht keine Amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo-Datei (%1);; Alle Dateien (*.*) - + Load Amiibo Amiibo wird geladen - + Unable to open amiibo file "%1" for reading. Die Amiibo-Datei "%1" konnte nicht zum Lesen geöffnet werden. - + Record Movie Aufnahme starten - + Movie recording cancelled. Aufnahme abgebrochen. - - + + Movie Saved Aufnahme gespeichert - - + + The movie is successfully saved. Die Aufnahme wurde erfolgreich gespeichert. - + Application will unpause Die Anwendung wird fortgesetzt - + The application will be unpaused, and the next frame will be captured. Is this okay? - Die Anwendung wird fortgesetzt und das nächste Bild wird Aufgenommen. Ist das okay? + Die Anwendung wird fortgesetzt und das nächste Bild wird aufgenommen. Ist das okay? - + Invalid Screenshot Directory Ungültiges Bildschirmfoto-Verzeichnis - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - Kann das angegebene Bildschirmfoto-Verzeichnis nicht erstellen. Der Bildschirmfotopfad wurde auf die Voreinstellung zurückgesetzt. + Das angegebene Bildschirmfoto-Verzeichnis kann nicht erstellt werden. Der Bildschirmfotopfad wurde auf die Voreinstellung zurückgesetzt. - + Could not load video dumper Konnte Video-Dumper nicht laden - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. To view a guide on how to install FFmpeg, press Help. - FFmpeg konnte nicht geladen werden. Stellen Sie sicher, dass eine kompatible Version installiert ist. + FFmpeg konnte nicht geladen werden. Stelle sicher, dass eine kompatible Version installiert ist. -Um FFmpeg in Azahar zu installieren, klicken Sie auf „Offnen“ und wählen Sie Ihr FFmpeg-Verzeichnis. +Um FFmpeg in Azahar zu installieren, klicke auf „Offnen“ und wähle dein FFmpeg-Verzeichnis. -Um eine Anleitung zur Installation von FFmpeg anzuzeigen, klicken Sie auf „Hilfe“. +Um eine Anleitung zur Installation von FFmpeg anzuzeigen, klicke auf „Hilfe“. - + + Load 3DS ROM Files + + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + Select FFmpeg Directory Wähle FFmpeg-Verzeichnis - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. Das angegebene FFmpeg-Verzeichnis fehlt %1. Bitte stelle sicher, dass du das richtige Verzeichnis ausgewählt hast. - + FFmpeg has been sucessfully installed. FFmpeg wurde erfolgreich installiert. - + Installation of FFmpeg failed. Check the log file for details. Installation von FFmpeg fehlgeschlagen. Prüfe die Protokolldatei für Details. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - Video-Dump konnte nicht gestartet werden.1<br>Bitte überprüfe, ob der Video-Encoder richtig eingestellt ist.<br>Schau im Protokoll nach, für weitere Informationen. + Video-Dump konnte nicht gestartet werden.<br>Bitte überprüfe, ob der Video-Encoder richtig eingestellt ist.<br>Schau im Protokoll für weitere Informationen nach. - + Recording %1 %1 wird aufgenommen - + Playing %1 / %2 %1 / %2 wird abgespielt - + Movie Finished Aufnahme beendet - + (Accessing SharedExtData) (Zugriff auf SharedExtData) - + (Accessing SystemSaveData) (Zugriff auf SystemSaveData) - + (Accessing BossExtData) (Zugriff auf BossExtData) - + (Accessing ExtData) (Zugriff auf ExtData) - + (Accessing SaveData) (Zugriff auf SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 Artic Traffic: %1 %2%3 - + Speed: %1% Geschwindigkeit: %1% - + Speed: %1% / %2% Geschwindigkeit: %1% / %2% - + App: %1 FPS App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Einzelbild: %1 ms - + VOLUME: MUTE LAUTSTÄRKE: STUMM - + VOLUME: %1% Volume percentage (e.g. 50%) LAUTSTÄRKE: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - %1 fehlt. <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Bitte dumpe deine Systemarchive</a>. <br/>Das Fortfahren könnte zu ungewollten Abstürzen oder Problemen führen. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + - + A system archive Ein Systemarchiv - + System Archive Not Found Systemarchiv nicht gefunden - + System Archive Missing Systemarchiv fehlt - + Save/load Error Speichern/Laden Fehler - + Fatal Error Schwerwiegender Fehler - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Ein fataler Fehler ist aufgetreten. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Überprüfe das Protokoll</a> für weitere Informationen.<br/>Das Fortfahren könnte zu ungewollten Abstürzen oder Problemen führen. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + - + Fatal Error encountered Auf schwerwiegenden Fehler gestoßen - + Continue Fortsetzen - + Quit Application Beende die Anwendung - + OK O.K. - + Would you like to exit now? Möchtest du die Anwendung jetzt verlassen? - + The application is still running. Would you like to stop emulation? - Die Anwendung wird läuft noch. Möchten sie die Emulation stoppen? + Die Anwendung läuft noch. Möchtest du die Emulation stoppen? - + Playback Completed Wiedergabe abgeschlossen - + Movie playback completed. Wiedergabe der Aufnahme abgeschlossen. - + Update Available Aktualisierung verfügbar - + Update %1 for Azahar is available. Would you like to download it? Für Azahar ist die Aktualisierung %1 verfügbar. Soll es heruntergeladen werden? - + Primary Window Hauptfenster - + Secondary Window Zweifenster @@ -4898,284 +5040,294 @@ Soll es heruntergeladen werden? GRenderWindow - + OpenGL not available! OpenGL nicht verfügbar! - + OpenGL shared contexts are not supported. OpenGL-Shared-Contexts sind nicht unterstützt. - + Error while initializing OpenGL! Fehler beim Initialisieren von OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - Deine Grafikkarte unterstützt möglicherweise kein OpenGL, oder sie ist nicht dem neuesten Stand. + Deine Grafikkarte unterstützt möglicherweise kein OpenGL, oder sie ist nicht auf dem neuesten Stand. - + Error while initializing OpenGL 4.3! Fehler beim Initialisieren von „OpenGL 4.3“! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Deine Grafikkarte unterstützt möglicherweise kein „OpenGL 4.3“, oder sie ist nicht auf dem neusten Stand.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! Fehler beim Initialisieren von „OpenGL ES 3.2“! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - Deine Grafikkarte unterstützt möglicherweise kein„OpenGL ES 3.2“, oder ist nicht auf dem neusten Stand.<br><br>GL-Renderer:<br>%1 + Deine Grafikkarte unterstützt möglicherweise kein „OpenGL ES 3.2“, oder sie ist nicht auf dem neusten Stand.<br><br>GL-Renderer:<br>%1 GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - WICHTIG: Verschlüsselte Dateien und .3ds-Dateien werden nicht mehr unterstützt. Eine Entschlüsselung und/oder Umbenennung in .cci kann erforderlich sein. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Erfahre mehr</a> - - - - Don't show again - Nicht nochmal anzeigen - - - - + + Compatibility Kompatibilität - - + + Region Region - - + + File type Dateiart - - + + Size Größe - - + + Play time Spielzeit - + Favorite Favorit - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open Öffnen - + Application Location - Anwendungsstandort + Anwendungsspeicherort - + Save Data Location Speicherdatenstandort - + Extra Data Location Extradatenstandort - + Update Data Location - Speicherdatenverzeichnis aktualisieren + Updatedaten-Verzeichnis - + DLC Data Location DLC-Verzeichnis - + Texture Dump Location Textur-Dump-Pfad - + Custom Texture Location Benutzerdefinierte-Texturen-Verzeichnis - + Mods Location Mod-Verzeichnis - + Dump RomFS RomFS dumpen - + Disk Shader Cache Shader-Cache - + Open Shader Cache Location Shader-Cache-Standort öffnen - + Delete OpenGL Shader Cache OpenGL-Shader-Cache löschen - + + Delete Vulkan Shader Cache + + + + Uninstall Deinstallieren - + Everything Alles - + Application Anwendung - + Update - Updates + Update - + DLC Zusatzinhalte - + Remove Play Time Data Spielzeitdaten entfernen - + Create Shortcut Verknüpfung erstellen - + Add to Desktop Zum Desktop hinzufügen - + Add to Applications Menu Zum Anwendungsmenü hinzufügen - + + Stress Test: App Launch + + + + Properties Eigenschaften - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - Möchten Sie wirklich vollständig deinstallieren '%1'? + Möchtest du '%1' wirklich vollständig deinstallieren? -Dadurch werden die Anwendung, sofern installiert ,sowie alle installierten Updates oder DLCs gelöscht. +Dadurch werden die Anwendung, sofern installiert, sowie alle installierten Updates oder DLCs gelöscht. - - + + %1 (Update) %1 (Update) - - + + %1 (DLC) %1 (Zusatzinhalt) - + Are you sure you want to uninstall '%1'? - Bist du sicher, dass du '%1' deinstallieren möchten? + Bist du sicher, dass du '%1' deinstallieren möchtest? - + Are you sure you want to uninstall the update for '%1'? - Bist du sicher, dass du die Updates für '%1' deinstallieren möchten? + Bist du sicher, dass du das Update für '%1' deinstallieren möchtest? - + Are you sure you want to uninstall all DLC for '%1'? - Bist du sicher, dass du die Zusatzinhalte für '%1' deinstallieren möchten? + Bist du sicher, dass du die Zusatzinhalte für '%1' deinstallieren möchtest? - + Scan Subfolders Unterordner scannen - + Remove Application Directory Anwendungsverzeichnis entfernen - + Move Up Hoch bewegen - + Move Down Runter bewegen - + Open Directory Location Verzeichnispfad öffnen - + Clear Leeren - + Name Name @@ -5183,115 +5335,115 @@ Dadurch werden die Anwendung, sofern installiert ,sowie alle installierten Updat GameListItemCompat - + Perfect Perfekt - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. Die App funktioniert einwandfrei, ohne Audio- oder Grafikfehler, alle getesteten Funktionen funktionieren wie vorgesehen, ohne -eine erforderlichen Problemumgehung. +jegliche Problemumgehungen. - + Great Gut - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. Die App funktioniert mit kleineren Grafik- oder Audiofehlern und ist von Anfang bis Ende spielbar. Möglicherweise sind Problemumgehungen erforderlich. - + Okay Okay - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - Die App funktioniert mit erheblichen Grafik- oder Audiofehlern, ist jedoch mit folgenden Problembehebungen von Anfang bis Ende spielbar + Die App funktioniert mit erheblichen Grafik- oder Audiofehlern, ist jedoch mit Problemumgehungen von Anfang bis Ende spielbar - + Bad Schlecht - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. Die App funktioniert, weist jedoch erhebliche Grafik- oder Audiofehler auf. Aufgrund von Störungen ist es nicht möglich, in bestimmten Bereichen Fortschritte zu machen auch mit Workarounds. - + Intro/Menu Intro/Menü - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. Die App ist aufgrund erheblicher Grafik- oder Audiofehler völlig unspielbar. Es ist nicht möglich, über den Startbildschirm hinauszugehen. - + Won't Boot Startet nicht - + The app crashes when attempting to startup. - Die App stürtzt beim Versuch zu starten ab + Die Anwendung stürtzt beim Versuch zu starten ab - + Not Tested Nicht getestet - + The app has not yet been tested. - Die App wurde noch nicht getestet + Die Anwendung wurde noch nicht getestet GameListPlaceholder - + Double-click to add a new folder to the application list - Doppel-klicke um einen neuen Ordner zur Anwendungs Liste hinzuzufügen + Klicke doppelt, um einen neuen Ordner zur Anwendungsliste hinzuzufügen GameListSearchField - + of von - + result Ergebnis - + results Ergebnisse - + Filter: Filter: - + Enter pattern to filter Gib Wörter zum Filtern ein @@ -5299,47 +5451,47 @@ Screen. GameRegion - + Japan Japan - + North America Nordamerika - + Europe Europa - + Australia Australien - + China China - + Korea Korea - + Taiwan Taiwan - + Invalid region Ungültige Region - + Region free Regionsfrei @@ -5512,7 +5664,7 @@ Screen. Failed to completely write surface data to file. The saved data will likely be corrupt. - Konnte Oberflächendaten nicht komplett in eine Datei schreiben. Die gespeicherten Daten sind wahrscheinlich kaputt. + Oberflächendaten konnten nicht komplett in die Datei geschrieben werden. Die gespeicherten Daten sind wahrscheinlich korrupt. @@ -5620,87 +5772,87 @@ Wenn nein, werden die aufgenommenen Daten verworfen. Cycle-Index: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Adressenregister: %1, %2 - + Compare Result: %1, %2 Ergebnis vergleichen: %1, %2 - + Static Condition: %1 Statische Bedingung: %1 - + Dynamic Conditions: %1, %2 Dynamische Konditionen: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Schleifenparameter: %1 (repeats), %2 (initializer), %3 (increment), %4 - + Instruction offset: 0x%1 Instruktionsverschiebung: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (letzte Instruktion) @@ -5917,32 +6069,32 @@ Debug-Meldung: Preloading Textures %1 / %2 - Lade Texturen %1 / %2 im Voraus + Lade Texturen im Voraus %1 / %2 Preparing Shaders %1 / %2 - Bereite Shader %1 / %2 vor + Bereite Shader vor %1 / %2 + + + + Loading %3 %1 / %2 + - Loading Shaders %1 / %2 - Lade Shader %1 / %2 - - - Launching... Startvorgang... - + Now Loading %1 Lädt %1 - + Estimated Time %1 Geschätzte verbleibende Zeit %1 @@ -6001,32 +6153,32 @@ Debug-Meldung: Passwort: - + Room Name Raumname - + Preferred Application Bevorzugte Anwendung - + Host Host - + Players Spieler - + Refreshing Neu Laden - + Refresh List Liste aktualisieren @@ -6109,342 +6261,352 @@ Debug-Meldung: Aufnahme - + Help Hilfe - + Load File... Datei laden... - + Install CIA... CIA installieren... - + Connect to Artic Base... Verbinde dich mit Artic-Base - + Set Up System Files... Systemdateien einrichten... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit Beenden - + Pause Pausieren - + Stop - Stop + Stoppen - + Save Speichern - + Load Laden - + FAQ F&A - + About Azahar Über Azahar - + Single Window Mode Einzelfenstermodus - + Save to Oldest Slot Im ältesten Slot speichern - + Quick Save Schnellspeichern - + Load from Newest Slot Vom neuesten Slot laden - + Quick Load Schnellladen - + Configure... Konfigurieren... - + Display Dock Widget Headers Dock Widget Header anzeigen - + Show Filter Bar Filterleiste anzeigen - + Show Status Bar Statusleiste anzeigen - + Create Pica Surface Viewer Pica-Oberflächenansicht - + Record... Aufnehmen... - + Play... Abspielen... - + Close Schließen - + Save without Closing Speichern ohne zu schließen - + Read-Only Mode Nur-Lesen-Modus - + Advance Frame Nächster Frame - + Capture Screenshot Screenshot aufnehmen - + Dump Video Video dumpen + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms Durchsuche öffentliche Räume - + Create Room Raum erstellen - + Leave Room Raum verlassen - + Direct Connect to Room Direkt verbinden - + Show Current Room Zeige aktuellen Raum an - + Fullscreen Vollbild - + Open Log Folder Protokoll-Ordner öffnen - + Opens the Azahar Log folder - Öffnet den Azahar-Protokoll Ordner + Öffnet den Azahar-Protokoll-Ordner - + Default Standard - + Single Screen Einzelner Bildschirm - + Large Screen Großer Bildschirm - + Side by Side Nebeneinander - + Separate Windows Getrennte Fenster - + Hybrid Screen Hybride-Bildschirme - + Custom Layout - Benutzerdefinierte Anordnung + Benutzerdefiniertes Layout - + Top Right Oben Rechts - + Middle Right Mitte rechts - + Bottom Right Unten links - + Top Left Oben Links - + Middle Left Mitte links - + Bottom Left Unten links - + Above Oben - + Below Unten - + Swap Screens Bildschirme tauschen - + Rotate Upright Aufrecht drehen - + Report Compatibility Kompatibilität melden - + Restart Neustart - + Load... Laden... - + Remove Entfernen - + Open Azahar Folder Öffne den Azahar-Ordner - + Configure Current Application... Konfiguriere die aktuelle Anwendung... @@ -6590,7 +6752,7 @@ Debug-Meldung: Application used in this movie is not in Applications list. - Die in diesem Film verwendete Anwendung befindet sich nicht in der Anwendungs liste + Die in diesem Film verwendete Anwendung befindet sich nicht in der Anwendungsliste @@ -6678,7 +6840,7 @@ Debug-Meldung: Failed to update the room information. Please check your Internet connection and try hosting the room again. Debug Message: - Aktualisieren der Raum-Informationen fehlgeschlagen. Überprüfen deine Internetverbindung und versuchen den Raum erneut zu hosten. + Aktualisieren der Raum-Informationen fehlgeschlagen. Überprüfe deine Internetverbindung und versuche den Raum erneut zu hosten. Debug-Meldung: @@ -6740,7 +6902,7 @@ Debug-Meldung: You must choose a Preferred Application to host a room. If you do not have any applications in your Applications list yet, add an applications folder by clicking on the plus icon in the Applications list. - Die musst eine bevorzugte Anwendung auswählen, um einen Raum zuhosten. Wenn du noch keine Anwendungen in deiner Anwendungs Liste hast, füge einen Anwendungs Ordner hinzu indem du das Plus in der Anwendungs Liste klickst. + Du musst eine bevorzugte Anwendung auswählen, um einen Raum zu hosten. Wenn du noch keine Anwendungen in deiner Anwendungsliste hast, füge einen Anwendungsordner hinzu, indem du auf das Plus in der Anwendungsliste klickst. @@ -6766,12 +6928,12 @@ Eventuell muss Azahar neugestartet werden. The host of the room has banned you. Speak with the host to unban you or try a different room. - Der Raumgastgeber hat dich gebannt. Spreche mit dem Gastgeber und bitte darum, wieder freigeschaltet zu werden, oder probiere einen anderen Raum. + Der Raumgastgeber hat dich gebannt. Sprich mit dem Gastgeber und bitte darum, wieder freigeschaltet zu werden, oder probiere einen anderen Raum. Version mismatch! Please update to the latest version of Azahar. If the problem persists, contact the room host and ask them to update the server. - Alte Version gefunden. Bitte aktualisiere Azahar auf die aktuellste Version. Wenn das Problem weiterhin bestehen bleibt, sprich den Raumgastgeber an und bitte drum, den Server aktualisieren zu lassen. + Version stimmt nicht überein! Bitte aktualisiere Azahar auf die aktuellste Version. Wenn das Problem weiterhin bestehen bleibt, sprich den Raumgastgeber an und bitte drum, den Server zu aktualisieren. @@ -6791,12 +6953,12 @@ Eventuell muss Azahar neugestartet werden. You have been kicked by the room host. - Du wurdest vom Raumgastgeber rausgeworfen. + Du wurdest vom Raumhost rausgeworfen. MAC address is already in use. Please choose another. - Die MAC Adresse wird schon genutzt. Bitte wählen Sie eine andere. + Diese MAC-Adresse wird schon genutzt. Bitte wähle eine andere. @@ -7019,32 +7181,32 @@ Vielleicht hat dieser Nutzer bereits den Raum verlassen. %1 (0x%2) - + Unsupported encrypted application Nicht unterstützte verschlüsselte Anwendung - + Invalid region Ungültige Region - + Installed Titles Installierte Titel - + System Titles System-Titel - + Add New Application Directory - Füge ein neues Anwendungsverzeichniss hinzu + Füge ein neues Anwendungsverzeichnis hinzu - + Favorites Favoriten @@ -7061,7 +7223,7 @@ Vielleicht hat dieser Nutzer bereits den Raum verlassen. %1 is running %2 - %1 läuft %2 + %1 führt %2 aus @@ -7077,12 +7239,12 @@ Vielleicht hat dieser Nutzer bereits den Raum verlassen. Text length is not correct (should be %1 characters) - Textlänge ist nicht korrekt (Sollte %1 Buchstabe(n) sein) + Textlänge ist nicht korrekt (Sollte %1 Buchstaben sein) Text is too long (should be no more than %1 characters) - Text ist zu lange (Sollte nicht mehr als %1 Buchstaben sein) + Text ist zu lang (Sollte nicht mehr als %1 Buchstaben sein) @@ -7234,7 +7396,7 @@ Vielleicht hat dieser Nutzer bereits den Raum verlassen. Vector Stride - Vektor Stride + Vektor-Schrittweite @@ -7261,8 +7423,8 @@ Vielleicht hat dieser Nutzer bereits den Raum verlassen. Would you like to migrate your data for use in Azahar? (This may take a while; The old data will not be deleted) - Möchten Sie Ihre Daten zur Verwendung in Azahar migrieren? - (Dies kann eine Weile dauern; die alten Daten werden nicht gelöscht) + Möchtest du deine Daten zur Verwendung in Azahar migrieren? +(Dies kann eine Weile dauern; die alten Daten werden nicht gelöscht) @@ -7308,13 +7470,13 @@ Vielleicht hat dieser Nutzer bereits den Raum verlassen. Azahar hat Benutzerdaten für Lime3DS erkannt. - + You can manually re-trigger this prompt by deleting the new user data directory: %1 - Sie können diese Eingabeaufforderung durch das löschen des neuen Benutzerdatenverzeichnis erneut auslösen: + Du kannst diese Anzeige manuell durch das Löschen des neuen Benutzerdatenverzeichnisses erneut auslösen: %1 @@ -7323,9 +7485,9 @@ Vielleicht hat dieser Nutzer bereits den Raum verlassen. If you wish to clean up the files which were left in the old data location, you can do so by deleting the following directory: %1 - Daten wurden erfolgreich migriert. + Daten wurden erfolgreich migriert. -Wenn Sie die Dateien bereinigen möchten, die am alten Datenspeicherort verblieben sind, können Sie dies tun, indem Sie das folgende Verzeichnis löschen: +Wenn du die Dateien bereinigen möchtest, die am alten Datenspeicherort verblieben sind, kannst du das folgende Verzeichnis löschen: %1 @@ -7363,7 +7525,7 @@ Wenn Sie die Dateien bereinigen möchten, die am alten Datenspeicherort verblieb waiting for all objects - wartet auf alle Objekte + Warte auf alle Objekte @@ -7464,7 +7626,7 @@ Wenn Sie die Dateien bereinigen möchten, die am alten Datenspeicherort verblieb object id = %1 - objekt id = %1 + Objekt-ID = %1 diff --git a/dist/languages/el.ts b/dist/languages/el.ts index 0a1ba8b42..c12ef9d04 100644 --- a/dist/languages/el.ts +++ b/dist/languages/el.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -292,8 +292,8 @@ This would ban both their forum username and their IP address. - Emulation: - Εξομοίωση: + Emulation + Εξομοίωση @@ -322,8 +322,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Αυτό το μετεπεξεργαστικό εφέ προσαρμόζει την ταχύτητα του ήχου για να ταιριάξει με την ταχύτητα εξομοίωσης και βοηθά στην αποτροπή το «κόμπιασμα» του ήχου. Αυτό ωστόσο αυξάνει την καθυστέρηση του ήχου. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ This would ban both their forum username and their IP address. + Camera Κάμερα @@ -408,8 +409,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - Κάμερα για διαμόρφωση: + Camera to Configure + @@ -429,8 +430,8 @@ This would ban both their forum username and their IP address. - Camera mode: - Τύπος κάμερας: + Camera mode + @@ -450,8 +451,8 @@ This would ban both their forum username and their IP address. - Camera position: - Θέση κάμερας: + Camera position + @@ -471,13 +472,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Επιλέξτε την προέλευση της εικόνας της εξομοιωμένης κάμερας. Μπορεί να είναι μια εικόνα ή μια πραγματική κάμερα. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Πηγή εικόνας κάμερας: + Camera Image Source + @@ -496,8 +497,8 @@ This would ban both their forum username and their IP address. - File: - Αρχείο: + File + @@ -510,11 +511,6 @@ This would ban both their forum username and their IP address. Select the system camera to use Επιλέξτε την κάμερα συστήματος προς χρήση - - - Camera: - Κάμερα: - <Default> @@ -528,8 +524,8 @@ This would ban both their forum username and their IP address. - Flip: - Αναστροφή: + Flip + @@ -1082,7 +1078,7 @@ Would you like to ignore the error and continue? - Reverse Side by Side + Side by Side Full Width @@ -1141,48 +1137,53 @@ Would you like to ignore the error and continue? - + + Swap Eyes + + + + Utility - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures + + Preload custom textures - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading @@ -1195,91 +1196,111 @@ Would you like to ignore the error and continue? - General - Γενικά + Updates + - Confirm exit while emulation is running - Επιβεβαίωση εξόδου όταν γίνεται εξομοίωση - - - - Pause emulation when in background - Παύση εξομοίωσης όταν η εφαρμογή είναι στο παρασκήνιο - - - - Mute audio when in background - - - - - Hide mouse on inactivity - Απόκρυψη ποντικιού κατά την αδράνεια - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Γενικά + + + + Confirm exit while emulation is running + Επιβεβαίωση εξόδου όταν γίνεται εξομοίωση + + + + Pause emulation when in background + Παύση εξομοίωσης όταν η εφαρμογή είναι στο παρασκήνιο + + + + Mute audio when in background + + + + + Hide mouse on inactivity + Απόκρυψη ποντικιού κατά την αδράνεια + + + + Enable Gamemode + + + + Emulation Εξομοίωση - + Use global emulation speed - - Set emulation speed: + + Set emulation speed - - Emulation Speed: - Ταχύτητα εξομοίωσης: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots Στιγμιότυπα - + Use global screenshot path - + Set screenshot path: - + Save Screenshots To - + ... ... - + Reset All Settings Επαναφορά όλων των ρυθμίσεων @@ -1287,8 +1308,8 @@ Would you like to ignore the error and continue? - - + + unthrottled χωρίς επιτάχυνση @@ -1298,12 +1319,12 @@ Would you like to ignore the error and continue? - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1357,12 +1378,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1382,8 +1403,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - Ενεργοποίηση shader υλικού + Enable hardware shader + @@ -1392,8 +1413,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - Ακριβής πολλαπλασιασμός + Accurate multiplication + @@ -1402,8 +1423,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - Ενεργοποίηση Shader JIT + Enable shader JIT + @@ -1412,17 +1433,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1462,13 +1483,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache - Χρήση προσωρινής μνήμης shader δίσκου + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - Το VSync αποτρέπει τα γραφικά από το να χαλάνε, αλλά κάποιες κάρτες γραφικών μπορεί να δίνουν χειρότερη απόδοση αν η ρύθμιση είναι ανοιχτή. Κρατήστε το VSync ανοιχτό μόνο εάν δεν δείτε κάποια αλλαγή στην απόδοση. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1476,22 +1497,32 @@ Would you like to ignore the error and continue? Ενεργοποίηση VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1976,12 +2007,12 @@ Would you like to ignore the error and continue? - Swap Screens - Εναλλαγή οθονών + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2098,7 +2129,7 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2270,7 +2301,7 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2446,8 +2477,8 @@ Would you like to ignore the error and continue? - Use Virtual SD - Χρήση εικονικής SD + Use virtual SD card + @@ -2456,7 +2487,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location @@ -2487,6 +2518,16 @@ Would you like to ignore the error and continue? SDMC Directory Κατάλογος SDMC + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2533,8 +2574,8 @@ online features (if installed) - Region: - + Region + Περιοχή @@ -2542,326 +2583,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Όνομα χρήστη - + Birthday Γενέθλια - + January Ιανουάριος - + February Φεβρουάριος - + March Μάρτιος - + April Απρίλιος - + May Μάιος - + June Ιούνιος - + July Ιούλιος - + August Αύγουστος - + September Σεπτέμβριος - + October Οκτώβριος - + November Νοέμβριος - + December Δεκέμβριος - + Language Γλώσσα - + Note: this can be overridden when region setting is auto-select Σημείωση: αυτό μπορεί να παρακαμφθεί όταν επιλέγεται αυτόματα η περιοχή - + Japanese (日本語) Ιαπωνικά (日本語) - + English Αγγλικά (English) - + French (français) Γαλλικά (français) - + German (Deutsch) Γερμανικά (Deutsch) - + Italian (italiano) Ιταλικά (italiano) - + Spanish (español) Ισπανικά (español) - + Simplified Chinese (简体中文) Απλοποιημένα Κινεζικά (简体中文) - + Korean (한국어) Κορεατικά (한국어) - + Dutch (Nederlands) Ολλανδικά (Nederlands) - + Portuguese (português) Πορτογαλικά (português) - + Russian (Русский) Ρωσικά (Русский) - + Traditional Chinese (正體中文) Παραδοσιακά Κινεζικά (正體中文) - + Sound output mode Λειτουργία εξόδου ήχου - + Mono Μονοφωνικό - + Stereo Στερεοφωνικό - + Surround Πολυκάναλο - + Country Χώρα - + Clock Ρολόι - + System Clock Ρολόι συστήματος - + Fixed Time Καθορισμένη ώρα - + Startup time Χρόνος εκκίνησης - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: ID κονσόλας: - - + + Regenerate Επαναδημιουργία - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3571,76 +3623,76 @@ online features (if installed) - - + + Console ID: 0x%1 ID κονσόλας: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Προειδοποίηση - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3756,13 +3808,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Γλώσσα περιβάλλοντος: + Interface Language + - Theme: - Θέμα: + Theme + @@ -3771,8 +3823,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - Μέγεθος εικονιδίων: + Icon Size + @@ -3792,8 +3844,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - Κείμενο σειράς 1: + Row 1 Text + @@ -3827,18 +3879,18 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - Κείμενο σειράς 2: + Row 2 Text + - Hide Titles without Icon - Απόκρυψη τίτλων χωρίς εικονίδιο + Hide titles without icon + - Single Line Mode - Λειτουργία ενιαίας γραμμής + Single line mode + @@ -3847,7 +3899,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3930,12 +3982,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Σύνδεση - + Connect Σύνδεση @@ -4054,556 +4106,596 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Η ταχύτητα της προσομοίωσης. Ταχύτητες μεγαλύτερες ή μικρότερες από 100% δείχνουν ότι η προσομοίωση λειτουργεί γρηγορότερα ή πιο αργά από ένα 3DS αντίστοιχα. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Ο χρόνος που χρειάζεται για την εξομοίωση ενός καρέ 3DS, χωρίς να υπολογίζεται ο περιορισμός καρέ ή το v-sync. Για εξομοίωση σε πλήρη ταχύτητα, αυτό θα πρέπει να είναι το πολύ 16.67 ms. - + MicroProfile (unavailable) - + Clear Recent Files Απαλοιφή πρόσφατων αρχείων - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. Προέκυψε άγνωστο σφάλμα. Παρακαλώ δείτε το αρχείο καταγραφής για περισσότερες λεπτομέρειες. - + CIA must be installed before usage Το CIA πρέπει να εγκατασταθεί πριν από τη χρήση - + Before using this CIA, you must install it. Do you want to install it now? Πριν από τη χρήση αυτού του CIA, πρέπει να το εγκαταστήσετε. Θέλετε να το εγκαταστήσετε τώρα; - + Quick Load - + Quick Save Γρήγορη Αποθήκευση - - + + Slot %1 Θέση %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder Σφάλμα ανοίγματος %1 φακέλου - - + + Folder does not exist! Ο φάκελος δεν υπάρχει! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon Δημηουργία Εικονιδίου - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... Αποτύπωση... - - + + Cancel Ακύρωση - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. Δεν ήταν δυνατή η αποτύπωση του βασικού RomFS. Ανατρέξτε στο αρχείο καταγραφής για λεπτομέρειες. - + Error Opening %1 Σφάλμα ανοίγματος του «%1» - + Select Directory Επιλογή καταλόγου - + Properties Ιδιότητες - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Εκτελέσιμο 3DS (%1);;Όλα τα αρχεία (*.*) - + Load File Φόρτωση αρχείου - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Φόρτωση αρχείων - - 3DS Installation File (*.CIA*) - Αρχείο εγκατάστασης 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Όλα τα αρχεία (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. Το «%1» εγκαταστάθηκε επιτυχώς. - + Unable to open File Δεν είναι δυνατό το άνοιγμα του αρχείου - + Could not open %1 Δεν ήταν δυνατό το άνοιγμα του «%1» - + Installation aborted Η εγκατάσταση ακυρώθηκε - + The installation of %1 was aborted. Please see the log for more details Η εγκατάσταση του «%1» ακυρώθηκε. Παρακαλώ δείτε το αρχείο καταγραφής για περισσότερες λεπτομέρειες - + Invalid File Μη έγκυρο αρχείο - + %1 is not a valid CIA Το «%1» δεν είναι έγκυρο CIA - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. - + File not found Το αρχείο δεν βρέθηκε - + File "%1" not found Το αρχείο «%1» δεν βρέθηκε - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Αρχείο Amiibo (%1);; Όλα τα αρχεία (*.*) - + Load Amiibo Φόρτωση Amiibo - + Unable to open amiibo file "%1" for reading. - + Record Movie Εγγραφή βίντεο - + Movie recording cancelled. Η εγγραφή βίντεο ακυρώθηκε. - - + + Movie Saved Το βίντεο αποθηκεύτηκε - - + + The movie is successfully saved. Το βίντεο αποθηκεύτηκε επιτυχώς. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4612,214 +4704,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - Εγγραφή %1 - - - - Playing %1 / %2 - Αναπαραγωγή %1 / %2 - - - - Movie Finished - Το βίντεο τελείωσε - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + Εγγραφή %1 + + + + Playing %1 / %2 + Αναπαραγωγή %1 / %2 + + + + Movie Finished + Το βίντεο τελείωσε + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Ταχύτητα: %1% - + Speed: %1% / %2% Ταχύτητα: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Καρέ: %1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Ένα αρχείο συστήματος - + System Archive Not Found Δεν βρέθηκε αρχείο συστήματος - + System Archive Missing Απουσία αρχείου συστήματος - + Save/load Error Σφάλμα αποθήκευσης/φόρτωσης - + Fatal Error Κρίσιμο σφάλμα - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered Προέκυψε κρίσιμο σφάλμα - + Continue Συνέχεια - + Quit Application - + OK OK - + Would you like to exit now? Θέλετε να κλείσετε το πρόγραμμα τώρα; - + The application is still running. Would you like to stop emulation? - + Playback Completed Η αναπαραγωγή ολοκληρώθηκε - + Movie playback completed. Η αναπαραγωγή βίντεο ολοκληρώθηκε. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4882,42 +5024,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4925,239 +5067,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Συμβατότητα - - + + Region Περιοχή - - + + File type Τύπος αρχείου - - + + Size Μέγεθος - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open Άνοιγμα - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS Αποτύπωση RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties Ιδιότητες - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders Σάρωση υποφακέλων - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location Άνοιγμα τοποθεσίας καταλόγου - + Clear Απαλοιφή - + Name Όνομα @@ -5165,77 +5317,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Τέλειο - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Πολύ καλή - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Εντάξει - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Κακή - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Εκκίνηση/Μενού - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Δεν εκκινείται - + The app crashes when attempting to startup. - + Not Tested Δεν έχει δοκιμαστεί - + The app has not yet been tested. @@ -5243,7 +5395,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5251,27 +5403,27 @@ Screen. GameListSearchField - + of από - + result αποτέλεσμα - + results αποτελέσματα - + Filter: Φίλτρο: - + Enter pattern to filter Εισαγάγετε μοτίβο για φιλτράρισμα @@ -5279,47 +5431,47 @@ Screen. GameRegion - + Japan Ιαπωνία - + North America Βόρεια Αμερική - + Europe Ευρώπη - + Australia Αυστραλία - + China Κίνα - + Korea Κορέα - + Taiwan Ταϊβάν - + Invalid region Μη έγκυρη περιοχή - + Region free Χωρίς περιορισμό περιοχής @@ -5599,87 +5751,87 @@ Screen. Ευρετήριο κύκλου: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Καταχωρητές διευθύνσεων: %1, %2 - + Compare Result: %1, %2 Σύγκριση αποτελέσματος: %1, %2 - + Static Condition: %1 Στατική συνθήκη: %1 - + Dynamic Conditions: %1, %2 Δυναμικές συνθήκες: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Παράμετροι βρόχου: %1 (επαναλήψεις), %2 (αρχικοποίηση), %3 (αύξηση), %4 - + Instruction offset: 0x%1 Μετατόπιση οδηγιών: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (τελευταία οδηγία) @@ -5903,24 +6055,24 @@ Debug Message: Προετοιμασία shader %1 / %2 - - Loading Shaders %1 / %2 - Φόρτωση shader %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Εκκίνηση... - + Now Loading %1 Γίνεται φόρτωση %1 - + Estimated Time %1 Εκτιμώμενος χρόνος: %1 @@ -5979,32 +6131,32 @@ Debug Message: Κωδικός πρόσβασης: - + Room Name Όνομα δωματίου - + Preferred Application - + Host Διαχειριστής - + Players Παίκτες - + Refreshing Ανανέωση - + Refresh List Ανανέωση λίστας @@ -6087,342 +6239,352 @@ Debug Message: Βίντεο - + Help - + Load File... Φόρτωση αρχείου... - + Install CIA... Εγκατάσταση CIA... - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit - + Pause - + Stop - + Save Αποθήκευση - + Load Φόρτωση - + FAQ - + About Azahar Σχετικά με το Azahar - + Single Window Mode Λειτουργία μονού παραθύρου - + Save to Oldest Slot Αποθήκευση στην παλαιότερη θέση - + Quick Save Γρήγορη Αποθήκευση - + Load from Newest Slot Φόρτωση από την νεότερη θέση - + Quick Load - + Configure... Διαμόρφωση... - + Display Dock Widget Headers Προβολή κεφαλίδων widget - + Show Filter Bar Εμφάνιση γραμμής φίλτρων - + Show Status Bar Εμφάνιση γραμμής κατάστασης - + Create Pica Surface Viewer Δημιουργία Pica Surface Viewer - + Record... Εγγραφή... - + Play... Αναπαραγωγή... - + Close Κλείσιμο - + Save without Closing Αποθήκευση χωρίς κλείσιμο - + Read-Only Mode Λειτουργία «Μόνο για ανάγνωση» - + Advance Frame Επίσπευση καρέ - + Capture Screenshot Λήψη στιγμιότυπου - + Dump Video Αποτύπωση βίντεο + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Δημιουργία δωματίου - + Leave Room Αποχώρηση από δωμάτιο - + Direct Connect to Room Άμεση σύνδεση σε δωμάτιο - + Show Current Room Εμφάνιση τρέχοντος δωματίου - + Fullscreen Πλήρης οθόνη - + Open Log Folder - + Opens the Azahar Log folder - + Default Προεπιλογή - + Single Screen Μονή οθόνη - + Large Screen Μεγάλη οθόνη - + Side by Side Παραπλεύρως - + Separate Windows - + Hybrid Screen - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Εναλλαγή οθονών - + Rotate Upright Κατακόρυφη περιστροφή - + Report Compatibility Αναφορά συμβατότητας - + Restart Επανεκκίνηση - + Load... Φόρτωση... - + Remove Αφαίρεση - + Open Azahar Folder - + Configure Current Application... @@ -6993,32 +7155,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Μη έγκυρη περιοχή - + Installed Titles Εγκατεστημένοι τίτλοι - + System Titles Τίτλοι συστήματος - + Add New Application Directory - + Favorites diff --git a/dist/languages/es_ES.ts b/dist/languages/es_ES.ts index dfd75dc24..de87fa9c6 100644 --- a/dist/languages/es_ES.ts +++ b/dist/languages/es_ES.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,8 +298,8 @@ This would ban both their forum username and their IP address. - Emulation: - Emulación: + Emulation + Emulación @@ -328,8 +328,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Este efecto de post-procesado ajusta la velocidad del audio para igualarla a la del emulador y ayuda a prevenir parones de audio, pero aumenta la latencia de éste. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + <html><head/><body><p>Este efecto de post-procesado ajusta la velocidad del audio para igualarla a la del emulador y ayuda a prevenir parones de audio, pero aumenta la latencia de éste.</p></body></html> @@ -338,8 +338,8 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Ajusta la velocidad de reproducción de audio para tener en cuenta las caidas de fotogramas. El audio se reproducirá a velocidad completa pese a que los fotogramas de la aplicación sean bajos. Puede causar problemas de desincronización. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + <html><head/><body><p>Ajusta la velocidad de reproducción de audio para tener en cuenta las caidas de fotogramas. El audio se reproducirá a velocidad completa pese a que los fotogramas de la aplicación sean bajos. Puede causar problemas de desincronización.</p></body></html> @@ -403,6 +403,7 @@ This would ban both their forum username and their IP address. + Camera Cámara @@ -414,8 +415,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - Configurar la cámara: + Camera to Configure + Configurar la cámara @@ -435,8 +436,8 @@ This would ban both their forum username and their IP address. - Camera mode: - Modo de cámara: + Camera mode + Modo de cámara @@ -456,8 +457,8 @@ This would ban both their forum username and their IP address. - Camera position: - Posición de cámara: + Camera position + Posición de cámara @@ -477,13 +478,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Selecciona el lugar de donde proviene la imagen de la cámara emulada. Puede ser una imagen o una cámara real. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + <html><head/><body><p>Selecciona el lugar de donde proviene la imagen de la cámara emulada. Puede ser una imagen o una cámara real.</p></body></html> - Camera Image Source: - Fuente de la Imagen de la Cámara: + Camera Image Source + Fuente de la Imagen de la Cámara @@ -502,8 +503,8 @@ This would ban both their forum username and their IP address. - File: - Archivo: + File + Archivo @@ -516,11 +517,6 @@ This would ban both their forum username and their IP address. Select the system camera to use Seleccione la cámara del sistema que será usada - - - Camera: - Cámara: - <Default> @@ -534,8 +530,8 @@ This would ban both their forum username and their IP address. - Flip: - Rotación: + Flip + Rotación @@ -1088,8 +1084,8 @@ Would you like to ignore the error and continue? - Reverse Side by Side - De lado a lado inverso + Side by Side Full Width + De lado a lado ancho completo @@ -1147,48 +1143,53 @@ Would you like to ignore the error and continue? <html><head/><body><p>Desactivar Dibujado de Ojo Derecho</p><p>Desactiva el dibujado de la imagen del ojo derecho cuando no se utiliza el modo estereoscópico. Mejora significativamente el rendimiento en algunos juegos, pero puede causar parpadeo en otros.</p></body></html> - + + Swap Eyes + Intercambiar Ojos + + + Utility Utilidad - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Cambia las texturas por archivos PNG.</p><p>Las texturas son cargadas desde load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures Usar texturas personalizadas - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Vuelca las texturas a archivos PNG.</p><p>Las texturas son volcadas a dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures Volcar texturas - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>Carga todas las texturas personalizadas en memoria al iniciar, en vez de cargarlas cuando la aplicación las necesite.</p></body></html> - - Preload Custom Textures + + Preload custom textures Precargar texturas personalizadas - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Carga las texturas personalizadas de manera asíncrona con los hilos de fondo para reducir los parones de carga</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading Carga de Texturas Personalizadas Asíncrona @@ -1201,91 +1202,111 @@ Would you like to ignore the error and continue? - General - General + Updates + Actualizaciones - Confirm exit while emulation is running - Confirmar salida durante la emulación - - - - Pause emulation when in background - Pausar emulación al estar en segundo plano - - - - Mute audio when in background - Silenciar audio al estar en segundo plano - - - - Hide mouse on inactivity - Ocultar ratón mientras esté inactivo - - - - Enable Gamemode - Activar Gamemode - - - Check for updates Buscar actualizaciones - + + Update Channel + Actualización Canal + + + + Stable + Estable + + + + Prerelease + Prelanzamiento + + + + General + General + + + + Confirm exit while emulation is running + Confirmar salida durante la emulación + + + + Pause emulation when in background + Pausar emulación al estar en segundo plano + + + + Mute audio when in background + Silenciar audio al estar en segundo plano + + + + Hide mouse on inactivity + Ocultar ratón mientras esté inactivo + + + + Enable Gamemode + Activar Gamemode + + + Emulation Emulación - + Use global emulation speed Usar la velocidad de emulación global - - Set emulation speed: - Establecer la velocidad de emulación: + + Set emulation speed + Establecer la velocidad de emulación - - Emulation Speed: - Velocidad de Emulación: + + Emulation Speed + Velocidad de Emulación - + Turbo Speed Limit: Límite de Velocidad Turbo: - + Screenshots Capturas de pantalla - + Use global screenshot path Usar ruta de captura de pantalla global - + Set screenshot path: Establecer ruta de captura de pantalla: - + Save Screenshots To Guardar capturas a - + ... ... - + Reset All Settings Reiniciar Toda la Configuración @@ -1293,8 +1314,8 @@ Would you like to ignore the error and continue? - - + + unthrottled Ilimitada @@ -1304,12 +1325,12 @@ Would you like to ignore the error and continue? Seleccione el directorio de capturas de pantalla - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? ¿Desea de verdad<b>reiniciar tu configuración</b> y cerrar Azahar? @@ -1363,13 +1384,13 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation + SPIR-V shader generation Generación de Sombreados SPIR-V - Disable GLSL -> SPIR-V Optimizer - Desactivar optimizador GLSL -> SPIR-V + Disable GLSL -> SPIR-V optimizer + Desactivar GLSL -> SPIR-V optimizador @@ -1388,7 +1409,7 @@ Would you like to ignore the error and continue? - Enable Hardware Shader + Enable hardware shader Activar Sombreador de Hardware @@ -1398,7 +1419,7 @@ Would you like to ignore the error and continue? - Accurate Multiplication + Accurate multiplication Multiplicación Precisa @@ -1408,7 +1429,7 @@ Would you like to ignore the error and continue? - Enable Shader JIT + Enable shader JIT Activar Sombreado JIT @@ -1418,17 +1439,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation Activar Compilación de Sombreados Asíncrona - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Presentar en hilos diferentes. Mejora el rendimiento cuando se usa Vulkan en muchos juegos.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + <html><head/><body><p>Presentar en hilos diferentes. Mejora el rendimiento cuando se usa Vulkan en muchos juegos. Agrega ~1 fotograma de retraso de lag.</p></body></html> - Enable Async Presentation + Enable async presentation Activar Presentación Asíncrona @@ -1468,13 +1489,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache + Use disk shader cache Usar Caché Almacenada de Sombreadores - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - La Sincronización Vertical impide el tearing de la imagen, pero algunas tarjetas gráficas tienen peor rendimiento cuando éste está activado. Manténlo activado si no notas ninguna diferencia en el rendimiento. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + <html><head/><body><p>La Sincronización Vertical impide el tearing de la imagen, pero algunas tarjetas gráficas tienen peor rendimiento cuando éste está activado. Manténlo activado si no notas ninguna diferencia en el rendimiento.</p></body></html> @@ -1482,22 +1503,32 @@ Would you like to ignore the error and continue? Activar Sincronización Vertical - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global Usar global - + Use per-application Usar configuración de la aplicación - - Delay application render thread: + + Delay Application Render Thread Demorar el hilo de ejecución de renderizado: - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>Demora el hilo emulado de renderizado del juego una determinada cantidad de milisegundos cada vez que envíe comandos de renderizado a la GPU.</p><p>Ajusta esta característica en los (pocos) juegos con FPS dinámicos para arreglar problemas de rendimiento.</p></body></html> @@ -1982,12 +2013,12 @@ Would you like to ignore the error and continue? - Swap Screens + Swap screens Intercambiar pantallas - Rotate Screens Upright + Rotate screens upright Rotar pantallas en vertical @@ -2104,8 +2135,8 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Porcentaje de Opacidad de la Pantalla Inferior (sólo OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + <html><head/><body><p>Porcentaje de Opacidad de la Pantalla Inferior %</p></body></html> @@ -2276,8 +2307,8 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Más Información</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Más Información</span></a> @@ -2452,8 +2483,8 @@ Would you like to ignore the error and continue? - Use Virtual SD - Usar SD Virtual + Use virtual SD card + Usar tarjeta SD Virtual @@ -2462,7 +2493,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location Usar almacenamiento personalizado @@ -2493,6 +2524,16 @@ Would you like to ignore the error and continue? SDMC Directory Directorio SDMC + + + Compress installed CIA content + Comprimir el contenido de CIAs instalados + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + <html><head/><body><p>Comprime el contenido de archivos CIA cuando son instalados a la SD emulada. Solo afecta contenido CIA instalado con esta opción activada.</p></body></html> + Select NAND Directory @@ -2540,8 +2581,8 @@ las funciones en línea (si están instalados) - Region: - Región: + Region + Región @@ -2549,326 +2590,337 @@ las funciones en línea (si están instalados) Auto-elegir - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Nombre - + Birthday Cumpleaños - + January Enero - + February Febrero - + March Marzo - + April Abril - + May Mayo - + June Junio - + July Julio - + August Agosto - + September Septiembre - + October Octubre - + November Noviembre - + December Diciembre - + Language Idioma - + Note: this can be overridden when region setting is auto-select Nota: puede ser sobreescrito cuando la región es auto-seleccionada - + Japanese (日本語) Japonés (日本語) - + English Inglés (English) - + French (français) Francés (français) - + German (Deutsch) Alemán (Deutsch) - + Italian (italiano) Italiano (italiano) - + Spanish (español) Español - + Simplified Chinese (简体中文) Chino Simplificado (简体中文) - + Korean (한국어) Coreano (한국어) - + Dutch (Nederlands) Neerlandés (Nederlands) - + Portuguese (português) Portugués (português) - + Russian (Русский) Ruso (Русский) - + Traditional Chinese (正體中文) Chino Tradicional (正體中文) - + Sound output mode Modo de salida del audio - + Mono Mono - + Stereo Estéreo - + Surround Envolvente - + Country País - + Clock Reloj - + System Clock Reloj del Sistema - + Fixed Time Tiempo Fijado - + Startup time Tiempo del Inicio - + yyyy-MM-ddTHH:mm:ss aaaa-mm-ddTHH:mm:ss - + Offset time Tiempo de compensación - + days días - + HH:mm:ss HH:mm:ss - + Initial System Ticks Ticks de Sistema Iniciales - + Random Aleatorias - + Fixed Fijadas - + Initial System Ticks Override Sobreescribir Ticks de Sistema Iniciales - + Play Coins Monedas de Juego - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>Cantidad de pasos por hora determinadas por el podómetro. Van desde 0 a 65,535.</p></body></html> - + Pedometer Steps per Hour Pasos por hora del Podómetro - + Run System Setup when Home Menu is launched Ejecutar la Configuración de la consola cuando se ejecute el Menú Home - + Console ID: ID de Consola: - - + + Regenerate Regenerar - + MAC: Dirección MAC: - - 3GX Plugin Loader: - Cargador de complementos 3GX: + + 3GX Plugin Loader + Cargador de complementos 3GX - + Enable 3GX plugin loader Habilitar el cargador de complementos 3GX - + Allow applications to change plugin loader state Permitir que los juegos cambien el estado del cargador de plugins. - + Real Console Unique Data Datos únicos de la consola real - + Your real console is linked to Azahar. Tu consola real está enlazada a Azahar. - + Unlink Desenlazar - + OTP OTP - - - - + + + + Choose Elegir - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. La configuración del sistema solo está disponible cuando la aplicación no se está ejecutando. @@ -3578,76 +3630,76 @@ las funciones en línea (si están instalados) Archivo Sed (*.sed);;Todos los archivos (*.*) - - + + Console ID: 0x%1 ID de Consola: 0x%1 - - + + MAC: %1 Dirección MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? Esto reemplazará tu ID de consola de 3DS virtual por una nueva. Tu ID actual será irrecuperable. Esto puede tener efectos inesperados en determinadas aplicaciones. Si usas un archivo de configuración obsoleto, esto podría fallar. ¿Desea continuar? - - - + + + Warning Advertencia - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? Esto reemplazará tu dirección MAC actual por una nueva. No se recomienda hacerlo si obtuviste la dirección MAC de tu consola real con la herramienta de configuración. ¿Continuar? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? Esta acción desvinculará tu consola real de Azahar, con las siguientes consecuencias:<ul><li>OTP, SecureInfo y LocalFriendCodeSeed serán eliminados de Azahar.</li><li>Tu lista de amigos se restablecerá y se cerrará la sesión de tu cuenta NNID/PNID.</li><li>Los archivos del sistema y los títulos de la eshop obtenidos a través de Azahar se volverán inaccesibles hasta que la misma consola se vincule nuevamente mediante la herramienta de configuración (los datos guardados no se perderán).</li></ul><br>¿Continuar? - + Invalid country for configured region País incorrecto para la región configurada - + Invalid country for console unique data País incorrecto para los datos de consola únicos - + Status: Loaded Estado: Cargado - + Status: Loaded (Invalid Signature) Estado: Cargado (Firma Inválida) - + Status: Loaded (Region Changed) Estado: Cargado (Cambiado de Región) - + Status: Not Found Estado: No Encontrado - + Status: Invalid Estado: Inválido - + Status: IO Error Estado: Error E/S @@ -3763,13 +3815,13 @@ Mueve los puntos para cambiar la posición, o haz doble click en las celdas de l - Interface language: + Interface Language Idioma de la Interfaz - Theme: - Tema: + Theme + Tema @@ -3778,8 +3830,8 @@ Mueve los puntos para cambiar la posición, o haz doble click en las celdas de l - Icon Size: - Tamaño de Icono: + Icon Size + Tamaño de Icono @@ -3799,8 +3851,8 @@ Mueve los puntos para cambiar la posición, o haz doble click en las celdas de l - Row 1 Text: - Texto de Fila 1: + Row 1 Text + Texto de Fila 1 @@ -3834,17 +3886,17 @@ Mueve los puntos para cambiar la posición, o haz doble click en las celdas de l - Row 2 Text: - Texto de Fila 2: + Row 2 Text + Texto de Fila 2 - Hide Titles without Icon + Hide titles without icon Ocultar Títulos sin Icono - Single Line Mode + Single line mode Modo Una Línea @@ -3854,7 +3906,7 @@ Mueve los puntos para cambiar la posición, o haz doble click en las celdas de l - Show Advanced Frame Time Info + Show advanced frame time info Mostrar información de fotogramas avanzada @@ -3937,12 +3989,12 @@ Mueve los puntos para cambiar la posición, o haz doble click en las celdas de l DirectConnectWindow - + Connecting Conectando - + Connect Conectar @@ -4062,471 +4114,511 @@ Por favor, compruebe la instalación de FFmpeg usada para la compilación. GMainWindow - + No Suitable Vulkan Devices Detected Dispositivos compatibles con Vulkan no encontrados. - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. El inicio de Vulkan falló durante el inicio.<br/>Tu GPU, o no soporta Vulkan 1.1, o no tiene los últimos drivers gráficos. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. La velocidad de tráfico actual de Artic. Los valores altos indican una carga mayor de transferencia. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. La velocidad de emulación actual. Valores mayores o menores de 100% indican que la velocidad de emulación funciona más rápida o lentamente que en una 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. Los fotogramas por segundo que está mostrando el juego. Variarán de aplicación en aplicación y de escena a escena. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. El tiempo que lleva emular un fotograma de 3DS, sin tener en cuenta el limitador de fotogramas, ni la sincronización vertical. Para una emulación óptima, este valor no debe superar los 16.67 ms. - + MicroProfile (unavailable) MicroProfile (no disponible) - + Clear Recent Files Limpiar Archivos Recientes - + &Continue &Continuar - + &Pause &Pausar - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar está ejecutando una aplicación - - + + Invalid App Format Formato de aplicación inválido - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Tu formato de aplicación no es válido.<br/>Por favor, sigue las instrucciones para volver a volcar tus <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>cartucho de juego</a> y/o <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - + App Corrupted Aplicación corrupta - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Tu aplicación está corrupta. <br/>Por favor, sigue las instrucciones para volver a volcar tus <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de juego</a> y/o <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - + App Encrypted Aplicación encriptada - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Tu aplicación está encriptada. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Por favor visita nuestro blog para más información.</a> - + Unsupported App Aplicación no soportada - + GBA Virtual Console is not supported by Azahar. Consola Virtual de GBA no está soportada por Azahar. - - + + Artic Server Servidor Artic - + + Invalid system mode + Modo de sistema no válido + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! ¡Error al cargar la aplicación! - + An unknown error occurred. Please see the log for more details. Un error desconocido ha ocurrido. Por favor, mira el log para más detalles. - + CIA must be installed before usage El CIA debe estar instalado antes de usarse - + Before using this CIA, you must install it. Do you want to install it now? Antes de usar este CIA, debes instalarlo. ¿Quieres instalarlo ahora? - + Quick Load Carga Rápida - + Quick Save Guardado Rápido - - + + Slot %1 Ranura %1 - + %2 %3 %2 %3 - + Quick Save - %1 Guardado Rápido - %1 - + Quick Load - %1 Carga Rápida - %1 - + Slot %1 - %2 %3 Ranura %1 - %2 %3 - + Error Opening %1 Folder Error al abrir la carpeta %1 - - + + Folder does not exist! ¡La carpeta no existe! - + Remove Play Time Data Quitar Datos de Tiempo de Juego - + Reset play time? ¿Reiniciar tiempo de juego? - - - - + + + + Create Shortcut Crear atajo - + Do you want to launch the application in fullscreen? ¿Desea lanzar esta aplicación en pantalla completa? - + Successfully created a shortcut to %1 Atajo a %1 creado con éxito - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Ésto creará un atajo a la AppImage actual. Puede no funcionar bien si actualizas. ¿Continuar? - + Failed to create a shortcut to %1 Fallo al crear un atajo a %1 - + Create Icon Crear icono - + Cannot create icon file. Path "%1" does not exist and cannot be created. No se pudo crear un archivo de icono. La ruta "%1" no existe y no puede ser creada. - + Dumping... Volcando... - - + + Cancel Cancelar - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. No se pudo volcar el RomFS base. Compruebe el registro para más detalles. - + Error Opening %1 Error al abrir %1 - + Select Directory Seleccionar directorio - + Properties Propiedades - + The application properties could not be loaded. No se pudieron cargar las propiedades de la aplicación. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Ejecutable 3DS(%1);;Todos los archivos(*.*) - + Load File Cargar Archivo - - + + Set Up System Files Configurar Archivos de Sistema - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> <p>Azahar necesita archivos de una consola real para poder utilizar algunas de sus funciones.<br>Puedes obtener los archivos con la <a href=https://github.com/azahar-emu/ArticSetupTool>herramienta de configuración Artic</a><br>Notas:<ul><li><b>Esta operación instalará archivos únicos de la consola en Azahar, ¡no compartas las carpetas de usuario ni nand<br>después de realizar el proceso de configuración!</b></li><li>Tras la configuración, Azahar se enlazará a la consola que ha ejecutado la herramienta de configuración. Puedes desvincular la<br>consola más tarde desde la pestaña "Archivos de sistema" del menú de opciones del emulador.</li><li>No te conectes en línea con Azahar y la consola 3DS al mismo tiempo después de configurar los archivos del sistema,<br>ya que esto podría causar problemas.</li><li>Se necesita la configuración de Old 3DS para que funcione la configuración de New 3DS (configurar ambos modos es recomendado).</li><li>Ambos modos de configuración funcionarán independientemente del modelo de la consola que ejecute la herramienta de configuración.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: Introduce la dirección de la herramienta de configuración Artic - + <br>Choose setup mode: <br>Elige el modo de configuración: - + (ℹ️) Old 3DS setup (ℹ️) Configuración Old 3DS - - + + Setup is possible. La configuración es posible. - + (⚠) New 3DS setup (⚠) Configuración New 3DS - + Old 3DS setup is required first. La configuración Old 3DS es necesaria primero. - + (✅) Old 3DS setup (✅) Configuración Old 3DS - - + + Setup completed. Configuración completa. - + (ℹ️) New 3DS setup (ℹ️) Configuración New 3DS - + (✅) New 3DS setup (✅) Configuración New 3DS - + The system files for the selected mode are already set up. Reinstall the files anyway? Los archivos de sistema para el modo seleccionado ya están configurados. ¿Desea reinstalar los archivos de todas formas? - + Load Files Cargar archivos - - 3DS Installation File (*.CIA*) - Archivo de Instalación de 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + Archivo de Instalación de 3DS (*.cia *.zcia) - + + + All Files (*.*) Todos los archivos (*.*) - + Connect to Artic Base Conectar a Artic Base - + Enter Artic Base server address: Introduce la dirección del servidor Artic Base - + %1 has been installed successfully. %1 ha sido instalado con éxito. - + Unable to open File No se pudo abrir el Archivo - + Could not open %1 No se pudo abrir %1 - + Installation aborted Instalación interrumpida - + The installation of %1 was aborted. Please see the log for more details La instalación de %1 ha sido cancelada. Por favor, consulte los registros para más información. - + Invalid File Archivo no válido - + %1 is not a valid CIA %1 no es un archivo CIA válido - + CIA Encrypted CIA encriptado - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Tu archivo CIA está encriptado. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Por favor visita nuestro blog para más información.</a> - + Unable to find File No puede encontrar el archivo - + Could not find %1 No se pudo encontrar %1 - + + + + + Z3DS Compression + Compresión Z3DS + + + + Failed to compress some files, check log for details. + No se pudieron comprimir algunos archivos, mira el registro para más detalles. + + + + Failed to decompress some files, check log for details. + No se pudieron descomprimir algunos archivos, mira el registro para más detalles. + + + + All files have been compressed successfully. + Todos los archivos ya comprimido con éxtio. + + + + All files have been decompressed successfully. + Todos los archivos ya descompresión con éxtio. + + + Uninstalling '%1'... Desinstalando '%1'... - + Failed to uninstall '%1'. Falló la desinstalación de '%1'. - + Successfully uninstalled '%1'. '%1' desinstalado con éxito. - + File not found Archivo no encontrado - + File "%1" not found Archivo "%1" no encontrado - + Savestates Estados - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! @@ -4535,86 +4627,86 @@ Use at your own risk! ¡Úsalos bajo tu propio riesgo! - - - + + + Error opening amiibo data file Error al abrir los archivos de datos del Amiibo - + A tag is already in use. Ya está en uso una etiqueta. - + Application is not looking for amiibos. La aplicación no está buscando amiibos. - + Amiibo File (%1);; All Files (*.*) Archivo de Amiibo(%1);; Todos los archivos (*.*) - + Load Amiibo Cargar Amiibo - + Unable to open amiibo file "%1" for reading. No se pudo abrir el archivo del amiibo "%1" para su lectura. - + Record Movie Grabar Película - + Movie recording cancelled. Grabación de película cancelada. - - + + Movie Saved Película Guardada - - + + The movie is successfully saved. Película guardada con éxito. - + Application will unpause La aplicación se despausará - + The application will be unpaused, and the next frame will be captured. Is this okay? La aplicación se despausará, y el siguiente fotograma será capturado. ¿Estás de acuerdo? - + Invalid Screenshot Directory Directorio de capturas de pantalla no válido - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. No se puede crear el directorio de capturas de pantalla. La ruta de capturas de pantalla vuelve a su valor por defecto. - + Could not load video dumper No se pudo cargar el volcador de vídeo - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4627,215 +4719,265 @@ Para instalar FFmpeg en Azahar, pulsa Abrir y elige el directorio de FFmpeg. Para ver una guía sobre cómo instalar FFmpeg, pulsa Ayuda. - + + Load 3DS ROM Files + Cargar ROM de 3DS + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + Archivos ROM 3DS (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + 3DS Compressed ROM File (*.%1) + Archivo ROM 3DS comprimido (*.%1) + + + + Save 3DS Compressed ROM File + Guardar archivo 3DS comprimido + + + + Select Output 3DS Compressed ROM Folder + Seleccione la carpeta de salida comprimida del ROM 3DS + + + + Load 3DS Compressed ROM Files + Cargar archivo 3DS comprimido + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + Archivo ROM 3DS comprimido (*.zcia *zcci *z3dsx *zcxi) + + + + 3DS ROM File (*.%1) + Archivo ROM 3DS (*.%1) + + + + Save 3DS ROM File + Guardar archivo ROM 3DS + + + + Select Output 3DS ROM Folder + Seleccione la carpeta de salida del ROM 3DS + + + Select FFmpeg Directory Seleccionar Directorio FFmpeg - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. Al directorio de FFmpeg indicado le falta %1. Por favor, asegúrese de haber seleccionado el directorio correcto. - + FFmpeg has been sucessfully installed. FFmpeg ha sido instalado con éxito. - + Installation of FFmpeg failed. Check the log file for details. La instalación de FFmpeg ha fallado. Compruebe el archivo del registro para más detalles. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. No se pudo empezar a grabar vídeo.<br>Asegúrese de que el encodeador de vídeo está configurado correctamente.<br>Para más detalles, observe el registro. - + Recording %1 Grabando %1 - + Playing %1 / %2 Reproduciendo %1 / %2 - + Movie Finished Película terminada - + (Accessing SharedExtData) (Accediendo al SharedExtData) - + (Accessing SystemSaveData) (Accediendo al SystemSaveData) - + (Accessing BossExtData) (Accediendo al BossExtData) - + (Accessing ExtData) (Accediendo al ExtData) - + (Accessing SaveData) (Accediendo al SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 Tráfico Artic: %1 %2%3 - + Speed: %1% Velocidad: %1% - + Speed: %1% / %2% Velocidad: %1% / %2% - + App: %1 FPS App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Frame: %1 ms - + VOLUME: MUTE VOLUMEN: SILENCIO - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUMEN: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - Falta %1 . Por favor, <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>vuelca tus archivos de sistema</a>.<br/>Continuar la emulación puede resultar en cuelgues y errores. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + Falta %1. Por favor,<a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>vuelca tus archivos de sistema</a>.<br/>Continuar la emulación puede resultar en cuelgues y errores. - + A system archive Un archivo de sistema - + System Archive Not Found Archivo de Sistema no encontrado - + System Archive Missing Falta un Archivo de Sistema - + Save/load Error Error de guardado/carga - + Fatal Error Error Fatal - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Error fatal. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Mira el log</a> para más detalles.<br/>Continuar la emulación puede resultar en cuelgues y errores. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + Ha ocurrido un error fatal.<a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Mira el log</a>para más detalles.<br/>Continuar la emulación puede resultar en cuelgues y errores. - + Fatal Error encountered Error Fatal encontrado - + Continue Continuar - + Quit Application Cerrar aplicación - + OK Aceptar - + Would you like to exit now? ¿Quiere salir ahora? - + The application is still running. Would you like to stop emulation? La aplicación sigue en ejecución. ¿Quiere parar la emulación? - + Playback Completed Reproducción Completada - + Movie playback completed. Reproducción de película completada. - + Update Available Actualización disponible - + Update %1 for Azahar is available. Would you like to download it? La actualización %1 de Azahar está disponible. ¿Quieres descargarla? - + Primary Window Ventana Primaria - + Secondary Window Ventana Secundaria @@ -4898,42 +5040,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! ¡OpenGL no disponible! - + OpenGL shared contexts are not supported. Los contextos compartidos de OpenGL no están soportados. - + Error while initializing OpenGL! ¡Error al iniciar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Tu GPU, o no soporta OpenGL, o no tienes los últimos drivers de la tarjeta gráfica. - + Error while initializing OpenGL 4.3! ¡Error al iniciar OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Tu GPU, o no soporta OpenGL 4.3, o no tienes los últimos drivers de la tarjeta gráfica.<br><br>Renderizador GL:<br>%1 - + Error while initializing OpenGL ES 3.2! ¡Error al iniciar OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Tu GPU, o no soporta OpenGL ES 3.2, o no tienes los últimos drivers de la tarjeta gráfica.<br><br>Renderizador GL:<br>%1 @@ -4941,175 +5083,185 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - IMPORTANTE: Los archivos cifrados y .3ds ya no son compatibles. Puede que sea necesario descifrarlos o renombrarlos a .cci. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Más Información</a> - - - - Don't show again - No volver a mostrar - - - - + + Compatibility Compatibilidad - - + + Region Región - - + + File type Tipo de Archivo - - + + Size Tamaño - - + + Play time Tiempo de juego - + Favorite Favorito - + + Eject Cartridge + Expulsar Cartucho + + + + Insert Cartridge + Insertar Cartucho + + + Open Abrir - + Application Location Localización de aplicaciones - + Save Data Location Localización de datos de guardado - + Extra Data Location Localización de Datos Extra - + Update Data Location Localización de datos de actualización - + DLC Data Location Localización de datos de DLC - + Texture Dump Location Localización del volcado de texturas - + Custom Texture Location Localización de las texturas personalizadas - + Mods Location Localización de los mods - + Dump RomFS Volcar RomFS - + Disk Shader Cache Caché de sombreador de disco - + Open Shader Cache Location Abrir ubicación de caché de sombreador - + Delete OpenGL Shader Cache Eliminar caché de sombreado de OpenGL - + + Delete Vulkan Shader Cache + Eliminar caché de sombreado de Vulkan + + + Uninstall Desinstalar - + Everything Todo - + Application Aplicación - + Update Actualización - + DLC DLC - + Remove Play Time Data Quitar Datos de Tiempo de Juego - + Create Shortcut Crear atajo - + Add to Desktop Añadir al Escritorio - + Add to Applications Menu Añadir al Menú Aplicación - + + Stress Test: App Launch + Prueba de estrés: lanzamiento de la aplicación + + + Properties Propiedades - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. @@ -5118,64 +5270,64 @@ This will delete the application if installed, as well as any installed updates Ésto eliminará la aplicación si está instalada, así como también las actualizaciones y DLC instaladas. - - + + %1 (Update) %1 (Actualización) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? ¿Estás seguro de querer desinstalar '%1'? - + Are you sure you want to uninstall the update for '%1'? ¿Estás seguro de querer desinstalar la actualización de '%1'? - + Are you sure you want to uninstall all DLC for '%1'? ¿Estás seguro de querer desinstalar todo el DLC de '%1'? - + Scan Subfolders Escanear subdirectorios - + Remove Application Directory Quitar carpeta de aplicaciones - + Move Up Mover arriba - + Move Down Mover abajo - + Open Directory Location Abrir ubicación del directorio - + Clear Reiniciar - + Name Nombre @@ -5183,77 +5335,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Perfecto - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. La aplicación funciona sin errores gráficos o de audio. Todas las funciones probadas funcionan según lo previso sin necesidad de soluciones alternativas. - + Great Excelente - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. La aplicación funciona con pequeños errores gráficos o de audio y es jugable de principio a fin. Puede necesitar soluciones alternativas. - + Okay Bien - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. La aplicación funciona con grandes errores gráficos o de audio, pero es jugable de principio a fin con soluciones alternativas. - + Bad Mal - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. La aplicación funciona, pero con grandes errores gráficos o de audio. No es posible continuar tras ciertos puntos debido a errores, incluso con soluciones alternativas. - + Intro/Menu Intro/Menú - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. La aplicación es completamente inutilizable debido a grandes errores gráficos o de audio. No es posible continuar tras la pantalla de título. - + Won't Boot No inicia - + The app crashes when attempting to startup. La aplicación se cae cuando se intenta iniciar. - + Not Tested Sin probar - + The app has not yet been tested. La aplicación no ha sido probada. @@ -5261,7 +5413,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list Haz doble click para añadir una nueva carpeta a la lista de aplicaciones @@ -5269,27 +5421,27 @@ Screen. GameListSearchField - + of de - + result resultado - + results resultados - + Filter: Filtro: - + Enter pattern to filter Introduzca un patrón para filtrar @@ -5297,47 +5449,47 @@ Screen. GameRegion - + Japan Japón - + North America América del Norte - + Europe Europa - + Australia Australia - + China China - + Korea Korea - + Taiwan Taiwán - + Invalid region Región no válida - + Region free Region free @@ -5617,87 +5769,87 @@ Screen. Índice de Ciclo: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Registros de Dirección: %1, %2 - + Compare Result: %1, %2 Comparar Resultados: %1, %2 - + Static Condition: %1 Condición Estática: %1 - + Dynamic Conditions: %1, %2 Condiciones Dinámicas: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Parámetros de Bucle: %1 (repeticiones), %2 (inicializador), %3 (incremental), %4 - + Instruction offset: 0x%1 Instrucción offset: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (última instrucción) @@ -5922,24 +6074,24 @@ Mensaje de depuración: Preparando Sombreadores %1 / %2 - - Loading Shaders %1 / %2 - Cargando Sombreadores %1 / %2 + + Loading %3 %1 / %2 + Cargando %3 %1 / %2 - + Launching... Iniciando... - + Now Loading %1 Cargando %1 - + Estimated Time %1 Tiempo Estimado %1 @@ -5998,32 +6150,32 @@ Mensaje de depuración: Contraseña: - + Room Name Nombre de Sala - + Preferred Application Aplicación preferida - + Host Host - + Players Jugadores - + Refreshing Actualizando - + Refresh List Actualizar Lista @@ -6106,342 +6258,352 @@ Mensaje de depuración: Película - + Help Ayuda - + Load File... Cargar Archivo... - + Install CIA... Instalar CIA... - + Connect to Artic Base... Conectando a Artic Base... - + Set Up System Files... Configurar Archivos de Sistema... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit Salir - + Pause Pausa - + Stop Detener - + Save Guardar - + Load Cargar - + FAQ FAQ - + About Azahar Acerca de Azahar - + Single Window Mode Modo Ventana Única - + Save to Oldest Slot Guardar en la ranura más antigua - + Quick Save Guardado Rápido - + Load from Newest Slot Cargar desde la ranura más reciente - + Quick Load Carga Rápida - + Configure... Configurar... - + Display Dock Widget Headers Mostrar Títulos de Widgets del Dock - + Show Filter Bar Mostrar Barra de Filtro - + Show Status Bar Mostrar Barra de Estado - + Create Pica Surface Viewer Crear Observador de Superficie de Pica - + Record... Grabar... - + Play... Reproducir... - + Close Cerrar - + Save without Closing Guardar sin cerrar - + Read-Only Mode Modo sólo lectura - + Advance Frame Avanzar Fotograma - + Capture Screenshot Hacer Captura de Pantalla - + Dump Video Volcar Vídeo + Compress ROM File... + Comprimir archivo ROM... + + + + Decompress ROM File... + Descomprimir archivo ROM... + + + Browse Public Rooms Buscar salas públicas - + Create Room Crear Sala - + Leave Room Abandonar Sala - + Direct Connect to Room Conectar Directamente a Sala - + Show Current Room Mostrar Sala Actual - + Fullscreen Pantalla Completa - + Open Log Folder Abrir Carpeta de Registros - + Opens the Azahar Log folder Abrir carpeta de logs de Azahar - + Default Por defecto - + Single Screen Pantalla única - + Large Screen Pantalla amplia - + Side by Side Conjunta - + Separate Windows Ventanas separadas - + Hybrid Screen Pantalla Híbrida - + Custom Layout Estilo personalizado - + Top Right Arriba a la derecha - + Middle Right Derecha en el medio - + Bottom Right Abajo a la derecha - + Top Left Abajo a la izquierda - + Middle Left Izquierda en el medio - + Bottom Left Abajo a la izquierda - + Above Encima - + Below Debajo - + Swap Screens Intercambiar pantallas - + Rotate Upright Rotar en Vertical - + Report Compatibility Informar de compatibilidad - + Restart Reiniciar - + Load... Cargar... - + Remove Quitar - + Open Azahar Folder Abrir carpeta de Azahar - + Configure Current Application... Configurar aplicación actual... @@ -7015,32 +7177,32 @@ Puede que haya dejado la sala. %1 (0x%2) - + Unsupported encrypted application Aplicación encriptada no soportada - + Invalid region Región no válida - + Installed Titles Títulos Instalados - + System Titles Títulos de Sistema - + Add New Application Directory Agregar nueva carpeta de aplicaciones - + Favorites Favoritos diff --git a/dist/languages/fi.ts b/dist/languages/fi.ts index 00f4df91d..2fda25233 100644 --- a/dist/languages/fi.ts +++ b/dist/languages/fi.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -292,8 +292,8 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - Emulation: - Emulaatio: + Emulation + Emulaatio @@ -322,8 +322,8 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Tämä prosessointiefekti säätää äänen nopeuden samaan nopeuteen emulaation kanssa, joka auttaa ääniongelmissa. Tämä kuitenkin lisää äänen viivettä. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. + Camera Kamera @@ -408,8 +409,8 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - Camera to configure: - Kamera jota määritellään: + Camera to Configure + @@ -429,8 +430,8 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - Camera mode: - Kameratila: + Camera mode + @@ -450,8 +451,8 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - Camera position: - Kameran sijainti: + Camera position + @@ -471,13 +472,13 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Valitse, mistä emuloitu kamera tulee. Se voi olla kuva tai oikea kamera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Kameran kuvalähde: + Camera Image Source + @@ -496,8 +497,8 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - File: - Tiedosto: + File + @@ -510,11 +511,6 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen.Select the system camera to use Valitse laitteen kamera, jota käytetään - - - Camera: - Kamera: - <Default> @@ -528,8 +524,8 @@ Tämä antaa porttikiellon heidän käyttäjänimelleen ja IP-osoitteelleen. - Flip: - Kääntö: + Flip + @@ -1081,7 +1077,7 @@ Would you like to ignore the error and continue? - Reverse Side by Side + Side by Side Full Width @@ -1140,48 +1136,53 @@ Would you like to ignore the error and continue? - + + Swap Eyes + + + + Utility - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures + + Preload custom textures - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading @@ -1194,91 +1195,111 @@ Would you like to ignore the error and continue? - General - Yleinen + Updates + - Confirm exit while emulation is running - Hyväksy poistuminen emulaation käynnissäolossa - - - - Pause emulation when in background - Pysäytä emulointi kun taustalla - - - - Mute audio when in background - - - - - Hide mouse on inactivity - - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Yleinen + + + + Confirm exit while emulation is running + Hyväksy poistuminen emulaation käynnissäolossa + + + + Pause emulation when in background + Pysäytä emulointi kun taustalla + + + + Mute audio when in background + + + + + Hide mouse on inactivity + + + + + Enable Gamemode + + + + Emulation Emulaatio - + Use global emulation speed - - Set emulation speed: + + Set emulation speed - - Emulation Speed: + + Emulation Speed - + Turbo Speed Limit: - + Screenshots - + Use global screenshot path - + Set screenshot path: - + Save Screenshots To - + ... ... - + Reset All Settings Tyhjennä Kaikki Asetukset @@ -1286,8 +1307,8 @@ Would you like to ignore the error and continue? - - + + unthrottled @@ -1297,12 +1318,12 @@ Would you like to ignore the error and continue? - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1356,12 +1377,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1381,8 +1402,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - Aktivoi Laitteistovarjostin + Enable hardware shader + @@ -1391,8 +1412,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - Tarkka Kertominen + Accurate multiplication + @@ -1401,8 +1422,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - Aktivoi JIT-Varjostin + Enable shader JIT + @@ -1411,17 +1432,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1461,12 +1482,12 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache + Use disk shader cache - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> @@ -1475,22 +1496,32 @@ Would you like to ignore the error and continue? Aktivoi V-Sync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1975,12 +2006,12 @@ Would you like to ignore the error and continue? - Swap Screens - Vaihda näytöt + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2097,7 +2128,7 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2269,7 +2300,7 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2445,7 +2476,7 @@ Would you like to ignore the error and continue? - Use Virtual SD + Use virtual SD card @@ -2455,7 +2486,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location @@ -2486,6 +2517,16 @@ Would you like to ignore the error and continue? SDMC Directory + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2532,8 +2573,8 @@ online features (if installed) - Region: - + Region + Alue @@ -2541,326 +2582,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Käyttäjänimi - + Birthday Syntymäpäivä - + January Tammikuu - + February Helmikuu - + March Maaliskuu - + April Huhtikuu - + May Toukokuu - + June Kesäkuu - + July Heinäkuu - + August Elokuu - + September Syyskuu - + October Lokakuu - + November Marraskuu - + December Joulukuu - + Language Kieli - + Note: this can be overridden when region setting is auto-select Huom: tämä voidaan korvata jos alueasetukset ovat automaattiset - + Japanese (日本語) Japani (日本語) - + English Englanti - + French (français) Ranska (français) - + German (Deutsch) Saksa (Deutsch) - + Italian (italiano) Italia (italiano) - + Spanish (español) Espanja (español) - + Simplified Chinese (简体中文) Yksinkertaistettu Kiina (简体中文) - + Korean (한국어) Korea (한국어) - + Dutch (Nederlands) Hollanti (Nederlands) - + Portuguese (português) Portugali (português) - + Russian (Русский) Venäjä (Русский) - + Traditional Chinese (正體中文) Tavallinen Kiina (正體中文) - + Sound output mode Äänen ulostulotila - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Maa - + Clock Kello - + System Clock Järjestelmän Kello - + Fixed Time Yksittäinen Aika - + Startup time Aloitusaika - + yyyy-MM-ddTHH:mm:ss vvvv-KK-ppATT:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: Konsolin Tunnus: - - + + Regenerate Uudista - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3570,76 +3622,76 @@ online features (if installed) - - + + Console ID: 0x%1 Konsolin Tunnus: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Varoitus - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3754,13 +3806,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Käyttöliittymän kieli: + Interface Language + - Theme: - Teema: + Theme + @@ -3769,8 +3821,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - Kuvakkeen koko: + Icon Size + @@ -3790,8 +3842,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - Rivin 1 Teksti: + Row 1 Text + @@ -3825,17 +3877,17 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - Rivin 2 Teksti: + Row 2 Text + - Hide Titles without Icon - Piilota pelit ilman kuvakkeita + Hide titles without icon + - Single Line Mode + Single line mode @@ -3845,7 +3897,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3928,12 +3980,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Yhdistetään - + Connect Yhdistä @@ -4052,555 +4104,595 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Nykyinen emulaationopeus. Arvot yli tai ali 100% osoittavat, että emulaatio on nopeampi tai hitaampi kuin 3DS:än nopeus. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + MicroProfile (unavailable) - + Clear Recent Files - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage CIA pitää asenaa ennen käyttöä - + Before using this CIA, you must install it. Do you want to install it now? Ennen, kun voit käyttää tätä CIA:aa, sinun täytyy asentaa se. Haluatko asentaa sen nyt? - + Quick Load - + Quick Save - - + + Slot %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder Virhe Avatessa %1 Kansio - - + + Folder does not exist! Kansio ei ole olemassa! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... - - + + Cancel Peruuta - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. - + Error Opening %1 Virhe avatessa %1 - + Select Directory Valitse hakemisto - + Properties - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. - + Load File Lataa tiedosto - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Lataa tiedostoja - - 3DS Installation File (*.CIA*) - 3DS Asennustiedosto (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Kaikki tiedostot (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1 asennettiin onnistuneesti. - + Unable to open File Tiedostoa ei voitu avata - + Could not open %1 Ei voitu avata %1 - + Installation aborted Asennus keskeytetty - + The installation of %1 was aborted. Please see the log for more details - + Invalid File Sopimaton Tiedosto - + %1 is not a valid CIA %1 ei ole sopiva CIA-tiedosto - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. - + File not found Tiedostoa ei löytynyt - + File "%1" not found Tiedosto "%1" ei löytynyt. - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo tiedosto (%1);; Kaikki tiedostot (*.*) - + Load Amiibo Lataa Amiibo - + Unable to open amiibo file "%1" for reading. - + Record Movie Tallenna Video - + Movie recording cancelled. - - + + Movie Saved - - + + The movie is successfully saved. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4609,214 +4701,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Nopeus: %1% - + Speed: %1% / %2% Nopeus %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Kuvaruutu: %1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive - + System Archive Not Found - + System Archive Missing - + Save/load Error - + Fatal Error - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered - + Continue Jatka - + Quit Application - + OK OK - + Would you like to exit now? Haluatko poistua nyt? - + The application is still running. Would you like to stop emulation? - + Playback Completed - + Movie playback completed. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4879,42 +5021,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4922,239 +5064,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Yhteensopivuus - - + + Region Alue - - + + File type Tiedoston tyyppi - - + + Size Koko - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location Avaa hakemiston sijainti - + Clear Tyhjennä - + Name Nimi @@ -5162,77 +5314,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Täydellinen - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Mahtava - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Hyvä - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Huono - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Intro/Menu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Ei Käynnisty - + The app crashes when attempting to startup. - + Not Tested Ei Testattu - + The app has not yet been tested. @@ -5240,7 +5392,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5248,27 +5400,27 @@ Screen. GameListSearchField - + of - + result - + results - + Filter: Suodatin: - + Enter pattern to filter @@ -5276,47 +5428,47 @@ Screen. GameRegion - + Japan Japani - + North America Pohjois-Amerikka - + Europe Eurooppa - + Australia Australia - + China Kiina - + Korea Korea - + Taiwan Taiwan - + Invalid region Virheellinen alue - + Region free Aluevapaa @@ -5596,77 +5748,77 @@ Screen. - + SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 - + Compare Result: %1, %2 - + Static Condition: %1 - + Dynamic Conditions: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 - + Instruction offset: 0x%1 - + -> 0x%2 - + (last instruction) @@ -5890,23 +6042,23 @@ Debug Message: - - Loading Shaders %1 / %2 + + Loading %3 %1 / %2 - + Launching... - + Now Loading %1 - + Estimated Time %1 @@ -5965,32 +6117,32 @@ Debug Message: Salasana: - + Room Name Huoneen nimi - + Preferred Application - + Host Isäntä - + Players Pelaajia - + Refreshing Päivitetään - + Refresh List Päivitä lista @@ -6073,342 +6225,352 @@ Debug Message: Video - + Help - + Load File... Lataa tiedosto... - + Install CIA... Asenna CIA... - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit - + Pause - + Stop - + Save Tallenna - + Load - + FAQ - + About Azahar - + Single Window Mode Yhden ikkunan tila - + Save to Oldest Slot - + Quick Save - + Load from Newest Slot - + Quick Load - + Configure... Asetukset... - + Display Dock Widget Headers - + Show Filter Bar Näytä suodatinpalkki - + Show Status Bar Näytä tilapalkki - + Create Pica Surface Viewer - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame - + Capture Screenshot Kaappaa näyttökuva - + Dump Video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Luo huone - + Leave Room Lähde huoneesta - + Direct Connect to Room Suora yhteys huoneeseen - + Show Current Room Näytä Nykyinen Huone - + Fullscreen Koko näyttö - + Open Log Folder - + Opens the Azahar Log folder - + Default Oletus - + Single Screen Yksittäinen näyttö - + Large Screen Suuri näyttö - + Side by Side Vierekkäin - + Separate Windows - + Hybrid Screen - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Vaihda näytöt - + Rotate Upright - + Report Compatibility Ilmoita yhteensopivuus - + Restart Käynnistä uudelleen - + Load... Lataa... - + Remove Poista - + Open Azahar Folder - + Configure Current Application... @@ -6481,7 +6643,7 @@ Debug Message: File: - Tiedosto: + @@ -6573,7 +6735,7 @@ Debug Message: File: - Tiedosto: + @@ -6978,32 +7140,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Virheellinen alue - + Installed Titles Asennetut pelit - + System Titles - + Add New Application Directory - + Favorites diff --git a/dist/languages/fr.ts b/dist/languages/fr.ts index 464de61f3..d8a6179f8 100644 --- a/dist/languages/fr.ts +++ b/dist/languages/fr.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,8 +298,8 @@ Cela bannira à la fois son nom du forum et son adresse IP. - Emulation: - Émulation : + Emulation + Émulation @@ -328,8 +328,8 @@ Cela bannira à la fois son nom du forum et son adresse IP. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Cet effet de post-traitement ajuste la vitesse audio pour correspondre à la vitesse d'émulation et aide à prévenir les distorsions. Cela augmente cependant la latence du son. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -338,8 +338,8 @@ Cela bannira à la fois son nom du forum et son adresse IP. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Adapte la vitesse de lecture de l'audio pour tenir compte des baisses de fréquence d'images de l'émulation. Cela signifie que l'audio sera lu à pleine vitesse même si la fréquence d'images de l'application est faible. Peut entraîner des problèmes de désynchronisation de l'audio. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + @@ -403,6 +403,7 @@ Cela bannira à la fois son nom du forum et son adresse IP. + Camera Caméra @@ -414,8 +415,8 @@ Cela bannira à la fois son nom du forum et son adresse IP. - Camera to configure: - Caméra à configurer : + Camera to Configure + Caméra à configurer @@ -435,8 +436,8 @@ Cela bannira à la fois son nom du forum et son adresse IP. - Camera mode: - Mode de la caméra : + Camera mode + Mode caméra @@ -456,8 +457,8 @@ Cela bannira à la fois son nom du forum et son adresse IP. - Camera position: - Position de la caméra : + Camera position + Position de la caméra @@ -477,13 +478,13 @@ Cela bannira à la fois son nom du forum et son adresse IP. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Choisissez la provenance de l'image de la caméra émulée. Elle peut être une image ou une vraie caméra. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Source de l'image de la caméra : + Camera Image Source + Source d'images de la caméra @@ -502,8 +503,8 @@ Cela bannira à la fois son nom du forum et son adresse IP. - File: - Fichier : + File + Fichier @@ -516,11 +517,6 @@ Cela bannira à la fois son nom du forum et son adresse IP. Select the system camera to use Choisissez la caméra système à utiliser - - - Camera: - Caméra : - <Default> @@ -534,8 +530,8 @@ Cela bannira à la fois son nom du forum et son adresse IP. - Flip: - Basculement : + Flip + Inverser @@ -1088,8 +1084,8 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Reverse Side by Side - Côte à côte inversé + Side by Side Full Width + Côte à côte largeur maximale @@ -1147,48 +1143,53 @@ Souhaitez vous ignorer l'erreur et poursuivre ? <html><head/><body><p>Désactiver le rendu de l'œil droit</p><p>Désactive le rendu de l'œil droit lorsque le mode stéréoscopique n'est pas utilisé. Améliore considérablement les performances dans certaines applications, mais peut provoquer un scintillement dans d'autres.</p></body></html> - + + Swap Eyes + Intervertir les yeux + + + Utility Utilitaires - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Remplace les textures par des fichiers PNG.</p><p>Les textures sont chargées depuis load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures Utiliser des textures personnalisées - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Extrait les textures en fichiers PNG.</p><p>Les textures sont extraites vers dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures Exporter les textures - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>Charge toutes les textures personnalisées en mémoire au démarrage, au lieu de les charger lorsque l'application en a besoin.</p></body></html> - - Preload Custom Textures + + Preload custom textures Précharger des textures personnalisées - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head><body><p>Chargez les textures personnalisées de manière asynchrone avec des threads d’arrière-plan pour réduire le retard de chargement </p></body></head></html> - - Async Custom Texture Loading + + Async custom texture loading Chargement asynchrone des textures personnalisées @@ -1201,91 +1202,111 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - General - Général + Updates + Mises à jour - Confirm exit while emulation is running - Valider la fermeture pendant que l'émulation est en cours - - - - Pause emulation when in background - Mettre en pause l'émulation si en arrière-plan - - - - Mute audio when in background - Couper le son si en arrière-plan - - - - Hide mouse on inactivity - Cacher la souris si inactif - - - - Enable Gamemode - Activer le mode jeu - - - Check for updates Vérifier les mises à jour - + + Update Channel + Canal de mises à jour + + + + Stable + Stable + + + + Prerelease + Préversion + + + + General + Général + + + + Confirm exit while emulation is running + Valider la fermeture pendant que l'émulation est en cours + + + + Pause emulation when in background + Mettre en pause l'émulation si en arrière-plan + + + + Mute audio when in background + Couper le son si en arrière-plan + + + + Hide mouse on inactivity + Cacher la souris si inactif + + + + Enable Gamemode + Activer le mode jeu + + + Emulation Émulation - + Use global emulation speed Utiliser la vitesse d'émulation globale - - Set emulation speed: - Définir la vitesse d'émulation : + + Set emulation speed + Définir vitesse d'émulation - - Emulation Speed: - Vitesse d'émulation : + + Emulation Speed + Vitesse d'émulation - + Turbo Speed Limit: Turbo Speed Limite : - + Screenshots Captures d'écran - + Use global screenshot path Utiliser le répertoire des captures d'écran - + Set screenshot path: Définir le répertoire des captures d'écran : - + Save Screenshots To Enregistrer les captures d'écran sous - + ... ... - + Reset All Settings Tout réinitialiser @@ -1293,8 +1314,8 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - - + + unthrottled illimité @@ -1304,12 +1325,12 @@ Souhaitez vous ignorer l'erreur et poursuivre ? Choix du répertoire des captures d'écran - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? Voulez-vous vraiment <b>réinitialiser vos paramètres</b> et fermer Azahar ? @@ -1363,12 +1384,12 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - SPIR-V Shader Generation + SPIR-V shader generation Génération de shaders SPIR-V - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer Désactiver l'optimiseur GLSL -> SPIR-V @@ -1388,8 +1409,8 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Enable Hardware Shader - Activer le nuanceur matériel + Enable hardware shader + Activer le shader matériel @@ -1398,7 +1419,7 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Accurate Multiplication + Accurate multiplication Multiplication précise @@ -1408,8 +1429,8 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Enable Shader JIT - Activer le nuanceur JIT + Enable shader JIT + Activer le Shader JIT @@ -1418,18 +1439,18 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Enable Async Shader Compilation - Activer la compilation asynchrone des shaders + Enable async shader compilation + Activer la compilation de shader asynchrone. - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Effectue la présentation sur des threads séparés. Améliore les performances lors de l'utilisation de Vulkan dans la plupart des applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + <html><head/><body><p>Effectue la présentation sur des threads séparés. Améliore les performances lors de l'utilisation de Vulkan dans la plupart des applications. Rajoute environ 1 image de latence d'entrée.</p></body></html> - Enable Async Presentation - Activer la présentation asynchrone + Enable async presentation + Activer la présentation asynchrone. @@ -1468,13 +1489,13 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Use Disk Shader Cache + Use disk shader cache Utiliser le cache de shaders sur disque - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync empêche les effets de déchirement de l'image, mais elle réduira la performance de certaines cartes graphiques. Laissez-la activée si vous ne constatez pas de différence. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1482,22 +1503,32 @@ Souhaitez vous ignorer l'erreur et poursuivre ? Activer VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global Utiliser la globale - + Use per-application Utilisation par application - - Delay application render thread: - Délai du thread de rendu de l'application : + + Delay Application Render Thread + Retarder le thread de rendu de l'application : - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>Délaie le thread de rendu de l'application émulée du nombre de millisecondes spécifié chaque fois qu'il soumet des commandes de rendu au GPU.</p><p> Ajustez cette fonction dans les (très rares) applications à fréquence d'images dynamique pour résoudre les problèmes de performance.</p></body></html> @@ -1982,12 +2013,12 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Swap Screens + Swap screens Permuter les écrans - Rotate Screens Upright + Rotate screens upright Rotation des écrans vers le haut @@ -2104,8 +2135,8 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>% d'opacité de l'écran inférieur (OpenGL uniquement)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + <html><head/><body><p>Opacité de l'écran inférieur %</p></body></html> @@ -2276,8 +2307,8 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">En savoir plus</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">En savoir plus</span></a> @@ -2452,7 +2483,7 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Use Virtual SD + Use virtual SD card Utiliser une carte SD virtuelle @@ -2462,8 +2493,8 @@ Souhaitez vous ignorer l'erreur et poursuivre ? - Use Custom Storage - Utiliser le stockage personnalisé + Use custom storage location + Utiliser des répertoires de stockage personnalisés @@ -2493,6 +2524,16 @@ Souhaitez vous ignorer l'erreur et poursuivre ? SDMC Directory Répertoire SDMC + + + Compress installed CIA content + Compresser le contenu CIA installé + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2540,8 +2581,8 @@ les fonctionnalités en ligne (si installés) - Region: - Région : + Region + Région @@ -2549,326 +2590,338 @@ les fonctionnalités en ligne (si installés) Sélection automatique - + + Apply region free patch to +installed applications. + Appliquer des correctifs pour +désactiver les restrictions régionales des applications installées. + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + Corrige la région des applications installées pour qu'elles soient sans région, afin qu'elles apparaissent toujours dans le menu home. + + + Username Nom d'utilisateur - + Birthday Date de naissance - + January Janvier - + February Février - + March Mars - + April Avril - + May Mai - + June Juin - + July Juillet - + August Août - + September Septembre - + October Octobre - + November Novembre - + December Décembre - + Language Langue - + Note: this can be overridden when region setting is auto-select Note : ceci peut être remplacé quand le paramètre de région est défini sur Automatique - + Japanese (日本語) Japonais (日本語) - + English Anglais (English) - + French (français) Français - + German (Deutsch) Allemand (Deutsch) - + Italian (italiano) Italien (italiano) - + Spanish (español) Espagnol (español) - + Simplified Chinese (简体中文) Chinois simplifié (简体中文) - + Korean (한국어) Coréen (한국어) - + Dutch (Nederlands) Néerlandais (Nederlands) - + Portuguese (português) Portugais (português) - + Russian (Русский) Russe (Русский) - + Traditional Chinese (正體中文) Chinois traditionnel (正體中文) - + Sound output mode Mode de sortie audio - + Mono Mono - + Stereo Stéréo - + Surround Surround - + Country Pays - + Clock Horloge - + System Clock Horloge système - + Fixed Time Temps fixe - + Startup time Heure au démarrage - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time Décalage horaire - + days jours - + HH:mm:ss HH:mm:ss - + Initial System Ticks Ticks systèmes initiaux - + Random Aléatoire - + Fixed Fixe - + Initial System Ticks Override Remplacement des ticks systèmes initiaux - + Play Coins Pièces de jeu - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body></p>Nombre de pas par heure reporté par le podomètre. Sur une échelle de 0 à 65 535.</p></body></html> - + Pedometer Steps per Hour Pas de podomètre par heure - + Run System Setup when Home Menu is launched Exécuter la configuration du système lorsque le menu home est lancé - + Console ID: ID de la console : - - + + Regenerate Regénérer - + MAC: MAC : - - 3GX Plugin Loader: - 3GX Plugin Loader : + + 3GX Plugin Loader + 3GX Plugin Loader - + Enable 3GX plugin loader Activer le 3GX Plugin Loader - + Allow applications to change plugin loader state Permettre aux applications de modifier l'état du Plugin Loader - + Real Console Unique Data Données uniques d'une vraie console - + Your real console is linked to Azahar. Votre console réelle est liée à Azahar. - + Unlink Dissocier - + OTP OTP - - - - + + + + Choose Choisir - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. Les paramètres du système ne sont disponibles que lorsque les applications ne sont pas en cours d'exécution. @@ -3578,76 +3631,76 @@ les fonctionnalités en ligne (si installés) Fichier Sed (*.sed);;Tous les fichiers (*.*) - - + + Console ID: 0x%1 Console ID : 0x%1 - - + + MAC: %1 MAC : %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? Cela remplacera l'ID actuel de votre console virtuelle 3DS par un nouveau. L'ID actuel de votre console virtuelle 3DS ne pourra pas être récupéré. Cela pourrait avoir des effets inattendus sur certaines applications. L'opération peut échouer si vous utilisez une sauvegarde de configuration obsolète. Continuer ? - - - + + + Warning Avertissement - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? Cela remplacera votre adresse MAC actuelle par une nouvelle. Il n'est pas recommandé de faire cela si vous avez récupéré l'adresse MAC depuis votre console réelle à l'aide de l'outil de configuration. Continuer ? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? Cette action désassociera votre console réelle d'Azahar, avec les conséquences suivantes :<br><ul><li>Votre OTP, SecureInfo et LocalFriendCodeSeed seront supprimés d'Azahar.</li><li>Votre liste d'amis sera réinitialisée et vous serez déconnecté de votre compte NNID/PNID.</li><li>Les fichiers système et les titres de l'eShop obtenus via Azahar deviendront inaccessibles jusqu'à ce que la même console soit à nouveau connectée (les données sauvegardées ne seront pas perdues).</li></ul><br>Continuer ? - + Invalid country for configured region Pays invalide pour la région configurée - + Invalid country for console unique data Pays invalide pour les données uniques de la console - + Status: Loaded Statut : Chargé - + Status: Loaded (Invalid Signature) Statut : Chargé (signature invalide) - + Status: Loaded (Region Changed) Statut : Chargé (région modifiée) - + Status: Not Found Statut : Introuvable - + Status: Invalid Statut : invalide - + Status: IO Error Statut : Erreur d'E/S @@ -3763,13 +3816,13 @@ Glissez les points pour modifier la position, ou double-cliquez les cellules pou - Interface language: + Interface Language Langue de l'interface : - Theme: - Thème : + Theme + Thème @@ -3778,8 +3831,8 @@ Glissez les points pour modifier la position, ou double-cliquez les cellules pou - Icon Size: - Talle de l'icône : + Icon Size + Taille de l'ïcône @@ -3799,8 +3852,8 @@ Glissez les points pour modifier la position, ou double-cliquez les cellules pou - Row 1 Text: - Texte de la ligne 1 : + Row 1 Text + Texte de la ligne 1 @@ -3834,18 +3887,18 @@ Glissez les points pour modifier la position, ou double-cliquez les cellules pou - Row 2 Text: - Texte de la ligne 2 : + Row 2 Text + Texte de la ligne 2 - Hide Titles without Icon + Hide titles without icon Masquer les titres sans icône - Single Line Mode - Mode simple ligne + Single line mode + Mode ligne unique @@ -3854,7 +3907,7 @@ Glissez les points pour modifier la position, ou double-cliquez les cellules pou - Show Advanced Frame Time Info + Show advanced frame time info Afficher les informations avancées sur le temps d'image @@ -3937,12 +3990,12 @@ Glissez les points pour modifier la position, ou double-cliquez les cellules pou DirectConnectWindow - + Connecting Connexion en cours - + Connect Connecter @@ -4062,471 +4115,511 @@ Veuillez vérifier votre installation FFmpeg utilisée pour la compilation. GMainWindow - + No Suitable Vulkan Devices Detected Aucun périphérique Vulkan adapté détecté - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. L'initialisation de Vulkan a échoué au démarrage.<br/>Votre GPU pourrait ne pas prendre en charge Vulkan 1.1, ou vous pourriez ne pas avoir le pilote graphique le plus récent. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. Vitesse actuelle du trafic Artic. Des valeurs plus élevées indiquent des charges de transfert plus importantes. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Vitesse actuelle d'émulation. Les valeurs supérieures ou inférieures à 100% indiquent que l'émulation est plus rapide ou plus lente qu'une 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. Nombre d'images par seconde affichées par l'application. Cela varie d'une application à l'autre et d'une scène à l'autre. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Temps nécessaire pour émuler une trame 3DS, sans compter la limitation de trame ou la synchronisation verticale V-Sync. Pour une émulation à pleine vitesse, cela ne devrait pas dépasser 16,67 ms. - + MicroProfile (unavailable) MicroProfile (indisponible) - + Clear Recent Files Effacer les fichiers récents - + &Continue &Continuer - + &Pause &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar exécute une application - - + + Invalid App Format Format d'application invalide - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Le format de votre application n'est pas pris en charge.<br/> Veuillez suivre les guides pour extraire à nouveau vos <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>cartouches de jeu</a> ou les <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>titres installés</a>. - + App Corrupted Application corrompue - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Votre application est corrompue. <br/>Veuillez suivre les guides pour récupérer vos <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>cartouches de jeux</a> ou les <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>titres installés</a>. - + App Encrypted Application encryptée - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Votre application est encryptée. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Consultez notre blog pour plus d'informations.</a> - + Unsupported App Application non supportée - + GBA Virtual Console is not supported by Azahar. La console virtuelle de la GBA n'est pas prise en charge par Azahar. - - + + Artic Server Serveur Artic - + + Invalid system mode + Mode système invalide. + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + Les applications exclusives New 3DS ne peuvent pas être chargées sans activer le mode New 3DS. + + + Error while loading App! Erreur lors du chargement de l'application ! - + An unknown error occurred. Please see the log for more details. Une erreur inconnue s'est produite. Veuillez consulter le journal pour plus de détails. - + CIA must be installed before usage CIA doit être installé avant utilisation - + Before using this CIA, you must install it. Do you want to install it now? Avant d'utiliser ce CIA, vous devez l'installer. Voulez-vous l'installer maintenant ? - + Quick Load Chargement rapide - + Quick Save Sauvegarde rapide - - + + Slot %1 Emplacement %1 - + %2 %3 %2 %3 - + Quick Save - %1 Sauvegarde rapide - %1 - + Quick Load - %1 Chargement rapide - %1 - + Slot %1 - %2 %3 Emplacement %1 - %2 %3 - + Error Opening %1 Folder Erreur lors de l'ouverture du dossier %1 - - + + Folder does not exist! Le répertoire n'existe pas ! - + Remove Play Time Data Retirer les données de temps de jeu ? - + Reset play time? Réinitialiser le temps de jeu ? - - - - + + + + Create Shortcut Créer un raccourci - + Do you want to launch the application in fullscreen? Voulez-vous lancer l'application en plein écran ? - + Successfully created a shortcut to %1 Création réussie d'un raccourci vers %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Cela créera un raccourci vers l'AppImage actuelle. Il se peut que cela ne fonctionne pas bien si vous effectuez une mise à jour. Poursuivre ? - + Failed to create a shortcut to %1 Échec de la création d'un raccourci vers %1 - + Create Icon Créer icône - + Cannot create icon file. Path "%1" does not exist and cannot be created. Impossible de créer le fichier icône. Le chemin "%1" n'existe pas et ne peut pas être créé. - + Dumping... Extraction... - - + + Cancel Annuler - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. Impossible d'extraire les RomFS de base. Référez-vous aux logs pour plus de détails. - + Error Opening %1 Erreur lors de l'ouverture de %1 - + Select Directory Sélectionner un répertoire - + Properties Propriétés - + The application properties could not be loaded. Les propriétés de l'application n'ont pas pu être chargées. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Exécutable 3DS (%1);;Tous les fichiers (*.*) - + Load File Charger un fichier - - + + Set Up System Files Configurer les fichiers système - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> <p>Azahar a besoin des données et des fichiers de firmware propres à une console réelle pour pouvoir utiliser certaines de ses fonctionnalités.<br>Ces fichiers et données peuvent être configurés à l'aide de l'outil <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool.</a><br>Notes :<ul><li><b>Cette opération installera des données uniques à la console Azahar. Ne partagez pas vos dossiers utilisateur ou nand <br>après avoir effectué le processus d'installation !</b></li><li>Pendant le processus d'installation, Azahar se connectera à la console exécutant l'outil d'installation. Vous pourrez ensuite déconnecter la <br>console à partir de l'onglet Système dans le menu de configuration de l'émulateur.</li><li>Ne vous connectez pas à Internet avec Azahar et votre console 3DS en même temps après avoir configuré les fichiers système,<br> car cela pourrait causer des problèmes.</li><li>La configuration de l'ancienne 3DS est nécessaire pour que la configuration de la nouvelle 3DS fonctionne (il est recommandé d'effectuer les deux modes de configuration).</li><li>Les deux modes de configuration fonctionnent quel que soit le modèle de console sur lequel l'outil de configuration est exécuté.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: Entrer l'adresse de l'outil de configuration Artic d'Azahar : - + <br>Choose setup mode: <br>Choisissez le mode de configuration : - + (ℹ️) Old 3DS setup (ℹ️) Configuration Old 3DS - - + + Setup is possible. La configuration est possible. - + (⚠) New 3DS setup (⚠) Configuration New 3DS - + Old 3DS setup is required first. La configuration Old 3DS est requise d'abord. - + (✅) Old 3DS setup (✅) Configuration Old 3DS - - + + Setup completed. Configuration terminée. - + (ℹ️) New 3DS setup (ℹ️) Configuration New 3DS - + (✅) New 3DS setup (✅) Configuration New 3DS - + The system files for the selected mode are already set up. Reinstall the files anyway? Les fichiers système pour le mode sélectionné sont déjà configurés. Voulez-vous les réinstaller quand même ? - + Load Files Charger des fichiers - - 3DS Installation File (*.CIA*) - Fichier d'installation 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + Fichier d'installation 3DS (*.cia *.zcia) - + + + All Files (*.*) Tous les fichiers (*.*) - + Connect to Artic Base Se connecter à Artic Base - + Enter Artic Base server address: Entrez l'adresse du serveur Artic Base : - + %1 has been installed successfully. %1 a été installé avec succès. - + Unable to open File Impossible d'ouvrir le fichier - + Could not open %1 Impossible d'ouvrir %1 - + Installation aborted Installation annulée - + The installation of %1 was aborted. Please see the log for more details L'installation de %1 a été interrompue. Veuillez consulter les logs pour plus de détails. - + Invalid File Fichier invalide - + %1 is not a valid CIA %1 n'est pas un CIA valide - + CIA Encrypted CIA chiffré - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Votre fichier CIA est chiffré.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Consultez notre blog pour plus d'informations.</a> - + Unable to find File Impossible de trouver le fichier - + Could not find %1 Impossible de trouver %1 - + + + + + Z3DS Compression + Compression Z3DS + + + + Failed to compress some files, check log for details. + Échec de la compression de certains fichiers, vérifiez le log pour plus de détails. + + + + Failed to decompress some files, check log for details. + Échec de la décompression de certains fichiers, vérifiez le log pour plus de détails. + + + + All files have been compressed successfully. + Tous les fichiers ont été compréssé avec succès. + + + + All files have been decompressed successfully. + Tous les fichiers ont été décompréssé avec succès. + + + Uninstalling '%1'... Désinstallation de '%1'... - + Failed to uninstall '%1'. Échec de la désinstallation de '%1'. - + Successfully uninstalled '%1'. Désinstallation de '%1' réussie. - + File not found Fichier non trouvé - + File "%1" not found Le fichier "%1" n'a pas été trouvé - + Savestates Points de récupération - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! @@ -4535,86 +4628,86 @@ Use at your own risk! À utiliser à vos risques et périls ! - - - + + + Error opening amiibo data file Erreur d'ouverture du fichier de données amiibo - + A tag is already in use. Un tag est déjà en cours d'utilisation. - + Application is not looking for amiibos. L'application ne recherche pas d'amiibos. - + Amiibo File (%1);; All Files (*.*) Fichier Amiibo (%1);; Tous les fichiers (*.*) - + Load Amiibo Charger un Amiibo - + Unable to open amiibo file "%1" for reading. Impossible d'ouvrir le fichier amiibo "%1" pour le lire. - + Record Movie Enregistrer une vidéo - + Movie recording cancelled. Enregistrement de la vidéo annulé. - - + + Movie Saved Vidéo enregistrée - - + + The movie is successfully saved. La vidéo a été enregistrée avec succès. - + Application will unpause L'application sera rétablie. - + The application will be unpaused, and the next frame will be captured. Is this okay? L'application sera rétablie et l'image suivante sera capturée. Cela vous convient-il ? - + Invalid Screenshot Directory Répertoire des captures d'écran invalide - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. Création du répertoire des captures d'écran spécifié impossible. Le chemin d'accès vers les captures d'écran est réinitialisé à sa valeur par défaut. - + Could not load video dumper Impossible de charger le module de capture vidéo. - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4627,215 +4720,265 @@ Pour installer FFmpeg sur Azahar, appuyez sur Ouvrir et sélectionnez votre rép Pour afficher un guide sur l'installation de FFmpeg, appuyez sur Aide. - + + Load 3DS ROM Files + Charger les fichiers ROM 3DS + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + Fichiers ROM 3DS (*.cia *.cci *.3dsx *.cci *.3ds) + + + + 3DS Compressed ROM File (*.%1) + Fichier ROM compressé 3DS (*.%1) + + + + Save 3DS Compressed ROM File + Enregistrer le fichier ROM compressé 3DS + + + + Select Output 3DS Compressed ROM Folder + Sélectionner le dossier de sortie des fichiers ROM 3DS compressés + + + + Load 3DS Compressed ROM Files + Charger des fichiers ROM 3DS compréssés + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + Fichiers ROM compressés 3DS (*.zcia *zcci *z3dsx *zcxi) + + + + 3DS ROM File (*.%1) + Fichier ROM 3DS (*.%1) + + + + Save 3DS ROM File + Enregistrer le fichier ROM 3DS + + + + Select Output 3DS ROM Folder + Sélectionner le dossier de sortie des fichiers ROM 3DS + + + Select FFmpeg Directory Sélectionnez le répertoire FFmpeg. - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. Le répertoire FFmpeg fourni manque %1. Assurez-vous d'avoir sélectionné le répertoire correct. - + FFmpeg has been sucessfully installed. FFmpeg a été installé avec succès. - + Installation of FFmpeg failed. Check the log file for details. L'installation de FFmpeg a échoué. Consultez le fichier journal pour plus de détails. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. Impossible de lancer le dump vidéo.<br>Veuillez vous assurer que l'encodeur vidéo est configuré correctement.<br>Reportez-vous au logs pour plus de détails. - + Recording %1 Enregistrement %1 - + Playing %1 / %2 Lecture de %1 / %2 - + Movie Finished Vidéo terminée - + (Accessing SharedExtData) (Accès à SharedExtData) - + (Accessing SystemSaveData) (Accès à SystemSaveData) - + (Accessing BossExtData) (Accès à BossExtData) - + (Accessing ExtData) (Accès à ExtData) - + (Accessing SaveData) (Accès à SaveData) - + MB/s Mo/s - + KB/s Ko/s - + Artic Traffic: %1 %2%3 Trafic Artic : %1 %2%3 - + Speed: %1% Vitesse : %1% - + Speed: %1% / %2% Vitesse : %1% / %2% - + App: %1 FPS App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms (CPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Trame : %1 ms - + VOLUME: MUTE VOLUME : MUET - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUME : %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - %1 est manquant. <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'> extrayez vos archives systèmes</a>. <br/>Continuer l'émulation pourrait entraîner des plantages et des bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + %1 est manquant. Veuillez <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>vider les archives de votre système</a>. <br/>La poursuite de l'émulation peut entraîner des plantages et des bogues. - + A system archive Une archive système - + System Archive Not Found Archive système non trouvée - + System Archive Missing Archive système absente - + Save/load Error Erreur de sauvegarde/chargement - + Fatal Error Erreur fatale - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Une erreur fatale est survenue. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Vérifiez les logs</a> pour plus d'infos.<br/>Continuer l'émulation pourrait entraîner des crashs et des bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + Une erreur fatale s'est produite. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Consultez le journal</a> pour plus de détails.<br/> La poursuite de l'émulation peut entraîner des plantages et des bogues. - + Fatal Error encountered Une erreur fatale s'est produite - + Continue Continuer - + Quit Application Quitter l'application - + OK OK - + Would you like to exit now? Voulez-vous quitter maintenant ? - + The application is still running. Would you like to stop emulation? L'application est toujours en cours d'exécution. Voulez-vous arrêter l'émulation ? - + Playback Completed Lecture terminée - + Movie playback completed. Lecture de la vidéo terminée. - + Update Available Mise à jour disponible - + Update %1 for Azahar is available. Would you like to download it? La mise à jour %1 pour Azahar est disponible. Souhaitez-vous la télécharger ? - + Primary Window Fenêtre principale - + Secondary Window Fenêtre secondaire @@ -4898,42 +5041,42 @@ Souhaitez-vous la télécharger ? GRenderWindow - + OpenGL not available! OpenGL non disponible ! - + OpenGL shared contexts are not supported. Les contextes partagés OpenGL ne sont pas pris en charge. - + Error while initializing OpenGL! Erreur lors de l'initialisation d'OpenGL ! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Votre GPU peut ne pas prendre en charge OpenGL ou vous ne disposez pas des derniers pilotes graphiques. - + Error while initializing OpenGL 4.3! Erreur lors de l'initialisation d'OpenGL 4.3 ! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Votre GPU peut ne pas prendre en charge OpenGL 4.3 ou vous ne disposez pas des derniers pilotes graphiques.<br><br>Moteur de rendu GL :<br>%1 - + Error while initializing OpenGL ES 3.2! Erreur lors de l'initialisation d'OpenGL ES 3.2 ! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Votre GPU pourrait ne pas prendre en charge OpenGL ES 3.2, ou vous pourriez ne pas avoir le pilote graphique le plus récent.<br><br>Moteur de rendu GL :<br>%1 @@ -4941,175 +5084,185 @@ Souhaitez-vous la télécharger ? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - IMPORTANT : Les fichiers encryptés et les fichiers .3ds ne sont plus pris en charge. Il peut être nécessaire de les décrypter et/ou de les renommer en .cci. <a href='https://azahar-emu.org/blog/game-loading-changes/'>En savoir plus.</a> - - - - Don't show again - Ne pas montrer à nouveau - - - - + + Compatibility Compatibilité - - + + Region Région - - + + File type Type de fichier - - + + Size Taille - - + + Play time Temps de jeu - + Favorite Favori - + + Eject Cartridge + Éjecter Cartouche + + + + Insert Cartridge + Insérer Cartouche + + + Open Ouvrir - + Application Location Chemin de l'application - + Save Data Location Chemin des données de sauvegarde - + Extra Data Location Chemin des données additionnelles - + Update Data Location Chemin des données de mise à jour - + DLC Data Location Chemin des données de DLC - + Texture Dump Location Chemin d'extraction de textures - + Custom Texture Location Chemin des textures personnalisées - + Mods Location Emplacement des Mods - + Dump RomFS Extraire RomFS - + Disk Shader Cache Cache de shader de disque - + Open Shader Cache Location Ouvrir l'emplacement du cache de shader - + Delete OpenGL Shader Cache Supprimer le cache de shader OpenGL - + + Delete Vulkan Shader Cache + + + + Uninstall Désinstaller - + Everything Tout - + Application Application - + Update Mise à jour - + DLC DLC - + Remove Play Time Data Retirer les données de temps de jeu - + Create Shortcut Créer un raccourci - + Add to Desktop Ajouter au bureau - + Add to Applications Menu Ajouter au menu d'applications - + + Stress Test: App Launch + Stress Test : Lancement d'application + + + Properties Propriétés - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. @@ -5118,64 +5271,64 @@ This will delete the application if installed, as well as any installed updates Cela supprimera l'application si elle est installée, ainsi que toutes ses mises à jour et DLCs. - - + + %1 (Update) %1 (Mise à jour) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? Êtes-vous sûr de vouloir désinstaller '%1' ? - + Are you sure you want to uninstall the update for '%1'? Êtes-vous sûr de vouloir désinstaller la mise à jour de '%1' ? - + Are you sure you want to uninstall all DLC for '%1'? Êtes-vous sûr de vouloir désinstaller le DLC de '%1' ? - + Scan Subfolders Scanner les sous-dossiers - + Remove Application Directory Supprimer le répertoire d'applications - + Move Up Déplacer en haut - + Move Down Déplacer en bas - + Open Directory Location Ouvrir l'emplacement de ce répertoire - + Clear Effacer - + Name Nom @@ -5183,82 +5336,82 @@ Cela supprimera l'application si elle est installée, ainsi que toutes ses GameListItemCompat - + Perfect Parfait - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. L'application fonctionne parfaitement, sans problème audio ou graphique, et toutes les fonctionnalités testées fonctionnent comme prévu sans qu'aucune solution. de contournement ne soit nécessaire. - + Great Bien - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. L'application fonctionne avec quelques glitches graphiques et/ou audios et est jouable du début à la fin. Peut demander quelques contournements. - + Okay Ok - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. L'application fonctionne avec des glitches graphiques et/ou audios majeurs, mais l'appli est jouable du début à la fin avec des contournements. - + Bad Mauvais - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. L'appli fonctionne, mais avec des glitches graphiques et/ou audios majeurs. Difficile de progresser dans des endroits spécifiques à cause des glitches même avec des contournements. - + Intro/Menu Intro/Menu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. L'appli est complètement injouable à cause des glitches audios et graphiques majeurs. Difficile de progresser après l'écran de démarrage. - + Won't Boot Ne se lance pas - + The app crashes when attempting to startup. L'application plante au démarrage. - + Not Tested Non testé - + The app has not yet been tested. L'appli n'a pas été testée. Référez-vous aux versions américaines pour voir les potentiels tests effectués ! @@ -5266,7 +5419,7 @@ de démarrage. GameListPlaceholder - + Double-click to add a new folder to the application list Double-cliquez pour ajouter un nouveau dossier à la liste des applications. @@ -5274,27 +5427,27 @@ de démarrage. GameListSearchField - + of sur - + result résultat - + results résultats - + Filter: Filtre : - + Enter pattern to filter Entrer le motif de filtrage @@ -5302,47 +5455,47 @@ de démarrage. GameRegion - + Japan Japon - + North America Amérique du nord - + Europe Europe - + Australia Australie - + China Chine - + Korea Corée - + Taiwan Taïwan - + Invalid region Région non valide - + Region free Non zoné @@ -5622,87 +5775,87 @@ de démarrage. Index du cycle : - + SRC1: %1, %2, %3, %4 SRC1 : %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2 : %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3 : %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN : %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT : %1, %2, %3, %4 - + Address Registers: %1, %2 Adresse des Registres : %1, %2 - + Compare Result: %1, %2 Comparer le résultat : %1, %2 - + Static Condition: %1 Condition Statique : %1 - + Dynamic Conditions: %1, %2 Conditions Dynamiques : %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Paramètres de la boucle : %1 (répétitions), %2 (initialisation), %3 (incrémentation), %4 - + Instruction offset: 0x%1 Instruction offset : 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (instruction précédente) @@ -5927,24 +6080,24 @@ Message de débogage : Préparation des shaders %1 / %2 - - Loading Shaders %1 / %2 - Chargement des shaders %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Démarrage... - + Now Loading %1 Chargement en cours %1 - + Estimated Time %1 Durée estimée %1 @@ -6003,32 +6156,32 @@ Message de débogage : Mot de passe : - + Room Name Nom du salon - + Preferred Application Application favorite - + Host Hôte - + Players Joueurs - + Refreshing Actualisation - + Refresh List Actualiser la liste @@ -6111,342 +6264,352 @@ Message de débogage : Vidéo - + Help Aide - + Load File... Charger un fichier... - + Install CIA... Installer un CIA... - + Connect to Artic Base... Se connecter à Artic Base... - + Set Up System Files... Configurer les fichiers système... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit Quitter - + Pause Pause - + Stop Arrêter - + Save Sauvegarder - + Load Charger - + FAQ FAQ - + About Azahar À propos d'Azahar - + Single Window Mode Mode fenêtre unique - + Save to Oldest Slot Sauvegarder dans l'emplacement le plus ancien - + Quick Save Sauvegarde rapide - + Load from Newest Slot Charger depuis le dernier emplacement - + Quick Load Chargement rapide - + Configure... Configurer... - + Display Dock Widget Headers Afficher les en-têtes des widgets Dock - + Show Filter Bar Montrer la barre des filtres - + Show Status Bar Montrer la barre de statut - + Create Pica Surface Viewer Créer une surface Pica - + Record... Enregistrement... - + Play... Lecture... - + Close Fermer - + Save without Closing Enregistrer sans fermer - + Read-Only Mode Mode lecture seule - + Advance Frame Avancer la trame - + Capture Screenshot Capture d'écran - + Dump Video Capturer la vidéo + Compress ROM File... + Compresser le fichier ROM... + + + + Decompress ROM File... + Décompresser le fichier ROM... + + + Browse Public Rooms Rechercher des salons publics - + Create Room Créer un salon - + Leave Room Quitter le salon - + Direct Connect to Room Connexion directe à un salon - + Show Current Room Afficher le salon actuel - + Fullscreen Plein écran - + Open Log Folder Ouvrir le dossier des logs - + Opens the Azahar Log folder Ouvre le dossier des logs d'Azahar - + Default Par défaut - + Single Screen Un seul écran - + Large Screen Écran large - + Side by Side Côte à côte - + Separate Windows Fenêtres séparées - + Hybrid Screen Écran hybride - + Custom Layout Disposition personnalisée - + Top Right En haut à droite - + Middle Right Au milieu à droite - + Bottom Right En bas à droite - + Top Left En haut à gauche - + Middle Left Au milieu à gauche - + Bottom Left En bas à gauche - + Above Au dessus - + Below En dessous - + Swap Screens Permuter les écrans - + Rotate Upright Rotation vers le haut - + Report Compatibility Faire un rapport de compatibilité - + Restart Redémarrer - + Load... Charger... - + Remove Supprimer - + Open Azahar Folder Ouvrir le dossier Azahar - + Configure Current Application... Configurer l'application actuelle... @@ -7020,32 +7183,32 @@ Il a peut-être quitté la salon. %1 (0x%2) - + Unsupported encrypted application Application chiffrée non supportée - + Invalid region Région Invalide - + Installed Titles Titres installés - + System Titles Titres système - + Add New Application Directory Ajouter un nouvel emplacement d'applications - + Favorites Favorites diff --git a/dist/languages/hu_HU.ts b/dist/languages/hu_HU.ts index 7aa97acda..30a3af46c 100644 --- a/dist/languages/hu_HU.ts +++ b/dist/languages/hu_HU.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -290,8 +290,8 @@ This would ban both their forum username and their IP address. - Emulation: - Emuláció: + Emulation + Emuláció @@ -320,8 +320,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Ez az utófeldolgozási hatás beállítja a hang sebességét, hogy az emuláció sebességével megegyezzen, és segít a hang-akadozás megakadályozásában. Azonban ez megnöveli a hang késleltetését. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -330,7 +330,7 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -395,6 +395,7 @@ This would ban both their forum username and their IP address. + Camera Kamera @@ -406,8 +407,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - Konfigurálandó kamera: + Camera to Configure + @@ -427,8 +428,8 @@ This would ban both their forum username and their IP address. - Camera mode: - Kamera mód: + Camera mode + @@ -448,8 +449,8 @@ This would ban both their forum username and their IP address. - Camera position: - Kamera pozíció: + Camera position + @@ -469,13 +470,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Válaszd ki hogy honnan jön az emulált kamera képe. Lehet egy kép, vagy egy igazi kamera is. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Kamera Kép Forrása: + Camera Image Source + @@ -494,8 +495,8 @@ This would ban both their forum username and their IP address. - File: - Fájl: + File + @@ -508,11 +509,6 @@ This would ban both their forum username and their IP address. Select the system camera to use Válaszd ki a használandó rendszerkamerát - - - Camera: - Kamera: - <Default> @@ -526,8 +522,8 @@ This would ban both their forum username and their IP address. - Flip: - Forgatás: + Flip + @@ -1080,7 +1076,7 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Reverse Side by Side + Side by Side Full Width @@ -1139,48 +1135,53 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - + + Swap Eyes + + + + Utility Segédprogramok - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures - Egyéni textúrák használata + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures - Textúrák kimentése + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures - Egyéni textúrák előtöltése + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading @@ -1193,91 +1194,111 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - General - Általános + Updates + - Confirm exit while emulation is running - Kilépés megerősítése amikor az emuláció fut - - - - Pause emulation when in background - Emuláció szüneteltetése a háttérben - - - - Mute audio when in background - Hang némítása, amikor háttérben van - - - - Hide mouse on inactivity - Egér elrejtése inaktivitáskor - - - - Enable Gamemode - Játékmód engedélyezése - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Általános + + + + Confirm exit while emulation is running + Kilépés megerősítése amikor az emuláció fut + + + + Pause emulation when in background + Emuláció szüneteltetése a háttérben + + + + Mute audio when in background + Hang némítása, amikor háttérben van + + + + Hide mouse on inactivity + Egér elrejtése inaktivitáskor + + + + Enable Gamemode + Játékmód engedélyezése + + + Emulation Emuláció - + Use global emulation speed Globális emulációsebesség használata - - Set emulation speed: - Emuláció sebességének beállítása: + + Set emulation speed + - - Emulation Speed: - Emuláció sebessége: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots Képernyőmentések - + Use global screenshot path Globális útvonal használata képernyőmentésekhez - + Set screenshot path: Képernyőmentések útvonala: - + Save Screenshots To Képernyőfotók mentése ide - + ... ... - + Reset All Settings Összes beállítás visszaállítása @@ -1285,8 +1306,8 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - - + + unthrottled @@ -1296,12 +1317,12 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? Képernyőmentések könyvtár kiválasztása - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1355,12 +1376,12 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1380,8 +1401,8 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Enable Hardware Shader - Hardver Shader Bekapcsolása + Enable hardware shader + @@ -1390,8 +1411,8 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Accurate Multiplication - Pontos Szorzás + Accurate multiplication + @@ -1400,8 +1421,8 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Enable Shader JIT - Shader JIT Bekapcsolása + Enable shader JIT + @@ -1410,18 +1431,18 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation - Aszinkron prezentálás engedélyezése + Enable async presentation + @@ -1460,12 +1481,12 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Use Disk Shader Cache + Use disk shader cache - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> @@ -1474,22 +1495,32 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? VSync engedélyezése - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1974,12 +2005,12 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Swap Screens - Képernyők Cseréje + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2096,7 +2127,7 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2268,7 +2299,7 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2444,8 +2475,8 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Use Virtual SD - Virtuális SD használata + Use virtual SD card + @@ -2454,8 +2485,8 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? - Use Custom Storage - Egyéni tárhely használata + Use custom storage location + @@ -2485,6 +2516,16 @@ Szeretnéd figyelmen kívül hagyni a hibát, és folytatod? SDMC Directory SDMC könyvtár + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2531,8 +2572,8 @@ online features (if installed) - Region: - + Region + Régió @@ -2540,326 +2581,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Felhasználónév - + Birthday Születésnap - + January Január - + February Február - + March Március - + April Április - + May Május - + June Június - + July Július - + August Augusztus - + September Szeptember - + October Október - + November November - + December December - + Language Nyelv - + Note: this can be overridden when region setting is auto-select Megjegyzés: Ez felülírható ha a régió auto-kiválasztásra van beállítva - + Japanese (日本語) Japán (日本語) - + English English - + French (français) Francia (français) - + German (Deutsch) Német (Deutsch) - + Italian (italiano) Italian (Italiano) - + Spanish (español) Spanyol (español) - + Simplified Chinese (简体中文) Egyszerűsített Kínai (简体中文) - + Korean (한국어) Koreai (한국어) - + Dutch (Nederlands) Holland (Nederlands) - + Portuguese (português) Portugál (português) - + Russian (Русский) Russian (Русский) - + Traditional Chinese (正體中文) Hagyományos Kínai (正體中文) - + Sound output mode Hang kimeneteli mód - + Mono Monó - + Stereo Sztereó - + Surround Surround - + Country Ország - + Clock Óra - + System Clock Rendszeróra - + Fixed Time Fix idő - + Startup time - + yyyy-MM-ddTHH:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random Véletlenszerű - + Fixed Fix - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: Konzol ID: - - + + Regenerate Regenerálás - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3569,76 +3621,76 @@ online features (if installed) - - + + Console ID: 0x%1 Konzol ID: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Figyelem - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3753,13 +3805,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Kezelőfelület nyelve: + Interface Language + - Theme: - Téma: + Theme + @@ -3768,8 +3820,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - Ikonméret: + Icon Size + @@ -3789,8 +3841,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - 1. sor szövege: + Row 1 Text + @@ -3824,17 +3876,17 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - 2. sor szövege: + Row 2 Text + - Hide Titles without Icon - Ikon nélküli játékok elrejtése + Hide titles without icon + - Single Line Mode + Single line mode @@ -3844,7 +3896,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3927,12 +3979,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Kapcsolódás - + Connect Kapcsolás @@ -4051,555 +4103,595 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Jelenlegi emulációs sebesség. A 100%-nál nagyobb vagy kisebb értékek azt mutatják, hogy az emuláció egy 3DS-nél gyorsabban vagy lassabban fut. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Mennyi idő szükséges egy 3DS képkocka emulálásához, képkocka-limit vagy V-Syncet leszámítva. Teljes sebességű emulációnál ez maximum 16.67 ms-nek kéne lennie. - + MicroProfile (unavailable) - + Clear Recent Files Legutóbbi fájlok törlése - + &Continue &Folytatás - + &Pause &Szünet - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage - + Before using this CIA, you must install it. Do you want to install it now? - + Quick Load - + Quick Save - - + + Slot %1 Foglalat %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 Foglalat %1 - %2 %3 - + Error Opening %1 Folder Hiba %1 Mappa Megnyitásában - - + + Folder does not exist! A mappa nem létezik! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... Kimentés... - - + + Cancel Mégse - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. - + Error Opening %1 Hiba Indulás %1 - + Select Directory Könyvtár Kiválasztása - + Properties Tulajdonságok - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS állományok (%1);;Minden fájl (*.*) - + Load File Fájl Betöltése - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Fájlok Betöltése - - 3DS Installation File (*.CIA*) - 3DS Telepítési Fájl (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Minden fájl (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1 sikeresen fel lett telepítve. - + Unable to open File A fájl megnyitása sikertelen - + Could not open %1 Nem lehet megnyitni: %1 - + Installation aborted Telepítés megszakítva - + The installation of %1 was aborted. Please see the log for more details %1 telepítése meg lett szakítva. Kérjük olvasd el a naplót több részletért. - + Invalid File Ismeretlen Fájl - + %1 is not a valid CIA %1 nem érvényes CIA - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File A fájl nem található - + Could not find %1 %1 nem található - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... '%1' eltávolítása... - + Failed to uninstall '%1'. '%1' eltávolítása sikertelen. - + Successfully uninstalled '%1'. '%1' sikeresen eltávolítva. - + File not found A fájl nem található - + File "%1" not found Fájl "%1" nem található - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo fájl (%1);; Minden fájl (*.*) - + Load Amiibo Amiibo betöltése - + Unable to open amiibo file "%1" for reading. - + Record Movie Film felvétele - + Movie recording cancelled. Filmfelvétel megszakítva. - - + + Movie Saved Film mentve - - + + The movie is successfully saved. A film sikeresen mentve. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4608,214 +4700,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - FFmpeg könyvtár kiválasztása - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - FFmpeg sikeresen telepítve. - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - Felvétel %1 - - - - Playing %1 / %2 - Lejátszás %1 / %2 - - - - Movie Finished - Film befejezve - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + FFmpeg könyvtár kiválasztása + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + FFmpeg sikeresen telepítve. + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + Felvétel %1 + + + + Playing %1 / %2 + Lejátszás %1 / %2 + + + + Movie Finished + Film befejezve + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Sebesség: %1% - + Speed: %1% / %2% Sebesség: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Képkocka: %1 ms - + VOLUME: MUTE HANGERŐ: NÉMÍTVA - + VOLUME: %1% Volume percentage (e.g. 50%) HANGERŐ: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Egy rendszerarchívum - + System Archive Not Found Rendszerarchívum Nem Található - + System Archive Missing - + Save/load Error Mentési/betöltési hiba - + Fatal Error Kritikus Hiba - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered Végzetes hiba lépett fel - + Continue Folytatás - + Quit Application - + OK OK - + Would you like to exit now? Szeretnél most kilépni? - + The application is still running. Would you like to stop emulation? - + Playback Completed - + Movie playback completed. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window Elsődleges ablak - + Secondary Window Másodlagos ablak @@ -4878,42 +5020,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! OpenGL nem elérhető! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! Hiba történt az OpenGL inicializálásakor! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! Hiba történt az OpenGL 4.3 inicializálásakor! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! Hiba történt az OpenGL ES 3.2 inicializálásakor! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4921,239 +5063,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Kompatibilitás - - + + Region Régió - - + + File type Fájltípus - - + + Size Méret - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open Megnyitás - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS RomFS kimentése - + Disk Shader Cache Lemez árnyékoló-gyorsítótár - + Open Shader Cache Location - + Delete OpenGL Shader Cache OpenGL árnyékoló gyorsítótár törlése - + + Delete Vulkan Shader Cache + + + + Uninstall Eltávolítás - + Everything Minden - + Application - + Update Frissítés - + DLC DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties Tulajdonságok - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) %1 (frissítés) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? Biztosan törölni szeretnéd: '%1'? - + Are you sure you want to uninstall the update for '%1'? Biztosan törölni szeretnéd a(z) '%1' frissítését? - + Are you sure you want to uninstall all DLC for '%1'? Biztosan törölni szeretnéd a(z) '%1' összes DLC-jét? - + Scan Subfolders Almappák szkennelése - + Remove Application Directory - + Move Up Feljebb mozgatás - + Move Down Lejjebb mozgatás - + Open Directory Location - + Clear Törlés - + Name Név @@ -5161,77 +5313,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Tökéletes - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Rendben - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Rossz - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Intro/Menü - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Nem indul - + The app crashes when attempting to startup. - + Not Tested Nem tesztelt - + The app has not yet been tested. @@ -5239,7 +5391,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5247,27 +5399,27 @@ Screen. GameListSearchField - + of - + result eredmény - + results eredmény - + Filter: Szürő: - + Enter pattern to filter Adj meg egy mintát a szűréshez @@ -5275,47 +5427,47 @@ Screen. GameRegion - + Japan - + North America - + Europe - + Australia - + China - + Korea - + Taiwan - + Invalid region Érvénytelen régió - + Region free Régiómentes @@ -5595,87 +5747,87 @@ Screen. Ciklus Index: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Címregisztrációk: %1, %2 - + Compare Result: %1, %2 Eredmény Összehasonlítása: %1, %2 - + Static Condition: %1 Statikus Állapot: %1 - + Dynamic Conditions: %1, %2 Dinamikus Állapotok: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Loop Paraméterek: %1 (ismétlések), %2 (inicializáló), %3 (lépés), %4 - + Instruction offset: 0x%1 Instrukció eltolás: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (utolsó instrukció) @@ -5899,24 +6051,24 @@ Debug Message: Árnyékolók előkészítése %1 / %2 - - Loading Shaders %1 / %2 - Árnyékolók betöltése %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Indítás... - + Now Loading %1 Betöltés %1 - + Estimated Time %1 Hátralévő idő %1 @@ -5975,32 +6127,32 @@ Debug Message: Jelszó: - + Room Name Szoba Neve - + Preferred Application - + Host Gazda - + Players Játékosok - + Refreshing Frissítés - + Refresh List Lista Frissítése @@ -6083,342 +6235,352 @@ Debug Message: Film - + Help - + Load File... Fájl Betöltése... - + Install CIA... CIA Telepítése... - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit - + Pause - + Stop - + Save Mentés - + Load Betöltés - + FAQ - + About Azahar - + Single Window Mode Egyablakos Mód - + Save to Oldest Slot Legrégebbi foglalatba mentés - + Quick Save - + Load from Newest Slot Legfrissebb foglalatból betöltés - + Quick Load - + Configure... Konfiguráció... - + Display Dock Widget Headers Dokk Modul Fejlécek Megjelenítése - + Show Filter Bar Filtersáv Megjelenítése - + Show Status Bar Állapotsáv Megjelenítése - + Create Pica Surface Viewer Pica Felülnézegető Létrehozása - + Record... Felvétel... - + Play... Lejátszás... - + Close Bezárás - + Save without Closing Mentés bezárás nélkül - + Read-Only Mode Csak olvasható mód - + Advance Frame - + Capture Screenshot Képernyőkép készítése - + Dump Video Videó kimentése + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Szoba Létrehozása - + Leave Room Szoba Elhagyása - + Direct Connect to Room Közvetlen Kapcsolódás Szobához - + Show Current Room Jelenlegi Szoba Mutatása - + Fullscreen Teljes Képernyő - + Open Log Folder - + Opens the Azahar Log folder - + Default Alapértelmezett - + Single Screen Egy Képernyő - + Large Screen Nagy Képernyő - + Side by Side Egymás Mellett - + Separate Windows Külön ablakok - + Hybrid Screen Hibrid képernyő - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Képernyők Cseréje - + Rotate Upright Felfelé forgatás - + Report Compatibility Kompatibilitás Jelentése - + Restart Újraindítás - + Load... Betöltés... - + Remove Eltávolítás - + Open Azahar Folder - + Configure Current Application... @@ -6988,32 +7150,32 @@ They may have left the room. %1 (0x%2) - + Unsupported encrypted application - + Invalid region Érvénytelen régió - + Installed Titles Telepített játékok - + System Titles Rendszercímek - + Add New Application Directory - + Favorites diff --git a/dist/languages/id.ts b/dist/languages/id.ts index 55c615d33..c38a574bb 100644 --- a/dist/languages/id.ts +++ b/dist/languages/id.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -292,8 +292,8 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - Emulation: - Emulasi: + Emulation + Emulasi @@ -322,8 +322,8 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Efek pasca-pemrosesan ini dilakukan untuk menyesuaikan kecepatan audio agar sesuai dengan kecepatan emulasi dan mencegah terjadinya audio stutter. Namun proses ini meningkatkan latensi audio. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka + Camera Kamera @@ -408,8 +409,8 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - Camera to configure: - Kamera yang diatur: + Camera to Configure + @@ -429,8 +430,8 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - Camera mode: - Mode kamera: + Camera mode + @@ -450,8 +451,8 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - Camera position: - Posisi kamera: + Camera position + @@ -471,13 +472,13 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Pilih di mana gambar dari kamera yang di emulasi datang berasal. Bisa dari gambar atau kamera asli. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Sumber Gambar Kamera: + Camera Image Source + @@ -496,8 +497,8 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - File: - File: + File + @@ -510,11 +511,6 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka Select the system camera to use Pilih kamera sistem untuk digunakan - - - Camera: - Kamera: - <Default> @@ -528,8 +524,8 @@ Ini akan mem-banned nama pengguna dan alamat IP mereka - Flip: - Balik: + Flip + @@ -1082,7 +1078,7 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Reverse Side by Side + Side by Side Full Width @@ -1141,48 +1137,53 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - + + Swap Eyes + + + + Utility - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures + + Preload custom textures - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading @@ -1195,91 +1196,111 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - General - Umum + Updates + - Confirm exit while emulation is running - Konfirmasi keluar saat emulasi berjalan - - - - Pause emulation when in background - Hentikan emulasi ketika di latar belakang - - - - Mute audio when in background - - - - - Hide mouse on inactivity - Sembunyikan mouse jika tidak ada aktivitas - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Umum + + + + Confirm exit while emulation is running + Konfirmasi keluar saat emulasi berjalan + + + + Pause emulation when in background + Hentikan emulasi ketika di latar belakang + + + + Mute audio when in background + + + + + Hide mouse on inactivity + Sembunyikan mouse jika tidak ada aktivitas + + + + Enable Gamemode + + + + Emulation Emulasi - + Use global emulation speed - - Set emulation speed: + + Set emulation speed - - Emulation Speed: - Kecepatan Emulasi: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots - + Use global screenshot path - + Set screenshot path: - + Save Screenshots To - + ... ... - + Reset All Settings Setel Ulang Semua Pengaturan @@ -1287,8 +1308,8 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - - + + unthrottled tidak dibatasi @@ -1298,12 +1319,12 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1357,12 +1378,12 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1382,8 +1403,8 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Enable Hardware Shader - Gunakan Hardware Shader + Enable hardware shader + @@ -1392,8 +1413,8 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Accurate Multiplication - Penggandaan Akurat + Accurate multiplication + @@ -1402,8 +1423,8 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Enable Shader JIT - Aktifkan Shader JIT + Enable shader JIT + @@ -1412,17 +1433,17 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1462,13 +1483,13 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Use Disk Shader Cache - Gunakan Disk Shader Cache + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync mencegah layar dari "robekan", tetapi beberapa kartu grafis mempunyai performa yang lebih rendah ketika VSync dinyalakan. Biarkan VSync menyala jika kamu tidak merasa adanya perbedaan pada performa. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1476,22 +1497,32 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? Aktifkan VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1976,12 +2007,12 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Swap Screens - Layar Swap + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2098,7 +2129,7 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2270,7 +2301,7 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2446,8 +2477,8 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Use Virtual SD - Gunakan Kartu SD virtual + Use virtual SD card + @@ -2456,7 +2487,7 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? - Use Custom Storage + Use custom storage location @@ -2487,6 +2518,16 @@ Apakah Anda ingin mengabaikan kesalahan dan melanjutkan? SDMC Directory + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2533,7 +2574,7 @@ online features (if installed) - Region: + Region @@ -2542,326 +2583,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Nama User - + Birthday Ulang tahun - + January Januari - + February Februari - + March Maret - + April April - + May Mei - + June Juni - + July Juli - + August Agustus - + September September - + October Oktober - + November November - + December Desember - + Language Bahasa - + Note: this can be overridden when region setting is auto-select Catatan: ini bisa di lewati bila pengaturan region-nya otomatis di pilih - + Japanese (日本語) Jepang (日本語) - + English Inggris - + French (français) Prancis (français) - + German (Deutsch) Jerman (Deutsch) - + Italian (italiano) Itali (italiano) - + Spanish (español) Spanyol (español) - + Simplified Chinese (简体中文) Cina Yang Di Sederhanakan (简体中文) - + Korean (한국어) Korea (한국어) - + Dutch (Nederlands) Belanda (Nederlands) - + Portuguese (português) Portugis (português) - + Russian (Русский) Rusia (Русский) - + Traditional Chinese (正體中文) Cina Tradisional (正體中文) - + Sound output mode Mode output suara - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Negara - + Clock Jam - + System Clock Jam Sistem - + Fixed Time Waktu Tetap - + Startup time Waktu Mulai - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: ID Konsol: - - + + Regenerate Perbaharui - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3571,76 +3623,76 @@ online features (if installed) - - + + Console ID: 0x%1 ID Konsol: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Peringatan - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3755,13 +3807,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Bahasa Antarmuka: + Interface Language + - Theme: - Tema: + Theme + @@ -3770,8 +3822,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - Ukuran Ikon: + Icon Size + @@ -3791,8 +3843,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - Teks Barisan 1: + Row 1 Text + @@ -3826,18 +3878,18 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - Teks Barisan 2: + Row 2 Text + - Hide Titles without Icon - Sembunyikan Judul tanpa Ikon + Hide titles without icon + - Single Line Mode - Mode Satu Baris + Single line mode + @@ -3846,7 +3898,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3929,12 +3981,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Menghubungkan - + Connect Hubungkan @@ -4053,555 +4105,595 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Kecepatan emulasi saat ini. Nilai yang lebih tinggi atau lebih rendah dari 100% menunjukan emulasi berjalan lebih cepat atau lebih lambat dari 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Waktu yang dibutuhkan untuk mengemulasi frame 3DS, tidak menghitung pembatasan frame atau v-sync. setidaknya emulasi yang tergolong kecepatan penuh harus berada setidaknya pada 16.67 ms. - + MicroProfile (unavailable) - + Clear Recent Files Bersihkan Berkas File Terbaru - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage CIA harus di install terlebih dahulu sebelum bisa di gunakan - + Before using this CIA, you must install it. Do you want to install it now? Sebelum memakai CIA ini kau harus memasangnya terlebih dahulu. Apa anda ingin menginstallnya sekarang? - + Quick Load - + Quick Save - - + + Slot %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder Kesalahan Dalam Membuka Folder %1 - - + + Folder does not exist! Folder tidak ada! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... - - + + Cancel Batal - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. - + Error Opening %1 Kesalahan Dalam Membuka %1 - + Select Directory Pilih Direktori - + Properties Properti - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. - + Load File Muat File - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Muat berkas - - 3DS Installation File (*.CIA*) - 3DS Installation File (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Semua File (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1 telah terinstall. - + Unable to open File Tidak dapat membuka File - + Could not open %1 Tidak dapat membuka %1 - + Installation aborted Instalasi dibatalkan - + The installation of %1 was aborted. Please see the log for more details Instalasi %1 dibatalkan. Silahkan lihat file log untuk info lebih lanjut. - + Invalid File File yang tidak valid - + %1 is not a valid CIA %1 bukan CIA yang valid - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... Mencopot Pemasangan '%1'... - + Failed to uninstall '%1'. Gagal untuk mencopot pemasangan '%1%. - + Successfully uninstalled '%1'. - + File not found File tidak ditemukan - + File "%1" not found File "%1" tidak ditemukan - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo Muat Amiibo - + Unable to open amiibo file "%1" for reading. - + Record Movie Rekam Video - + Movie recording cancelled. Perekaman Video Di Batalkan. - - + + Movie Saved Video Di Simpan - - + + The movie is successfully saved. Video telah berhasil di simpan. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4610,214 +4702,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Kecepatan: %1% - + Speed: %1% / %2% Kelajuan: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Frame: %1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Sebuah arsip sistem - + System Archive Not Found Arsip Sistem Tidak Ditemukan - + System Archive Missing Arsip sistem tidak ada - + Save/load Error - + Fatal Error Fatal Error - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered Galat fatal terjadi - + Continue Lanjut - + Quit Application - + OK OK - + Would you like to exit now? Apakah anda ingin keluar sekarang? - + The application is still running. Would you like to stop emulation? - + Playback Completed Pemutaran Kembali Telah Selesai - + Movie playback completed. Pemutaran kembali video telah selesai. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4880,42 +5022,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4923,239 +5065,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility - - + + Region - - + + File type - - + + Size - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open Buka - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties Properti - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders Pindai Subfolder - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location Buka Lokasi Penyimpanan - + Clear Bersihkan - + Name Nama @@ -5163,77 +5315,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Sempurna - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Hebat - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Setuju - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Buruk - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Intro/Menu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Tidak Mau Memulai - + The app crashes when attempting to startup. - + Not Tested Belum Di Uji - + The app has not yet been tested. @@ -5241,7 +5393,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5249,27 +5401,27 @@ Screen. GameListSearchField - + of dari - + result hasil - + results hasil - + Filter: Saringan: - + Enter pattern to filter Masukkan pola untuk menyaring @@ -5277,47 +5429,47 @@ Screen. GameRegion - + Japan Jepang - + North America - + Europe - + Australia Australia - + China China - + Korea - + Taiwan Taiwan - + Invalid region Region Tidak Valid - + Region free @@ -5597,87 +5749,87 @@ Screen. Indeks Siklus: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Register Alamat: %1, %2 - + Compare Result: %1, %2 Bandingkan Hasil: %1, %2 - + Static Condition: %1 Kondisi Statis: %1 - + Dynamic Conditions: %1, %2 Kondisi Dinamis: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Parameter Pengulangan: %1 (pengulangan), %2 (penginisialisasi), %3 (tambahan), %4 - + Instruction offset: 0x%1 Instruksi offset: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (instruksi terakhir) @@ -5901,23 +6053,23 @@ Debug Message: - - Loading Shaders %1 / %2 + + Loading %3 %1 / %2 - + Launching... - + Now Loading %1 - + Estimated Time %1 @@ -5976,32 +6128,32 @@ Debug Message: Kata Sandi: - + Room Name Nama Ruangan - + Preferred Application - + Host Host - + Players Pemain - + Refreshing Menyegarkan - + Refresh List Segarkan Daftar @@ -6084,342 +6236,352 @@ Debug Message: Video - + Help - + Load File... Muat File... - + Install CIA... Pasang CIA... - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit - + Pause - + Stop - + Save Simpan - + Load - + FAQ - + About Azahar - + Single Window Mode Mode Satu Jendela - + Save to Oldest Slot - + Quick Save - + Load from Newest Slot - + Quick Load - + Configure... Konfigurasi... - + Display Dock Widget Headers Tampilkan Dock Widget Headers - + Show Filter Bar Tampilkan Filter Bar - + Show Status Bar Tampilkan Status Bar - + Create Pica Surface Viewer Buat Penampil Permukaan Pica - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame Pemercepat Frame - + Capture Screenshot - + Dump Video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Buat Ruangan - + Leave Room Tinggalkan Ruangan - + Direct Connect to Room Koneksi Langsung ke Ruangan - + Show Current Room Tunjukkan Ruangan Saat Ini - + Fullscreen Layar penuh - + Open Log Folder - + Opens the Azahar Log folder - + Default Default - + Single Screen Layar Tunggal - + Large Screen Layar Besar - + Side by Side Bersebelahan - + Separate Windows - + Hybrid Screen - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Layar Swap - + Rotate Upright - + Report Compatibility Laporkan Kompatibilitas - + Restart Mulai ulang - + Load... - + Remove - + Open Azahar Folder - + Configure Current Application... @@ -6492,7 +6654,7 @@ Debug Message: File: - File: + @@ -6584,7 +6746,7 @@ Debug Message: File: - File: + @@ -6989,32 +7151,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Region Tidak Valid - + Installed Titles - + System Titles - + Add New Application Directory - + Favorites diff --git a/dist/languages/it.ts b/dist/languages/it.ts index 414b8dc3b..0df8a2c12 100644 --- a/dist/languages/it.ts +++ b/dist/languages/it.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,8 +298,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - Emulation: - Emulazione: + Emulation + Emulazione @@ -328,8 +328,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Questo effetto di post-processing permette di far combaciare la velocità dell'emulazione con quella dell'audio per prevenire lo stutter. Questo però aumenta la latenza dell'audio. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + <html><head/><body><p>Questo effetto di post-processing regola la velocità dell’audio per adattarla alla velocità dell’emulazione e aiuta a prevenire le interruzioni dell’audio. Tuttavia aumenta la latenza audio.</p></body></html> @@ -338,8 +338,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Regola la velocità della riproduzione dell'audio per compensare i cali nel framerate dell'emulazione. Questo significa che l'audio verrà riprodotto a velocità normale anche mentre il framerate del gioco è basso. Può causare problemi di desincronizzazione dell'audio. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + <html><head/><body><p>Adatta la velocità di riproduzione dell’audio per compensare i cali del framerate dell’emulazione. Questo significa che l’audio verrà riprodotto a velocità normale anche quando il framerate dell’applicazione è basso. Potrebbe causare problemi di desincronizzazione audio.</p></body></html> @@ -403,6 +403,7 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. + Camera Fotocamera @@ -414,8 +415,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - Camera to configure: - Fotocamera da configurare: + Camera to Configure + Fotocamera da configurare @@ -435,8 +436,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - Camera mode: - Modalità della fotocamera: + Camera mode + Modalità fotocamera @@ -456,8 +457,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - Camera position: - Posizione della fotocamera: + Camera position + Posizione fotocamera @@ -477,13 +478,13 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Seleziona la fonte dell'immagine della fotocamera emulata. Può essere un'immagine o una vera fotocamera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + <html><head/><body><p>Seleziona la sorgente dell’immagine della fotocamera emulata. Può essere un’immagine oppure di una fotocamera reale.</p></body></html> - Camera Image Source: - Fonte dell'immagine della fotocamera: + Camera Image Source + Sorgente fotocamera @@ -502,8 +503,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - File: - File: + File + File @@ -516,11 +517,6 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP.Select the system camera to use Seleziona la fotocamera di sistema da utilizzare - - - Camera: - Fotocamera: - <Default> @@ -534,8 +530,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP. - Flip: - Rotazione: + Flip + Capovolgi @@ -727,7 +723,7 @@ Desideri ignorare l'errore e continuare? Show log output in console - + Mostra l'output del log nella console @@ -737,7 +733,7 @@ Desideri ignorare l'errore e continuare? Flush log output on every message - Pulisci l'output del log ad ogni messaggio + Svuota l'output del log ad ogni messaggio @@ -827,7 +823,7 @@ Desideri ignorare l'errore e continuare? <html><head/><body><p>Enables the RPC server on port 45987. This allows remotely reading/writing guest memory, do not enable if you don't know what you are doing.</p></body></html> - + <html><head/><body><p>Abilita il server RPC sulla porta 45987. Ciò consente di leggere/scrivere da remoto la memoria dell'ospite, non attivarlo se non sai cosa stai facendo.</p></body></html> @@ -1088,8 +1084,8 @@ Desideri ignorare l'errore e continuare? - Reverse Side by Side - Affiancato invertito + Side by Side Full Width + Affiancato a larghezza intera @@ -1147,48 +1143,53 @@ Desideri ignorare l'errore e continuare? <html><head/><body><p>Disabilita il rendering dell'occhio destro</p><p>Disabilita il rendering dell'immagine dell'occhio destro quando la modalità steroscopica non è attiva. Migliora enormemente le prestazioni in alcune applicazioni, ma può causare flickering in altre.</p></body></html> - + + Swap Eyes + Inverti occhi + + + Utility Utilità - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Sostituisci le texture con file PNG.</p><p>Le texture verranno caricate dalla cartella load/textures/[ID titolo]/.</p></body></html> - - Use Custom Textures + + Use custom textures Usa texture personalizzate - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Estrai le texture su file PNG.</p><p>Le texture verranno estratte nella cartella dump/textures/[ID titolo]/.</p></body></html> - - Dump Textures + + Dump textures Estrai texture - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>Carica tutte le texture personalizzate in memoria all'avvio, invece di caricarle quando l'applicazione ne ha bisogno.</p></body></html> - - Preload Custom Textures + + Preload custom textures Precarica texture personalizzate - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Carica le texture personalizzate in maniera asincrona usando dei thread in background per ridurre gli scatti causati dal loro caricamento.</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading Caricamento asincrono delle texture personalizzate @@ -1201,91 +1202,111 @@ Desideri ignorare l'errore e continuare? - General - Generale + Updates + Aggiornamenti - Confirm exit while emulation is running - Conferma uscita con emulazione in corso - - - - Pause emulation when in background - Metti in pausa l'emulazione quando la finestra è in background - - - - Mute audio when in background - Silenzia l'audio quando la finestra è in background - - - - Hide mouse on inactivity - Nascondi il puntatore quando inattivo - - - - Enable Gamemode - Abilita Modalità Gioco - - - Check for updates Controlla gli aggiornamenti - + + Update Channel + Canale di aggiornamento + + + + Stable + Stabile + + + + Prerelease + Anteprima + + + + General + Generale + + + + Confirm exit while emulation is running + Conferma uscita con emulazione in corso + + + + Pause emulation when in background + Metti in pausa l'emulazione quando la finestra è in background + + + + Mute audio when in background + Silenzia l'audio quando la finestra è in background + + + + Hide mouse on inactivity + Nascondi il mouse in caso di inattività + + + + Enable Gamemode + Abilita Modalità Gioco + + + Emulation Emulazione - + Use global emulation speed Usa la velocità di emulazione globale - - Set emulation speed: - Imposta la velocità di emulazione: + + Set emulation speed + Imposta la velocità di emulazione - - Emulation Speed: - Velocità di emulazione: + + Emulation Speed + Velocità di emulazione - + Turbo Speed Limit: Limite della velocità Turbo: - + Screenshots Screenshot - + Use global screenshot path Usa il percorso degli screenshot globale - + Set screenshot path: Imposta il percorso degli screenshot: - + Save Screenshots To Salva gli screenshot in - + ... ... - + Reset All Settings Ripristina tutte le impostazioni @@ -1293,8 +1314,8 @@ Desideri ignorare l'errore e continuare? - - + + unthrottled illimitata @@ -1304,12 +1325,12 @@ Desideri ignorare l'errore e continuare? Seleziona la cartella degli screenshot - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? Sei sicuro di voler <b>reimpostare le impostazioni</b> e chiudere Azahar? @@ -1363,18 +1384,18 @@ Desideri ignorare l'errore e continuare? - SPIR-V Shader Generation + SPIR-V shader generation Generazione shader SPIR-V - Disable GLSL -> SPIR-V Optimizer - + Disable GLSL -> SPIR-V optimizer + Disabilita ottimizzazione GLSL -> SPIR-V <html><head/><body><p>Disables the SPIR-V optimization pass, reducing stuttering considerably while barely affecting performance.</p></body></html> - + <html><head/><body><p>Disabilita il passaggio di ottimizzazione SPIR-V, riducendo considerevolmente gli scatti con un impatto minimo sulle prestazioni.</p></body></html> @@ -1388,7 +1409,7 @@ Desideri ignorare l'errore e continuare? - Enable Hardware Shader + Enable hardware shader Abilita shader hardware @@ -1398,7 +1419,7 @@ Desideri ignorare l'errore e continuare? - Accurate Multiplication + Accurate multiplication Moltiplicazione accurata @@ -1408,7 +1429,7 @@ Desideri ignorare l'errore e continuare? - Enable Shader JIT + Enable shader JIT Abilita shader JIT @@ -1418,17 +1439,17 @@ Desideri ignorare l'errore e continuare? - Enable Async Shader Compilation + Enable async shader compilation Abilita la compilazione asincrona degli shader - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Esegui la presentazione su thread separati. Migliora le prestazioni durante l'uso di Vulkan nella maggior parte delle applicazioni.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + <html><head/><body><p>Esegue la presentazione su thread separati. Migliora le prestazioni nella maggior parte delle applicazioni quando si utilizza Vulkan. Aggiunge ~1 frame di ritardo di input.</p></body></html> - Enable Async Presentation + Enable async presentation Abilita la presentazione asincrona @@ -1468,13 +1489,13 @@ Desideri ignorare l'errore e continuare? - Use Disk Shader Cache + Use disk shader cache Utilizza la cache degli shader su disco - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - Il VSync evita il tearing dello schermo, ma alcune schede video hanno prestazioni peggiori quando il VSync è abilitato. Lascialo abilitato se non noti una differenza nelle prestazioni. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + <html><head/><body><p>Il VSync impedisce il tearing dello schermo, ma alcune schede video hanno prestazioni inferiori con il VSync attivato. Mantienilo attivo se non noti differenze di prestazioni.</p></body></html> @@ -1482,22 +1503,32 @@ Desideri ignorare l'errore e continuare? Abilita VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + <html><head/><body><p>Se abilitata, questa impostazione rileva quando la frequenza di aggiornamento dello schermo è inferiore a quella del 3DS e, quando lo è, disabilita automaticamente VSync per evitare che la velocità di emulazione venga forzata al di sotto del 100%.</p></body></html> + + + + Enable display refresh rate detection + Abilita il rilevamento della frequenza di aggiornamento del display + + + Use global Usa la configurazione globale - + Use per-application Usa la configurazione dell'applicazione - - Delay application render thread: - Ritarda il thread di render dell'applicazione: + + Delay Application Render Thread + Ritarda il thread di render dell'applicazione - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>Ritarda il thread dell'applicazione emulata per il quantitativo specificato di millisecondi ogni volta che invia dei comandi di render alla GPU.</p><p>Configura questa feature nelle (poche) applicazioni con framerate variabile per risolvere problemi di prestazioni.</p></body></html> @@ -1614,7 +1645,7 @@ Desideri ignorare l'errore e continuare? Shoulder Buttons - Pulsanti dorsali + Tasti posteriori @@ -1664,7 +1695,7 @@ Desideri ignorare l'errore e continuare? Directional Pad - Pulsanti direzionali + Tasti direzionali @@ -1982,18 +2013,18 @@ Desideri ignorare l'errore e continuare? - Swap Screens + Swap screens Inverti schermi - Rotate Screens Upright + Rotate screens upright Ruota schermi in verticale Screen Gap - + Spazio tra gli schermi @@ -2104,8 +2135,8 @@ Desideri ignorare l'errore e continuare? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Opacità dello schermo inferiore in % (solo OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + <html><head/><body><p>Opacità dello schermo inferiore %</p></body></html> @@ -2276,8 +2307,8 @@ Desideri ignorare l'errore e continuare? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Scopri di più</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Ulteriori informazioni</span></a> @@ -2452,8 +2483,8 @@ Desideri ignorare l'errore e continuare? - Use Virtual SD - Usa la SD virtuale + Use virtual SD card + Usa la scheda SD virtuale @@ -2462,8 +2493,8 @@ Desideri ignorare l'errore e continuare? - Use Custom Storage - Usa l'archiviazione personalizzata + Use custom storage location + Usa percorso personalizzato @@ -2493,6 +2524,16 @@ Desideri ignorare l'errore e continuare? SDMC Directory Cartella SDMC + + + Compress installed CIA content + Comprimi i contenuti CIA installati + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + <html><head/><body><p>Comprime il contenuto dei file CIA durante l’installazione sulla scheda SD emulata. L’impostazione influisce solo sui contenuti CIA installati mentre è attiva.</p></body></html> + Select NAND Directory @@ -2539,8 +2580,8 @@ online features (if installed) - Region: - Regione: + Region + Regione @@ -2548,326 +2589,337 @@ online features (if installed) Seleziona automaticamente - + + Apply region free patch to +installed applications. + Applica la patch region-free alle applicazioni installate. + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + Corregge la regione delle applicazioni installate per renderle region-free, in modo che vengano sempre visualizzate nel menù Home. + + + Username Nome utente - + Birthday Compleanno - + January Gennaio - + February Febbraio - + March Marzo - + April Aprile - + May Maggio - + June Giugno - + July Luglio - + August Agosto - + September Settembre - + October Ottobre - + November Novembre - + December Dicembre - + Language Lingua - + Note: this can be overridden when region setting is auto-select Nota: questa impostazione può essere sovrascritta quando le impostazioni regionali sono su Selezione automatica - + Japanese (日本語) Giapponese (日本語) - + English English - + French (français) Francese (Français) - + German (Deutsch) Tedesco (Deutsch) - + Italian (italiano) - Italiano (italiano) + Italiano - + Spanish (español) Spagnolo (Español) - + Simplified Chinese (简体中文) Cinese semplificato (简体中文) - + Korean (한국어) Coreano (한국어) - + Dutch (Nederlands) Olandese (Nederlands) - + Portuguese (português) Portoghese (Português) - + Russian (Русский) Russo (Русский) - + Traditional Chinese (正體中文) Cinese tradizionale (正體中文) - + Sound output mode Modalità di output del suono - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country - Nazione + Stato - + Clock Orario - + System Clock Orario del sistema - + Fixed Time Orario fisso - + Startup time Ora di avvio - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time Offset Orario - + days giorni - + HH:mm:ss HH:mm:ss - + Initial System Ticks Tick ​​di sistema iniziali - + Random Casuale - + Fixed - Fissato + Fisso - + Initial System Ticks Override Sovrascrittura dei Tick ​​di sistema iniziali - + Play Coins Monete di gioco - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - <html><head/><body><p>Numero di passi per ogni ora contati dal contapassi. Range da 0 a 65.535.</p></body></html> + <html><head/><body><p>Numero di passi all'ora rilevati dal contapassi. Intervallo da 0 a 65.535.</p></body></html> - + Pedometer Steps per Hour - Passi contapassi per ogni ora + Passi del contapassi all'ora - + Run System Setup when Home Menu is launched - Esegui il Setup del Sistema quando l'Home Menu viene avviato. + Esegui la configurazione del sistema quando il menù Home viene avviato - + Console ID: ID Console: - - + + Regenerate Rigenera - + MAC: MAC: - - 3GX Plugin Loader: - Caricamento plugin 3GX: + + 3GX Plugin Loader + Caricamento dei plugin 3GX - + Enable 3GX plugin loader Abilita il caricamento dei plugin 3GX - + Allow applications to change plugin loader state Permetti alle applicazioni di cambiare lo stato del plugin loader - + Real Console Unique Data Dati univoci della console fisica - + Your real console is linked to Azahar. La tua console fisica è collegata con Azahar. - + Unlink Scollega - + OTP OTP - - - - + + + + Choose Scegli - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. Le impostazioni di sistema sono disponibili solo quando non ci sono applicazioni in esecuzione. @@ -3577,76 +3629,76 @@ online features (if installed) File sed (*.sed);;Tutti i file (*.*) - - + + Console ID: 0x%1 ID console: 0x%1 - - + + MAC: %1 MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? L'attuale ID della console 3DS virtuale verrà sostituito con uno nuovo e non potrà più essere recuperato. Ciò potrebbe avere degli effetti inaspettati in alcune applicazioni. Questo processo potrebbe fallire se usi un salvataggio della configurazione obsoleto. Vuoi continuare? - - - + + + Warning Attenzione - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? Il tuo indirizzo MAC attuale verrà sostituito con uno nuovo. È sconsigliato procedere se hai ottenuto l'indirizzo MAC dalla tua console fisica usando lo strumento di configurazione. Vuoi continuare? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Questa azione scollegherà la tua console reale da Azahar, con le seguenti conseguenze:<br><ul><li>il tuo OTP, SecureInfo e LocalFriendCodeSeed verranno rimossi da Azahar.</li><li>La tua lista amici verrà reimpostata e verrai disconnesso dal tuo account NNID/PNID.</li><li>I file di sistema e i titoli eshop ottenuti tramite Azahar diventeranno inaccessibili finché la stessa console non verrà nuovamente collegata (i dati di salvataggio non andranno persi).</ul><br>Continuare? - + Invalid country for configured region Nazione non valida per la regione configurata - + Invalid country for console unique data Nazione non valida per i dati univoci della console - + Status: Loaded Stato: Caricato - + Status: Loaded (Invalid Signature) Stato: Caricato (firma non valida) - + Status: Loaded (Region Changed) Stato: Caricato (regione modificata) - + Status: Not Found Stato: Non trovato - + Status: Invalid Stato: Non valido - + Status: IO Error Stato: Errore di I/O @@ -3762,13 +3814,13 @@ Trascina i punti per cambiarne la posizione, o fai doppio clic sulla tabella per - Interface language: - Lingua dell'interfaccia: + Interface Language + Lingua dell'interfaccia - Theme: - Tema: + Theme + Tema @@ -3777,8 +3829,8 @@ Trascina i punti per cambiarne la posizione, o fai doppio clic sulla tabella per - Icon Size: - Dimensione dell'icona: + Icon Size + Dimensione icona @@ -3798,8 +3850,8 @@ Trascina i punti per cambiarne la posizione, o fai doppio clic sulla tabella per - Row 1 Text: - Testo riga 1: + Row 1 Text + Testo riga 1 @@ -3833,17 +3885,17 @@ Trascina i punti per cambiarne la posizione, o fai doppio clic sulla tabella per - Row 2 Text: - Testo riga 2: + Row 2 Text + Testo riga 2 - Hide Titles without Icon - Nascondi giochi senza icona + Hide titles without icon + Nascondi titoli senza icona - Single Line Mode + Single line mode Modalità riga singola @@ -3853,8 +3905,8 @@ Trascina i punti per cambiarne la posizione, o fai doppio clic sulla tabella per - Show Advanced Frame Time Info - + Show advanced frame time info + Mostra dettagli avanzati sul frame time @@ -3936,12 +3988,12 @@ Trascina i punti per cambiarne la posizione, o fai doppio clic sulla tabella per DirectConnectWindow - + Connecting Connessione in corso - + Connect Connetti @@ -4061,559 +4113,599 @@ Verifica l'installazione di FFmpeg usata per la compilazione. GMainWindow - + No Suitable Vulkan Devices Detected Impossibile trovare un dispositivo compatibile con Vulkan. - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. L'inizializzazione di Vulkan ha fallito durante il boot. <br/>La tua GPU potrebbe non supportare Vulkan 1.1, oppure non hai i driver più recenti. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. Attuale velocità del traffico di Artic. Valori alti indicano carichi di trasferimento più grandi. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Velocità di emulazione corrente. Valori più alti o più bassi di 100% indicano che l'emulazione sta funzionando più velocemente o lentamente di un 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. Quanti frame al secondo l'app sta attualmente mostrando. Varierà da app ad app e da scena a scena. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tempo necessario per emulare un fotogramma del 3DS, senza tenere conto del limite al framerate o del V-Sync. Per un'emulazione alla massima velocità, il valore non dovrebbe essere superiore a 16.67 ms. - + MicroProfile (unavailable) MicroProfile (Non disponibile) - + Clear Recent Files Elimina file recenti - + &Continue &Continua - + &Pause &Pausa - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar sta eseguendo un'applicazione - - + + Invalid App Format Formato App non valido - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Il formato dell'applicazione non è supportato. <br/>Segui la guida per effettuare il dump delle tue <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>schedine di gioco</a> o dei <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>titoli installati</a>. - + App Corrupted App corrotta - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. L'applicazione è corrotta. <br/>Segui la guida per effettuare il dump delle tue <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>schedine di gioco</a> o dei <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>titoli installati</a>. - + App Encrypted App criptata - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> L'applicazione è criptata. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Consulta il nostro blog per maggiori informazioni.</a> - + Unsupported App App non supportata - + GBA Virtual Console is not supported by Azahar. La GBA Virtual Console non è supportata da Azahar. - - + + Artic Server Artic Server - + + Invalid system mode + Modalità di sistema non valida + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + Le applicazioni esclusive del New 3DS non possono essere caricate senza abilitare la modalità New 3DS. + + + Error while loading App! Errore nel caricamento dell'app! - + An unknown error occurred. Please see the log for more details. Si è verificato un errore sconosciuto. Consulta il log per maggiori dettagli. - + CIA must be installed before usage Il CIA deve essere installato prima dell'uso - + Before using this CIA, you must install it. Do you want to install it now? Devi installare questo CIA prima di poterlo usare. Desideri farlo ora? - + Quick Load Carica salvataggio rapido - + Quick Save Salvataggio rapido - - + + Slot %1 Slot %1 - + %2 %3 %2 %3 - + Quick Save - %1 Salvataggio rapido (%1) - + Quick Load - %1 Carica salvataggio rapido (%1) - + Slot %1 - %2 %3 Slot %1 - %2 %3 - + Error Opening %1 Folder Errore nell'apertura della cartella %1 - - + + Folder does not exist! La cartella non esiste! - + Remove Play Time Data Rimuovi dati sul tempo di gioco - + Reset play time? Reimpostare il tempo di gioco? - - - - + + + + Create Shortcut Crea scorciatoia - + Do you want to launch the application in fullscreen? Vuoi avviare l'applicazione a schermo intero? - + Successfully created a shortcut to %1 Scorciatoia creata con successo in %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Verrà creata una scorciatoia all'attuale AppImage, che potrebbe non funzionare correttamente in caso di aggiornamento. Vuoi continuare? - + Failed to create a shortcut to %1 Impossibile creare scorciatoia in %1 - + Create Icon Crea icona - + Cannot create icon file. Path "%1" does not exist and cannot be created. Impossibile creare file icona. La cartella "%1" non esiste e non può essere creato. - + Dumping... Estrazione in corso... - - + + Cancel Annulla - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. Impossibile estrarre la RomFS base. Consulta il log per i dettagli. - + Error Opening %1 Errore nell'apertura di %1 - + Select Directory Seleziona cartella - + Properties Proprietà - + The application properties could not be loaded. Impossibile caricare le proprietà dell'applicazione. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Eseguibile 3DS (%1);;Tutti i file (*.*) - + Load File Carica file - - + + Set Up System Files Configura i file di sistema - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + <p>Azahar necessita di dati univoci della console e di file firmware da una console reale per poter utilizzare alcune delle sue funzionalità.<br>Tali file e dati possono essere configurati con <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Note:<ul><li><b>questa operazione installerà dati univoci della console su Azahar, non condividere le cartelle utente o nand<br>dopo aver eseguito il processo di configurazione!</b></li><li>Durante il processo di configurazione, Azahar si collegherà alla console che esegue lo strumento di configurazione. È possibile scollegare la console in un secondo momento dalla scheda Sistema nel menu di configurazione dell'emulatore.</li><li>Non andare online con Azahar e con la console 3DS contemporaneamente dopo aver configurato i file di sistema,<br>poiché potrebbe causare problemi.</li><li>La vecchia configurazione 3DS è necessaria affinché la nuova configurazione 3DS funzioni (si consiglia di eseguire entrambe le modalità di configurazione).</li><li>Entrambe le modalità di configurazione funzioneranno indipendentemente dal modello della console che esegue lo strumento di configurazione.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: Inserisci l'indirizzo di Artic Setup Tool: - + <br>Choose setup mode: <br>Scegli la modalità di configurazione: - + (ℹ️) Old 3DS setup - (ℹ️) Old 3DS + (ℹ️) Configurazione Old 3DS - - + + Setup is possible. La configurazione è possibile. - + (⚠) New 3DS setup - (⚠) New 3DS + (⚠) Configurazione New 3DS - + Old 3DS setup is required first. È necessario eseguire prima la configurazione Old 3DS. - + (✅) Old 3DS setup - (✅) Old 3DS + (✅) Configurazione Old 3DS - - + + Setup completed. Configurazione completata. - + (ℹ️) New 3DS setup - (ℹ️) New 3DS + (ℹ️) Configurazione New 3DS - + (✅) New 3DS setup - (✅) New 3DS + (✅) Configurazione New 3DS - + The system files for the selected mode are already set up. Reinstall the files anyway? I file di sistema per la modalità selezionata sono già stati configurati. Vuoi comunque reinstallarli? - + Load Files Carica file - - 3DS Installation File (*.CIA*) - File di installazione 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + File di installazione 3DS (*.cia *.zcia) - + + + All Files (*.*) Tutti i file (*.*) - + Connect to Artic Base Connettiti ad Artic Base - + Enter Artic Base server address: Inserisci l'indirizzo del server Artic Base: - + %1 has been installed successfully. %1 è stato installato con successo. - + Unable to open File Impossibile aprire il file - + Could not open %1 Impossibile aprire %1 - + Installation aborted Installazione annullata - + The installation of %1 was aborted. Please see the log for more details L'installazione di %1 è stata annullata. Visualizza il log per maggiori dettagli. - + Invalid File File non valido - + %1 is not a valid CIA %1 non è un CIA valido - + CIA Encrypted File CIA criptato - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Il file CIA è criptato. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Consulta il nostro blog per maggiori informazioni.</a> - + Unable to find File Impossibile trovare il file - + Could not find %1 Impossibile trovare %1 - + + + + + Z3DS Compression + Compressione Z3DS + + + + Failed to compress some files, check log for details. + Impossibile comprimere alcuni file, controllare il log per i dettagli. + + + + Failed to decompress some files, check log for details. + Impossibile decomprimere alcuni file, controllare il log per i dettagli. + + + + All files have been compressed successfully. + Tutti i file sono stati compressi con successo. + + + + All files have been decompressed successfully. + Tutti i file sono stati decompressi con successo. + + + Uninstalling '%1'... Disinstallazione di "%1" in corso... - + Failed to uninstall '%1'. Errore nella disinstallazione di "%1". - + Successfully uninstalled '%1'. "%1" è stato disinstallato con successo. - + File not found File non trovato - + File "%1" not found File "%1" non trovato - + Savestates Stati salvati - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - Attenzione: Gli stati salvati NON sono un sostituto per i salvataggi in-game, e non sono pensati per essere affidabili. + Attenzione: Gli stati salvati NON sostituiscono i salvataggi in-game, e non sono pensati per essere affidabili. Usali a tuo rischio e pericolo. - - - + + + Error opening amiibo data file Errore durante l'apertura dell'amiibo. - + A tag is already in use. Un tag è già in uso. - + Application is not looking for amiibos. L'applicazione non sta cercando alcun amiibo. - + Amiibo File (%1);; All Files (*.*) File Amiibo (%1);; Tutti i file (*.*) - + Load Amiibo Carica Amiibo - + Unable to open amiibo file "%1" for reading. Impossibile leggere il file amiibo "%1". - + Record Movie Registra filmato - + Movie recording cancelled. Registrazione del filmato annullata. - - + + Movie Saved Filmato salvato - - + + The movie is successfully saved. Il filmato è stato salvato con successo. - + Application will unpause L'applicazione riprenderà - + The application will be unpaused, and the next frame will be captured. Is this okay? L'applicazione riprenderà, e il prossimo frame verrà catturato. Va bene? - + Invalid Screenshot Directory Cartella degli screenshot non valida - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. Non è stato possibile creare la cartella degli screenshot specificata. Il percorso a tale cartella è stato ripristinato al suo valore predefinito. - + Could not load video dumper Impossibile caricare l'estrattore del video - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4626,215 +4718,265 @@ Per installare FFmpeg su Azahar, clicca su Apri e seleziona la cartella di FFmpe Per istruzioni su come installare FFmpeg, clicca su Aiuto. - + + Load 3DS ROM Files + Carica file ROM 3DS + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + File ROM 3DS (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + 3DS Compressed ROM File (*.%1) + File ROM 3DS compresso (*.%1) + + + + Save 3DS Compressed ROM File + Salva file ROM 3DS compresso + + + + Select Output 3DS Compressed ROM Folder + Seleziona la cartella di destinazione delle ROM 3DS compresse + + + + Load 3DS Compressed ROM Files + Carica file ROM 3DS compressi + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + File ROM 3DS compresso (*.zcia *zcci *z3dsx *zcxi) + + + + 3DS ROM File (*.%1) + File ROM 3DS (*.%1) + + + + Save 3DS ROM File + Salva file ROM 3DS + + + + Select Output 3DS ROM Folder + Seleziona la cartella di destinazione delle ROM 3DS + + + Select FFmpeg Directory Seleziona la cartella di installazione di FFmpeg. - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. La cartella di FFmpeg selezionata non contiene %1. Assicurati di aver selezionato la cartella corretta. - + FFmpeg has been sucessfully installed. FFmpeg è stato installato con successo. - + Installation of FFmpeg failed. Check the log file for details. Installazione di FFmpeg fallita. Consulta i file di log per maggiori dettagli. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. Impossibile iniziare il dumping video.<br> Assicurati che l'encoder video sia configurato correttamente. <br>Controlla il log per ulteriori dettagli. - + Recording %1 Registrazione in corso (%1) - + Playing %1 / %2 Riproduzione in corso (%1 / %2) - + Movie Finished Filmato terminato - + (Accessing SharedExtData) (Accessing SharedExtData) - + (Accessing SystemSaveData) (Accessing SystemSaveData) - + (Accessing BossExtData) (Accessing BossExtData) - + (Accessing ExtData) (Accessing ExtData) - + (Accessing SaveData) (Accessing SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 Traffico Artic: %1 %2%3 - + Speed: %1% Velocità: %1% - + Speed: %1% / %2% Velocità: %1% / %2% - + App: %1 FPS App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Frame: %1 ms - + VOLUME: MUTE VOLUME: MUTO - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUME: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - %1 non trovato. <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Estrai i tuoi archivi di sistema</a>.<br/>Proseguendo l'emulazione si potrebbero verificare bug e arresti anomali. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + %1 non trovato. <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Estrai i tuoi archivi di sistema</a>.<br/>Proseguendo l'emulazione si potrebbero verificare arresti anomali e bug. - + A system archive Un archivio di sistema - + System Archive Not Found Archivio di sistema non trovato - + System Archive Missing Archivio di sistema mancante - + Save/load Error Errore di salvataggio/caricamento - + Fatal Error Errore irreversibile - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Si è verificato un errore irreversibile. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Controlla il log</a> per ulteriori dettagli.<br/>Proseguendo l'emulazione si potrebbero verificare bug e arresti anomali. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + Si è verificato un errore fatale. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Controlla il log</a> per i dettagli.<br/>Continuare l'emulazione potrebbe causare arresti anomali e bug. - + Fatal Error encountered Errore irreversibile riscontrato - + Continue Continua - + Quit Application Chiudi applicazione - + OK OK - + Would you like to exit now? Desideri uscire ora? - + The application is still running. Would you like to stop emulation? L'applicazione è ancora in esecuzione. Vuoi arrestare l'emulazione? - + Playback Completed Riproduzione completata - + Movie playback completed. Riproduzione del filmato completata. - + Update Available Aggiornamento disponibile - + Update %1 for Azahar is available. Would you like to download it? L'aggiornamento %1 di Azahar è disponibile. Vuoi installarlo? - + Primary Window Finestra principale - + Secondary Window Finestra secondaria @@ -4897,42 +5039,42 @@ Vuoi installarlo? GRenderWindow - + OpenGL not available! OpenGL non disponibile! - + OpenGL shared contexts are not supported. Gli shared context di OpenGL non sono supportati. - + Error while initializing OpenGL! Errore durante l'inizializzazione di OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. La tua GPU potrebbe non supportare OpenGL, o non hai installato l'ultima versione dei driver video. - + Error while initializing OpenGL 4.3! Errore durante l'inizializzazione di OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 La tua GPU potrebbe non supportare OpenGL 4.3, o non hai installato l'ultima versione dei driver video.<br><br>Renderer GL:<br>%1 - + Error while initializing OpenGL ES 3.2! Errore durante l'inizializzazione di OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 La tua GPU potrebbe non supportare OpenGL ES 3.2, oppure non hai i driver grafici più recenti. <br><br>GL Renderer: <br>%1 @@ -4940,241 +5082,251 @@ Vuoi installarlo? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - IMPORTANTE: I file criptati e i file .3ds non sono più supportati. Potrebbe essere necessario decriptare o rinominare i file usando l'estensione .cci. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Scopri di più.</a> - - - - Don't show again - Non mostrare più - - - - + + Compatibility Compatibilità - - + + Region Regione - - + + File type Tipo di file - - + + Size Dimensione - - + + Play time Tempo di gioco - + Favorite Preferito - + + Eject Cartridge + Rimuovi schedina + + + + Insert Cartridge + Inserisci schedina + + + Open Apri - + Application Location Cartella dell'applicazione - + Save Data Location Cartella dei dati di salvataggio - + Extra Data Location Cartella dei dati aggiuntivi - + Update Data Location Cartella dei dati di aggiornamento - + DLC Data Location Cartella dei dati dei DLC - + Texture Dump Location Cartella di estrazione delle texture - + Custom Texture Location Cartella delle texture personalizzate - + Mods Location Cartella delle mod - + Dump RomFS Estrai la RomFS - + Disk Shader Cache Cache degli shader su disco - + Open Shader Cache Location Apri la cartella della cache degli shader - + Delete OpenGL Shader Cache Elimina la cache degli shader OpenGL - + + Delete Vulkan Shader Cache + + + + Uninstall Disinstalla - + Everything Tutto - + Application Applicazione - + Update Aggiornamento - + DLC DLC - + Remove Play Time Data Rimuovi dati sul tempo di gioco - + Create Shortcut Crea scorciatoia - + Add to Desktop Aggiungi al desktop - + Add to Applications Menu Aggiungi al menù delle applicazioni - + + Stress Test: App Launch + Stress Test: Avvio dell'app + + + Properties Proprietà - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - Sei sicuro di voler disinstallare completamente "%1"? + Sei sicuro di voler disinstallare completamente '%1'? Se installata, l'applicazione verrà rimossa assieme ad eventuali aggiornamenti e DLC installati. - - + + %1 (Update) %1 (Aggiornamento) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? - Sei sicuro di voler disinstallare "%1"? + Sei sicuro di voler disinstallare '%1'? - + Are you sure you want to uninstall the update for '%1'? - Sei sicuro di voler disinstallare l'aggiornamento di "%1"? + Sei sicuro di voler disinstallare l'aggiornamento di '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - Sei sicuro di voler disinstallare tutti i DLC di "%1"? + Sei sicuro di voler disinstallare tutti i DLC di '%1'? - + Scan Subfolders Scansiona le sottocartelle - + Remove Application Directory Rimuovi cartella delle applicazioni - + Move Up Sposta in alto - + Move Down Sposta in basso - + Open Directory Location Apri cartella - + Clear Ripristina - + Name Nome @@ -5182,82 +5334,82 @@ Se installata, l'applicazione verrà rimossa assieme ad eventuali aggiornam GameListItemCompat - + Perfect Perfetto - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. Il gioco funziona perfettamente senza alcun glitch audio o video, tutte le funzionalità testate funzionano come dovrebbero senza la necessità di utilizzare alcun espediente. - + Great Ottimo - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. L'app presenta alcuni glitch audio o video minori ed è possibile giocare dall'inizio alla fine. Potrebbe richiedere l'utilizzo di alcuni espedienti. - + Okay Okay - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. L'app presenta considerevoli glitch audio o video, ma è possibile giocare dall'inizio alla fine utilizzando degli espedienti. - + Bad Scadente - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. L'app funziona, ma presenta glitch audio e video considerevoli. Impossibile progredire in alcune aree a causa di alcuni glitch anche usando espedienti. - + Intro/Menu Intro/Menù - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. L'app è del tutto ingiocabile a causa di considerevoli glitch audio o video. È impossibile proseguire oltre la schermata iniziale. - + Won't Boot Non si avvia - + The app crashes when attempting to startup. L'app va in crash quando viene avviata. - + Not Tested Non testato - + The app has not yet been tested. L'app non è ancora stata testata. @@ -5265,7 +5417,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list Fai doppio clic per aggiungere una nuova cartella alla lista delle applicazioni @@ -5273,27 +5425,27 @@ Screen. GameListSearchField - + of di - + result risultato - + results risultati - + Filter: Filtro: - + Enter pattern to filter Inserisci pattern per filtrare @@ -5301,49 +5453,49 @@ Screen. GameRegion - + Japan Giappone - + North America Nord America - + Europe Europa - + Australia Australia - + China Cina - + Korea Corea - + Taiwan Taiwan - + Invalid region Regione non valida - + Region free - Region free + Region-free @@ -5621,87 +5773,87 @@ Screen. Indice Ciclo: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Registri dell'indirizzo: %1, %2 - + Compare Result: %1, %2 Risultato del confronto: %1, %2 - + Static Condition: %1 Condizione statica: %1 - + Dynamic Conditions: %1, %2 Condizioni dinamiche: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Parametri loop: %1 (ripetute), %2 (inizializzatore), %3 (incremento), %4 - + Instruction offset: 0x%1 Offset istruzione: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (ultima istruzione) @@ -5926,24 +6078,24 @@ Messaggio di debug: Preparazione shader %1 / %2 - - Loading Shaders %1 / %2 - Caricamento shader %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Avvio in corso... - + Now Loading %1 Caricamento %1 - + Estimated Time %1 Tempo stimato %1 @@ -6002,32 +6154,32 @@ Messaggio di debug: Password: - + Room Name Nome stanza - + Preferred Application Applicazioni preferite - + Host Host - + Players Giocatori - + Refreshing Aggiornamento in corso - + Refresh List Aggiorna lista @@ -6110,342 +6262,352 @@ Messaggio di debug: Filmato - + Help Aiuto - + Load File... Carica file... - + Install CIA... Installa CIA... - + Connect to Artic Base... Connessione ad Artic Base... - + Set Up System Files... Configura i file di sistema... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit Esci - + Pause Pausa - + Stop Ferma - + Save Salva - + Load Carica - + FAQ Domande frequenti - + About Azahar Informazioni su Azahar - + Single Window Mode Modalità finestra singola - + Save to Oldest Slot Salva nello slot più vecchio - + Quick Save Salvataggio rapido - + Load from Newest Slot Carica dallo slot più recente - + Quick Load Carica salvataggio rapido - + Configure... Configura... - + Display Dock Widget Headers Visualizza le intestazioni del dock dei widget - + Show Filter Bar Mostra barra del filtro - + Show Status Bar Mostra barra di stato - + Create Pica Surface Viewer Crea visualizzatore superficie Pica - + Record... Registra... - + Play... Riproduci... - + Close Chiudi - + Save without Closing Salva senza chiudere - + Read-Only Mode Modalità in sola lettura - + Advance Frame Avanza fotogramma - + Capture Screenshot Cattura uno screenshot - + Dump Video Cattura video + Compress ROM File... + Comprimi file ROM... + + + + Decompress ROM File... + Decomprimi file ROM... + + + Browse Public Rooms Sfoglia stanze pubbliche - + Create Room Crea stanza - + Leave Room Esci dalla stanza - + Direct Connect to Room Collegamento diretto alla stanza - + Show Current Room Mostra stanza attuale - + Fullscreen Schermo intero - + Open Log Folder Apri la cartella dei log - + Opens the Azahar Log folder Apre la cartella dei log di Azahar - + Default Predefinita - + Single Screen Schermo singolo - + Large Screen Schermo grande - + Side by Side Affiancati - + Separate Windows Finestre separate - + Hybrid Screen Schermo ibrido - + Custom Layout Disposizione personalizzata - + Top Right In alto a destra - + Middle Right In centro a destra - + Bottom Right In basso a destra - + Top Left In alto a sinistra - + Middle Left In centro a sinistra - + Bottom Left In basso a sinistra - + Above Sopra - + Below Sotto - + Swap Screens Inverti schermi - + Rotate Upright Ruota in verticale - + Report Compatibility Segnala compatibilità - + Restart Riavvia - + Load... Carica... - + Remove Rimuovi - + Open Azahar Folder Apri la cartella di Azahar - + Configure Current Application... Configura l'applicazione corrente... @@ -6726,37 +6888,37 @@ Messaggio di debug: Username is already in use or not valid. Please choose another. - Il nome utente è già in uso, oppure non è valido. Scegline un altro. + Il nome utente è già in uso o non è valido. Scegline un altro. IP is not a valid IPv4 address. - Quest'indirizzo IPv4 non è valido. + L'IP non è un indirizzo IPv4 valido. Port must be a number between 0 to 65535. - Il numero della porta dev'essere compreso tra 0 e 65535. + Il numero della porta deve essere compreso tra 0 e 65535. You must choose a Preferred Application to host a room. If you do not have any applications in your Applications list yet, add an applications folder by clicking on the plus icon in the Applications list. - Devi scegliere un'applicazione preferita per poter ospitare una stanza. Se non hai ancora delle applicazioni nella lista delle applicazioni, aggiungi una cartella cliccando sull'icona + nella lista. + Devi scegliere un'applicazione preferita per poter ospitare una stanza. Se non hai ancora delle applicazioni in lista, aggiungi una cartella delle applicazioni cliccando sull'icona + nella lista. Unable to find an internet connection. Check your internet settings. - Impossibile trovare una connessione ad Internet. Ricontrolla le tue impostazioni di rete. + Impossibile trovare una connessione ad Internet. Controlla le tue impostazioni di rete. Unable to connect to the host. Verify that the connection settings are correct. If you still cannot connect, contact the room host and verify that the host is properly configured with the external port forwarded. - Impossibile connettersi all'host. Accertati che le impostazioni di connessione siano corrette. Se ancora non riesci a connetterti, contatta l'host della stanza per verificare che l'host abbia abilitato il forwarding delle porte. + Impossibile connettersi all'host. Assicurati che le impostazioni di connessione siano corrette. Se ancora non riesci a connetterti, contatta l'host della stanza per verificare che abbia abilitato il forwarding delle porte. Unable to connect to the room because it is already full. - La stanza è piena. + Impossibile connettersi: la stanza è piena. @@ -6766,7 +6928,7 @@ Messaggio di debug: The host of the room has banned you. Speak with the host to unban you or try a different room. - L'host della stanza ti ha bannato. Contatta l'host o connettiti ad un altra stanza. + L'host della stanza ti ha bannato. Contatta l'host o prova a connetterti a un altra stanza. @@ -6776,7 +6938,7 @@ Messaggio di debug: Incorrect password. - Password sbagliata + Password errata. @@ -6816,7 +6978,7 @@ Vai in Emulazione > Configura > Sistema per generarne un altro. The user you are trying to kick/ban could not be found. They may have left the room. - L'utente che stai cercando di espellere/bannare non è stato trovato. + L'utente che stai cercando di espellere/bandire non è stato trovato. Potrebbe aver lasciato la stanza. @@ -7019,32 +7181,32 @@ Potrebbe aver lasciato la stanza. %1 (0x%2) - + Unsupported encrypted application Applicazione criptata non supportata - + Invalid region Regione non valida - + Installed Titles Titoli installati - + System Titles Titoli di sistema - + Add New Application Directory Aggiungi una nuova cartella delle applicazioni - + Favorites Preferiti @@ -7347,7 +7509,7 @@ Se vuoi cancellare i file rimasti nella precedente cartella dei dati, puoi farlo free - free + libero @@ -7355,7 +7517,7 @@ Se vuoi cancellare i file rimasti nella precedente cartella dei dati, puoi farlo holding mutexes - holding mutexes + mutex trattenuti @@ -7404,7 +7566,7 @@ Se vuoi cancellare i file rimasti nella precedente cartella dei dati, puoi farlo sleeping - in sleep + in riposo diff --git a/dist/languages/ja_JP.ts b/dist/languages/ja_JP.ts index 218c88784..a1c1b2cc4 100644 --- a/dist/languages/ja_JP.ts +++ b/dist/languages/ja_JP.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + @@ -298,8 +298,8 @@ This would ban both their forum username and their IP address. - Emulation: - エミュレーション + Emulation + エミュレーション @@ -328,8 +328,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - この後処理エフェクトを有効にすると、エミュレーション速度に合わせて音声を伸長し、音声のカクつきを低減させます。ただし、レイテンシが増加します。 + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -338,8 +338,8 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - アプリケーションのフレームレートの低下を考慮して、オーディオの再生速度を調整します。これにより、ゲームのフレームレートが低くてもオーディオは通常の速度で再生されますが、オーディオのズレが発生する可能性があります。 + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + @@ -349,12 +349,12 @@ This would ban both their forum username and their IP address. Use global volume - + グローバル音量を使用します Set volume: - + 音量を設定します: @@ -403,6 +403,7 @@ This would ban both their forum username and their IP address. + Camera カメラ設定 @@ -414,8 +415,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - 設定を行うカメラ + Camera to Configure + @@ -435,8 +436,8 @@ This would ban both their forum username and their IP address. - Camera mode: - カメラモード + Camera mode + @@ -456,8 +457,8 @@ This would ban both their forum username and their IP address. - Camera position: - カメラの位置 + Camera position + @@ -477,13 +478,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - カメラに表示する画像もしくは実際に接続されているカメラを選択 + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - カメラに表示する画像(映像)選択 + Camera Image Source + @@ -502,8 +503,8 @@ This would ban both their forum username and their IP address. - File: - ファイル + File + @@ -516,11 +517,6 @@ This would ban both their forum username and their IP address. Select the system camera to use 使用するシステムカメラを選択 - - - Camera: - カメラ - <Default> @@ -534,8 +530,8 @@ This would ban both their forum username and their IP address. - Flip: - フリップ効果 + Flip + @@ -644,12 +640,12 @@ This would ban both their forum username and their IP address. Notes: - + メモ: Code: - + コード: @@ -671,7 +667,7 @@ This would ban both their forum username and their IP address. Please enter the cheat code. - + チートコードを入力してください. @@ -683,7 +679,7 @@ Would you like to ignore the error and continue? [new cheat] - + [新しいチート] @@ -716,12 +712,12 @@ Would you like to ignore the error and continue? Global Log Filter - Global Log Filter + グローバルログフィルタ Regex Log Filter - + 正規表現ログフィルタ @@ -751,7 +747,7 @@ Would you like to ignore the error and continue? Use global clock speed - + グローバルクロック速度を使用します @@ -973,57 +969,57 @@ Would you like to ignore the error and continue? Native (400x240) - + ネーティブ (400x240) 2x Native (800x480) - + 2x ネーティブ (800x480) 3x Native (1200x720) - + 3x ネーティブ (1200x720) 4x Native (1600x960) - + 4x ネーティブ (1600x960) 5x Native (2000x1200) - + 5x ネーティブ (2000x1200) 6x Native (2400x1440) - + 6x ネーティブ (2400x1440) 7x Native (2800x1680) - + 7x ネーティブ (2800x1680) 8x Native (3200x1920) - + 8x ネーティブ (3200x1920) 9x Native (3600x2160) - + 9x ネーティブ (3600x2160) 10x Native (4000x2400) - + 10x ネーティブ (4000x2400) Enable Linear Filtering - 線形フィルタリングを有効化 + @@ -1078,7 +1074,7 @@ Would you like to ignore the error and continue? Off - + OFF @@ -1087,28 +1083,28 @@ Would you like to ignore the error and continue? - Reverse Side by Side + Side by Side Full Width Anaglyph - + アナグリフ Interlaced - + インターレース Reverse Interlaced - + 逆インターレース Depth - + 深度 @@ -1146,49 +1142,54 @@ Would you like to ignore the error and continue? <html><head/><body><p>右目側の描写を無効にする</p><p>立体視モードでないとき、右目側の画像を描写するのを無効にします。いくつかのアプリケーションで大きくパフォーマンスが向上しますが、ちらつきが起こる可能性があります。</p></body></html> - + + Swap Eyes + + + + Utility ユーティリティ - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>テクスチャをPNGファイルで置き換えます。</p><p>テクスチャは/load/textures/[Title ID]/から読み込まれます。</p></body></html> - - Use Custom Textures - カスタムテクスチャを使用 + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>PNGファイルにテクスチャを出力</p><p>テクスチャは dump/textures/[Title ID]/に出力されます。 - - Dump Textures - テクスチャをダンプ + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>カスタムテクスチャーをアプリケーションが使用するときでなく、起動時にメモリーにすべて読み込みます。</p></body></html> - - Preload Custom Textures - カスタムテクスチャをプリロードする + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>バックグラウンドスレッドと同期してカスタムテクスチャを読み込み、ロード時のカクつきを軽減します。</p></body></html> - - Async Custom Texture Loading - カスタムテクスチャーを非同期的に読み込む + + Async custom texture loading + @@ -1200,91 +1201,111 @@ Would you like to ignore the error and continue? - General - 基本設定 - - - - Confirm exit while emulation is running - エミュレーション停止時に確認 - - - - Pause emulation when in background - バックグラウンドでエミュレーションを一時停止する - - - - Mute audio when in background - バックグラウンド時に音声をミュートする - - - - Hide mouse on inactivity - 非アクティブ時にマウスを非表示にする - - - - Enable Gamemode + Updates - + Check for updates アップデートの確認 - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + 基本設定 + + + + Confirm exit while emulation is running + エミュレーション停止時に確認 + + + + Pause emulation when in background + バックグラウンドでエミュレーションを一時停止する + + + + Mute audio when in background + バックグラウンド時に音声をミュートする + + + + Hide mouse on inactivity + 非アクティブ時にマウスを非表示にする + + + + Enable Gamemode + + + + Emulation エミュレーション - + Use global emulation speed - - Set emulation speed: - エミュレーション速度: - - - - Emulation Speed: - エミュレーション速度 - - - - Turbo Speed Limit: + + Set emulation speed - + + Emulation Speed + + + + + Turbo Speed Limit: + ターボ制限: + + + Screenshots スクリーンショット - + Use global screenshot path - + Set screenshot path: - + Save Screenshots To - + ... ... - + Reset All Settings すべての設定をリセット @@ -1292,8 +1313,8 @@ Would you like to ignore the error and continue? - - + + unthrottled 制限なし @@ -1303,12 +1324,12 @@ Would you like to ignore the error and continue? - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? 本当に<b>設定をリセットして</b>Azaharを閉じますか? @@ -1362,12 +1383,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation - SPIR-V シェーダー生成 + SPIR-V shader generation + - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1387,8 +1408,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - ハードウェアシェーダーを有効化 + Enable hardware shader + @@ -1397,8 +1418,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - Accurate Multiplication + Accurate multiplication + @@ -1407,8 +1428,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - シェーダーJITを有効化 + Enable shader JIT + @@ -1417,17 +1438,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation - 非同期シェーダー処理を有効にする + Enable async shader compilation + - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1467,13 +1488,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache - ディスクシェーダーキャッシュを使う + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSyncはティアリングを防止しますが、グラフィックカードによってはパフォーマンスが低下します。パフォーマンスに影響がないようなら有効にしてください。 + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1481,22 +1502,32 @@ Would you like to ignore the error and continue? Vsync有効化 - - Use global + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> - + + Enable display refresh rate detection + + + + + Use global + グローバルを使用します + + + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1537,7 +1568,7 @@ Would you like to ignore the error and continue? Toggle Turbo Mode - + ターボトグル @@ -1936,12 +1967,12 @@ Would you like to ignore the error and continue? Screens - + 画面 Screen Layout - 画面レイアウト + 画面構成 @@ -1951,12 +1982,12 @@ Would you like to ignore the error and continue? Single Screen - Single Screen + 単一画面 Large Screen - Large Screen + 大画面 @@ -1971,7 +2002,7 @@ Would you like to ignore the error and continue? Hybrid Screen - + ハイブリッド画面 @@ -1981,12 +2012,12 @@ Would you like to ignore the error and continue? - Swap Screens - スクリーンの上下を入れ替える + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -1997,12 +2028,12 @@ Would you like to ignore the error and continue? Large Screen Proportion - + 大画面比率 Small Screen Position - + 小画面の位置 @@ -2017,7 +2048,7 @@ Would you like to ignore the error and continue? Bottom Right (default) - + 右下(デフォルト) @@ -2032,17 +2063,17 @@ Would you like to ignore the error and continue? Bottom Left - + 左下 Above large screen - + 大画面の上 Below large screen - + 大画面の下 @@ -2053,7 +2084,7 @@ Would you like to ignore the error and continue? Top Screen - + 上画面 @@ -2099,17 +2130,17 @@ Would you like to ignore the error and continue? Bottom Screen - + 下画面 - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>下スクリーンの透明度(OpenGLのみ)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + Single Screen Layout - + 単一画面構成 @@ -2275,8 +2306,8 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">詳しく知る...</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + @@ -2451,8 +2482,8 @@ Would you like to ignore the error and continue? - Use Virtual SD - 仮想SDを使う + Use virtual SD card + @@ -2461,7 +2492,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location @@ -2492,6 +2523,16 @@ Would you like to ignore the error and continue? SDMC Directory SDMCディレクトリ + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2538,8 +2579,8 @@ online features (if installed) - Region: - + Region + 地域 @@ -2547,326 +2588,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username ユーザーネーム - + Birthday 誕生日 - + January 1月 - + February 2月 - + March 3月 - + April 4月 - + May 5月 - + June 6月 - + July 7月 - + August 8月 - + September 9月 - + October 10月 - + November 11月 - + December 12月 - + Language 言語 - + Note: this can be overridden when region setting is auto-select 注:地域設定が自動選択の場合、この設定は無視されます。 - + Japanese (日本語) 日本語 (Japanese) - + English 英語 (English) - + French (français) フランス語 (Français) - + German (Deutsch) ドイツ語 (Deutsch) - + Italian (italiano) イタリア語 (Italiano) - + Spanish (español) スペイン語 (Español) - + Simplified Chinese (简体中文) 簡体字中国語 (简体中文) - + Korean (한국어) 韓国語 (한국어) - + Dutch (Nederlands) オランダ語 (Nederlands) - + Portuguese (português) ポルトガル語 (Português) - + Russian (Русский) ロシア語 (Русский) - + Traditional Chinese (正體中文) 繁体字中国語 (正體中文) - + Sound output mode サウンド - + Mono モノラル - + Stereo ステレオ - + Surround サラウンド - + Country - + Clock 時刻 - + System Clock システムの時刻を使用 - + Fixed Time 固定 - + Startup time 起動時の時刻 - + yyyy-MM-ddTHH:mm:ss yyyy-MM-dd THH:mm:ss - + Offset time - + days - + HH:mm:ss 時時:分分:秒秒 - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>1時間あたりに歩数計が記録する歩数。0-65535の間で指定してください。</p></body></html> - + Pedometer Steps per Hour 1時間当たりの歩数計の歩数 - + Run System Setup when Home Menu is launched ホームメニューの起動時に初回セットアップを実行する - + Console ID: コンソールID: - - + + Regenerate コンソールの再作成 - + MAC: - - 3GX Plugin Loader: - 3GXプラグインローダー: + + 3GX Plugin Loader + - + Enable 3GX plugin loader 3GXプラグインローダーを有効にする - + Allow applications to change plugin loader state - + Real Console Unique Data 本体に固有のデータ - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. @@ -3576,76 +3628,76 @@ online features (if installed) - - + + Console ID: 0x%1 コンソール ID: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning 警告 - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3761,13 +3813,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - UIの言語 + Interface Language + - Theme: - テーマ + Theme + @@ -3776,8 +3828,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - アイコンサイズ + Icon Size + @@ -3797,8 +3849,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - 1行目の表示項目 + Row 1 Text + @@ -3832,18 +3884,18 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - 2行目の表示項目 + Row 2 Text + - Hide Titles without Icon - アイコンのないタイトルを非表示 + Hide titles without icon + - Single Line Mode - シングルラインモード + Single line mode + @@ -3852,7 +3904,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3935,12 +3987,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting 接続中... - + Connect 接続 @@ -4059,556 +4111,596 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. 現在のエミュレーション速度です。100%以外の値は、エミュレーションが3DS実機より高速または低速で行われていることを表します。 - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 3DSフレームをエミュレートするのにかかった時間です。フレームリミットや垂直同期の有効時にはカウントしません。フルスピードで動作させるには16.67ms以下に保つ必要があります。 - + MicroProfile (unavailable) - + Clear Recent Files 最近のファイルを消去 - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> このアプリは暗号化されています。<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>ブログで詳細な情報を確認してください。</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. GBAバーチャルコンソールはAzaharではサポートされていません。 - - + + Artic Server Artic Base - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. 不明なエラーが発生しました. 詳細はログを参照してください. - + CIA must be installed before usage CIAを使用前にインストールする必要有 - + Before using this CIA, you must install it. Do you want to install it now? CIAを使用するには先にインストールを行う必要があります。今すぐインストールしますか? - + Quick Load - + Quick Save - - + + Slot %1 スロット %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder フォルダ %1 を開く際のエラー - - + + Folder does not exist! フォルダが見つかりません! - + Remove Play Time Data プレイ時間のデータを削除 - + Reset play time? プレイ時間をリセットしますか? - - - - + + + + Create Shortcut ショートカットを作成する - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 %1にショートカットを作成しました。 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... ダンプ中... - - + + Cancel キャンセル - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. ベースRomFSをダンプできませんでした。 詳細はログを参照してください。 - + Error Opening %1 %1 を開く際のエラー - + Select Directory 3DSのROMがあるフォルダを選択 - + Properties プロパティ - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS実行ファイル (%1);;すべてのファイル (*.*) - + Load File ゲームファイルの読み込み - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files ファイルの読み込み - - 3DS Installation File (*.CIA*) - 3DS インストールファイル (.CIA *) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) すべてのファイル (*.*) - + Connect to Artic Base Arctic Baseに接続 - + Enter Artic Base server address: - + %1 has been installed successfully. %1が正常にインストールされました - + Unable to open File ファイルを開けません - + Could not open %1 %1を開くことができませんでした - + Installation aborted インストール中止 - + The installation of %1 was aborted. Please see the log for more details %1のインストールは中断されました。詳細はログを参照してください - + Invalid File 無効なファイル - + %1 is not a valid CIA %1は有効なCIAではありません - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File ファイルが見つかりません - + Could not find %1 %1を見つけられませんでした - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... '%1'をアンインストールしています - + Failed to uninstall '%1'. '%1' をアンインストールできませんでした - + Successfully uninstalled '%1'. - + File not found ファイルなし - + File "%1" not found ファイル%1が見つかりませんでした - + Savestates ステートセーブ - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Amiiboファイル (%1);; すべてのファイル (*.*) - + Load Amiibo Amiiboを読込 - + Unable to open amiibo file "%1" for reading. - + Record Movie 操作を記録 - + Movie recording cancelled. 操作の記録がキャンセルされました - - + + Movie Saved 保存成功 - - + + The movie is successfully saved. 操作記録を保存しました - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4617,214 +4709,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% スピード:%1% - + Speed: %1% / %2% スピード:%1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms フレーム:%1 ms - + VOLUME: MUTE - + 音量: ミュート - + VOLUME: %1% Volume percentage (e.g. 50%) + 音量: %1% + + + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - %1 が見つかりません。<a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>システムアーカイブをダンプしてください<br/>。このままエミュレーションを続行すると、クラッシュやバグが発生する可能性があります。 - - - + A system archive システムアーカイブ - + System Archive Not Found システムアーカイブなし - + System Archive Missing システムアーカイブが見つかりません - + Save/load Error セーブ/ロード エラー - + Fatal Error 致命的なエラー - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - 致命的なエラーが発生しました。 詳細は<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>ログを確認</a>してください。<br/>エミュレーションを継続するとクラッシュやバグが発生するかもしれません。 + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + - + Fatal Error encountered 致命的なエラーが発生しました - + Continue 続行 - + Quit Application - + OK OK - + Would you like to exit now? 今すぐ終了しますか? - + The application is still running. Would you like to stop emulation? - + Playback Completed 再生完了 - + Movie playback completed. 操作記録の再生が完了しました - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4887,42 +5029,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! OpenGLを初期化中にエラーが発生しました! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. あなたのGPUはOpenGLをサポートしていないか、あなたのGPUドライバーが古い可能性があります。 - + Error while initializing OpenGL 4.3! OpenGL 4.3を初期化中にエラーが発生しました! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 あなたのGPUはOpenGL 4.3をサポートしていないか、あなたのGPUドライバーが古い可能性があります。<br><br>GLレンダラー:<br>%1 - + Error while initializing OpenGL ES 3.2! OpenGL ES 3.2を初期化中にエラーが発生しました! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 あなたのGPUはOpenGL ES 3.2をサポートしていないか、あなたのGPUドライバーが古い可能性があります。<br><br>GLレンダラー:<br>%1 @@ -4930,239 +5072,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility 動作状況 - - + + Region 地域 - - + + File type ファイルの種類 - - + + Size サイズ - - + + Play time プレイ時間 - + Favorite お気に入り - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open 開く - + Application Location アプリケーションの場所 - + Save Data Location セーブデータの場所 - + Extra Data Location 追加データの場所 - + Update Data Location アップデートデータの場所 - + DLC Data Location DLCデータの場所 - + Texture Dump Location テクスチャのダンプ場所 - + Custom Texture Location カスタムテクスチャの場所 - + Mods Location モッドの場所 - + Dump RomFS RomFSをダンプ - + Disk Shader Cache ディスクシェーダーキャッシュ - + Open Shader Cache Location シェーダーキャッシュの場所を開く - + Delete OpenGL Shader Cache OpenGLシェーダーキャッシュを削除 - + + Delete Vulkan Shader Cache + + + + Uninstall アンインストール - + Everything すべて - + Application - + Update アップデート - + DLC DLC - + Remove Play Time Data プレイ時間のデータを削除 - + Create Shortcut ショートカットを作成する - + Add to Desktop デスクトップ - + Add to Applications Menu スタートメニューに追加 - + + Stress Test: App Launch + + + + Properties プロパティ - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? '%1'をアンインストールしますか? - + Are you sure you want to uninstall the update for '%1'? '%1'のアップデートをアンインストールしますか? - + Are you sure you want to uninstall all DLC for '%1'? '%1'のすべてのDLCを削除しますか? - + Scan Subfolders サブフォルダも検索 - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location フォルダの場所を開く - + Clear クリア - + Name タイトル @@ -5170,77 +5322,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect カンペキ - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great サクサク - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay ソコソコ - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad ガタガタ - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu イントロ - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot ダメダメ - + The app crashes when attempting to startup. - + Not Tested 未検証 - + The app has not yet been tested. @@ -5248,7 +5400,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5256,27 +5408,27 @@ Screen. GameListSearchField - + of 件ヒットしました - + result 件中 - + results 件中 - + Filter: タイトル名でフィルタ - + Enter pattern to filter ゲームタイトルを入力 @@ -5284,47 +5436,47 @@ Screen. GameRegion - + Japan 日本 - + North America North America - + Europe Europe - + Australia Australia - + China China - + Korea Korea - + Taiwan Taiwan - + Invalid region 無効な地域 - + Region free リージョンフリー @@ -5604,87 +5756,87 @@ Screen. Cycle Index: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Address Registers: %1, %2 - + Compare Result: %1, %2 Compare Result: %1, %2 - + Static Condition: %1 Static Condition: %1 - + Dynamic Conditions: %1, %2 Dynamic Conditions: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 - + Instruction offset: 0x%1 Instruction offset: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (last instruction) @@ -5908,24 +6060,24 @@ Debug Message: シェーダーを準備中 %1 / %2 - - Loading Shaders %1 / %2 - シェーダーをロード中 %1 / %2 + + Loading %3 %1 / %2 + - + Launching... 起動中... - + Now Loading %1 ロード中 %1 - + Estimated Time %1 予想時間 %1 @@ -5984,32 +6136,32 @@ Debug Message: パスワードを入力 - + Room Name ルーム名 - + Preferred Application - + Host ホスト - + Players プレイヤー - + Refreshing 更新 - + Refresh List リスト更新 @@ -6074,7 +6226,7 @@ Debug Message: Small Screen Position - + 小画面の位置 @@ -6092,342 +6244,352 @@ Debug Message: 操作の記録 - + Help - + Load File... ファイルを開く... - + Install CIA... CIAをインストール... - + Connect to Artic Base... Arctic Baseに接続 - + Set Up System Files... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit - + Pause - + Stop - + Save セーブ - + Load ロード - + FAQ FAQ - + About Azahar Azaharについて - + Single Window Mode シングルウィンドウモード - + Save to Oldest Slot 一番古いスロットにセーブ - + Quick Save - + Load from Newest Slot 一番新しいスロットからロード - + Quick Load - + Configure... 設定 - + Display Dock Widget Headers Dock Widget ヘッダを表示 - + Show Filter Bar フィルタバーを表示 - + Show Status Bar ステータスバーを表示 - + Create Pica Surface Viewer Create Pica Surface Viewer - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame Advance Frame - + Capture Screenshot スクリーンショット実行 - + Dump Video ビデオをダンプ + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room 新しくルームを作成 - + Leave Room 退室 - + Direct Connect to Room 指定ルームへ直接接続 - + Show Current Room 現在のルームを表示 - + Fullscreen フルスクリーンで表示 - + Open Log Folder - + Opens the Azahar Log folder - + Default デフォルト - + Single Screen Single Screen - + Large Screen - Large Screen + 大画面 - + Side by Side Side by Side - + Separate Windows ウインドウを分ける - + Hybrid Screen - + ハイブリッド画面 - + Custom Layout - + Top Right 右上 - + Middle Right - + Bottom Right 右下 - + Top Left 左上 - + Middle Left - + Bottom Left - + 左下 - + Above - + Below - + Swap Screens スクリーンの上下を入れ替える - + Rotate Upright 回転する - + Report Compatibility 動作状況を報告 - + Restart 再起動 - + Load... 読込... - + Remove 削除 - + Open Azahar Folder - + Configure Current Application... @@ -6500,7 +6662,7 @@ Debug Message: File: - ファイル + @@ -6592,7 +6754,7 @@ Debug Message: File: - ファイル + @@ -7000,32 +7162,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region 無効な地域 - + Installed Titles インストールされたタイトル - + System Titles システムタイトル - + Add New Application Directory - + Favorites diff --git a/dist/languages/ko_KR.ts b/dist/languages/ko_KR.ts index 647f49a19..fa53ac869 100644 --- a/dist/languages/ko_KR.ts +++ b/dist/languages/ko_KR.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -292,8 +292,8 @@ This would ban both their forum username and their IP address. - Emulation: - 에뮬레이션: + Emulation + 에뮬레이션 @@ -322,8 +322,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - 이 후처리 효과는 오디오 속도를 에뮬레이션 속도와 일치시키고 오디오 떨림을 방지하는 데 도움이 됩니다. 하지만 이렇게 되면 오디오 지연 시간이 늘어납니다. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ This would ban both their forum username and their IP address. + Camera 카메라 @@ -408,8 +409,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - 설정할 카메라: + Camera to Configure + @@ -429,8 +430,8 @@ This would ban both their forum username and their IP address. - Camera mode: - 카메라모드: + Camera mode + @@ -450,8 +451,8 @@ This would ban both their forum username and their IP address. - Camera position: - 카메라 위치: + Camera position + @@ -471,13 +472,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - 에뮬레이션되는 카메라의 이미지를 가져올 위치를 선택하십시오. 이미지 또는 실제 카메라일 수 있습니다. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - 카메라 이미지 소스: + Camera Image Source + @@ -496,8 +497,8 @@ This would ban both their forum username and their IP address. - File: - 파일: + File + @@ -510,11 +511,6 @@ This would ban both their forum username and their IP address. Select the system camera to use 사용할 시스템 카메라 선택하기 - - - Camera: - 카메라: - <Default> @@ -528,8 +524,8 @@ This would ban both their forum username and their IP address. - Flip: - 뒤집기: + Flip + @@ -1018,7 +1014,7 @@ Would you like to ignore the error and continue? Enable Linear Filtering - 리니어 필터링 활성화 + @@ -1082,7 +1078,7 @@ Would you like to ignore the error and continue? - Reverse Side by Side + Side by Side Full Width @@ -1141,49 +1137,54 @@ Would you like to ignore the error and continue? - + + Swap Eyes + + + + Utility 도구 - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>텍스처를 PNG 파일로 교체합니다.</p><p>텍스처는 load/textures/[Title ID]/에서 로드됩니다.</p></body></html> - - Use Custom Textures - 사용자 정의 텍스처 사용 + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>텍스처를 PNG 파일로 덤프합니다.</p><p>텍스처를 dump/textures/[Title ID]/에 덤프합니다.</p></body></html> - - Dump Textures - 텍스처 덤프 + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures - 사용자 지정 텍스처 미리 불러오기 + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>로딩 끊김을 줄이기 위해 배경 스레드와 비동기식으로 사용자 지정 텍스처를 로드합니다.</p></body></html> - - Async Custom Texture Loading - 비동기 커스텀 텍스처 로딩 + + Async custom texture loading + @@ -1195,91 +1196,111 @@ Would you like to ignore the error and continue? - General - 일반 + Updates + - Confirm exit while emulation is running - 에뮬레이션이 실행중일때 종료 확인 - - - - Pause emulation when in background - 백그라운드에 있을때 에뮬레이션 일시중지 - - - - Mute audio when in background - - - - - Hide mouse on inactivity - 비활성화시 마우스 숨기기 - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + 일반 + + + + Confirm exit while emulation is running + 에뮬레이션이 실행중일때 종료 확인 + + + + Pause emulation when in background + 백그라운드에 있을때 에뮬레이션 일시중지 + + + + Mute audio when in background + + + + + Hide mouse on inactivity + 비활성화시 마우스 숨기기 + + + + Enable Gamemode + + + + Emulation 에뮬레이션 - + Use global emulation speed 전역 에뮬레이션 속도 사용하기 - - Set emulation speed: - 에뮬레이션 속도 설정: + + Set emulation speed + - - Emulation Speed: - 에뮬레이션 속도: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots 스크린숏 - + Use global screenshot path 전역 스크린숏 경로 사용하기 - + Set screenshot path: 스크린숏 경로 설정: - + Save Screenshots To 스크린숏 저장 위치 - + ... ... - + Reset All Settings 모든 설정 초기화 @@ -1287,8 +1308,8 @@ Would you like to ignore the error and continue? - - + + unthrottled 제한없음 @@ -1298,12 +1319,12 @@ Would you like to ignore the error and continue? 스크린숏 디렉터리 선택하기 - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1357,12 +1378,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1382,8 +1403,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - 하드웨어 셰이더 활성화 + Enable hardware shader + @@ -1392,8 +1413,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - 정확한 곱셈연산 + Accurate multiplication + @@ -1402,8 +1423,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - 셰이더 JIT 활성화 + Enable shader JIT + @@ -1412,17 +1433,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1462,13 +1483,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache - 디스크 셰이더 캐시 사용 + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync는 티어링을 방지하지만 일부 그래픽 카드는 VSync를 활성화하면 성능이 저하됩니다. 성능 차이가 눈에 띄지 않으면 활성화하십시오. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1476,22 +1497,32 @@ Would you like to ignore the error and continue? VSync 활성화 - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1976,12 +2007,12 @@ Would you like to ignore the error and continue? - Swap Screens - 화면 바꾸기 + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2098,7 +2129,7 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2270,7 +2301,7 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2446,8 +2477,8 @@ Would you like to ignore the error and continue? - Use Virtual SD - Virtual SD 사용 + Use virtual SD card + @@ -2456,8 +2487,8 @@ Would you like to ignore the error and continue? - Use Custom Storage - 사용자 정의 저장공간 사용 + Use custom storage location + @@ -2487,6 +2518,16 @@ Would you like to ignore the error and continue? SDMC Directory SDMC 디렉터리 + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2533,8 +2574,8 @@ online features (if installed) - Region: - + Region + 지역 @@ -2542,326 +2583,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username 사용자 이름 - + Birthday 생일 - + January 1월 - + February 2월 - + March 3월 - + April 4월 - + May 5월 - + June 6월 - + July 7월 - + August 8월 - + September 9월 - + October 10월 - + November 11월 - + December 12월 - + Language 언어 - + Note: this can be overridden when region setting is auto-select Note: 이 설정은 언어설정이 자동일경우 무시될수 있습니다 - + Japanese (日本語) 일본어 (日本語) - + English 영어 (English) - + French (français) 프랑스어 (français) - + German (Deutsch) 독일어 (Deutsch) - + Italian (italiano) 이탈리아어 (italiano) - + Spanish (español) 스페인어 (español) - + Simplified Chinese (简体中文) 간체 (简体中文) - + Korean (한국어) 한국어 - + Dutch (Nederlands) 네덜란드어 (Nederlands) - + Portuguese (português) 포르투갈어 (português) - + Russian (Русский) 러시아어 (Русский) - + Traditional Chinese (正體中文) 번체 (正體中文) - + Sound output mode 사운드 출력모드 - + Mono 모노 - + Stereo 스테레오 - + Surround 서라운드 - + Country 국가 - + Clock 시계 - + System Clock 시스템 시계 - + Fixed Time 수정된 시간 - + Startup time 시작 시간 - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time 오프셋 시간 - + days - + HH:mm:ss HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched 홈 메뉴가 실행되면 시스템 설정 실행 - + Console ID: 콘솔 ID: - - + + Regenerate 재생성 - + MAC: - - 3GX Plugin Loader: - 3GX 플러그인 로더: + + 3GX Plugin Loader + - + Enable 3GX plugin loader 3GX 플러그인 로더 활성화 - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3571,76 +3623,76 @@ online features (if installed) - - + + Console ID: 0x%1 콘솔 ID: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning 경고 - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3756,13 +3808,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - 인터페이스 언어: + Interface Language + - Theme: - 테마: + Theme + @@ -3771,8 +3823,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - 아이콘 사이즈: + Icon Size + @@ -3792,8 +3844,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - 첫째행 텍스트: + Row 1 Text + @@ -3827,18 +3879,18 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - 둘째행 텍스트: + Row 2 Text + - Hide Titles without Icon - 아이콘이 없는 제목 숨기기 + Hide titles without icon + - Single Line Mode - 한 줄 모드 + Single line mode + @@ -3847,7 +3899,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3930,12 +3982,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting 연결하는 중 - + Connect 연결하기 @@ -4055,556 +4107,596 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. 현재 에뮬레이션 속도. 100%보다 높거나 낮은 값은 에뮬레이션이 3DS보다 빠르거나 느린 것을 나타냅니다. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 3DS 프레임을 에뮬레이션 하는 데 걸린 시간, 프레임제한 또는 v-동기화를 카운트하지 않음. 최대 속도 에뮬레이션의 경우, 이는 최대 16.67 ms여야 합니다. - + MicroProfile (unavailable) - + Clear Recent Files 최근 파일 삭제 - + &Continue 계속(&C) - + &Pause 일시중지(&P) - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. 알 수 없는 오류가 발생했습니다. 자세한 내용은 로그를 참조하십시오. - + CIA must be installed before usage CIA를 사용하기 전에 설치되어야 합니다 - + Before using this CIA, you must install it. Do you want to install it now? 이 CIA를 사용하기 전에 설치해야합니다. 지금 설치 하시겠습니까? - + Quick Load - + Quick Save - - + + Slot %1 슬롯 %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 슬롯 %1 - %2 %3 - + Error Opening %1 Folder %1 폴더 열기 오류 - - + + Folder does not exist! 폴더가 존재하지 않습니다! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... 덤프중... - - + + Cancel 취소 - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. 베이스 RomFS를 덤프 할 수 없습니다. 자세한 내용은 로그를 참조하십시오. - + Error Opening %1 %1 열기 오류 - + Select Directory 디렉터리 선택하기 - + Properties 속성 - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS 실행파일 (%1);;모든파일 (*.*) - + Load File 파일 불러오기 - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files 파일 불러오기 - - 3DS Installation File (*.CIA*) - 3DS 설치 파일 (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) 모든파일 (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1가 성공적으로 설치되었습니다. - + Unable to open File 파일을 열 수 없음 - + Could not open %1 %1을(를) 열 수 없음 - + Installation aborted 설치 중단됨 - + The installation of %1 was aborted. Please see the log for more details %1의 설치가 중단되었습니다. 자세한 내용은 로그를 참조하십시오. - + Invalid File 올바르지 않은 파일 - + %1 is not a valid CIA %1은 올바른 CIA가 아닙니다 - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File 파일을 찾을 수 없음 - + Could not find %1 1을(를) 찾을 수 없습니다 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. - + File not found 파일을 찾을 수 없음 - + File "%1" not found "%1" 파일을 찾을 수 없음 - + Savestates 상태저장(Savestates) - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file Amiibo 데이터 파일 열기 오류 - + A tag is already in use. 태그가 이미 사용중입니다. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo 파일 (%1);; 모든파일 (*.*) - + Load Amiibo Amiibo 불러오기 - + Unable to open amiibo file "%1" for reading. Amiibo 파일 "%1"을 읽을 수 없습니다. - + Record Movie 무비 녹화 - + Movie recording cancelled. 무비 레코딩이 취소되었습니다. - - + + Movie Saved 무비 저장됨 - - + + The movie is successfully saved. 무비가 성공적으로 저장되었습니다 - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory 올바르지 않은 스크린숏 디렉터리 - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. 지정된 스크린숏 디렉터리를 생성할 수 없습니다. 스크린숏 경로가 기본값으로 다시 설정됩니다. - + Could not load video dumper 비디오 덤퍼를 불러올 수 없습니다 - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4613,214 +4705,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - FFmpeg 디렉토리 선택 - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - 제공된 FFmpeg 디렉토리에 %1이 없습니다. 올바른 디렉토리가 선택되었는지 확인하십시오. - - - - FFmpeg has been sucessfully installed. - FFmpeg가 성공적으로 설치되었습니다. - - - - Installation of FFmpeg failed. Check the log file for details. - FFmpeg 설치에 실패했습니다. 자세한 내용은 로그 파일을 확인하십시오. - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - %1 녹화 중 - - - - Playing %1 / %2 - %1 / %2 재생 중 - - - - Movie Finished - 무비 완료됨 - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + FFmpeg 디렉토리 선택 + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + 제공된 FFmpeg 디렉토리에 %1이 없습니다. 올바른 디렉토리가 선택되었는지 확인하십시오. + + + + FFmpeg has been sucessfully installed. + FFmpeg가 성공적으로 설치되었습니다. + + + + Installation of FFmpeg failed. Check the log file for details. + FFmpeg 설치에 실패했습니다. 자세한 내용은 로그 파일을 확인하십시오. + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + %1 녹화 중 + + + + Playing %1 / %2 + %1 / %2 재생 중 + + + + Movie Finished + 무비 완료됨 + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% 속도: %1% - + Speed: %1% / %2% 속도: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms 프레임: %1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive 시스템 아카이브 - + System Archive Not Found 시스템 아카이브를 찾을수 없습니다 - + System Archive Missing 시스템 아카이브가 없습니다 - + Save/load Error 저장하기/불러오기 오류 - + Fatal Error 치명적인 오류 - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered 치명적인 오류가 발생했습니다 - + Continue 계속 - + Quit Application - + OK 확인 - + Would you like to exit now? 지금 종료하시겠습니까? - + The application is still running. Would you like to stop emulation? - + Playback Completed 재생 완료 - + Movie playback completed. 무비 재생 완료 - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window 첫번째 윈도우 - + Secondary Window 두번째 윈도우 @@ -4883,42 +5025,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! OpenGL을 사용할 수 없습니다! - + OpenGL shared contexts are not supported. OpenGL 공유 컨텍스트가 지원되지 않습니다. - + Error while initializing OpenGL! OpenGL을 초기화하는 동안 오류가 발생했습니다! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. GPU가 OpenGL을 지원하지 않거나 최신 그래픽 드라이버가 없을 수 있습니다. - + Error while initializing OpenGL 4.3! OpenGL 4.3을 초기화하는 동안 오류가 발생했습니다! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 GPU가 OpenGL 4.3을 지원하지 않거나 최신 그래픽 드라이버를 가지고 있지 않을 수 있습니다.<br><br>GL 렌더러:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4926,239 +5068,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility 호환성 - - + + Region 지역 - - + + File type 파일 타입 - - + + Size 크기 - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open 열기 - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS RomFS 덤프 - + Disk Shader Cache 디스크 셰이더 캐시 - + Open Shader Cache Location 셰이더 캐시 위치 열기 - + Delete OpenGL Shader Cache OpenGL 셰이더 캐시 삭제하기 - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties 속성 - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders 서브 디렉토리 스캔 - + Remove Application Directory - + Move Up 위로 - + Move Down 아래로 - + Open Directory Location 디렉터리 위치 열기 - + Clear 지우기 - + Name 이름 @@ -5166,77 +5318,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect 완벽함 - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great 좋음 - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay 양호 - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad 나쁨 - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu 인트로/메뉴 - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot 실행불가 - + The app crashes when attempting to startup. - + Not Tested 테스트되지 않음 - + The app has not yet been tested. @@ -5244,7 +5396,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5252,27 +5404,27 @@ Screen. GameListSearchField - + of 중의 - + result 결과 - + results 결과 - + Filter: 필터: - + Enter pattern to filter 검색 필터 입력 @@ -5280,47 +5432,47 @@ Screen. GameRegion - + Japan 일본 - + North America 북미 - + Europe 유럽 - + Australia 호주 - + China 중국 - + Korea 한국 - + Taiwan 대만 - + Invalid region 올바르지 않은 지역 - + Region free 지역해제 @@ -5600,86 +5752,86 @@ Screen. 사이클 인덱스: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 주소 레지스터: %1, %2 - + Compare Result: %1, %2 비교 결과: %1, %2 - + Static Condition: %1 정적 조건: %1 - + Dynamic Conditions: %1, %2 동적 조건: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 루프 매개변수: %1(반복), %2(이니셜라이저), %3(증분), %4 - + Instruction offset: 0x%1 인스트럭션 오프셋: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (마지막 명령어) @@ -5903,24 +6055,24 @@ Debug Message: 셰이더 준비중 %1 / %2 - - Loading Shaders %1 / %2 - %1 / %2 셰이더 불러오는 중 + + Loading %3 %1 / %2 + - + Launching... 실행중... - + Now Loading %1 지금 불러오는 중 %1 - + Estimated Time %1 추정 시간 %1 @@ -5979,32 +6131,32 @@ Debug Message: 비밀번호: - + Room Name 방 이름 - + Preferred Application - + Host 호스트 - + Players 플레이어 - + Refreshing 새로고침중 - + Refresh List 목록 새로고침 @@ -6087,342 +6239,352 @@ Debug Message: 무비 - + Help - + Load File... 파일 불러오기... - + Install CIA... CIA 설치하기... - + Connect to Artic Base... - + Set Up System Files... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit - + Pause - + Stop - + Save 저장하기 - + Load 불러오기 - + FAQ - + About Azahar - + Single Window Mode 단일 창 모드 - + Save to Oldest Slot 가장 오래된 슬롯에 저장하기 - + Quick Save - + Load from Newest Slot 최신 슬롯에서 불러오기 - + Quick Load - + Configure... 설정... - + Display Dock Widget Headers Dock 위젯 헤더 보이기 - + Show Filter Bar 필터 표시줄 표시하기 - + Show Status Bar 상태 표시줄 표시하기 - + Create Pica Surface Viewer Pica Surface Viewer 생성 - + Record... 녹화하기... - + Play... 재생하기... - + Close 닫기 - + Save without Closing 닫지 않고 저장하기 - + Read-Only Mode 읽기 전용 모드 - + Advance Frame 프레임 진행 - + Capture Screenshot 캡쳐 스크린숏 - + Dump Video 비디오 덤프 + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room 방 만들기 - + Leave Room 방 나가기 - + Direct Connect to Room 방에 직접 연결하기 - + Show Current Room 현재 방 표시하기 - + Fullscreen 전체화면 - + Open Log Folder - + Opens the Azahar Log folder - + Default 기본값 - + Single Screen 단일 화면 - + Large Screen 큰 화면 - + Side by Side 좌우 보기 - + Separate Windows 독립된 창 - + Hybrid Screen 하이브리드 스크린 - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens 화면 바꾸기 - + Rotate Upright 수직 회전 - + Report Compatibility 호환성 보고하기 - + Restart 재시작 - + Load... 불러오기... - + Remove 제거 - + Open Azahar Folder - + Configure Current Application... @@ -6993,32 +7155,32 @@ They may have left the room. %1 (0x%2) - + Unsupported encrypted application - + Invalid region 올바르지 않은 지역 - + Installed Titles 설치된 제목 - + System Titles 시스템 제목 - + Add New Application Directory - + Favorites diff --git a/dist/languages/lt_LT.ts b/dist/languages/lt_LT.ts index 3417df303..6750d4e67 100644 --- a/dist/languages/lt_LT.ts +++ b/dist/languages/lt_LT.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -290,8 +290,8 @@ This would ban both their forum username and their IP address. - Emulation: - Emuliacija: + Emulation + Emuliacija @@ -320,8 +320,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Šis efektas suderina garso greitį su emuliacijos greičiu ir padeda išvengti garso trūkinėjimų. Bet tai kartu pailgina garso latenciją. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -330,7 +330,7 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -395,6 +395,7 @@ This would ban both their forum username and their IP address. + Camera Kamera @@ -406,8 +407,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - Kamera, kurią konfigūruosite: + Camera to Configure + @@ -427,8 +428,8 @@ This would ban both their forum username and their IP address. - Camera mode: - Kameros režimas: + Camera mode + @@ -448,8 +449,8 @@ This would ban both their forum username and their IP address. - Camera position: - Kameros pozicija: + Camera position + @@ -469,13 +470,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Pasirinkite kameros įvestį. Tai gali būti paveikslėlis arba tikra kamera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Kameros įvestis: + Camera Image Source + @@ -494,8 +495,8 @@ This would ban both their forum username and their IP address. - File: - Failas: + File + @@ -508,11 +509,6 @@ This would ban both their forum username and their IP address. Select the system camera to use Pasirinkite, kurią sistemos kamerą naudoti - - - Camera: - Kamera: - <Default> @@ -526,8 +522,8 @@ This would ban both their forum username and their IP address. - Flip: - Apvertimas: + Flip + @@ -1079,7 +1075,7 @@ Would you like to ignore the error and continue? - Reverse Side by Side + Side by Side Full Width @@ -1138,48 +1134,53 @@ Would you like to ignore the error and continue? - + + Swap Eyes + + + + Utility - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures + + Preload custom textures - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading @@ -1192,91 +1193,111 @@ Would you like to ignore the error and continue? - General - Pagrindinis + Updates + - Confirm exit while emulation is running - Patvirtinti išėjimą veikiant emuliacijai - - - - Pause emulation when in background - - - - - Mute audio when in background - - - - - Hide mouse on inactivity - - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Pagrindinis + + + + Confirm exit while emulation is running + Patvirtinti išėjimą veikiant emuliacijai + + + + Pause emulation when in background + + + + + Mute audio when in background + + + + + Hide mouse on inactivity + + + + + Enable Gamemode + + + + Emulation Emuliacija - + Use global emulation speed - - Set emulation speed: + + Set emulation speed - - Emulation Speed: + + Emulation Speed - + Turbo Speed Limit: - + Screenshots - + Use global screenshot path - + Set screenshot path: - + Save Screenshots To - + ... ... - + Reset All Settings Atstatyti visus nustatymus @@ -1284,8 +1305,8 @@ Would you like to ignore the error and continue? - - + + unthrottled @@ -1295,12 +1316,12 @@ Would you like to ignore the error and continue? - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1354,12 +1375,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1379,8 +1400,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - Įjungti techninės įrangos šešėliuoklę + Enable hardware shader + @@ -1389,8 +1410,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - Tiksli multiplikacija + Accurate multiplication + @@ -1399,8 +1420,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - Įjungti šešėliuoklės JIT + Enable shader JIT + @@ -1409,17 +1430,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1459,12 +1480,12 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache + Use disk shader cache - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> @@ -1473,22 +1494,32 @@ Would you like to ignore the error and continue? - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1973,12 +2004,12 @@ Would you like to ignore the error and continue? - Swap Screens - Apkeisti ekranus + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2095,7 +2126,7 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2267,7 +2298,7 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2443,7 +2474,7 @@ Would you like to ignore the error and continue? - Use Virtual SD + Use virtual SD card @@ -2453,7 +2484,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location @@ -2484,6 +2515,16 @@ Would you like to ignore the error and continue? SDMC Directory + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2530,8 +2571,8 @@ online features (if installed) - Region: - + Region + Regionas @@ -2539,326 +2580,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Vartotojo vardas - + Birthday Gimtadienis - + January Sausio - + February Vasario - + March Kovo - + April Balandžio - + May Gegužės - + June Birželio - + July Liepos - + August Rugpjūčio - + September Rugsėjo - + October Spalio - + November Lapkričio - + December Gruodžio - + Language Kalba - + Note: this can be overridden when region setting is auto-select Pastaba: šis nustatymas bus ignoruojamas jeigu regionas nustatytas į "Automatiškai pasirinkti" - + Japanese (日本語) Japonų (日本語) - + English Anglų (English) - + French (français) Prancūzų (français) - + German (Deutsch) Vokiečių (Deutsch) - + Italian (italiano) Italų (italiano) - + Spanish (español) Ispanų (español) - + Simplified Chinese (简体中文) Supaprastinta kinų (简体中文) - + Korean (한국어) Korėjiečių (한국어) - + Dutch (Nederlands) Olandų (Nederlands) - + Portuguese (português) Portugalų (português) - + Russian (Русский) Rusų (Русский) - + Traditional Chinese (正體中文) Tradicinė kinų (正體中文) - + Sound output mode Garso išvesties režimas - + Mono Mono - + Stereo Stereo - + Surround Erdvinis - + Country Šalis - + Clock Laikrodis - + System Clock Sistemos laikrodis - + Fixed Time Nustatytas laikas - + Startup time Užkrovimo laikas - + yyyy-MM-ddTHH:mm:ss metai-MĖNESIAI-dienaTVALANDA:minutė:sekundė - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: Konsolės ID: - - + + Regenerate Regeneruoti - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3568,76 +3620,76 @@ online features (if installed) - - + + Console ID: 0x%1 Konsolės ID: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Įspėjimas - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3752,13 +3804,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Sąsajos kalba: + Interface Language + - Theme: - Tema: + Theme + @@ -3767,8 +3819,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - Žaidimo paveikslėlio dydis: + Icon Size + @@ -3788,8 +3840,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - 1 eilutės tekstas: + Row 1 Text + @@ -3823,17 +3875,17 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - 2 eilutės tekstas: + Row 2 Text + - Hide Titles without Icon - Paslėpti programas be paveikslėlio + Hide titles without icon + - Single Line Mode + Single line mode @@ -3843,7 +3895,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3926,12 +3978,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Jungiamasi - + Connect Prisijungti @@ -4050,555 +4102,595 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Dabartinės emuliacijos greitis. Reikšmės žemiau ar aukščiau 100% parodo, kad emuliacija veikia greičiau ar lėčiau negu 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Laikas, kuris buvo sunaudotas atvaizduoti 1 3DS kadrą, neskaičiuojant FPS ribojimo ar V-Sync. Pilno greičio emuliacijai reikalinga daugiausia 16.67 ms reikšmė. - + MicroProfile (unavailable) - + Clear Recent Files Pravalyti neseniai įkrautus failus - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage - + Before using this CIA, you must install it. Do you want to install it now? - + Quick Load - + Quick Save - - + + Slot %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder Klaida atidarant %1 aplanką - - + + Folder does not exist! Aplankas neegzistuoja! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... - - + + Cancel Atšaukti - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. - + Error Opening %1 Klaida atidarant %1 - + Select Directory Pasirinkti katalogą - + Properties - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS programa (%1);;Visi failai (*.*) - + Load File Įkrauti failą - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Įkrauti failus - - 3DS Installation File (*.CIA*) - 3DS instaliacijos failas (*.cia*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Visi failai (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1 buvo įdiegtas sėkmingai. - + Unable to open File Negalima atverti failo - + Could not open %1 Nepavyko atverti %1 - + Installation aborted Instaliacija nutraukta - + The installation of %1 was aborted. Please see the log for more details Failo %1 instaliacija buvo nutraukta. Pasižiūrėkite į žurnalą dėl daugiau informacijos - + Invalid File Klaidingas failas - + %1 is not a valid CIA %1 nėra tinkamas CIA - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. - + File not found Failas nerastas - + File "%1" not found Failas "%1" nerastas - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) „Amiibo“ failas (%1);; Visi failai (*.*) - + Load Amiibo Įkrauti „Amiibo“ - + Unable to open amiibo file "%1" for reading. - + Record Movie Įrašyti įvesčių vaizdo įrašą - + Movie recording cancelled. Įrašo įrašymas nutrauktas. - - + + Movie Saved Įrašas išsaugotas - - + + The movie is successfully saved. Filmas sėkmingai išsaugotas. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4607,214 +4699,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Greitis: %1% - + Speed: %1% / %2% Greitis: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Kadras: %1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive - + System Archive Not Found Sisteminis archyvas nerastas - + System Archive Missing - + Save/load Error - + Fatal Error Nepataisoma klaida - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered - + Continue Tęsti - + Quit Application - + OK Gerai - + Would you like to exit now? Ar norite išeiti? - + The application is still running. Would you like to stop emulation? - + Playback Completed Atkūrimas užbaigtas - + Movie playback completed. Įrašo atkūrimas užbaigtas. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4877,42 +5019,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4920,239 +5062,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Suderinamumas - - + + Region Regionas - - + + File type Failo tipas - - + + Size Dydis - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders Ieškoti poaplankius - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location Atidaryti katalogo vietą - + Clear Išvalyti - + Name Pavadinimas @@ -5160,77 +5312,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Tobulas - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Puikus - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Geras - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Blogas - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Rodo tik pradžios ekraną - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Nepasileidžia - + The app crashes when attempting to startup. - + Not Tested Netestuota - + The app has not yet been tested. @@ -5238,7 +5390,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5246,27 +5398,27 @@ Screen. GameListSearchField - + of - + result rezultatų - + results rezultatai - + Filter: Filtras: - + Enter pattern to filter Įveskite raktinius žodžius filtravimui @@ -5274,47 +5426,47 @@ Screen. GameRegion - + Japan Japonija - + North America - + Europe - + Australia Australija - + China Kinija - + Korea - + Taiwan Taivanas - + Invalid region Klaidingas regionas - + Region free @@ -5594,87 +5746,87 @@ Screen. Rato indeksas: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Adreso registrai: %1, %2 - + Compare Result: %1, %2 Palyginti rezultatus: %1, %2 - + Static Condition: %1 Statinė sąlyga %1 - + Dynamic Conditions: %1, %2 Dinaminės sąlygos: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Ciklo parametrai: %1 (pasikartoja), %2 (inicijuoja), %3 (didina), %4 - + Instruction offset: 0x%1 Instrukcijos ofsetas: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (paskutinė instrukcija) @@ -5898,23 +6050,23 @@ Debug Message: - - Loading Shaders %1 / %2 + + Loading %3 %1 / %2 - + Launching... - + Now Loading %1 - + Estimated Time %1 @@ -5973,32 +6125,32 @@ Debug Message: Slaptažodis: - + Room Name Serverio pavadinimas - + Preferred Application - + Host Vartotojas - + Players Žaidėjų skaičius - + Refreshing Atnaujinama - + Refresh List Atnaujinti sąrašą @@ -6081,342 +6233,352 @@ Debug Message: Įvesčių įrašai - + Help - + Load File... Įkrauti failą... - + Install CIA... Diegti CIA... - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit - + Pause - + Stop - + Save Išsaugoti - + Load - + FAQ - + About Azahar Apie Azahar - + Single Window Mode Vieno lango režimas - + Save to Oldest Slot - + Quick Save - + Load from Newest Slot - + Quick Load - + Configure... Konfigūruoti... - + Display Dock Widget Headers Rodyti ikonėles apačioje - + Show Filter Bar Rodyti paieškos juostą - + Show Status Bar Rodyti būsenos juostą - + Create Pica Surface Viewer Sukurti „Pica“ pagrindo žiūryklę - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame Pereiti į kitą kadrą - + Capture Screenshot - + Dump Video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Sukurti serverį - + Leave Room Palikti serverį - + Direct Connect to Room Tiesioginis prisijungimas prie serverio - + Show Current Room Rodyti dabartinį serverį - + Fullscreen Per visą ekraną - + Open Log Folder - + Opens the Azahar Log folder - + Default Numatytasis - + Single Screen Vienas ekranas - + Large Screen Didelis ekranas - + Side by Side Vienas prie kito šonu - + Separate Windows - + Hybrid Screen - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Apkeisti ekranus - + Rotate Upright - + Report Compatibility Pranešti suderinamumą - + Restart Persirauti - + Load... Įkrauti... - + Remove Pašalinti - + Open Azahar Folder - + Configure Current Application... @@ -6489,7 +6651,7 @@ Debug Message: File: - Failas: + @@ -6581,7 +6743,7 @@ Debug Message: File: - Failas: + @@ -6986,32 +7148,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Klaidingas regionas - + Installed Titles - + System Titles - + Add New Application Directory - + Favorites diff --git a/dist/languages/nb.ts b/dist/languages/nb.ts index 5cb57e9b8..833d312c3 100644 --- a/dist/languages/nb.ts +++ b/dist/languages/nb.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -292,8 +292,8 @@ Dette ville forby både deres brukernavn og IP-adressen. - Emulation: - Emulering: + Emulation + Emulering @@ -322,8 +322,8 @@ Dette ville forby både deres brukernavn og IP-adressen. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Denne etterbehandlingeffekten justerer lydhastigheten for å samsvare med emuleringshastigheten og bidrar til å forhindre lyd-hakking. Dette øker imidlertid lyd forsinkelsen. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ Dette ville forby både deres brukernavn og IP-adressen. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ Dette ville forby både deres brukernavn og IP-adressen. + Camera Kamera @@ -408,8 +409,8 @@ Dette ville forby både deres brukernavn og IP-adressen. - Camera to configure: - Konfigurer kamera: + Camera to Configure + @@ -429,8 +430,8 @@ Dette ville forby både deres brukernavn og IP-adressen. - Camera mode: - Kameramodus: + Camera mode + @@ -450,8 +451,8 @@ Dette ville forby både deres brukernavn og IP-adressen. - Camera position: - Kamera posisjon: + Camera position + @@ -471,13 +472,13 @@ Dette ville forby både deres brukernavn og IP-adressen. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Velg hvor bildet fra det emulerte kameraet kommer fra. Det kan være et bilde eller et ekte kamera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Kamerabildekilde: + Camera Image Source + @@ -496,8 +497,8 @@ Dette ville forby både deres brukernavn og IP-adressen. - File: - Fil: + File + @@ -510,11 +511,6 @@ Dette ville forby både deres brukernavn og IP-adressen. Select the system camera to use Velg systemkameraet som skal brukes - - - Camera: - Kamera: - <Default> @@ -528,8 +524,8 @@ Dette ville forby både deres brukernavn og IP-adressen. - Flip: - Flip: + Flip + @@ -1081,7 +1077,7 @@ Would you like to ignore the error and continue? - Reverse Side by Side + Side by Side Full Width @@ -1140,48 +1136,53 @@ Would you like to ignore the error and continue? - + + Swap Eyes + + + + Utility - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures + + Preload custom textures - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading @@ -1194,91 +1195,111 @@ Would you like to ignore the error and continue? - General - Generelt + Updates + - Confirm exit while emulation is running - Bekreft avslutting mens emuleringen kjører - - - - Pause emulation when in background - Pause emuleringen når i bakgrunnen - - - - Mute audio when in background - - - - - Hide mouse on inactivity - Skjul musen ved inaktivitet - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Generelt + + + + Confirm exit while emulation is running + Bekreft avslutting mens emuleringen kjører + + + + Pause emulation when in background + Pause emuleringen når i bakgrunnen + + + + Mute audio when in background + + + + + Hide mouse on inactivity + Skjul musen ved inaktivitet + + + + Enable Gamemode + + + + Emulation Emulering - + Use global emulation speed - - Set emulation speed: + + Set emulation speed - - Emulation Speed: - Emulator Hastighet: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots - + Use global screenshot path - + Set screenshot path: - + Save Screenshots To - + ... ... - + Reset All Settings Nullstill Alle Innstillinger @@ -1286,8 +1307,8 @@ Would you like to ignore the error and continue? - - + + unthrottled Ubegrenset @@ -1297,12 +1318,12 @@ Would you like to ignore the error and continue? - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1356,12 +1377,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1381,8 +1402,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - Aktiver Maskinvare Gjengivelse + Enable hardware shader + @@ -1391,8 +1412,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - Nøyaktig Multiplikasjon + Accurate multiplication + @@ -1401,8 +1422,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - Aktiver Gjengivelse JIT + Enable shader JIT + @@ -1411,17 +1432,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1461,13 +1482,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache + Use disk shader cache - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync forhindrer screen tearing, men noen grafikkort har lavere ytelse når VSync er aktivert. Hold den aktivert hvis du ikke merker en ytelsesforskjell. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1475,22 +1496,32 @@ Would you like to ignore the error and continue? Aktiver VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1975,12 +2006,12 @@ Would you like to ignore the error and continue? - Swap Screens - Bytt Skjerm + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2097,7 +2128,7 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2269,7 +2300,7 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2445,7 +2476,7 @@ Would you like to ignore the error and continue? - Use Virtual SD + Use virtual SD card @@ -2455,7 +2486,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location @@ -2486,6 +2517,16 @@ Would you like to ignore the error and continue? SDMC Directory + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2532,8 +2573,8 @@ online features (if installed) - Region: - + Region + Region @@ -2541,326 +2582,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Brukernavn - + Birthday Fødselsdag - + January Januar - + February Februar - + March Mars - + April April - + May Mai - + June Juni - + July Juli - + August August - + September September - + October Oktober - + November November - + December Desember - + Language Språk - + Note: this can be overridden when region setting is auto-select Merk: dette kan overstyres når regioninnstillingen er automatisk valgt - + Japanese (日本語) Japansk (日本語) - + English Engelsk - + French (français) Fransk (français) - + German (Deutsch) Tysk (Deutsch) - + Italian (italiano) Italiensk (italiano) - + Spanish (español) Spansk (español) - + Simplified Chinese (简体中文) Enkel Kinesisk (简体中文) - + Korean (한국어) Koreansk (한국어) - + Dutch (Nederlands) Nederlandsk (Nederlands) - + Portuguese (português) portugisisk (português) - + Russian (Русский) Russisk (Русский) - + Traditional Chinese (正體中文) Tradisjonell Kinesisk (正體中文) - + Sound output mode Lydutgangsmodus - + Mono Mono - + Stereo Stero - + Surround Surround - + Country Land - + Clock Klokke - + System Clock System Klokke - + Fixed Time Bestemt Tid - + Startup time Oppstartstid - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: Konsoll ID: - - + + Regenerate Regenerere - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3570,76 +3622,76 @@ online features (if installed) - - + + Console ID: 0x%1 Konsoll ID: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Advarsel - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3755,13 +3807,13 @@ Dra punkter for å endre posisjon, eller dobbeltklikk på tabellceller for å re - Interface language: - Grensesnittspråk: + Interface Language + - Theme: - Tema: + Theme + @@ -3770,8 +3822,8 @@ Dra punkter for å endre posisjon, eller dobbeltklikk på tabellceller for å re - Icon Size: - Ikon Størrelse: + Icon Size + @@ -3791,8 +3843,8 @@ Dra punkter for å endre posisjon, eller dobbeltklikk på tabellceller for å re - Row 1 Text: - Rad 1 tekst: + Row 1 Text + @@ -3826,18 +3878,18 @@ Dra punkter for å endre posisjon, eller dobbeltklikk på tabellceller for å re - Row 2 Text: - Rad 2 tekst: + Row 2 Text + - Hide Titles without Icon - Skjul titler uten ikon + Hide titles without icon + - Single Line Mode - Enkeltlinjemodus + Single line mode + @@ -3846,7 +3898,7 @@ Dra punkter for å endre posisjon, eller dobbeltklikk på tabellceller for å re - Show Advanced Frame Time Info + Show advanced frame time info @@ -3929,12 +3981,12 @@ Dra punkter for å endre posisjon, eller dobbeltklikk på tabellceller for å re DirectConnectWindow - + Connecting Kobler til - + Connect Koble til @@ -4053,556 +4105,596 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Nåværende emuleringhastighet. Verdier høyere eller lavere enn 100% indikerer at emuleringen kjører raskere eller langsommere enn en 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tid tatt for å emulere et 3DS bilde, gjelder ikke bildebegrensning eller V-Sync. For raskest emulering bør dette være høyst 16,67 ms. - + MicroProfile (unavailable) - + Clear Recent Files Tøm nylige filer - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage CIA må installeres før bruk - + Before using this CIA, you must install it. Do you want to install it now? Før du bruker denne CIA, må du installere den. Vil du installere det nå? - + Quick Load - + Quick Save - - + + Slot %1 Spor %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder Feil ved Åpning av %1 Mappe - - + + Folder does not exist! Mappen eksistere ikke! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... Dumper... - - + + Cancel Kanseller - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. Kunne ikke dumpe basen RomFS. Se loggen for detaljer. - + Error Opening %1 Feil ved åpning av %1 - + Select Directory Velg Mappe - + Properties - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS Executable (%1);;All Files (*.*) - + Load File Last Fil - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Last Filer - - 3DS Installation File (*.CIA*) - 3DS Installasjons Fil (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Alle Filer (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1 Ble installert vellykket. - + Unable to open File Kan ikke åpne Fil - + Could not open %1 Kunne ikke åpne %1 - + Installation aborted Installasjon avbrutt - + The installation of %1 was aborted. Please see the log for more details Installeringen av %1 ble avbrutt. Vennligst se logg for detaljer - + Invalid File Ugyldig Fil - + %1 is not a valid CIA %1 er ikke en gyldig CIA - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. - + File not found Fil ikke funnet - + File "%1" not found Fil "%1" ble ikke funnet - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo File (%1);; All Files (*.*) - + Load Amiibo Last inn Amiibo - + Unable to open amiibo file "%1" for reading. - + Record Movie Ta Opp Video - + Movie recording cancelled. Filmopptak avbrutt. - - + + Movie Saved Film Lagret - - + + The movie is successfully saved. Filmen ble lagret vellykket. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4611,214 +4703,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Fart: %1% - + Speed: %1% / %2% Fart: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Bilde: %1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Et System Arkiv - + System Archive Not Found System Arkiv ikke funnet - + System Archive Missing System Arkiv Mangler - + Save/load Error Lagre/laste inn Feil - + Fatal Error Fatal Feil - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered Fatal Feil Oppstått - + Continue Fortsett - + Quit Application - + OK OK - + Would you like to exit now? Vil du avslutte nå? - + The application is still running. Would you like to stop emulation? - + Playback Completed Avspilling Fullført - + Movie playback completed. Filmavspilling fullført. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4881,42 +5023,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4924,239 +5066,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Kompatibilitet - - + + Region Region - - + + File type Filtype - - + + Size Størrelse - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS Dump RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders Skann Undermapper - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location Fjern Mappe Plassering - + Clear - + Name Navn @@ -5164,77 +5316,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Perfekt - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Bra - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Ok - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Dårlig - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Intro/Meny - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Vil ikke starte opp - + The app crashes when attempting to startup. - + Not Tested Ikke Testet - + The app has not yet been tested. @@ -5242,7 +5394,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5250,27 +5402,27 @@ Screen. GameListSearchField - + of av - + result Resultat - + results Resultater - + Filter: Filter: - + Enter pattern to filter Skriv inn mønster for å filtrere @@ -5278,47 +5430,47 @@ Screen. GameRegion - + Japan Japan - + North America Nord Amerika - + Europe Europa - + Australia Australia - + China Kina - + Korea Korea - + Taiwan Taiwan - + Invalid region Ugyldig region - + Region free Regionfri @@ -5598,87 +5750,87 @@ Screen. Syklusindeks: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Adresse Register: %1, %2 - + Compare Result: %1, %2 Sammenlign Resultater: %1, %2 - + Static Condition: %1 Statisk Tilstand: %1 - + Dynamic Conditions: %1, %2 Dynamiske Betingelser: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 - + Instruction offset: 0x%1 Instruksjons forskyvning: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (siste instruksjon) @@ -5902,24 +6054,24 @@ Debug Message: Forbereder Shaders %1 / %2 - - Loading Shaders %1 / %2 - Laster Shaders %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Starter... - + Now Loading %1 Laster %1 - + Estimated Time %1 Estimert Tid %1 @@ -5978,32 +6130,32 @@ Debug Message: Passord: - + Room Name Rom Navn - + Preferred Application - + Host Vert - + Players Spillere - + Refreshing Oppdaterer - + Refresh List Oppdaterer Liste @@ -6086,342 +6238,352 @@ Debug Message: Video - + Help - + Load File... Last inn fil... - + Install CIA... Installer CIA... - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit - + Pause - + Stop - + Save Lagre - + Load Laste Inn - + FAQ - + About Azahar - + Single Window Mode Enkelt vindu modus - + Save to Oldest Slot Lagre til Eldste Spor - + Quick Save - + Load from Newest Slot Last Inn fra Nyeste Spor - + Quick Load - + Configure... Konfigurer... - + Display Dock Widget Headers Vis Dock Widget Headere - + Show Filter Bar Vis filter linje - + Show Status Bar Vis status linje - + Create Pica Surface Viewer Lag Pica overflate visning - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame Advance Frame - + Capture Screenshot Ta skjermbilde - + Dump Video Dump Video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Opprett Rom - + Leave Room Forlat Rom - + Direct Connect to Room Koble Direkte til Rom - + Show Current Room Vis Nåværende Rom - + Fullscreen Fullskjerm - + Open Log Folder - + Opens the Azahar Log folder - + Default Standard - + Single Screen Enkel Skjerm - + Large Screen Stor Skjerm - + Side by Side Side ved Side - + Separate Windows - + Hybrid Screen - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Bytt Skjerm - + Rotate Upright Roter Oppreist - + Report Compatibility Rapporter Kompatibilitet - + Restart Omstart - + Load... Last inn... - + Remove Fjern - + Open Azahar Folder - + Configure Current Application... @@ -6494,7 +6656,7 @@ Debug Message: File: - Fil: + @@ -6586,7 +6748,7 @@ Debug Message: File: - Fil: + @@ -6992,32 +7154,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Ugyldig region - + Installed Titles Installerte Tittler - + System Titles System Tittler - + Add New Application Directory - + Favorites diff --git a/dist/languages/nl.ts b/dist/languages/nl.ts index b66514dd9..d9fba478a 100644 --- a/dist/languages/nl.ts +++ b/dist/languages/nl.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -292,8 +292,8 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - Emulation: - Emulatie: + Emulation + Emulatie @@ -322,8 +322,8 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Dit post-processing effect past de geluidssnelheid aan om gelijk te zijn aan de emulatiesnelheid en helpt audiostotter te voorkomen. Dit zorgt wel voor meer audiovertraging. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. + Camera Camera @@ -408,8 +409,8 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - Camera to configure: - Camera om te configureren: + Camera to Configure + @@ -429,8 +430,8 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - Camera mode: - Camera modus: + Camera mode + @@ -450,8 +451,8 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - Camera position: - Camera positie: + Camera position + @@ -471,13 +472,13 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Selecteer waar de afbeelding van de ge-emuleerde camera vandaan komt. Het mag een afbeelding zijn of een echte camera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Camera Afbeelding Bron: + Camera Image Source + @@ -496,8 +497,8 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - File: - Bestand: + File + @@ -510,11 +511,6 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. Select the system camera to use Selecteer systeem camera om te gebruiken - - - Camera: - Camera: - <Default> @@ -528,8 +524,8 @@ Dit zal hun Forum gebruikersnaam en IP adres verbannen. - Flip: - Omdraaing: + Flip + @@ -1018,7 +1014,7 @@ Wilt u de fout negeren en doorgaan? Enable Linear Filtering - Activeer lineaire filtering + @@ -1082,7 +1078,7 @@ Wilt u de fout negeren en doorgaan? - Reverse Side by Side + Side by Side Full Width @@ -1141,49 +1137,54 @@ Wilt u de fout negeren en doorgaan? - + + Swap Eyes + + + + Utility Utility - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Vervang texturen met PNG-bestanden.</p><p>Texturen worden geladen vanuit load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures - Gebruik aangepaste texturen + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Dump texturen naar PNG-bestanden.</p><p>Texturen worden gedumpt naar dump/textures/[Title ID]/. - - Dump Textures - Dump texturen + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures - Aangepaste texturen vooraf laden + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Aangepaste texturen asynchroon laden met achtergrondthreads om stotteren bij het laden te verminderen</p></body></html> - - Async Custom Texture Loading - Async aangepaste texturen laden + + Async custom texture loading + @@ -1195,91 +1196,111 @@ Wilt u de fout negeren en doorgaan? - General - Algemeen + Updates + - Confirm exit while emulation is running - Afsluiten bevestigen terwijl emulatie actief is - - - - Pause emulation when in background - Emulatie pauzeren wanneer op achtergrond geplaatst - - - - Mute audio when in background - Demp geluid wanneer in de achtergond - - - - Hide mouse on inactivity - Verberg de muis wanneer niet actief - - - - Enable Gamemode - Schakel Gamemode in - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Algemeen + + + + Confirm exit while emulation is running + Afsluiten bevestigen terwijl emulatie actief is + + + + Pause emulation when in background + Emulatie pauzeren wanneer op achtergrond geplaatst + + + + Mute audio when in background + Demp geluid wanneer in de achtergond + + + + Hide mouse on inactivity + Verberg de muis wanneer niet actief + + + + Enable Gamemode + Schakel Gamemode in + + + Emulation Emulatie - + Use global emulation speed Gebruik globale emulatiesnelheid - - Set emulation speed: - Emulatiesnelheid instellen: + + Set emulation speed + - - Emulation Speed: - Emulatiesnelheid: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots Schermafbeeldingen - + Use global screenshot path Globaal pad voor schermafbeeldingen gebruiken - + Set screenshot path: Schermafbeeldingpad instellen: - + Save Screenshots To Schermafbeeldingen opslaan in - + ... ... - + Reset All Settings Alle Instellingen Herstellen @@ -1287,8 +1308,8 @@ Wilt u de fout negeren en doorgaan? - - + + unthrottled onbeperkt @@ -1298,12 +1319,12 @@ Wilt u de fout negeren en doorgaan? schermafbeelding-map selecteren - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1357,12 +1378,12 @@ Wilt u de fout negeren en doorgaan? - SPIR-V Shader Generation - SPIR-V shadergeneratie + SPIR-V shader generation + - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1382,8 +1403,8 @@ Wilt u de fout negeren en doorgaan? - Enable Hardware Shader - Activeer Hardware Shader + Enable hardware shader + @@ -1392,8 +1413,8 @@ Wilt u de fout negeren en doorgaan? - Accurate Multiplication - Nauwkeurige Vermenigvuldiging + Accurate multiplication + @@ -1402,8 +1423,8 @@ Wilt u de fout negeren en doorgaan? - Enable Shader JIT - Activeer Shader JIT + Enable shader JIT + @@ -1412,18 +1433,18 @@ Wilt u de fout negeren en doorgaan? - Enable Async Shader Compilation - Activeer Async shadercompilatie + Enable async shader compilation + - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation - Activeer Async-presentatie + Enable async presentation + @@ -1462,13 +1483,13 @@ Wilt u de fout negeren en doorgaan? - Use Disk Shader Cache - Gebruik schijfshadercache + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync voorkomt dat het scherm scheurt, maar sommige grafische kaarten presteren minder goed als VSync is ingeschakeld. Laat het ingeschakeld als u geen prestatieverschil merkt. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1476,22 +1497,32 @@ Wilt u de fout negeren en doorgaan? Activeer VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1976,13 +2007,13 @@ Wilt u de fout negeren en doorgaan? - Swap Screens - Wissel Schermen + Swap screens + - Rotate Screens Upright - Draai Schermen Rechtop + Rotate screens upright + @@ -2098,8 +2129,8 @@ Wilt u de fout negeren en doorgaan? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Onderste Scherm Doorzichtigheid % (alleen OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + @@ -2270,7 +2301,7 @@ Wilt u de fout negeren en doorgaan? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2446,8 +2477,8 @@ Wilt u de fout negeren en doorgaan? - Use Virtual SD - Gebruik virtuele SD + Use virtual SD card + @@ -2456,8 +2487,8 @@ Wilt u de fout negeren en doorgaan? - Use Custom Storage - Gebruik aangepaste opslag + Use custom storage location + @@ -2487,6 +2518,16 @@ Wilt u de fout negeren en doorgaan? SDMC Directory SDMC map + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2533,8 +2574,8 @@ online features (if installed) - Region: - + Region + Regio @@ -2542,326 +2583,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Gebruikersnaam - + Birthday Geboortedatum - + January januari - + February februari - + March maart - + April april - + May mei - + June juni - + July juli - + August augustus - + September september - + October oktober - + November november - + December december - + Language Taal - + Note: this can be overridden when region setting is auto-select Opmerking: dit kan overschreven worden wanneer regio instelling op automatisch selecteren staat - + Japanese (日本語) Japans (日本語) - + English Engels - + French (français) Frans (français) - + German (Deutsch) Duits (Deutsch) - + Italian (italiano) Italiaans (italiano) - + Spanish (español) Spaans (español) - + Simplified Chinese (简体中文) Versimpeld Chinees (简体中文) - + Korean (한국어) Koreaans (한국어) - + Dutch (Nederlands) Nederlands (Nederlands) - + Portuguese (português) Portugees (português) - + Russian (Русский) Russisch (Русский) - + Traditional Chinese (正體中文) Traditioneel Chinees (正體中文) - + Sound output mode Geluidsuitvoer modus - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Land - + Clock Klok - + System Clock Systeemklok - + Fixed Time Vaste tijd - + Startup time Opstarttijd - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time Offset tijd - + days - + HH:mm:ss HH:mm:ss - + Initial System Ticks - + Random Willekeurig - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched Systeeminstellingen opstarten wanneer het Home-menu wordt gestart - + Console ID: Console ID: - - + + Regenerate Herstellen - + MAC: - - 3GX Plugin Loader: - 3GX-pluginlader: + + 3GX Plugin Loader + - + Enable 3GX plugin loader Activeer 3GX-pluginlader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3571,76 +3623,76 @@ online features (if installed) - - + + Console ID: 0x%1 Console ID: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Waarschuwing - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3756,13 +3808,13 @@ Sleep punten om de positie te wijzigen of dubbelklik op tabelcellen om waarden t - Interface language: - Interfacetaal: + Interface Language + - Theme: - Thema: + Theme + @@ -3771,8 +3823,8 @@ Sleep punten om de positie te wijzigen of dubbelklik op tabelcellen om waarden t - Icon Size: - Icoongrootte + Icon Size + @@ -3792,8 +3844,8 @@ Sleep punten om de positie te wijzigen of dubbelklik op tabelcellen om waarden t - Row 1 Text: - Rij 1 Tekst: + Row 1 Text + @@ -3827,18 +3879,18 @@ Sleep punten om de positie te wijzigen of dubbelklik op tabelcellen om waarden t - Row 2 Text: - Rij 2 Tekst: + Row 2 Text + - Hide Titles without Icon - Verberg titels zonder icoon + Hide titles without icon + - Single Line Mode - Enkelvoudige lijnmodus + Single line mode + @@ -3847,7 +3899,7 @@ Sleep punten om de positie te wijzigen of dubbelklik op tabelcellen om waarden t - Show Advanced Frame Time Info + Show advanced frame time info @@ -3930,12 +3982,12 @@ Sleep punten om de positie te wijzigen of dubbelklik op tabelcellen om waarden t DirectConnectWindow - + Connecting Verbinden - + Connect Verbind @@ -4055,556 +4107,596 @@ Controleer de FFmpeg-installatie die wordt gebruikt voor de compilatie. GMainWindow - + No Suitable Vulkan Devices Detected Geen geschikte Vulkan-apparaten gedetecteerd - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. Vulkan-initialisatie mislukt tijdens het opstarten.<br/>Uw GPU ondersteunt Vulkan 1.1 mogelijk niet of u hebt niet het nieuwste grafische stuurprogramma. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Huidige emulatiesnelheid. Waardes hoger of lager dan 100% geven aan dat de emulatie sneller of langzamer gaat dan een 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tijd verstrekt om één 3DS frame te emuleren, zonder framelimitatie of V-Sync te tellen. Voor volledige snelheid emulatie zal dit maximaal 16.67 ms moeten zijn. - + MicroProfile (unavailable) - + Clear Recent Files Wis recente bestanden - + &Continue &Continue - + &Pause &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. Er heeft zich een onbekende fout voorgedaan. Raadpleeg het log voor meer informatie. - + CIA must be installed before usage CIA moet worden geïnstalleerd voor gebruik - + Before using this CIA, you must install it. Do you want to install it now? Voordat u deze CIA kunt gebruiken, moet u hem installeren. Wilt u het nu installeren? - + Quick Load - + Quick Save - - + + Slot %1 Slot %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 Slot %1 - %2 %3 - + Error Opening %1 Folder Fout bij het openen van de map %1 - - + + Folder does not exist! Map bestaat niet! - + Remove Play Time Data Verwijder speeltijd gegevens - + Reset play time? Stel speeltijd opnieuw in? - - - - + + + + Create Shortcut Snelkoppeling maken - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 Het maken van een snelkoppeling naar %1 was succesvol - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Dit zal een snelkoppeling naar het huidige AppImage aanmaken. Dit zal mogelijk niet meer werken als u deze software bijwerkt. Wilt u doorgaan? - + Failed to create a shortcut to %1 Kon geen snelkoppeling naar %1 aanmaken - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... Dumping... - - + + Cancel Annuleren - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. Kon basis RomFS niet dumpen. Raadpleeg het log voor meer informatie. - + Error Opening %1 Fout bij het openen van %1 - + Select Directory Selecteer Folder - + Properties Eigenschappen - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS Executable (%1);;Alle bestanden (*.*) - + Load File Laad bestand - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Laad Bestanden - - 3DS Installation File (*.CIA*) - 3DS Installatie bestand (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Alle bestanden (*.*) - + Connect to Artic Base Verbind met Artic Base - + Enter Artic Base server address: Voer Artic Base server adres in: - + %1 has been installed successfully. %1 is succesvol geïnstalleerd. - + Unable to open File Kan bestand niet openen - + Could not open %1 Kan %1 niet openen - + Installation aborted Installatie onderbroken - + The installation of %1 was aborted. Please see the log for more details De installatie van %1 is afgebroken. Zie het logboek voor meer details - + Invalid File Ongeldig bestand - + %1 is not a valid CIA %1 is geen geldige CIA - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File Bestand niet gevonden - + Could not find %1 Kon %1 niet vinden - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... '%1' aan het verwijderen... - + Failed to uninstall '%1'. Kon niet '%1' verwijderen. - + Successfully uninstalled '%1'. '%1' succesvol verwijderd. - + File not found Bestand niet gevonden - + File "%1" not found Bestand "%1" niet gevonden - + Savestates Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file Fout bij het openen van het amiibo databestand - + A tag is already in use. Er is al een tag in gebruik. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo Bestand (%1);; Alle Bestanden (*.*) - + Load Amiibo Laad Amiibo - + Unable to open amiibo file "%1" for reading. Kan amiibo-bestand "%1" niet openen om te worden gelezen. - + Record Movie Film opnemen - + Movie recording cancelled. Filmopname geannuleerd. - - + + Movie Saved Film Opgeslagen - - + + The movie is successfully saved. De film is met succes opgeslagen. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory Ongeldige schermafbeeldmap - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. Kan de opgegeven map voor schermafbeeldingen niet maken. Het pad voor schermafbeeldingen wordt teruggezet naar de standaardwaarde. - + Could not load video dumper Kan videodumper niet laden - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4613,214 +4705,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - Selecteer FFmpeg map - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - De opgegeven FFmpeg directory ontbreekt %1. Controleer of de juiste map is geselecteerd. - - - - FFmpeg has been sucessfully installed. - FFmpeg is met succes geïnstalleerd. - - - - Installation of FFmpeg failed. Check the log file for details. - Installatie van FFmpeg is mislukt. Controleer het logbestand voor meer informatie. - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - Opname %1 - - - - Playing %1 / %2 - Afspelen %1 / %2 - - - - Movie Finished - Film Voltooid - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + Selecteer FFmpeg map + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + De opgegeven FFmpeg directory ontbreekt %1. Controleer of de juiste map is geselecteerd. + + + + FFmpeg has been sucessfully installed. + FFmpeg is met succes geïnstalleerd. + + + + Installation of FFmpeg failed. Check the log file for details. + Installatie van FFmpeg is mislukt. Controleer het logbestand voor meer informatie. + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + Opname %1 + + + + Playing %1 / %2 + Afspelen %1 / %2 + + + + Movie Finished + Film Voltooid + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Snelheid: %1% - + Speed: %1% / %2% Snelheid: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Frame: %1 ms - + VOLUME: MUTE VOLUME: STIL - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUME: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Een systeemarchief - + System Archive Not Found Systeem archief niet gevonden - + System Archive Missing Systeemarchief ontbreekt - + Save/load Error Opslaan/Laad fout - + Fatal Error Fatale Fout - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered Fatale fout opgetreden - + Continue Doorgaan - + Quit Application - + OK OK - + Would you like to exit now? Wilt u nu afsluiten? - + The application is still running. Would you like to stop emulation? - + Playback Completed Afspelen voltooid - + Movie playback completed. Film afspelen voltooid. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window Primaire venster - + Secondary Window Secundair venster @@ -4883,42 +5025,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! OpenGL niet beschikbaar! - + OpenGL shared contexts are not supported. OpenGL gedeelde contexten zijn niet ondersteund. - + Error while initializing OpenGL! Fout bij het initialiseren van OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Het kan zijn dat uw GPU OpenGL niet ondersteunt of dat u niet de nieuwste grafische stuurprogramma geïnstalleert hebt. - + Error while initializing OpenGL 4.3! Fout tijdens het initialiseren van OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Uw GPU ondersteunt mogelijk OpenGL 4.3 niet of u hebt niet het meest recente grafische stuurprogramma.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! Fout tijdens het initialiseren van OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Uw GPU ondersteunt mogelijk OpenGL ES 3.2 niet of u hebt niet het meest recente grafische stuurprogramma.<br><br>GL Renderer:<br>%1 @@ -4926,239 +5068,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Compatibiliteit - - + + Region Regio - - + + File type Bestandstype - - + + Size Grootte - - + + Play time Gespeelde tijd - + Favorite Favoriet - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open Open - + Application Location Applicatie Locatie - + Save Data Location Opgeslagen Gegevens Locatie - + Extra Data Location Extra Gegevens Locatie - + Update Data Location Updategegevens Locatie - + DLC Data Location DLC Gegevens Locatie - + Texture Dump Location Textures Dump Locatie - + Custom Texture Location Aangepaste Textures Locatie - + Mods Location Mods Locatie - + Dump RomFS Dump RomFS - + Disk Shader Cache Schijf Shader-cache - + Open Shader Cache Location Shader-cache locatie openen - + Delete OpenGL Shader Cache OpenGL Shader-cache verwijderen - + + Delete Vulkan Shader Cache + + + + Uninstall Verwijder - + Everything Alles - + Application - + Update Update - + DLC DLC - + Remove Play Time Data Verwijder Speeltijd Gegevens - + Create Shortcut Maak snelkoppeling - + Add to Desktop Voeg toe aan Bureaublad - + Add to Applications Menu Voeg to aan Applicatie Menu - + + Stress Test: App Launch + + + + Properties Eigenschappen - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) %1 (Update) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? Weet u zeker dat u '%1' wilt verwijderen? - + Are you sure you want to uninstall the update for '%1'? Weet u zeker dat u de update voor '%1' wilt verwijderen? - + Are you sure you want to uninstall all DLC for '%1'? Weet u zeker dat u alle DLC voor '%1' wilt verwijderen? - + Scan Subfolders Scan Submappen - + Remove Application Directory - + Move Up Omhoog - + Move Down Omlaag - + Open Directory Location Open map Locatie - + Clear Wissen - + Name Naam @@ -5166,77 +5318,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Perfect - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Geweldig - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Oké - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Slecht - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Intro/Menu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Start Niet - + The app crashes when attempting to startup. - + Not Tested Niet Getest - + The app has not yet been tested. @@ -5244,7 +5396,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5252,27 +5404,27 @@ Screen. GameListSearchField - + of van de - + result resultaat - + results resultaten - + Filter: Filter: - + Enter pattern to filter Patroon invoeren om te filteren @@ -5280,47 +5432,47 @@ Screen. GameRegion - + Japan Japan - + North America Noord-Amerika - + Europe Europa - + Australia Australië - + China China - + Korea Korea - + Taiwan Taiwan - + Invalid region Ongeldige regio - + Region free Regio vrij @@ -5600,87 +5752,87 @@ Screen. Cyclus Index: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Adres Registers: %1, %2 - + Compare Result: %1, %2 Vergelijkings-resultaten: %1, %2 - + Static Condition: %1 Statische Toestand: %1 - + Dynamic Conditions: %1, %2 Dynamische Toestand: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Loop Parameters: %1 (Herhaaldelijk), %2 (Tot stand brengen), %3 (Ophoging), %4 - + Instruction offset: 0x%1 Instructie verspringing: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (laatste instructie) @@ -5904,24 +6056,24 @@ Debug Message: Shaders voorbereiden %1 / %2 - - Loading Shaders %1 / %2 - Shaders laden %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Starten... - + Now Loading %1 Nu aan het laden %1 - + Estimated Time %1 Geschatte tijd %1 @@ -5980,32 +6132,32 @@ Debug Message: Wachtwoord: - + Room Name Kamernaam - + Preferred Application - + Host Host - + Players Spelers - + Refreshing Vernieuwen - + Refresh List Lijst vernieuwen @@ -6088,342 +6240,352 @@ Debug Message: Film - + Help - + Load File... Laad Bestand... - + Install CIA... CIA Installeren... - + Connect to Artic Base... Verbind met Artic Base... - + Set Up System Files... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit - + Pause - + Stop - + Save Opslaan - + Load Laden - + FAQ - + About Azahar - + Single Window Mode Enkel Scherm Modus - + Save to Oldest Slot Sla op in het Oudste Slot - + Quick Save - + Load from Newest Slot Laad het nieuwste slot - + Quick Load - + Configure... Configureren... - + Display Dock Widget Headers Dock Widget Headers Tonen - + Show Filter Bar Filter Bar Tonen - + Show Status Bar Status Bar Tonen - + Create Pica Surface Viewer Pica Surface Viewer Maken - + Record... Opnemen... - + Play... Afspelen... - + Close Sluiten - + Save without Closing Opslaan zonder af te sluiten - + Read-Only Mode Alleen-lezen modus - + Advance Frame Vooruitgang van frame - + Capture Screenshot Maak Schermafbeelding - + Dump Video Dump Video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Kamer Aanmaken - + Leave Room Kamer Verlaten - + Direct Connect to Room Directe verbinding naar kamer - + Show Current Room Huidige kamer tonen - + Fullscreen Volledig Scherm - + Open Log Folder Open Log Map - + Opens the Azahar Log folder - + Default Standaard - + Single Screen Enkel Scherm - + Large Screen Groot Scherm - + Side by Side Zij aan zij - + Separate Windows Gescheide vensters - + Hybrid Screen Hybride scherm - + Custom Layout Gepersonaliseerde Lay-out - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Verwissel Schermen - + Rotate Upright Schermen rechtop draaien - + Report Compatibility Compatibiliteit rapporteren - + Restart Herstart - + Load... Laden... - + Remove Verwijder - + Open Azahar Folder - + Configure Current Application... @@ -6997,32 +7159,32 @@ Misschien hebben ze de kamer verlaten. %1 (0x%2) - + Unsupported encrypted application - + Invalid region Ongeldige regio - + Installed Titles Geïnstalleerde titels - + System Titles Systeem titels - + Add New Application Directory - + Favorites Favorieten diff --git a/dist/languages/pl_PL.ts b/dist/languages/pl_PL.ts index e47f835a4..e367da963 100644 --- a/dist/languages/pl_PL.ts +++ b/dist/languages/pl_PL.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,8 +298,8 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - Emulation: - Emulacja: + Emulation + Emulacja @@ -328,8 +328,8 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Efekt ten dostosowuje prędkość dźwięku do prędkości emulacji w celu zapobiegnięcia tzw. "stutteringu" dźwięku. Opcja ta zwiększa opóźnienie dźwięku. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + <html><head/><body><p>Efekt ten dostosowuje prędkość dźwięku do prędkości emulacji w celu zapobiegnięcia tzw. "stutteringu" dźwięku. Opcja ta zwiększa opóźnienie dźwięku.</p></body></html> @@ -338,8 +338,8 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Skaluje prędkość odtwarzania dźwięku, aby uwzględnić spadki liczby klatek na sekundę emulacji. Oznacza to, że dźwięk będzie odtwarzany z pełną prędkością nawet przy niskim framerate aplikacji. Może powodować problemy z desynchronizacją dźwięku. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + <html><head/><body><p>Skaluje prędkość odtwarzania dźwięku, aby uwzględnić spadki liczby klatek na sekundę emulacji. Oznacza to, że dźwięk będzie odtwarzany z pełną prędkością nawet przy niskim framerate aplikacji. Może powodować problemy z desynchronizacją dźwięku.</p></body></html> @@ -403,6 +403,7 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I + Camera Kamera @@ -414,8 +415,8 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - Camera to configure: - Kamera do konfiguracji: + Camera to Configure + Konfiguracja Kamery @@ -435,8 +436,8 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - Camera mode: - Tryb kamery: + Camera mode + Tryb Kamery: @@ -456,8 +457,8 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - Camera position: - Położenie kamery: + Camera position + Pozycja Kamery @@ -477,13 +478,13 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Wybierz obraz, z którego ma być emulowana kamera. Może to być plik lub prawdziwa kamera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + <html><head/><body><p>Wybierz obraz, z którego ma być emulowana kamera. Może to być plik lub prawdziwa kamera.</p></body></html> - Camera Image Source: - Źródło Obrazu Kamery: + Camera Image Source + Źródło Obrazu Kamery @@ -502,8 +503,8 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - File: - Plik: + File + Plik @@ -516,11 +517,6 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I Select the system camera to use Wybierz kamerę, której chcesz użyć - - - Camera: - Kamera: - <Default> @@ -534,8 +530,8 @@ Spowodowałoby to zablokowanie zarówno nazwy użytkownika forum, jak i adresu I - Flip: - Obrót: + Flip + Obrót @@ -1088,8 +1084,8 @@ Czy chcesz zignorować błąd i kontynuować? - Reverse Side by Side - Odwróć Obok Siebie + Side by Side Full Width + Obok Siebie na Pełną Szerokość @@ -1139,7 +1135,7 @@ Czy chcesz zignorować błąd i kontynuować? Disable Right Eye Rendering - Wyłącz renderowanie prawego oka + Wyłącz Renderowanie Prawego Oka @@ -1147,49 +1143,54 @@ Czy chcesz zignorować błąd i kontynuować? <html><head/><body><p>Wyłącza renderowanie prawego oka</p><p>Wyłącza renderowanie obrazu dla prawego oka, gdy nie jest używany tryb stereoskopowy. Znacznie poprawia wydajność w niektórych grach, ale w innych grach może powodować migotanie obrazu.</p></body></html> - + + Swap Eyes + Zamiana Oczu + + + Utility Narzędzia - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Zastępuje tekstury przez pliki PNG.</p><p>Tekstury są ładowane z pliku load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures Użyj niestandardowych tekstur - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Zrzuca tekstury do plików PNG.</p><p>Tekstury są zrzucane do pliku dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures Zrzuć Tekstury - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>Ładowanie wszystkich niestandardowych tekstur do pamięci podczas uruchamiania, zamiast ładowania ich, gdy wymaga tego aplikacja.</p></body></html> - - Preload Custom Textures - Wczytaj niestandardowe tekstury + + Preload custom textures + Wczytaj Customowe Tekstury - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Załaduj niestandardowe tekstury asynchronicznie za pomocą wątków w tle, aby zmniejszyć opóźnienia w ładowaniu.</p></body></html> - - Async Custom Texture Loading - Asynchroniczne ładowanie własnych tekstur + + Async custom texture loading + Asynchroniczne ładowanie customowych tekstur @@ -1201,91 +1202,111 @@ Czy chcesz zignorować błąd i kontynuować? - General - Ogólne + Updates + Aktualizacje - Confirm exit while emulation is running - Potwierdź wyjście, gdy emulator jest uruchomiony - - - - Pause emulation when in background - Wstrzymaj emulowanie w tle - - - - Mute audio when in background - Wycisz dźwięk w tle - - - - Hide mouse on inactivity - Ukryj mysz przy braku aktywności - - - - Enable Gamemode - Włącz tryb gry - - - Check for updates Sprawdź dostępność aktualizacji - + + Update Channel + Kanał Aktualizacji + + + + Stable + Stabilny + + + + Prerelease + Wersja próbna + + + + General + Ogólne + + + + Confirm exit while emulation is running + Potwierdź wyjście, gdy emulator jest uruchomiony + + + + Pause emulation when in background + Wstrzymaj emulowanie w tle + + + + Mute audio when in background + Wycisz dźwięk w tle + + + + Hide mouse on inactivity + Ukryj mysz przy braku aktywności + + + + Enable Gamemode + Włącz tryb gry + + + Emulation Emulacja - + Use global emulation speed Użyj ogólnej prędkości emulacji - - Set emulation speed: - Ustaw prędkość emulacji: + + Set emulation speed + Ustaw prędkość emulacji - - Emulation Speed: - Szybkość emulowania: + + Emulation Speed + Szybkość Emulacji - + Turbo Speed Limit: Limit prędkości Turbo: - + Screenshots Zrzuty ekranu - + Use global screenshot path Użyj ogólnej ścieżki zrzutu ekranu - + Set screenshot path: Ustaw ścieżkę zrzutu ekranu: - + Save Screenshots To Zapisz zrzuty ekranu do - + ... ... - + Reset All Settings Zresetuj Wszystkie Ustawienia @@ -1293,8 +1314,8 @@ Czy chcesz zignorować błąd i kontynuować? - - + + unthrottled nieograniczony @@ -1304,12 +1325,12 @@ Czy chcesz zignorować błąd i kontynuować? Wybierz katalog zrzutów ekranu - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? Czy na pewno chcesz<b>przywrócić ustawienia</b>i zamknąć Azahar? @@ -1363,12 +1384,12 @@ Czy chcesz zignorować błąd i kontynuować? - SPIR-V Shader Generation + SPIR-V shader generation Generowanie shaderów SPIR-V - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer Wyłącz optymalizator GLSL -> SPIR-V @@ -1388,7 +1409,7 @@ Czy chcesz zignorować błąd i kontynuować? - Enable Hardware Shader + Enable hardware shader Aktywuj Shader Sprzętowy @@ -1398,7 +1419,7 @@ Czy chcesz zignorować błąd i kontynuować? - Accurate Multiplication + Accurate multiplication Dokładne Mnożenie @@ -1408,7 +1429,7 @@ Czy chcesz zignorować błąd i kontynuować? - Enable Shader JIT + Enable shader JIT Aktywuj Shader JIT @@ -1418,17 +1439,17 @@ Czy chcesz zignorować błąd i kontynuować? - Enable Async Shader Compilation + Enable async shader compilation Włącz asynchroniczną kompilację shaderów - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Wykonywanie rejestracji na oddzielnych wątkach. Poprawia wydajność podczas korzystania z Vulkan w większości aplikacjach.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + <html><head/><body><p>Wykonywuje renderowanie w oddzielnych wątkach. Poprawia wydajność podczas korzystania z Vulkan w większości aplikacji. Zwiększa opóźnienie wprowadzania o około 1 klatkę.</p></body></html> - Enable Async Presentation + Enable async presentation Włącz rejestr asynchroniczną @@ -1468,13 +1489,13 @@ Czy chcesz zignorować błąd i kontynuować? - Use Disk Shader Cache + Use disk shader cache Użyj pamięci podręcznej shaderów na dysku - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync zapobiega efektowi rozdarcia ekranu, ale niektóre karty graficzne mają niższą wydajność z włączoną funkcją VSync. Pozostaw ją włączoną, jeśli nie zauważysz różnicy w wydajności. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + <html><head/><body><p>VSync zapobiega efektowi rozdarcia ekranu, ale niektóre karty graficzne mają niższą wydajność z włączoną funkcją VSync. Pozostaw ją włączoną, jeśli nie zauważysz różnicy w wydajności.</p></body></html> @@ -1482,22 +1503,32 @@ Czy chcesz zignorować błąd i kontynuować? Włącz V-Sync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + <html><head/><body><p>Po włączeniu tej opcji, wykrywa ona, kiedy częstotliwość odświeżania ekranu jest niższa niż w 3DS, i w takim przypadku, automatycznie wyłącza VSync, żeby uniknąć zmniejszenia prędkości emulacji poniżej 100%.</p></body></html> + + + + Enable display refresh rate detection + Włącz wykrywanie częstotliwości odświeżania wyświetlacza + + + Use global Użyj ustawień ogólnych - + Use per-application Użyj dla każdej aplikacji - - Delay application render thread: - Opóźnienie renderowania wątku aplikacji: + + Delay Application Render Thread + Opóźnij renderowanie wątku aplikacji: - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>Opóźnia emulowany wątek renderowania aplikacji o określoną liczbę milisekund za każdym razem, gdy wysyła polecenia renderowania do GPU.</p><p>Dostosuj tę funkcję w (bardzo niewielu) aplikacjach z dynamiczną liczbą klatek na sekundę, aby naprawić problemy z wydajnością.</p></body></html> @@ -1982,12 +2013,12 @@ Czy chcesz zignorować błąd i kontynuować? - Swap Screens + Swap screens Zamień Ekrany - Rotate Screens Upright + Rotate screens upright Obróć ekrany w pozycji pionowej @@ -2104,8 +2135,8 @@ Czy chcesz zignorować błąd i kontynuować? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>% krycia dolnego ekranu (tylko OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + <html><head/><body><p>krycia dolnego ekranu %</p></body></html> @@ -2276,8 +2307,8 @@ Czy chcesz zignorować błąd i kontynuować? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Dowiedz się więcej</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Dowiedz się więcej</span></a> @@ -2452,7 +2483,7 @@ Czy chcesz zignorować błąd i kontynuować? - Use Virtual SD + Use virtual SD card Użyj Wirtualnej karty SD @@ -2462,8 +2493,8 @@ Czy chcesz zignorować błąd i kontynuować? - Use Custom Storage - Użyj niestandardowego przechowywania + Use custom storage location + Użyj customowej lokalizacji przechowywania @@ -2493,6 +2524,16 @@ Czy chcesz zignorować błąd i kontynuować? SDMC Directory Katalog SDMC + + + Compress installed CIA content + Skompresuj zainstalowaną zawartość CIA + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + <html><head/><body><p>Kompresuje zawartość plików CIA zainstalowanych na emulowanej karcie SD. Ma wpływ tylko na zawartość CIA, która jest instalowana, gdy ustawienie jest włączone.</p></body></html> + Select NAND Directory @@ -2540,8 +2581,8 @@ funkcji online (jeśli są zainstalowane) - Region: - Region: + Region + Region @@ -2549,326 +2590,338 @@ funkcji online (jeśli są zainstalowane) Wybór automatyczny - + + Apply region free patch to +installed applications. + Zastosuj łatkę bez regionu +do zainstalowanych aplikacji. + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + Naprawia region zainstalowanych aplikacji, aby były one wolne od ograniczeń regionalnych, dzięki czemu zawsze pojawiają się w menu głównym. + + + Username Nazwa Użytkownika - + Birthday Urodziny - + January Styczeń - + February Luty - + March Marzec - + April Kwiecień - + May Maj - + June Czerwiec - + July Lipiec - + August Sierpień - + September Wrzesień - + October Październik - + November Listopad - + December Grudzień - + Language Język - + Note: this can be overridden when region setting is auto-select Uwaga: może zostać nadpisane jeśli region jest ustawiony na "Wybór automatyczny" - + Japanese (日本語) Japoński (日本語) - + English Angielski (English) - + French (français) Francuzki (français) - + German (Deutsch) Niemiecki (Deutsch) - + Italian (italiano) Włoski (italiano) - + Spanish (español) Hiszpański (español) - + Simplified Chinese (简体中文) Chiński Uproszczony (简体中文) - + Korean (한국어) Koreański (한국어) - + Dutch (Nederlands) Niderlandzki (Nederlands) - + Portuguese (português) Portugalski (português) - + Russian (Русский) Rosyjski (Русский) - + Traditional Chinese (正體中文) Chiński Tradycyjny (正體中文) - + Sound output mode Tryb wyjścia dźwięku - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Kraj - + Clock Zegar - + System Clock Zegar Systemowy - + Fixed Time Stały Czas - + Startup time Czas Uruchomienia - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time Przesunięcie czasu - + days dni - + HH:mm:ss HH:mm:ss - + Initial System Ticks Startowe tyknięcia systemu - + Random Losowe - + Fixed Naprawione - + Initial System Ticks Override Nadpisanie początkowych tyknięć systemu - + Play Coins Monety gry - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>Liczba kroków na godzinę podawana przez krokomierz. Wartość może wynosić od 0 do 65,535. - + Pedometer Steps per Hour Liczba kroków krokomierza na godzinę - + Run System Setup when Home Menu is launched Uruchom ustawienia systemu po uruchomieniu Home Menu - + Console ID: ID konsoli: - - + + Regenerate Regeneruj - + MAC: MAC: - - 3GX Plugin Loader: - Moduł ładowania wtyczki 3GX: + + 3GX Plugin Loader + Wtyczka 3GX Loader - + Enable 3GX plugin loader Włącz ładowanie wtyczki 3GX - + Allow applications to change plugin loader state Zezwól aplikacjom na zmianę stanu programu ładującego wtyczki - + Real Console Unique Data Unikalne Dane Rzeczywistej Konsoli - + Your real console is linked to Azahar. Twoja rzeczywista konsola jest połączona z Azahar. - + Unlink Odłącz - + OTP OTP - - - - + + + + Choose Wybierz - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. Ustawienia systemowe są dostępne tylko wtedy, gdy aplikacja nie jest uruchomiona @@ -3578,76 +3631,76 @@ funkcji online (jeśli są zainstalowane) Plik sed (*.sed);;Wszystkie pliki (*.*) - - + + Console ID: 0x%1 ID konsoli: 0x%1 - - + + MAC: %1 MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? To zastąpi twojego obecnego wirtualnego 3DS. Odzyskanie twojego obecnego 3DS będzie niemożliwe. To może spowodować niespodziewane efekty w aplikacjach. Operacja może się nie powieść jeżeli korzystasz z przestarzałej konfiguracji zapisów aplikacji. Kontynuować? - - - + + + Warning Ostrzeżenie - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? Spowoduje to zastąpienie bieżącego adresu MAC nowym. Nie zaleca się wykonywania tej czynności, jeśli adres MAC został uzyskany z rzeczywistej konsoli za pomocą narzędzia konfiguracyjnego. Kontynuować? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? Ta czynność spowoduje odłączenie twojej rzeczywistej konsoli od Azahar, z następującymi konsekwencjami: <br><ul><li>Twój OTP, SecureInfo i LocalFriendCodeSeed zostaną usunięte z Azahar.</li><li>Lista znajomych zostanie zresetowana, a użytkownik zostanie wylogowany z konta NNID/PNID.</li><li>Pliki systemowe i tytuły z eshopu uzyskane za pośrednictwem Azahar staną się niedostępne do czasu ponownego połączenia z tą samą konsolą (dane zapisu nie zostaną utracone).</li></ul><br>Kontynuować? - + Invalid country for configured region Nieprawidłowy kraj dla skonfigurowanego regionu - + Invalid country for console unique data Nieprawidłowy kraj dla unikalnych danych konsoli - + Status: Loaded Status: Wczytano - + Status: Loaded (Invalid Signature) Status: Wczytano (Nieprawidłowy znak) - + Status: Loaded (Region Changed) Status: Załadowano (Zmieniono region) - + Status: Not Found Status: Nie znaleziono - + Status: Invalid Status: Nieprawidłowy - + Status: IO Error Status: Błąd IO @@ -3763,12 +3816,12 @@ Przeciągnij punkty, aby zmienić ich położenie lub kliknij dwukrotnie pola ta - Interface language: + Interface Language Język Interfejsu - Theme: + Theme Motyw: @@ -3778,7 +3831,7 @@ Przeciągnij punkty, aby zmienić ich położenie lub kliknij dwukrotnie pola ta - Icon Size: + Icon Size Rozmiar Ikony: @@ -3799,7 +3852,7 @@ Przeciągnij punkty, aby zmienić ich położenie lub kliknij dwukrotnie pola ta - Row 1 Text: + Row 1 Text Pierwszy wiersz tekstu: @@ -3834,17 +3887,17 @@ Przeciągnij punkty, aby zmienić ich położenie lub kliknij dwukrotnie pola ta - Row 2 Text: + Row 2 Text Drugi wiersz tekstu: - Hide Titles without Icon + Hide titles without icon Ukryj tytuły bez ikon - Single Line Mode + Single line mode Tryb jednoliniowy @@ -3854,7 +3907,7 @@ Przeciągnij punkty, aby zmienić ich położenie lub kliknij dwukrotnie pola ta - Show Advanced Frame Time Info + Show advanced frame time info Pokaż zaawansowane informacje o liczbie klatek @@ -3937,12 +3990,12 @@ Przeciągnij punkty, aby zmienić ich położenie lub kliknij dwukrotnie pola ta DirectConnectWindow - + Connecting Łączenie - + Connect Połączono @@ -4062,471 +4115,511 @@ Sprawdź instalację FFmpeg używaną do kompilacji. GMainWindow - + No Suitable Vulkan Devices Detected Nie wykryto odpowiednich urządzeń Vulkan - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. Podczas uruchamiania systemu uruchamianie Vulkan nie powiodło się.<br/>Twój procesor graficzny może nie obsługiwać Vulkan 1.1 lub nie masz najnowszego sterownika graficznego. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. Bieżąca prędkość ruchu Artic Base. Wyższe wartości oznaczają większe obciążenia transferowe. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Obecna szybkość emulacji. Wartości większe lub mniejsze niż 100 % oznaczają, że emulacja jest szybsza lub wolniejsza niż 3DS - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. Jak wiele klatek na sekundę aplikacja wyświetla w tej chwili. Ta wartość będzie się różniła między aplikacji, jak również między scenami w aplikacji. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Czas potrzebny do emulacji klatki 3DS, nie zawiera limitowania klatek oraz v-sync. Dla pełnej prędkości emulacji, wartość nie powinna przekraczać 16.67 ms. - + MicroProfile (unavailable) MicroProfile (niedostępne) - + Clear Recent Files Wyczyść Ostatnio Używane - + &Continue &Kontynuuj - + &Pause &Wstrzymaj - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar jest w trakcie uruchamiania aplikację - - + + Invalid App Format Nieprawidłowy format aplikacji - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Twój format aplikacji nie jest obsługiwany.<br/>Postępuj zgodnie z instrukcjami, aby ponownie zrzucić <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>kartridże z grami</a> lub <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>zainstalowane tytuły</a>. - + App Corrupted Aplikacja jest uszkodzona - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Twoja aplikacja jest uszkodzona. <br/>Postępuj zgodnie z instrukcjami, aby ponownie zrzucić <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>kartridże z grami</a> lub <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>zainstalowane tytuły</a>. - + App Encrypted Aplikacja jest zaszyfrowana - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Twoja aplikacja jest zaszyfrowana. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Więcej informacji można znaleźć na naszym blogu.</a> - + Unsupported App Nieobsługiwana aplikacja - + GBA Virtual Console is not supported by Azahar. Wirtualnej konsola GBA nie są obsługiwana przez Azahar. - - + + Artic Server Serwer Artic - + + Invalid system mode + Nieprawidłowy moduł systemu + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + Aplikacje dostępne wyłącznie na konsoli New 3DS nie mogą być uruchamiane bez włączenia trybu New 3DS. + + + Error while loading App! Błąd podczas ładowania aplikacji! - + An unknown error occurred. Please see the log for more details. Wystąpił nieznany błąd. Więcej informacji można znaleźć w logu. - + CIA must be installed before usage CIA musi być zainstalowana przed użyciem - + Before using this CIA, you must install it. Do you want to install it now? Przed użyciem CIA należy ją zainstalować. Czy chcesz zainstalować ją teraz? - + Quick Load Szybkie wczytywanie - + Quick Save Szybkie zapisywanie - - + + Slot %1 Slot %1 - + %2 %3 %2 %3 - + Quick Save - %1 Szybkie zapisywanie - %1 - + Quick Load - %1 Szybkie wczytywanie - %1 - + Slot %1 - %2 %3 Slot %1 - %2 %3 - + Error Opening %1 Folder Błąd podczas otwierania folderu %1 - - + + Folder does not exist! Folder nie istnieje! - + Remove Play Time Data Usuń dane czasu odtwarzania - + Reset play time? Zresetować czas gry? - - - - + + + + Create Shortcut Utwórz skrót - + Do you want to launch the application in fullscreen? Czy chcesz uruchomić aplikacje na pełnym ekranie? - + Successfully created a shortcut to %1 Pomyślnie utworzono skrót do %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Spowoduje to utworzenie skrótu do bieżącego obrazu aplikacji. Może to nie działać dobrze po aktualizacji. Kontynuować? - + Failed to create a shortcut to %1 Nie udało się utworzyć skrótu do %1 - + Create Icon Stwórz ikonę - + Cannot create icon file. Path "%1" does not exist and cannot be created. Nie można utworzyć pliku ikony. Ścieżka "%1" nie istnieje i nie można jej utworzyć. - + Dumping... Zrzucanie... - - + + Cancel Anuluj - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. Nie można zrzucić podstawowego RomFS. Szczegółowe informacje można znaleźć w logu. - + Error Opening %1 Błąd podczas otwierania %1 - + Select Directory Wybierz Folder - + Properties Właściwości - + The application properties could not be loaded. Nie można wczytać właściwości aplikacji. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Pliki wykonywalne 3DS (%1);;Wszystkie pliki (*.*) - + Load File Załaduj Plik - - + + Set Up System Files Konfiguracja plików systemowych - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> <p>Azahar potrzebuje plików z rzeczywistej konsoli, aby móc korzystać z niektórych jej funkcji.<br>Możesz uzyskać te pliki za pomocą <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Uwagi:<ul><li><b>Ta operacja zainstaluje unikalne pliki konsoli do Azahar, nie udostępniaj swoich folderów użytkownika lub nand<br>po wykonaniu procesu konfiguracji!</b></li><li>Podczas procesu konfiguracji Azahar połączy się z konsolą, na której uruchomione jest narzędzie instalacyjne.<br>Konsolę można później odłączyć w zakładce System w menu konfiguracji emulatora.</li><li>Nie korzystaj jednocześnie z Azahar i konsoli 3DS po skonfigurowaniu plików systemowych,<br>bo może to spowodować błędy. </li><li>Old 3DS jest wymagany do działania konfiguracji New 3DS (zalecane jest wykonanie obu tych konfiguracji).</li><li>Oba tryby konfiguracji będą działać niezależnie od modelu konsoli, na której uruchomiono narzędzie konfiguracyjne.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: Wprowadź adres narzędzia konfiguracyjnego Azahar Artic: - + <br>Choose setup mode: <br>Wybierz tryb konfiguracji: - + (ℹ️) Old 3DS setup (ℹ️) Konfiguracja Old 3DS - - + + Setup is possible. Konfiguracja jest możliwa. - + (⚠) New 3DS setup (⚠) Konfiguracja New 3DS - + Old 3DS setup is required first. Najpierw wymagana jest konfiguracja Old 3DS. - + (✅) Old 3DS setup (✅) Konfiguracja Old 3DS - - + + Setup completed. Konfiguracja została zakończona. - + (ℹ️) New 3DS setup (ℹ️) Konfiguracja New 3DS - + (✅) New 3DS setup (✅) Konfiguracja New 3DS - + The system files for the selected mode are already set up. Reinstall the files anyway? Pliki systemowe dla wybranego trybu są już skonfigurowane. Czy mimo to chcesz ponownie zainstalować pliki? - + Load Files Załaduj Pliki - - 3DS Installation File (*.CIA*) - Plik Instalacyjny 3DS'a (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + Plik Instalacyjny 3DS (*.cia *.zcia) - + + + All Files (*.*) Wszystkie Pliki (*.*) - + Connect to Artic Base Połącz z Artic Base - + Enter Artic Base server address: Wprowadź adres serwera Artic Base: - + %1 has been installed successfully. %1 został poprawnie zainstalowany. - + Unable to open File Nie można otworzyć Pliku - + Could not open %1 Nie można otworzyć %1 - + Installation aborted Instalacja przerwana - + The installation of %1 was aborted. Please see the log for more details Instalacja %1 została przerwana. Sprawdź logi, aby uzyskać więcej informacji. - + Invalid File Niepoprawny Plik - + %1 is not a valid CIA %1 nie jest prawidłowym plikiem CIA - + CIA Encrypted Plik CIA jest zaszyfrowany - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Twój plik CIA jest zaszyfrowany.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Więcej informacji można znaleźć na naszym blogu.</a> - + Unable to find File Nie można odnaleźć pliku - + Could not find %1 Nie można odnaleźć %1 - + + + + + Z3DS Compression + Kompresuj pliki Z3DS + + + + Failed to compress some files, check log for details. + Nie udało się skompresować niektórych plików, sprawdź log, aby uzyskać szczegółowe informacje. + + + + Failed to decompress some files, check log for details. + Nie udało się rozpakować niektórych plików. Szczegółowe informacje można znaleźć w logu. + + + + All files have been compressed successfully. + Wszystkie pliki zostały pomyślnie skompresowane. + + + + All files have been decompressed successfully. + Wszystkie pliki zostały pomyślnie zdekompresowane. + + + Uninstalling '%1'... Odinstalowywanie '%1'... - + Failed to uninstall '%1'. Nie udało się odinstalować '%1'. - + Successfully uninstalled '%1'. Pomyślnie odinstalowano '%1'. - + File not found Nie znaleziono pliku - + File "%1" not found Nie znaleziono pliku "%1" - + Savestates Savestate.y - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! @@ -4535,86 +4628,86 @@ Use at your own risk! Używaj na własne ryzyko! - - - + + + Error opening amiibo data file Błąd podczas otwierania pliku danych amiibo - + A tag is already in use. Tag jest już używany. - + Application is not looking for amiibos. Aplikacja nie szuka amiibo. - + Amiibo File (%1);; All Files (*.*) Plik Amiibo (%1);; Wszystkie pliki (*.*) - + Load Amiibo Załaduj Amiibo - + Unable to open amiibo file "%1" for reading. Nie można otworzyć pliku amiibo "%1" do odczytu. - + Record Movie Nagraj Film - + Movie recording cancelled. Nagrywanie zostało przerwane. - - + + Movie Saved Zapisano Film - - + + The movie is successfully saved. Film został poprawnie zapisany. - + Application will unpause Aplikacja zostanie wstrzymana - + The application will be unpaused, and the next frame will be captured. Is this okay? Aplikacja zostanie zatrzymana, a następna klatka zostanie przechwycona. Czy jest to w porządku? - + Invalid Screenshot Directory Nieprawidłowy katalog zrzutów ekranu - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. Nie można utworzyć określonego katalogu zrzutów ekranu. Ścieżka zrzutu ekranu zostanie przywrócona do wartości domyślnej. - + Could not load video dumper Nie można załadować zrzutu filmu - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4627,215 +4720,265 @@ Aby zainstalować FFmpeg do Azahar, naciśnij Otwórz i wybierz katalog FFmpeg. Aby wyświetlić poradnik dotyczący instalacji FFmpeg, naciśnij Pomoc. - + + Load 3DS ROM Files + Załaduj pliki ROMów 3DS + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + Pliki ROMów 3DS (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + 3DS Compressed ROM File (*.%1) + Skompresowany plik ROMu 3DS (*.%1) + + + + Save 3DS Compressed ROM File + Zapisz skompresowany plik ROMu 3DS + + + + Select Output 3DS Compressed ROM Folder + Wybierz folder wyjściowy skompresowanych plików ROMów 3DS + + + + Load 3DS Compressed ROM Files + Wczytaj skompresowane pliki ROMów 3DS + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + Skompresowane pliki ROMów 3DS (*.zcia *zcci *z3dsx *zcxi) + + + + 3DS ROM File (*.%1) + Plik ROMu 3DS (*.%1) + + + + Save 3DS ROM File + Zapisz plik ROMu 3DS + + + + Select Output 3DS ROM Folder + Wybierz folder wyjściowy ROMów 3DS + + + Select FFmpeg Directory Wybierz katalog FFmpeg - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. W podanym katalogu FFmpeg brakuje %1. Upewnij się, że wybrany został poprawny katalog. - + FFmpeg has been sucessfully installed. FFmpeg został pomyślnie zainstalowany. - + Installation of FFmpeg failed. Check the log file for details. Instalacja FFmpeg nie powiodła się. Sprawdź plik dziennika, aby uzyskać szczegółowe informacje. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. Nie można uruchomić zrzutu filmu.<br>Upewnij się, że koder filmu jest poprawnie skonfigurowany.<br>Szczegółowe informacje można znaleźć w logu. - + Recording %1 Nagrywanie %1 - + Playing %1 / %2 Odtwarzanie %1 / %2 - + Movie Finished Film ukończony - + (Accessing SharedExtData) (Uzyskiwanie dostępu do SharedExtData) - + (Accessing SystemSaveData) (Uzyskiwanie dostępu do SystemSaveData) - + (Accessing BossExtData) (Uzyskiwanie dostępu do BossExtData) - + (Accessing ExtData) (Uzyskiwanie dostępu do ExtData) - + (Accessing SaveData) (Uzyskiwanie dostępu do SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 Ruch Artic: %1 %2%3 - + Speed: %1% Prędkość: %1% - + Speed: %1% / %2% Prędkość: %1% / %2% - + App: %1 FPS Aplikacja: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) Klatka: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Klatka: %1 ms - + VOLUME: MUTE GŁOŚNOŚĆ: WYCISZONA - + VOLUME: %1% Volume percentage (e.g. 50%) GŁOŚNOŚĆ: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - Brak %1 . <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Zrzuć archiwa systemowe</a>. <br/>Kontynuowanie emulacji może spowodować awarie i błędy. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + Brakuje %1. Prosimy o <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>zrzucenie archiwów systemowych</a>.<br/>Dalsze korzystanie z emulacji może spowodować awarie i błędy. - + A system archive Archiwum systemu - + System Archive Not Found Archiwum Systemowe nie zostało odnalezione - + System Archive Missing Brak archiwum systemu - + Save/load Error Błąd zapisywania/wczytywania - + Fatal Error Krytyczny Błąd - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Wystąpił krytyczny błąd. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Sprawdź szczegóły w logu</a>.<br/>Kontynuowanie emulacji może spowodować awarie i błędy. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + Wystąpił krytyczny błąd. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Sprawdź szczegóły w logu</a>.<br/>Dalsze korzystanie z emulacji może spowodować awarie i błędy. - + Fatal Error encountered Wystąpił błąd krytyczny - + Continue Kontynuuj - + Quit Application Wyjdź z aplikacji - + OK OK - + Would you like to exit now? Czy chcesz teraz wyjść? - + The application is still running. Would you like to stop emulation? Aplikacja jest nadal uruchomiona. Czy chcesz przerwać emulację? - + Playback Completed Odtwarzanie Zakończone - + Movie playback completed. Odtwarzanie filmu zostało zakończone. - + Update Available Dostępna jest aktualizacja - + Update %1 for Azahar is available. Would you like to download it? Aktualizacja %1 dla Azahar jest dostępna. Czy chcesz ją pobrać? - + Primary Window Główne okno - + Secondary Window Dodatkowe okno @@ -4898,42 +5041,42 @@ Czy chcesz ją pobrać? GRenderWindow - + OpenGL not available! OpenGL jest niedostępny! - + OpenGL shared contexts are not supported. Współdzielone konteksty OpenGL nie są obsługiwane. - + Error while initializing OpenGL! Błąd podczas uruchamiania OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Twój procesor graficzny może nie obsługiwać OpenGL lub nie masz najnowszego sterownika graficznego. - + Error while initializing OpenGL 4.3! Błąd podczas uruchamiania OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Twój procesor graficzny może nie obsługiwać OpenGL 4.3 lub nie masz najnowszego sterownika graficznego.<br><br>Render GL:<br>%1 - + Error while initializing OpenGL ES 3.2! Błąd podczas uruchamiania OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Twój procesor graficzny może nie obsługiwać OpenGL ES 3.2 lub nie masz najnowszego sterownika graficznego.<br><br>Render GL:<br>%1 @@ -4941,175 +5084,185 @@ Czy chcesz ją pobrać? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - WAŻNE: Zaszyfrowane pliki i pliki .3ds nie są już obsługiwane. Konieczne może być odszyfrowanie i/lub zmiana nazwy pliku na .cci. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Więcej informacji.</a> - - - - Don't show again - Nie pokazuj tego ponownie - - - - + + Compatibility Kompatybilność - - + + Region Region - - + + File type Typ pliku - - + + Size Rozmiar - - + + Play time Czas gry - + Favorite Ulubione - + + Eject Cartridge + Wyjmij Kartridż + + + + Insert Cartridge + Włóż Kartridż + + + Open Otwórz - + Application Location Lokalizacja aplikacji - + Save Data Location Lokalizacja zapisywanych danych - + Extra Data Location Lokalizacja dodatkowych danych - + Update Data Location Zaktualizuj lokalizację danych - + DLC Data Location Lokalizacja danych DLC - + Texture Dump Location Lokalizacja zrzutu tekstur - + Custom Texture Location Lokalizacja niestandardowych tekstur - + Mods Location Lokalizacja modów - + Dump RomFS Zrzuć RomFS - + Disk Shader Cache Pamięć podręczna shaderów na dysku - + Open Shader Cache Location Otwórz lokalizację pamięci podręcznej shaderów - + Delete OpenGL Shader Cache Usuń pamięć podręczną shaderów OpenGL - + + Delete Vulkan Shader Cache + Usuń pamięć podręczną shaderów Vulkan + + + Uninstall Odinstaluj - + Everything Wszystko - + Application Aplikacja - + Update Aktualizacje - + DLC DLC - + Remove Play Time Data Usuń dane czasu gry - + Create Shortcut Utwórz skrót - + Add to Desktop Dodaj do pulpitu - + Add to Applications Menu Dodaj do menu aplikacji - + + Stress Test: App Launch + Analiza wydajnościowa: uruchomienie aplikacji + + + Properties Właściwości - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. @@ -5118,64 +5271,64 @@ This will delete the application if installed, as well as any installed updates Spowoduje to usunięcie aplikacji, jeśli jest zainstalowana, a także wszelkich zainstalowanych aktualizacji lub DLC. - - + + %1 (Update) %1 (Aktualizacja) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? Czy na pewno chcesz odinstalować '%1'? - + Are you sure you want to uninstall the update for '%1'? Czy na pewno chcesz odinstalować aktualizacje '%1'? - + Are you sure you want to uninstall all DLC for '%1'? Czy na pewno chcesz odinstalować DLC '%1'? - + Scan Subfolders Przeszukaj Podkatalogi - + Remove Application Directory Usuń Katalog Aplikacji - + Move Up Przesuń w górę - + Move Down Przesuń w dół - + Open Directory Location Otwórz lokalizację katalogu - + Clear Wyczyść - + Name Nazwa @@ -5183,82 +5336,82 @@ Spowoduje to usunięcie aplikacji, jeśli jest zainstalowana, a także wszelkich GameListItemCompat - + Perfect Idealna - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. Aplikacja działa bez zarzutu, bez błędów graficznych lub dźwiękowych. Nie potrzebuje żadnych obejść ani poprawek. - + Great Świetna - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. Aplikacja działa z pomniejszymi błędami dźwiękowymi lub graficznymi, jest grywalna od początku do końca. Może wymagać kilku obejść/poprawek. - + Okay W porządku - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. Aplikacja działa z większymi błędami dźwiękowymi lub graficznymi, ale jest grywalna od początku do końca. Może wymagać kilku obejść/poprawek. - + Bad Zła - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. Gra działa z większymi błędami dźwiękowymi lub graficznymi. Niemożliwe jest przejście konkretnych miejsc nawet z obejściami. - + Intro/Menu Intro/Menu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. Gra jest całkowicie niegrywalna z uwagi na poważne błędy graficzne lub dźwiękowe. Działa jedynie ekran startowy. - + Won't Boot Nie uruchamia się - + The app crashes when attempting to startup. Aplikacja zawiesza się przy próbie uruchomienia - + Not Tested Nieprzetestowana - + The app has not yet been tested. Aplikacja nie została jeszcze przetestowana. @@ -5266,7 +5419,7 @@ Działa jedynie ekran startowy. GameListPlaceholder - + Double-click to add a new folder to the application list Kliknij dwukrotnie, aby dodać nowy folder do listy aplikacji. @@ -5274,27 +5427,27 @@ Działa jedynie ekran startowy. GameListSearchField - + of z - + result wynik - + results wyniki - + Filter: Filtr: - + Enter pattern to filter Wprowadź wzór filtra @@ -5302,47 +5455,47 @@ Działa jedynie ekran startowy. GameRegion - + Japan Japonia - + North America Ameryka Północna - + Europe Europa - + Australia Australia - + China Chiny - + Korea Korea - + Taiwan Tajwan - + Invalid region Nieprawidłowy region - + Region free Bez ograniczenia regionalnego @@ -5622,87 +5775,87 @@ Działa jedynie ekran startowy. Indeks Cyklu: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Adresy Rejestrów: %1, %2 - + Compare Result: %1, %2 Porównanie Wyników: %1, %2 - + Static Condition: %1 Warunek Statyczny: %1 - + Dynamic Conditions: %1, %2 Warunki Dynamiczne: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Parametry Pętli: %1 (powtórzeń), %2 (inicjacji), %3 (inkrementacji), %4 - + Instruction offset: 0x%1 Przesunięcie Instrukcji: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (ostatnia instrukcja) @@ -5927,24 +6080,24 @@ Komunikat debugowania: Przygotowanie shaderów %1 / %2 - - Loading Shaders %1 / %2 - Ładowanie shaderów %1 / %2 + + Loading %3 %1 / %2 + Ładowanie %3 %1 / %2 - + Launching... Uruchamianie... - + Now Loading %1 Aktualnie Ładowanie %1 - + Estimated Time %1 Oszacowany Czas %1 @@ -6003,32 +6156,32 @@ Komunikat debugowania: Hasło: - + Room Name Nazwa Pokoju - + Preferred Application Preferowana aplikacja - + Host Gospodarz - + Players Graczy - + Refreshing Odświeżanie - + Refresh List Odśwież Listę @@ -6111,342 +6264,352 @@ Komunikat debugowania: Film - + Help Pomoc - + Load File... Załaduj Plik... - + Install CIA... Instaluj CIA... - + Connect to Artic Base... Podłącz do Artic Base... - + Set Up System Files... Konfiguracja plików systemowych - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit Wyjdź - + Pause Wstrzymaj - + Stop Zatrzymaj - + Save Zapisz - + Load Wczytaj - + FAQ Najczęściej zadawane pytania - + About Azahar O Azahar - + Single Window Mode Tryb Pojedynczego Okna - + Save to Oldest Slot Zapisz w najstarszym slocie - + Quick Save Szybkie zapisywanie - + Load from Newest Slot Wczytaj z najnowszego slotu - + Quick Load Szybkie wczytywanie - + Configure... Skonfiguruj... - + Display Dock Widget Headers Wyświetl Nagłówki Widgetów. - + Show Filter Bar Pokaż Pasek Filtrowania - + Show Status Bar Pokaż Pasek Statusu - + Create Pica Surface Viewer Stwórz Podgląd Powierzchni Pica - + Record... Nagraj... - + Play... Odtwórz... - + Close Zamknij - + Save without Closing Zapisz bez zamykania - + Read-Only Mode Tryb tylko do odczytu - + Advance Frame Przesuwanie Klatek - + Capture Screenshot Przechwyć zrzut ekranu - + Dump Video Zrzuć Film + Compress ROM File... + Kompresja pliku ROM... + + + + Decompress ROM File... + Dekompresja pliku ROM... + + + Browse Public Rooms Przeglądaj Publiczne Pokoje - + Create Room Stwórz Pokój - + Leave Room Opóść Pokój - + Direct Connect to Room Bezpośrednie Połączenie z Pokojem - + Show Current Room Pokaż Aktualny Pokój - + Fullscreen Pełny Ekran - + Open Log Folder Otwórz folder logu - + Opens the Azahar Log folder Otwiera folder logu Azahar - + Default Domyślny - + Single Screen Pojedynczy Ekran - + Large Screen Duży Ekran - + Side by Side Obok Siebie - + Separate Windows Oddzielne okna - + Hybrid Screen Ekran hybrydowy - + Custom Layout Niestandardowy układ - + Top Right Prawy górny róg - + Middle Right Środkowy prawy - + Bottom Right Prawy dolny róg - + Top Left Lewo górny róg - + Middle Left Środkowy lewy - + Bottom Left Lewy dolny róg - + Above Powyżej - + Below Poniżej - + Swap Screens Zamień Ekrany - + Rotate Upright Obrót w pionie - + Report Compatibility Zgłoś Kompatybilność - + Restart Zrestartuj - + Load... Wczytaj... - + Remove Usuń - + Open Azahar Folder Otwórz folder Azahar - + Configure Current Application... Konfiguruj bieżącą aplikacje... @@ -7020,32 +7183,32 @@ Możliwe, że opuścił pokój. %1 (0x%2) - + Unsupported encrypted application Nieobsługiwana zaszyfrowana aplikacja - + Invalid region Nieprawidłowy region - + Installed Titles Zainstalowane Gry - + System Titles Tytuły systemowe - + Add New Application Directory Dodaj nowy katalog aplikacji - + Favorites Ulubione diff --git a/dist/languages/pt_BR.ts b/dist/languages/pt_BR.ts index d22c82cf8..8c78ab5d9 100644 --- a/dist/languages/pt_BR.ts +++ b/dist/languages/pt_BR.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,8 +298,8 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - Emulation: - Emulação: + Emulation + Emulação @@ -328,8 +328,8 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Este efeito de pós-processamento ajusta a velocidade do áudio para acompanhar a velocidade de emulação e ajuda a evitar cortes no áudio. No entanto, isto aumenta a latência do áudio. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + <html><head/><body><p>Este efeito de pós-processamento ajusta a velocidade do áudio para corresponder à velocidade de emulação e ajuda a evitar engasgos no áudio. Isso, no entanto, aumenta a latência de áudio.</p></body></html> @@ -338,8 +338,8 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Dimensiona a velocidade de reprodução de áudio para compensar quedas na taxa de quadros da emulação. Isso significa que o áudio será reproduzido em velocidade máxima mesmo quando a taxa de quadros do aplicativo estiver baixa. Pode causar problemas de dessincronização de áudio. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + <html><head/><body><p>Escala a velocidade de reprodução do áudio para compensar quedas na taxa de quadros da emulação. Isso significa que o áudio será reproduzido em velocidade total mesmo quando a taxa de quadros do aplicativo estiver baixa. Pode causar problemas de dessincronização de áudio.</p></body></html> @@ -403,6 +403,7 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço + Camera Câmera @@ -414,8 +415,8 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - Camera to configure: - Câmera a configurar: + Camera to Configure + Câmera a configurar @@ -435,8 +436,8 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - Camera mode: - Modo de câmera: + Camera mode + Modo da câmera @@ -456,8 +457,8 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - Camera position: - Posição da câmera: + Camera position + Posição da câmera @@ -477,13 +478,13 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Selecione de onde vem a imagem da câmera emulada. Pode ser um arquivo de imagem ou uma câmera real. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + <html><head/><body><p>Selecione de onde vem a imagem da câmera emulada. Pode ser uma imagem ou uma câmera real.</p></body></html> - Camera Image Source: - Origem da imagem da câmera: + Camera Image Source + Origem da imagem da camêra @@ -502,8 +503,8 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - File: - Arquivo: + File + Arquivo @@ -516,11 +517,6 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço Select the system camera to use Selecione o tipo de câmera a ser utilizado - - - Camera: - Câmera: - <Default> @@ -534,8 +530,8 @@ Esta ação banirá tanto o seu nome de usuário do fórum como o seu endereço - Flip: - Espelhar imagem: + Flip + Flip @@ -1024,7 +1020,7 @@ Gostaria de ignorar o erro e continuar? Enable Linear Filtering - Ativar filtragem linear + Ativar Filtragem Linear @@ -1088,8 +1084,8 @@ Gostaria de ignorar o erro e continuar? - Reverse Side by Side - Inverter Lado a Lado + Side by Side Full Width + Lado a Lado (Largura Total) @@ -1139,7 +1135,7 @@ Gostaria de ignorar o erro e continuar? Disable Right Eye Rendering - Desativar a renderização do olho direito + Desativar Renderização do Olho Direito @@ -1147,49 +1143,54 @@ Gostaria de ignorar o erro e continuar? <html><head/><body><p>Desativar a Renderização do Olho Direito</p><p>Desativa a renderização da imagem do olho direito quanto não estiver usando o modo. Melhora muito o desempenho em alguns aplicativos, mas pode causar piscadas em outros.</p></body></html> - + + Swap Eyes + Inverter Olhos + + + Utility Utilidade - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Substitui as texturas por arquivos PNG.</p><p>As texturas são carregadas a partir de load/textures/[ID do título]/.</p></body></html> - - Use Custom Textures + + Use custom textures Usar texturas personalizadas - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Extrai as texturas em arquivos PNG.</p><p>As texturas são extraídas para dump/textures/[ID do título]/.</p></body></html> - - Dump Textures + + Dump textures Extrair texturas - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>Carregar todas as texturas personalizadas na memória ao iniciar, em vez de carregá-las apenas quando o aplicativo exigir.</p></body></html> - - Preload Custom Textures + + Preload custom textures Pré-carregar texturas personalizadas - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Carregue texturas personalizadas de maneira assíncrona com threads em segundo plano para reduzir o stutter do carregamento</p></body></html> - - Async Custom Texture Loading - Carregamento Assíncrono de Textura Personalizada + + Async custom texture loading + Carregamento assíncrono de texturas personalizadas @@ -1201,91 +1202,111 @@ Gostaria de ignorar o erro e continuar? - General - Geral + Updates + Atualizações - Confirm exit while emulation is running - Confirmar saída quando a emulação estiver em execução - - - - Pause emulation when in background - Pausar emulação ao ficar em segundo plano - - - - Mute audio when in background - Silencie ao ficar em segundo plano - - - - Hide mouse on inactivity - Esconder ponteiro do mouse ao ficar inativo - - - - Enable Gamemode - Ativar Gamemode - - - Check for updates Procurar por atualizações - + + Update Channel + Canal de Atualização + + + + Stable + Estável + + + + Prerelease + Pré-lançamento + + + + General + Geral + + + + Confirm exit while emulation is running + Confirmar saída quando a emulação estiver em execução + + + + Pause emulation when in background + Pausar emulação ao ficar em segundo plano + + + + Mute audio when in background + Silencie ao ficar em segundo plano + + + + Hide mouse on inactivity + Esconder ponteiro do mouse ao ficar inativo + + + + Enable Gamemode + Ativar Gamemode + + + Emulation Emulação - + Use global emulation speed Usar velocidade da emulação global - - Set emulation speed: - Definir velocidade da emulação: + + Set emulation speed + Definir velocidade de emulação - - Emulation Speed: - Velocidade da emulação: + + Emulation Speed + Velocidade de Emulação - + Turbo Speed Limit: Limite da velocidade turbo: - + Screenshots Capturas de tela - + Use global screenshot path Usar caminho global - + Set screenshot path: Definir caminho da captura de tela: - + Save Screenshots To Salvar capturas de tela em - + ... ... - + Reset All Settings Redefinir todos os ajustes @@ -1293,8 +1314,8 @@ Gostaria de ignorar o erro e continuar? - - + + unthrottled sem limitação @@ -1304,12 +1325,12 @@ Gostaria de ignorar o erro e continuar? Selecionar pasta - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? Tem certeza de que deseja<b> redefinir suas configurações</b> e fechar o Azahar? @@ -1363,13 +1384,13 @@ Gostaria de ignorar o erro e continuar? - SPIR-V Shader Generation - Geração de Sombreadores SPIR-V + SPIR-V shader generation + Geração de shaders SPIR-V - Disable GLSL -> SPIR-V Optimizer - Desativar GLSL -> Otimizador de SPIR-V + Disable GLSL -> SPIR-V optimizer + Desativar o otimizador GLSL → SPIR-V @@ -1388,8 +1409,8 @@ Gostaria de ignorar o erro e continuar? - Enable Hardware Shader - Ativar shaders via hardware + Enable hardware shader + Ativar shader por hardware @@ -1398,7 +1419,7 @@ Gostaria de ignorar o erro e continuar? - Accurate Multiplication + Accurate multiplication Multiplicação precisa @@ -1408,8 +1429,8 @@ Gostaria de ignorar o erro e continuar? - Enable Shader JIT - Ativar JIT para shaders + Enable shader JIT + Ativar compilação assíncrona de shaders @@ -1418,17 +1439,17 @@ Gostaria de ignorar o erro e continuar? - Enable Async Shader Compilation - Ativar a compilação assíncrona de shaders + Enable async shader compilation + Ativar compilação assíncrona de shaders - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Realiza a apresentação em threads separadas. Melhora o desempenho ao usar o Vulkan na maioria dos aplicativos.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + <html><head/><body><p>Executar a apresentação em threads separadas. Melhora o desempenho ao usar Vulkan na maioria dos aplicativos. Adiciona cerca de 1 quadro (frame) de atraso de entrada (input lag).</p></body></html> - Enable Async Presentation + Enable async presentation Ativar apresentação assíncrona @@ -1468,13 +1489,13 @@ Gostaria de ignorar o erro e continuar? - Use Disk Shader Cache + Use disk shader cache Usar cache de shaders em disco - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - A sincronização vertical evita que as imagens do jogo pareçam cortadas, porém algumas placas gráficas apresentam redução de desempenho quando esta está ativada. Deixe-a ativada se você não reparar alguma diferença de desempenho. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + <html><head/><body><p>O VSync evita que a tela sofra rasgos (tearing), mas algumas placas de vídeo têm menor desempenho com o VSync ativado. Mantenha-o ativado se não notar diferença de desempenho.</p></body></html> @@ -1482,22 +1503,32 @@ Gostaria de ignorar o erro e continuar? Ativar sincronização vertical - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + <html><head/><body><p>Quando ativada, esta configuração detecta quando a taxa de atualização da tela está abaixo da do 3DS e, quando isso ocorre, desativa o VSync automaticamente para evitar que a velocidade de emulação seja forçada abaixo de 100%.</p></body></html> + + + + Enable display refresh rate detection + Ativar detecção da taxa de atualização da tela + + + Use global Usar global - + Use per-application Usar por aplicativo - - Delay application render thread: - Atrasar thread de renderização do aplicativo: + + Delay Application Render Thread + Atrasar Thread de Renderização da Aplicação - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>Atrasa a thread de renderização emulada por uma quantidade específica de milissegundos toda vez que forem enviados comandos para a GPU.</p><p>Ajuste esta funcionalidade em (bem poucos) aplicativos com taxa de quadros dinâmica para corrigir problemas de desempenho.</p></body></html> @@ -1982,13 +2013,13 @@ Gostaria de ignorar o erro e continuar? - Swap Screens - Trocar Telas + Swap screens + Trocar telas - Rotate Screens Upright - Girar Verticalmente + Rotate screens upright + Rotacionar telas para a posição vertical @@ -2104,8 +2135,8 @@ Gostaria de ignorar o erro e continuar? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>% de Opacidade da Tela Inferior (Apenas OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + <html><head/><body><p>Opacidade da tela inferior %</p></body></html> @@ -2276,8 +2307,8 @@ Gostaria de ignorar o erro e continuar? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Saiba mais</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Saiba Mais</span></a> @@ -2452,8 +2483,8 @@ Gostaria de ignorar o erro e continuar? - Use Virtual SD - Usar SD virtual + Use virtual SD card + Usar cartão SD virtual @@ -2462,7 +2493,7 @@ Gostaria de ignorar o erro e continuar? - Use Custom Storage + Use custom storage location Usar armazenamento personalizado @@ -2493,6 +2524,16 @@ Gostaria de ignorar o erro e continuar? SDMC Directory Pasta SDMC + + + Compress installed CIA content + Comprimir conteúdo CIA instalado + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + <html><head/><body><p>Compacta o conteúdo de arquivos CIA quando instalados no cartão SD emulado. Afeta apenas o conteúdo CIA instalado enquanto a configuração estiver ativada.</p></body></html> + Select NAND Directory @@ -2540,8 +2581,8 @@ os recursos online (se instalado) - Region: - Região: + Region + Região @@ -2549,326 +2590,337 @@ os recursos online (se instalado) Seleção automática - + + Apply region free patch to +installed applications. + Aplicar patch de região livre os apps instalados. + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + Aplica um patch de região livre aos aplicativos instalados, para que eles sempre apareçam no menu inicial. + + + Username Nome de usuário - + Birthday Aniversário - + January Janeiro - + February Fevereiro - + March Março - + April Abril - + May Maio - + June Junho - + July Julho - + August Agosto - + September Setembro - + October Outubro - + November Novembro - + December Dezembro - + Language Idioma - + Note: this can be overridden when region setting is auto-select Nota: isso pode ser ignorado quando a configuração de região for seleção automática - + Japanese (日本語) Japonês (日本語) - + English Inglês (English) - + French (français) Francês (français) - + German (Deutsch) Alemão (Deutsch) - + Italian (italiano) Italiano (italiano) - + Spanish (español) Espanhol (español) - + Simplified Chinese (简体中文) Chinês simplificado (简体中文) - + Korean (한국어) Coreano (한국어) - + Dutch (Nederlands) Neerlandês (Nederlands) - + Portuguese (português) Português (Português) - + Russian (Русский) Russo (Русский) - + Traditional Chinese (正體中文) Chinês tradicional (正體中文) - + Sound output mode Modo de saída de som - + Mono Mono - + Stereo Estéreo - + Surround Surround - + Country País - + Clock Relógio - + System Clock Relógio do sistema - + Fixed Time Horário fixo - + Startup time Horário na inicialização - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time Tempo de deslocamento - + days dias - + HH:mm:ss HH:mm:ss - + Initial System Ticks Ticks Iniciais do Sistema - + Random Aleatório - + Fixed Fixado - + Initial System Ticks Override Substituição Inicial de Ticks do Sistema - + Play Coins Moedas de Jogo - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>Número de passos por hora relatados pelo pedômetro. Na faixa de 0 a 65.535.</p></body></html> - + Pedometer Steps per Hour Passos do Pedômetro por Hora - + Run System Setup when Home Menu is launched Executar configuração do sistema quando o Menu Inicial for aberto - + Console ID: ID do console: - - + + Regenerate Gerar um novo - + MAC: MAC: - - 3GX Plugin Loader: - Carregador do plug-in 3GX: + + 3GX Plugin Loader + Carregador de Plugins 3GX - + Enable 3GX plugin loader Ativar carregador do plug-in 3GX - + Allow applications to change plugin loader state Permitir que os aplicativos alterem o estado do carregador de plug-ins - + Real Console Unique Data Dados exclusivos do console real - + Your real console is linked to Azahar. Seu console real está vinculado ao Azahar. - + Unlink Desvincular - + OTP OTP - - - - + + + + Choose Escolha - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. As configurações do sistema só estarão disponíveis quando nenhum aplicativo estiver em execução. @@ -3578,76 +3630,76 @@ os recursos online (se instalado) Arquivo sed (*.sed);;Todos os arquivos (*.*) - - + + Console ID: 0x%1 ID do console: 0x%1 - - + + MAC: %1 MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? Isso substituirá seu ID do console 3DS virtual atual por um novo. Seu ID do console 3DS virtual atual não poderá ser recuperado. Isso pode ter efeitos inesperados nos aplicativos. Poderão ocorrer falhas ao usar um arquivo salvo de configuração desatualizado. Deseja continuar? - - - + + + Warning Alerta - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? Isto substituirá seu endereço MAC atual por um novo. Não é recomendado fazer isso se você possuir o endereço MAC do seu console real usando esta ferramenta de configuração. Deseja continuar? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? Esta ação irá desvincular seu console real do Azahar, com as seguintes consequências:<br><ul><li>Seu OTP, SecureInfo e LocalFriendCodeSeed serão removidos do Azahar.</li><li>Sua lista de amigos será redefinida e sua sessão será finalizada em sua conta NNID/PNID.</li><li>Arquivos do sistema e títulos da eshop obtidos pelo Azahar se tornarão inacessíveis até que o mesmo console seja vinculado de novo (dados salvos não serão perdidos).</li></ul><br>Deseja continuar? - + Invalid country for configured region País inválido para a região selecionada - + Invalid country for console unique data País inválido para os dados exclusivos do console - + Status: Loaded Estado: carregado - + Status: Loaded (Invalid Signature) Estado: carregado (assinatura inválida) - + Status: Loaded (Region Changed) Estado: carregado (região alterada) - + Status: Not Found Estado: não encontrado - + Status: Invalid Estado: inválido - + Status: IO Error Estado: erro de E/S @@ -3721,12 +3773,12 @@ Arraste os pontos para alterar a posição ou clique duas vezes nas células da Delete Profile - Apagar perfil + Excluir Perfil Delete profile %1? - Apagar perfil %1? + Excluir perfil %1? @@ -3763,13 +3815,13 @@ Arraste os pontos para alterar a posição ou clique duas vezes nas células da - Interface language: - Idioma da interface: + Interface Language + Idioma da Interface - Theme: - Tema: + Theme + Tema @@ -3778,8 +3830,8 @@ Arraste os pontos para alterar a posição ou clique duas vezes nas células da - Icon Size: - Tamanho do ícone: + Icon Size + Tamanho do ícone @@ -3799,8 +3851,8 @@ Arraste os pontos para alterar a posição ou clique duas vezes nas células da - Row 1 Text: - Texto da 1ª linha: + Row 1 Text + Texto da linha 1 @@ -3834,17 +3886,17 @@ Arraste os pontos para alterar a posição ou clique duas vezes nas células da - Row 2 Text: - Texto da 2ª linha: + Row 2 Text + Texto da linha 2 - Hide Titles without Icon + Hide titles without icon Ocultar títulos sem ícone - Single Line Mode + Single line mode Modo de linha única @@ -3854,8 +3906,8 @@ Arraste os pontos para alterar a posição ou clique duas vezes nas células da - Show Advanced Frame Time Info - Mostrar informação avançada de tempo de quadro + Show advanced frame time info + Mostrar informações avançadas de tempo de quadro @@ -3937,12 +3989,12 @@ Arraste os pontos para alterar a posição ou clique duas vezes nas células da DirectConnectWindow - + Connecting Conectando - + Connect Conectar @@ -4062,471 +4114,511 @@ Por favor, verifique a instalação do FFmpeg usada para compilação. GMainWindow - + No Suitable Vulkan Devices Detected Nenhum Dispositivo Vulkan Adequado Detectado - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. O Vulkan falhou durante sua inicialização.<br/>Sua GPU pode não suportar o Vulkan 1.1 ou você não possui o driver gráfico mais recente. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. Velocidade atual do tráfego do Artic. Valores mais altos indicam cargas de transferência maiores. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Velocidade atual de emulação. Valores maiores ou menores que 100% indicam que a emulação está funcionando mais rápida ou lentamente que num 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. Quantos quadros por segundo que o app está mostrando atualmente. Pode variar de app para app e cena para cena. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tempo levado para emular um quadro do 3DS, sem considerar o limitador de taxa de quadros ou a sincronização vertical. Valores menores ou iguais a 16,67 ms indicam que a emulação está em velocidade plena. - + MicroProfile (unavailable) Micro-perfil (indisponível) - + Clear Recent Files Limpar Arquivos Recentes - + &Continue &Continuar - + &Pause &Pausar - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar está executando um aplicativo - - + + Invalid App Format Formato de App inválido - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. O formato do seu app não é suportado.<br/>Siga os guias para reextrair seus <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de jogos</a> ou <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - + App Corrupted App corrompido - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Seu app está corrompido. <br/>Siga os guias para reextrair seus <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de jogos</a> ou <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - + App Encrypted App criptografado - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Seu app está criptografado. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Confira nosso blog para mais informações.</a> - + Unsupported App App não suportado - + GBA Virtual Console is not supported by Azahar. O Console Virtual de GBA não é suportado pelo Azahar. - - + + Artic Server Servidor Artic - + + Invalid system mode + Modo de sistema inválido + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + Aplicativos exclusivos do New 3DS não podem ser carregados sem ativar o modo New 3DS. + + + Error while loading App! Erro ao carregar o App! - + An unknown error occurred. Please see the log for more details. Ocorreu um erro desconhecido. Verifique o registro para mais detalhes. - + CIA must be installed before usage É necessário instalar o CIA antes de usar - + Before using this CIA, you must install it. Do you want to install it now? É necessário instalar este CIA antes de poder usá-lo. Deseja instalá-lo agora? - + Quick Load Carregamento rápido - + Quick Save Salvamento rápido - - + + Slot %1 Espaço %1 - + %2 %3 %2 %3 - + Quick Save - %1 Salvamento rápido - %1 - + Quick Load - %1 Carregamento rápido - %1 - + Slot %1 - %2 %3 Espaço %1 - %2 %3 - + Error Opening %1 Folder Erro ao abrir a pasta %1 - - + + Folder does not exist! A pasta não existe! - + Remove Play Time Data Remover Dados de Tempo de Jogo - + Reset play time? Redefinir tempo de jogo? - - - - + + + + Create Shortcut Criar Atalho - + Do you want to launch the application in fullscreen? Você gostaria de iniciar o aplicativo em tela cheia? - + Successfully created a shortcut to %1 Atalho para %1 criado com sucesso - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Isso criará um atalho para o AppImage atual. Isso pode não funcionar bem se você atualizar. Deseja continuar? - + Failed to create a shortcut to %1 Não foi possível criar um atalho para %1 - + Create Icon Criar Ícone - + Cannot create icon file. Path "%1" does not exist and cannot be created. Não foi possível criar o arquivo de ícone. O caminho "%1" não existe e não pode ser criado. - + Dumping... Extraindo... - - + + Cancel Cancelar - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. Não foi possível extrair o RomFS base. Consulte o registro para ver os detalhes. - + Error Opening %1 Erro ao abrir %1 - + Select Directory Selecionar pasta - + Properties Propriedades - + The application properties could not be loaded. Não foi possível carregar as propriedades do aplicativo. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Executável do 3DS (%1);;Todos os arquivos (*.*) - + Load File Carregar arquivo - - + + Set Up System Files Configurar arquivos do sistema - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> <p>O Azahar precisa dos dados exclusivos do console e arquivos de firmware de um console real para que seja possível usar alguns de seus recursos.<br>Tais arquivos e dados podem ser configurados através da <a href=https://github.com/azahar-emu/ArticSetupTool>Ferramenta de Configuração Artic do Azahar</a><br>Notas:<ul><li><b>Esta operação instalará os dados exclusivos do console para o Azahar, não compartilhe sua pasta de usuário ou nand<br>depois de realizar este processo!</b></li><li>Enquanto estiver realizando o processo de configuração, o Azahar irá vincular-se ao console executando a ferramenta de configuração. Você poderá desvincular<br>o console mais tarde na aba Sistema no menu de configuração do emulador.</li><li>Não entre no online com ambos Azahar e seu console 3DS ao mesmo tempo depois de configurar os arquivos de sistema,<br>já que isso poderá causar problemas.</li><li>A configuração do Antigo 3DS é necessária para a configuração do Novo 3DS funcionar (realizar ambas as configurações é recomendado).</li><li>Ambos os modos de configuração irão funcionar independente do modelo do console executando a ferramenta de configuração.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: Digite o endereço da Ferramenta de Configuração Artic do Azahar: - + <br>Choose setup mode: <br>Escolha o modo de configuração: - + (ℹ️) Old 3DS setup (ℹ️) Configuração do Antigo 3DS - - + + Setup is possible. É possível configurar. - + (⚠) New 3DS setup (⚠) Configuração do Novo 3DS - + Old 3DS setup is required first. A configuração do Antigo 3DS é requisitada primeiro. - + (✅) Old 3DS setup (✅) Configuração do Antigo 3DS - - + + Setup completed. Configuração concluída. - + (ℹ️) New 3DS setup (ℹ️) Configuração do Novo 3DS - + (✅) New 3DS setup (✅) Configuração do Novo 3DS - + The system files for the selected mode are already set up. Reinstall the files anyway? Os arquivos do sistema para o modo selecionado já foram configurados. Reinstalar os arquivos mesmo assim? - + Load Files Carregar arquivos - - 3DS Installation File (*.CIA*) - Arquivo de instalação 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + Arquivo de Instalação 3DS (.cia .zcia) - + + + All Files (*.*) Todos os arquivos (*.*) - + Connect to Artic Base Conectar-se ao Artic Base - + Enter Artic Base server address: Digite o endereço do servidor Artic Base: - + %1 has been installed successfully. %1 foi instalado. - + Unable to open File Não foi possível abrir o arquivo - + Could not open %1 Não foi possível abrir %1 - + Installation aborted Instalação cancelada - + The installation of %1 was aborted. Please see the log for more details A instalação de %1 foi interrompida. Consulte o registro para mais detalhes - + Invalid File Arquivo inválido - + %1 is not a valid CIA %1 não é um CIA válido - + CIA Encrypted CIA criptografado - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Seu arquivo CIA está criptografado.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Confira nosso blog para mais informações.</a> - + Unable to find File Não foi possível localizar o arquivo - + Could not find %1 Não foi possível localizar %1 - + + + + + Z3DS Compression + Compressão Z3DS + + + + Failed to compress some files, check log for details. + Falha ao comprimir alguns arquivos. Verifique o log para mais detalhes. + + + + Failed to decompress some files, check log for details. + Falha ao descomprimir alguns arquivos. Verifique o log para mais detalhes. + + + + All files have been compressed successfully. + Todos os arquivos foram comprimidos com sucesso. + + + + All files have been decompressed successfully. + Todos os arquivos foram descomprimidos com sucesso. + + + Uninstalling '%1'... Desinstalando '%1'... - + Failed to uninstall '%1'. Erro ao desinstalar '%1'. - + Successfully uninstalled '%1'. '%1' desinstalado com sucesso. - + File not found Arquivo não encontrado - + File "%1" not found Arquivo "%1" não encontrado - + Savestates Estados salvos - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! @@ -4535,86 +4627,86 @@ Use at your own risk! Use por sua conta e risco! - - - + + + Error opening amiibo data file Erro ao abrir arquivo de dados do amiibo - + A tag is already in use. Uma tag já está em uso. - + Application is not looking for amiibos. O aplicativo não está procurando por amiibos. - + Amiibo File (%1);; All Files (*.*) Arquivo do Amiibo (%1);; Todos os arquivos (*.*) - + Load Amiibo Carregar Amiibo - + Unable to open amiibo file "%1" for reading. Não foi possível abrir o arquivo amiibo "%1" para realizar a leitura. - + Record Movie Gravar passos - + Movie recording cancelled. Gravação cancelada. - - + + Movie Saved Gravação salva - - + + The movie is successfully saved. A gravação foi salva. - + Application will unpause O aplicativo será retomado - + The application will be unpaused, and the next frame will be captured. Is this okay? O aplicativo será retomado, e o próximo quadro será capturado. Tudo bem? - + Invalid Screenshot Directory Pasta inválida - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. Não é possível criar a pasta especificada. O caminho original foi restabelecido. - + Could not load video dumper Não foi possível carregar o gravador de vídeo - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4627,215 +4719,265 @@ Para instalar o FFmpeg no Azahar, pressione Abrir e selecione seu diretório FFm Para ver um guia sobre como instalar o FFmpeg, pressione Ajuda. - + + Load 3DS ROM Files + Carregar arquivos de ROM do 3DS + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + **Arquivos de ROM do 3DS (.cia *.cci *.3dsx .cxi .3ds) + + + + 3DS Compressed ROM File (*.%1) + Arquivo de ROM 3DS Comprimido (*.%1) + + + + Save 3DS Compressed ROM File + Salvar Arquivo de ROM 3DS Comprimido + + + + Select Output 3DS Compressed ROM Folder + Selecionar Pasta de Saída das ROMs 3DS Comprimidas + + + + Load 3DS Compressed ROM Files + Carregar Arquivos de ROM 3DS Comprimidos + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + Arquivos de ROM 3DS Comprimidos (*.zcia *.zcci .z3dsx .zcxi) + + + + 3DS ROM File (*.%1) + Arquivo de ROM 3DS (*.%1) + + + + Save 3DS ROM File + Salvar Arquivo de ROM 3DS + + + + Select Output 3DS ROM Folder + Selecionar Pasta de Saída das ROMs 3DS + + + Select FFmpeg Directory Selecione o Diretório FFmpeg - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. O diretório FFmpeg fornecido não foi encontrado %1. Por favor, certifique-se de que o diretório correto foi selecionado. - + FFmpeg has been sucessfully installed. O FFmpeg foi instalado com sucesso. - + Installation of FFmpeg failed. Check the log file for details. A instalação do FFmpeg falhou. Verifique o arquivo de log para obter detalhes. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. Não foi possível começar a gravação do vídeo.<br>Assegure-se que o codificador de vídeo está configurado corretamente.<br>Refira-se ao log para mais detalhes. - + Recording %1 Gravando %1 - + Playing %1 / %2 Reproduzindo %1 / %2 - + Movie Finished Reprodução concluída - + (Accessing SharedExtData) (Acessando SharedExtData) - + (Accessing SystemSaveData) (Acessando SystemSaveData) - + (Accessing BossExtData) (Accessando BossExtData) - + (Accessing ExtData) (Acessando ExtData) - + (Accessing SaveData) (Acessando SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 Tráfego do Artic: %1 %2%3 - + Speed: %1% Velocidade: %1% - + Speed: %1% / %2% Velocidade: %1% / %2% - + App: %1 FPS App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Quadro: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rest: %6 ms) - + Frame: %1 ms Quadro: %1 ms - + VOLUME: MUTE VOLUME: SILENCIADO - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUME: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - %1 está faltando. <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Faça a extração dos arquivos do seu sistema</a>.<br/>Continuar a emulação pode causar travamentos e bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + %1 está ausente. Por favor,<a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>faça a extração dos arquivos do sistema</a>. <br/>Continuar a emulação pode causar falhas e bugs. - + A system archive Um arquivo do sistema - + System Archive Not Found Arquivo de sistema não encontrado - + System Archive Missing Arquivo de sistema em falta - + Save/load Error Erro ao salvar/carregar - + Fatal Error Erro fatal - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Ocorreu um erro fatal. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Verifique o registro</a> para mais detalhes.<br/>Continuar a emulação pode causar travamentos e bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + Ocorreu um erro fatal. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Verifique o log</a> para mais detalhes.<br/>Continuar a emulação pode causar falhas e bugs. - + Fatal Error encountered Erro fatal encontrado - + Continue Continuar - + Quit Application Sair do Aplicativo - + OK OK - + Would you like to exit now? Deseja sair agora? - + The application is still running. Would you like to stop emulation? O aplicativo ainda está em execução. Deseja parar a emulação? - + Playback Completed Reprodução concluída - + Movie playback completed. Reprodução dos passos concluída. - + Update Available Atualização disponível - + Update %1 for Azahar is available. Would you like to download it? A atualização %1 para o Azahar está disponível. Você gostaria de baixá-la? - + Primary Window Janela Principal - + Secondary Window Janela Secundária @@ -4898,42 +5040,42 @@ Você gostaria de baixá-la? GRenderWindow - + OpenGL not available! OpenGL indisponível! - + OpenGL shared contexts are not supported. Shared contexts do OpenGL não são suportados. - + Error while initializing OpenGL! Erro ao inicializar o OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Sua GPU pode não suportar OpenGL, ou você não possui o driver gráfico mais recente. - + Error while initializing OpenGL 4.3! Erro ao inicializar OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Sua GPU pode não ser compatível com o OpenGL 4.3 ou você não possui o driver mais recente.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! Erro ao inicializar o OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Sua GPU pode não suportar o OpenGL ES 3.2 ou você não possui o driver gráfico mais recente.<br><br>Renderizador GL:<br>%1 @@ -4941,175 +5083,185 @@ Você gostaria de baixá-la? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - IMPORTANTE: Arquivos criptografados e arquivos .3ds não são mais suportados. Talvez seja necessário descriptografá-los e/ou renomeá-los para .cci. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Saiba mais.</a> - - - - Don't show again - Não mostrar novamente - - - - + + Compatibility Compatibilidade - - + + Region Região - - + + File type Tipo de arquivo - - + + Size Tamanho - - + + Play time Tempo de jogo - + Favorite Favorito - + + Eject Cartridge + Ejetar Cartucho + + + + Insert Cartridge + Inserir Cartucho + + + Open Abrir - + Application Location Local do Aplicativo - + Save Data Location Local de Dados Salvos - + Extra Data Location Local de Dados Extras - + Update Data Location Atualizar Local dos Dados - + DLC Data Location Local de Dados de DLC  - + Texture Dump Location Local de Dump de Texturas - + Custom Texture Location Local de Texturas Personalizadas - + Mods Location Diretório de Mods - + Dump RomFS Extrair RomFS - + Disk Shader Cache Cache de shaders em disco - + Open Shader Cache Location Abrir local do cache dos shaders - + Delete OpenGL Shader Cache Apagar cache de shaders do OpenGL - + + Delete Vulkan Shader Cache + + + + Uninstall Desinstalar - + Everything Tudo - + Application Aplicativo - + Update Atualização - + DLC DLC - + Remove Play Time Data Remover Dados de Tempo de Jogo - + Create Shortcut Criar Atalho - + Add to Desktop Adicionar à Área de Trabalho - + Add to Applications Menu Adicionar ao Menu Iniciar - + + Stress Test: App Launch + Teste de Estresse: Inicialização de Aplicativos + + + Properties Propriedades - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. @@ -5118,64 +5270,64 @@ This will delete the application if installed, as well as any installed updates Isso irá deletar o aplicativo caso ele esteja instalado, assim como qualquer atualização ou DLC instalada. - - + + %1 (Update) %1 (Atualização) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? Tem certeza que quer desinstalar '%1'? - + Are you sure you want to uninstall the update for '%1'? Tem certeza que deseja desinstalar a atualização para '%1'? - + Are you sure you want to uninstall all DLC for '%1'? Tem certeza de que deseja desinstalar todas as DLCs de '%1'? - + Scan Subfolders Examinar Subpastas - + Remove Application Directory Remover Diretório de Aplicativos - + Move Up Mover para cima - + Move Down Mover para baixo - + Open Directory Location Abrir local da pasta - + Clear Limpar - + Name Nome @@ -5183,82 +5335,82 @@ Isso irá deletar o aplicativo caso ele esteja instalado, assim como qualquer at GameListItemCompat - + Perfect Perfeito - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. O app funciona impecavelmente, sem nenhum problema de áudio ou nos gráficos. Todas as funcionalidades testadas funcionam como deveriam, sem a necessidade de soluções alternativas. - + Great Ótimo - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. O app funciona com leves defeitos gráficos ou de áudio e é jogável do início ao fim. Pode exigir algumas soluções alternativas. - + Okay Bom - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. O aplicativo funciona com graves defeitos gráficos ou de áudio, mas o app é jogável do início ao fim com o uso de soluções alternativas. - + Bad Ruim - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. O app funciona, só que com problemas significativos nos gráficos ou no áudio. Não é possível progredir em certas áreas por conta de tais problemas, mesmo com soluções alternativas. - + Intro/Menu Intro/menu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. É impossível executar o aplicativo devido a graves defeitos nos gráficos ou no áudio. Não é possível passar da Tela Inicial. - + Won't Boot Não inicia - + The app crashes when attempting to startup. O app trava ou fecha-se abruptamente ao tentar iniciá-lo. - + Not Tested Não testado - + The app has not yet been tested. O app ainda não foi testado. @@ -5266,7 +5418,7 @@ Tela Inicial. GameListPlaceholder - + Double-click to add a new folder to the application list Clique duas vezes para adicionar uma pasta à lista de aplicativos @@ -5274,27 +5426,27 @@ Tela Inicial. GameListSearchField - + of de - + result resultado - + results resultados - + Filter: Filtro: - + Enter pattern to filter Insira o padrão para filtrar @@ -5302,47 +5454,47 @@ Tela Inicial. GameRegion - + Japan Japão - + North America América do Norte - + Europe Europa - + Australia Austrália - + China China - + Korea Coreia - + Taiwan Taiwan - + Invalid region Região inválida - + Region free Livre de região @@ -5622,87 +5774,87 @@ Tela Inicial. Índice cíclico: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Registradores de endereço: %1, %2 - + Compare Result: %1, %2 Comparar resultado: %1, %2 - + Static Condition: %1 Condição estática: %1 - + Dynamic Conditions: %1, %2 Condições dinâmicas: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Parâmetros do ciclo: %1 (repetições), %2 (inicializador), %3 (incremento), %4 - + Instruction offset: 0x%1 Offset de instrução: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (última instrução) @@ -5927,24 +6079,24 @@ Mensagem de depuração: Preparando shaders %1 / %2 - - Loading Shaders %1 / %2 - Carregando shaders %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Iniciando... - + Now Loading %1 Carregando %1 - + Estimated Time %1 Tempo estimado %1 @@ -6003,32 +6155,32 @@ Mensagem de depuração: Senha: - + Room Name Nome da sala - + Preferred Application Aplicativo preferido - + Host Anfitrião - + Players Jogadores - + Refreshing Atualizando - + Refresh List Atualizar lista @@ -6111,342 +6263,352 @@ Mensagem de depuração: Gravações (TAS) - + Help Ajuda - + Load File... Carregar arquivo... - + Install CIA... Instalar CIA... - + Connect to Artic Base... Conectando-se à Artic Base... - + Set Up System Files... Configurar arquivos do sistema... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit Sair - + Pause Pausar - + Stop Parar - + Save Salvar - + Load Carregar - + FAQ Perguntas Frequentes - + About Azahar Sobre o Azahar - + Single Window Mode Modo de janela única - + Save to Oldest Slot Salvar no espaço mais antigo - + Quick Save Salvamento rápido - + Load from Newest Slot Carregar do espaço mais recente - + Quick Load Carregamento rápido - + Configure... Configurar... - + Display Dock Widget Headers Mostrar títulos de widgets afixados - + Show Filter Bar Mostrar barra de filtro - + Show Status Bar Mostrar barra de status - + Create Pica Surface Viewer Criar visualizador de superfícies Pica - + Record... Gravar... - + Play... Reproduzir... - + Close Fechar - + Save without Closing Fechar sem salvar - + Read-Only Mode Modo apenas leitura - + Advance Frame - Avançar quadro + Avançar Quadro - + Capture Screenshot Tirar uma captura de tela - + Dump Video Gravar vídeo + Compress ROM File... + Comprimindo Arquivo de ROM... + + + + Decompress ROM File... + Descomprimindo Arquivo de ROM... + + + Browse Public Rooms Procurar salas públicas - + Create Room Criar sala - + Leave Room Sair da sala - + Direct Connect to Room Conectar-se diretamente a uma sala - + Show Current Room Mostrar sala atual - + Fullscreen Tela inteira - + Open Log Folder Abrir Pasta de Logs - + Opens the Azahar Log folder Abrir a pasta de logs do Azahar - + Default Padrão - + Single Screen Tela única - + Large Screen Tela grande - + Side by Side Lado a lado - + Separate Windows Janelas Separadas - + Hybrid Screen Tela Híbrida - + Custom Layout Disposição Personalizada - + Top Right Superior Direita - + Middle Right Centro à Direita - + Bottom Right Inferior Direita - + Top Left Superior Esquerda - + Middle Left Centro à Esquerda - + Bottom Left Inferior Esquerda - + Above Acima - + Below Abaixo - + Swap Screens Trocar telas - + Rotate Upright Girar verticalmente - + Report Compatibility Informar compatibilidade - + Restart Reiniciar - + Load... Carregar... - + Remove Remover - + Open Azahar Folder Abrir pasta do Azahar - + Configure Current Application... Configurar aplicativo atual... @@ -7020,32 +7182,32 @@ Ele pode ter saído da sala. %1 (0x%2) - + Unsupported encrypted application Aplicativo criptografado não suportado - + Invalid region Região inválida - + Installed Titles Títulos instalados - + System Titles Títulos do sistema - + Add New Application Directory Adicionar nova pasta de aplicativos - + Favorites Favoritos diff --git a/dist/languages/ro_RO.ts b/dist/languages/ro_RO.ts index 1b78def9a..ab550862c 100644 --- a/dist/languages/ro_RO.ts +++ b/dist/languages/ro_RO.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -292,8 +292,8 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - Emulation: - Emulare: + Emulation + Emulare @@ -322,8 +322,8 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Acest efect de post-procesare ajustează viteza audio pentru a se potrivi la viteza emulatorului și ajută la împiedicarea bâlbâielilor audio. Acest lucru, totuși, mărește latența audio. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. + Camera Cameră @@ -408,8 +409,8 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - Camera to configure: - Camera pentru configurare: + Camera to Configure + @@ -429,8 +430,8 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - Camera mode: - Mod cameră: + Camera mode + @@ -450,8 +451,8 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - Camera position: - Poziție cameră: + Camera position + @@ -471,13 +472,13 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Selectați de unde provine imaginea camerei emulate. Poate fi o imagine sau o cameră reală. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Sursă de Imagine de la Cameră: + Camera Image Source + @@ -496,8 +497,8 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - File: - Fișier: + File + @@ -510,11 +511,6 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP.Select the system camera to use Selectați camera de sistem pentru a utiliza - - - Camera: - Cameră: - <Default> @@ -528,8 +524,8 @@ Astfel vor fi banați din forum numele lor de utilizator și adresa IP. - Flip: - Rotație: + Flip + @@ -1018,7 +1014,7 @@ Doriți să ignorați eroarea și să continuați? Enable Linear Filtering - Aprinde Linear Filtering + @@ -1082,8 +1078,8 @@ Doriți să ignorați eroarea și să continuați? - Reverse Side by Side - Inversează Side by Side + Side by Side Full Width + @@ -1133,7 +1129,7 @@ Doriți să ignorați eroarea și să continuați? Disable Right Eye Rendering - Dezactivează randarea ochiului drept + @@ -1141,49 +1137,54 @@ Doriți să ignorați eroarea și să continuați? - + + Swap Eyes + + + + Utility Utilizare - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Înlocuiește texture cu fișierele PNG.</p><p>Texturele sunt încărcați din load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures - Folosește texturi personalizate + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Dump-eaza texturele în fișiere PNG.</p><p>Texturele erau dump-ate în dump/textures/[Title ID]/.</p></body></html> - - Dump Textures - Dump-eaza Texture + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures - Preîncarca Texturele Personalizate + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Încarcă texturele asincron cu background threads pentru a reduce încărcarea lentă</p></body></html> - - Async Custom Texture Loading - Încărcare asincronă a texturelor personalizate + + Async custom texture loading + @@ -1195,91 +1196,111 @@ Doriți să ignorați eroarea și să continuați? - General - General + Updates + - Confirm exit while emulation is running - Confirmați ieșirea în timp ce emularea rulează - - - - Pause emulation when in background - Întrerupe emulația în fundal - - - - Mute audio when in background - Pune pe mute audio în fundal - - - - Hide mouse on inactivity - Ascunde mouse-ul atunci când este inactiv - - - - Enable Gamemode - Aprinde Gamemode - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + General + + + + Confirm exit while emulation is running + Confirmați ieșirea în timp ce emularea rulează + + + + Pause emulation when in background + Întrerupe emulația în fundal + + + + Mute audio when in background + Pune pe mute audio în fundal + + + + Hide mouse on inactivity + Ascunde mouse-ul atunci când este inactiv + + + + Enable Gamemode + Aprinde Gamemode + + + Emulation Emulare - + Use global emulation speed Folosește viteza de emulare globală - - Set emulation speed: - Setează viteza emulației: + + Set emulation speed + - - Emulation Speed: - Viteza Emulării: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots Capturi de ecran - + Use global screenshot path Folosește calea globală a capturii de ecran - + Set screenshot path: Setează calea a capturii de ecran: - + Save Screenshots To Salvează capturile de ecran în - + ... ... - + Reset All Settings Resetați Toate Setările @@ -1287,8 +1308,8 @@ Doriți să ignorați eroarea și să continuați? - - + + unthrottled neatruntat @@ -1298,12 +1319,12 @@ Doriți să ignorați eroarea și să continuați? Selectează Directoria Capturilor de ecran - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1357,12 +1378,12 @@ Doriți să ignorați eroarea și să continuați? - SPIR-V Shader Generation - SPIR-V Shader Generare + SPIR-V shader generation + - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1382,8 +1403,8 @@ Doriți să ignorați eroarea și să continuați? - Enable Hardware Shader - Activează Hardware Shader + Enable hardware shader + @@ -1392,8 +1413,8 @@ Doriți să ignorați eroarea și să continuați? - Accurate Multiplication - Înmulțire Precisă + Accurate multiplication + @@ -1402,8 +1423,8 @@ Doriți să ignorați eroarea și să continuați? - Enable Shader JIT - Activează Shader-ul JIT + Enable shader JIT + @@ -1412,18 +1433,18 @@ Doriți să ignorați eroarea și să continuați? - Enable Async Shader Compilation - Activați compilarea Async Shader + Enable async shader compilation + - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation - Aprinde Async Presentation + Enable async presentation + @@ -1462,13 +1483,13 @@ Doriți să ignorați eroarea și să continuați? - Use Disk Shader Cache - Folosește Disk Shader Cache + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync previne screen tearing, dar unele plăci grafice au performanțe mai scăzute cu VSync activat. Păstrați-l activat dacă nu observați o diferență de performanță. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1476,22 +1497,32 @@ Doriți să ignorați eroarea și să continuați? Permite VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global Folosește global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1976,13 +2007,13 @@ Doriți să ignorați eroarea și să continuați? - Swap Screens - Schimbă Ecranele + Swap screens + - Rotate Screens Upright - Rotește Drept Ecranurile + Rotate screens upright + @@ -2098,8 +2129,8 @@ Doriți să ignorați eroarea și să continuați? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Opacitatea Ecranului de Jos % (Numai OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + @@ -2270,7 +2301,7 @@ Doriți să ignorați eroarea și să continuați? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2446,8 +2477,8 @@ Doriți să ignorați eroarea și să continuați? - Use Virtual SD - Folosește SD Virtual + Use virtual SD card + @@ -2456,8 +2487,8 @@ Doriți să ignorați eroarea și să continuați? - Use Custom Storage - Folosește Storage Personalizat + Use custom storage location + @@ -2487,6 +2518,16 @@ Doriți să ignorați eroarea și să continuați? SDMC Directory Directoria SDMC + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2533,8 +2574,8 @@ online features (if installed) - Region: - + Region + Regiune @@ -2542,326 +2583,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Nume de utilizator - + Birthday Zi de naștere - + January Ianuarie - + February Februarie - + March Martie - + April Aprilie - + May Mai - + June Iunie - + July Iulie - + August August - + September Septembrie - + October Octombrie - + November Noiembrie - + December Decembrie - + Language Limbă - + Note: this can be overridden when region setting is auto-select Atenție: Acestea pot fi suprapuse când regiunea este pe selectare automată - + Japanese (日本語) Japoneză (日本語) - + English Engleză - + French (français) Franceză (français) - + German (Deutsch) Germană (Deutsch) - + Italian (italiano) Italiană (italiano) - + Spanish (español) Spaniolă (español) - + Simplified Chinese (简体中文) Chineză simplificată (简体中文) - + Korean (한국어) Coreană (한국어) - + Dutch (Nederlands) Olandeză (Nederlands) - + Portuguese (português) Portugheză (português) - + Russian (Русский) Rusă (Русский) - + Traditional Chinese (正體中文) Chineză tradițională (正體中文) - + Sound output mode Mod ieșire sunet - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Țară - + Clock Ceas - + System Clock Ceas de Sistem - + Fixed Time Oră Fixă - + Startup time Timp de Pornire - + yyyy-MM-ddTHH:mm:ss aaaa-LL-zzTOO:mm:ss - + Offset time Offset timp - + days - + HH:mm:ss HH:mm:ss - + Initial System Ticks Bifele Inițiale de Sistem - + Random Aleatoriu - + Fixed Fixed - + Initial System Ticks Override Bifele Inițiale de Sistem Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched Rulează System Setup când Home Menu este pornit - + Console ID: ID Consolă: - - + + Regenerate Regenerează - + MAC: - - 3GX Plugin Loader: - 3GX Plugin Loader: + + 3GX Plugin Loader + - + Enable 3GX plugin loader Aprinde 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3571,76 +3623,76 @@ online features (if installed) - - + + Console ID: 0x%1 ID Consolă: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Atenționare - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3756,13 +3808,13 @@ Trageți puncte pentru a schimba poziția sau faceți dublu clic pe celulele tab - Interface language: - Limbaj de Interfață: + Interface Language + - Theme: - Temă: + Theme + @@ -3771,8 +3823,8 @@ Trageți puncte pentru a schimba poziția sau faceți dublu clic pe celulele tab - Icon Size: - Mărime de Icoană: + Icon Size + @@ -3792,8 +3844,8 @@ Trageți puncte pentru a schimba poziția sau faceți dublu clic pe celulele tab - Row 1 Text: - Text din Rând 1: + Row 1 Text + @@ -3827,18 +3879,18 @@ Trageți puncte pentru a schimba poziția sau faceți dublu clic pe celulele tab - Row 2 Text: - Text din Rând 2: + Row 2 Text + - Hide Titles without Icon - Ascunde Titluri fără Icoană + Hide titles without icon + - Single Line Mode - Modul Liniei Unice + Single line mode + @@ -3847,7 +3899,7 @@ Trageți puncte pentru a schimba poziția sau faceți dublu clic pe celulele tab - Show Advanced Frame Time Info + Show advanced frame time info @@ -3930,12 +3982,12 @@ Trageți puncte pentru a schimba poziția sau faceți dublu clic pe celulele tab DirectConnectWindow - + Connecting Conectând - + Connect Conectare @@ -4055,556 +4107,596 @@ Vă rugăm să verificați instalarea FFmpeg utilizată pentru compilare. GMainWindow - + No Suitable Vulkan Devices Detected Nu au fost detectate dispozitive Vulkan adecvate Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. Inițializarea Vulkan a eșuat în timpul pornirii.<br/>Este posibil ca GPU-ul dvs. să nu accepte Vulkan 1.1 sau să nu aveți cel mai recent driver grafic. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Viteza actuală de emulare. Valori mai mari sau mai mici de 100% indică cum emularea rulează mai repede sau mai încet decât un 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Timp luat pentru a emula un cadru 3DS, fără a pune în calcul limitarea de cadre sau v-sync. Pentru emulare la viteza maximă, această valoare ar trebui să fie maxim 16.67 ms. - + MicroProfile (unavailable) - + Clear Recent Files Curăță Fișiere Recente - + &Continue &Continue - + &Pause &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. A apărut o eroare necunoscută. Vă rugăm să consultați jurnalul pentru mai multe detalii. - + CIA must be installed before usage CIA-ul trebuie instalat înainte de uz - + Before using this CIA, you must install it. Do you want to install it now? Înainte de a folosi acest CIA, trebuie să-l instalati. Doriți s-o faceți acum? - + Quick Load - + Quick Save - - + + Slot %1 Slot %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 Slot %1 - %2 %3 - + Error Opening %1 Folder Eroare Deschizând Folderul %1 - - + + Folder does not exist! Folderul nu există! - + Remove Play Time Data Eliminați datele privind timpul petrecut - + Reset play time? Resetați play time? - - - - + + + + Create Shortcut Creează un Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 Shortcut-ul către %1 a fost creat cu succes - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Asta va crea un shortcut la AppImage-ul curent. Este posibilitate că nu va lucra normal dacă veți actualiza. Continuă? - + Failed to create a shortcut to %1 Nu s-a putut crea o comandă rapidă către %1 - + Create Icon Creează un Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. Nu se poate crea fișierul de icon. Calea "%1" nu există și nu poate fi creat. - + Dumping... Dumping... - - + + Cancel Anulare - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. Nu s-a putut să facă dump-ul bazei RomFS. Consultați log-urile pentru detalii. - + Error Opening %1 Eroare Deschizând %1 - + Select Directory Selectează Directorul - + Properties Proprietăți - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Executabilă 3DS (%1);;Toate Fișierele (*.*) - + Load File Încarcă Fișier - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Încarcă Fișiere - - 3DS Installation File (*.CIA*) - Fișier de Instalare 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Toate Fișierele (*.*) - + Connect to Artic Base Conectează Arctic Base - + Enter Artic Base server address: Introduceți adresa serverului Arctic Base: - + %1 has been installed successfully. %1 a fost instalat cu succes. - + Unable to open File Nu s-a putut deschide Fișierul - + Could not open %1 Nu s-a putut deschide %1 - + Installation aborted Instalare anulată - + The installation of %1 was aborted. Please see the log for more details Instalarea lui %1 a fost anulată. Vă rugăm să vedeți log-ul pentru mai multe detalii. - + Invalid File Fișier Invalid - + %1 is not a valid CIA %1 nu este un CIA valid - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File Nu se poate găsi Fișierul - + Could not find %1 %1 n-a fost găsit - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... Dezinstalarea '%1'... - + Failed to uninstall '%1'. Dezinstalarea '%1' a eșuat. - + Successfully uninstalled '%1'. '%1' era dezinstalat cu succes. - + File not found Fișier negăsit - + File "%1" not found Fișierul "%1" nu a fost găsit - + Savestates Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file Eroare la deschiderea fișierului de date amiibo - + A tag is already in use. Un tag deja este in folosire. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Fișier Amiibo (%1);; Toate Fișierele (*.*) - + Load Amiibo Încarcă Amiibo - + Unable to open amiibo file "%1" for reading. Nu se poate deschide fișierul amiibo "%1" pentru citire. - + Record Movie Înregistrează Film - + Movie recording cancelled. Înregistrarea filmului a fost anulată. - - + + Movie Saved Film Salvat - - + + The movie is successfully saved. Filmul a fost salvat cu succes. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory Directoria Capturii de Ecran este Invalidă - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. Nu se poate crea directoria specificată a capturii de ecran. Calea capturii de ecran a fost setat implicit - + Could not load video dumper Dumperul video nu a putut fi încărcat - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4613,214 +4705,264 @@ To view a guide on how to install FFmpeg, press Help. - + + Load 3DS ROM Files + + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + Select FFmpeg Directory Selectați Directoria FFmpeg - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. Directoria FFmpeg furnizată nu este prezentă %1. Vă rugăm să vă asigurați că ați selectat directoria corectă. - + FFmpeg has been sucessfully installed. FFmpeg era instalat cu succes. - + Installation of FFmpeg failed. Check the log file for details. Instalația FFmpeg a eșuat. Verificați log-urile pentru detalii. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - + Recording %1 Înregistrarea %1 - + Playing %1 / %2 Playing %1 / %2 - + Movie Finished Filmul finisat - + (Accessing SharedExtData) (Se accesează SharedExtData) - + (Accessing SystemSaveData) (Se accesează SystemSaveData) - + (Accessing BossExtData) (Se accesează BossExtData) - + (Accessing ExtData) (Se accesează ExtData) - + (Accessing SaveData) (Se accesează SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Viteză: %1% - + Speed: %1% / %2% Viteză: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Cadru: %1 ms - + VOLUME: MUTE VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUME: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Arhivul sistemului - + System Archive Not Found Fișier de Sistem Negăsit - + System Archive Missing Arhivul Sistemului nu este Prezent - + Save/load Error Eroare la salvare/încărcare - + Fatal Error Eroare Fatală - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered S-a Produs o Eroare Fatală - + Continue Continuă - + Quit Application - + OK OK - + Would you like to exit now? Doriți să ieșiți acum? - + The application is still running. Would you like to stop emulation? - + Playback Completed Redare Finalizată - + Movie playback completed. Redarea filmului a fost finalizată. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window Fereastră Primară - + Secondary Window Fereastră Secundară @@ -4883,42 +5025,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! OpenGL nu este disponibil! - + OpenGL shared contexts are not supported. OpenGL shared contexts nu sunt suportate. - + Error while initializing OpenGL! S-a produs o eroare inițializând OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Este posibil ca GPU-ul dvs. să nu accepte OpenGL, este posibil să nu aveți cel mai recent driver grafic - + Error while initializing OpenGL 4.3! Eroare la inițializarea OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Este posibil ca GPU-ul dvs. să nu accepte OpenGL 4.3, sau dvs. nu aveți cel mai recent driver grafic. <br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! Eroare la inițializare OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Este posibil ca GPU-ul dvs. să nu accepte OpenGL ES 3.2, sau dvs. nu aveți cel mai recent driver grafic. <br><br>GL Renderer:<br>%1 @@ -4926,239 +5068,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Compatibilitate - - + + Region Regiune - - + + File type Tip de Fișier - - + + Size Mărime - - + + Play time Timp de joacă - + Favorite Favorit - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open Deschide - + Application Location Locația Aplicației - + Save Data Location Locația Datelor Salvării - + Extra Data Location Locația Datelor Extra - + Update Data Location Locația Datelor de Actualizare - + DLC Data Location Locația Datelor DLC - + Texture Dump Location Locația Dump-ului de Texturi - + Custom Texture Location Locația Custom a Texturilor - + Mods Location Locația Modurilor - + Dump RomFS Dump RomFS - + Disk Shader Cache Disk Shader Cache - + Open Shader Cache Location Locația Cache-ului de Open Shader - + Delete OpenGL Shader Cache Șterge OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall Dezinstalează - + Everything Totul - + Application - + Update Actualizare - + DLC DLC - + Remove Play Time Data Șterge Datele Timpului de Joacă - + Create Shortcut Creează un Shortcut - + Add to Desktop Adaugă pe desktop - + Add to Applications Menu Adaugă în Meniul de Aplicații - + + Stress Test: App Launch + + + + Properties Proprietăți - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) %1 (Actualizare) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? Sunteți siguri că doriți să dezinstalați '%1'? - + Are you sure you want to uninstall the update for '%1'? Sunteți siguri că doriți să dezinstalați actualizarea pentru '%1'? - + Are you sure you want to uninstall all DLC for '%1'? Sunteți siguri că doriți să dezinstalați toate DLC-urile pentru '%1'? - + Scan Subfolders Scanează Subfolderele - + Remove Application Directory - + Move Up Mută în Sus - + Move Down Mută în Jos - + Open Directory Location Deschide Locația Directorului - + Clear Șterge - + Name Nume @@ -5166,77 +5318,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Perfect - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Grozav - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Bun - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Rău - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Introducere/Meniu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Nu Pornește - + The app crashes when attempting to startup. - + Not Tested Netestat - + The app has not yet been tested. @@ -5244,7 +5396,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5252,27 +5404,27 @@ Screen. GameListSearchField - + of de - + result rezultat - + results rezultate - + Filter: Filtru: - + Enter pattern to filter Introduceți un tipar de filtrare @@ -5280,47 +5432,47 @@ Screen. GameRegion - + Japan Japonia - + North America America de Nord - + Europe Europa - + Australia Australia - + China China - + Korea Coreea - + Taiwan Taiwan - + Invalid region Regiune invalidă - + Region free Region free @@ -5600,87 +5752,87 @@ Screen. Index de Ciclu: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Registre de Adresă: %1, %2 - + Compare Result: %1, %2 Compară Rezultate: %1, %2 - + Static Condition: %1 Condiție Statică: %1 - + Dynamic Conditions: %1, %2 Condiții Dinamice: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Parametrii de Buclă: %1 (repetiții), %2 (inițializator), %3 (increment), %4 - + Instruction offset: 0x%1 Offset de instrucțiuni: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (ultima instrucțiune) @@ -5904,24 +6056,24 @@ Debug Message: Se Pregătesc Texturele %1 / %2 - - Loading Shaders %1 / %2 - Se încarc Texturele %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Se Lansează... - + Now Loading %1 Se Încarcă %1 - + Estimated Time %1 Timpul Estimat %1 @@ -5980,32 +6132,32 @@ Debug Message: Parolă: - + Room Name Nume de Sală - + Preferred Application - + Host Gazdă - + Players Jucători - + Refreshing Actualizând - + Refresh List Actualizează Lista @@ -6088,342 +6240,352 @@ Debug Message: Film - + Help - + Load File... Încarcă fișier... - + Install CIA... Instalează CIA... - + Connect to Artic Base... Conectează la Baza Arctic... - + Set Up System Files... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit - + Pause - + Stop - + Save Salvare - + Load Încarcă - + FAQ FAQ - + About Azahar Despre Azahar - + Single Window Mode Mod Fereastră Unică - + Save to Oldest Slot Salvează în cel mai vechi slot - + Quick Save - + Load from Newest Slot Încarcă din cel mai nou slot - + Quick Load - + Configure... Configurare... - + Display Dock Widget Headers Afișează Titlurile de la Widget-urile de Dock - + Show Filter Bar Afișează Bara de Filtru - + Show Status Bar Afișează Bara de Stare - + Create Pica Surface Viewer Creează Vizualizator de Suprafață de Pica - + Record... Înregistrează... - + Play... Redați... - + Close Închide - + Save without Closing Salvează fără a închide - + Read-Only Mode Modul Read-Only - + Advance Frame Avansează Cadru - + Capture Screenshot Fă o Captură de Ecran - + Dump Video Dump Video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Creează o Sală - + Leave Room Părăsește Sala - + Direct Connect to Room Conexiune Directă spre Sală - + Show Current Room Afișează Sala Curentă - + Fullscreen Ecran Complet - + Open Log Folder Deschide Mapa Log-urilor - + Opens the Azahar Log folder - + Default Implicit - + Single Screen Ecran Simplu - + Large Screen Ecran Larg - + Side by Side Side by Side - + Separate Windows Ferestre Separate - + Hybrid Screen Ecran Hibrid - + Custom Layout Aspect Personalizat - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Schimbă Ecranele - + Rotate Upright Rotește Drept - + Report Compatibility Raportează Compatibiltate - + Restart Repornește - + Load... Încarcă... - + Remove Elimină - + Open Azahar Folder - + Configure Current Application... @@ -6994,32 +7156,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Regiune invalidă - + Installed Titles - + System Titles - + Add New Application Directory - + Favorites diff --git a/dist/languages/ru_RU.ts b/dist/languages/ru_RU.ts index 6e1151340..d1ebe1e48 100644 --- a/dist/languages/ru_RU.ts +++ b/dist/languages/ru_RU.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + @@ -298,8 +298,8 @@ This would ban both their forum username and their IP address. - Emulation: - Эмуляция: + Emulation + Эмуляция @@ -328,8 +328,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Этот эффект постобработки предотвращает появление прерывистости звука и корректирует скорость воспроизведения так, чтобы она совпадала со скоростью эмуляции. Однако всё это увеличивает звуковую задержку. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -338,8 +338,8 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Выравнивает скорость воспроизведения звука с учётом пропуска кадров в эмуляции. Это означает, что звук будет воспроизводиться с полной скоростью даже при низкой частосте кадров в приложении. Может вызывать рассинхронизацию звука. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + @@ -403,6 +403,7 @@ This would ban both their forum username and their IP address. + Camera Камера @@ -414,8 +415,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - Настраиваемая камера: + Camera to Configure + @@ -435,8 +436,8 @@ This would ban both their forum username and their IP address. - Camera mode: - Режим камеры: + Camera mode + @@ -456,8 +457,8 @@ This would ban both their forum username and their IP address. - Camera position: - Позиция камеры: + Camera position + @@ -477,13 +478,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Выберите источник отображения для эмулируемой камеры. Это может быть как картинка, так и настоящая камера. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Источник отображения для камеры: + Camera Image Source + @@ -502,8 +503,8 @@ This would ban both their forum username and their IP address. - File: - Файл: + File + @@ -516,11 +517,6 @@ This would ban both their forum username and their IP address. Select the system camera to use Выберите использование системной камеры - - - Camera: - Камера: - <Default> @@ -534,8 +530,8 @@ This would ban both their forum username and their IP address. - Flip: - Поворот изображения: + Flip + @@ -1024,7 +1020,7 @@ Would you like to ignore the error and continue? Enable Linear Filtering - Включить линейную фильтрацию + @@ -1088,8 +1084,8 @@ Would you like to ignore the error and continue? - Reverse Side by Side - Рядом (в обратном порядке) + Side by Side Full Width + @@ -1139,7 +1135,7 @@ Would you like to ignore the error and continue? Disable Right Eye Rendering - Отключить отрисовку правого глаза + @@ -1147,49 +1143,54 @@ Would you like to ignore the error and continue? <html><head/><body><p>Выключить отрисовку правого глаза</p><p>Отключает отрисовку изображения для правого глаза, когда не используется стереоскопический режим. В некоторых приложениях сильно повышает производительность, но в других может вызвать мелькание.</p></body></html> - + + Swap Eyes + + + + Utility Инструменты - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Заменить текстуры файлами PNG.</p><p>Текстуры загружаются из папки load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures - Использовать внешние текстуры + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Создать дамп текстур в виде файлов PNG.</p><p>Дамп текстур создаётся в папке dump/textures/[Title ID]/.</p></body></html> - - Dump Textures - Создать дамп текстур + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>Загружать сразу все внешние текстуры в память при запуске вместо их подгрузки по мере востребованности приложением.</p></body></html> - - Preload Custom Textures - Предзагрузка внешних текстур + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Загружать внешние текстуры асинхронно в фоновых потоках для снижения подвисаний при загрузке</p></body></html> - - Async Custom Texture Loading - Асинхронная загрузка внешних текстур + + Async custom texture loading + @@ -1201,91 +1202,111 @@ Would you like to ignore the error and continue? - General - Общие + Updates + - Confirm exit while emulation is running - Подтверждать выход при работающей эмуляции - - - - Pause emulation when in background - Приостанавливать эмуляцию при работе в фоновом режиме - - - - Mute audio when in background - Заглушать звук в фоновом режиме - - - - Hide mouse on inactivity - Скрывать курсор мыши во время бездействия - - - - Enable Gamemode - Включить игровой режим - - - Check for updates Проверить обновления - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Общие + + + + Confirm exit while emulation is running + Подтверждать выход при работающей эмуляции + + + + Pause emulation when in background + Приостанавливать эмуляцию при работе в фоновом режиме + + + + Mute audio when in background + Заглушать звук в фоновом режиме + + + + Hide mouse on inactivity + Скрывать курсор мыши во время бездействия + + + + Enable Gamemode + Включить игровой режим + + + Emulation Эмуляция - + Use global emulation speed Использовать глобальную скорость эмуляции - - Set emulation speed: - Установить скорость эмуляции: + + Set emulation speed + - - Emulation Speed: - Скорость эмуляции: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots Скриншоты - + Use global screenshot path Использовать глобальный путь для скриншотов - + Set screenshot path: Установить путь для скриншотов: - + Save Screenshots To Сохранять скриншоты в - + ... ... - + Reset All Settings Сбросить все настройки @@ -1293,8 +1314,8 @@ Would you like to ignore the error and continue? - - + + unthrottled нерегулируемый @@ -1304,12 +1325,12 @@ Would you like to ignore the error and continue? Выбрать папку для скриншотов - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? Точно <b>сбросить ваши настройки</b> и закрыть Azahar? @@ -1363,12 +1384,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation - Генерация шейдеров SPIR-V + SPIR-V shader generation + - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1388,8 +1409,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - Включить аппаратный шейдер + Enable hardware shader + @@ -1398,8 +1419,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - Точное умножение + Accurate multiplication + @@ -1408,8 +1429,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - Включить JIT-компиляцию шейдеров + Enable shader JIT + @@ -1418,18 +1439,18 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation - Включить асинхронную компиляцию шейдеров + Enable async shader compilation + - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Выполнять презентацию в отдельных потоках. При использовании Vulkan улучшает производительность в большинстве приложений.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + - Enable Async Presentation - Включить асинхронную презентацию + Enable async presentation + @@ -1468,13 +1489,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache - Использовать кеш шейдеров на диске + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync предотвращает появление разрывов экрана, но у некоторых графических карт включение опции VSync ухудшает производительность. Если не будет заметного ухудшения производительности, можно оставить её включённой. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1482,22 +1503,32 @@ Would you like to ignore the error and continue? Включить VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global Использовать глобально - + Use per-application - - Delay application render thread: - Задержка потока отрисовки приложения: + + Delay Application Render Thread + - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>Задерживает поток отрисовки эмулирумого приложения на указанное количество миллисекунд при каждой отправке им команд отрисовки на графический процессор.</p><p>Регулируйте эту настройку в (очень немногих) приложениях с динамической частотой кадров, чтобы исправить проблемы с производительностью.</p></body></html> @@ -1982,13 +2013,13 @@ Would you like to ignore the error and continue? - Swap Screens - Поменять экраны местами + Swap screens + - Rotate Screens Upright - Повернуть экраны вертикально + Rotate screens upright + @@ -2104,8 +2135,8 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Процент прозрачности нижнего экрана (только OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + @@ -2276,8 +2307,8 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Узнать больше</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + @@ -2452,8 +2483,8 @@ Would you like to ignore the error and continue? - Use Virtual SD - Использовать виртуальную SD-карту + Use virtual SD card + @@ -2462,7 +2493,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location @@ -2493,6 +2524,16 @@ Would you like to ignore the error and continue? SDMC Directory Каталог SDMC + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2539,8 +2580,8 @@ online features (if installed) - Region: - Регион: + Region + Регион @@ -2548,326 +2589,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Имя пользователя - + Birthday Дата рождения - + January Январь - + February Февраль - + March Март - + April Апрель - + May Май - + June Июнь - + July Июль - + August Август - + September Сентябрь - + October Октябрь - + November Ноябрь - + December Декабрь - + Language Язык - + Note: this can be overridden when region setting is auto-select Примечание: этот параметр может быть переопределён, если включён параметр автовыбора региона - + Japanese (日本語) Японский (日本語) - + English Английский (English) - + French (français) Французский (français) - + German (Deutsch) Немецкий (Deutsch) - + Italian (italiano) Итальянский (italiano) - + Spanish (español) Испанский (español) - + Simplified Chinese (简体中文) Упрощённый китайский (简体中文) - + Korean (한국어) Корейский (한국어) - + Dutch (Nederlands) Голландский (Nederlands) - + Portuguese (português) Португальский (português) - + Russian (Русский) Русский - + Traditional Chinese (正體中文) Традиционный китайский (正體中文) - + Sound output mode Режим вывода звука - + Mono Моно - + Stereo Стерео - + Surround Объёмный - + Country Страна - + Clock Часы - + System Clock Системные часы - + Fixed Time Фиксированное время - + Startup time Время запуска - + yyyy-MM-ddTHH:mm:ss dd-MM-yyyyTHH:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random Случайно - + Fixed Статично - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: ID консоли: - - + + Regenerate Пересоздать - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3577,76 +3629,76 @@ online features (if installed) - - + + Console ID: 0x%1 ID консоли: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Предупреждение - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3764,13 +3816,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Язык интерфейса: + Interface Language + - Theme: - Тема: + Theme + @@ -3779,8 +3831,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - Размер значков: + Icon Size + @@ -3800,8 +3852,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - Текст на 1-й строке: + Row 1 Text + @@ -3835,18 +3887,18 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - Текст на 2-й строке: + Row 2 Text + - Hide Titles without Icon - Скрывать названия игр без значков + Hide titles without icon + - Single Line Mode - Однострочный режим + Single line mode + @@ -3855,7 +3907,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3884,7 +3936,7 @@ Drag points to change position, or double-click table cells to edit values. Show current application in your Discord status - + Показывать текущее приложение в статусе Discord @@ -3938,12 +3990,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Подключение - + Connect Подключиться @@ -4017,7 +4069,7 @@ Drag points to change position, or double-click table cells to edit values. Azahar - Azahar + Azahar @@ -4062,556 +4114,596 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Текущая скорость эмуляции. Значения выше или ниже 100% указывают на то, что эмуляция работает быстрее или медленнее, чем в 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Время, затрачиваемое на эмуляцию кадра 3DS, без учёта ограничения кадров или вертикальной синхронизации. Для полноскоростной эмуляции это значение должно быть не более 16,67 мс. - + MicroProfile (unavailable) - + Clear Recent Files Очистить последние файлы - + &Continue &Продолжить - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - + Azahar не поддерживает GBA Virtual Console. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. Произошла неизвестная ошибка. Подробную информацию см. в журнале. - + CIA must be installed before usage Перед использованием необходимо установить CIA-файл - + Before using this CIA, you must install it. Do you want to install it now? Перед использованием этого CIA-файла, необходимо его установить. Установить сейчас? - + Quick Load Быстрая загрузка - + Quick Save Быстрое сохранение - - + + Slot %1 Ячейка %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder Ошибка открытия папки %1 - - + + Folder does not exist! Папка не существует! - + Remove Play Time Data - + Reset play time? Сбросить игровое время? - - - - + + + + Create Shortcut Создать ярлык - + Do you want to launch the application in fullscreen? Запускать приложение в полном экране? - + Successfully created a shortcut to %1 Успешно создан ярлык для %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 Не удалось создать ярлык для %1 - + Create Icon Создать иконку - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... Создание дампа... - - + + Cancel Отмена - - - - - - - - - + + + + + + + + + Azahar - Azahar + Azahar - + Could not dump base RomFS. Refer to the log for details. Не удалось создать дамп base RomFS. Подробную информацию см. в журнале. - + Error Opening %1 Ошибка при открытии %1 - + Select Directory Выбрать каталог - + Properties Свойства - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Исполняемый файл 3DS (%1);;Все файлы (*.*) - + Load File Загрузка файла - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: Выберите режим установки: - + (ℹ️) Old 3DS setup (ℹ️) Обычная 3DS - - + + Setup is possible. - + (⚠) New 3DS setup (⚠) New 3DS - + Old 3DS setup is required first. Сначала требуется установка обычной 3DS. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Загрузка файлов - - 3DS Installation File (*.CIA*) - Установочный файл 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Все файлы (*.*) - + Connect to Artic Base Подключиться к Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1 был успешно установлен. - + Unable to open File Не удалось открыть файл - + Could not open %1 Не удалось открыть %1 - + Installation aborted Установка прервана - + The installation of %1 was aborted. Please see the log for more details Установка %1 была прервана. Более подробную информацию см. в журнале. - + Invalid File Недопустимый файл - + %1 is not a valid CIA %1 — недопустимый CIA-файл - + CIA Encrypted CIA файл зашифрован - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File Не удалось найти файл - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... Удаление '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. Успешно удалён '%1'. - + File not found Файл не найден - + File "%1" not found Файл «%1» не найден - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Файл Amiibo (%1);; Все файлы (*.*) - + Load Amiibo Загрузка Amiibo - + Unable to open amiibo file "%1" for reading. - + Record Movie Запись видеоролика - + Movie recording cancelled. Запись видеоролика отменена. - - + + Movie Saved Сохранение видеоролика - - + + The movie is successfully saved. Видеоролик сохранён успешно. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4620,214 +4712,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - Выберите каталог FFmpeg - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + Выберите каталог FFmpeg + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Скорость: %1% - + Speed: %1% / %2% Скорость: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Кадр: %1 мс - + VOLUME: MUTE ГРОМКОСТЬ: ЗАГЛУШЕНО - + VOLUME: %1% Volume percentage (e.g. 50%) ГРОМКОСТЬ: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Системный архив - + System Archive Not Found Системный архив не найден - + System Archive Missing Не удалось найти системный архив - + Save/load Error Ошибка сохранения/загрузки - + Fatal Error Неустранимая ошибка - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered Произошла неустранимая ошибка - + Continue Продолжить - + Quit Application Закрыть Приложение - + OK OK - + Would you like to exit now? Выйти сейчас? - + The application is still running. Would you like to stop emulation? - + Playback Completed Воспроизведение завершено - + Movie playback completed. Воспроизведение видеоролика завершено. - + Update Available Доступно обновление - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window Основной Экран - + Secondary Window Дополнительный Экран @@ -4890,42 +5032,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! OpenGL недоступен! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! Ошибка при инициализации OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! Ошибка при инициализации OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4933,239 +5075,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Совместимость - - + + Region Регион - - + + File type Тип файла - - + + Size Размер - - + + Play time Игровое время - + Favorite Избранное - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open Открыть - + Application Location Путь к приложению - + Save Data Location Путь к файлам сохранений - + Extra Data Location - + Update Data Location Путь к файлам обновлений - + DLC Data Location Путь к файлам DLC - + Texture Dump Location Путь к файлам дампа текстур - + Custom Texture Location Путь к пользовательским текстурам - + Mods Location Путь к модификациям - + Dump RomFS Создать дамп RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall Удалить - + Everything Всё - + Application Приложение - + Update Обновления - + DLC - + Remove Play Time Data - + Create Shortcut Создать ярлык - + Add to Desktop Добавить на рабочий стол - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties Свойства - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders Сканировать подпапки - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location Открыть расположение каталога - + Clear Очистить - + Name Имя @@ -5173,77 +5325,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Отлично - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Хорошо - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Удовлетворительно - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Плохо - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Вступительный видеоролик/меню - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Не запускается - + The app crashes when attempting to startup. - + Not Tested Не проверялась - + The app has not yet been tested. @@ -5251,7 +5403,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5259,27 +5411,27 @@ Screen. GameListSearchField - + of из - + result результат - + results результатов - + Filter: Фильтр: - + Enter pattern to filter Введите шаблон для фильтрации @@ -5287,47 +5439,47 @@ Screen. GameRegion - + Japan Япония - + North America Северная Америка - + Europe Европа - + Australia Австралия - + China Китай - + Korea Корея - + Taiwan Тайвань - + Invalid region Недопустимый регион - + Region free Без указания региона @@ -5607,87 +5759,87 @@ Screen. Индекс цикла: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Адресные регистры: %1, %2 - + Compare Result: %1, %2 Сравнить результат: %1, %2 - + Static Condition: %1 Статическое состояние: %1 - + Dynamic Conditions: %1, %2 Динамические состояния: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Параметры цикла: %1 (повторов), %2 (инициализатор), %3 (приращение), %4 - + Instruction offset: 0x%1 Смещение инструкции: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (последняя инструкция) @@ -5911,24 +6063,24 @@ Debug Message: Подготовка шейдеров %1 / %2 - - Loading Shaders %1 / %2 - Загрузка шейдеров %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Запуск... - + Now Loading %1 Выполняется загрузка %1 - + Estimated Time %1 Оставшееся время %1 @@ -5987,32 +6139,32 @@ Debug Message: Пароль: - + Room Name Название комнаты - + Preferred Application - + Host Хост - + Players Игроки - + Refreshing Обновление - + Refresh List Обновить список @@ -6095,342 +6247,352 @@ Debug Message: Видеоролик - + Help - + Load File... Загрузить файл... - + Install CIA... Установить CIA... - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit Выход - + Pause - + Stop - + Save Сохранить - + Load Загрузить - + FAQ FAQ - + About Azahar Об Azahar - + Single Window Mode Режим одного окна - + Save to Oldest Slot Сохранить в самую раннюю ячейку - + Quick Save Быстрое сохранение - + Load from Newest Slot Загрузить из самой последней ячейки - + Quick Load Быстрая загрузка - + Configure... Настроить... - + Display Dock Widget Headers Отображать заголовки закреплённых виджетов - + Show Filter Bar Показывать панель фильтров - + Show Status Bar Показывать строку состояния - + Create Pica Surface Viewer Создать просмотрщик поверхностей Pica - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame Следующий кадр - + Capture Screenshot Сделать снимок экрана - + Dump Video Создать дамп видео + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Создать комнату - + Leave Room Покинуть комнату - + Direct Connect to Room Прямое подключение к комнате - + Show Current Room Показать текущую комнату - + Fullscreen Полный экран - + Open Log Folder - + Opens the Azahar Log folder - + Default По умолчанию - + Single Screen Один экран - + Large Screen Большой экран - + Side by Side Рядом - + Separate Windows Отдельные окна - + Hybrid Screen Совмещённый экран - + Custom Layout Своя компоновка - + Top Right - + Middle Right Посередине справа - + Bottom Right - + Top Left - + Middle Left Посередине слева - + Bottom Left Снизу слева - + Above - + Below - + Swap Screens Смена экранов - + Rotate Upright Повернуть вертикально - + Report Compatibility Сообщить о совместимости - + Restart Перезапустить - + Load... Загрузить... - + Remove Удалить - + Open Azahar Folder - + Configure Current Application... @@ -6503,7 +6665,7 @@ Debug Message: File: - Файл: + @@ -6595,7 +6757,7 @@ Debug Message: File: - Файл: + @@ -7001,32 +7163,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Недопустимый регион - + Installed Titles Названия установленных игр - + System Titles Названия предустановленных игр - + Add New Application Directory - + Favorites @@ -7277,7 +7439,8 @@ They may have left the room. Azahar has detected user data for Citra. - + Azahar обнаружил файлы пользователя Citra. + diff --git a/dist/languages/sv.ts b/dist/languages/sv.ts index 230108584..e1f412b0f 100644 --- a/dist/languages/sv.ts +++ b/dist/languages/sv.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,8 +298,8 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - Emulation: - Emulering: + Emulation + Emulering @@ -328,8 +328,8 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Denna efterbehandlingseffekt justerar ljudhastigheten för att matcha emuleringshastigheten och hjälper till att förhindra ljudstörningar. Detta kan dock öka ljudlatensen. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + <html><head/><body><p>Denna efterbearbetningseffekt justerar ljudhastigheten så att den matchar emuleringshastigheten och hjälper till att förhindra ljudhack. Detta ökar dock ljudfördröjningen.</p></body></html> @@ -338,8 +338,8 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Skalar uppspelningshastigheten för ljud för att kompensera för minskad bildfrekvens i emuleringen. Detta innebär att ljudet spelas upp med full hastighet även om programmets bildfrekvens är låg. Kan orsaka problem med felsynkronisering av ljud. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + <html><head/><body><p>Anpassar ljuduppspelningshastigheten för att kompensera för minskad bildfrekvens i emuleringen. Detta innebär att ljudet spelas upp i full hastighet även när applikationens bildfrekvens är låg. Kan orsaka problem med ljudsynkronisering.</p></body></html> @@ -403,6 +403,7 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. + Camera Kamera @@ -414,8 +415,8 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - Camera to configure: - Kamera att konfigurera: + Camera to Configure + Kamera att konfigurera @@ -435,8 +436,8 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - Camera mode: - Kameraläge: + Camera mode + Kameraläge @@ -456,8 +457,8 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - Camera position: - Kameraposition: + Camera position + Kameraposition @@ -477,13 +478,13 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Välj varifrån bilden av den emulerade kameran kommer. Det kan vara en bild eller en riktig kamera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + <html><head/><body><p>Välj var bilden från den emulerade kameran kommer ifrån. Det kan vara en bild eller en riktig kamera.</p></body></html> - Camera Image Source: - Inmatningskälla för kamera: + Camera Image Source + Kamerabildskälla @@ -502,8 +503,8 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - File: - Fil: + File + Fil @@ -516,11 +517,6 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress.Select the system camera to use Välj systemkameran att använda - - - Camera: - Kamera: - <Default> @@ -534,8 +530,8 @@ Detta skulle bannlysa både deras forumanvändarnamn och deras IP-adress. - Flip: - Vänd: + Flip + Vänd @@ -1024,7 +1020,7 @@ Vill du ignorera felet och fortsätta? Enable Linear Filtering - Aktivera linjär filtering + Aktivera linjär filtrering @@ -1088,8 +1084,8 @@ Vill du ignorera felet och fortsätta? - Reverse Side by Side - Omvänd sida vid sida + Side by Side Full Width + Sida vid sida full bredd @@ -1139,7 +1135,7 @@ Vill du ignorera felet och fortsätta? Disable Right Eye Rendering - Avaktivera rendering för höger öga + Inaktivera rendering för höger öga @@ -1147,48 +1143,53 @@ Vill du ignorera felet och fortsätta? <html><head/><body><p>Inaktivera rendering av höger öga</p><p>Inaktiverar rendering av högerögats bild när stereoskopiskt läge inte används. Förbättrar prestandan avsevärt i vissa applikationer, men kan orsaka flimmer i andra.</p></body></html> - + + Swap Eyes + Byt ögon + + + Utility Verktyg - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Ersätt texturer med PNG- filer.</p><p>Texturer läses in från load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures Använd anpassade texturer - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>Dumpa texturer till PNG-filer.</p><p>Texturer dumpas till dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures Dumpa texturer - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>Läs in alla anpassade texturer i minnet vid uppstart, istället för att läsa in dem när programmet kräver dem.</p></body></html> - - Preload Custom Textures - Förinläs anpassade texturer + + Preload custom textures + Förladda anpassade texturer - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>Läs in anpassade texturer asynkront med bakgrundstrådar för att minska inläsningsskakning</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading Asynkron inläsning av anpassade texturer @@ -1201,91 +1202,111 @@ Vill du ignorera felet och fortsätta? - General - Allmänt + Updates + Uppdateringar - Confirm exit while emulation is running - Bekräfta avsluta när emuleringen körs - - - - Pause emulation when in background - Pausa emulering när i bakgrunden - - - - Mute audio when in background - Inget ljud när i bakgrunden - - - - Hide mouse on inactivity - Dölj muspekare vid inaktivitet - - - - Enable Gamemode - Aktivera spelläge - - - Check for updates Leta efter uppdateringar - + + Update Channel + Uppdateringskanal + + + + Stable + Stabil + + + + Prerelease + Förutgåva + + + + General + Allmänt + + + + Confirm exit while emulation is running + Bekräfta avsluta när emuleringen körs + + + + Pause emulation when in background + Pausa emulering när i bakgrunden + + + + Mute audio when in background + Inget ljud när i bakgrunden + + + + Hide mouse on inactivity + Dölj muspekare vid inaktivitet + + + + Enable Gamemode + Aktivera spelläge + + + Emulation Emulering - + Use global emulation speed Använd global emuleringshastighet - - Set emulation speed: - Ställ in emuleringshastighet: + + Set emulation speed + Ställ in emuleringshastighet - - Emulation Speed: - Emuleringshastighet: + + Emulation Speed + Emuleringshastighet - + Turbo Speed Limit: Begränsa turbohastighet: - + Screenshots Skärmbilder - + Use global screenshot path Använd global sökväg för skärmbilder - + Set screenshot path: Ange sökväg för skärmbilder: - + Save Screenshots To Spara skärmbilder till - + ... ... - + Reset All Settings Nollställ alla inställningar @@ -1293,8 +1314,8 @@ Vill du ignorera felet och fortsätta? - - + + unthrottled full hastighet @@ -1304,12 +1325,12 @@ Vill du ignorera felet och fortsätta? Välj katalog för skärmdump - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? Är du säker att du vill <b>återställa dina inställningar</b> och stänga Azahar? @@ -1363,13 +1384,13 @@ Vill du ignorera felet och fortsätta? - SPIR-V Shader Generation - SPIR-V Shader-generering + SPIR-V shader generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer - Inaktivera GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer + Inaktivera GLSL -> SPIR-V-optimerare @@ -1388,7 +1409,7 @@ Vill du ignorera felet och fortsätta? - Enable Hardware Shader + Enable hardware shader Aktivera hårdvaru-shader @@ -1398,7 +1419,7 @@ Vill du ignorera felet och fortsätta? - Accurate Multiplication + Accurate multiplication Exakt multiplikation @@ -1408,8 +1429,8 @@ Vill du ignorera felet och fortsätta? - Enable Shader JIT - Aktivera Shader JIT + Enable shader JIT + Aktivera shader JIT @@ -1418,18 +1439,18 @@ Vill du ignorera felet och fortsätta? - Enable Async Shader Compilation + Enable async shader compilation Aktivera asynkron shader-kompilering - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Utför presentationen i separata trådar. Förbättrar prestandan när Vulkan används i de flesta applikationer.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + <html><head/><body><p>Utför presentation på separata trådar. Förbättrar prestandan vid användning av Vulkan i de flesta applikationer. Lägger till ~1 bildruta i inmatningsfördröjning.</p></body></html> - Enable Async Presentation - Aktivera asynkron presentation + Enable async presentation + Aktivera async-presentation @@ -1468,13 +1489,13 @@ Vill du ignorera felet och fortsätta? - Use Disk Shader Cache - Använd disk shadercache + Use disk shader cache + Använd diskcache för shader - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync förhindrar grafikproblem, men vissa grafikkort har lägre prestanda med VSync aktiverat. Låt det vara aktiverat om du inte märker någon prestandaskillnad. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + <html><head/><body><p>VSync förhindrar att skärmen flimrar, men vissa grafikkort har sämre prestanda när VSync är aktiverat. Låt det vara aktiverat om du inte märker någon skillnad i prestanda.</p></body></html> @@ -1482,22 +1503,32 @@ Vill du ignorera felet och fortsätta? Aktivera VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + <html><head/><body><p>När denna inställning är aktiverad upptäcker den när skärmens uppdateringsfrekvens är lägre än för 3DS, och när så är fallet inaktiveras VSync automatiskt för att undvika att emuleringshastigheten tvingas ned under 100%.</p></body></html> + + + + Enable display refresh rate detection + Aktivera detektering av skärmens uppdateringsfrekvens + + + Use global Använd globalt - + Use per-application Använd per-applikation - - Delay application render thread: - Fördröj applikationens renderingstråd: + + Delay Application Render Thread + Fördröj applikationsrenderingstråd - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>Fördröjer det emulerade programmets renderingstråd med det angivna antalet millisekunder varje gång den skickar renderingskommandon till GPU:n.</p><p>Justera den här funktionen i de (mycket få) dynamiska bildfrekvensapplikationerna för att åtgärda prestandaproblem.</p></body></html> @@ -1982,13 +2013,13 @@ Vill du ignorera felet och fortsätta? - Swap Screens + Swap screens Växla skärmar - Rotate Screens Upright - Rotera skärmarna upprätt + Rotate screens upright + Rotera skärmar upprätt @@ -2104,8 +2135,8 @@ Vill du ignorera felet och fortsätta? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Opacitet för nedre skärmen % (endast OpenGL)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + <html><head/><body><p>Opacitet för nedre skärm %</p></body></html> @@ -2276,8 +2307,8 @@ Vill du ignorera felet och fortsätta? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Lär dig mer</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Läs mer</span></a> @@ -2452,8 +2483,8 @@ Vill du ignorera felet och fortsätta? - Use Virtual SD - Använd Virtual SD + Use virtual SD card + Använd virtuellt SD-kort @@ -2462,8 +2493,8 @@ Vill du ignorera felet och fortsätta? - Use Custom Storage - Använd anpassad lagring + Use custom storage location + Använd anpassad lagringsplats @@ -2493,6 +2524,16 @@ Vill du ignorera felet och fortsätta? SDMC Directory SDMC-katalog + + + Compress installed CIA content + Komprimera installerat CIA-innehåll + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + <html><head/><body><p>Komprimerar innehållet i CIA-filer när det installeras på det emulerade SD-kortet. Påverkar endast CIA-innehåll som installeras medan inställningen är aktiverad.</p></body></html> + Select NAND Directory @@ -2540,8 +2581,8 @@ onlinefunktioner (om installerade) - Region: - Region: + Region + Region @@ -2549,326 +2590,338 @@ onlinefunktioner (om installerade) Välj automatiskt - + + Apply region free patch to +installed applications. + Tillämpa regionsfri patch till +installerade applikationer. + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + Patchar regionen för installerade applikationer till att vara regionsfria så att de alltid visas på hemmenyn. + + + Username Användarnamn - + Birthday Födelsedag - + January Januari - + February Februari - + March Mars - + April April - + May Maj - + June Juni - + July Juli - + August Augusti - + September September - + October Oktober - + November November - + December December - + Language Språk - + Note: this can be overridden when region setting is auto-select Obs: detta kan åsidosättas när regioninställningen är automatiskt vald - + Japanese (日本語) Japanska (日本語) - + English Engelska - + French (français) Franska (français) - + German (Deutsch) Tyska (Deutsch) - + Italian (italiano) Italienska (italiano) - + Spanish (español) Spanska (español) - + Simplified Chinese (简体中文) Förenklad kinesiska (简体中文) - + Korean (한국어) Koreanska (한국어) - + Dutch (Nederlands) Nederländska (Nederlands) - + Portuguese (português) Portugisiska (português) - + Russian (Русский) Ryska (Русский) - + Traditional Chinese (正體中文) Traditionell kinesiska (正體中文) - + Sound output mode Läge för ljudutmatning - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Land - + Clock Klocka - + System Clock Systemklocka - + Fixed Time Fast tid - + Startup time Uppstartstid - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time - Offset-tid + Tidsförskjutning - + days dagar - + HH:mm:ss HH:mm:ss - + Initial System Ticks Initiala systemticks - + Random Slumpmässig - + Fixed Fast - + Initial System Ticks Override Åsidosätt Initial System Ticks - + Play Coins Spelmynt - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>Antal steg per timme som rapporterats av stegmätaren. Intervall från 0 till 65,535.</p></body></html> - + Pedometer Steps per Hour Stegmätare steg per timme - + Run System Setup when Home Menu is launched Kör System Setup när Home Menu startas - + Console ID: Konsol-ID: - - + + Regenerate Generera om - + MAC: MAC: - - 3GX Plugin Loader: - Inläsare för 3GX-insticksmodul: + + 3GX Plugin Loader + 3GX-insticksläsare - + Enable 3GX plugin loader Aktivera inläsare för 3GX-insticksmodul - + Allow applications to change plugin loader state Tillåt applikationer att ändra tillståndet för inläsaren av insticksmoduler - + Real Console Unique Data Unikt data från riktig konsoll - + Your real console is linked to Azahar. Din riktiga konsoll är länkad till Azahar. - + Unlink Koppla bort - + OTP OTP - - - - + + + + Choose Välj - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. Systeminställningarna är endast tillgängliga när applikationer inte körs. @@ -3578,76 +3631,76 @@ onlinefunktioner (om installerade) Sed-fil (*.sed);;Alla filer (*.*) - - + + Console ID: 0x%1 Konsol-ID: 0x%1 - - + + MAC: %1 MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? Detta kommer att ersätta ditt nuvarande virtuella 3DS-konsol-ID med ett nytt. Ditt nuvarande virtuella 3DS-konsol-ID kommer inte att kunna återställas. Detta kan ha oväntade effekter i applikationer. Detta kan misslyckas om du använder en föråldrad konfigurationssparning. Fortsätta? - - - + + + Warning Varning - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? Detta kommer att ersätta din nuvarande MAC-adress med en ny. Det är inte rekommenderat att göra detta om du fick MAC-adressen från din riktiga konsol med hjälp av installationsverktyget. Fortsätta? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? Denna åtgärd kommer att koppla bort din riktiga konsol från Azahar, med följande konsekvenser: <br><ul><li>Din OTP, SecureInfo och LocalFriendCodeSeed kommer att tas bort från Azahar. </li><li>Din vänlista kommer att återställas och du kommer att loggas ut från ditt NNID/PNID-konto.</li><li> Systemfiler och e-shop-titlar som erhållits via Azahar kommer att bli oåtkomliga tills samma konsol länkas igen (sparade data kommer inte att gå förlorade).</li></ul><br> Fortsätta? - + Invalid country for configured region Ogiltigt land för konfigurerad region - + Invalid country for console unique data Ogiltigt land för konsollunikt data - + Status: Loaded Status: Inläst - + Status: Loaded (Invalid Signature) Status: Inläst (ogiltig signatur) - + Status: Loaded (Region Changed) Status: Inläst (ändrad region) - + Status: Not Found Status: Hittades inte - + Status: Invalid Status: Ogiltig - + Status: IO Error Status: In/ut-fel @@ -3763,13 +3816,13 @@ Dra punkterna för att ändra position, eller dubbelklicka på tabellcellerna f - Interface language: - Gränssnittsspråk: + Interface Language + Gränssnittsspråk - Theme: - Tema: + Theme + Tema @@ -3778,8 +3831,8 @@ Dra punkterna för att ändra position, eller dubbelklicka på tabellcellerna f - Icon Size: - Ikonstorlek: + Icon Size + Ikonstorlek @@ -3799,8 +3852,8 @@ Dra punkterna för att ändra position, eller dubbelklicka på tabellcellerna f - Row 1 Text: - Rad 1-text: + Row 1 Text + Rad 1-text @@ -3834,18 +3887,18 @@ Dra punkterna för att ändra position, eller dubbelklicka på tabellcellerna f - Row 2 Text: - Rad 2-text: + Row 2 Text + Rad 2-text - Hide Titles without Icon + Hide titles without icon Dölj titlar utan ikon - Single Line Mode - Enkel rad-läge + Single line mode + Enradigt läge @@ -3854,8 +3907,8 @@ Dra punkterna för att ändra position, eller dubbelklicka på tabellcellerna f - Show Advanced Frame Time Info - Visa avancerad information om bildrutor + Show advanced frame time info + Visa avancerad bildtidsinformation @@ -3937,12 +3990,12 @@ Dra punkterna för att ändra position, eller dubbelklicka på tabellcellerna f DirectConnectWindow - + Connecting Ansluter - + Connect Anslut @@ -4062,471 +4115,511 @@ Kontrollera din FFmpeg-installation som användes för kompilering. GMainWindow - + No Suitable Vulkan Devices Detected Inga lämpliga Vulkan-enheter upptäcktes - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. Vulkan-initialiseringen misslyckades under uppstarten.<br/>Din GPU kanske inte stöder Vulkan 1.1, eller så har du inte den senaste grafikdrivrutinen. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. Aktuell hastighet för Artic-trafiken. Högre värden indikerar större överföringslaster. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Aktuell emuleringshastighet. Värden som är högre eller lägre än 100% indikerar att emuleringen körs snabbare eller långsammare än 3DS. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. Hur många bilder per sekund som appen visar för närvarande. Detta varierar från app till app och från scen till scen. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tidsåtgång för att emulera en 3DS-bildruta, utan att räkna med framelimiting eller v-sync. För emulering med full hastighet bör detta vara högst 16,67 ms. - + MicroProfile (unavailable) MicroProfile (inte tillgänglig) - + Clear Recent Files Töm senaste filer - + &Continue &Fortsätt - + &Pause &Paus - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar kör en applikation - - + + Invalid App Format Ogiltigt appformat - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Ditt appformat stöds inte.<br/>Följ anvisningarna för att återdumpa dina <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>spelkassetter</a> eller <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installerade titlar</a>. - + App Corrupted Appen skadad - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Din app är skadad. <br/>Följ guiderna för att återdumpa dina <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>spelkassetter</a> eller <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installerade titlar</a>. - + App Encrypted App krypterad - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Din app är krypterad. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Mer information finns på vår blogg.</a> - + Unsupported App App som inte stöds - + GBA Virtual Console is not supported by Azahar. GBA Virtual Console stöds inte av Azahar. - - + + Artic Server Artic-server - + + Invalid system mode + Ogiltigt systemläge + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + Nya 3DS-exklusiva applikationer kan inte läsas in utan att aktivera Ny 3DS-läget. + + + Error while loading App! Fel vid inläsning av app! - + An unknown error occurred. Please see the log for more details. Ett okänt fel har inträffat. Se loggen för mer information. - + CIA must be installed before usage CIA måste installeras före användning - + Before using this CIA, you must install it. Do you want to install it now? Innan du använder denna CIA måste du installera den. Vill du installera den nu? - + Quick Load Snabbinläsning - + Quick Save Snabbsparning - - + + Slot %1 Plats %1 - + %2 %3 %2 %3 - + Quick Save - %1 Snabbsparning - %1 - + Quick Load - %1 Snabbinläsning - %1 - + Slot %1 - %2 %3 Plats %1 - %2 %3 - + Error Opening %1 Folder Fel vid öppning av mappen %1 - - + + Folder does not exist! Mappen finns inte! - + Remove Play Time Data Ta bort data om speltid - + Reset play time? Återställ speltid? - - - - + + + + Create Shortcut Skapa genväg - + Do you want to launch the application in fullscreen? Vill du starta applikationen i helskärm? - + Successfully created a shortcut to %1 Skapade framgångsrikt en genväg till %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? Detta kommer att skapa en genväg till den aktuella AppImage. Detta kanske inte fungerar så bra om du uppdaterar. Fortsätta? - + Failed to create a shortcut to %1 Misslyckades med att skapa en genväg till %1 - + Create Icon Skapa ikon - + Cannot create icon file. Path "%1" does not exist and cannot be created. Det går inte att skapa en ikonfil. Sökvägen "%1" finns inte och kan inte skapas. - + Dumping... Dumpar... - - + + Cancel Avbryt - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. Kunde inte dumpa RomFS-basen. Se loggen för mer information. - + Error Opening %1 Fel vid öppning av %1 - + Select Directory Välj katalog - + Properties Egenskaper - + The application properties could not be loaded. Applikationsegenskaperna kunde inte läsas in. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. Körbar 3DS-fil (%1);;Alla filer (*.*) - + Load File Läs in fil - - + + Set Up System Files Konfigurera systemfiler - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> <p>Azahar behöver konsolunika data och firmware-filer från en riktig konsol för att kunna använda vissa av dess funktioner. <br>Sådana filer och data kan konfigureras med <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool </a><br>Observera:<ul><li><b> Den här åtgärden installerar konsolunika data till Azahar, dela inte dina användar- eller nand-mappar<br> efter att du har utfört installationsprocessen!</b></li><li> Under installationsprocessen kommer Azahar att länkas till den konsol som kör installationsverktyget. Du kan koppla bort <br>konsolen senare från fliken System i emulatorns konfigurationsmeny. </li><li>Gå inte online med både Azahar och din 3DS-konsol samtidigt efter att du har konfigurerat systemfiler, <br>eftersom det kan orsaka problem.</li><li> En installation av den gamla 3DS:en behövs för att installationen av den nya 3DS:en ska fungera (vi rekommenderar att du gör båda installationslägena).</li><li> Båda installationslägena fungerar oavsett vilken konsolmodell som kör installationsverktyget.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: Ange adressen till Azahar Artic Setup Tool: - + <br>Choose setup mode: <br>Välj konfigurationsläge: - + (ℹ️) Old 3DS setup (ℹ️) Gammal 3DS-konfiguration - - + + Setup is possible. Konfiguration är möjlig. - + (⚠) New 3DS setup (⚠) Ny 3DS-konfiguration - + Old 3DS setup is required first. Gammal 3DS-konfiguration krävs först. - + (✅) Old 3DS setup (✅) Gammal 3DS-konfiguration - - + + Setup completed. Konfigurationen är färdig. - + (ℹ️) New 3DS setup (ℹ️) Ny 3DS-konfiguration - + (✅) New 3DS setup (✅) Ny 3DS-konfiguration - + The system files for the selected mode are already set up. Reinstall the files anyway? Systemfilerna för det valda läget är redan konfigurerade. Installera om filerna i alla fall? - + Load Files Läs in filer - - 3DS Installation File (*.CIA*) - 3DS-installationsfil (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + 3DS-installationsfil (*.cia *.zcia) - + + + All Files (*.*) Alla filer (*.*) - + Connect to Artic Base Anslut till Artic Base - + Enter Artic Base server address: Ange Artic Base-serveradress: - + %1 has been installed successfully. %1 har installerats. - + Unable to open File Kunde inte öppna filen - + Could not open %1 Kunde inte öppna %1 - + Installation aborted Installationen avbröts - + The installation of %1 was aborted. Please see the log for more details Installationen av %1 avbröts. Se loggen för mer information - + Invalid File Ogiltig fil - + %1 is not a valid CIA %1 är inte en giltig CIA - + CIA Encrypted CIA-krypterad - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> Din CIA-fil är krypterad.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Kolla vår blogg för mer info</a> - + Unable to find File Det går inte att hitta filen - + Could not find %1 Kunde inte hitta %1 - + + + + + Z3DS Compression + Z3DS-komprimering + + + + Failed to compress some files, check log for details. + Misslyckades med att komprimera några filer. Kontrollera loggen. + + + + Failed to decompress some files, check log for details. + Misslyckades med att packa upp några filer. Kontrollera loggen. + + + + All files have been compressed successfully. + Alla filer har komprimerats utan problem. + + + + All files have been decompressed successfully. + Alla filer har packats upp utan problem. + + + Uninstalling '%1'... Avinstallation av "%1"... - + Failed to uninstall '%1'. Misslyckades med att avinstallera "%1". - + Successfully uninstalled '%1'. Avinstallationen av "%1" har lyckats. - + File not found Filen hittades inte - + File "%1" not found Filen "%1" hittades inte - + Savestates Sparade tillstånd - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! @@ -4535,86 +4628,86 @@ Use at your own risk! Använd på egen risk! - - - + + + Error opening amiibo data file Fel vid öppning av amiibo datafil - + A tag is already in use. En tagg är redan i bruk. - + Application is not looking for amiibos. Applikationen letar inte efter amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo-fil (%1);; Alla filer (*.*) - + Load Amiibo Läs in Amiibo - + Unable to open amiibo file "%1" for reading. Det gick inte att öppna amiibo-filen "%1" för läsning. - + Record Movie Spela in film - + Movie recording cancelled. Filminspelning avbruten. - - + + Movie Saved Filmen sparades - - + + The movie is successfully saved. Filmen sparades. - + Application will unpause Applikationen kommer att återupptas - + The application will be unpaused, and the next frame will be captured. Is this okay? Applikationen kommer att återupptas och nästa bildruta kommer att fångas. Är det här okej? - + Invalid Screenshot Directory Ogiltig katalog för skärmbilder - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. Det går inte att skapa angiven skärmbildskatalog. Sökvägen för skärmbilder återställs till sitt standardvärde. - + Could not load video dumper Kunde inte läsa in videodumpern - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4627,215 +4720,265 @@ För att installera FFmpeg till Azahar, tryck på Öppna och välj din FFmpeg-ka Om du vill visa en guide om hur du installerar FFmpeg trycker du på Hjälp. - + + Load 3DS ROM Files + Läs in 3DS ROM-filer + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + 3DS ROM-filer (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + 3DS Compressed ROM File (*.%1) + Komprimerad 3DS ROM-fil (*.%1) + + + + Save 3DS Compressed ROM File + Spara komprimerad 3DS ROM-fil + + + + Select Output 3DS Compressed ROM Folder + Välj utdatamapp för 3DS-komprimerad ROM + + + + Load 3DS Compressed ROM Files + Läs in 3DS-komprimerade ROM-filer + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + Komprimerade 3DS ROM-filer (*.zcia *zcci *z3dsx *zcxi) + + + + 3DS ROM File (*.%1) + 3DS ROM-fil (*.%1) + + + + Save 3DS ROM File + Spara 3DS ROM-fil + + + + Select Output 3DS ROM Folder + Välj utdatamapp för 3DS ROM + + + Select FFmpeg Directory Välj FFmpeg-katalog - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. Den angivna FFmpeg-katalogen saknar %1. Kontrollera att rätt katalog har valts. - + FFmpeg has been sucessfully installed. FFmpeg har installerats. - + Installation of FFmpeg failed. Check the log file for details. Installationen av FFmpeg misslyckades. Kontrollera loggfilen för mer information. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. Det gick inte att starta videodumpningen.<br>Kontrollera att videokodaren är korrekt konfigurerad.<br>Se loggen för mer information. - + Recording %1 Spelar in %1 - + Playing %1 / %2 Spelar %1 / %2 - + Movie Finished Filmen är färdig - + (Accessing SharedExtData) (Åtkomst till SharedExtData) - + (Accessing SystemSaveData) (Åtkomst till SystemSaveData) - + (Accessing BossExtData) (Åtkomst till BossExtData) - + (Accessing ExtData) (Åtkomst till ExtData) - + (Accessing SaveData) (Åtkomst till SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 Artic-trafik: %1 %2%3 - + Speed: %1% Hastighet: %1% - + Speed: %1% / %2% Hastighet: %1% / %2% - + App: %1 FPS App: %1 bilder/s - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) Bildruta: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Bildruta: %1 ms - + VOLUME: MUTE VOLYM: TYST - + VOLUME: %1% Volume percentage (e.g. 50%) VOLYM: %1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - %1 saknas. <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Dumpa dina systemarkiv</a>.<br/>Fortsatt emulering kan resultera i krascher och buggar. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + %1 saknas. <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Dumpa dina systemarkiv</a>.<br/>Fortsatt emulering kan resultera i krascher och buggar. - + A system archive Ett systemarkiv - + System Archive Not Found Systemarkiv hittades inte - + System Archive Missing Systemarkiv saknas - + Save/load Error Fel vid spara/läs in - + Fatal Error Ödesdigert fel - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Ett allvarligt fel har inträffat. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Kontrollera loggen</a> för mer information.<br/>Fortsatt emulering kan leda till krascher och buggar. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + Ett ödesdigert fel inträffade. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Kontrollera loggen</a> för detaljer.<br/>Fortsatt emulering kan resultera i krascher och buggar. - + Fatal Error encountered Allvarligt fel uppstod - + Continue Fortsätt - + Quit Application Avsluta applikation - + OK Ok - + Would you like to exit now? Vill du avsluta nu? - + The application is still running. Would you like to stop emulation? Applikationen körs fortfarande. Vill du stoppa emuleringen? - + Playback Completed Uppspelningen är färdig - + Movie playback completed. Uppspelning av film slutförd. - + Update Available Uppdatering tillgänglig - + Update %1 for Azahar is available. Would you like to download it? Uppdatering %1 för Azahar finns tillgänglig. Vill du hämta ner den? - + Primary Window Primärt fönster - + Secondary Window Sekundärt fönster @@ -4898,42 +5041,42 @@ Vill du hämta ner den? GRenderWindow - + OpenGL not available! OpenGL är inte tillgängligt! - + OpenGL shared contexts are not supported. Delade OpenGL-kontexter stöds inte. - + Error while initializing OpenGL! Fel vid initiering av OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Din GPU kanske inte stöder OpenGL, eller så har du inte den senaste grafikdrivrutinen. - + Error while initializing OpenGL 4.3! Fel vid initiering av OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Din GPU kanske inte stöder OpenGL 4.3, eller så har du inte den senaste grafikdrivrutinen.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! Fel vid initiering av OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Din GPU kanske inte stöder OpenGL ES 3.2, eller så har du inte den senaste grafikdrivrutinen.<br><br>GL Renderer:<br>%1 @@ -4941,175 +5084,185 @@ Vill du hämta ner den? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - VIKTIGT: Krypterade filer och .3ds-filer stöds inte längre. Dekryptering och/eller namnändring till .cci kan vara nödvändigt. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Läs mer om hur du gör. - - - - Don't show again - Visa inte igen - - - - + + Compatibility Kompatibilitet - - + + Region Region - - + + File type Filtyp - - + + Size Storlek - - + + Play time Speltid - + Favorite Favorit - + + Eject Cartridge + Mata ut cartridge + + + + Insert Cartridge + Mata in cartridge + + + Open Öppna - + Application Location Programplats - + Save Data Location Plats för sparat data - + Extra Data Location Plats för extradata - + Update Data Location Plats för uppdateringsdata - + DLC Data Location Plats för DLC-data - + Texture Dump Location Plats för texturdumpar - + Custom Texture Location Plats för anpassade texturer - + Mods Location Plats för mods - + Dump RomFS Dumpa RomFS - + Disk Shader Cache Disk shadercache - + Open Shader Cache Location Öppna plats för shadercache - + Delete OpenGL Shader Cache Ta bort OpenGL-shadercache - + + Delete Vulkan Shader Cache + + + + Uninstall Avinstallera - + Everything Allting - + Application Applikation - + Update Uppdatering - + DLC DLC - + Remove Play Time Data Ta bort data för speltid - + Create Shortcut Skapa genväg - + Add to Desktop Lägg till på skrivbordet - + Add to Applications Menu Lägg till i programmenyn - + + Stress Test: App Launch + Stresstest: Appstart + + + Properties Egenskaper - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. @@ -5118,64 +5271,64 @@ This will delete the application if installed, as well as any installed updates Detta kommer att radera programmet om det är installerat, samt alla installerade uppdateringar eller DLC. - - + + %1 (Update) %1 (Uppdatering) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? Är du säker att du vill avinstallera "%1"? - + Are you sure you want to uninstall the update for '%1'? Är du säker på att du vill avinstallera uppdateringen för "%1"? - + Are you sure you want to uninstall all DLC for '%1'? Är du säker på att du vill avinstallera alla DLC för "%1"? - + Scan Subfolders Sök igenom undermappar - + Remove Application Directory Ta bort applikationskatalog - + Move Up Flytta upp - + Move Down Flytta ner - + Open Directory Location Öppna katalogplats - + Clear Töm - + Name Namn @@ -5183,82 +5336,82 @@ Detta kommer att radera programmet om det är installerat, samt alla installerad GameListItemCompat - + Perfect Perfekt - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. Appen fungerar felfritt utan ljud- eller grafiska problem, all testad funktionalitet fungerar som avsett utan några temporära lösningar behövs. - + Great Bra - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. Appen fungerar med mindre grafiska eller ljudmässiga problem och är spelbar från början till slut. Kan kräva vissa temporära lösningar. - + Okay Okej - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. Appen fungerar med större grafiska eller ljudmässiga problem, men appen är spelbar från början till slut med temporära lösningar. - + Bad Dåligt - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. Appen fungerar, men med stora grafiska eller ljudmässiga problem. Det går inte att göra framsteg inom vissa områden på grund av problem även med temporära lösningar. - + Intro/Menu Intro/Meny - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. Appen är helt ospelbar på grund av stora grafiska eller ljudmässiga fel. Det går inte att ta sig förbi startskärmen. - + Won't Boot Startar inte - + The app crashes when attempting to startup. Appen kraschar när den försöker starta upp. - + Not Tested Inte testat - + The app has not yet been tested. Appen har ännu inte testats. @@ -5266,7 +5419,7 @@ startskärmen. GameListPlaceholder - + Double-click to add a new folder to the application list Dubbelklicka för att lägga till en ny mapp i applikationslistan @@ -5274,27 +5427,27 @@ startskärmen. GameListSearchField - + of av - + result resultat - + results resultat - + Filter: Filtrera: - + Enter pattern to filter Ange mönster att filtrera @@ -5302,47 +5455,47 @@ startskärmen. GameRegion - + Japan Japan - + North America Nordamerika - + Europe Europa - + Australia Australien - + China Kina - + Korea Korea - + Taiwan Taiwan - + Invalid region Ogiltig region - + Region free Regionsfri @@ -5566,7 +5719,7 @@ startskärmen. Offset - Offset + Förskjutning @@ -5622,87 +5775,87 @@ startskärmen. Cykelindex: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Adressregister: %1, %2 - + Compare Result: %1, %2 Jämför resultat: %1, %2 - + Static Condition: %1 Statiskt villkor: %1 - + Dynamic Conditions: %1, %2 Dynamiska villkor: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Loop-parametrar: %1 (upprepningar), %2 (initiering), %3 (ökning), %4 - + Instruction offset: 0x%1 Instruktionsoffset: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (sista instruktionen) @@ -5927,24 +6080,24 @@ Felsökningsmeddelande: Förbereder shaders %1 / %2 - - Loading Shaders %1 / %2 - Läser in shaders %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Startar... - + Now Loading %1 Läser nu in %1 - + Estimated Time %1 Beräknad tid %1 @@ -6003,32 +6156,32 @@ Felsökningsmeddelande: Lösenord: - + Room Name Rumsnamn - + Preferred Application Föredragen applikation - + Host Värd - + Players Spelare - + Refreshing Uppdaterar - + Refresh List Uppdatera lista @@ -6098,7 +6251,7 @@ Felsökningsmeddelande: Multiplayer - Flerspelare + Flera spelare @@ -6111,342 +6264,352 @@ Felsökningsmeddelande: Film - + Help Hjälp - + Load File... Läs in fil... - + Install CIA... Installera CIA... - + Connect to Artic Base... Anslut till Artic Base... - + Set Up System Files... Konfigurera systemfiler... - + JPN JPN - + USA USA - + EUR EUR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit Avsluta - + Pause Paus - + Stop Stoppa - + Save Spara - + Load Läs in - + FAQ - FAQ + Frågor och svar - + About Azahar Om Azahar - + Single Window Mode Enstaka fönsterläge - + Save to Oldest Slot Spara till äldsta plats - + Quick Save Snabbsparning - + Load from Newest Slot Läs in från senaste plats - + Quick Load Snabbinläsning - + Configure... Konfigurera... - + Display Dock Widget Headers Visa dockwidgetrubriker - + Show Filter Bar Visa filterrad - + Show Status Bar Visa statusrad - + Create Pica Surface Viewer Skapa Pica Surface-visare - + Record... Spela in... - + Play... Spela upp... - + Close Stäng - + Save without Closing Spara utan att stänga - + Read-Only Mode Skrivskyddat läge - + Advance Frame Framåt en bildruta - + Capture Screenshot Fånga skärmbild - + Dump Video Dumpa video + Compress ROM File... + Komprimera ROM-fil... + + + + Decompress ROM File... + Avkomprimera ROM-fil... + + + Browse Public Rooms Bläddra bland publika rum - + Create Room Skapa rum - + Leave Room Lämna rum - + Direct Connect to Room Direktanslut till rum - + Show Current Room Visa aktuellt rum - + Fullscreen Helskärm - + Open Log Folder Öppna loggmapp - + Opens the Azahar Log folder Öppnar Azahar-loggmappen - + Default Standard - + Single Screen En skärm - + Large Screen Stor skärm - + Side by Side Sida vid sida - + Separate Windows Separata fönster - + Hybrid Screen Hybridskärm - + Custom Layout Anpassad layout - + Top Right Överst till höger - + Middle Right Mellan höger - + Bottom Right Nederst till höger - + Top Left Överst till vänster - + Middle Left Mellan vänster - + Bottom Left Nederst till vänster - + Above Ovan - + Below Nedan - + Swap Screens Växla skärmar - + Rotate Upright Rotera upprätt - + Report Compatibility Rapportera kompatibilitet - + Restart Starta om - + Load... Läs in... - + Remove Ta bort - + Open Azahar Folder Öppna Azahar-mappen - + Configure Current Application... Konfigurera aktuell applikation... @@ -7020,32 +7183,32 @@ De kan ha lämnat rummet. %1 (0x%2) - + Unsupported encrypted application Krypterad applikation som inte stöds - + Invalid region Ogiltig region - + Installed Titles Installerade titlar - + System Titles Systemtitlar - + Add New Application Directory Lägg till ny applikationskatalog - + Favorites Favoriter diff --git a/dist/languages/tr_TR.ts b/dist/languages/tr_TR.ts index 1b99f3cfa..5efdc8fd6 100644 --- a/dist/languages/tr_TR.ts +++ b/dist/languages/tr_TR.ts @@ -16,7 +16,7 @@ Value - Value + Değer @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,7 +298,7 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - Emulation: + Emulation Emülasyon @@ -328,8 +328,8 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Bu post-processing efekti ses hızını emülasyon hızına eşleşmesi için ayarlar ve ses takılmasını önlemeye yardımcı olur. Ancak bu ses gecikmesini arttırır. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -338,8 +338,8 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - Emülasyon kare hızındaki düşüşleri hesaba katmak için ses çalma hızını ölçeklendirir. Bu, uygulama kare hızı düşük olsa bile sesin tam hızda çalınacağı anlamına gelir. Ses senkronizasyon sorunlarına neden olabilir. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + @@ -403,6 +403,7 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. + Camera Kamera @@ -414,8 +415,8 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - Camera to configure: - Yapılandırılacak kamera: + Camera to Configure + Yapılandırılacak Kamera @@ -435,8 +436,8 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - Camera mode: - Kamera modu: + Camera mode + Kamera modu @@ -456,8 +457,8 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - Camera position: - Kamera konumu: + Camera position + Kamera konumu @@ -477,13 +478,13 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Emülasyon yapılmış kameranın görüntüsünün nereden geldiğini seçin. Bir resim veya gerçek bir kamera olabilir. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Kamera Görüntü Kaynağı: + Camera Image Source + @@ -502,8 +503,8 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - File: - Dosya: + File + Dosya @@ -516,11 +517,6 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. Select the system camera to use Kullanılacak sistem kamerasını seçin - - - Camera: - Kamera: - <Default> @@ -534,8 +530,8 @@ Bu onun hem forum kullanıcı adını hemde IP adresini yasaklar. - Flip: - Çevir: + Flip + Çevir @@ -727,7 +723,7 @@ Hataya aldırmayıp devam etmek ister misiniz? Show log output in console - + Konsolda günlük çıktısını göster @@ -1024,7 +1020,7 @@ Hataya aldırmayıp devam etmek ister misiniz? Enable Linear Filtering - Doğrusal Filtrelemeyi Etkinleştir + @@ -1088,8 +1084,8 @@ Hataya aldırmayıp devam etmek ister misiniz? - Reverse Side by Side - Ters Yan Yana + Side by Side Full Width + @@ -1139,7 +1135,7 @@ Hataya aldırmayıp devam etmek ister misiniz? Disable Right Eye Rendering - Sağ Göz İşlemesini Devre Dışı Bırak + @@ -1147,49 +1143,54 @@ Hataya aldırmayıp devam etmek ister misiniz? - + + Swap Eyes + + + + Utility - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures - Özel Dokuları Kullan + + Use custom textures + Özel dokular kullan - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures + + Dump textures - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures - Özel Dokuları Önceden Yükle + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading - Asenkron Özel Doku Yükleme + + Async custom texture loading + @@ -1201,91 +1202,111 @@ Hataya aldırmayıp devam etmek ister misiniz? - General - Genel + Updates + - Confirm exit while emulation is running - Emülasyon devam ederken çıkışı onaylayın - - - - Pause emulation when in background - Arkaplandayken emülasyonu durdur - - - - Mute audio when in background - Arka plandayken sesi kapat - - - - Hide mouse on inactivity - Hareketsizlik durumunda fareyi gizle - - - - Enable Gamemode - Oyun Modunu Etkinleştir - - - Check for updates Güncellemeleri denetle - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Genel + + + + Confirm exit while emulation is running + Emülasyon devam ederken çıkışı onaylayın + + + + Pause emulation when in background + Arkaplandayken emülasyonu durdur + + + + Mute audio when in background + Arka plandayken sesi kapat + + + + Hide mouse on inactivity + Hareketsizlik durumunda fareyi gizle + + + + Enable Gamemode + Oyun Modunu Etkinleştir + + + Emulation Emülasyon - + Use global emulation speed Evrensel emülasyon hızını kullan - - Set emulation speed: - Emülasyon hızını ayarla: + + Set emulation speed + Emülasyon hızını ayarla - - Emulation Speed: - Emülasyon Hızı: + + Emulation Speed + Emülasyon Hızı - + Turbo Speed Limit: Turbo Hız Limiti: - + Screenshots Ekran Görüntüleri - + Use global screenshot path - + Set screenshot path: Ekran Görüntüsü Yolu Ayarla: - + Save Screenshots To - + ... ... - + Reset All Settings Tüm Ayarları Sıfırla @@ -1293,8 +1314,8 @@ Hataya aldırmayıp devam etmek ister misiniz? - - + + unthrottled @@ -1304,12 +1325,12 @@ Hataya aldırmayıp devam etmek ister misiniz? Ekran Görüntüsü Dizini Seç - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? <b>Ayarlarınızı sıfırlamak</b> ve Azahar'ı kapatmak istediğinizden emin misiniz? @@ -1363,12 +1384,12 @@ Hataya aldırmayıp devam etmek ister misiniz? - SPIR-V Shader Generation - SPIR-V Gölgelendirici Oluşturma + SPIR-V shader generation + SPIR-V gölgelendirici oluşturma - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1388,8 +1409,8 @@ Hataya aldırmayıp devam etmek ister misiniz? - Enable Hardware Shader - Donanımsal Shader'ı Etkinleştir + Enable hardware shader + @@ -1398,8 +1419,8 @@ Hataya aldırmayıp devam etmek ister misiniz? - Accurate Multiplication - İsabetli Çoğaltma + Accurate multiplication + @@ -1408,8 +1429,8 @@ Hataya aldırmayıp devam etmek ister misiniz? - Enable Shader JIT - Shader JIT'i etkinleştir + Enable shader JIT + @@ -1418,18 +1439,18 @@ Hataya aldırmayıp devam etmek ister misiniz? - Enable Async Shader Compilation - Asenkron Gölgeleme Derlemesini Etkinleştir + Enable async shader compilation + - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>Sunumu ayrı iş parçacıkları üzerinde gerçekleştirin. Çoğu uygulamada Vulkan kullanırken performansı artırır.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + - Enable Async Presentation - Asenkron Sunumu Etkinleştir + Enable async presentation + Asenkron sunumu etkinleştir @@ -1468,13 +1489,13 @@ Hataya aldırmayıp devam etmek ister misiniz? - Use Disk Shader Cache + Use disk shader cache - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync ekran yırtılmasını engeller, fakat bazı görüntü kartları VSync etkinken daha az performans sergileyebilir. Eğer performans değişikliği hissetmiyorsanız açık bırakın. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1482,22 +1503,32 @@ Hataya aldırmayıp devam etmek ister misiniz? VSync Etkin - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1538,7 +1569,7 @@ Hataya aldırmayıp devam etmek ister misiniz? Toggle Turbo Mode - + Turbo Modu Aç/Kapat @@ -1982,13 +2013,13 @@ Hataya aldırmayıp devam etmek ister misiniz? - Swap Screens - Ekranları Değiştir + Swap screens + Ekranları değiştir - Rotate Screens Upright - Ekranları Yukarı Döndür + Rotate screens upright + @@ -2104,8 +2135,8 @@ Hataya aldırmayıp devam etmek ister misiniz? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - <html><head/><body><p>Alt Ekran Opaklığı % (Sadece OpenGL İçin</p></body></html>) + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + @@ -2116,7 +2147,7 @@ Hataya aldırmayıp devam etmek ister misiniz? Stretch - + Gerdir @@ -2276,7 +2307,7 @@ Hataya aldırmayıp devam etmek ister misiniz? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2365,7 +2396,7 @@ Hataya aldırmayıp devam etmek ister misiniz? Filepath - + Dosya yolu @@ -2452,8 +2483,8 @@ Hataya aldırmayıp devam etmek ister misiniz? - Use Virtual SD - Sanal SD'yi kullan + Use virtual SD card + @@ -2462,8 +2493,8 @@ Hataya aldırmayıp devam etmek ister misiniz? - Use Custom Storage - Özel Depolama Kullan + Use custom storage location + @@ -2493,6 +2524,16 @@ Hataya aldırmayıp devam etmek ister misiniz? SDMC Directory SDMC Dizini + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2539,8 +2580,8 @@ online features (if installed) - Region: - Bölge: + Region + Bölge @@ -2548,326 +2589,337 @@ online features (if installed) Otomatik seç - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Kullanıcı Adı - + Birthday Doğum Günü - + January Ocak - + February Şubat - + March Mart - + April Nisan - + May Mayıs - + June Haziran - + July Temmuz - + August Ağustos - + September Eylül - + October Ekim - + November Kasım - + December Aralık - + Language Dil - + Note: this can be overridden when region setting is auto-select Not: Bölge ayarı otomatik seç ise bu geçersiz kılınabilir. - + Japanese (日本語) Japonca (日本語) - + English İngilizce - + French (français) Fransızca (français) - + German (Deutsch) Almanca (Deutsch) - + Italian (italiano) İtalyanca (italiano) - + Spanish (español) İspanyolca (español) - + Simplified Chinese (简体中文) Basitleştirilmiş Çince (简体中文) - + Korean (한국어) Korece (한국어) - + Dutch (Nederlands) Felemenkçe (Nederlands) - + Portuguese (português) Portekizce (português) - + Russian (Русский) Rusça (Русский) - + Traditional Chinese (正體中文) Geleneksel Çince (正體中文) - + Sound output mode Ses Çıkış Modu - + Mono Mono - + Stereo Stereo - + Surround Surround - + Country Ülke - + Clock Saat - + System Clock Sistem Saati - + Fixed Time Sabit Zaman - + Startup time Başlangıç Zamanı - + yyyy-MM-ddTHH:mm:ss yyyy-AA-ggSS:dd:ss - + Offset time - + days günler - + HH:mm:ss - + Initial System Ticks - + Random Rastgele - + Fixed Sabit - + Initial System Ticks Override - + Play Coins Play Coin'leri - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>Adımsayar tarafından bildirilen saat başına adım sayısı. 0 ile 65,535 arasında değişir.</p></body></html> - + Pedometer Steps per Hour Saat Başına Adımsayar Adımları - + Run System Setup when Home Menu is launched Home menüsü açıldığında sistem kurulumunu başlat - + Console ID: Konsol ID: - - + + Regenerate Yeniden Oluştur - + MAC: MAC: - - 3GX Plugin Loader: - 3GX Rklenti Yükleyici: + + 3GX Plugin Loader + - + Enable 3GX plugin loader 3GX Eklenti Yükleyicisini Etkinleştir - + Allow applications to change plugin loader state Uygulamaların eklenti yükleyici durumunu değiştirmesine izin verin - + Real Console Unique Data - + Your real console is linked to Azahar. Gerçek konsolunuz Azahar'a bağlandı. - + Unlink Bağlantıyı Kes - + OTP OTP - - - - + + + + Choose Seç - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. Sistem ayarlarına sadece uygulama çalışmıyorken erişilebilir. @@ -3577,76 +3629,76 @@ online features (if installed) - - + + Console ID: 0x%1 Konsol ID: 0x%1 - - + + MAC: %1 MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? Bu, mevcut sanal 3DS konsol kimliğinizi yenisiyle değiştirecektir. Mevcut sanal 3DS konsol kimliğiniz kurtarılamayacaktır. Bu, uygulamalarında beklenmedik etkilere neden olabilir. Eski bir konfigürasyon kaydı kullanıyorsanız bu işlem başarısız olabilir. Devam etmek istiyor musunuz? - - - + + + Warning Uyarı - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? Bu, mevcut MAC adresinizi yenisiyle değiştirecektir. MAC adresini kurulum aracını kullanarak gerçek konsolunuzdan aldıysanız bunu yapmanız önerilmez. Yine de devam etmek ister misiniz? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region Yapılandırılmış bölge için geçersiz ülke - + Invalid country for console unique data - + Status: Loaded Durum: Yüklendi - + Status: Loaded (Invalid Signature) Durum: Yüklendi (Geçersiz İmza) - + Status: Loaded (Region Changed) Durum: Yüklendi (Bölge Değiştirildi) - + Status: Not Found Durum: Bulunamadı - + Status: Invalid Durum: Geçersiz - + Status: IO Error Durum: IO Hatası @@ -3761,13 +3813,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Arayüz dili: + Interface Language + - Theme: - Tema: + Theme + Tema @@ -3776,8 +3828,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - İkon Boyutu: + Icon Size + @@ -3797,8 +3849,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - Satır 1 Metni: + Row 1 Text + @@ -3832,27 +3884,27 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - Satır 2 Metni: + Row 2 Text + - Hide Titles without Icon - İkonu Olmayan Oyunları Gizle + Hide titles without icon + - Single Line Mode - Tek Satır Modu + Single line mode + Status Bar - + Durum Çubuğu - Show Advanced Frame Time Info + Show advanced frame time info @@ -3935,12 +3987,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Bağlanılıyor - + Connect Bağlan @@ -4059,469 +4111,509 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Geçerli emülasyon hızı. 100%'den az veya çok olan değerler emülasyonun bir 3DS'den daha yavaş veya daha hızlı çalıştığını gösterir. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Bir 3DS karesini emüle etmekte geçen zaman, karelimitleme ve v-sync hariç. Tam hız emülasyon için bu en çok 16,67 ms. olmalı. - + MicroProfile (unavailable) MikroProfil (kullanılamaz) - + Clear Recent Files Son Dosyaları Temizle - + &Continue &Devam et - + &Pause &Duraklat - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar bir uygulama çalıştırıyor - - + + Invalid App Format Geçersiz Uygulama Biçimi - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted Uygulama Şifreli - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App Desteklenmeyen Uygulama - + GBA Virtual Console is not supported by Azahar. GBA Sanal Konsolu Azahar tarafından desteklenmiyor. - - + + Artic Server Artic Sunucusu - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! Uygulama yüklenirken hata oluştu! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage CIA dosyası kullanılmadan önce yüklenmelidir - + Before using this CIA, you must install it. Do you want to install it now? Bu CIA dosyasını kullanmadan önce yüklemeniz gerekir. Şimdi yüklemek ister misiniz? - + Quick Load Hızlı Yükle - + Quick Save Hızlı Kaydet - - + + Slot %1 Slot %1 - + %2 %3 %2 %3 - + Quick Save - %1 Hızlı Kayıt - %1 - + Quick Load - %1 Hızlı Yükleme - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder %1 Klasörü Açılırken Hata Oluştu - - + + Folder does not exist! Klasör mevcut değil! - + Remove Play Time Data - + Reset play time? Oynama süresi sıfırlansın mı? - - - - + + + + Create Shortcut Kısayol Oluştur - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon Simge Oluştur - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... Dump ediliyor... - - + + Cancel İptal et - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. Temel RomFS dump edilemedi. Detaylar için kütük dosyasına bakınız. - + Error Opening %1 %1 Açılırken Hata Oluştu - + Select Directory Dizin Seç - + Properties Özellikler - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS Çalıştırılabiliri (%1);; Bütün Dosyalar (*.*) - + Load File Dosya Yükle - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + Kurulum tamamlandı. - + (ℹ️) New 3DS setup - + (ℹ️) Yeni 3DS kurulumu - + (✅) New 3DS setup - + (✅) Yeni 3DS kurulumu - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Dosyaları Yükle - - 3DS Installation File (*.CIA*) - 3DS Kurulum Dosyası (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Tüm Dosyalar (*.*) - + Connect to Artic Base Artic Base'e Bağla - + Enter Artic Base server address: - + %1 has been installed successfully. %1 başarıyla yüklendi. - + Unable to open File Dosya açılamıyor - + Could not open %1 %1 açılamıyor - + Installation aborted Yükleme iptal edildi - + The installation of %1 was aborted. Please see the log for more details %1'in yüklemesi iptal edildi. Daha fazla detay için lütfen kütüğe bakınız. - + Invalid File Geçersiz Dosya - + %1 is not a valid CIA %1 geçerli bir CIA dosyası değil - + CIA Encrypted CİA Şifreli - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File Dosya bulunamadı - + Could not find %1 %1 bulunamadı - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... '%1' siliniyor... - + Failed to uninstall '%1'. '%1' silinemedi. - + Successfully uninstalled '%1'. '%1' başarıyla silindi. - + File not found Dosya bulunamadı - + File "%1" not found "%1" Dosyası bulunamadı - + Savestates Kayıt Durumları - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! @@ -4530,86 +4622,86 @@ Use at your own risk! Kullanım riski size aittir! - - - + + + Error opening amiibo data file Amiibo veri dosyasını açarken bir hata oldu - + A tag is already in use. Bir etiket zaten kullanılıyor. - + Application is not looking for amiibos. Uygulama amiibo aramıyor. - + Amiibo File (%1);; All Files (*.*) Amiibo Dosyası (%1);; Tüm Dosyalar (*.*) - + Load Amiibo Amiibo Yükle - + Unable to open amiibo file "%1" for reading. - + Record Movie Klip Kaydet - + Movie recording cancelled. Klip kaydı iptal edildi. - - + + Movie Saved Klip Kaydedildi - - + + The movie is successfully saved. Klip başarıyla kayıt edildi. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory Geçersiz Ekran Görüntüsü Dizini - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4618,214 +4710,264 @@ To view a guide on how to install FFmpeg, press Help. - + + Load 3DS ROM Files + + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + Select FFmpeg Directory FFmpeg Dizini Seç - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - + FFmpeg has been sucessfully installed. FFmpeg başarıyla yüklendi. - + Installation of FFmpeg failed. Check the log file for details. FFmpeg yüklemesi başarısız oldu. Detaylar için log dosyasına bakınız. - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - + Recording %1 Ekran Kaydediliyor %1 - + Playing %1 / %2 Oynatılıyor %1 / %2 - + Movie Finished Film Bitti - + (Accessing SharedExtData) (SharedExtData'ya Erişiliyor) - + (Accessing SystemSaveData) (SystemSaveData'ya Erişiliyor) - + (Accessing BossExtData) (BossExtData'ya Erişiliyor) - + (Accessing ExtData) (ExtData'ya Erişiliyor) - + (Accessing SaveData) (SaveData'ya Erişiliyor) - + MB/s MB/sn - + KB/s KB/sn - + Artic Traffic: %1 %2%3 - + Speed: %1% Hız: %1% - + Speed: %1% / %2% Hız: %1% / %2% - + App: %1 FPS Uygulama: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Kare: %1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Bir sistem arşivi - + System Archive Not Found Sistem Arşivi Bulunamadı - + System Archive Missing Sistem Arşivi Eksik - + Save/load Error Kaydetme/yükleme Hatası - + Fatal Error Önemli Hata - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered Kritik hatayla karşılaşıldı - + Continue Devam - + Quit Application Uygulamadan Çık - + OK Tamam - + Would you like to exit now? Çıkmak istediğinize emin misiniz? - + The application is still running. Would you like to stop emulation? Uygulama hala çalışıyor. Emülasyonu durdurmak ister misiniz? - + Playback Completed Oynatma Tamamlandı - + Movie playback completed. Klip oynatması tamamlandı. - + Update Available Güncelleme Mevcut - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window Birincil Pencere - + Secondary Window İkincil Pencere @@ -4888,42 +5030,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! OpenGL başlatılırken bir hata oluştu! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. GPU'nuz OpenGL'i desteklemiyor veya grafik sürücünüz eski olabilir. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4931,239 +5073,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - Tekrar gösterme - - - - + + Compatibility Uyumluluk - - + + Region Bölge - - + + File type Dosya türü - - + + Size Boyut - - + + Play time Oyun süresi - + Favorite Favori - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open - + Application Location Uygulama Konumu - + Save Data Location Kayıt Verileri Konumu - + Extra Data Location Ekstra Veri Konumu - + Update Data Location - + DLC Data Location - + DLC Veri Konumu - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS RomFS Dump - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall Sil - + Everything Her şey - + Application Uygulama - + Update Güncelle - + DLC DLC - + Remove Play Time Data - + Create Shortcut Kısayol Oluştur - + Add to Desktop Masaüstüne Ekle - + Add to Applications Menu Uygulamalar Menüsüne Ekle - + + Stress Test: App Launch + + + + Properties Özellikler - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) %1 (Güncelleme) - - + + %1 (DLC) %1 (DLC) - + Are you sure you want to uninstall '%1'? '%1'i silmek istediğinizden emin misiniz? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders Alt Dizinleri Tara - + Remove Application Directory Uygulama Dizinini Kaldır - + Move Up Yukarı Taşı - + Move Down Aşağı Taşı - + Open Directory Location Dizinin Bulunduğu Yeri Aç - + Clear Temizle - + Name İsim @@ -5171,77 +5323,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Mükemmel - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Çok İyi - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Yeterli - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Kötü - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Giriş/Menü - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Açılmıyor - + The app crashes when attempting to startup. - + Not Tested Test Edilmedi - + The app has not yet been tested. Bu Uygulama henüz test edilmedi. @@ -5249,7 +5401,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list Uygulama listesine yeni bir klasör eklemek için çift tıklayın @@ -5257,27 +5409,27 @@ Screen. GameListSearchField - + of 'nun - + result sonuç - + results sonuçlar - + Filter: Filtre: - + Enter pattern to filter Filtrelenecek düzeni girin @@ -5285,47 +5437,47 @@ Screen. GameRegion - + Japan Japonya - + North America Kuzey Amerika - + Europe Avrupa - + Australia Avustralya - + China Çin - + Korea Kore - + Taiwan Tayvan - + Invalid region Geçersiz Bölge - + Region free Bölge kilitsiz @@ -5605,87 +5757,87 @@ Screen. Cycle Index: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Address Registers: %1, %2 - + Compare Result: %1, %2 Compare Result: %1, %2 - + Static Condition: %1 Static Condition: %1 - + Dynamic Conditions: %1, %2 Dynamic Conditions: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 - + Instruction offset: 0x%1 Instruction offset: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (last instruction) @@ -5909,23 +6061,23 @@ Debug Message: Shader'lar Hazırlanıyor %1 / %2 - - Loading Shaders %1 / %2 - Shader'lar Yükleniyor %1 / %2 + + Loading %3 %1 / %2 + - + Launching... Başlatılıyor... - + Now Loading %1 Şimdi Yükleniyor %1 - + Estimated Time %1 Tahmini Süre %1 @@ -5984,32 +6136,32 @@ Debug Message: Şifre: - + Room Name Oda İsmi - + Preferred Application Tercih Edilen Uygulama - + Host Sunucu - + Players Oyuncular - + Refreshing Yenileniyor - + Refresh List Listeyi Yenile @@ -6092,342 +6244,352 @@ Debug Message: Fil - + Help Yardım - + Load File... Dosya Yükle... - + Install CIA... CIA Yükle... - + Connect to Artic Base... Artic Base'e Bağlan... - + Set Up System Files... - + JPN JPN - + USA ABD - + EUR AVR - + AUS AUS - + CHN CHN - + KOR KOR - + TWN TWN - + Exit - + Pause Duraklat - + Stop Durdur - + Save Kaydet - + Load Yükle - + FAQ SSS - + About Azahar Azahar Hakkında - + Single Window Mode Tek Pencere Modu - + Save to Oldest Slot En Eski Yuvaya Kaydet - + Quick Save - Hızlı Kaydet + Hızlı Kaydet - + Load from Newest Slot En Yeni Yuvadan Yükle - + Quick Load - Hızlı Yükle + Hızlı Yükle - + Configure... Yapılandır... - + Display Dock Widget Headers Dock Widget'ı Başlıklarını Göster - + Show Filter Bar Filtre Çubuğunu Göster - + Show Status Bar Durum Çubuğunu Göster - + Create Pica Surface Viewer Create Pica Surface Viewer - + Record... - + Play... - + Oyna... - + Close Kapat - + Save without Closing - + Kapatmadan Kaydet - + Read-Only Mode - + Salt Okunur Mod - + Advance Frame Kare İlerlet - + Capture Screenshot Ekran Görüntüsünü Kaydet - + Dump Video Video Dump - Browse Public Rooms + Compress ROM File... + ROM Dosyası Sıkıştır... + + + + Decompress ROM File... - + + Browse Public Rooms + Herkese Açık Odalara Gözat + + + Create Room Oda Oluştur - + Leave Room Odadan Ayrıl - + Direct Connect to Room Odaya Doğrudan Bağlan - + Show Current Room Mevcut Odayı Göster - + Fullscreen Tam ekran - + Open Log Folder Log Dosyasını Aç - + Opens the Azahar Log folder - + Default Varsayılan - + Single Screen Tek Ekran - + Large Screen Büyük Ekran - + Side by Side Yan Yana - + Separate Windows Ayrı Pencereler - + Hybrid Screen Hibrit Ekran - + Custom Layout Özel Düzen - + Top Right Sağ Üst - + Middle Right Sağ Orta - + Bottom Right Sağ Alt - + Top Left Sol Üst - + Middle Left Sol Orta - + Bottom Left Sol Alt - + Above Yukarı - + Below Aşağı - + Swap Screens Ekranları değiştir - + Rotate Upright Yukarı doğru Döndür - + Report Compatibility Uyumluluk Bildir - + Restart Yeniden Başlat - + Load... Yükle... - + Remove Kaldır - + Open Azahar Folder Azahar Klasörünü Aç - + Configure Current Application... @@ -6578,7 +6740,7 @@ Debug Message: (>1 day) - + (>1 gün) @@ -6820,7 +6982,7 @@ Odayı terk etmiş olabilirler. unknown - + bilinmeyen @@ -6975,7 +7137,7 @@ Odayı terk etmiş olabilirler. auto - + otomatik @@ -6999,32 +7161,32 @@ Odayı terk etmiş olabilirler. - + Unsupported encrypted application Desteklenmeyen şifreli uygulama - + Invalid region Geçersiz Bölge - + Installed Titles Yüklü Başlıklar - + System Titles Sistem Başlıkları - + Add New Application Directory - + Favorites Favoriler diff --git a/dist/languages/vi_VN.ts b/dist/languages/vi_VN.ts index 5e0165b21..db6f779ef 100644 --- a/dist/languages/vi_VN.ts +++ b/dist/languages/vi_VN.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -121,7 +121,7 @@ p, li { white-space: pre-wrap; } Cancel - Bỏ qua + Hủy bỏ @@ -179,12 +179,12 @@ p, li { white-space: pre-wrap; } %1 has been kicked - %1 đã bị kick. + %1 đã bị đuổi %1 has been banned - %1 đã bị cấm. + %1 đã bị cấm @@ -210,7 +210,7 @@ p, li { white-space: pre-wrap; } Kick - Kick + Đuổi @@ -220,12 +220,12 @@ p, li { white-space: pre-wrap; } Kick Player - Kick người chơi + Đuổi người chơi Are you sure you would like to <b>kick</b> %1? - Bạn có chắc muốn <b>kick</b> %1? + Bạn có chắc muốn <b>đuổi</b> %1? @@ -237,7 +237,7 @@ p, li { white-space: pre-wrap; } Are you sure you would like to <b>kick and ban</b> %1? This would ban both their forum username and their IP address. - Bạn có chắc muốn <b>kick và chặn</b> %1? + Bạn có chắc muốn <b>đuổi và cấm</b> %1? Điều này sẽ chặn cả tài khoản diễn đàn và địa chỉ IP của họ. @@ -292,8 +292,8 @@ This would ban both their forum username and their IP address. - Emulation: - Giả lập: + Emulation + Giả lập @@ -322,8 +322,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Hiệu ứng hậu xử lý giúp tăng tốc âm giúp phù hợp với tốc độ giả lập và cải thiện âm thanh, giúp hạn chế âm rè. Song điều này có thể tăng độ trễ âm. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ This would ban both their forum username and their IP address. + Camera Máy ảnh @@ -408,8 +409,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - Cấu hình máy ảnh: + Camera to Configure + @@ -429,8 +430,8 @@ This would ban both their forum username and their IP address. - Camera mode: - Chế độ máy ảnh: + Camera mode + @@ -450,8 +451,8 @@ This would ban both their forum username and their IP address. - Camera position: - Vị trí máy ảnh: + Camera position + @@ -471,13 +472,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - Chọn nguồn ảnh mà giả lập sẽ nhận từ máy ảnh. Nó có thể là tệp tin hoặc một đầu ra Camera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - Nguồn máy ảnh: + Camera Image Source + @@ -496,8 +497,8 @@ This would ban both their forum username and their IP address. - File: - Tệp tin: + File + @@ -510,11 +511,6 @@ This would ban both their forum username and their IP address. Select the system camera to use Chọn đầu ra camera để sử dụng - - - Camera: - Máy ảnh - <Default> @@ -528,8 +524,8 @@ This would ban both their forum username and their IP address. - Flip: - Lật ảnh: + Flip + @@ -1081,7 +1077,7 @@ Would you like to ignore the error and continue? - Reverse Side by Side + Side by Side Full Width @@ -1140,48 +1136,53 @@ Would you like to ignore the error and continue? - + + Swap Eyes + + + + Utility - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - - Use Custom Textures + + Use custom textures - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - - Dump Textures - Trích xuất textures + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures + + Preload custom textures - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading @@ -1194,91 +1195,111 @@ Would you like to ignore the error and continue? - General - Chung + Updates + - Confirm exit while emulation is running - Xác nhận thoát khi đang chạy giả lập - - - - Pause emulation when in background - Tạm ngưng giả lập khi chạy dưới nền - - - - Mute audio when in background - - - - - Hide mouse on inactivity - - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + Chung + + + + Confirm exit while emulation is running + Xác nhận thoát khi đang chạy giả lập + + + + Pause emulation when in background + Tạm ngưng giả lập khi chạy dưới nền + + + + Mute audio when in background + + + + + Hide mouse on inactivity + + + + + Enable Gamemode + + + + Emulation Giả lập - + Use global emulation speed - - Set emulation speed: + + Set emulation speed - - Emulation Speed: + + Emulation Speed - + Turbo Speed Limit: - + Screenshots - + Use global screenshot path - + Set screenshot path: - + Save Screenshots To - + ... ... - + Reset All Settings Đặt lại tất cả cài đặt @@ -1286,8 +1307,8 @@ Would you like to ignore the error and continue? - - + + unthrottled @@ -1297,12 +1318,12 @@ Would you like to ignore the error and continue? - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1356,12 +1377,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1381,8 +1402,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - Bật Hardware Shader + Enable hardware shader + @@ -1391,8 +1412,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - Accurate Multiplication + Accurate multiplication + @@ -1401,8 +1422,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - Bật xử lý đổ bóng bằng JIT + Enable shader JIT + @@ -1411,17 +1432,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1461,13 +1482,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache + Use disk shader cache - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - VSync giúp giảm thiểu hiện tượng tải chia cắt hình ảnh hiển thị trên màn hình, một số các phần cứng độ họa sẽ chạy hiệu suất thấp khi bật VSync. Bật VSync nếu bạn không thấy ảnh hưởng gì. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1475,22 +1496,32 @@ Would you like to ignore the error and continue? Bật VSync - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1975,12 +2006,12 @@ Would you like to ignore the error and continue? - Swap Screens - Đổi vị trí màn hình + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2097,7 +2128,7 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2269,7 +2300,7 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2445,7 +2476,7 @@ Would you like to ignore the error and continue? - Use Virtual SD + Use virtual SD card @@ -2455,7 +2486,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location @@ -2486,6 +2517,16 @@ Would you like to ignore the error and continue? SDMC Directory + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2532,8 +2573,8 @@ online features (if installed) - Region: - + Region + Khu vực @@ -2541,326 +2582,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username Tên người dùng - + Birthday Sinh nhật - + January Tháng 1 - + February Tháng 2 - + March Tháng 3 - + April Tháng 4 - + May Tháng 5 - + June Tháng 6 - + July Tháng 7 - + August Tháng 8 - + September Tháng 9 - + October Tháng 10 - + November Tháng 11 - + December Tháng 12 - + Language Ngôn ngữ - + Note: this can be overridden when region setting is auto-select Lưu ý: tùy chọn này có thể bị thay thế khi thiết lập vùng đặt ở chế độ tự động - + Japanese (日本語) Tiếng Nhật (日本語) - + English Tiếng Anh (English) - + French (français) Tiếng Pháp (Français) - + German (Deutsch) Tiếng Đức (Deutsch) - + Italian (italiano) Tiếng Ý (Italiano) - + Spanish (español) Tiếng Tây Ban Nha (Español) - + Simplified Chinese (简体中文) Tiếng Hoa (Giản Thể) - + Korean (한국어) Tiếng Hàn (한국어) - + Dutch (Nederlands) Tiếng Hà Lan (Dutch) - + Portuguese (português) Tiếng Bồ Đào Nha (Português) - + Russian (Русский) Tiếng Nga (Pу́сский язы́к) - + Traditional Chinese (正體中文) Tiếng Hoa (Phồn Thể) - + Sound output mode Chế độ đầu ra âm thanh - + Mono Đơn âm - + Stereo Đa âm - + Surround Âm thanh vòm - + Country Quốc gia - + Clock Đồng hồ - + System Clock Đồng hồ hệ thống - + Fixed Time Giờ cố định - + Startup time Giờ bắt đầu - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: ID Máy: - - + + Regenerate Tạo mới - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3570,76 +3622,76 @@ online features (if installed) - - + + Console ID: 0x%1 Tên Máy: 0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning Cảnh báo - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3754,13 +3806,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - Ngôn ngữ giao diện: + Interface Language + - Theme: - Giao diện: + Theme + @@ -3769,8 +3821,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - Kích cỡ Icon: + Icon Size + @@ -3790,8 +3842,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - Nội dung dòng 1: + Row 1 Text + @@ -3825,18 +3877,18 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - Nội dung dòng 2: + Row 2 Text + - Hide Titles without Icon - Ẩn tiêu đề giữ Icon + Hide titles without icon + - Single Line Mode - Chế độ đơn dòng + Single line mode + @@ -3845,7 +3897,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3928,12 +3980,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting Đang kết nối - + Connect Kết nối @@ -4052,556 +4104,596 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Tốc độ giả lập hiện tại. Giá trị cao hoặc thấp hơn 100% thể hiện giả lập đang chạy nhanh hay chậm hơn một chiếc máy 3DS thực sự. - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Thời gian để giả lập một khung hình của máy 3DS, không gồm giới hạn khung hay v-sync Một giả lập tốt nhất sẽ tiệm cận 16.67 ms. - + MicroProfile (unavailable) - + Clear Recent Files Xóa danh sách tệp gần đây - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage CIA cần được cài đặt trước khi dùng - + Before using this CIA, you must install it. Do you want to install it now? Trước khi sử dụng CIA, bạn cần cài đặt nó. Bạn có muốn cài đặt nó ngay không? - + Quick Load - + Quick Save - - + + Slot %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder Lỗi khi mở thư mục %1 - - + + Folder does not exist! Thư mục này không tồn tại! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... Đang trích xuất... - - + + Cancel - Bỏ qua + Hủy bỏ - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. Không thể trích xuất base RomFS. Kiểm tra log để biết thêm chi tiết. - + Error Opening %1 Lỗi khi mở %1 - + Select Directory Chọn thư mục - + Properties - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. - + Load File Mở tệp tin - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files Mở các tệp tin - - 3DS Installation File (*.CIA*) - Tệp cài đặt 3DS (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) Tất cả tệp tin (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. %1 đã được cài đặt thành công. - + Unable to open File Không thể mở tệp tin - + Could not open %1 Không thể mở %1 - + Installation aborted Việc cài đặt đã bị hoãn - + The installation of %1 was aborted. Please see the log for more details Việc cài đặt %1 đã bị hoãn. Vui lòng xem bản ghi nhật ký để biết thêm chi tiết. - + Invalid File Tệp tin không hợp lệ - + %1 is not a valid CIA %1 không phải là một tệp CIA hợp lệ - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. - + File not found Không tìm thấy tệp - + File "%1" not found Không tìm thấy tệp tin "%1" - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Tệp Amiibo (%1);; Tất cả tệp (*.*) - + Load Amiibo Tải Amiibo - + Unable to open amiibo file "%1" for reading. - + Record Movie Quay phim - + Movie recording cancelled. Ghi hình đã bị hủy. - - + + Movie Saved Đã lưu phim. - - + + The movie is successfully saved. Phim đã được lưu lại thành công. - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4610,214 +4702,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% Tốc độ: %1% - + Speed: %1% / %2% Tốc độ: %1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms Khung: %1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive Một tập tin hệ thống - + System Archive Not Found Không tìm thấy tập tin hệ thống - + System Archive Missing Thiếu tập tin hệ thống - + Save/load Error - + Fatal Error Lỗi nghiêm trọng - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered - + Continue Tiếp tục - + Quit Application - + OK OK - + Would you like to exit now? Bạn có muốn thoát ngay bây giờ không? - + The application is still running. Would you like to stop emulation? - + Playback Completed Phát lại hoàn tất - + Movie playback completed. Phát lại phim hoàn tất. - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4880,42 +5022,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4923,239 +5065,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility Tính tương thích - - + + Region Khu vực - - + + File type Loại tệp tin - - + + Size Kích thước - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS Trích xuất RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders Quét thư mục con - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location Mở thư mục - + Clear - + Name Tên @@ -5163,77 +5315,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect Hoàn mỹ - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great Tuyệt vời - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay Ổn - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad Kém - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu Intro/Menu - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot Không mở được - + The app crashes when attempting to startup. - + Not Tested Chưa thử - + The app has not yet been tested. @@ -5241,7 +5393,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5249,27 +5401,27 @@ Screen. GameListSearchField - + of của - + result kết quả - + results kết quả - + Filter: Bộ lọc: - + Enter pattern to filter Nhập mẫu ký tự để lọc @@ -5277,47 +5429,47 @@ Screen. GameRegion - + Japan Nhật Bản - + North America - + Europe - + Australia Úc - + China Trung Quốc - + Korea - + Taiwan Đài Loan - + Invalid region Vùng không hợp lệ - + Region free @@ -5597,87 +5749,87 @@ Screen. Cycle Index: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 Địa chỉ đăng ký: %1, %2 - + Compare Result: %1, %2 So sánh kết quả: %1, %2 - + Static Condition: %1 Điều kiện cứng: %1 - + Dynamic Conditions: %1, %2 Điều kiện biến: %1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 Các tham số lặp: %1 (số lần lặp), %2 (biến khởi tạo), %3 (độ tăng), %4 - + Instruction offset: 0x%1 Instruction offset: 0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (chỉ thị cuối cùng) @@ -5901,23 +6053,23 @@ Debug Message: - - Loading Shaders %1 / %2 + + Loading %3 %1 / %2 - + Launching... - + Now Loading %1 - + Estimated Time %1 @@ -5976,32 +6128,32 @@ Debug Message: Mật khẩu phòng: - + Room Name Tên phòng - + Preferred Application - + Host Host - + Players Số người - + Refreshing Đang tải - + Refresh List Làm mới @@ -6084,342 +6236,352 @@ Debug Message: Phim - + Help - + Load File... Mở tệp tin... - + Install CIA... Cài đặt CIA... - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit - + Pause - + Stop - + Save Lưu - + Load - + FAQ - + About Azahar - + Single Window Mode Chế độ đơn cửa sổ - + Save to Oldest Slot - + Quick Save - + Load from Newest Slot - + Quick Load - + Configure... Cấu hình... - + Display Dock Widget Headers Hiển thị thanh Dock - + Show Filter Bar Hiển thị thanh tìm kiếm - + Show Status Bar Hiển thị trạng thái - + Create Pica Surface Viewer Tạo trình xem mặt bằng Pica - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame - + Capture Screenshot Chụp màn hình - + Dump Video Trích xuất video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room Tạo phòng - + Leave Room Rời phòng - + Direct Connect to Room Kết nối trực tiếp đến phòng - + Show Current Room Xem phòng hiện tại - + Fullscreen Toàn màn hình - + Open Log Folder - + Opens the Azahar Log folder - + Default Mặc định - + Single Screen Đơn màn hình - + Large Screen Màn hình lớn - + Side by Side Nằm kề nhau - + Separate Windows - + Hybrid Screen - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens Đổi vị trí màn hình - + Rotate Upright - + Report Compatibility Gửi báo cáo tính tương thích - + Restart Khởi động lại - + Load... Tải... - + Remove Xóa - + Open Azahar Folder - + Configure Current Application... @@ -6492,7 +6654,7 @@ Debug Message: File: - Tệp tin: + @@ -6584,7 +6746,7 @@ Debug Message: File: - Tệp tin: + @@ -6990,32 +7152,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region Vùng không hợp lệ - + Installed Titles Các tiêu đề đã cài - + System Titles Các tiêu đề hệ thống - + Add New Application Directory - + Favorites diff --git a/dist/languages/zh_CN.ts b/dist/languages/zh_CN.ts index c5050e0b7..df5b6749c 100644 --- a/dist/languages/zh_CN.ts +++ b/dist/languages/zh_CN.ts @@ -28,8 +28,8 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -298,8 +298,8 @@ This would ban both their forum username and their IP address. - Emulation: - 模拟: + Emulation + 模拟 @@ -328,8 +328,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - 这种后处理效果可以调整音频速度以匹配模拟速度,并有助于防止音频断断续续。 但是会增加音频延迟。 + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -338,8 +338,8 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. - 调整音频播放速度以适应模拟帧率的下降。这意味着即使应用帧率较低,音频也会全速播放。可能会导致音频不同步问题。 + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> + @@ -403,6 +403,7 @@ This would ban both their forum username and their IP address. + Camera 摄像头 @@ -414,8 +415,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - 要配置的摄像头: + Camera to Configure + 要配置的摄像头 @@ -435,8 +436,8 @@ This would ban both their forum username and their IP address. - Camera mode: - 摄像头模式: + Camera mode + 摄像头模式 @@ -456,8 +457,8 @@ This would ban both their forum username and their IP address. - Camera position: - 摄像头位置: + Camera position + 摄像头位置 @@ -477,13 +478,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - 选择虚拟摄像头图像的来源。这可以是一张图片或一个真实的摄像头。 + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - 摄像头图像来源: + Camera Image Source + 摄像头图像来源 @@ -502,8 +503,8 @@ This would ban both their forum username and their IP address. - File: - 图像文件: + File + 文件 @@ -516,11 +517,6 @@ This would ban both their forum username and their IP address. Select the system camera to use 选择要使用的系统摄像头 - - - Camera: - 摄像头: - <Default> @@ -534,8 +530,8 @@ This would ban both their forum username and their IP address. - Flip: - 翻转: + Flip + 翻转 @@ -1024,7 +1020,7 @@ Would you like to ignore the error and continue? Enable Linear Filtering - 启用线性过滤 + @@ -1088,8 +1084,8 @@ Would you like to ignore the error and continue? - Reverse Side by Side - 反向并排 + Side by Side Full Width + @@ -1139,7 +1135,7 @@ Would you like to ignore the error and continue? Disable Right Eye Rendering - 禁用右眼渲染 + @@ -1147,48 +1143,53 @@ Would you like to ignore the error and continue? <html><head/><body><p>禁用右眼渲染</p><p>不使用立体模式时禁用右眼图像渲染。在某些应用中可大大提高性能,但在其他应用中可能会导致闪烁。</p></body></html> - + + Swap Eyes + + + + Utility 工具 - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>使用 PNG 文件进行纹理的替换。</p><p>将加载 load/textures/[Title ID]/ 目录的纹理文件。</p></body></html> - - Use Custom Textures + + Use custom textures 使用自定义纹理 - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>将纹理转储为 PNG 文件。</p><p>转储的文件保存于 dump/textures/[Title ID]/ 目录下。</p></body></html> - - Dump Textures - 转储纹理文件 + + Dump textures + 转储纹理 - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> <html><head/><body><p>启动时将所有的自定义纹理加载到内存中,而不是在应用需要时才进行加载。</p></body></html> - - Preload Custom Textures + + Preload custom textures 预加载自定义纹理 - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>在后台线程中异步加载自定义纹理,以减少加载带来的卡顿</p></body></html> - - Async Custom Texture Loading + + Async custom texture loading 异步加载自定义纹理 @@ -1201,91 +1202,111 @@ Would you like to ignore the error and continue? - General - 通用 + Updates + - Confirm exit while emulation is running - 在游戏运行时退出需要确认 - - - - Pause emulation when in background - 模拟器位于后台时暂停模拟 - - - - Mute audio when in background - 模拟器位于后台时静音 - - - - Hide mouse on inactivity - 自动隐藏鼠标光标 - - - - Enable Gamemode - 启用游戏模式 - - - Check for updates 检查更新 - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + 通用 + + + + Confirm exit while emulation is running + 在游戏运行时退出需要确认 + + + + Pause emulation when in background + 模拟器位于后台时暂停模拟 + + + + Mute audio when in background + 模拟器位于后台时静音 + + + + Hide mouse on inactivity + 自动隐藏鼠标光标 + + + + Enable Gamemode + 启用游戏模式 + + + Emulation 模拟 - + Use global emulation speed 使用全局模拟速度 - - Set emulation speed: - 模拟速度: + + Set emulation speed + 设置模拟速度 - - Emulation Speed: - 模拟速度: + + Emulation Speed + 模拟速度 - + Turbo Speed Limit: 加速限制: - + Screenshots 截图 - + Use global screenshot path 使用全局截图保存位置 - + Set screenshot path: 截图保存位置: - + Save Screenshots To 将截图保存至 - + ... - + Reset All Settings 重置所有设置 @@ -1293,8 +1314,8 @@ Would you like to ignore the error and continue? - - + + unthrottled 无限制 @@ -1304,12 +1325,12 @@ Would you like to ignore the error and continue? 选择截图保存目录 - + Azahar Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? 您确定要<b>重置设置</b>并关闭 Azahar 吗? @@ -1363,12 +1384,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation - SPIR-V 着色器 + SPIR-V shader generation + SPIR-V 着色器生成 - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer 禁用 GLSL -> SPIR-V 优化器 @@ -1388,8 +1409,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - 开启硬件着色器 + Enable hardware shader + 启用硬件着色器 @@ -1398,7 +1419,7 @@ Would you like to ignore the error and continue? - Accurate Multiplication + Accurate multiplication 精确乘法运算 @@ -1408,8 +1429,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - 开启着色器 JIT + Enable shader JIT + 启用着色器 JIT @@ -1418,18 +1439,18 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation 启用异步着色器编译 - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> - <html><head/><body><p>在单独的线程上执行着色器提交。提升大多数应用使用 Vulkan 时的性能。</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> + - Enable Async Presentation - 启用异步着色器提交 + Enable async presentation + 启用异步提交 @@ -1468,13 +1489,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache + Use disk shader cache 启用磁盘着色器缓存 - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - 垂直同步可防止画面产生撕裂感。但启用垂直同步后,某些设备性能可能会有所降低。如果您没有感到性能差异,请保持启用状态。 + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1482,22 +1503,32 @@ Would you like to ignore the error and continue? 启用垂直同步 - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global 使用全局 - + Use per-application 用于每个应用程序 - - Delay application render thread: - 延迟应用渲染线程: + + Delay Application Render Thread + 延迟应用渲染线程 - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> <html><head/><body><p>每次向 GPU 提交渲染命令时,将模拟的应用渲染线程延迟指定的毫秒数。</p><p>在(极少数)动态帧率应用中调整此功能以解决性能问题。</p></body></html> @@ -1982,13 +2013,13 @@ Would you like to ignore the error and continue? - Swap Screens + Swap screens 交换屏幕 - Rotate Screens Upright - 顺时针旋转屏幕 + Rotate screens upright + 旋转屏幕为垂直 @@ -2104,8 +2135,8 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> - 下屏幕透明度 %(仅 OpenGL) + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> + <html><head/><body><p>下屏不透明度 %</p></body></html> @@ -2276,8 +2307,8 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">了解更多</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">了解更多</span></a> @@ -2452,8 +2483,8 @@ Would you like to ignore the error and continue? - Use Virtual SD - 启用虚拟 SD 卡 + Use virtual SD card + 使用虚拟 SD 卡 @@ -2462,8 +2493,8 @@ Would you like to ignore the error and continue? - Use Custom Storage - 使用自定义存储目录 + Use custom storage location + 使用自定义存储位置 @@ -2493,6 +2524,16 @@ Would you like to ignore the error and continue? SDMC Directory SD 卡目录 + + + Compress installed CIA content + 压缩已安装的 CIA 内容 + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2540,8 +2581,8 @@ LLE 模块(如果已安装) - Region: - 地区: + Region + 区域 @@ -2549,326 +2590,337 @@ LLE 模块(如果已安装) 自动选择 - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username 用户名 - + Birthday 生日 - + January 一月 - + February 二月 - + March 三月 - + April 四月 - + May 五月 - + June 六月 - + July 七月 - + August 八月 - + September 九月 - + October 十月 - + November 十一月 - + December 十二月 - + Language 语言 - + Note: this can be overridden when region setting is auto-select 注意:当“地区”设置是“自动选择”时,此设置可能会被覆盖。 - + Japanese (日本語) 日语(日本語) - + English 英语(English) - + French (français) 法语(Français) - + German (Deutsch) 德语(Deutsch) - + Italian (italiano) 意大利语(Italiano) - + Spanish (español) 西班牙语(Español) - + Simplified Chinese (简体中文) 简体中文 - + Korean (한국어) 朝鲜语(한국어) - + Dutch (Nederlands) 荷兰语(Nederlands) - + Portuguese (português) 葡萄牙语(Português) - + Russian (Русский) 俄语(Русский) - + Traditional Chinese (正體中文) 繁体中文(正體中文) - + Sound output mode 声音输出模式 - + Mono 单声道 - + Stereo 立体声 - + Surround 环绕声 - + Country 国家或地区 - + Clock 时钟 - + System Clock 系统时钟 - + Fixed Time 固定时间 - + Startup time 启动时间 - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time 偏移时间 - + days - + HH:mm:ss HH:mm:ss - + Initial System Ticks 初始系统定时器 - + Random 随机 - + Fixed 固定值 - + Initial System Ticks Override 覆盖初始系统定时器 - + Play Coins 游戏币 - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> <html><head/><body><p>计步器报告的每小时步数。范围从 0 到 65535。</p></body></html> - + Pedometer Steps per Hour 计步器每小时步数 - + Run System Setup when Home Menu is launched 启动 Home 菜单时运行系统设置 - + Console ID: 设备 ID: - - + + Regenerate 重置 ID - + MAC: MAC: - - 3GX Plugin Loader: - 3GX 插件加载器: + + 3GX Plugin Loader + 3GX 插件加载器 - + Enable 3GX plugin loader 启用 3GX 插件加载器 - + Allow applications to change plugin loader state 允许应用更改插件加载器状态 - + Real Console Unique Data 实机唯一数据 - + Your real console is linked to Azahar. 您的真实掌机已关联到 Azahar。 - + Unlink 解除关联 - + OTP OTP - - - - + + + + Choose 选择 - + SecureInfo_A/B SecureInfo_A/B - + LocalFriendCodeSeed_A/B LocalFriendCodeSeed_A/B - + movable.sed movable.sed - + System settings are available only when applications is not running. 只有当应用不在运行时,系统设置才可用。 @@ -3578,76 +3630,76 @@ LLE 模块(如果已安装) Sed 文件 (*.sed);;所有文件 (*.*) - - + + Console ID: 0x%1 设备 ID:0x%1 - - + + MAC: %1 MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? 这将使用一个新的虚拟 3DS 掌机 ID 取代您当前的虚拟 3DS 掌机 ID。您当前的虚拟 3DS 掌机 ID 将无法恢复。可能会对应用产生意外影响。如果您使用一个过时的配置存档则可能会失败。是否继续? - - - + + + Warning 警告 - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? 这将用新 MAC 地址替换您当前的 MAC 地址。如果您使用设置工具从真实掌机获取 MAC 地址,则不建议执行此操作。是否继续? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? 此操作将取消您真实掌机与 Azahar 的关联,并产生以下后果:<br><ul><li>您的 OTP、SecureInfo 和 LocalFriendCodeSeed 文件将从 Azahar 中删除。</li><li>您的好友列表将被重置,并且注销 NNID/PNID 帐户。</li><li>通过 Azahar 获得的系统文件和 eshop 数字版应用将变得无法访问,直到再次关联同一掌机(保存的数据不会丢失)。</li></ul><br>是否继续? - + Invalid country for configured region 已配置区域的国家/地区无效 - + Invalid country for console unique data 掌机独有数据的国家/地区无效 - + Status: Loaded 状态:已载入 - + Status: Loaded (Invalid Signature) 状态:已载入(无效签名) - + Status: Loaded (Region Changed) 状态:已载入(区域已更改) - + Status: Not Found 状态:未找到 - + Status: Invalid 状态:无效 - + Status: IO Error 状态:IO 错误 @@ -3763,13 +3815,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - 界面语言: + Interface Language + 界面语言 - Theme: - 主题: + Theme + 主题 @@ -3778,8 +3830,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - 图标大小: + Icon Size + 图标大小 @@ -3799,8 +3851,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - 第 1 行: + Row 1 Text + 第 1 行 @@ -3834,17 +3886,17 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - 第 2 行: + Row 2 Text + 第 2 行 - Hide Titles without Icon + Hide titles without icon 隐藏没有图标的游戏 - Single Line Mode + Single line mode 单行模式 @@ -3854,7 +3906,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info 显示高级帧生成时间信息 @@ -3937,12 +3989,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting 连接中 - + Connect 连接 @@ -4062,471 +4114,511 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected 未检测到可用的 Vulkan 设备 - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. Vulkan 初始化失败。<br/>您的 GPU 可能不支持 Vulkan 1.1,或者您没有安装最新的图形驱动程序。 - + Current Artic traffic speed. Higher values indicate bigger transfer loads. 当前 Artic 连接速度。数值越高,表示传递载荷越大。 - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. 当前模拟速度。高于或低于 100% 的值表示模拟正在运行得比实际 3DS 更快或更慢。 - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. 应用当前显示的每秒帧数。这会因应用和场景而异。 - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 在不计算速度限制和垂直同步的情况下,模拟一个 3DS 帧的实际时间。若要进行全速模拟,这个数值不应超过 16.67 毫秒。 - + MicroProfile (unavailable) 微档案文件(不可用) - + Clear Recent Files 清除最近文件 - + &Continue 继续(&C) - + &Pause 暂停(&P) - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping Azahar 正在运行应用 - - + + Invalid App Format 无效的应用格式 - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. 您的应用格式不受支持。<br/>请遵循以下指引重新转储您的<a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>游戏卡带</a>或<a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>已安装的应用</a>。 - + App Corrupted 应用已损坏 - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. 您的应用已损坏。<br/>请遵循以下指引重新转储您的<a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>游戏卡带</a>或<a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>已安装的应用</a>。 - + App Encrypted 应用已加密 - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> 您的应用已加密。 <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>请查看我们的博客以了解更多信息。</a> - + Unsupported App 不支持的应用 - + GBA Virtual Console is not supported by Azahar. GBA 虚拟主机不受 Azahar 支持。 - - + + Artic Server Artic 服务器 - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! 加载应用时出错! - + An unknown error occurred. Please see the log for more details. 发生了一个未知错误。详情请参阅日志。 - + CIA must be installed before usage CIA 文件必须安装后才能使用 - + Before using this CIA, you must install it. Do you want to install it now? 在使用这个 CIA 文件前,您必须先进行安装。您希望现在就安装它吗? - + Quick Load 快速载入 - + Quick Save 快速保存 - - + + Slot %1 插槽 %1 - + %2 %3 %2 %3 - + Quick Save - %1 快速保存 - %1 - + Quick Load - %1 快速载入 - %1 - + Slot %1 - %2 %3 插槽 %1 - %2 %3 - + Error Opening %1 Folder 无法打开 %1 文件夹 - - + + Folder does not exist! 文件夹不存在! - + Remove Play Time Data 删除游戏时间数据 - + Reset play time? 重置游戏时间? - - - - + + + + Create Shortcut 创建快捷方式 - + Do you want to launch the application in fullscreen? 您想以全屏幕运行应用吗? - + Successfully created a shortcut to %1 已经在 %1 上创建了快捷方式。 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? 这将会为当前的 AppImage 创建一个快捷方式。如果您更新,此快捷方式可能会无效。继续吗? - + Failed to create a shortcut to %1 在 %1 上创建快捷方式失败。 - + Create Icon 创建图标 - + Cannot create icon file. Path "%1" does not exist and cannot be created. 无法创建图标文件。路径“%1”不存在,且无法创建。 - + Dumping... 转储中... - - + + Cancel 取消 - - - - - - - - - + + + + + + + + + Azahar Azahar - + Could not dump base RomFS. Refer to the log for details. 无法转储 RomFS 。 有关详细信息,请参考日志文件。 - + Error Opening %1 无法打开 %1 - + Select Directory 选择目录 - + Properties 属性 - + The application properties could not be loaded. 无法加载应用属性。 - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS 可执行文件 (%1);;所有文件 (*.*) - + Load File 加载文件 - - + + Set Up System Files 设置系统文件 - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> <p>Azahar 需要来自真实掌机的独有数据和固件文件才能使用其部分功能。<br>此类文件和数据可通过 <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic 设置工具</a>进行设置<br>注意:<ul><li><b>此操作会将掌机独有数据安装到 Azahar,<br>执行设置过程后请勿共享您的用户或 nand 文件夹!</b></li><li>在执行设置过程时,Azahar 将关联到运行设置工具的掌机。<br>您可以随时从模拟器配置菜单的“系统”选项卡中取消关联掌机。</li><li>设置系统文件后,请勿同时使用 Azahar 和 3DS 掌机联网,<br>因为这可能会导致问题。</li><li>新 3DS 设置需要先进行老 3DS 设置才能运作(建议两种设置模式都执行)。</li><li>无论运行设置工具的掌机型号如何,两种设置模式均可运作。</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: 输入 Azahar Artic 设置工具地址: - + <br>Choose setup mode: <br>选择设置模式: - + (ℹ️) Old 3DS setup (ℹ️) 老 3DS 设置 - - + + Setup is possible. 可以进行设置。 - + (⚠) New 3DS setup (⚠) 新 3DS 设置 - + Old 3DS setup is required first. 首先需要设置老 3DS。 - + (✅) Old 3DS setup (✅) 老 3DS 设置 - - + + Setup completed. 设置完成。 - + (ℹ️) New 3DS setup (ℹ️) 新 3DS 设置 - + (✅) New 3DS setup (✅) 新 3DS 设置 - + The system files for the selected mode are already set up. Reinstall the files anyway? 所选模式的系统文件已设置。 是否要重新安装文件? - + Load Files 加载多个文件 - - 3DS Installation File (*.CIA*) - 3DS 安装文件 (*.CIA*) + + 3DS Installation File (*.cia *.zcia) + 3DS 安装文件 (*.cia *.zcia) - + + + All Files (*.*) 所有文件 (*.*) - + Connect to Artic Base 连接到 Artic Base - + Enter Artic Base server address: 输入 Artic Base 服务器地址: - + %1 has been installed successfully. %1 已成功安装。 - + Unable to open File 无法打开文件 - + Could not open %1 无法打开 %1 - + Installation aborted 安装失败 - + The installation of %1 was aborted. Please see the log for more details %1 的安装过程失败。请参阅日志以了解细节。 - + Invalid File 文件无效 - + %1 is not a valid CIA %1 不是有效的 CIA 文件 - + CIA Encrypted CIA 已加密 - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> 您的 CIA 文件已加密。 <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>请查看我们的博客以了解更多信息。</a> - + Unable to find File 无法找到文件 - + Could not find %1 找不到 %1 - + + + + + Z3DS Compression + Z3DS 压缩 + + + + Failed to compress some files, check log for details. + 部分文件压缩失败,请查看日志了解详情。 + + + + Failed to decompress some files, check log for details. + 部分文件解压缩失败,请查看日志了解详情。 + + + + All files have been compressed successfully. + 所有文件已成功压缩。 + + + + All files have been decompressed successfully. + 所有文件已成功解压缩。 + + + Uninstalling '%1'... 正在卸载“%1”... - + Failed to uninstall '%1'. 卸载“%1”失败。 - + Successfully uninstalled '%1'. “%1”卸载成功。 - + File not found 找不到文件 - + File "%1" not found 找不到文件“%1” - + Savestates 保存状态 - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! @@ -4535,86 +4627,86 @@ Use at your own risk! 您必须自行承担使用风险! - - - + + + Error opening amiibo data file 打开 Amiibo 数据文件时出错 - + A tag is already in use. 当前已有 Amiibo 标签在使用中。 - + Application is not looking for amiibos. 应用未在寻找 Amiibo。 - + Amiibo File (%1);; All Files (*.*) Amiibo 文件 (%1);;所有文件 (*.*) - + Load Amiibo 加载 Amiibo - + Unable to open amiibo file "%1" for reading. 无法打开 Amiibo 文件 %1 。 - + Record Movie 录制影像 - + Movie recording cancelled. 影像录制已取消。 - - + + Movie Saved 影像已保存 - - + + The movie is successfully saved. 影像已成功保存。 - + Application will unpause 应用将取消暂停 - + The application will be unpaused, and the next frame will be captured. Is this okay? 将取消暂停应用,并捕获下一帧。这样可以吗? - + Invalid Screenshot Directory 无效的截图保存目录 - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. 无法创建指定的截图保存目录。截图保存路径将重设为默认值。 - + Could not load video dumper 无法加载视频转储器 - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4627,215 +4719,265 @@ To view a guide on how to install FFmpeg, press Help. 要查看如何安装 FFmpeg 的指南,请按“帮助”。 - + + Load 3DS ROM Files + 加载 3DS ROM 文件 + + + + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + 3DS 压缩 ROM 文件 (*.%1) + + + + Save 3DS Compressed ROM File + 保存 3DS 压缩 ROM 文件 + + + + Select Output 3DS Compressed ROM Folder + 选择输出 3DS 压缩 ROM 的文件夹 + + + + Load 3DS Compressed ROM Files + 加载 3DS 压缩 ROM 文件 + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + 3DS 压缩 ROM 文件 (*.zcia *zcci *z3dsx *zcxi) + + + + 3DS ROM File (*.%1) + 3DS ROM 文件 (*.%1) + + + + Save 3DS ROM File + 保存 3DS ROM 文件 + + + + Select Output 3DS ROM Folder + 选择输出 3DS ROM 的文件夹 + + + Select FFmpeg Directory 选择 FFmpeg 目录 - + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. 选择的 FFmpeg 目录中缺少 %1 。请确保选择了正确的目录。 - + FFmpeg has been sucessfully installed. FFmpeg 已成功安装。 - + Installation of FFmpeg failed. Check the log file for details. 安装 FFmpeg 失败。详情请参阅日志文件。 - + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. 无法开始视频转储。<br>请确保视频编码器配置正确。<br>有关详细信息,请参阅日志。 - + Recording %1 录制中 %1 - + Playing %1 / %2 播放中 %1 / %2 - + Movie Finished 录像播放完毕 - + (Accessing SharedExtData) (正在获取 SharedExtData) - + (Accessing SystemSaveData) (正在获取 SystemSaveData) - + (Accessing BossExtData) (正在获取 BossExtData) - + (Accessing ExtData) (正在获取 ExtData) - + (Accessing SaveData) 正在获取(SaveData) - + MB/s MB/s - + KB/s KB/s - + Artic Traffic: %1 %2%3 Artic 流量:%1 %2%3 - + Speed: %1% 速度:%1% - + Speed: %1% / %2% 速度:%1% / %2% - + App: %1 FPS 应用: %1 帧 - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + 帧: %1 毫秒 (GPU: [CMD: %2 毫秒, SWP: %3 毫秒], IPC: %4 毫秒, SVC: %5 毫秒, Rem: %6 毫秒) - + Frame: %1 ms 帧延迟:%1 毫秒 - + VOLUME: MUTE 音量:静音 - + VOLUME: %1% Volume percentage (e.g. 50%) 音量:%1% - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - %1 缺失。请<a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>转储您的系统档案</a>。<br/>继续进行模拟可能会导致崩溃和错误。 + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + %1 缺失。请 <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>转储您的系统档案</a>。<br/>继续进行模拟可能会导致崩溃和错误。 - + A system archive 系统档案 - + System Archive Not Found 未找到系统档案 - + System Archive Missing 系统档案丢失 - + Save/load Error 保存/读取出现错误 - + Fatal Error 致命错误 - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - 发生了致命错误。请<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>参阅日志</a>了解详细信息。<br/>继续进行模拟可能会导致崩溃和错误。 + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + 发生了致命错误。请<a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>参阅日志</a>了解详细信息。<br/>继续进行模拟可能会导致崩溃和错误。 - + Fatal Error encountered 发生致命错误 - + Continue 继续 - + Quit Application 退出应用 - + OK 确定 - + Would you like to exit now? 您现在要退出么? - + The application is still running. Would you like to stop emulation? 应用仍在运行。您想停止模拟吗? - + Playback Completed 播放完成 - + Movie playback completed. 影像播放完成。 - + Update Available 有可用更新 - + Update %1 for Azahar is available. Would you like to download it? Azahar 的更新 %1 已发布。 您要下载吗? - + Primary Window 主窗口 - + Secondary Window 次级窗口 @@ -4898,42 +5040,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! OpenGL 不可用! - + OpenGL shared contexts are not supported. 不支持 OpenGL 共享上下文。 - + Error while initializing OpenGL! 初始化 OpenGL 时出错! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. 您的 GPU 可能不支持 OpenGL,或没有安装最新的显卡驱动程序。 - + Error while initializing OpenGL 4.3! 初始化 OpenGL 4.3 时出错! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 您的 GPU 可能不支持 OpenGL 4.3,或没有安装最新的显卡驱动程序。<br><br>GL 渲染器:<br>%1 - + Error while initializing OpenGL ES 3.2! 初始化 OpenGL ES 3.2 时出错! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 您的 GPU 可能不支持 OpenGL ES 3.2,或没有安装最新的 GPU 驱动程序。<br><br>GL 渲染器:<br>%1 @@ -4941,175 +5083,185 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - 重要提示:加密文件和 3ds 后缀名文件不再受支持。可能需要解密和/或重命名为 cci 后缀名。<a href='https://azahar-emu.org/blog/game-loading-changes/'>了解详情。</a> - - - - Don't show again - 不再显示 - - - - + + Compatibility 兼容性 - - + + Region 地区 - - + + File type 文件类型 - - + + Size 大小 - - + + Play time 游戏时间 - + Favorite 收藏 - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open 打开 - + Application Location 应用路径 - + Save Data Location 存档数据路径 - + Extra Data Location 额外数据路径 - + Update Data Location 更新数据路径 - + DLC Data Location DLC 数据路径 - + Texture Dump Location 纹理转储路径 - + Custom Texture Location 自定义纹理路径 - + Mods Location Mods 路径 - + Dump RomFS 转储 RomFS - + Disk Shader Cache 磁盘着色器缓存 - + Open Shader Cache Location 打开着色器缓存位置 - + Delete OpenGL Shader Cache 删除 OpenGL 着色器缓存 - + + Delete Vulkan Shader Cache + + + + Uninstall 卸载 - + Everything 所有内容 - + Application 应用 - + Update 更新补丁 - + DLC DLC - + Remove Play Time Data 删除游玩时间 - + Create Shortcut 创建快捷方式 - + Add to Desktop 添加到桌面 - + Add to Applications Menu 添加到应用菜单 - + + Stress Test: App Launch + 压力测试:应用启动 + + + Properties 属性 - - - - + + + + Azahar Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. @@ -5118,64 +5270,64 @@ This will delete the application if installed, as well as any installed updates 这将删除应用、已安装的更新补丁或 DLC。 - - + + %1 (Update) %1(更新补丁) - - + + %1 (DLC) %1(DLC) - + Are you sure you want to uninstall '%1'? 您确定要卸载“%1”吗? - + Are you sure you want to uninstall the update for '%1'? 您确定要卸载“%1”的更新补丁吗? - + Are you sure you want to uninstall all DLC for '%1'? 您确定要卸载“%1”的所有 DLC 吗? - + Scan Subfolders 扫描子文件夹 - + Remove Application Directory 移除应用目录 - + Move Up 向上移动 - + Move Down 向下移动 - + Open Directory Location 打开目录位置 - + Clear 清除 - + Name 名称 @@ -5183,82 +5335,82 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect 完美 - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. 应用运行完美,没有音频或图形问题。所有测试功能均按预期运行。 无需任何另外的解决方法。 - + Great 良好 - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. 应用运行时会有非常轻微的图像或音频问题,但是能从头玩到尾。 可能需要一些方法来避免问题。 - + Okay 一般 - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. 应用运行时会有严重的图像或音频错误, 但是在使用一些方法之后能从头到尾地完成流程。 - + Bad 较差 - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. 应用能运行,但是会有严重的图像或音频错误。 即使有解决方法仍无法通过某些特定区域。 - + Intro/Menu 开场 / 菜单 - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. 应用完全无法运行,图像或音频有重大错误。 无法通过开场菜单。 - + Won't Boot 无法打开 - + The app crashes when attempting to startup. 应用在尝试启动时直接崩溃。 - + Not Tested 未测试 - + The app has not yet been tested. 应用尚未经过测试。 @@ -5266,7 +5418,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list 双击将新文件夹添加到应用列表 @@ -5274,27 +5426,27 @@ Screen. GameListSearchField - + of / - + result 结果 - + results 结果 - + Filter: 搜索: - + Enter pattern to filter 搜索游戏 @@ -5302,47 +5454,47 @@ Screen. GameRegion - + Japan 日本 - + North America 北美 - + Europe 欧洲 - + Australia 澳大利亚 - + China 中国大陆 - + Korea 韩国 - + Taiwan 港台 - + Invalid region 无效的地区 - + Region free 不锁区 @@ -5622,87 +5774,87 @@ Screen. 循环索引: - + SRC1: %1, %2, %3, %4 SRC1: %1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 SRC2: %1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 SRC3: %1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 DEST_IN: %1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 DEST_OUT: %1, %2, %3, %4 - + Address Registers: %1, %2 地址寄存器:%1, %2 - + Compare Result: %1, %2 比较结果:%1, %2 - + Static Condition: %1 静态状态:%1 - + Dynamic Conditions: %1, %2 动态状态:%1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 循环参数:%1 (循环), %2(初始值), %3(增量), %4 - + Instruction offset: 0x%1 指令偏移量:0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (上一个指令) @@ -5927,24 +6079,24 @@ Debug Message: 正在准备着色器... %1 / %2 - - Loading Shaders %1 / %2 - 正在加载着色器... %1 / %2 + + Loading %3 %1 / %2 + - + Launching... 载入中... - + Now Loading %1 正在加载 %1 - + Estimated Time %1 所需时间:%1 @@ -6003,32 +6155,32 @@ Debug Message: 密码: - + Room Name 房间名称 - + Preferred Application 首选应用 - + Host 创建者 - + Players 玩家 - + Refreshing 正在刷新 - + Refresh List 刷新列表 @@ -6111,342 +6263,352 @@ Debug Message: 影像 - + Help 帮助 - + Load File... 加载文件… - + Install CIA... 安装 CIA… - + Connect to Artic Base... 连接到 Artic Base... - + Set Up System Files... 设置系统文件... - + JPN 日本 - + USA 北美 - + EUR 欧洲 - + AUS 澳大利亚 - + CHN 中国大陆 - + KOR 韩国 - + TWN 港台 - + Exit 退出 - + Pause 暂停 - + Stop 停止 - + Save 保存 - + Load 读取 - + FAQ 常见问题 - + About Azahar 关于 Azahar - + Single Window Mode 单窗口模式 - + Save to Oldest Slot 覆盖保存到最旧存档 - + Quick Save 快速保存 - + Load from Newest Slot 读取最新存档 - + Quick Load 快速载入 - + Configure... 设置… - + Display Dock Widget Headers 显示停靠小部件的标题 - + Show Filter Bar 显示搜索栏 - + Show Status Bar 显示状态栏 - + Create Pica Surface Viewer 新建 Pica 表面浏览器 - + Record... 录制... - + Play... 播放... - + Close 关闭 - + Save without Closing 保存但不关闭 - + Read-Only Mode 只读模式 - + Advance Frame 播放下一帧 - + Capture Screenshot 捕获截图 - + Dump Video 转储屏幕录像 + Compress ROM File... + 压缩 ROM 文件... + + + + Decompress ROM File... + 解压 ROM 文件... + + + Browse Public Rooms 浏览公共房间 - + Create Room 创建房间 - + Leave Room 离开房间 - + Direct Connect to Room 直接连接到房间 - + Show Current Room 显示当前房间 - + Fullscreen 全屏 - + Open Log Folder 打开日志文件夹 - + Opens the Azahar Log folder 打开 Azahar 日志文件夹 - + Default 默认 - + Single Screen 单屏 - + Large Screen 大屏 - + Side by Side 并排屏幕 - + Separate Windows 分离窗口 - + Hybrid Screen 混合式屏幕 - + Custom Layout 自定义布局 - + Top Right 右上 - + Middle Right 右中 - + Bottom Right 右下 - + Top Left 左上 - + Middle Left 左中 - + Bottom Left 左下 - + Above - + Below - + Swap Screens 交换上下屏 - + Rotate Upright 逆时针旋转 - + Report Compatibility 报告兼容性 - + Restart 重新启动 - + Load... 加载... - + Remove 移除 - + Open Azahar Folder 打开 Azahar 文件夹 - + Configure Current Application... 配置当前应用… @@ -7020,32 +7182,32 @@ They may have left the room. %1 (0x%2) - + Unsupported encrypted application 不支持的加密应用 - + Invalid region 无效的地区 - + Installed Titles 已安装的项目 - + System Titles 系统项目 - + Add New Application Directory 添加新的应用目录 - + Favorites 收藏 diff --git a/dist/languages/zh_TW.ts b/dist/languages/zh_TW.ts index c2e85606f..8c6f5ad4a 100644 --- a/dist/languages/zh_TW.ts +++ b/dist/languages/zh_TW.ts @@ -28,7 +28,7 @@ - <html><head/><body><p><img src=":/icons/azahar.png"/></p></body></html> + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -292,8 +292,8 @@ This would ban both their forum username and their IP address. - Emulation: - 模擬 + Emulation + 模擬 @@ -322,8 +322,8 @@ This would ban both their forum username and their IP address. - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - 讓音訊速度與遊戲的模擬速度透過後處理效果同步,這有助於防止音訊斷斷續續,但是也增加了音訊延遲。 + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> + @@ -332,7 +332,7 @@ This would ban both their forum username and their IP address. - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> @@ -397,6 +397,7 @@ This would ban both their forum username and their IP address. + Camera 相機 @@ -408,8 +409,8 @@ This would ban both their forum username and their IP address. - Camera to configure: - 設定的鏡頭: + Camera to Configure + @@ -429,8 +430,8 @@ This would ban both their forum username and their IP address. - Camera mode: - 相機模式: + Camera mode + @@ -450,8 +451,8 @@ This would ban both their forum username and their IP address. - Camera position: - 鏡頭位置: + Camera position + @@ -471,13 +472,13 @@ This would ban both their forum username and their IP address. - Select where the image of the emulated camera comes from. It may be an image or a real camera. - 選擇相機畫面的來源,可以使用圖片或電腦相機。 + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> + - Camera Image Source: - 相機畫面來源: + Camera Image Source + @@ -496,8 +497,8 @@ This would ban both their forum username and their IP address. - File: - 檔案: + File + @@ -510,11 +511,6 @@ This would ban both their forum username and their IP address. Select the system camera to use 選擇電腦相機 - - - Camera: - 相機: - <Default> @@ -528,8 +524,8 @@ This would ban both their forum username and their IP address. - Flip: - 翻轉圖片: + Flip + @@ -1018,7 +1014,7 @@ Would you like to ignore the error and continue? Enable Linear Filtering - 啟用線性過濾 + @@ -1082,7 +1078,7 @@ Would you like to ignore the error and continue? - Reverse Side by Side + Side by Side Full Width @@ -1141,49 +1137,54 @@ Would you like to ignore the error and continue? - + + Swap Eyes + + + + Utility 工具 - + <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> <html><head/><body><p>使用 PNG 文件進行紋理的替換。 </p><p>將於 load/textures/[Title ID]/ 目錄下加載紋理文件。 </p></body></html> - - Use Custom Textures - 使用自定義紋理 + + Use custom textures + - + <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> <html><head/><body><p>使用 PNG 文件進行紋理的替換。 </p><p>將於 load/textures/[Title ID]/ 目錄下加載紋理文件。 </p></body></html> - - Dump Textures - 轉儲紋理文件 + + Dump textures + - + <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - - Preload Custom Textures - 預加載自定義紋理 + + Preload custom textures + - + <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> <html><head/><body><p>在後台線程中異步加載自定義紋理,以減少加載帶來的卡頓</p></body></html> - - Async Custom Texture Loading - 異步加載自定義紋理 + + Async custom texture loading + @@ -1195,91 +1196,111 @@ Would you like to ignore the error and continue? - General - 一般 + Updates + - Confirm exit while emulation is running - 在遊戲執行中離開時確認 - - - - Pause emulation when in background - 模擬器位於後台時暫停模擬 - - - - Mute audio when in background - - - - - Hide mouse on inactivity - 自動隱藏鼠標光標 - - - - Enable Gamemode - - - - Check for updates - + + Update Channel + + + + + Stable + + + + + Prerelease + + + + + General + 一般 + + + + Confirm exit while emulation is running + 在遊戲執行中離開時確認 + + + + Pause emulation when in background + 模擬器位於後台時暫停模擬 + + + + Mute audio when in background + + + + + Hide mouse on inactivity + 自動隱藏鼠標光標 + + + + Enable Gamemode + + + + Emulation 模擬 - + Use global emulation speed 使用全局模擬速度 - - Set emulation speed: - 設置模擬速度: + + Set emulation speed + - - Emulation Speed: - 模擬速度: + + Emulation Speed + - + Turbo Speed Limit: - + Screenshots 截圖 - + Use global screenshot path 使用全局截圖保存位置 - + Set screenshot path: 截圖保存位置: - + Save Screenshots To 將截圖保存至 - + ... - + Reset All Settings 全部重設 @@ -1287,8 +1308,8 @@ Would you like to ignore the error and continue? - - + + unthrottled 無限制 @@ -1298,12 +1319,12 @@ Would you like to ignore the error and continue? 選擇截圖保存目錄 - + Azahar - + Are you sure you want to <b>reset your settings</b> and close Azahar? @@ -1357,12 +1378,12 @@ Would you like to ignore the error and continue? - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer @@ -1382,8 +1403,8 @@ Would you like to ignore the error and continue? - Enable Hardware Shader - 啟用硬體著色 + Enable hardware shader + @@ -1392,8 +1413,8 @@ Would you like to ignore the error and continue? - Accurate Multiplication - 精準著色增值 + Accurate multiplication + @@ -1402,8 +1423,8 @@ Would you like to ignore the error and continue? - Enable Shader JIT - 啟用 JIT 著色 + Enable shader JIT + @@ -1412,17 +1433,17 @@ Would you like to ignore the error and continue? - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -1462,13 +1483,13 @@ Would you like to ignore the error and continue? - Use Disk Shader Cache - 啟用磁盤著色器緩存 + Use disk shader cache + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - 垂直同步可防止畫面產生撕裂感。但啟用垂直同步後,某些設備性能可能會有所降低。如果您沒有感到性能差異,請保持啟用狀態。 + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> + @@ -1476,22 +1497,32 @@ Would you like to ignore the error and continue? - + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + + + Enable display refresh rate detection + + + + Use global - + Use per-application - - Delay application render thread: + + Delay Application Render Thread - + <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -1976,12 +2007,12 @@ Would you like to ignore the error and continue? - Swap Screens - 交換上下畫面 + Swap screens + - Rotate Screens Upright + Rotate screens upright @@ -2098,7 +2129,7 @@ Would you like to ignore the error and continue? - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> @@ -2270,7 +2301,7 @@ Would you like to ignore the error and continue? - <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> @@ -2446,7 +2477,7 @@ Would you like to ignore the error and continue? - Use Virtual SD + Use virtual SD card @@ -2456,7 +2487,7 @@ Would you like to ignore the error and continue? - Use Custom Storage + Use custom storage location @@ -2487,6 +2518,16 @@ Would you like to ignore the error and continue? SDMC Directory + + + Compress installed CIA content + + + + + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> + + Select NAND Directory @@ -2533,8 +2574,8 @@ online features (if installed) - Region: - + Region + 地區 @@ -2542,326 +2583,337 @@ online features (if installed) - + + Apply region free patch to +installed applications. + + + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + Username 使用者名稱 - + Birthday 生日 - + January 一月 - + February 二月 - + March 三月 - + April 四月 - + May 五月 - + June 六月 - + July 七月 - + August 八月 - + September 九月 - + October 十月 - + November 十一月 - + December 十二月 - + Language 語言 - + Note: this can be overridden when region setting is auto-select 注意:當「地區」設定是自動時,會覆寫這個設定。 - + Japanese (日本語) 日文 (日本語) - + English 英文 (English) - + French (français) 法文 (français) - + German (Deutsch) 德文 (Deutsch) - + Italian (italiano) 義大利文 (Italiano) - + Spanish (español) 西班牙文 (Español) - + Simplified Chinese (简体中文) 簡體中文 (简体中文) - + Korean (한국어) 韓文 (한국어) - + Dutch (Nederlands) 荷蘭文 (Nederlands) - + Portuguese (português) 葡萄牙文 (Português) - + Russian (Русский) 俄文 (Русский) - + Traditional Chinese (正體中文) 正體中文 (正體中文) - + Sound output mode 聲音輸出模式 - + Mono 單聲道 - + Stereo 立體聲 - + Surround 環繞 - + Country 國家 - + Clock 時鐘 - + System Clock 系統時鐘 - + Fixed Time 固定時間 - + Startup time 每次開始的時間 - + yyyy-MM-ddTHH:mm:ss yyyy-MM-ddTHH:mm:ss - + Offset time - + days - + HH:mm:ss - + Initial System Ticks - + Random - + Fixed - + Initial System Ticks Override - + Play Coins - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> - + Pedometer Steps per Hour - + Run System Setup when Home Menu is launched - + Console ID: 裝置 ID: - - + + Regenerate 更換 ID - + MAC: - - 3GX Plugin Loader: + + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state - + Real Console Unique Data - + Your real console is linked to Azahar. - + Unlink - + OTP - - - - + + + + Choose - + SecureInfo_A/B - + LocalFriendCodeSeed_A/B - + movable.sed - + System settings are available only when applications is not running. @@ -3571,76 +3623,76 @@ online features (if installed) - - + + Console ID: 0x%1 裝置 ID:0x%1 - - + + MAC: %1 - + This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects in applications. This might fail if you use an outdated config save. Continue? - - - + + + Warning 警告 - + This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue? - + This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again (save data will not be lost).</li></ul><br>Continue? - + Invalid country for configured region - + Invalid country for console unique data - + Status: Loaded - + Status: Loaded (Invalid Signature) - + Status: Loaded (Region Changed) - + Status: Not Found - + Status: Invalid - + Status: IO Error @@ -3755,13 +3807,13 @@ Drag points to change position, or double-click table cells to edit values. - Interface language: - 介面語言: + Interface Language + - Theme: - 主題: + Theme + @@ -3770,8 +3822,8 @@ Drag points to change position, or double-click table cells to edit values. - Icon Size: - 圖示大小: + Icon Size + @@ -3791,8 +3843,8 @@ Drag points to change position, or double-click table cells to edit values. - Row 1 Text: - 第一行: + Row 1 Text + @@ -3826,17 +3878,17 @@ Drag points to change position, or double-click table cells to edit values. - Row 2 Text: - 第二行: + Row 2 Text + - Hide Titles without Icon - 隱藏不能執行的遊戲 + Hide titles without icon + - Single Line Mode + Single line mode @@ -3846,7 +3898,7 @@ Drag points to change position, or double-click table cells to edit values. - Show Advanced Frame Time Info + Show advanced frame time info @@ -3929,12 +3981,12 @@ Drag points to change position, or double-click table cells to edit values. DirectConnectWindow - + Connecting 連線中 - + Connect 連線 @@ -4053,557 +4105,597 @@ Please check your FFmpeg installation used for compilation. GMainWindow - + No Suitable Vulkan Devices Detected - + Vulkan initialization failed during boot.<br/>Your GPU may not support Vulkan 1.1, or you do not have the latest graphics driver. - + Current Artic traffic speed. Higher values indicate bigger transfer loads. - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. 目前模擬速度, 「高於/低於」100% 代表模擬速度比 3DS 實機「更快/更慢」。 - - + + How many frames per second the app is currently displaying. This will vary from app to app and scene to scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 不計算影格限制或垂直同步時, 模擬一個 3DS 影格所花的時間。全速模擬時,這個數值最多應為 16.67 毫秒。 - + MicroProfile (unavailable) - + Clear Recent Files 清除檔案使用紀錄 - + &Continue - + &Pause - + Azahar is running an application TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the computer from sleeping - - + + Invalid App Format - - + + Your app format is not supported.<br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Corrupted - + Your app is corrupted. <br/>Please follow the guides to redump your <a href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + App Encrypted - + Your app is encrypted. <br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unsupported App - + GBA Virtual Console is not supported by Azahar. - - + + Artic Server - + + Invalid system mode + + + + + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. + + + + Error while loading App! - + An unknown error occurred. Please see the log for more details. - + CIA must be installed before usage CIA 檔案必須先安裝 - + Before using this CIA, you must install it. Do you want to install it now? CIA 檔案必須先安裝才能夠執行。您現在要安裝這個檔案嗎? - + Quick Load - + Quick Save - - + + Slot %1 - + %2 %3 - + Quick Save - %1 - + Quick Load - %1 - + Slot %1 - %2 %3 - + Error Opening %1 Folder 開啟 %1 資料夾時錯誤 - - + + Folder does not exist! 資料夾不存在! - + Remove Play Time Data - + Reset play time? - - - - + + + + Create Shortcut - + Do you want to launch the application in fullscreen? - + Successfully created a shortcut to %1 - + This will create a shortcut to the current AppImage. This may not work well if you update. Continue? - + Failed to create a shortcut to %1 - + Create Icon - + Cannot create icon file. Path "%1" does not exist and cannot be created. - + Dumping... - - + + Cancel 取消 - - - - - - - - - + + + + + + + + + Azahar - + Could not dump base RomFS. Refer to the log for details. - + Error Opening %1 開啟 %1 時錯誤 - + Select Directory 選擇目錄 - + Properties - + The application properties could not be loaded. - + 3DS Executable (%1);;All Files (*.*) %1 is an identifier for the 3DS executable file extensions. 3DS 可執行檔案 (%1);;所有檔案 (*.*) - + Load File 讀取檔案 - - + + Set Up System Files - + <p>Azahar needs console unique data and firmware files from a real console to be able to use some of its features.<br>Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the<br>console later from the System tab in the emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files,<br>as it could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both setup modes is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul><hr></p> - + Enter Azahar Artic Setup Tool address: - + <br>Choose setup mode: - + (ℹ️) Old 3DS setup - - + + Setup is possible. - + (⚠) New 3DS setup - + Old 3DS setup is required first. - + (✅) Old 3DS setup - - + + Setup completed. - + (ℹ️) New 3DS setup - + (✅) New 3DS setup - + The system files for the selected mode are already set up. Reinstall the files anyway? - + Load Files 讀取多個檔案 - - 3DS Installation File (*.CIA*) - 3DS 安裝檔 (*.CIA) + + 3DS Installation File (*.cia *.zcia) + - + + + All Files (*.*) 所有檔案 (*.*) - + Connect to Artic Base - + Enter Artic Base server address: - + %1 has been installed successfully. 已成功安裝 %1。 - + Unable to open File 無法開啟檔案 - + Could not open %1 無法開啟 %1 - + Installation aborted 安裝中斷 - + The installation of %1 was aborted. Please see the log for more details 安裝 %1 時中斷,請參閱日誌了解細節。 - + Invalid File 無效的檔案 - + %1 is not a valid CIA %1 不是有效的 CIA 檔案 - + CIA Encrypted - + Your CIA file is encrypted.<br/><a href='https://azahar-emu.org/blog/game-loading-changes/'>Please check our blog for more info.</a> - + Unable to find File - + Could not find %1 - + + + + + Z3DS Compression + + + + + Failed to compress some files, check log for details. + + + + + Failed to decompress some files, check log for details. + + + + + All files have been compressed successfully. + + + + + All files have been decompressed successfully. + + + + Uninstalling '%1'... - + Failed to uninstall '%1'. - + Successfully uninstalled '%1'. - + File not found 找不到檔案 - + File "%1" not found 找不到「%1」 - + Savestates - + Warning: Savestates are NOT a replacement for in-application saves, and are not meant to be reliable. Use at your own risk! - - - + + + Error opening amiibo data file - + A tag is already in use. - + Application is not looking for amiibos. - + Amiibo File (%1);; All Files (*.*) Amiibo 檔案 (%1);;所有檔案 (*.*) - + Load Amiibo 讀取 Amiibo - + Unable to open amiibo file "%1" for reading. - + Record Movie 錄影 - + Movie recording cancelled. 錄影已取消。 - - + + Movie Saved 已儲存影片 - - + + The movie is successfully saved. 影片儲存成功。 - + Application will unpause - + The application will be unpaused, and the next frame will be captured. Is this okay? - + Invalid Screenshot Directory - + Cannot create specified screenshot directory. Screenshot path is set back to its default value. - + Could not load video dumper - + FFmpeg could not be loaded. Make sure you have a compatible version installed. To install FFmpeg to Azahar, press Open and select your FFmpeg directory. @@ -4612,214 +4704,264 @@ To view a guide on how to install FFmpeg, press Help. - - Select FFmpeg Directory - - - - - The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. - - - - - FFmpeg has been sucessfully installed. - - - - - Installation of FFmpeg failed. Check the log file for details. - - - - - Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. - - - - - Recording %1 - - - - - Playing %1 / %2 - - - - - Movie Finished - - - - - (Accessing SharedExtData) - - - - - (Accessing SystemSaveData) - - - - - (Accessing BossExtData) + + Load 3DS ROM Files + 3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds) + + + + + 3DS Compressed ROM File (*.%1) + + + + + Save 3DS Compressed ROM File + + + + + Select Output 3DS Compressed ROM Folder + + + + + Load 3DS Compressed ROM Files + + + + + 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) + + + + + 3DS ROM File (*.%1) + + + + + Save 3DS ROM File + + + + + Select Output 3DS ROM Folder + + + + + Select FFmpeg Directory + + + + + The provided FFmpeg directory is missing %1. Please make sure the correct directory was selected. + + + + + FFmpeg has been sucessfully installed. + + + + + Installation of FFmpeg failed. Check the log file for details. + + + + + Could not start video dumping.<br>Please ensure that the video encoder is configured correctly.<br>Refer to the log for details. + + + + + Recording %1 + + + + + Playing %1 / %2 + + + + + Movie Finished + + + + + (Accessing SharedExtData) + + + + + (Accessing SystemSaveData) + + + + + (Accessing BossExtData) + + + + (Accessing ExtData) - + (Accessing SaveData) - + MB/s - + KB/s - + Artic Traffic: %1 %2%3 - + Speed: %1% 速度:%1% - + Speed: %1% / %2% 速度:%1% / %2% - + App: %1 FPS - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms 影格:%1 ms - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - - %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + + %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + A system archive - + System Archive Not Found 找不到系統檔案 - + System Archive Missing - + Save/load Error - + Fatal Error 嚴重錯誤 - - A fatal error occurred. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + + A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Fatal Error encountered - + Continue 繼續 - + Quit Application - + OK 確定 - + Would you like to exit now? 您確定要離開嗎? - + The application is still running. Would you like to stop emulation? - + Playback Completed 播放完成 - + Movie playback completed. 影片已結束播放。 - + Update Available - + Update %1 for Azahar is available. Would you like to download it? - + Primary Window - + Secondary Window @@ -4882,42 +5024,42 @@ Would you like to download it? GRenderWindow - + OpenGL not available! - + OpenGL shared contexts are not supported. - + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.3! - + Your GPU may not support OpenGL 4.3, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Error while initializing OpenGL ES 3.2! - + Your GPU may not support OpenGL ES 3.2, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 @@ -4925,239 +5067,249 @@ Would you like to download it? GameList - - IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a> - - - - - Don't show again - - - - - + + Compatibility 相容性 - - + + Region 地區 - - + + File type 檔案類型 - - + + Size 大小 - - + + Play time - + Favorite - + + Eject Cartridge + + + + + Insert Cartridge + + + + Open - + Application Location - + Save Data Location - + Extra Data Location - + Update Data Location - + DLC Data Location - + Texture Dump Location - + Custom Texture Location - + Mods Location - + Dump RomFS - + Disk Shader Cache - + Open Shader Cache Location - + Delete OpenGL Shader Cache - + + Delete Vulkan Shader Cache + + + + Uninstall - + Everything - + Application - + Update - + DLC - + Remove Play Time Data - + Create Shortcut - + Add to Desktop - + Add to Applications Menu - + + Stress Test: App Launch + + + + Properties - - - - + + + + Azahar - + Are you sure you want to completely uninstall '%1'? This will delete the application if installed, as well as any installed updates or DLC. - - + + %1 (Update) - - + + %1 (DLC) - + Are you sure you want to uninstall '%1'? - + Are you sure you want to uninstall the update for '%1'? - + Are you sure you want to uninstall all DLC for '%1'? - + Scan Subfolders 掃描子資料夾 - + Remove Application Directory - + Move Up - + Move Down - + Open Directory Location 開啟資料夾位置 - + Clear 清除 - + Name 名稱 @@ -5165,77 +5317,77 @@ This will delete the application if installed, as well as any installed updates GameListItemCompat - + Perfect 完美 - + App functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great 良好 - + App functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay 普通 - + App functions with major graphical or audio glitches, but app is playable from start to finish with workarounds. - + Bad 不好 - + App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu 片頭/選單 - + App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot 無法啟動 - + The app crashes when attempting to startup. - + Not Tested 未測試 - + The app has not yet been tested. @@ -5243,7 +5395,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the application list @@ -5251,27 +5403,27 @@ Screen. GameListSearchField - + of / - + result 項符合 - + results 項符合 - + Filter: 項目篩選 - + Enter pattern to filter 輸入項目關鍵字 @@ -5279,47 +5431,47 @@ Screen. GameRegion - + Japan 日本 - + North America - + Europe - + Australia 澳洲 - + China 中國 - + Korea - + Taiwan 台灣 - + Invalid region 無效的地區 - + Region free @@ -5599,87 +5751,87 @@ Screen. 循環指標: - + SRC1: %1, %2, %3, %4 來源一:%1, %2, %3, %4 - + SRC2: %1, %2, %3, %4 來源二:%1, %2, %3, %4 - + SRC3: %1, %2, %3, %4 來源三:%1, %2, %3, %4 - + DEST_IN: %1, %2, %3, %4 目標在內:%1, %2, %3, %4 - + DEST_OUT: %1, %2, %3, %4 目標在外:%1, %2, %3, %4 - + Address Registers: %1, %2 位址暫存器:%1, %2 - + Compare Result: %1, %2 比較結果:%1, %2 - + Static Condition: %1 靜態:%1 - + Dynamic Conditions: %1, %2 動態:%1, %2 - + Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 迴圈參數:%1(重複)、%2(初始)、%3(增量)、%4 - + Instruction offset: 0x%1 指令偏置:0x%1 - + -> 0x%2 -> 0x%2 - + (last instruction) (上一個指令) @@ -5903,23 +6055,23 @@ Debug Message: - - Loading Shaders %1 / %2 + + Loading %3 %1 / %2 - + Launching... - + Now Loading %1 - + Estimated Time %1 @@ -5978,32 +6130,32 @@ Debug Message: 密碼: - + Room Name 房間名稱 - + Preferred Application - + Host 建立者 - + Players 玩家數 - + Refreshing 正在重新整理 - + Refresh List 重新整理 @@ -6086,342 +6238,352 @@ Debug Message: 影片 - + Help - + Load File... 讀取檔案… - + Install CIA... 安裝 CIA… - + Connect to Artic Base... - + Set Up System Files... - + JPN - + USA - + EUR - + AUS - + CHN - + KOR - + TWN - + Exit - + Pause - + Stop - + Save - + Load - + FAQ - + About Azahar - + Single Window Mode 統一視窗 - + Save to Oldest Slot - + Quick Save - + Load from Newest Slot - + Quick Load - + Configure... 設定… - + Display Dock Widget Headers 顯示小工具的標題 - + Show Filter Bar 顯示項目篩選列 - + Show Status Bar 顯示狀態列 - + Create Pica Surface Viewer 建立 Pica 表層檢視器 - + Record... - + Play... - + Close - + Save without Closing - + Read-Only Mode - + Advance Frame 步進 - + Capture Screenshot 畫面擷取 - + Dump Video + Compress ROM File... + + + + + Decompress ROM File... + + + + Browse Public Rooms - + Create Room 建立房間 - + Leave Room 離開房間 - + Direct Connect to Room 連線到特定房間 - + Show Current Room 顯示目前房間 - + Fullscreen 全螢幕 - + Open Log Folder - + Opens the Azahar Log folder - + Default 預設 - + Single Screen 單一畫面 - + Large Screen 大畫面 - + Side by Side 並排 - + Separate Windows - + Hybrid Screen - + Custom Layout - + Top Right - + Middle Right - + Bottom Right - + Top Left - + Middle Left - + Bottom Left - + Above - + Below - + Swap Screens 交換上下畫面 - + Rotate Upright - + Report Compatibility 回報遊戲相容性 - + Restart 重新開始 - + Load... 讀取… - + Remove 移除 - + Open Azahar Folder - + Configure Current Application... @@ -6494,7 +6656,7 @@ Debug Message: File: - 檔案: + @@ -6586,7 +6748,7 @@ Debug Message: File: - 檔案: + @@ -6992,32 +7154,32 @@ They may have left the room. - + Unsupported encrypted application - + Invalid region 無效的地區 - + Installed Titles - + System Titles - + Add New Application Directory - + Favorites diff --git a/dist/license.md b/dist/license.md index 207fc638e..801b0a519 100644 --- a/dist/license.md +++ b/dist/license.md @@ -16,6 +16,7 @@ qt_themes/default/icons/48x48/no_avatar.png | CC BY-ND 3.0 | https://icons8.com qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com qt_themes/default/icons/48x48/star.png | CC BY-ND 3.0 | https://icons8.com +qt_themes/default/icons/128x128/cartridge.png | CC0 1.0 | Designed by PabloMK7 qt_themes/qdarkstyle/icons/16x16/connected.png | CC BY-ND 3.0 | https://icons8.com qt_themes/qdarkstyle/icons/16x16/connected_notification.png | CC BY-ND 3.0 | https://icons8.com qt_themes/qdarkstyle/icons/16x16/disconnected.png | CC BY-ND 3.0 | https://icons8.com diff --git a/dist/org.azahar_emu.Azahar.xml b/dist/org.azahar_emu.Azahar.xml index 6f884c9ea..0fa7afbae 100644 --- a/dist/org.azahar_emu.Azahar.xml +++ b/dist/org.azahar_emu.Azahar.xml @@ -16,6 +16,7 @@ CTR Cart Image + diff --git a/dist/qt_themes/default/icons/128x128/cartridge.png b/dist/qt_themes/default/icons/128x128/cartridge.png new file mode 100644 index 000000000..cb669ee29 Binary files /dev/null and b/dist/qt_themes/default/icons/128x128/cartridge.png differ diff --git a/dist/qt_themes/default/icons/index.theme b/dist/qt_themes/default/icons/index.theme index 1edbe6408..a7cfb3306 100644 --- a/dist/qt_themes/default/icons/index.theme +++ b/dist/qt_themes/default/icons/index.theme @@ -1,13 +1,16 @@ [Icon Theme] Name=default Comment=default theme -Directories=16x16,48x48,256x256 +Directories=16x16,48x48,128x128,256x256 [16x16] Size=16 [48x48] Size=48 - + +[128x128] +Size=128 + [256x256] Size=256 \ No newline at end of file diff --git a/dist/qt_themes/default/icons_light/128x128/cartridge.png b/dist/qt_themes/default/icons_light/128x128/cartridge.png new file mode 100644 index 000000000..cb669ee29 Binary files /dev/null and b/dist/qt_themes/default/icons_light/128x128/cartridge.png differ diff --git a/dist/qt_themes/default/icons_light/index.theme b/dist/qt_themes/default/icons_light/index.theme index 1edbe6408..a7cfb3306 100644 --- a/dist/qt_themes/default/icons_light/index.theme +++ b/dist/qt_themes/default/icons_light/index.theme @@ -1,13 +1,16 @@ [Icon Theme] Name=default Comment=default theme -Directories=16x16,48x48,256x256 +Directories=16x16,48x48,128x128,256x256 [16x16] Size=16 [48x48] Size=48 - + +[128x128] +Size=128 + [256x256] Size=256 \ No newline at end of file diff --git a/dist/qt_themes/default/theme_default.qrc b/dist/qt_themes/default/theme_default.qrc index c8339f86d..90ae777aa 100644 --- a/dist/qt_themes/default/theme_default.qrc +++ b/dist/qt_themes/default/theme_default.qrc @@ -13,6 +13,7 @@ icons/48x48/no_avatar.png icons/48x48/plus.png icons/48x48/sd_card.png + icons/128x128/cartridge.png icons/256x256/azahar.png icons/48x48/star.png icons/256x256/plus_folder.png @@ -31,6 +32,7 @@ icons_light/48x48/no_avatar.png icons_light/48x48/plus.png icons_light/48x48/sd_card.png + icons_light/128x128/cartridge.png icons_light/256x256/azahar.png icons_light/48x48/star.png icons_light/256x256/plus_folder.png diff --git a/docker/azahar-room/Dockerfile b/docker/azahar-room/Dockerfile new file mode 100644 index 000000000..c47896dd9 --- /dev/null +++ b/docker/azahar-room/Dockerfile @@ -0,0 +1,31 @@ +# This Dockerfile assumes that it is being built from the project root directory, e.g.: +# $ docker build -f docker/azahar-room/Dockerfile -t azahar-room . + +# --- Builder ---------------- +FROM opensauce04/azahar-build-environment:latest AS builder + +COPY . /var/azahar-src + +RUN mkdir builddir && cd builddir && \ + cmake /var/azahar-src -G Ninja \ + -DENABLE_QT=OFF \ + -DENABLE_TESTS=OFF \ + -DENABLE_ROOM=ON \ + -DENABLE_ROOM_STANDALONE=ON \ + -DENABLE_OPENGL=OFF $( : "TODO: Can we disable these automatically when there's no frontend?") \ + -DENABLE_VULKAN=OFF \ + -DENABLE_SDL2=OFF \ + -DENABLE_LIBUSB=OFF \ + -DENABLE_CUBEB=OFF \ + -DENABLE_OPENAL=OFF && \ + ninja && \ + mv bin/Release/azahar-room /usr/local/bin/ && \ + cd .. && rm -rf builddir + +# --- Final ------------------ +FROM debian:trixie AS final + +RUN apt-get update && apt-get -y full-upgrade +RUN apt-get install -y iputils-ping net-tools + +COPY --from=builder /usr/local/bin/azahar-room /usr/local/bin/azahar-room diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 21a32d642..01e76a095 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -1,24 +1,37 @@ # Definitions for all external bundled libraries # Suppress warnings from external libraries -if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") +if (MSVC) add_compile_options(/W0) else() add_compile_options(-w) endif() +function(target_disable_warnings target) + if (MSVC) + target_compile_options(${target} INTERFACE /W0) + else() + target_compile_options(${target} INTERFACE -w) + endif() +endfunction() + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) include(DownloadExternals) include(ExternalProject) # Boost -if (NOT USE_SYSTEM_BOOST) +if (USE_SYSTEM_BOOST) + unset(BOOST_ROOT CACHE) + unset(Boost_INCLUDE_DIR CACHE) + set(Boost_NO_SYSTEM_PATHS OFF CACHE BOOL "" FORCE) +else() message(STATUS "Including vendored Boost library") set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "") set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "") set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "") add_library(boost INTERFACE) - target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR}) + target_include_directories(boost INTERFACE ${Boost_INCLUDE_DIR}) + target_disable_warnings(boost) # Boost::serialization file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp") @@ -33,11 +46,7 @@ if (NOT USE_SYSTEM_BOOST) ${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp ) target_link_libraries(boost_iostreams PUBLIC boost) -# Add additional boost libs here; remember to ALIAS them in the root CMakeLists! -else() - unset(BOOST_ROOT CACHE) - unset(Boost_INCLUDE_DIR CACHE) - set(Boost_NO_SYSTEM_PATHS OFF CACHE BOOL "" FORCE) + # Add additional boost libs here; remember to ALIAS them in the root CMakeLists! endif() # Catch2 @@ -73,6 +82,7 @@ endif() # dds-ktx add_library(dds-ktx INTERFACE) target_include_directories(dds-ktx INTERFACE ./dds-ktx) +target_disable_warnings(dds-ktx) # fmt and Xbyak need to be added before dynarmic # libfmt @@ -137,7 +147,8 @@ endif() # MicroProfile add_library(microprofile INTERFACE) -target_include_directories(microprofile SYSTEM INTERFACE ./microprofile) +target_include_directories(microprofile INTERFACE ./microprofile) +target_disable_warnings(microprofile) if (ENABLE_MICROPROFILE) target_compile_definitions(microprofile INTERFACE MICROPROFILE_ENABLED=1) else() @@ -146,10 +157,11 @@ endif() # Nihstro add_library(nihstro-headers INTERFACE) -target_include_directories(nihstro-headers SYSTEM INTERFACE ./nihstro/include) -if (MSVC) - # TODO: For some reason MSVC still applies this warning even with /W0 for externals. - target_compile_options(nihstro-headers INTERFACE /wd4715) +target_include_directories(nihstro-headers INTERFACE ./nihstro/include) +target_disable_warnings(nihstro-headers) +if (NOT MSVC) + # TODO: For some reason MSYS2 still applied this warnin even with -w + target_compile_options(nihstro-headers INTERFACE -Wno-invalid-specialization) endif() # Open Source Archives @@ -173,7 +185,8 @@ if (USE_SYSTEM_FFMPEG_HEADERS) endif() if (NOT FOUND_FFMPEG_HEADERS) message(STATUS "Using bundled ffmpeg headers.") - target_include_directories(library-headers SYSTEM INTERFACE ./library-headers/ffmpeg/include) + target_include_directories(library-headers INTERFACE ./library-headers/ffmpeg/include) + target_disable_warnings(library-headers) endif() # SoundTouch @@ -230,13 +243,8 @@ else() ) target_link_libraries(zstd_seekable PUBLIC libzstd_static) - target_link_libraries(libzstd_static INTERFACE zstd_seekable) - - add_library(zstd ALIAS libzstd_static) - - install(TARGETS zstd_seekable - EXPORT zstdExports - ) + add_library(zstd INTERFACE) + target_link_libraries(zstd INTERFACE libzstd_static zstd_seekable) endif() # ENet @@ -294,7 +302,8 @@ if (USE_SYSTEM_JSON) # Citra uses "#include " so we have to add this manually target_include_directories(json-headers SYSTEM INTERFACE "${NLOHMANN_PREFIX}/nlohmann") else() - target_include_directories(json-headers SYSTEM INTERFACE ./json) + target_include_directories(json-headers INTERFACE ./json) + target_disable_warnings(json-headers) endif() # OpenSSL @@ -310,7 +319,8 @@ if (NOT OPENSSL_FOUND) set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "") set(OPENSSLDIR "/etc/ssl/") add_subdirectory(libressl EXCLUDE_FROM_ALL) - target_include_directories(ssl SYSTEM INTERFACE ./libressl/include) + target_include_directories(ssl INTERFACE ./libressl/include) + target_disable_warnings(ssl) target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP) get_directory_property(OPENSSL_LIBRARIES DIRECTORY libressl @@ -327,17 +337,20 @@ if(USE_SYSTEM_CPP_HTTPLIB) get_target_property(HTTP_LIBS httplib::httplib INTERFACE_LINK_LIBRARIES) if(HTTP_LIBS) message(WARNING "Shared cpp-http (${HTTP_LIBS}) not supported. Falling back to bundled...") - target_include_directories(httplib SYSTEM INTERFACE ./httplib) + target_include_directories(httplib INTERFACE ./httplib) + target_disable_warnings(httplib) else() if(CppHttp_FOUND) target_link_libraries(httplib INTERFACE httplib::httplib) else() message(STATUS "Cpp-httplib not found or not suitable version! Falling back to bundled...") - target_include_directories(httplib SYSTEM INTERFACE ./httplib) - endif() + target_include_directories(httplib INTERFACE ./httplib) + target_disable_warnings(httplib) + endif() endif() else() - target_include_directories(httplib SYSTEM INTERFACE ./httplib) + target_include_directories(httplib INTERFACE ./httplib) + target_disable_warnings(httplib) endif() target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT) target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES}) @@ -354,7 +367,8 @@ if (ENABLE_WEB_SERVICE) target_link_libraries(cpp-jwt INTERFACE cpp-jwt::cpp-jwt) else() add_library(cpp-jwt INTERFACE) - target_include_directories(cpp-jwt SYSTEM INTERFACE ./cpp-jwt/include) + target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include) + target_disable_warnings(cpp-jwt) target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON) endif() endif() @@ -402,6 +416,24 @@ endif() # Vulkan dependencies if (ENABLE_VULKAN) + # spirv-headers + if(USE_SYSTEM_SPIRV_HEADERS) + find_package(SPIRV-Headers REQUIRED) + if(TARGET SPIRV-Headers::SPIRV-Headers) + message(STATUS "Found SPIRV headers") + get_target_property(SPIRV-Headers_SOURCE_DIR SPIRV-Headers::SPIRV-Headers INTERFACE_INCLUDE_DIRECTORIES) + set(SPIRV-Headers_SOURCE_DIR "${SPIRV-Headers_SOURCE_DIR}/../") # Not sure why this is necessary + endif() + else() + set(SPIRV-Headers_SOURCE_DIR "${CMAKE_SOURCE_DIR}/externals/spirv-headers") + add_subdirectory(spirv-headers EXCLUDE_FROM_ALL) + endif() + + # spirv-tools + # TODO: Implement USE_SYSTEM_SPIRV_TOOLS -OS + set(SPIRV_SKIP_EXECUTABLES ON) + add_subdirectory(spirv-tools EXCLUDE_FROM_ALL) + # glslang if(USE_SYSTEM_GLSLANG) find_package(glslang REQUIRED) @@ -413,10 +445,6 @@ if (ENABLE_VULKAN) get_target_property(GLSLANG_PREFIX glslang::SPIRV INTERFACE_INCLUDE_DIRECTORIES) target_include_directories(SPIRV SYSTEM INTERFACE "${GLSLANG_PREFIX}/glslang") else() - set(SPIRV-Headers_SOURCE_DIR "${CMAKE_SOURCE_DIR}/externals/spirv-headers") - add_subdirectory(spirv-headers EXCLUDE_FROM_ALL) - set(SPIRV_SKIP_EXECUTABLES ON) - add_subdirectory(spirv-tools EXCLUDE_FROM_ALL) set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "") set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "") set(ENABLE_SPVREMAPPER OFF CACHE BOOL "") @@ -439,7 +467,8 @@ if (ENABLE_VULKAN) endif() else() add_library(vma INTERFACE) - target_include_directories(vma SYSTEM INTERFACE ./vma/include) + target_include_directories(vma INTERFACE ./vma/include) + target_disable_warnings(vma) endif() # vulkan-headers @@ -451,7 +480,8 @@ if (ENABLE_VULKAN) target_link_libraries(vulkan-headers INTERFACE Vulkan::Headers) endif() else() - target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include) + target_include_directories(vulkan-headers INTERFACE ./vulkan-headers/include) + target_disable_warnings(vulkan-headers) endif() # adrenotools @@ -459,3 +489,17 @@ if (ENABLE_VULKAN) add_subdirectory(libadrenotools) endif() endif() + +set(XXHASH_BUILD_XXHSUM OFF) +add_subdirectory(xxHash/cmake_unofficial EXCLUDE_FROM_ALL) +target_compile_definitions(xxhash PRIVATE XXH_FORCE_MEMORY_ACCESS=2) +if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") + target_compile_definitions(xxhash PRIVATE XXH_VECTOR=XXH_SSE2) + message(STATUS "Enabling SSE2 for xxHash") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|armv8") + target_compile_definitions(xxhash PRIVATE XXH_VECTOR=XXH_NEON) + message(STATUS "Enabling NEON for xxHash") +else() + target_compile_definitions(xxhash PRIVATE XXH_VECTOR=XXH_SCALAR) + message(STATUS "Disabling SIMD for xxHash") +endif() \ No newline at end of file diff --git a/externals/boost b/externals/boost index 3c27c785a..2c82bd787 160000 --- a/externals/boost +++ b/externals/boost @@ -1 +1 @@ -Subproject commit 3c27c785ad0f8a742af02e620dc225673f3a12d8 +Subproject commit 2c82bd787302398bcae990e3c9ab2b451284f4ca diff --git a/externals/cmake-modules/CitraHandleSystemLibs.cmake b/externals/cmake-modules/CitraHandleSystemLibs.cmake index b1bb7ccd9..00fbd7cbe 100644 --- a/externals/cmake-modules/CitraHandleSystemLibs.cmake +++ b/externals/cmake-modules/CitraHandleSystemLibs.cmake @@ -25,6 +25,7 @@ option(USE_SYSTEM_LODEPNG "Use the system lodepng (instead of the bundled one)" option(USE_SYSTEM_OPENAL "Use the system OpenAL (instead of the bundled one)" OFF) option(USE_SYSTEM_VMA "Use the system VulkanMemoryAllocator (instead of the bundled one)" OFF) option(USE_SYSTEM_VULKAN_HEADERS "Use the system Vulkan headers (instead of the bundled ones)" OFF) +option(USE_SYSTEM_SPIRV_HEADERS "Use the system SPIRV headers (instead of the bundled ones)" OFF) option(USE_SYSTEM_CATCH2 "Use the system Catch2 (instead of the bundled one)" OFF) # Qt and MoltenVK are handled separately @@ -50,6 +51,7 @@ CMAKE_DEPENDENT_OPTION(DISABLE_SYSTEM_LODEPNG "Disable system lodepng" OFF "USE_ CMAKE_DEPENDENT_OPTION(DISABLE_SYSTEM_OPENAL "Disable system OpenAL" OFF "USE_SYSTEM_LIBS" OFF) CMAKE_DEPENDENT_OPTION(DISABLE_SYSTEM_VMA "Disable system VulkanMemoryAllocator" OFF "USE_SYSTEM_LIBS" OFF) CMAKE_DEPENDENT_OPTION(DISABLE_SYSTEM_VULKAN_HEADERS "Disable system Vulkan headers" OFF "USE_SYSTEM_LIBS" OFF) +CMAKE_DEPENDENT_OPTION(DISABLE_SYSTEM_SPIRV_HEADERS "Disable system SPIRV headers" OFF "USE_SYSTEM_LIBS" OFF) CMAKE_DEPENDENT_OPTION(DISABLE_SYSTEM_CATCH2 "Disable system Catch2" OFF "USE_SYSTEM_LIBS" OFF) set(LIB_VAR_LIST @@ -75,6 +77,7 @@ set(LIB_VAR_LIST OPENAL VMA VULKAN_HEADERS + SPIRV_HEADERS CATCH2 ) diff --git a/externals/dynarmic b/externals/dynarmic index 278405bd7..526227eeb 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit 278405bd71999ed3f3c77c5f78344a06fef798b9 +Subproject commit 526227eebe1efff3fb14dbf494b9c5b44c2e9c1f diff --git a/externals/fmt b/externals/fmt index 123913715..e424e3f2e 160000 --- a/externals/fmt +++ b/externals/fmt @@ -1 +1 @@ -Subproject commit 123913715afeb8a437e6388b4473fcc4753e1c9a +Subproject commit e424e3f2e607da02742f73db84873b8084fc714c diff --git a/externals/sdl2/SDL b/externals/sdl2/SDL index 2359383fc..5d2495703 160000 --- a/externals/sdl2/SDL +++ b/externals/sdl2/SDL @@ -1 +1 @@ -Subproject commit 2359383fc187386204c3bb22de89655a494cd128 +Subproject commit 5d249570393f7a37e037abf22cd6012a4cc56a71 diff --git a/externals/teakra b/externals/teakra index 01db7cdd0..3d697a18d 160000 --- a/externals/teakra +++ b/externals/teakra @@ -1 +1 @@ -Subproject commit 01db7cdd00aabcce559a8dddce8798dabb71949b +Subproject commit 3d697a18df504f4677b65129d9ab14c7c597e3eb diff --git a/externals/xxHash b/externals/xxHash new file mode 160000 index 000000000..e626a72bc --- /dev/null +++ b/externals/xxHash @@ -0,0 +1 @@ +Subproject commit e626a72bc2321cd320e953a0ccf1584cad60f363 diff --git a/license.txt b/license.txt index f94c73f1a..7b0e5ad1b 100644 --- a/license.txt +++ b/license.txt @@ -357,3 +357,4 @@ plus.png (Default, Dark) | CC0 1.0 | Designed by BreadFish64 fro plus.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com sd_card.png | CC BY-ND 3.0 | https://icons8.com star.png | CC BY-ND 3.0 | https://icons8.com +cartridge.png | CC0 1.0 | Designed by PabloMK7 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 43ab20d46..69d17bac2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -174,6 +174,9 @@ endif() if(ENABLE_VULKAN) add_compile_definitions(ENABLE_VULKAN) endif() +if(ENABLE_DEVELOPER_OPTIONS) + add_compile_definitions(ENABLE_DEVELOPER_OPTIONS) +endif() add_subdirectory(common) add_subdirectory(core) diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 84006116f..0973a34c7 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -64,7 +64,7 @@ android { // The application ID refers to Lime3DS to allow for // the Play Store listing, which was originally set up for Lime3DS, to still be used. applicationId = "io.github.lime3ds.android" - minSdk = 28 + minSdk = 29 targetSdk = 35 versionCode = autoVersion versionName = getGitVersion() @@ -125,7 +125,7 @@ android { applicationIdSuffix = ".debug" versionNameSuffix = "-debug" signingConfig = signingConfigs.getByName("debug") - isShrinkResources = true + isShrinkResources = true // TODO: Does this actually do anything when isDebuggable is enabled? -OS isDebuggable = true isJniDebuggable = true proguardFiles( @@ -135,6 +135,22 @@ android { isDefault = true } + // Same as above, but with isDebuggable disabled. + // Primarily exists to allow development on hardened_malloc systems (e.g. GrapheneOS) without constantly tripping over years-old and seemingly harmless memory bugs. + // We should fix those bugs eventually, but for now this exists as a workaround to allow other work to be done. + register("relWithDebInfoLite") { + initWith(getByName("relWithDebInfo")) + signingConfig = signingConfigs.getByName("debug") + isDebuggable = false + installation { + enableBaselineProfile = false // Disabled by default when isDebuggable is true + } + lint { + checkReleaseBuilds = false // Ditto + // The name of this property is misleading, this doesn't actually disable linting for the `release` build. + } + } + // Signed by debug key disallowing distribution on Play Store. // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. debug { @@ -148,6 +164,18 @@ android { flavorDimensions.add("version") + productFlavors { + register("vanilla") { + isDefault = true + dimension = "version" + versionNameSuffix = "-vanilla" + } + register("googlePlay") { + dimension = "version" + versionNameSuffix = "-googleplay" + } + } + externalNativeBuild { cmake { version = "3.25.0+" @@ -186,7 +214,7 @@ dependencies { // Download Vulkan Validation Layers from the KhronosGroup GitHub. val downloadVulkanValidationLayers = tasks.register("downloadVulkanValidationLayers") { - src("https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download/vulkan-sdk-1.4.304.1/android-binaries-1.4.304.1.zip") + src("https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download/vulkan-sdk-1.4.313.0/android-binaries-1.4.313.0.zip") dest(file("${layout.buildDirectory.get().asFile.path}/tmp/Vulkan-ValidationLayers.zip")) onlyIfModified(true) } diff --git a/src/android/app/src/googlePlay/AndroidManifest.xml b/src/android/app/src/googlePlay/AndroidManifest.xml new file mode 100644 index 000000000..a95b9539c --- /dev/null +++ b/src/android/app/src/googlePlay/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index a7e3581ee..abc14939b 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml @@ -29,6 +29,8 @@ + + { + title = emulationActivity.getString(R.string.invalid_system_mode) + message = emulationActivity.getString(R.string.invalid_system_mode_message) + canContinue = false + } + CoreError.ErrorUnknown -> { title = emulationActivity.getString(R.string.fatal_error) message = emulationActivity.getString(R.string.fatal_error_message) @@ -567,6 +608,47 @@ object NativeLibrary { */ external fun logDeviceInfo() + enum class CompressStatus(val value: Int) { + SUCCESS(0), + COMPRESS_UNSUPPORTED(1), + COMPRESS_ALREADY_COMPRESSED(2), + COMPRESS_FAILED(3), + DECOMPRESS_UNSUPPORTED(4), + DECOMPRESS_NOT_COMPRESSED(5), + DECOMPRESS_FAILED(6), + INSTALLED_APPLICATION(7); + + companion object { + fun fromValue(value: Int): CompressStatus = + CompressStatus.entries.first { it.value == value } + } + } + + // Compression / Decompression + private external fun compressFileNative(inputPath: String?, outputPath: String): Int + + fun compressFile(inputPath: String?, outputPath: String): CompressStatus { + return CompressStatus.fromValue( + compressFileNative(inputPath, outputPath) + ) + } + + private external fun decompressFileNative(inputPath: String?, outputPath: String): Int + + fun decompressFile(inputPath: String?, outputPath: String): CompressStatus { + return CompressStatus.fromValue( + decompressFileNative(inputPath, outputPath) + ) + } + + external fun getRecommendedExtension(inputPath: String?, shouldCompress: Boolean): String + + @Keep + @JvmStatic + fun onCompressProgress(total: Long, current: Long) { + CompressProgressDialogViewModel.update(total, current) + } + @Keep @JvmStatic fun createFile(directory: String, filename: String): Boolean = @@ -607,6 +689,38 @@ object NativeLibrary { FileUtil.getFilesName(path) } + @Keep + @JvmStatic + fun getUserDirectory(uriOverride: Uri? = null): String { + BuildUtil.assertNotGooglePlay() + + val preferences: SharedPreferences = + PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext) + + val dirSep = "/" + val udUri = uriOverride ?: + preferences.getString("CITRA_DIRECTORY", "")!!.toUri() + val udPathSegment = udUri.lastPathSegment!! + val udVirtualPath = udPathSegment.substringAfter(":") + + if (udPathSegment.startsWith("primary:")) { // User directory is located in primary storage + val primaryStoragePath = Environment.getExternalStorageDirectory().absolutePath + return primaryStoragePath + dirSep + udVirtualPath + dirSep + } else { // User directory probably located on a removable storage device + val storageIdString = udPathSegment.substringBefore(":") + val udRemovablePath = RemovableStorageHelper.getRemovableStoragePath(storageIdString) + + if (udRemovablePath == null) { + android.util.Log.e("NativeLibrary", + "Unknown mount location for storage device '$storageIdString' (URI: $udUri)" + ) + return "" + } + return udRemovablePath + dirSep + udVirtualPath + dirSep + } + + } + @Keep @JvmStatic fun getSize(path: String): Long = @@ -616,6 +730,10 @@ object NativeLibrary { FileUtil.getFileSize(path) } + @Keep + @JvmStatic + fun getBuildFlavor(): String = BuildConfig.FLAVOR + @Keep @JvmStatic fun fileExists(path: String): Boolean = @@ -667,6 +785,24 @@ object NativeLibrary { FileUtil.renameFile(path, destinationFilename) } + @Keep + @JvmStatic + fun updateDocumentLocation(sourcePath: String, destinationPath: String): Boolean = + CitraApplication.documentsTree.updateDocumentLocation(sourcePath, destinationPath) + + @Keep + @JvmStatic + fun moveFile(filename: String, sourceDirPath: String, destinationDirPath: String): Boolean = + if (FileUtil.isNativePath(sourceDirPath)) { + try { + CitraApplication.documentsTree.moveFile(filename, sourceDirPath, destinationDirPath) + } catch (e: Exception) { + false + } + } else { + FileUtil.moveFile(filename, sourceDirPath, destinationDirPath) + } + @Keep @JvmStatic fun deleteDocument(path: String): Boolean = @@ -680,6 +816,7 @@ object NativeLibrary { ErrorSystemFiles, ErrorSavestate, ErrorArticDisconnected, + ErrorN3DSApplication, ErrorUnknown } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt index 9f59ea2c4..ca92b308d 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt @@ -10,6 +10,7 @@ import android.content.Intent import android.content.SharedPreferences import android.content.pm.PackageManager import android.net.Uri +import android.os.Build import android.os.Bundle import android.view.InputDevice import android.view.KeyEvent @@ -33,6 +34,7 @@ import org.citra.citra_emu.camera.StillImageCameraHelper.OnFilePickerResult import org.citra.citra_emu.contracts.OpenFileResultContract import org.citra.citra_emu.databinding.ActivityEmulationBinding import org.citra.citra_emu.display.ScreenAdjustmentUtil +import org.citra.citra_emu.display.SecondaryDisplay import org.citra.citra_emu.features.hotkeys.HotkeyUtility import org.citra.citra_emu.features.settings.model.BooleanSetting import org.citra.citra_emu.features.settings.model.IntSetting @@ -46,6 +48,7 @@ import org.citra.citra_emu.utils.FileBrowserHelper import org.citra.citra_emu.utils.EmulationLifecycleUtil import org.citra.citra_emu.utils.EmulationMenuSettings import org.citra.citra_emu.utils.Log +import org.citra.citra_emu.utils.RefreshRateUtil import org.citra.citra_emu.utils.ThemeUtil import org.citra.citra_emu.viewmodel.EmulationViewModel @@ -59,6 +62,15 @@ class EmulationActivity : AppCompatActivity() { private lateinit var binding: ActivityEmulationBinding private lateinit var screenAdjustmentUtil: ScreenAdjustmentUtil private lateinit var hotkeyUtility: HotkeyUtility + private lateinit var secondaryDisplay: SecondaryDisplay + + private val onShutdown = Runnable { + if (intent.getBooleanExtra("launched_from_shortcut", false)) { + finishAffinity() + } else { + this.finish() + } + } private val emulationFragment: EmulationFragment get() { @@ -72,11 +84,13 @@ class EmulationActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { requestWindowFeature(Window.FEATURE_NO_TITLE) + RefreshRateUtil.enforceRefreshRate(this, sixtyHz = true) + ThemeUtil.setTheme(this) - settingsViewModel.settings.loadSettings() - super.onCreate(savedInstanceState) + secondaryDisplay = SecondaryDisplay(this) + secondaryDisplay.updateDisplay() binding = ActivityEmulationBinding.inflate(layoutInflater) screenAdjustmentUtil = ScreenAdjustmentUtil(this, windowManager, settingsViewModel.settings) @@ -99,13 +113,7 @@ class EmulationActivity : AppCompatActivity() { windowManager.defaultDisplay.rotation ) - EmulationLifecycleUtil.addShutdownHook(hook = { - if (intent.getBooleanExtra("launched_from_shortcut", false)) { - finishAffinity() - } else { - this.finish() - } - }) + EmulationLifecycleUtil.addShutdownHook(onShutdown) isEmulationRunning = true instance = this @@ -136,6 +144,11 @@ class EmulationActivity : AppCompatActivity() { applyOrientationSettings() // Check for orientation settings changes on runtime } + override fun onStop() { + secondaryDisplay.releasePresentation() + super.onStop() + } + override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) enableFullscreenImmersive() @@ -143,6 +156,7 @@ class EmulationActivity : AppCompatActivity() { public override fun onRestart() { super.onRestart() + secondaryDisplay.updateDisplay() NativeLibrary.reloadCameraDevices() } @@ -157,10 +171,13 @@ class EmulationActivity : AppCompatActivity() { } override fun onDestroy() { - EmulationLifecycleUtil.clear() + EmulationLifecycleUtil.removeHook(onShutdown) NativeLibrary.playTimeManagerStop() isEmulationRunning = false instance = null + secondaryDisplay.releasePresentation() + secondaryDisplay.releaseVD() + super.onDestroy() } @@ -325,6 +342,7 @@ class EmulationActivity : AppCompatActivity() { preferences.getInt(InputBindingSetting.getInputAxisButtonKey(axis), -1) val guestOrientation = preferences.getInt(InputBindingSetting.getInputAxisOrientationKey(axis), -1) + val inverted = preferences.getBoolean(InputBindingSetting.getInputAxisInvertedKey(axis),false); if (nextMapping == -1 || guestOrientation == -1) { // Axis is unmapped continue @@ -333,6 +351,8 @@ class EmulationActivity : AppCompatActivity() { // Skip joystick wobble value = 0f } + if (inverted) value = -value; + when (nextMapping) { NativeLibrary.ButtonType.STICK_LEFT -> { axisValuesCirclePad[guestOrientation] = value diff --git a/src/android/app/src/main/java/org/citra/citra_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/citra/citra_emu/adapters/GameAdapter.kt index d03ff2936..dae538d73 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/adapters/GameAdapter.kt @@ -13,6 +13,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.content.Context +import android.content.SharedPreferences import android.widget.TextView import android.widget.ImageView import android.widget.Toast @@ -57,13 +58,21 @@ import org.citra.citra_emu.utils.FileUtil import org.citra.citra_emu.utils.GameIconUtils import org.citra.citra_emu.viewmodel.GamesViewModel -class GameAdapter(private val activity: AppCompatActivity, private val inflater: LayoutInflater, private val openImageLauncher: ActivityResultLauncher?) : +class GameAdapter( + private val activity: AppCompatActivity, + private val inflater: LayoutInflater, + private val openImageLauncher: ActivityResultLauncher?, + private val onRequestCompressOrDecompress: ((inputPath: String, suggestedName: String, shouldCompress: Boolean) -> Unit)? = null +) : ListAdapter(AsyncDifferConfig.Builder(DiffCallback()).build()), View.OnClickListener, View.OnLongClickListener { private var lastClickTime = 0L private var imagePath: String? = null private var dialogShortcutBinding: DialogShortcutBinding? = null + private val preferences: SharedPreferences + get() = PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext) + fun handleShortcutImageResult(uri: Uri?) { val path = uri?.toString() if (path != null) { @@ -191,6 +200,11 @@ class GameAdapter(private val activity: AppCompatActivity, private val inflater: binding.textGameTitle.text = game.title binding.textCompany.text = game.company binding.textGameRegion.text = game.regions + binding.imageCartridge.visibility = if (preferences.getString("insertedCartridge", "") != game.path) { + View.GONE + } else { + View.VISIBLE + } val backgroundColorId = if ( @@ -340,12 +354,29 @@ class GameAdapter(private val activity: AppCompatActivity, private val inflater: val bottomSheetDialog = BottomSheetDialog(context) bottomSheetDialog.setContentView(bottomSheetView) + val insertable = game.isInsertable + val inserted = insertable && (preferences.getString("insertedCartridge", "") == game.path) + bottomSheetView.findViewById(R.id.about_game_title).text = game.title bottomSheetView.findViewById(R.id.about_game_company).text = game.company bottomSheetView.findViewById(R.id.about_game_region).text = game.regions bottomSheetView.findViewById(R.id.about_game_id).text = context.getString(R.string.game_context_id) + " " + String.format("%016X", game.titleId) bottomSheetView.findViewById(R.id.about_game_filename).text = context.getString(R.string.game_context_file) + " " + game.filename bottomSheetView.findViewById(R.id.about_game_filetype).text = context.getString(R.string.game_context_type) + " " + game.fileType + + val insertButton = bottomSheetView.findViewById(R.id.insert_cartridge_button) + insertButton.text = if (inserted) { context.getString(R.string.game_context_eject) } else { context.getString(R.string.game_context_insert) } + insertButton.visibility = if (insertable) View.VISIBLE else View.GONE + insertButton.setOnClickListener { + if (inserted) { + preferences.edit().putString("insertedCartridge", "").apply() + } else { + preferences.edit().putString("insertedCartridge", game.path).apply() + } + bottomSheetDialog.dismiss() + notifyItemRangeChanged(0, currentList.size) + } + GameIconUtils.loadGameIcon(activity, game, bottomSheetView.findViewById(R.id.game_icon)) bottomSheetView.findViewById(R.id.about_game_play).setOnClickListener { @@ -441,6 +472,27 @@ class GameAdapter(private val activity: AppCompatActivity, private val inflater: bottomSheetDialog.dismiss() } + val compressDecompressButton = bottomSheetView.findViewById(R.id.compress_decompress) + if (game.isInstalled) { + compressDecompressButton.setOnClickListener { + Toast.makeText( + context, + context.getString(R.string.compress_decompress_installed_app), + Toast.LENGTH_LONG + ).show() + } + compressDecompressButton.alpha = 0.38f + } else { + compressDecompressButton.setOnClickListener { + val shouldCompress = !game.isCompressed + val recommendedExt = NativeLibrary.getRecommendedExtension(holder.game.path, shouldCompress) + val baseName = holder.game.filename.substringBeforeLast('.') + onRequestCompressOrDecompress?.invoke(holder.game.path, "$baseName.$recommendedExt", shouldCompress) + bottomSheetDialog.dismiss() + } + } + compressDecompressButton.text = context.getString(if (!game.isCompressed) R.string.compress else R.string.decompress) + bottomSheetView.findViewById(R.id.menu_button_open).setOnClickListener { showOpenContextMenu(it, game) } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/display/ScreenLayout.kt b/src/android/app/src/main/java/org/citra/citra_emu/display/ScreenLayout.kt index ea82fc07e..c46dcadd8 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/display/ScreenLayout.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/display/ScreenLayout.kt @@ -49,4 +49,51 @@ enum class PortraitScreenLayout(val int: Int) { return entries.firstOrNull { it.int == int } ?: TOP_FULL_WIDTH } } +} + +enum class SecondaryDisplayLayout(val int: Int) { + // These must match what is defined in src/common/settings.h + NONE(0), + TOP_SCREEN(1), + BOTTOM_SCREEN(2), + SIDE_BY_SIDE(3); + + companion object { + fun from(int: Int): SecondaryDisplayLayout { + return entries.firstOrNull { it.int == int } ?: NONE + } + } +} + +enum class StereoWhichDisplay(val int: Int) { + // These must match what is defined in src/common/settings.h + + NONE(0), // equivalent to StereoRenderOption = Off + BOTH(1), + PRIMARY_ONLY(2), + SECONDARY_ONLY(3); + + companion object { + fun from(int: Int): StereoWhichDisplay { + return entries.firstOrNull { it.int == int } ?: NONE + } + } +} + +enum class StereoMode(val int: Int) { + // These must match what is defined in src/common/settings.h + + OFF(0), + SIDE_BY_SIDE(1), + SIDE_BY_SIDE_FULL(2), + ANAGLYPH(3), + INTERLACED(4), + REVERSE_INTERLACED (5), + CARDBOARD_VR (6); + + companion object { + fun from(int: Int): StereoMode { + return entries.firstOrNull { it.int == int } ?: OFF + } + } } \ No newline at end of file diff --git a/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt b/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt new file mode 100644 index 000000000..d9c75f690 --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt @@ -0,0 +1,182 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.display + +import android.app.Presentation +import android.content.Context +import android.graphics.SurfaceTexture +import android.hardware.display.DisplayManager +import android.hardware.display.VirtualDisplay +import android.os.Bundle +import android.view.Display +import android.view.MotionEvent +import android.view.Surface +import android.view.SurfaceHolder +import android.view.SurfaceView +import android.view.WindowManager +import org.citra.citra_emu.features.settings.model.IntSetting +import org.citra.citra_emu.display.SecondaryDisplayLayout +import org.citra.citra_emu.NativeLibrary + +class SecondaryDisplay(val context: Context) : DisplayManager.DisplayListener { + private var pres: SecondaryDisplayPresentation? = null + private val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + private val vd: VirtualDisplay + + init { + vd = displayManager.createVirtualDisplay( + "HiddenDisplay", + 1920, + 1080, + 320, + null, + DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION + ) + displayManager.registerDisplayListener(this, null) + } + + fun updateSurface() { + NativeLibrary.secondarySurfaceChanged(pres!!.getSurfaceHolder().surface) + } + + fun destroySurface() { + NativeLibrary.secondarySurfaceDestroyed() + } + + private fun getExternalDisplay(context: Context): Display? { + val dm = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + val currentDisplayId = context.display.displayId + val displays = dm.displays + val presDisplays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + val extDisplays = displays.filter { + val isPresentable = presDisplays.any { pd -> pd.displayId == it.displayId } + val isNotDefaultOrPresentable = it.displayId != Display.DEFAULT_DISPLAY || isPresentable + isNotDefaultOrPresentable && + it.displayId != currentDisplayId && + it.name != "HiddenDisplay" && + it.state != Display.STATE_OFF && + it.isValid + } + // if there is a display called Built-In Display or Built-In Screen, prioritize the OTHER screen + val selected = extDisplays.firstOrNull { ! it.name.contains("Built",true) } + ?: extDisplays.firstOrNull() + return selected + } + + fun updateDisplay() { + // decide if we are going to the external display or the internal one + var display = getExternalDisplay(context) + if (display == null || + IntSetting.SECONDARY_DISPLAY_LAYOUT.int == SecondaryDisplayLayout.NONE.int) { + display = vd.display + } + + // if our presentation is already on the right display, ignore + if (pres?.display == display) return + + // otherwise, make a new presentation + releasePresentation() + pres = SecondaryDisplayPresentation(context, display!!, this) + pres?.show() + } + + fun releasePresentation() { + pres?.dismiss() + pres = null + } + + fun releaseVD() { + displayManager.unregisterDisplayListener(this) + vd.release() + } + + override fun onDisplayAdded(displayId: Int) { + updateDisplay() + } + + override fun onDisplayRemoved(displayId: Int) { + updateDisplay() + } + override fun onDisplayChanged(displayId: Int) { + updateDisplay() + } +} +class SecondaryDisplayPresentation( + context: Context, display: Display, val parent: SecondaryDisplay +) : Presentation(context, display) { + private lateinit var surfaceView: SurfaceView + private var touchscreenPointerId = -1 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window?.setFlags( + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + ) + + // Initialize SurfaceView + surfaceView = SurfaceView(context) + surfaceView.holder.addCallback(object : SurfaceHolder.Callback { + override fun surfaceCreated(holder: SurfaceHolder) { + + } + + override fun surfaceChanged( + holder: SurfaceHolder, format: Int, width: Int, height: Int + ) { + parent.updateSurface() + } + + override fun surfaceDestroyed(holder: SurfaceHolder) { + parent.destroySurface() + } + }) + + this.surfaceView.setOnTouchListener { _, event -> + + val pointerIndex = event.actionIndex + val pointerId = event.getPointerId(pointerIndex) + when (event.actionMasked) { + MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> { + if (touchscreenPointerId == -1) { + touchscreenPointerId = pointerId + NativeLibrary.onSecondaryTouchEvent( + event.getX(pointerIndex), + event.getY(pointerIndex), + true + ) + } + } + + MotionEvent.ACTION_MOVE -> { + val index = event.findPointerIndex(touchscreenPointerId) + if (index != -1) { + NativeLibrary.onSecondaryTouchMoved( + event.getX(index), + event.getY(index) + ) + } + } + + MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_CANCEL -> { + if (pointerId == touchscreenPointerId) { + NativeLibrary.onSecondaryTouchEvent(0f, 0f, false) + touchscreenPointerId = -1 + } + } + } + true + } + + setContentView(surfaceView) // Set SurfaceView as content + } + + // Publicly accessible method to get the SurfaceHolder + fun getSurfaceHolder(): SurfaceHolder { + return surfaceView.holder + } +} diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.kt index d2131d470..62032c620 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.kt @@ -19,13 +19,15 @@ enum class BooleanSetting( INSTANT_DEBUG_LOG("instant_debug_log", Settings.SECTION_DEBUG, false), ENABLE_RPC_SERVER("enable_rpc_server", Settings.SECTION_DEBUG, false), CUSTOM_LAYOUT("custom_layout",Settings.SECTION_LAYOUT,false), - OVERLAY_SHOW_FPS("overlay_show_fps", Settings.SECTION_LAYOUT, true), - OVERLAY_SHOW_FRAMETIME("overlay_show_frame_time", Settings.SECTION_LAYOUT, false), - OVERLAY_SHOW_SPEED("overlay_show_speed", Settings.SECTION_LAYOUT, false), - OVERLAY_SHOW_APP_RAM_USAGE("overlay_show_app_ram_usage", Settings.SECTION_LAYOUT, false), - OVERLAY_SHOW_AVAILABLE_RAM("overlay_show_available_ram", Settings.SECTION_LAYOUT, false), - OVERLAY_SHOW_BATTERY_TEMP("overlay_show_battery_temp", Settings.SECTION_LAYOUT, false), - OVERLAY_BACKGROUND("overlay_background", Settings.SECTION_LAYOUT, false), + SWAP_EYES_3D("swap_eyes_3d",Settings.SECTION_RENDERER,false), + PERF_OVERLAY_ENABLE("performance_overlay_enable", Settings.SECTION_LAYOUT, false), + PERF_OVERLAY_SHOW_FPS("performance_overlay_show_fps", Settings.SECTION_LAYOUT, true), + PERF_OVERLAY_SHOW_FRAMETIME("performance_overlay_show_frame_time", Settings.SECTION_LAYOUT, false), + PERF_OVERLAY_SHOW_SPEED("performance_overlay_show_speed", Settings.SECTION_LAYOUT, false), + PERF_OVERLAY_SHOW_APP_RAM_USAGE("performance_overlay_show_app_ram_usage", Settings.SECTION_LAYOUT, false), + PERF_OVERLAY_SHOW_AVAILABLE_RAM("performance_overlay_show_available_ram", Settings.SECTION_LAYOUT, false), + PERF_OVERLAY_SHOW_BATTERY_TEMP("performance_overlay_show_battery_temp", Settings.SECTION_LAYOUT, false), + PERF_OVERLAY_BACKGROUND("performance_overlay_background", Settings.SECTION_LAYOUT, false), DELAY_START_LLE_MODULES("delay_start_for_lle_modules", Settings.SECTION_DEBUG, true), DETERMINISTIC_ASYNC_OPERATIONS("deterministic_async_operations", Settings.SECTION_DEBUG, false), REQUIRED_ONLINE_LLE_MODULES("enable_required_online_lle_modules", Settings.SECTION_SYSTEM, false), @@ -43,16 +45,17 @@ enum class BooleanSetting( CPU_JIT("use_cpu_jit", Settings.SECTION_CORE, true), HW_SHADER("use_hw_shader", Settings.SECTION_RENDERER, true), SHADER_JIT("use_shader_jit", Settings.SECTION_RENDERER, true), - VSYNC("use_vsync_new", Settings.SECTION_RENDERER, true), + VSYNC("use_vsync", Settings.SECTION_RENDERER, false), USE_FRAME_LIMIT("use_frame_limit", Settings.SECTION_RENDERER, true), DEBUG_RENDERER("renderer_debug", Settings.SECTION_DEBUG, false), DISABLE_RIGHT_EYE_RENDER("disable_right_eye_render", Settings.SECTION_RENDERER, false), USE_ARTIC_BASE_CONTROLLER("use_artic_base_controller", Settings.SECTION_CONTROLS, false), UPRIGHT_SCREEN("upright_screen", Settings.SECTION_LAYOUT, false), COMPRESS_INSTALLED_CIA_CONTENT("compress_cia_installs", Settings.SECTION_STORAGE, false), + ANDROID_HIDE_IMAGES("android_hide_images", Settings.SECTION_CORE, false), + APPLY_REGION_FREE_PATCH("apply_region_free_patch", Settings.SECTION_SYSTEM, true), ENABLE_COMBO_KEY("enable_combo_key", Settings.SECTION_CONTROLS, true); - override var boolean: Boolean = defaultValue override val valueAsString: String @@ -85,6 +88,9 @@ enum class BooleanSetting( SHADERS_ACCURATE_MUL, USE_ARTIC_BASE_CONTROLLER, COMPRESS_INSTALLED_CIA_CONTENT, + ANDROID_HIDE_IMAGES, + PERF_OVERLAY_ENABLE, // Works in overlay options, but not from the settings menu + APPLY_REGION_FREE_PATCH ) fun from(key: String): BooleanSetting? = diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/FloatSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/FloatSetting.kt index 94ddb295d..69bc16ca7 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/FloatSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/FloatSetting.kt @@ -1,4 +1,4 @@ -// Copyright Citra Emulator Project / Lime3DS Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -10,6 +10,10 @@ enum class FloatSetting( override val defaultValue: Float ) : AbstractFloatSetting { LARGE_SCREEN_PROPORTION("large_screen_proportion",Settings.SECTION_LAYOUT,2.25f), + SECOND_SCREEN_OPACITY("custom_second_layer_opacity", Settings.SECTION_RENDERER, 100f), + BACKGROUND_RED("bg_red", Settings.SECTION_RENDERER, 0f), + BACKGROUND_BLUE("bg_blue", Settings.SECTION_RENDERER, 0f), + BACKGROUND_GREEN("bg_green", Settings.SECTION_RENDERER, 0f), EMPTY_SETTING("", "", 0.0f); override var float: Float = defaultValue diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt index bc8ede6ee..e26bcd6c6 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.kt @@ -17,7 +17,7 @@ enum class IntSetting( CAMERA_OUTER_RIGHT_FLIP("camera_outer_right_flip", Settings.SECTION_CAMERA, 0), GRAPHICS_API("graphics_api", Settings.SECTION_RENDERER, 1), RESOLUTION_FACTOR("resolution_factor", Settings.SECTION_RENDERER, 1), - STEREOSCOPIC_3D_MODE("render_3d", Settings.SECTION_RENDERER, 0), + STEREOSCOPIC_3D_MODE("render_3d", Settings.SECTION_RENDERER, 2), STEREOSCOPIC_3D_DEPTH("factor_3d", Settings.SECTION_RENDERER, 0), STEPS_PER_HOUR("steps_per_hour", Settings.SECTION_SYSTEM, 0), CARDBOARD_SCREEN_SIZE("cardboard_screen_size", Settings.SECTION_LAYOUT, 85), @@ -35,6 +35,7 @@ enum class IntSetting( LANDSCAPE_BOTTOM_HEIGHT("custom_bottom_height",Settings.SECTION_LAYOUT,480), SCREEN_GAP("screen_gap",Settings.SECTION_LAYOUT,0), PORTRAIT_SCREEN_LAYOUT("portrait_layout_option",Settings.SECTION_LAYOUT,0), + SECONDARY_DISPLAY_LAYOUT("secondary_display_layout",Settings.SECTION_LAYOUT,0), PORTRAIT_TOP_X("custom_portrait_top_x",Settings.SECTION_LAYOUT,0), PORTRAIT_TOP_Y("custom_portrait_top_y",Settings.SECTION_LAYOUT,0), PORTRAIT_TOP_WIDTH("custom_portrait_top_width",Settings.SECTION_LAYOUT,800), @@ -52,6 +53,7 @@ enum class IntSetting( ORIENTATION_OPTION("screen_orientation", Settings.SECTION_LAYOUT, 2), TURBO_LIMIT("turbo_limit", Settings.SECTION_CORE, 200), PERFORMANCE_OVERLAY_POSITION("performance_overlay_position", Settings.SECTION_LAYOUT, 0), + RENDER_3D_WHICH_DISPLAY("render_3d_which_display",Settings.SECTION_RENDERER,0), ASPECT_RATIO("aspect_ratio", Settings.SECTION_LAYOUT, 0); override var int: Int = defaultValue diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt index c10b12d7c..421852ff8 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt @@ -16,6 +16,7 @@ import org.citra.citra_emu.NativeLibrary import org.citra.citra_emu.R import org.citra.citra_emu.features.hotkeys.Hotkey import org.citra.citra_emu.features.settings.model.AbstractSetting +import org.citra.citra_emu.features.settings.model.AbstractStringSetting import org.citra.citra_emu.features.settings.model.Settings class InputBindingSetting( @@ -162,12 +163,14 @@ class InputBindingSetting( fun removeOldMapping() { // Try remove all possible keys we wrote for this setting val oldKey = preferences.getString(reverseKey, "") + (setting as AbstractStringSetting).string = "" if (oldKey != "") { preferences.edit() .remove(abstractSetting.key) // Used for ui text .remove(oldKey) // Used for button mapping .remove(oldKey + "_GuestOrientation") // Used for axis orientation .remove(oldKey + "_GuestButton") // Used for axis button + .remove(oldKey + "_Inverted") // used for axis inversion .apply() } } @@ -201,7 +204,7 @@ class InputBindingSetting( /** * Helper function to write a gamepad axis mapping for the setting. */ - private fun writeAxisMapping(axis: Int, value: Int) { + private fun writeAxisMapping(axis: Int, value: Int, inverted: Boolean) { // Cleanup old mapping removeOldMapping() @@ -209,6 +212,7 @@ class InputBindingSetting( preferences.edit() .putInt(getInputAxisOrientationKey(axis), if (isHorizontalOrientation()) 0 else 1) .putInt(getInputAxisButtonKey(axis), value) + .putBoolean(getInputAxisInvertedKey(axis),inverted) // Write next reverse mapping for future cleanup .putString(reverseKey, getInputAxisKey(axis)) .apply() @@ -236,7 +240,7 @@ class InputBindingSetting( * * @param device InputDevice from which the input event originated. * @param motionRange MotionRange of the movement - * @param axisDir Either '-' or '+' (currently unused) + * @param axisDir Either '-' or '+' */ fun onMotionInput(device: InputDevice, motionRange: MotionRange, axisDir: Char) { if (!isAxisMappingSupported()) { @@ -252,8 +256,10 @@ class InputBindingSetting( } else { buttonCode } - writeAxisMapping(motionRange.axis, button) - val uiString = "${device.name}: Axis ${motionRange.axis}" + // use UP (-) to map vertical, but use RIGHT (+) to map horizontal + val inverted = if (isHorizontalOrientation()) axisDir == '-' else axisDir == '+' + writeAxisMapping(motionRange.axis, button, inverted) + val uiString = "${device.name}: Axis ${motionRange.axis}" + axisDir value = uiString } @@ -309,6 +315,11 @@ class InputBindingSetting( */ fun getInputAxisButtonKey(axis: Int): String = "${getInputAxisKey(axis)}_GuestButton" + /** + * Helper function to get the settings key for an whether a gamepad axis is inverted. + */ + fun getInputAxisInvertedKey(axis: Int): String = "${getInputAxisKey(axis)}_Inverted" + /** * Helper function to get the settings key for an gamepad axis orientation. */ diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.kt index 79406594e..46ed42905 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.kt @@ -1,4 +1,4 @@ -// Copyright Citra Emulator Project / Lime3DS Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -10,7 +10,6 @@ import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.FloatSetting import org.citra.citra_emu.features.settings.model.ScaledFloatSetting import org.citra.citra_emu.utils.Log -import kotlin.math.roundToInt class SliderSetting( setting: AbstractSetting?, @@ -27,7 +26,8 @@ class SliderSetting( val selectedFloat: Float get() { val setting = setting ?: return defaultValue!!.toFloat() - return when (setting) { + + val ret = when (setting) { is AbstractIntSetting -> setting.int.toFloat() is FloatSetting -> setting.float is ScaledFloatSetting -> setting.float @@ -36,8 +36,8 @@ class SliderSetting( -1f } } + return ret.coerceIn(min.toFloat(), max.toFloat()) } - /** * Write a value to the backing int. If that int was previously null, * initializes a new one and returns it, so it can be added to the Hashmap. diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivity.kt index 070a8f487..064fa700e 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivity.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivity.kt @@ -7,6 +7,7 @@ package org.citra.citra_emu.features.settings.ui import android.content.Context import android.content.Intent import android.net.Uri +import android.os.Build import android.os.Bundle import android.view.View import android.view.ViewGroup.MarginLayoutParams @@ -37,6 +38,7 @@ import org.citra.citra_emu.features.settings.utils.SettingsFile import org.citra.citra_emu.utils.SystemSaveGame import org.citra.citra_emu.utils.DirectoryInitialization import org.citra.citra_emu.utils.InsetsHelper +import org.citra.citra_emu.utils.RefreshRateUtil import org.citra.citra_emu.utils.ThemeUtil class SettingsActivity : AppCompatActivity(), SettingsActivityView { @@ -49,6 +51,8 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView { override val settings: Settings get() = settingsViewModel.settings override fun onCreate(savedInstanceState: Bundle?) { + RefreshRateUtil.enforceRefreshRate(this) + ThemeUtil.setTheme(this) super.onCreate(savedInstanceState) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivityPresenter.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivityPresenter.kt index 06fcb19e4..33aea46f9 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivityPresenter.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivityPresenter.kt @@ -4,14 +4,19 @@ package org.citra.citra_emu.features.settings.ui +import android.net.Uri import android.os.Bundle import android.text.TextUtils +import androidx.documentfile.provider.DocumentFile +import org.citra.citra_emu.CitraApplication import org.citra.citra_emu.NativeLibrary -import org.citra.citra_emu.features.settings.model.IntSetting +import org.citra.citra_emu.features.settings.model.BooleanSetting import org.citra.citra_emu.features.settings.model.Settings import org.citra.citra_emu.utils.SystemSaveGame import org.citra.citra_emu.utils.DirectoryInitialization +import org.citra.citra_emu.utils.FileUtil import org.citra.citra_emu.utils.Log +import org.citra.citra_emu.utils.PermissionsHandler import org.citra.citra_emu.utils.TurboHelper class SettingsActivityPresenter(private val activityView: SettingsActivityView) { @@ -60,6 +65,32 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView) loadSettingsUI() } + private fun updateAndroidImageVisibility() { + val dataDirTreeUri: Uri + val dataDirDocument: DocumentFile + val nomediaFileDocument: DocumentFile? + val nomediaFileExists: Boolean + try { + dataDirTreeUri = PermissionsHandler.citraDirectory + dataDirDocument = DocumentFile.fromTreeUri(CitraApplication.appContext, dataDirTreeUri)!! + nomediaFileDocument = dataDirDocument.findFile(".nomedia") + nomediaFileExists = (nomediaFileDocument != null) + } catch (e: Exception) { + Log.error("[SettingsActivity]: Error occurred while trying to find .nomedia, error: " + e.message) + return + } + + if (BooleanSetting.ANDROID_HIDE_IMAGES.boolean) { + if (!nomediaFileExists) { + Log.info("[SettingsActivity]: Attempting to create .nomedia in user data directory") + FileUtil.createFile(dataDirTreeUri.toString(), ".nomedia") + } + } else if (nomediaFileExists) { + Log.info("[SettingsActivity]: Attempting to delete .nomedia in user data directory") + nomediaFileDocument!!.delete() + } + } + fun onStop(finishing: Boolean) { if (finishing && shouldSave) { Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...") @@ -67,6 +98,7 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView) //added to ensure that layout changes take effect as soon as settings window closes NativeLibrary.reloadSettings() NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode) + updateAndroidImageVisibility() TurboHelper.reloadTurbo(false) // TODO: Can this go somewhere else? -OS } NativeLibrary.reloadSettings() diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsAdapter.kt index 7e20e9e7b..13476ae24 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsAdapter.kt @@ -566,6 +566,21 @@ class SettingsAdapter( return true } + fun onInputBindingLongClick(setting: InputBindingSetting, position: Int): Boolean { + MaterialAlertDialogBuilder(context) + .setMessage(R.string.reset_setting_confirmation) + .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> + setting.removeOldMapping() + notifyItemChanged(position) + fragmentView.onSettingChanged() + fragmentView.loadSettingsList() + } + .setNegativeButton(android.R.string.cancel, null) + .show() + + return true + } + fun onClickDisabledSetting(isRuntimeDisabled: Boolean) { val titleId = if (isRuntimeDisabled) R.string.setting_not_editable diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt index 3bc96d01a..6814b9013 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -14,11 +14,11 @@ import android.os.Build import android.text.TextUtils import androidx.preference.PreferenceManager import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlin.math.min import org.citra.citra_emu.CitraApplication import org.citra.citra_emu.R -import org.citra.citra_emu.display.PortraitScreenLayout import org.citra.citra_emu.display.ScreenLayout +import org.citra.citra_emu.display.StereoMode +import org.citra.citra_emu.display.StereoWhichDisplay import org.citra.citra_emu.features.settings.model.AbstractBooleanSetting import org.citra.citra_emu.features.settings.model.AbstractIntSetting import org.citra.citra_emu.features.settings.model.AbstractMultiStringSetting @@ -49,7 +49,6 @@ import org.citra.citra_emu.utils.BirthdayMonth import org.citra.citra_emu.utils.Log import org.citra.citra_emu.utils.SystemSaveGame import org.citra.citra_emu.utils.ThemeUtil -import org.citra.citra_emu.utils.EmulationMenuSettings class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) { private var menuTag: String? = null @@ -116,20 +115,24 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) } /** Returns the portrait mode width */ - private fun getWidth(): Int { - val dm = Resources.getSystem().displayMetrics; - return if (dm.widthPixels < dm.heightPixels) - dm.widthPixels - else - dm.heightPixels + private fun getDimensions(): IntArray { + val dm = Resources.getSystem().displayMetrics + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val wm = settingsActivity.windowManager.maximumWindowMetrics + val height = wm.bounds.height().coerceAtLeast(dm.heightPixels) + val width = wm.bounds.width().coerceAtLeast(dm.widthPixels) + intArrayOf(width, height) + } else { + intArrayOf(dm.widthPixels, dm.heightPixels) + } } - private fun getHeight(): Int { - val dm = Resources.getSystem().displayMetrics; - return if (dm.widthPixels < dm.heightPixels) - dm.heightPixels - else - dm.widthPixels + private fun getSmallerDimension(): Int { + return getDimensions().min() + } + + private fun getLargerDimension(): Int { + return getDimensions().max() } private fun addConfigSettings(sl: ArrayList) { @@ -253,6 +256,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) IntSetting.TURBO_LIMIT.defaultValue.toFloat() ) ) + add( + SwitchSetting( + BooleanSetting.ANDROID_HIDE_IMAGES, + R.string.android_hide_images, + R.string.android_hide_images_description, + BooleanSetting.ANDROID_HIDE_IMAGES.key, + BooleanSetting.ANDROID_HIDE_IMAGES.defaultValue + ) + ) } } @@ -350,6 +362,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.array.regionValues, ) ) + add( + SwitchSetting( + BooleanSetting.APPLY_REGION_FREE_PATCH, + R.string.apply_region_free_patch, + R.string.apply_region_free_patch_desc, + BooleanSetting.APPLY_REGION_FREE_PATCH.key, + BooleanSetting.APPLY_REGION_FREE_PATCH.defaultValue + ) + ) val systemCountrySetting = object : AbstractShortSetting { override var short: Short get() { @@ -963,17 +984,30 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) add(HeaderSetting(R.string.stereoscopy)) + add( + SingleChoiceSetting( + IntSetting.RENDER_3D_WHICH_DISPLAY, + R.string.render_3d_which_display, + R.string.render_3d_which_display_description, + R.array.render3dWhichDisplay, + R.array.render3dDisplayValues, + IntSetting.RENDER_3D_WHICH_DISPLAY.key, + IntSetting.RENDER_3D_WHICH_DISPLAY.defaultValue + ) + ) add( SingleChoiceSetting( IntSetting.STEREOSCOPIC_3D_MODE, R.string.render3d, - 0, + R.string.render3d_description, R.array.render3dModes, R.array.render3dValues, IntSetting.STEREOSCOPIC_3D_MODE.key, - IntSetting.STEREOSCOPIC_3D_MODE.defaultValue + IntSetting.STEREOSCOPIC_3D_MODE.defaultValue, + isEnabled = IntSetting.RENDER_3D_WHICH_DISPLAY.int != StereoWhichDisplay.NONE.int ) ) + add( SliderSetting( IntSetting.STEREOSCOPIC_3D_DEPTH, @@ -996,6 +1030,17 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) ) + add( + SwitchSetting( + BooleanSetting.SWAP_EYES_3D, + R.string.swap_eyes_3d, + R.string.swap_eyes_3d_description, + BooleanSetting.SWAP_EYES_3D.key, + BooleanSetting.SWAP_EYES_3D.defaultValue, + isEnabled = IntSetting.RENDER_3D_WHICH_DISPLAY.int != StereoWhichDisplay.NONE.int + ) + ) + add(HeaderSetting(R.string.cardboard_vr)) add( SliderSetting( @@ -1006,7 +1051,8 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) 100, "%", IntSetting.CARDBOARD_SCREEN_SIZE.key, - IntSetting.CARDBOARD_SCREEN_SIZE.defaultValue.toFloat() + IntSetting.CARDBOARD_SCREEN_SIZE.defaultValue.toFloat(), + isEnabled = IntSetting.STEREOSCOPIC_3D_MODE.int == StereoMode.CARDBOARD_VR.int ) ) add( @@ -1018,7 +1064,8 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) 100, "%", IntSetting.CARDBOARD_X_SHIFT.key, - IntSetting.CARDBOARD_X_SHIFT.defaultValue.toFloat() + IntSetting.CARDBOARD_X_SHIFT.defaultValue.toFloat(), + isEnabled = IntSetting.STEREOSCOPIC_3D_MODE.int == StereoMode.CARDBOARD_VR.int ) ) add( @@ -1030,7 +1077,8 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) 100, "%", IntSetting.CARDBOARD_Y_SHIFT.key, - IntSetting.CARDBOARD_Y_SHIFT.defaultValue.toFloat() + IntSetting.CARDBOARD_Y_SHIFT.defaultValue.toFloat(), + isEnabled = IntSetting.STEREOSCOPIC_3D_MODE.int == StereoMode.CARDBOARD_VR.int ) ) @@ -1144,6 +1192,17 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) IntSetting.PORTRAIT_SCREEN_LAYOUT.defaultValue ) ) + add( + SingleChoiceSetting( + IntSetting.SECONDARY_DISPLAY_LAYOUT, + R.string.emulation_switch_secondary_layout, + R.string.emulation_switch_secondary_layout_description, + R.array.secondaryLayouts, + R.array.secondaryLayoutValues, + IntSetting.SECONDARY_DISPLAY_LAYOUT.key, + IntSetting.SECONDARY_DISPLAY_LAYOUT.defaultValue + ) + ) add( SingleChoiceSetting( IntSetting.ASPECT_RATIO, @@ -1153,7 +1212,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.array.aspectRatioValues, IntSetting.ASPECT_RATIO.key, IntSetting.ASPECT_RATIO.defaultValue, - isEnabled = IntSetting.SCREEN_LAYOUT.int == 1, + isEnabled = IntSetting.SCREEN_LAYOUT.int == ScreenLayout.SINGLE_SCREEN.int, ) ) add( @@ -1191,6 +1250,89 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) FloatSetting.LARGE_SCREEN_PROPORTION.defaultValue ) ) + add( + SliderSetting( + FloatSetting.SECOND_SCREEN_OPACITY, + R.string.second_screen_opacity, + R.string.second_screen_opacity_description, + 0, + 100, + "%", + FloatSetting.SECOND_SCREEN_OPACITY.key, + FloatSetting.SECOND_SCREEN_OPACITY.defaultValue, + isEnabled = IntSetting.SCREEN_LAYOUT.int == ScreenLayout.CUSTOM_LAYOUT.int + ) + ) + add(HeaderSetting(R.string.bg_color, R.string.bg_color_description)) + val bgRedSetting = object : AbstractIntSetting { + override var int: Int + get() = (FloatSetting.BACKGROUND_RED.float * 255).toInt() + set(value) { + FloatSetting.BACKGROUND_RED.float = value.toFloat() / 255 + settings.saveSetting(FloatSetting.BACKGROUND_RED, SettingsFile.FILE_NAME_CONFIG) + } + override val key = null + override val section = null + override val isRuntimeEditable = false + override val valueAsString = int.toString() + override val defaultValue = FloatSetting.BACKGROUND_RED.defaultValue + } + add( + SliderSetting( + bgRedSetting, + R.string.bg_red, + 0, + 0, + 255, + "" + ) + ) + val bgGreenSetting = object : AbstractIntSetting { + override var int: Int + get() = (FloatSetting.BACKGROUND_GREEN.float * 255).toInt() + set(value) { + FloatSetting.BACKGROUND_GREEN.float = value.toFloat() / 255 + settings.saveSetting(FloatSetting.BACKGROUND_GREEN, SettingsFile.FILE_NAME_CONFIG) + } + override val key = null + override val section = null + override val isRuntimeEditable = false + override val valueAsString = int.toString() + override val defaultValue = FloatSetting.BACKGROUND_GREEN.defaultValue + } + add( + SliderSetting( + bgGreenSetting, + R.string.bg_green, + 0, + 0, + 255, + "" + ) + ) + val bgBlueSetting = object : AbstractIntSetting { + override var int: Int + get() = (FloatSetting.BACKGROUND_BLUE.float * 255).toInt() + set(value) { + FloatSetting.BACKGROUND_BLUE.float = value.toFloat() / 255 + settings.saveSetting(FloatSetting.BACKGROUND_BLUE, SettingsFile.FILE_NAME_CONFIG) + } + override val key = null + override val section = null + override val isRuntimeEditable = false + override val valueAsString = int.toString() + override val defaultValue = FloatSetting.BACKGROUND_BLUE.defaultValue + } + add( + SliderSetting( + bgBlueSetting, + R.string.bg_blue, + 0, + 0, + 255, + "" + ) + ) add( SubmenuSetting( R.string.performance_overlay_options, @@ -1226,38 +1368,29 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) add( SwitchSetting( - object : AbstractBooleanSetting { - override val key = "EmulationMenuSettings_showPerfPerformanceOverlay" - override val section = Settings.SECTION_LAYOUT - override val defaultValue = false - override var boolean: Boolean - get() = EmulationMenuSettings.showPerformanceOverlay - set(value) { EmulationMenuSettings.showPerformanceOverlay = value } - override val isRuntimeEditable = true - override val valueAsString: String get() = boolean.toString() - }, + BooleanSetting.PERF_OVERLAY_ENABLE, R.string.performance_overlay_enable, 0, - "EmulationMenuSettings_showPerfPerformanceOverlay", - false + BooleanSetting.PERF_OVERLAY_ENABLE.key, + BooleanSetting.PERF_OVERLAY_ENABLE.defaultValue ) ) add( SwitchSetting( - BooleanSetting.OVERLAY_BACKGROUND, - R.string.overlay_background, - R.string.overlay_background_description, - "overlay_background", - false + BooleanSetting.PERF_OVERLAY_BACKGROUND, + R.string.performance_overlay_background, + R.string.performance_overlay_background_description, + BooleanSetting.PERF_OVERLAY_BACKGROUND.key, + BooleanSetting.PERF_OVERLAY_BACKGROUND.defaultValue ) ) add( SingleChoiceSetting( IntSetting.PERFORMANCE_OVERLAY_POSITION, - R.string.overlay_position, - R.string.overlay_position_description, + R.string.performance_overlay_position, + R.string.performance_overlay_position_description, R.array.statsPosition, R.array.statsPositionValues, ) @@ -1268,61 +1401,61 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) add( SwitchSetting( - BooleanSetting.OVERLAY_SHOW_FPS, - R.string.overlay_show_fps, - R.string.overlay_show_fps_description, - "overlay_show_fps", - true + BooleanSetting.PERF_OVERLAY_SHOW_FPS, + R.string.performance_overlay_show_fps, + R.string.performance_overlay_show_fps_description, + BooleanSetting.PERF_OVERLAY_SHOW_FPS.key, + BooleanSetting.PERF_OVERLAY_SHOW_FPS.defaultValue ) ) add( SwitchSetting( - BooleanSetting.OVERLAY_SHOW_FRAMETIME, - R.string.overlay_show_frametime, - R.string.overlay_show_frametime_description, - "overlay_show_frame_time", - true + BooleanSetting.PERF_OVERLAY_SHOW_FRAMETIME, + R.string.performance_overlay_show_frametime, + R.string.performance_overlay_show_frametime_description, + BooleanSetting.PERF_OVERLAY_SHOW_FRAMETIME.key, + BooleanSetting.PERF_OVERLAY_SHOW_FRAMETIME.defaultValue ) ) add( SwitchSetting( - BooleanSetting.OVERLAY_SHOW_SPEED, - R.string.overlay_show_speed, - R.string.overlay_show_speed_description, - "overlay_show_speed", - false + BooleanSetting.PERF_OVERLAY_SHOW_SPEED, + R.string.performance_overlay_show_speed, + R.string.performance_overlay_show_speed_description, + BooleanSetting.PERF_OVERLAY_SHOW_SPEED.key, + BooleanSetting.PERF_OVERLAY_SHOW_SPEED.defaultValue ) ) add( SwitchSetting( - BooleanSetting.OVERLAY_SHOW_APP_RAM_USAGE, - R.string.overlay_show_app_ram_usage, - R.string.overlay_show_app_ram_usage_description, - "overlay_show_app_ram_usage", - false + BooleanSetting.PERF_OVERLAY_SHOW_APP_RAM_USAGE, + R.string.performance_overlay_show_app_ram_usage, + R.string.performance_overlay_show_app_ram_usage_description, + BooleanSetting.PERF_OVERLAY_SHOW_APP_RAM_USAGE.key, + BooleanSetting.PERF_OVERLAY_SHOW_APP_RAM_USAGE.defaultValue ) ) add( SwitchSetting( - BooleanSetting.OVERLAY_SHOW_AVAILABLE_RAM, - R.string.overlay_show_available_ram, - R.string.overlay_show_available_ram_description, - "overlay_show_available_ram", - false + BooleanSetting.PERF_OVERLAY_SHOW_AVAILABLE_RAM, + R.string.performance_overlay_show_available_ram, + R.string.performance_overlay_show_available_ram_description, + BooleanSetting.PERF_OVERLAY_SHOW_AVAILABLE_RAM.key, + BooleanSetting.PERF_OVERLAY_SHOW_AVAILABLE_RAM.defaultValue ) ) add( SwitchSetting( - BooleanSetting.OVERLAY_SHOW_BATTERY_TEMP, - R.string.overlay_show_battery_temp, - R.string.overlay_show_battery_temp_description, - "overlay_show_battery_temp", - false + BooleanSetting.PERF_OVERLAY_SHOW_BATTERY_TEMP, + R.string.performance_overlay_show_battery_temp, + R.string.performance_overlay_show_battery_temp_description, + BooleanSetting.PERF_OVERLAY_SHOW_BATTERY_TEMP.key, + BooleanSetting.PERF_OVERLAY_SHOW_BATTERY_TEMP.defaultValue ) ) } @@ -1338,7 +1471,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_x, 0, 0, - getHeight(), + getLargerDimension(), "px", IntSetting.LANDSCAPE_TOP_X.key, IntSetting.LANDSCAPE_TOP_X.defaultValue.toFloat() @@ -1350,7 +1483,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_y, 0, 0, - getWidth(), + getSmallerDimension(), "px", IntSetting.LANDSCAPE_TOP_Y.key, IntSetting.LANDSCAPE_TOP_Y.defaultValue.toFloat() @@ -1362,7 +1495,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_width, 0, 0, - getHeight(), + getLargerDimension(), "px", IntSetting.LANDSCAPE_TOP_WIDTH.key, IntSetting.LANDSCAPE_TOP_WIDTH.defaultValue.toFloat() @@ -1374,7 +1507,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_height, 0, 0, - getWidth(), + getSmallerDimension(), "px", IntSetting.LANDSCAPE_TOP_HEIGHT.key, IntSetting.LANDSCAPE_TOP_HEIGHT.defaultValue.toFloat() @@ -1387,7 +1520,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_x, 0, 0, - getHeight(), + getLargerDimension(), "px", IntSetting.LANDSCAPE_BOTTOM_X.key, IntSetting.LANDSCAPE_BOTTOM_X.defaultValue.toFloat() @@ -1399,7 +1532,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_y, 0, 0, - getWidth(), + getSmallerDimension(), "px", IntSetting.LANDSCAPE_BOTTOM_Y.key, IntSetting.LANDSCAPE_BOTTOM_Y.defaultValue.toFloat() @@ -1411,7 +1544,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_width, 0, 0, - getHeight(), + getLargerDimension(), "px", IntSetting.LANDSCAPE_BOTTOM_WIDTH.key, IntSetting.LANDSCAPE_BOTTOM_WIDTH.defaultValue.toFloat() @@ -1423,7 +1556,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_height, 0, 0, - getWidth(), + getSmallerDimension(), "px", IntSetting.LANDSCAPE_BOTTOM_HEIGHT.key, IntSetting.LANDSCAPE_BOTTOM_HEIGHT.defaultValue.toFloat() @@ -1443,7 +1576,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_x, 0, 0, - getWidth(), + getSmallerDimension(), "px", IntSetting.PORTRAIT_TOP_X.key, IntSetting.PORTRAIT_TOP_X.defaultValue.toFloat() @@ -1455,7 +1588,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_y, 0, 0, - getHeight(), + getLargerDimension(), "px", IntSetting.PORTRAIT_TOP_Y.key, IntSetting.PORTRAIT_TOP_Y.defaultValue.toFloat() @@ -1467,7 +1600,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_width, 0, 0, - getWidth(), + getSmallerDimension(), "px", IntSetting.PORTRAIT_TOP_WIDTH.key, IntSetting.PORTRAIT_TOP_WIDTH.defaultValue.toFloat() @@ -1479,7 +1612,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_height, 0, 0, - getHeight(), + getLargerDimension(), "px", IntSetting.PORTRAIT_TOP_HEIGHT.key, IntSetting.PORTRAIT_TOP_HEIGHT.defaultValue.toFloat() @@ -1492,7 +1625,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_x, 0, 0, - getWidth(), + getSmallerDimension(), "px", IntSetting.PORTRAIT_BOTTOM_X.key, IntSetting.PORTRAIT_BOTTOM_X.defaultValue.toFloat() @@ -1504,7 +1637,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_y, 0, 0, - getHeight(), + getLargerDimension(), "px", IntSetting.PORTRAIT_BOTTOM_Y.key, IntSetting.PORTRAIT_BOTTOM_Y.defaultValue.toFloat() @@ -1516,7 +1649,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_width, 0, 0, - getWidth(), + getSmallerDimension(), "px", IntSetting.PORTRAIT_BOTTOM_WIDTH.key, IntSetting.PORTRAIT_BOTTOM_WIDTH.defaultValue.toFloat() @@ -1528,7 +1661,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) R.string.emulation_custom_layout_height, 0, 0, - getHeight(), + getLargerDimension(), "px", IntSetting.PORTRAIT_BOTTOM_HEIGHT.key, IntSetting.PORTRAIT_BOTTOM_HEIGHT.defaultValue.toFloat() diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/viewholder/InputBindingSettingViewHolder.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/viewholder/InputBindingSettingViewHolder.kt index 07dc636cd..5d2a812e0 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/viewholder/InputBindingSettingViewHolder.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/viewholder/InputBindingSettingViewHolder.kt @@ -51,7 +51,7 @@ class InputBindingSettingViewHolder(val binding: ListItemSettingBinding, adapter override fun onLongClick(clicked: View): Boolean { if (setting.isEditable) { - adapter.onLongClick(setting.setting!!, bindingAdapterPosition) + adapter.onInputBindingLongClick(setting, bindingAdapterPosition) } else { adapter.onClickDisabledSetting(!setting.isEditable) } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/CitraDirectoryDialogFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/CitraDirectoryDialogFragment.kt index 43fe1b22a..e663d290b 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/CitraDirectoryDialogFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/CitraDirectoryDialogFragment.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -60,7 +60,7 @@ class CitraDirectoryDialogFragment : DialogFragment() { } .setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int -> if (!PermissionsHandler.hasWriteAccess(requireContext())) { - (requireActivity() as MainActivity)?.openCitraDirectory?.launch(null) + PermissionsHandler.compatibleSelectDirectory((requireActivity() as MainActivity).openCitraDirectory) } } .show() diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/CompressProgressDialogFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/CompressProgressDialogFragment.kt new file mode 100644 index 000000000..bcd97ae03 --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/CompressProgressDialogFragment.kt @@ -0,0 +1,89 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.fragments + +import android.app.Dialog +import android.os.Bundle +import android.view.View +import android.widget.ProgressBar +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.lifecycle.Lifecycle +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.launch +import org.citra.citra_emu.R +import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel +import org.citra.citra_emu.NativeLibrary + +class CompressProgressDialogFragment : DialogFragment() { + private lateinit var progressBar: ProgressBar + private var outputPath: String? = null + private var isCompressing: Boolean = true + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.let { + isCompressing = it.getBoolean(ARG_IS_COMPRESSING, true) + outputPath = it.getString(ARG_OUTPUT_PATH) + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val view = layoutInflater.inflate(R.layout.dialog_compress_progress, null) + progressBar = view.findViewById(R.id.compress_progress) + val label = view.findViewById(R.id.compress_label) + label.text = if (isCompressing) getString(R.string.compressing) else getString(R.string.decompressing) + + isCancelable = false + progressBar.isIndeterminate = true + + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + combine(CompressProgressDialogViewModel.total, CompressProgressDialogViewModel.progress) { total, progress -> + total to progress + }.collectLatest { (total, progress) -> + if (total <= 0) { + progressBar.isIndeterminate = true + label.visibility = View.GONE + } else { + progressBar.isIndeterminate = false + label.visibility = View.VISIBLE + progressBar.max = total + progressBar.setProgress(progress, true) + } + } + } + } + + val builder = MaterialAlertDialogBuilder(requireContext()) + .setView(view) + .setCancelable(false) + .setNegativeButton(android.R.string.cancel) { _: android.content.DialogInterface, _: Int -> + outputPath?.let { path -> + NativeLibrary.deleteDocument(path) + } + } + + return builder.show() + } + + companion object { + const val TAG = "CompressProgressDialog" + private const val ARG_IS_COMPRESSING = "isCompressing" + private const val ARG_OUTPUT_PATH = "outputPath" + + fun newInstance(isCompressing: Boolean, outputPath: String?): CompressProgressDialogFragment { + val frag = CompressProgressDialogFragment() + val args = Bundle() + args.putBoolean(ARG_IS_COMPRESSING, isCompressing) + args.putString(ARG_OUTPUT_PATH, outputPath) + frag.arguments = args + return frag + } + } +} diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt index 55646f035..897050fc2 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt @@ -13,6 +13,7 @@ import android.content.IntentFilter import android.content.SharedPreferences import android.net.Uri import android.os.BatteryManager +import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper @@ -66,6 +67,7 @@ import org.citra.citra_emu.display.ScreenAdjustmentUtil import org.citra.citra_emu.display.ScreenLayout import org.citra.citra_emu.features.settings.model.BooleanSetting import org.citra.citra_emu.features.settings.model.IntSetting +import org.citra.citra_emu.features.settings.model.Settings import org.citra.citra_emu.features.settings.model.SettingsViewModel import org.citra.citra_emu.features.settings.ui.SettingsActivity import org.citra.citra_emu.features.settings.utils.SettingsFile @@ -100,6 +102,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram private val emulationViewModel: EmulationViewModel by activityViewModels() private val settingsViewModel: SettingsViewModel by viewModels() + private val settings get() = settingsViewModel.settings + + private val onPause = Runnable{ togglePause() } + private val onShutdown = Runnable{ emulationState.stop() } override fun onAttach(context: Context) { super.onAttach(context) @@ -139,6 +145,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram } } + val insertedCartridge = preferences.getString("insertedCartridge", "") + NativeLibrary.setInsertedCartridge(insertedCartridge ?: "") + try { game = args.game ?: intentGame!! } catch (e: NullPointerException) { @@ -155,9 +164,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram retainInstance = true emulationState = EmulationState(game.path) emulationActivity = requireActivity() as EmulationActivity - screenAdjustmentUtil = ScreenAdjustmentUtil(requireContext(), requireActivity().windowManager, settingsViewModel.settings) - EmulationLifecycleUtil.addShutdownHook(hook = { emulationState.stop() }) - EmulationLifecycleUtil.addPauseResumeHook(hook = { togglePause() }) + screenAdjustmentUtil = ScreenAdjustmentUtil(requireContext(), requireActivity().windowManager, settings) + EmulationLifecycleUtil.addPauseResumeHook(onPause) + EmulationLifecycleUtil.addShutdownHook(onShutdown) } override fun onCreateView( @@ -507,6 +516,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram super.onDetach() } + override fun onDestroy() { + EmulationLifecycleUtil.removeHook(onPause) + EmulationLifecycleUtil.removeHook(onShutdown) + super.onDestroy() + } + private fun setupCitraDirectoriesThenStartEmulation() { val directoryInitializationState = DirectoryInitialization.start() if (directoryInitializationState === @@ -662,7 +677,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram popupMenu.menu.apply { findItem(R.id.menu_show_overlay).isChecked = EmulationMenuSettings.showOverlay findItem(R.id.menu_performance_overlay_show).isChecked = - EmulationMenuSettings.showPerformanceOverlay + BooleanSetting.PERF_OVERLAY_ENABLE.boolean findItem(R.id.menu_haptic_feedback).isChecked = EmulationMenuSettings.hapticFeedback findItem(R.id.menu_emulation_joystick_rel_center).isChecked = EmulationMenuSettings.joystickRelCenter @@ -679,7 +694,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram } R.id.menu_performance_overlay_show -> { - EmulationMenuSettings.showPerformanceOverlay = !EmulationMenuSettings.showPerformanceOverlay + BooleanSetting.PERF_OVERLAY_ENABLE.boolean = !BooleanSetting.PERF_OVERLAY_ENABLE.boolean + settings.saveSetting(BooleanSetting.PERF_OVERLAY_ENABLE, SettingsFile.FILE_NAME_CONFIG) updateShowPerformanceOverlay() true } @@ -1017,7 +1033,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram enabledButtons[i] = preferences.getBoolean("buttonToggle$i", defaultValue) } - MaterialAlertDialogBuilder(requireContext()) + val dialog = MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.emulation_toggle_controls) .setMultiChoiceItems( R.array.n3dsButtons, enabledButtons @@ -1029,6 +1045,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram binding.surfaceInputOverlay.refreshControls() } .show() + + // Band-aid fix for strange dialog flickering issue + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val displayMetrics = requireActivity().windowManager.currentWindowMetrics + val displayHeight = displayMetrics.bounds.height() + // The layout visually breaks if we try to set the height directly rather than like this. + // Why? Fuck you, that's why! + val newAttributes = dialog.window?.attributes + newAttributes?.height = (displayHeight * 0.85f).toInt() + dialog.window?.attributes = newAttributes + } } private fun showAdjustScaleDialog(target: String) { @@ -1207,7 +1234,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) } - if (EmulationMenuSettings.showPerformanceOverlay) { + if (BooleanSetting.PERF_OVERLAY_ENABLE.boolean) { val SYSTEM_FPS = 0 val FPS = 1 val SPEED = 2 @@ -1222,11 +1249,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram val perfStats = NativeLibrary.getPerfStats() val dividerString = "\u00A0\u2502 " if (perfStats[FPS] > 0) { - if (BooleanSetting.OVERLAY_SHOW_FPS.boolean) { + if (BooleanSetting.PERF_OVERLAY_SHOW_FPS.boolean) { sb.append(String.format("FPS:\u00A0%d", (perfStats[FPS] + 0.5).toInt())) } - if (BooleanSetting.OVERLAY_SHOW_FRAMETIME.boolean) { + if (BooleanSetting.PERF_OVERLAY_SHOW_FRAMETIME.boolean) { if (sb.isNotEmpty()) sb.append(dividerString) sb.append( String.format( @@ -1241,7 +1268,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram ) } - if (BooleanSetting.OVERLAY_SHOW_SPEED.boolean) { + if (BooleanSetting.PERF_OVERLAY_SHOW_SPEED.boolean) { if (sb.isNotEmpty()) sb.append(dividerString) sb.append( String.format( @@ -1251,14 +1278,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram ) } - if (BooleanSetting.OVERLAY_SHOW_APP_RAM_USAGE.boolean) { + if (BooleanSetting.PERF_OVERLAY_SHOW_APP_RAM_USAGE.boolean) { if (sb.isNotEmpty()) sb.append(dividerString) val appRamUsage = File("/proc/self/statm").readLines()[0].split(' ')[1].toLong() * 4096 / 1000000 sb.append("Process\u00A0RAM:\u00A0$appRamUsage\u00A0MB") } - if (BooleanSetting.OVERLAY_SHOW_AVAILABLE_RAM.boolean) { + if (BooleanSetting.PERF_OVERLAY_SHOW_AVAILABLE_RAM.boolean) { if (sb.isNotEmpty()) sb.append(dividerString) context?.let { ctx -> val activityManager = @@ -1271,14 +1298,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram } } - if (BooleanSetting.OVERLAY_SHOW_BATTERY_TEMP.boolean) { + if (BooleanSetting.PERF_OVERLAY_SHOW_BATTERY_TEMP.boolean) { if (sb.isNotEmpty()) sb.append(dividerString) val batteryTemp = getBatteryTemperature() val tempF = celsiusToFahrenheit(batteryTemp) sb.append(String.format("%.1f°C/%.1f°F", batteryTemp, tempF)) } - if (BooleanSetting.OVERLAY_BACKGROUND.boolean) { + if (BooleanSetting.PERF_OVERLAY_BACKGROUND.boolean) { binding.performanceOverlayShowText.setBackgroundResource(R.color.citra_transparent_black) } else { binding.performanceOverlayShowText.setBackgroundResource(0) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/GamesFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/GamesFragment.kt index b224c5c15..cdcee4a19 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/GamesFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/GamesFragment.kt @@ -7,16 +7,12 @@ package org.citra.citra_emu.fragments import android.annotation.SuppressLint import android.net.Uri import android.os.Bundle -import android.text.method.LinkMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.ViewGroup.MarginLayoutParams -import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.edit -import androidx.core.text.HtmlCompat import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding @@ -30,14 +26,17 @@ import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.color.MaterialColors import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.transition.MaterialFadeThrough +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import org.citra.citra_emu.CitraApplication +import org.citra.citra_emu.NativeLibrary import org.citra.citra_emu.R import org.citra.citra_emu.adapters.GameAdapter import org.citra.citra_emu.databinding.FragmentGamesBinding import org.citra.citra_emu.features.settings.model.Settings import org.citra.citra_emu.model.Game +import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel import org.citra.citra_emu.viewmodel.GamesViewModel import org.citra.citra_emu.viewmodel.HomeViewModel @@ -47,7 +46,6 @@ class GamesFragment : Fragment() { private val gamesViewModel: GamesViewModel by activityViewModels() private val homeViewModel: HomeViewModel by activityViewModels() - private var show3DSFileWarning: Boolean = true private lateinit var gameAdapter: GameAdapter private val openImageLauncher = registerForActivityResult( @@ -56,6 +54,58 @@ class GamesFragment : Fragment() { gameAdapter.handleShortcutImageResult(uri) } + private var shouldCompress: Boolean = true + private var pendingCompressInvocation: String? = null + + companion object { + fun doCompression(fragment: Fragment, gamesViewModel: GamesViewModel, inputPath: String?, outputUri: Uri?, shouldCompress: Boolean) { + if (outputUri != null) { + CompressProgressDialogViewModel.reset() + val dialog = CompressProgressDialogFragment.newInstance(shouldCompress, outputUri.toString()) + dialog.showNow( + fragment.requireActivity().supportFragmentManager, + CompressProgressDialogFragment.TAG + ) + + fragment.lifecycleScope.launch(Dispatchers.IO) { + val status = if (shouldCompress) { + NativeLibrary.compressFile(inputPath, outputUri.toString()) + } else { + NativeLibrary.decompressFile(inputPath, outputUri.toString()) + } + + fragment.requireActivity().runOnUiThread { + dialog.dismiss() + val resId = when (status) { + NativeLibrary.CompressStatus.SUCCESS -> if (shouldCompress) R.string.compress_success else R.string.decompress_success + NativeLibrary.CompressStatus.COMPRESS_UNSUPPORTED -> R.string.compress_unsupported + NativeLibrary.CompressStatus.COMPRESS_ALREADY_COMPRESSED -> R.string.compress_already + NativeLibrary.CompressStatus.COMPRESS_FAILED -> R.string.compress_failed + NativeLibrary.CompressStatus.DECOMPRESS_UNSUPPORTED -> R.string.decompress_unsupported + NativeLibrary.CompressStatus.DECOMPRESS_NOT_COMPRESSED -> R.string.decompress_not_compressed + NativeLibrary.CompressStatus.DECOMPRESS_FAILED -> R.string.decompress_failed + NativeLibrary.CompressStatus.INSTALLED_APPLICATION -> R.string.compress_decompress_installed_app + } + + MaterialAlertDialogBuilder(fragment.requireContext()) + .setMessage(fragment.getString(resId)) + .setPositiveButton(android.R.string.ok, null) + .show() + + gamesViewModel.reloadGames(false) + } + } + } + } + } + + private val onCompressDecompressLauncher = registerForActivityResult( + ActivityResultContracts.CreateDocument("application/octet-stream") + ) { uri: Uri? -> + doCompression(this, gamesViewModel, pendingCompressInvocation, uri, shouldCompress) + pendingCompressInvocation = null + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enterTransition = MaterialFadeThrough() @@ -81,7 +131,12 @@ class GamesFragment : Fragment() { gameAdapter = GameAdapter( requireActivity() as AppCompatActivity, inflater, - openImageLauncher + openImageLauncher, + onRequestCompressOrDecompress = { inputPath, suggestedName, shouldCompress -> + pendingCompressInvocation = inputPath + onCompressDecompressLauncher.launch(suggestedName) + this.shouldCompress = shouldCompress + } ) binding.gridGames.apply { @@ -164,34 +219,6 @@ class GamesFragment : Fragment() { setInsets() } - override fun onResume() { - super.onResume() - - if (show3DSFileWarning && - !PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext) - .getBoolean("show_3ds_files_warning", false)) { - val message = HtmlCompat.fromHtml(getString(R.string.warning_3ds_files), - HtmlCompat.FROM_HTML_MODE_LEGACY) - - context?.let { - val alert = MaterialAlertDialogBuilder(it) - .setTitle(getString(R.string.important)) - .setMessage(message) - .setPositiveButton(R.string.dont_show_again) { _, _ -> - PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext) - .edit() { - putBoolean("show_3ds_files_warning", true) - } - } - .show() - - val alertMessage = alert.findViewById(android.R.id.message) as TextView - alertMessage.movementMethod = LinkMovementMethod.getInstance() - } - } - show3DSFileWarning = false - } - override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/GrantMissingFilesystemPermissionFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/GrantMissingFilesystemPermissionFragment.kt new file mode 100644 index 000000000..e07787c52 --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/GrantMissingFilesystemPermissionFragment.kt @@ -0,0 +1,81 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.fragments + +import android.Manifest +import android.app.Dialog +import android.content.DialogInterface +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.Environment +import android.provider.Settings +import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresApi +import androidx.fragment.app.DialogFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.citra.citra_emu.R +import org.citra.citra_emu.ui.main.MainActivity +import org.citra.citra_emu.utils.BuildUtil + +class GrantMissingFilesystemPermissionFragment : DialogFragment() { + private lateinit var mainActivity: MainActivity + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + BuildUtil.assertNotGooglePlay() + mainActivity = requireActivity() as MainActivity + + isCancelable = false + + val requestPermissionFunction = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + { + manageExternalStoragePermissionLauncher.launch( + Intent( + Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, + Uri.fromParts("package", mainActivity.packageName, null) + ) + ) + } + } else { + { permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) } + } + + + + return MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.filesystem_permission_warning) + .setMessage(R.string.filesystem_permission_lost) + .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> + requestPermissionFunction() + } + .show() + } + + @RequiresApi(Build.VERSION_CODES.R) + private val manageExternalStoragePermissionLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (Environment.isExternalStorageManager()) { + return@registerForActivityResult + } + } + + private val permissionLauncher = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> + if (isGranted) { + return@registerForActivityResult + } + } + + companion object { + const val TAG = "GrantMissingFilesystemPermissionFragment" + + fun newInstance(): GrantMissingFilesystemPermissionFragment { + BuildUtil.assertNotGooglePlay() + return GrantMissingFilesystemPermissionFragment() + } + } +} diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/HomeSettingsFragment.kt index 432a06aa0..63c435531 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/HomeSettingsFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/HomeSettingsFragment.kt @@ -159,7 +159,7 @@ class HomeSettingsFragment : Fragment() { R.string.select_citra_user_folder, R.string.select_citra_user_folder_home_description, R.drawable.ic_home, - { mainActivity?.openCitraDirectory?.launch(null) }, + { PermissionsHandler.compatibleSelectDirectory(mainActivity.openCitraDirectory) }, details = homeViewModel.userDir ), HomeSetting( diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/SearchFragment.kt index 94821023f..dab5ea745 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/SearchFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/SearchFragment.kt @@ -7,11 +7,13 @@ package org.citra.citra_emu.fragments import android.annotation.SuppressLint import android.content.Context import android.content.SharedPreferences +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat @@ -26,18 +28,19 @@ import androidx.preference.PreferenceManager import androidx.recyclerview.widget.GridLayoutManager import info.debatty.java.stringsimilarity.Jaccard import info.debatty.java.stringsimilarity.JaroWinkler +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.citra.citra_emu.CitraApplication import org.citra.citra_emu.R +import org.citra.citra_emu.NativeLibrary import org.citra.citra_emu.adapters.GameAdapter import org.citra.citra_emu.databinding.FragmentSearchBinding import org.citra.citra_emu.model.Game +import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel import org.citra.citra_emu.viewmodel.GamesViewModel import org.citra.citra_emu.viewmodel.HomeViewModel import java.time.temporal.ChronoField import java.util.Locale -import android.net.Uri -import androidx.activity.result.contract.ActivityResultContracts class SearchFragment : Fragment() { private var _binding: FragmentSearchBinding? = null @@ -53,6 +56,15 @@ class SearchFragment : Fragment() { gameAdapter.handleShortcutImageResult(uri) } + private var shouldCompress: Boolean = true + private var pendingCompressInvocation: String? = null + private val onCompressDecompressLauncher = registerForActivityResult( + ActivityResultContracts.CreateDocument("application/octet-stream") + ) { uri: Uri? -> + GamesFragment.doCompression(this, gamesViewModel, pendingCompressInvocation, uri, shouldCompress) + pendingCompressInvocation = null + } + private lateinit var preferences: SharedPreferences companion object { @@ -85,7 +97,13 @@ class SearchFragment : Fragment() { gameAdapter = GameAdapter( requireActivity() as AppCompatActivity, inflater, - openImageLauncher + openImageLauncher, + onRequestCompressOrDecompress = { inputPath, suggestedName, shouldCompress -> + pendingCompressInvocation = inputPath + onCompressDecompressLauncher.launch(suggestedName) + this.shouldCompress = shouldCompress + } + ) binding.gridGamesSearch.apply { diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/SelectUserDirectoryDialogFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/SelectUserDirectoryDialogFragment.kt index 988f90ccc..f0f945860 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/SelectUserDirectoryDialogFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/SelectUserDirectoryDialogFragment.kt @@ -13,21 +13,25 @@ import androidx.lifecycle.ViewModelProvider import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.citra.citra_emu.R import org.citra.citra_emu.ui.main.MainActivity +import org.citra.citra_emu.utils.PermissionsHandler import org.citra.citra_emu.viewmodel.HomeViewModel -class SelectUserDirectoryDialogFragment : DialogFragment() { +class SelectUserDirectoryDialogFragment(titleOverride: Int? = null, descriptionOverride: Int? = null) : DialogFragment() { private lateinit var mainActivity: MainActivity + private val title = titleOverride ?: R.string.select_citra_user_folder + private val description = descriptionOverride ?: R.string.selecting_user_directory_without_write_permissions + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { mainActivity = requireActivity() as MainActivity isCancelable = false return MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.select_citra_user_folder) - .setMessage(R.string.selecting_user_directory_without_write_permissions) + .setTitle(title) + .setMessage(description) .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> - mainActivity?.openCitraDirectoryLostPermission?.launch(null) + PermissionsHandler.compatibleSelectDirectory(mainActivity.openCitraDirectoryLostPermission) } .show() } @@ -35,9 +39,10 @@ class SelectUserDirectoryDialogFragment : DialogFragment() { companion object { const val TAG = "SelectUserDirectoryDialogFragment" - fun newInstance(activity: FragmentActivity): SelectUserDirectoryDialogFragment { + fun newInstance(activity: FragmentActivity, titleOverride: Int? = null, descriptionOverride: Int? = null): + SelectUserDirectoryDialogFragment { ViewModelProvider(activity)[HomeViewModel::class.java].setPickingUserDir(true) - return SelectUserDirectoryDialogFragment() + return SelectUserDirectoryDialogFragment(titleOverride, descriptionOverride) } } } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/SetupFragment.kt index fa47f99b8..0a25044ea 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/SetupFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/SetupFragment.kt @@ -11,11 +11,13 @@ import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.os.Bundle +import android.os.Environment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.OnBackPressedCallback import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat @@ -30,7 +32,9 @@ import androidx.preference.PreferenceManager import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import com.google.android.material.snackbar.Snackbar import com.google.android.material.transition.MaterialFadeThrough +import org.citra.citra_emu.BuildConfig import org.citra.citra_emu.CitraApplication +import org.citra.citra_emu.NativeLibrary import org.citra.citra_emu.R import org.citra.citra_emu.adapters.SetupAdapter import org.citra.citra_emu.databinding.FragmentSetupBinding @@ -41,6 +45,7 @@ import org.citra.citra_emu.model.PageState import org.citra.citra_emu.model.SetupCallback import org.citra.citra_emu.model.SetupPage import org.citra.citra_emu.ui.main.MainActivity +import org.citra.citra_emu.utils.BuildUtil import org.citra.citra_emu.utils.CitraDirectoryHelper import org.citra.citra_emu.utils.GameHelper import org.citra.citra_emu.utils.PermissionsHandler @@ -142,7 +147,56 @@ class SetupFragment : Fragment() { false, 0, pageButtons = mutableListOf().apply { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (!BuildUtil.isGooglePlayBuild) { + add( + PageButton( + R.drawable.ic_folder, + R.string.filesystem_permission, + R.string.filesystem_permission_description, + buttonAction = { + pageButtonCallback = it + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + manageExternalStoragePermissionLauncher.launch( + Intent( + android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, + Uri.fromParts( + "package", + requireActivity().packageName, + null + ) + ) + ) + } else { + permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } + }, + buttonState = { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (Environment.isExternalStorageManager()) { + ButtonState.BUTTON_ACTION_COMPLETE + } else { + ButtonState.BUTTON_ACTION_INCOMPLETE + } + } else { + if (ContextCompat.checkSelfPermission( + requireContext(), + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) == PackageManager.PERMISSION_GRANTED + ) { + ButtonState.BUTTON_ACTION_COMPLETE + } else { + ButtonState.BUTTON_ACTION_INCOMPLETE + } + } + }, + isUnskippable = true, + hasWarning = true, + R.string.filesystem_permission_warning, + R.string.filesystem_permission_warning_description, + ) + ) + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { add( PageButton( R.drawable.ic_notification, @@ -214,18 +268,35 @@ class SetupFragment : Fragment() { ) }, ) { - if ( + var permissionsComplete = + // Microphone ContextCompat.checkSelfPermission( requireContext(), Manifest.permission.RECORD_AUDIO ) == PackageManager.PERMISSION_GRANTED && + // Camera ContextCompat.checkSelfPermission( requireContext(), Manifest.permission.CAMERA ) == PackageManager.PERMISSION_GRANTED && + // Notifications NotificationManagerCompat.from(requireContext()) .areNotificationsEnabled() - ) { + // External Storage + if (!BuildUtil.isGooglePlayBuild) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + permissionsComplete = + (permissionsComplete && Environment.isExternalStorageManager()) + } else { + permissionsComplete = + (permissionsComplete && ContextCompat.checkSelfPermission( + requireContext(), + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) == PackageManager.PERMISSION_GRANTED) + } + } + + if (permissionsComplete) { PageState.PAGE_STEPS_COMPLETE } else { PageState.PAGE_STEPS_INCOMPLETE @@ -249,7 +320,7 @@ class SetupFragment : Fragment() { R.string.select_citra_user_folder_description, buttonAction = { pageButtonCallback = it - openCitraDirectory.launch(null) + PermissionsHandler.compatibleSelectDirectory(openCitraDirectory) }, buttonState = { if (PermissionsHandler.hasWriteAccess(requireContext())) { @@ -452,6 +523,19 @@ class SetupFragment : Fragment() { } } + private fun showPermissionDeniedSnackbar() { + Snackbar.make(binding.root, R.string.permission_denied, Snackbar.LENGTH_LONG) + .setAnchorView(binding.buttonNext) + .setAction(R.string.grid_menu_core_settings) { + val intent = + Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + val uri = Uri.fromParts("package", requireActivity().packageName, null) + intent.data = uri + startActivity(intent) + } + .show() + } + private val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> if (isGranted) { @@ -459,16 +543,20 @@ class SetupFragment : Fragment() { return@registerForActivityResult } - Snackbar.make(binding.root, R.string.permission_denied, Snackbar.LENGTH_LONG) - .setAnchorView(binding.buttonNext) - .setAction(R.string.grid_menu_core_settings) { - val intent = - Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - val uri = Uri.fromParts("package", requireActivity().packageName, null) - intent.data = uri - startActivity(intent) - } - .show() + showPermissionDeniedSnackbar() + } + + // We can't use permissionLauncher because MANAGE_EXTERNAL_STORAGE is a special snowflake + @RequiresApi(Build.VERSION_CODES.R) + private val manageExternalStoragePermissionLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + BuildUtil.assertNotGooglePlay() + if (Environment.isExternalStorageManager()) { + checkForButtonState.invoke() + return@registerForActivityResult + } + + showPermissionDeniedSnackbar() } private val openCitraDirectory = registerForActivityResult( @@ -478,6 +566,17 @@ class SetupFragment : Fragment() { return@registerForActivityResult } + if (!BuildUtil.isGooglePlayBuild) { + if (NativeLibrary.getUserDirectory(result) == "") { + SelectUserDirectoryDialogFragment.newInstance( + mainActivity, + R.string.invalid_selection, + R.string.invalid_user_directory + ).show(mainActivity.supportFragmentManager, SelectUserDirectoryDialogFragment.TAG) + return@registerForActivityResult + } + } + CitraDirectoryHelper(requireActivity(), true).showCitraDirectoryDialog(result, pageButtonCallback, checkForButtonState) } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/model/Game.kt b/src/android/app/src/main/java/org/citra/citra_emu/model/Game.kt index 85f483896..7a204e3fd 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/model/Game.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/model/Game.kt @@ -25,8 +25,10 @@ class Game( val isInstalled: Boolean = false, val isSystemTitle: Boolean = false, val isVisibleSystemTitle: Boolean = false, + val isInsertable: Boolean = false, val icon: IntArray? = null, val fileType: String = "", + val isCompressed: Boolean = false, val filename: String, ) : Parcelable { val keyAddedToLibraryTime get() = "${filename}_AddedToLibraryTime" @@ -64,7 +66,7 @@ class Game( val allExtensions: Set get() = extensions + badExtensions val extensions: Set = HashSet( - listOf("3dsx", "elf", "axf", "cci", "cxi", "app") + listOf("3dsx", "app", "axf", "cci", "cxi", "elf", "z3dsx", "zcci", "zcxi", "3ds") ) val badExtensions: Set = HashSet( diff --git a/src/android/app/src/main/java/org/citra/citra_emu/model/GameInfo.kt b/src/android/app/src/main/java/org/citra/citra_emu/model/GameInfo.kt index 817e5fdec..494d7bf75 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/model/GameInfo.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/model/GameInfo.kt @@ -37,6 +37,8 @@ class GameInfo(path: String) { external fun getFileType(): String + external fun getIsInsertable(): Boolean + companion object { @JvmStatic private external fun initialize(path: String): Long diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt index 0d3505b80..84fd0e8d9 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt @@ -98,173 +98,199 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex return onTouchWhileEditing(event) } - var hasActiveButtons = false - val pointerIndex = event.actionIndex - val pointerId = event.getPointerId(pointerIndex) - for (button in overlayButtons) { - if (button.trackId == pointerId) { - hasActiveButtons = true - break - } - } - var hasActiveDpad = false - if (!hasActiveButtons) { - for (dpad in overlayDpads) { - if (dpad.trackId == pointerId) { - hasActiveDpad = true - break - } - } - } - - var hasActiveJoystick = false - if(!hasActiveButtons && !hasActiveDpad){ - for (joystick in overlayJoysticks) { - if (joystick.trackId == pointerId) { - hasActiveJoystick = true - break - } - } - } - - var shouldUpdateView = false - if(!hasActiveDpad && !hasActiveJoystick) { - for (button in overlayButtons) { - val stateChanged = button.updateStatus(event, hasActiveButtons, this) - if (!stateChanged) { - continue - } - - if (button.id == NativeLibrary.ButtonType.BUTTON_SWAP && button.status == NativeLibrary.ButtonState.PRESSED) { - swapScreen() - } - else if (button.id == NativeLibrary.ButtonType.BUTTON_TURBO && button.status == NativeLibrary.ButtonState.PRESSED) { - TurboHelper.toggleTurbo(true) - } - else if (button.id == NativeLibrary.ButtonType.BUTTON_COMBO) { - ComboHelper.comboActivate(button) - } - - - NativeLibrary.onGamePadEvent( - NativeLibrary.TouchScreenDevice, - button.id, - button.status - ) - - shouldUpdateView = true - } - } - - if(!hasActiveButtons && !hasActiveJoystick) { - for (dpad in overlayDpads) { - val stateChanged = dpad.updateStatus( - event, - hasActiveDpad, - EmulationMenuSettings.dpadSlide, - this - ) - if (!stateChanged) { - continue - } - - NativeLibrary.onGamePadEvent( - NativeLibrary.TouchScreenDevice, - dpad.upId, - dpad.upStatus - ) - NativeLibrary.onGamePadEvent( - NativeLibrary.TouchScreenDevice, - dpad.downId, - dpad.downStatus - ) - NativeLibrary.onGamePadEvent( - NativeLibrary.TouchScreenDevice, - dpad.leftId, - dpad.leftStatus - ) - NativeLibrary.onGamePadEvent( - NativeLibrary.TouchScreenDevice, - dpad.rightId, - dpad.rightStatus - ) - - shouldUpdateView = true - } - } - - if(!hasActiveDpad && !hasActiveButtons) { - for (joystick in overlayJoysticks) { - val stateChanged = joystick.updateStatus(event, hasActiveJoystick, this) - if (!stateChanged) { - continue - } - - val axisID = joystick.joystickId - NativeLibrary.onGamePadMoveEvent( - NativeLibrary.TouchScreenDevice, - axisID, - joystick.xAxis, - joystick.yAxis - ) - - shouldUpdateView = true - } - } - - if (shouldUpdateView) { - invalidate() - } - - if (!preferences.getBoolean("isTouchEnabled", true)) { - return true - } - - val xPosition = event.getX(pointerIndex).toInt() - val yPosition = event.getY(pointerIndex).toInt() val motionEvent = event.action and MotionEvent.ACTION_MASK val isActionDown = motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN val isActionMove = motionEvent == MotionEvent.ACTION_MOVE val isActionUp = motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP - if (isActionDown && !isTouchInputConsumed(pointerId)) { - NativeLibrary.onTouchEvent(xPosition.toFloat(), yPosition.toFloat(), true) - } - if (isActionMove) { - for (i in 0 until event.pointerCount) { - val fingerId = event.getPointerId(i) - if (isTouchInputConsumed(fingerId)) { - continue + + val pointerList = (0 until event.pointerCount).toMutableList() + // Move the pointer that triggered the most recent event to the front + // of the list so that it is processed first + val currentActionPointer = event.actionIndex + pointerList.remove(pointerList.indexOf(currentActionPointer)) + pointerList.add(0, currentActionPointer) + + // Set up a loop for if we need to check touches other than the most recent one + // (Only happens if we're dragging the touch) + for (pointerIndex in pointerList) { + val pointerId = event.getPointerId(pointerIndex) + + val xPosition = event.getX(pointerIndex).toInt() + val yPosition = event.getY(pointerIndex).toInt() + + var hasActiveButtons = false + for (button in overlayButtons) { + if (button.trackId == pointerId) { + hasActiveButtons = true + break } - NativeLibrary.onTouchMoved(xPosition.toFloat(), yPosition.toFloat()) } - } - if (isActionUp && !isTouchInputConsumed(pointerId)) { - NativeLibrary.onTouchEvent(0f, 0f, false) + + var hasActiveDpad = false + if (!hasActiveButtons) { + for (dpad in overlayDpads) { + if (dpad.trackId == pointerId) { + hasActiveDpad = true + break + } + } + } + + var hasActiveJoystick = false + if(!hasActiveButtons && !hasActiveDpad){ + for (joystick in overlayJoysticks) { + if (joystick.trackId == pointerId) { + hasActiveJoystick = true + break + } + } + } + + val hasActiveOverlay = hasActiveButtons || hasActiveDpad || hasActiveJoystick + + if (preferences.getBoolean("isTouchEnabled", true) && !hasActiveOverlay) { + if (isActionMove) { + NativeLibrary.onTouchMoved(xPosition.toFloat(), yPosition.toFloat()) + continue + } else if (isActionUp) { + NativeLibrary.onTouchEvent(0f, 0f, false) + break // Up and down actions shouldn't loop + } + + } + + var anyOverlayStateChanged = false + var shouldUpdateView = false + if(!hasActiveDpad && !hasActiveJoystick) { + for (button in overlayButtons) { + val stateChanged = button.updateStatus(event, pointerIndex, hasActiveButtons, this) + if (!stateChanged) { + continue + } + anyOverlayStateChanged = true + + if (button.id == NativeLibrary.ButtonType.BUTTON_SWAP && button.status == NativeLibrary.ButtonState.PRESSED) { + swapScreen() + } + else if (button.id == NativeLibrary.ButtonType.BUTTON_TURBO && button.status == NativeLibrary.ButtonState.PRESSED) { + TurboHelper.toggleTurbo(true) + } + else if (button.id == NativeLibrary.ButtonType.BUTTON_COMBO) { + ComboHelper.comboActivate(button) + } + + NativeLibrary.onGamePadEvent( + NativeLibrary.TouchScreenDevice, + button.id, + button.status + ) + + shouldUpdateView = true + } + } + + if(!hasActiveButtons && !hasActiveJoystick) { + for (dpad in overlayDpads) { + val stateChanged = dpad.updateStatus( + event, + pointerIndex, + hasActiveDpad, + EmulationMenuSettings.dpadSlide, + this + ) + if (!stateChanged) { + continue + } + anyOverlayStateChanged = true + + NativeLibrary.onGamePadEvent( + NativeLibrary.TouchScreenDevice, + dpad.upId, + dpad.upStatus + ) + NativeLibrary.onGamePadEvent( + NativeLibrary.TouchScreenDevice, + dpad.downId, + dpad.downStatus + ) + NativeLibrary.onGamePadEvent( + NativeLibrary.TouchScreenDevice, + dpad.leftId, + dpad.leftStatus + ) + NativeLibrary.onGamePadEvent( + NativeLibrary.TouchScreenDevice, + dpad.rightId, + dpad.rightStatus + ) + + shouldUpdateView = true + } + } + + if(!hasActiveDpad && !hasActiveButtons) { + for (joystick in overlayJoysticks) { + val stateChanged = joystick.updateStatus(event, pointerIndex, hasActiveJoystick, this) + if (!stateChanged) { + continue + } + anyOverlayStateChanged = true + + val axisID = joystick.joystickId + NativeLibrary.onGamePadMoveEvent( + NativeLibrary.TouchScreenDevice, + axisID, + joystick.xAxis, + joystick.yAxis + ) + + shouldUpdateView = true + } + } + + if (shouldUpdateView) { + invalidate() + } + + if (preferences.getBoolean("isTouchEnabled", true) && + isActionDown && + !anyOverlayStateChanged + ) { + // These need to be recalculated because touching the area + // right in the middle of the dpad (between the "buttons") or + // tapping a joystick in a certain way both don't cause + // `anyOverlayStateChanged` to be set to true + var isDpadPressed = false + for (dpad in overlayDpads) { + if (dpad.trackId == pointerId) { + isDpadPressed = true + break + } + } + var isJoystickPressed = false + for (joystick in overlayJoysticks) { + if (joystick.trackId == pointerId) { + isJoystickPressed = true + break + } + } + + if (!isDpadPressed && !isJoystickPressed) { + NativeLibrary.onTouchEvent(xPosition.toFloat(), yPosition.toFloat(), true) + } + } + + // We should only loop here if touch is being dragged + if (!isActionMove) { + break + } + } return true } - private fun isTouchInputConsumed(trackId: Int): Boolean { - overlayButtons.forEach { - if (it.trackId == trackId) { - return true - } - } - overlayDpads.forEach { - if (it.trackId == trackId) { - return true - } - } - overlayJoysticks.forEach { - if (it.trackId == trackId) { - return true - } - } - return false - } - fun onTouchWhileEditing(event: MotionEvent): Boolean { val pointerIndex = event.actionIndex val fingerPositionX = event.getX(pointerIndex).toInt() diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableButton.kt b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableButton.kt index 0e9b0185d..0899074fe 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableButton.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableButton.kt @@ -70,9 +70,8 @@ class InputOverlayDrawableButton( * * @return true if value was changed */ - fun updateStatus(event: MotionEvent, hasActiveButtons: Boolean, overlay: InputOverlay): Boolean { + fun updateStatus(event: MotionEvent, pointerIndex: Int, hasActiveButtons: Boolean, overlay: InputOverlay): Boolean { val buttonSliding = EmulationMenuSettings.buttonSlide - val pointerIndex = event.actionIndex val xPosition = event.getX(pointerIndex).toInt() val yPosition = event.getY(pointerIndex).toInt() val pointerId = event.getPointerId(pointerIndex) @@ -92,7 +91,7 @@ class InputOverlayDrawableButton( if (trackId != pointerId) { return false } - buttonUp(overlay) + buttonUp(overlay, false) return true } @@ -105,11 +104,14 @@ class InputOverlayDrawableButton( if (inside || trackId != pointerId) { return false } + // prevent the first (directly pressed) button to deactivate when sliding off if (buttonSliding == ButtonSlidingMode.Alternative.int && isMotionFirstButton) { return false } - buttonUp(overlay) + + val preserveTrackId = (buttonSliding != ButtonSlidingMode.Disabled.int) + buttonUp(overlay, preserveTrackId) return true } else { // button was not yet pressed @@ -132,10 +134,12 @@ class InputOverlayDrawableButton( overlay.hapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY) } - private fun buttonUp(overlay: InputOverlay) { + private fun buttonUp(overlay: InputOverlay, preserveTrackId: Boolean) { pressedState = false isMotionFirstButton = false - trackId = -1 + if (!preserveTrackId) { + trackId = -1 + } overlay.hapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE) } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableDpad.kt b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableDpad.kt index c032ee3bc..5e902c99b 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableDpad.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableDpad.kt @@ -63,9 +63,8 @@ class InputOverlayDrawableDpad( trackId = -1 } - fun updateStatus(event: MotionEvent, hasActiveButtons: Boolean, dpadSlide: Boolean, overlay: InputOverlay): Boolean { + fun updateStatus(event: MotionEvent, pointerIndex: Int, hasActiveButtons: Boolean, dpadSlide: Boolean, overlay: InputOverlay): Boolean { var isDown = false - val pointerIndex = event.actionIndex val xPosition = event.getX(pointerIndex).toInt() val yPosition = event.getY(pointerIndex).toInt() val pointerId = event.getPointerId(pointerIndex) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableJoystick.kt b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableJoystick.kt index b66118c90..3cc871d30 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableJoystick.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableJoystick.kt @@ -93,8 +93,7 @@ class InputOverlayDrawableJoystick( currentStateBitmapDrawable.draw(canvas) } - fun updateStatus(event: MotionEvent, hasActiveButtons: Boolean, overlay: InputOverlay): Boolean { - val pointerIndex = event.actionIndex + fun updateStatus(event: MotionEvent, pointerIndex: Int, hasActiveButtons: Boolean, overlay: InputOverlay): Boolean { val xPosition = event.getX(pointerIndex).toInt() val yPosition = event.getY(pointerIndex).toInt() val pointerId = event.getPointerId(pointerIndex) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/citra/citra_emu/ui/main/MainActivity.kt index 3e4f36591..e1416bd37 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/ui/main/MainActivity.kt @@ -4,9 +4,13 @@ package org.citra.citra_emu.ui.main +import android.Manifest import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri +import android.os.Build import android.os.Bundle +import android.os.Environment import android.view.View import android.view.ViewGroup.MarginLayoutParams import android.view.WindowManager @@ -36,6 +40,8 @@ import androidx.work.WorkManager import com.google.android.material.color.MaterialColors import com.google.android.material.navigation.NavigationBarView import kotlinx.coroutines.launch +import org.citra.citra_emu.BuildConfig +import org.citra.citra_emu.NativeLibrary import org.citra.citra_emu.R import org.citra.citra_emu.contracts.OpenFileResultContract import org.citra.citra_emu.databinding.ActivityMainBinding @@ -43,14 +49,17 @@ import org.citra.citra_emu.features.settings.model.Settings import org.citra.citra_emu.features.settings.model.SettingsViewModel import org.citra.citra_emu.features.settings.ui.SettingsActivity import org.citra.citra_emu.features.settings.utils.SettingsFile +import org.citra.citra_emu.fragments.GrantMissingFilesystemPermissionFragment import org.citra.citra_emu.fragments.SelectUserDirectoryDialogFragment import org.citra.citra_emu.fragments.UpdateUserDirectoryDialogFragment +import org.citra.citra_emu.utils.BuildUtil import org.citra.citra_emu.utils.CiaInstallWorker import org.citra.citra_emu.utils.CitraDirectoryHelper import org.citra.citra_emu.utils.CitraDirectoryUtils import org.citra.citra_emu.utils.DirectoryInitialization import org.citra.citra_emu.utils.FileBrowserHelper import org.citra.citra_emu.utils.InsetsHelper +import org.citra.citra_emu.utils.RefreshRateUtil import org.citra.citra_emu.utils.PermissionsHandler import org.citra.citra_emu.utils.ThemeUtil import org.citra.citra_emu.viewmodel.GamesViewModel @@ -66,6 +75,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { override var themeId: Int = 0 override fun onCreate(savedInstanceState: Bundle?) { + RefreshRateUtil.enforceRefreshRate(this) + val splashScreen = installSplashScreen() CitraDirectoryUtils.attemptAutomaticUpdateDirectory() splashScreen.setKeepOnScreenCondition { @@ -185,14 +196,53 @@ class MainActivity : AppCompatActivity(), ThemeProvider { val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext) .getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true) - if (!firstTimeSetup && !PermissionsHandler.hasWriteAccess(this) && - !homeViewModel.isPickingUserDir.value - ) { + if (firstTimeSetup) { + return + } + + if (!BuildUtil.isGooglePlayBuild) { + fun requestMissingFilesystemPermission() = + GrantMissingFilesystemPermissionFragment.newInstance() + .show(supportFragmentManager, GrantMissingFilesystemPermissionFragment.TAG) + + if (supportFragmentManager.findFragmentByTag(GrantMissingFilesystemPermissionFragment.TAG) == null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (!Environment.isExternalStorageManager()) { + requestMissingFilesystemPermission() + } + } else { + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) != PackageManager.PERMISSION_GRANTED + ) { + requestMissingFilesystemPermission() + } + } + } + } + + if (homeViewModel.isPickingUserDir.value) { + return + } + + if (!PermissionsHandler.hasWriteAccess(this)) { SelectUserDirectoryDialogFragment.newInstance(this) .show(supportFragmentManager, SelectUserDirectoryDialogFragment.TAG) - } else if (!firstTimeSetup && !homeViewModel.isPickingUserDir.value && CitraDirectoryUtils.needToUpdateManually()) { + return + } else if (CitraDirectoryUtils.needToUpdateManually()) { UpdateUserDirectoryDialogFragment.newInstance(this) .show(supportFragmentManager,UpdateUserDirectoryDialogFragment.TAG) + return + } + + if (!BuildUtil.isGooglePlayBuild) { + if (supportFragmentManager.findFragmentByTag(SelectUserDirectoryDialogFragment.TAG) == null) { + if (NativeLibrary.getUserDirectory() == "") { + SelectUserDirectoryDialogFragment.newInstance(this) + .show(supportFragmentManager, SelectUserDirectoryDialogFragment.TAG) + } + } } } @@ -316,6 +366,17 @@ class MainActivity : AppCompatActivity(), ThemeProvider { return@registerForActivityResult } + if (!BuildUtil.isGooglePlayBuild) { + if (NativeLibrary.getUserDirectory(result) == "") { + SelectUserDirectoryDialogFragment.newInstance( + this, + R.string.invalid_selection, + R.string.invalid_user_directory + ).show(supportFragmentManager, SelectUserDirectoryDialogFragment.TAG) + return@registerForActivityResult + } + } + CitraDirectoryHelper(this@MainActivity, permissionsLost) .showCitraDirectoryDialog(result, buttonState = {}) } @@ -332,7 +393,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } val selectedFiles = - FileBrowserHelper.getSelectedFiles(result, applicationContext, listOf("cia")) + FileBrowserHelper.getSelectedFiles(result, applicationContext, listOf("cia", "zcia")) if (selectedFiles == null) { Toast.makeText(applicationContext, R.string.cia_file_not_found, Toast.LENGTH_LONG) .show() diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/BuildUtil.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/BuildUtil.kt new file mode 100644 index 000000000..71c2a9b76 --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/BuildUtil.kt @@ -0,0 +1,25 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.utils + +import org.citra.citra_emu.BuildConfig + +object BuildUtil { + @Suppress("unused") + object BuildFlavors { + const val GOOGLEPLAY = "googlePlay" + const val VANILLA = "vanilla" + } + + fun assertNotGooglePlay() { + if (isGooglePlayBuild) { + error("Non-GooglePlay code being called in GooglePlay build") + } + } + + @Suppress("SimplifyBooleanWithConstants", "KotlinConstantConditions") + val isGooglePlayBuild = + BuildConfig.FLAVOR == BuildFlavors.GOOGLEPLAY +} diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/DirectoryInitialization.kt index 1365c3722..e41b7c6db 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/DirectoryInitialization.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/DirectoryInitialization.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -28,8 +28,8 @@ object DirectoryInitialization { @Volatile private var directoryState: DirectoryInitializationState? = null var userPath: String? = null - val internalUserPath - get() = CitraApplication.appContext.getExternalFilesDir(null)!!.canonicalPath + val internalUserPath: String + get() = CitraApplication.appContext.filesDir.canonicalPath private val isCitraDirectoryInitializationRunning = AtomicBoolean(false) val context: Context get() = CitraApplication.appContext diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/DiskShaderCacheProgress.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/DiskShaderCacheProgress.kt index a34924a9a..15ea56d3c 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/DiskShaderCacheProgress.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/DiskShaderCacheProgress.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -23,7 +23,7 @@ object DiskShaderCacheProgress { } @JvmStatic - fun loadProgress(stage: LoadCallbackStage, progress: Int, max: Int) { + fun loadProgress(stage: LoadCallbackStage, progress: Int, max: Int, obj: String) { val emulationActivity = NativeLibrary.sEmulationActivity.get() if (emulationActivity == null) { Log.error("[DiskShaderCacheProgress] EmulationActivity not present") @@ -40,7 +40,7 @@ object DiskShaderCacheProgress { ) LoadCallbackStage.Build -> emulationViewModel.updateProgress( - emulationActivity.getString(R.string.building_shaders), + emulationActivity.getString(R.string.building_shaders, obj ), progress, max ) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/DocumentsTree.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/DocumentsTree.kt index e2b015d47..d5c4f791d 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/DocumentsTree.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/DocumentsTree.kt @@ -6,10 +6,12 @@ package org.citra.citra_emu.utils import android.net.Uri import android.provider.DocumentsContract +import androidx.core.net.toUri import androidx.documentfile.provider.DocumentFile import org.citra.citra_emu.CitraApplication import org.citra.citra_emu.model.CheapDocument import java.net.URLDecoder +import java.nio.file.Paths import java.util.StringTokenizer import java.util.concurrent.ConcurrentHashMap @@ -191,7 +193,7 @@ class DocumentsTree { } @Synchronized - fun renameFile(filepath: String, destinationFilename: String?): Boolean { + fun renameFile(filepath: String, destinationFilename: String): Boolean { val node = resolvePath(filepath) ?: return false try { val filename = URLDecoder.decode(destinationFilename, FileUtil.DECODE_METHOD) @@ -203,6 +205,20 @@ class DocumentsTree { } } + @Synchronized + fun moveFile(filename: String, sourceDirPath: String, destDirPath: String): Boolean { + val sourceFileNode = resolvePath(sourceDirPath + "/" + filename) ?: return false + val sourceDirNode = resolvePath(sourceDirPath) ?: return false + val destDirNode = resolvePath(destDirPath) ?: return false + try { + val newUri = DocumentsContract.moveDocument(context.contentResolver, sourceFileNode.uri!!, sourceDirNode.uri!!, destDirNode.uri!!) + updateDocumentLocation("$sourceDirPath/$filename", "$destDirPath/$filename") + return true + } catch (e: Exception) { + error("[DocumentsTree]: Cannot move file, error: " + e.message) + } + } + @Synchronized fun deleteDocument(filepath: String): Boolean { val node = resolvePath(filepath) ?: return false @@ -219,6 +235,29 @@ class DocumentsTree { } } + @Synchronized + fun updateDocumentLocation(sourcePath: String, destinationPath: String): Boolean { + val sourceNode = resolvePath(sourcePath) + val newName = Paths.get(destinationPath).fileName.toString() + val parentPath = Paths.get(destinationPath).parent.toString() + val newParent = resolvePath(parentPath) + val newUri = (getUri(parentPath).toString() + "%2F$newName").toUri() // <- Is there a better way? + + if (sourceNode == null || newParent == null) { + return false + } + + sourceNode.parent!!.removeChild(sourceNode) + + sourceNode.name = newName + sourceNode.parent = newParent + sourceNode.uri = newUri + + newParent.addChild(sourceNode) + + return true + } + @Synchronized private fun resolvePath(filepath: String): DocumentsNode? { root ?: return null diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationLifecycleUtil.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationLifecycleUtil.kt index 8f3b5dc07..5fafb7bed 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationLifecycleUtil.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationLifecycleUtil.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -18,15 +18,27 @@ object EmulationLifecycleUtil { } fun addShutdownHook(hook: Runnable) { - shutdownHooks.add(hook) + if (shutdownHooks.contains(hook)) { + Log.warning("[EmulationLifecycleUtil] Tried to add shutdown hook for function that already existed. Skipping.") + } else { + shutdownHooks.add(hook) + } } fun addPauseResumeHook(hook: Runnable) { - pauseResumeHooks.add(hook) + if (pauseResumeHooks.contains(hook)) { + Log.warning("[EmulationLifecycleUtil] Tried to add pause resume hook for function that already existed. Skipping.") + } else { + pauseResumeHooks.add(hook) + } } - fun clear() { - pauseResumeHooks.clear() - shutdownHooks.clear() + fun removeHook(hook: Runnable) { + if (pauseResumeHooks.contains(hook)) { + pauseResumeHooks.remove(hook) + } + if (shutdownHooks.contains(hook)) { + shutdownHooks.remove(hook) + } } } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationMenuSettings.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationMenuSettings.kt index 184964549..6ff08fa37 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationMenuSettings.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationMenuSettings.kt @@ -35,13 +35,6 @@ object EmulationMenuSettings { .apply() } - var showPerformanceOverlay: Boolean - get() = preferences.getBoolean("EmulationMenuSettings_showPerformanceOverlay", false) - set(value) { - preferences.edit() - .putBoolean("EmulationMenuSettings_showPerformanceOverlay", value) - .apply() - } var hapticFeedback: Boolean get() = preferences.getBoolean("EmulationMenuSettings_HapticFeedback", true) set(value) { diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/FileUtil.kt index 402a23857..9d9063c59 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/FileUtil.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/FileUtil.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -11,6 +11,7 @@ import android.net.Uri import android.provider.DocumentsContract import android.system.Os import android.util.Pair +import androidx.core.net.toUri import androidx.documentfile.provider.DocumentFile import org.citra.citra_emu.CitraApplication import org.citra.citra_emu.model.CheapDocument @@ -434,6 +435,20 @@ object FileUtil { return false } + @JvmStatic + fun moveFile(filename: String, sourceDirUriString: String, destDirUriString: String): Boolean { + try { + val sourceFileUri = ("$sourceDirUriString%2F$filename").toUri() + val sourceDirUri = sourceDirUriString.toUri() + val destDirUri = destDirUriString.toUri() + DocumentsContract.moveDocument(context.contentResolver, sourceFileUri, sourceDirUri, destDirUri) + return true + } catch (e: Exception) { + Log.error("[FileUtil]: Cannot move file, error: " + e.message) + } + return false + } + @JvmStatic fun deleteDocument(path: String): Boolean { try { diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/GameHelper.kt index ffbeaf394..90b011114 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/GameHelper.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/GameHelper.kt @@ -88,8 +88,10 @@ object GameHelper { isInstalled, gameInfo?.isSystemTitle() ?: false, gameInfo?.getIsVisibleSystemTitle() ?: false, + gameInfo?.getIsInsertable() ?: false, gameInfo?.getIcon(), gameInfo?.getFileType() ?: "", + gameInfo?.getFileType()?.contains("(Z)") ?: false, if (FileUtil.isNativePath(filePath)) { CitraApplication.documentsTree.getFilename(filePath) } else { diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/PermissionsHandler.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/PermissionsHandler.kt index 8f1e9193f..6ea04c779 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/PermissionsHandler.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/PermissionsHandler.kt @@ -8,6 +8,9 @@ import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.net.Uri +import android.os.Build +import android.provider.DocumentsContract +import androidx.activity.result.ActivityResultLauncher import androidx.preference.PreferenceManager import androidx.documentfile.provider.DocumentFile import org.citra.citra_emu.CitraApplication @@ -48,4 +51,17 @@ object PermissionsHandler { fun setCitraDirectory(uriString: String?) = preferences.edit().putString(CITRA_DIRECTORY, uriString).apply() + + fun compatibleSelectDirectory(activityLauncher: ActivityResultLauncher) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + activityLauncher.launch(null) + } else { + val initialUri = DocumentsContract.buildRootUri( + "com.android.externalstorage.documents", + "primary" + ) + activityLauncher.launch(initialUri) + } + + } } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/RefreshRateUtil.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/RefreshRateUtil.kt new file mode 100644 index 000000000..675fe6702 --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/RefreshRateUtil.kt @@ -0,0 +1,53 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.utils +import android.app.Activity +import android.os.Build +import androidx.annotation.RequiresApi + +object RefreshRateUtil { + // Since Android 15, the OS automatically runs apps categorized as games with a + // 60hz refresh rate by default, regardless of the refresh rate set by the user. + // + // This function sets the refresh rate to either the maximum allowed refresh rate or + // 60hz depending on the value of the `sixtyHz` parameter. + // + // Note: This isn't always the maximum refresh rate that the display is *capable of*, + // but is instead the refresh rate chosen by the user in the Android system settings. + // For example, if the user selected 120hz in the settings, but the display is capable + // of 144hz, 120hz will be treated as the maximum within this function. + fun enforceRefreshRate(activity: Activity, sixtyHz: Boolean = false) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + return + } + + val display = activity.display + val window = activity.window + + display?.let { + // Get all supported modes and find the one with the highest refresh rate + val supportedModes = it.supportedModes + val maxRefreshRate = supportedModes.maxByOrNull { mode -> mode.refreshRate } + + if (maxRefreshRate == null) { + return + } + + var newModeId: Int? + if (sixtyHz) { + newModeId = supportedModes.firstOrNull { mode -> mode.refreshRate == 60f }?.modeId + } else { + // Set the preferred display mode to the one with the highest refresh rate + newModeId = maxRefreshRate.modeId + } + + if (newModeId == null) { + return + } + + window.attributes.preferredDisplayModeId = newModeId + } + } +} \ No newline at end of file diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/RemovableStorageHelper.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/RemovableStorageHelper.kt new file mode 100644 index 000000000..82c4b9ffd --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/RemovableStorageHelper.kt @@ -0,0 +1,31 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.utils + +import org.citra.citra_emu.utils.BuildUtil +import java.io.File + +object RemovableStorageHelper { + // This really shouldn't be necessary, but the Android API seemingly + // doesn't have a way of doing this? + fun getRemovableStoragePath(idString: String): String? { + BuildUtil.assertNotGooglePlay() + + // On certain Android flavours the external storage mount location can + // vary, so add extra cases here if we discover them. + val possibleMountPaths = listOf("/mnt/media_rw/$idString", "/storage/$idString") + + for (mountPath in possibleMountPaths) { + val pathFile = File(mountPath); + if (pathFile.exists()) { + // TODO: Cache which mount location is being used for the remainder of the + // session, as it should never change. -OS + return pathFile.absolutePath + } + } + + return null + } +} diff --git a/src/android/app/src/main/java/org/citra/citra_emu/viewmodel/CompressProgressDialogViewModel.kt b/src/android/app/src/main/java/org/citra/citra_emu/viewmodel/CompressProgressDialogViewModel.kt new file mode 100644 index 000000000..7a6e71e52 --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/viewmodel/CompressProgressDialogViewModel.kt @@ -0,0 +1,33 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.viewmodel + +import androidx.lifecycle.ViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +object CompressProgressDialogViewModel: ViewModel() { + private val _progress = MutableStateFlow(0) + val progress = _progress.asStateFlow() + + private val _total = MutableStateFlow(0) + val total = _total.asStateFlow() + + private val _message = MutableStateFlow("") + val message = _message.asStateFlow() + + fun update(totalBytes: Long, currentBytes: Long) { + val percent = ((currentBytes * 100L) / totalBytes).coerceIn(0L, 100L).toInt() + _total.value = 100 + _progress.value = percent + _message.value = "" + } + + fun reset() { + _progress.value = 0 + _total.value = 0 + _message.value = "" + } +} \ No newline at end of file diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index f4c25d1f0..6d310fea6 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -147,7 +147,7 @@ void Config::ReadValues() { ReadSetting("Renderer", Settings::values.use_shader_jit); ReadSetting("Renderer", Settings::values.resolution_factor); ReadSetting("Renderer", Settings::values.use_disk_shader_cache); - ReadSetting("Renderer", Settings::values.use_vsync_new); + ReadSetting("Renderer", Settings::values.use_vsync); ReadSetting("Renderer", Settings::values.texture_filter); ReadSetting("Renderer", Settings::values.texture_sampling); ReadSetting("Renderer", Settings::values.turbo_limit); @@ -172,9 +172,11 @@ void Config::ReadValues() { ReadSetting("Renderer", Settings::values.bg_red); ReadSetting("Renderer", Settings::values.bg_green); ReadSetting("Renderer", Settings::values.bg_blue); + ReadSetting("Renderer", Settings::values.custom_second_layer_opacity); ReadSetting("Renderer", Settings::values.delay_game_render_thread_us); ReadSetting("Renderer", Settings::values.disable_right_eye_render); - + ReadSetting("Renderer", Settings::values.swap_eyes_3d); + ReadSetting("Renderer", Settings::values.render_3d_which_display); // Layout // Somewhat inelegant solution to ensure layout value is between 0 and 5 on read // since older config files may have other values @@ -209,6 +211,9 @@ void Config::ReadValues() { static_cast(sdl2_config->GetInteger( "Layout", "portrait_layout_option", static_cast(Settings::PortraitLayoutOption::PortraitTopFullWidth))); + Settings::values.secondary_display_layout = static_cast( + sdl2_config->GetInteger("Layout", "secondary_display_layout", + static_cast(Settings::SecondaryDisplayLayout::None))); ReadSetting("Layout", Settings::values.custom_portrait_top_x); ReadSetting("Layout", Settings::values.custom_portrait_top_y); ReadSetting("Layout", Settings::values.custom_portrait_top_width); @@ -258,6 +263,7 @@ void Config::ReadValues() { ReadSetting("System", Settings::values.plugin_loader_enabled); ReadSetting("System", Settings::values.allow_plugin_loader); ReadSetting("System", Settings::values.steps_per_hour); + ReadSetting("System", Settings::values.apply_region_free_patch); // Camera using namespace Service::CAM; diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h index fbf4ce030..08eaf3283 100644 --- a/src/android/app/src/main/jni/default_ini.h +++ b/src/android/app/src/main/jni/default_ini.h @@ -134,10 +134,10 @@ use_shader_jit = # 0 (default): Game Controlled, 1: Nearest Neighbor, 2: Linear texture_sampling = -# Forces VSync on the display thread. Usually doesn't impact performance, but on some drivers it can -# so only turn this off if you notice a speed difference. -# 0: Off, 1 (default): On -use_vsync_new = +# Forces VSync on the display thread. Can cause input delay, so only turn this on +# if you have screen tearing, which is unusual on Android +# 0 (default): Off, 1: On +use_vsync = # Reduce stuttering by storing and loading generated shaders to disk # 0: Off, 1 (default. On) @@ -148,10 +148,6 @@ use_disk_shader_cache = # factor for the 3DS resolution resolution_factor = -# Whether to enable V-Sync (caps the framerate at 60FPS) or not. -# 0 (default): Off, 1: On -vsync_enabled = - # Turns on the frame limiter, which will limit frames output to the target game speed # 0: Off, 1: On (default) use_frame_limit = @@ -170,14 +166,27 @@ bg_red = bg_blue = bg_green = +# Opacity of second layer when using custom layout option (bottom screen unless swapped). Useful if positioning on top of the first layer. +custom_second_layer_opacity = + # Whether and how Stereoscopic 3D should be rendered -# 0 (default): Off, 1: Side by Side, 2: Reverse Side by Side, 3: Anaglyph, 4: Interlaced, 5: Reverse Interlaced, 6: Cardboard VR +# 0: Off, 1: Half Width Side by Side, 2 (default): Full Width Side by Side, 3: Anaglyph, 4: Interlaced, 5: Reverse Interlaced, 6: Cardboard VR +# 0 is no longer supported in the interface, as using render_3d_which_display = 0 has the same effect, but supported here for backwards compatibility render_3d = # Change 3D Intensity # 0 - 255: Intensity. 0 (default) factor_3d = +# Swap Eyes in 3d +# true: Swap eyes, false (default): Do not swap eyes +swap_eyes_3d = + +# Which Display to render 3d mode to +# 0 (default) - None. Equivalent to render_3d=0 +# 1: Both, 2: Primary Only, 3: Secondary Only +render_3d_which_display = + # The name of the post processing shader to apply. # Loaded from shaders if render_3d is off or side by side. pp_shader_name = @@ -288,6 +297,15 @@ swap_screen = # 0 (default): Off, 1: On expand_to_cutout_area = +# Secondary Display Layout +# What the game should do if a secondary display is connected physically or using +# Miracast / Chromecast screen mirroring +# 0 (default) - Use System Default (mirror) +# 1 - Show Top Screen Only +# 2 - Show Bottom Screen Only +# 3 - Show both screens side by side +secondary_display_layout = + # Screen placement settings when using Cardboard VR (render3d = 4) # 30 - 100: Screen size as a percentage of the viewport. 85 (default) cardboard_screen_size = @@ -405,6 +423,11 @@ steps_per_hour = plugin_loader = allow_plugin_loader = +# Apply region free patch to installed applications +# Patches the region of installed applications to be region free, so that they always appear on the home menu. +# 0: Disabled, 1 (default): Enabled +apply_region_free_patch = + [Camera] # Which camera engine to use for the right outer camera # blank: a dummy camera that always returns black image diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index b33c734f5..8458a4f2b 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -49,16 +49,16 @@ void EmuWindow_Android::OnFramebufferSizeChanged() { const int bigger{window_width > window_height ? window_width : window_height}; const int smaller{window_width < window_height ? window_width : window_height}; - if (is_portrait_mode) { + if (is_portrait_mode && !is_secondary) { UpdateCurrentFramebufferLayout(smaller, bigger, is_portrait_mode); } else { UpdateCurrentFramebufferLayout(bigger, smaller, is_portrait_mode); } } -EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) : host_window{surface} { +EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface, bool is_secondary) + : EmuWindow{is_secondary}, host_window(surface) { LOG_DEBUG(Frontend, "Initializing EmuWindow_Android"); - if (!surface) { LOG_CRITICAL(Frontend, "surface is nullptr"); return; diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index 4266fd1bb..23c50f9a9 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -1,10 +1,11 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include +#include #include "core/frontend/emu_window.h" namespace Core { @@ -13,7 +14,7 @@ class System; class EmuWindow_Android : public Frontend::EmuWindow { public: - EmuWindow_Android(ANativeWindow* surface); + EmuWindow_Android(ANativeWindow* surface, bool is_secondary = false); ~EmuWindow_Android(); /// Called by the onSurfaceChanges() method to change the surface @@ -30,7 +31,12 @@ public: void DoneCurrent() override; virtual void TryPresenting() {} - + // EGL Context must be shared + // could probably use the existing + // SharedContext for this instead, this is maybe temporary + virtual EGLContext* GetEGLContext() { + return nullptr; + } virtual void StopPresenting() {} protected: diff --git a/src/android/app/src/main/jni/emu_window/emu_window_gl.cpp b/src/android/app/src/main/jni/emu_window/emu_window_gl.cpp index 25db55bbe..5c1b0ccbd 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window_gl.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window_gl.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -72,8 +72,9 @@ private: EGLContext egl_context{}; }; -EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativeWindow* surface) - : EmuWindow_Android{surface}, system{system_} { +EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativeWindow* surface, + bool is_secondary, EGLContext* sharedContext) + : EmuWindow_Android{surface, is_secondary}, system{system_} { if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) { LOG_CRITICAL(Frontend, "eglGetDisplay() failed"); return; @@ -96,9 +97,11 @@ EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativ if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) { return; } - - if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data()); - egl_context == EGL_NO_CONTEXT) { + if (sharedContext) { + egl_context = *sharedContext; + } else if (egl_context = + eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data()); + egl_context == EGL_NO_CONTEXT) { LOG_CRITICAL(Frontend, "eglCreateContext() failed"); return; } @@ -119,7 +122,7 @@ EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativ LOG_CRITICAL(Frontend, "gladLoadGLES2Loader() failed"); return; } - if (!eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0)) { + if (!eglSwapInterval(egl_display, Settings::values.use_vsync ? 1 : 0)) { LOG_CRITICAL(Frontend, "eglSwapInterval() failed"); return; } @@ -127,6 +130,10 @@ EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativ OnFramebufferSizeChanged(); } +EGLContext* EmuWindow_Android_OpenGL::GetEGLContext() { + return &egl_context; +} + bool EmuWindow_Android_OpenGL::CreateWindowSurface() { if (!host_window) { return true; @@ -204,14 +211,14 @@ void EmuWindow_Android_OpenGL::TryPresenting() { return; } if (presenting_state == PresentingState::Initial) [[unlikely]] { - eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); presenting_state = PresentingState::Running; } if (presenting_state != PresentingState::Running) [[unlikely]] { return; } - eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0); - system.GPU().Renderer().TryPresent(0); + eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + eglSwapInterval(egl_display, Settings::values.use_vsync ? 1 : 0); + system.GPU().Renderer().TryPresent(0, is_secondary); eglSwapBuffers(egl_display, egl_surface); } diff --git a/src/android/app/src/main/jni/emu_window/emu_window_gl.h b/src/android/app/src/main/jni/emu_window/emu_window_gl.h index a705174ac..fcbfa1147 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window_gl.h +++ b/src/android/app/src/main/jni/emu_window/emu_window_gl.h @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -19,13 +19,14 @@ struct ANativeWindow; class EmuWindow_Android_OpenGL : public EmuWindow_Android { public: - EmuWindow_Android_OpenGL(Core::System& system, ANativeWindow* surface); + EmuWindow_Android_OpenGL(Core::System& system, ANativeWindow* surface, bool is_secondary, + EGLContext* sharedContext = NULL); ~EmuWindow_Android_OpenGL() override = default; void TryPresenting() override; void StopPresenting() override; void PollEvents() override; - + EGLContext* GetEGLContext() override; std::unique_ptr CreateSharedContext() const override; private: diff --git a/src/android/app/src/main/jni/emu_window/emu_window_vk.cpp b/src/android/app/src/main/jni/emu_window/emu_window_vk.cpp index 238e1ae1a..3cc24bc34 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window_vk.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window_vk.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -24,8 +24,9 @@ private: }; EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan( - ANativeWindow* surface, std::shared_ptr driver_library_) - : EmuWindow_Android{surface}, driver_library{driver_library_} { + ANativeWindow* surface, std::shared_ptr driver_library_, + bool is_secondary) + : EmuWindow_Android{surface, is_secondary}, driver_library{driver_library_} { CreateWindowSurface(); if (core_context = CreateSharedContext(); !core_context) { diff --git a/src/android/app/src/main/jni/emu_window/emu_window_vk.h b/src/android/app/src/main/jni/emu_window/emu_window_vk.h index fe54f9a36..365a1916a 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window_vk.h +++ b/src/android/app/src/main/jni/emu_window/emu_window_vk.h @@ -1,4 +1,4 @@ -// Copyright 2022 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -11,7 +11,8 @@ struct ANativeWindow; class EmuWindow_Android_Vulkan : public EmuWindow_Android { public: EmuWindow_Android_Vulkan(ANativeWindow* surface, - std::shared_ptr driver_library); + std::shared_ptr driver_library, + bool is_secondary); ~EmuWindow_Android_Vulkan() override = default; void PollEvents() override {} diff --git a/src/android/app/src/main/jni/game_info.cpp b/src/android/app/src/main/jni/game_info.cpp index a8c27e53a..7ff043fff 100644 --- a/src/android/app/src/main/jni/game_info.cpp +++ b/src/android/app/src/main/jni/game_info.cpp @@ -25,14 +25,24 @@ struct GameInfoData { bool loaded = false; bool is_encrypted = false; std::string file_type = ""; + bool is_insertable = false; }; GameInfoData* GetNewGameInfoData(const std::string& path) { std::unique_ptr loader = Loader::GetLoader(path); u64 program_id = 0; bool is_encrypted = false; + Loader::ResultStatus result{}; + if (loader) { + result = loader->ReadProgramId(program_id); + if (result == Loader::ResultStatus::ErrorNotImplemented) { + // This can happen for 3DSX and ELF files. + program_id = 0; + result = Loader::ResultStatus::Success; + } + } - if (!loader || loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) { + if (!loader || result != Loader::ResultStatus::Success) { GameInfoData* gid = new GameInfoData(); memset(&gid->smdh, 0, sizeof(Loader::SMDH)); return gid; @@ -80,6 +90,7 @@ GameInfoData* GetNewGameInfoData(const std::string& path) { gid->is_encrypted = is_encrypted; gid->title_id = program_id; gid->file_type = Loader::GetFileTypeString(loader->GetFileType(), loader->IsFileCompressed()); + gid->is_insertable = loader->GetFileType() == Loader::FileType::CCI; return gid; } @@ -213,7 +224,7 @@ jboolean Java_org_citra_citra_1emu_model_GameInfo_getIsVisibleSystemTitle(JNIEnv return false; } - return smdh->flags & Loader::SMDH::Flags::Visible; + return smdh->flags.visible; } jstring Java_org_citra_citra_1emu_model_GameInfo_getFileType(JNIEnv* env, jobject obj) { @@ -221,4 +232,7 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getFileType(JNIEnv* env, jobjec return ToJString(env, file_type); } +jboolean Java_org_citra_citra_1emu_model_GameInfo_getIsInsertable(JNIEnv* env, jobject obj) { + return GetPointer(env, obj)->is_insertable; +} } diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp index 8bc0f976e..197e81aaa 100644 --- a/src/android/app/src/main/jni/id_cache.cpp +++ b/src/android/app/src/main/jni/id_cache.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -40,6 +40,7 @@ static jfieldID s_game_info_pointer; static jclass s_disk_cache_progress_class; static jmethodID s_disk_cache_load_progress; +static jmethodID s_compress_progress_method; static std::unordered_map s_java_load_callback_stages; static jclass s_cia_install_helper_class; @@ -131,6 +132,10 @@ jmethodID GetDiskCacheLoadProgress() { return s_disk_cache_load_progress; } +jmethodID GetCompressProgressMethod() { + return s_compress_progress_method; +} + jobject GetJavaLoadCallbackStage(VideoCore::LoadCallbackStage stage) { const auto it = s_java_load_callback_stages.find(stage); ASSERT_MSG(it != s_java_load_callback_stages.end(), "Invalid LoadCallbackStage: {}", stage); @@ -202,9 +207,12 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { env->NewGlobalRef(env->FindClass("org/citra/citra_emu/utils/DiskShaderCacheProgress"))); jclass load_callback_stage_class = env->FindClass("org/citra/citra_emu/utils/DiskShaderCacheProgress$LoadCallbackStage"); - s_disk_cache_load_progress = env->GetStaticMethodID( - s_disk_cache_progress_class, "loadProgress", - "(Lorg/citra/citra_emu/utils/DiskShaderCacheProgress$LoadCallbackStage;II)V"); + s_disk_cache_load_progress = + env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", + "(Lorg/citra/citra_emu/utils/" + "DiskShaderCacheProgress$LoadCallbackStage;IILjava/lang/String;)V"); + s_compress_progress_method = + env->GetStaticMethodID(s_native_library_class, "onCompressProgress", "(JJ)V"); // Initialize LoadCallbackStage map const auto to_java_load_callback_stage = [env, load_callback_stage_class](const std::string& stage) { diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h index 71a1cb67c..d7aeb8074 100644 --- a/src/android/app/src/main/jni/id_cache.h +++ b/src/android/app/src/main/jni/id_cache.h @@ -1,4 +1,4 @@ -// Copyright 2019 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -40,6 +40,7 @@ jfieldID GetGameInfoPointer(); jclass GetDiskCacheProgressClass(); jmethodID GetDiskCacheLoadProgress(); +jmethodID GetCompressProgressMethod(); jobject GetJavaLoadCallbackStage(VideoCore::LoadCallbackStage stage); jclass GetCiaInstallHelperClass(); diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 9fddc5c32..84a4fd3ce 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -16,11 +16,13 @@ #include #include "audio_core/dsp_interface.h" #include "common/arch.h" + #if CITRA_ARCH(arm64) #include "common/aarch64/cpu_detect.h" #elif CITRA_ARCH(x86_64) #include "common/x64/cpu_detect.h" #endif + #include "common/common_paths.h" #include "common/dynamic_library/dynamic_library.h" #include "common/file_util.h" @@ -32,10 +34,12 @@ #include "common/scope_exit.h" #include "common/settings.h" #include "common/string_util.h" +#include "common/zstd_compression.h" #include "core/core.h" #include "core/frontend/applets/default_applets.h" #include "core/frontend/camera/factory.h" #include "core/hle/service/am/am.h" +#include "core/hle/service/fs/archive.h" #include "core/hle/service/nfc/nfc.h" #include "core/hw/unique_data.h" #include "core/loader/loader.h" @@ -47,12 +51,18 @@ #include "jni/camera/ndk_camera.h" #include "jni/camera/still_image_camera.h" #include "jni/config.h" + #ifdef ENABLE_OPENGL #include "jni/emu_window/emu_window_gl.h" #endif + #ifdef ENABLE_VULKAN #include "jni/emu_window/emu_window_vk.h" +#if CITRA_ARCH(arm64) +#include #endif +#endif + #include "jni/id_cache.h" #include "jni/input_manager.h" #include "jni/ndk_motion.h" @@ -61,16 +71,25 @@ #include "video_core/gpu.h" #include "video_core/renderer_base.h" -#if defined(ENABLE_VULKAN) && CITRA_ARCH(arm64) -#include -#endif - namespace { -ANativeWindow* s_surf; +ANativeWindow* s_surface; +ANativeWindow* s_secondary_surface; + +enum class CompressionStatus : jint { + Success = 0, + Compress_Unsupported = 1, + Compress_AlreadyCompressed = 2, + Compress_Failed = 3, + Decompress_Unsupported = 4, + Decompress_NotCompressed = 5, + Decompress_Failed = 6, + Installed_Application = 7, +}; std::shared_ptr vulkan_library{}; std::unique_ptr window; +std::unique_ptr secondary_window; std::unique_ptr play_time_manager; jlong ptm_current_title_id = std::numeric_limits::max(); // Arbitrary default value @@ -82,6 +101,8 @@ std::mutex paused_mutex; std::mutex running_mutex; std::condition_variable running_cv; +std::string inserted_cartridge; + } // Anonymous namespace static jobject ToJavaCoreError(Core::System::ResultStatus result) { @@ -89,6 +110,7 @@ static jobject ToJavaCoreError(Core::System::ResultStatus result) { {Core::System::ResultStatus::ErrorSystemFiles, "ErrorSystemFiles"}, {Core::System::ResultStatus::ErrorSavestate, "ErrorSavestate"}, {Core::System::ResultStatus::ErrorArticDisconnected, "ErrorArticDisconnected"}, + {Core::System::ResultStatus::ErrorN3DSApplication, "ErrorN3DSApplication"}, {Core::System::ResultStatus::ErrorUnknown, "ErrorUnknown"}, }; @@ -108,12 +130,13 @@ static bool HandleCoreError(Core::System::ResultStatus result, const std::string env->NewStringUTF(details.c_str())) != JNI_FALSE; } -static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) { +static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max, + const std::string& object) { JNIEnv* env = IDCache::GetEnvForThread(); env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(), IDCache::GetDiskCacheLoadProgress(), IDCache::GetJavaLoadCallbackStage(stage), static_cast(progress), - static_cast(max)); + static_cast(max), env->NewStringUTF(object.c_str())); } static Camera::NDK::Factory* g_ndk_factory{}; @@ -124,8 +147,20 @@ static void TryShutdown() { } window->DoneCurrent(); - Core::System::GetInstance().Shutdown(); + if (secondary_window) { + secondary_window->DoneCurrent(); + } + + Core::System& system{Core::System::GetInstance()}; + + system.Shutdown(); + system.EjectCartridge(); + window.reset(); + if (secondary_window) { + secondary_window.reset(); + } + InputManager::Shutdown(); MicroProfileShutdown(); } @@ -150,16 +185,26 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { Core::System& system{Core::System::GetInstance()}; + if (!inserted_cartridge.empty()) { + system.InsertCartridge(inserted_cartridge); + } + const auto graphics_api = Settings::values.graphics_api.GetValue(); + EGLContext* shared_context; switch (graphics_api) { #ifdef ENABLE_OPENGL case Settings::GraphicsAPI::OpenGL: - window = std::make_unique(system, s_surf); + window = std::make_unique(system, s_surface, false); + shared_context = window->GetEGLContext(); + secondary_window = std::make_unique(system, s_secondary_surface, + true, shared_context); break; #endif #ifdef ENABLE_VULKAN case Settings::GraphicsAPI::Vulkan: - window = std::make_unique(s_surf, vulkan_library); + window = std::make_unique(s_surface, vulkan_library, false); + secondary_window = + std::make_unique(s_secondary_surface, vulkan_library, true); break; #endif default: @@ -167,11 +212,17 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { "Unknown or unsupported graphics API {}, falling back to available default", graphics_api); #ifdef ENABLE_OPENGL - window = std::make_unique(system, s_surf); + window = std::make_unique(system, s_surface, false); + shared_context = window->GetEGLContext(); + secondary_window = std::make_unique(system, s_secondary_surface, + true, shared_context); + #elif ENABLE_VULKAN - window = std::make_unique(s_surf, vulkan_library); + window = std::make_unique(s_surface, vulkan_library, false); + secondary_window = + std::make_unique(s_secondary_surface, vulkan_library, true); #else -// TODO: Add a null renderer backend for this, perhaps. + // TODO: Add a null renderer backend for this, perhaps. #error "At least one renderer must be enabled." #endif break; @@ -208,7 +259,8 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { InputManager::Init(); window->MakeCurrent(); - const Core::System::ResultStatus load_result{system.Load(*window, filepath)}; + const Core::System::ResultStatus load_result{ + system.Load(*window, filepath, secondary_window.get())}; if (load_result != Core::System::ResultStatus::Success) { return load_result; } @@ -216,13 +268,15 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { stop_run = false; pause_emulation = false; - LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); + LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0, ""); + + system.GPU().ApplyPerProgramSettings(program_id); std::unique_ptr cpu_context; system.GPU().Renderer().Rasterizer()->LoadDefaultDiskResources(stop_run, &LoadDiskCacheProgress); - LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); + LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0, ""); SCOPE_EXIT({ TryShutdown(); }); @@ -304,28 +358,68 @@ extern "C" { void Java_org_citra_citra_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, [[maybe_unused]] jobject obj, jobject surf) { - s_surf = ANativeWindow_fromSurface(env, surf); + s_surface = ANativeWindow_fromSurface(env, surf); bool notify = false; if (window) { - notify = window->OnSurfaceChanged(s_surf); + notify = window->OnSurfaceChanged(s_surface); } auto& system = Core::System::GetInstance(); if (notify && system.IsPoweredOn()) { - system.GPU().Renderer().NotifySurfaceChanged(); + system.GPU().Renderer().NotifySurfaceChanged(false); } LOG_INFO(Frontend, "Surface changed"); } +void Java_org_citra_citra_1emu_NativeLibrary_secondarySurfaceChanged(JNIEnv* env, + [[maybe_unused]] jobject obj, + jobject surf) { + auto& system = Core::System::GetInstance(); + + if (s_secondary_surface) { + ANativeWindow_release(s_secondary_surface); + s_secondary_surface = nullptr; + } + s_secondary_surface = ANativeWindow_fromSurface(env, surf); + if (!s_secondary_surface) { + return; + } + + bool notify = false; + if (secondary_window) { + // Second window already created, so update it + notify = secondary_window->OnSurfaceChanged(s_secondary_surface); + } else { + LOG_WARNING(Frontend, + "Second Window does not exist in native.cpp but surface changed. Ignoring."); + } + + if (notify && system.IsPoweredOn()) { + system.GPU().Renderer().NotifySurfaceChanged(true); + } + + LOG_INFO(Frontend, "Secondary Surface changed"); +} + +void Java_org_citra_citra_1emu_NativeLibrary_secondarySurfaceDestroyed( + JNIEnv* env, [[maybe_unused]] jobject obj) { + if (s_secondary_surface != nullptr) { + ANativeWindow_release(s_secondary_surface); + s_secondary_surface = nullptr; + } + + LOG_INFO(Frontend, "Secondary Surface Destroyed"); +} + void Java_org_citra_citra_1emu_NativeLibrary_surfaceDestroyed([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) { - if (s_surf != nullptr) { - ANativeWindow_release(s_surf); - s_surf = nullptr; + if (s_surface != nullptr) { + ANativeWindow_release(s_surface); + s_surface = nullptr; if (window) { - window->OnSurfaceChanged(s_surf); + window->OnSurfaceChanged(s_surface); } } } @@ -338,6 +432,9 @@ void Java_org_citra_citra_1emu_NativeLibrary_doFrame([[maybe_unused]] JNIEnv* en if (window) { window->TryPresenting(); } + if (secondary_window) { + secondary_window->TryPresenting(); + } } void JNICALL Java_org_citra_citra_1emu_NativeLibrary_initializeGpuDriver( @@ -392,6 +489,163 @@ jstring Java_org_citra_citra_1emu_NativeLibrary_getHomeMenuPath(JNIEnv* env, return ToJString(env, ""); } +static CompressionStatus GetCompressFileInfo(Loader::AppLoader::CompressFileInfo& out_info, + size_t& out_frame_size, const std::string& filepath, + bool compress) { + + if (Service::FS::IsInstalledApplication(filepath)) { + return CompressionStatus::Installed_Application; + } + + Loader::AppLoader::CompressFileInfo compress_info{}; + compress_info.is_supported = false; + size_t frame_size{}; + auto loader = Loader::GetLoader(filepath); + if (loader) { + compress_info = loader->GetCompressFileInfo(); + frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_FRAME_SIZE; + } else { + bool is_compressed = false; + if (Service::AM::CheckCIAToInstall(filepath, is_compressed, compress ? true : false) == + Service::AM::InstallStatus::Success) { + compress_info.is_supported = true; + compress_info.is_compressed = is_compressed; + compress_info.recommended_compressed_extension = "zcia"; + compress_info.recommended_uncompressed_extension = "cia"; + compress_info.underlying_magic = std::array({'C', 'I', 'A', '\0'}); + frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_CIA_FRAME_SIZE; + if (compress) { + auto meta_info = Service::AM::GetCIAInfos(filepath); + if (meta_info.Succeeded()) { + const auto& meta_info_val = meta_info.Unwrap(); + std::vector value(sizeof(Service::AM::TitleInfo)); + memcpy(value.data(), &meta_info_val.first, sizeof(Service::AM::TitleInfo)); + compress_info.default_metadata.emplace("titleinfo", value); + if (meta_info_val.second) { + value.resize(sizeof(Loader::SMDH)); + memcpy(value.data(), meta_info_val.second.get(), sizeof(Loader::SMDH)); + compress_info.default_metadata.emplace("smdh", value); + } + } + } + } + } + + if (!compress_info.is_supported) { + LOG_ERROR(Frontend, + "Error {} file {}, the selected file is not a compatible 3DS ROM format or is " + "encrypted.", + compress ? "compressing" : "decompressing", filepath); + return compress ? CompressionStatus::Compress_Unsupported + : CompressionStatus::Decompress_Unsupported; + } + if (compress_info.is_compressed && compress) { + LOG_ERROR(Frontend, "Error compressing file {}, the selected file is already compressed", + filepath); + return CompressionStatus::Compress_AlreadyCompressed; + } + if (!compress_info.is_compressed && !compress) { + LOG_ERROR(Frontend, + "Error decompressing file {}, the selected file is already decompressed", + filepath); + return CompressionStatus::Decompress_NotCompressed; + } + + out_info = compress_info; + out_frame_size = frame_size; + return CompressionStatus::Success; +} + +jint Java_org_citra_citra_1emu_NativeLibrary_compressFileNative(JNIEnv* env, jobject obj, + jstring j_input_path, + jstring j_output_path) { + const std::string input_path = GetJString(env, j_input_path); + const std::string output_path = GetJString(env, j_output_path); + + Loader::AppLoader::CompressFileInfo compress_info{}; + size_t frame_size{}; + CompressionStatus stat = GetCompressFileInfo(compress_info, frame_size, input_path, true); + if (stat != CompressionStatus::Success) { + return static_cast(stat); + } + + auto progress = [](std::size_t processed, std::size_t total) { + JNIEnv* env = IDCache::GetEnvForThread(); + env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), + IDCache::GetCompressProgressMethod(), static_cast(total), + static_cast(processed)); + }; + + bool success = + FileUtil::CompressZ3DSFile(input_path, output_path, compress_info.underlying_magic, + frame_size, progress, compress_info.default_metadata); + if (!success) { + FileUtil::Delete(output_path); + return static_cast(CompressionStatus::Compress_Failed); + } + + return static_cast(CompressionStatus::Success); +} + +jint Java_org_citra_citra_1emu_NativeLibrary_decompressFileNative(JNIEnv* env, jobject obj, + jstring j_input_path, + jstring j_output_path) { + const std::string input_path = GetJString(env, j_input_path); + const std::string output_path = GetJString(env, j_output_path); + + Loader::AppLoader::CompressFileInfo compress_info{}; + size_t frame_size{}; + CompressionStatus stat = GetCompressFileInfo(compress_info, frame_size, input_path, false); + if (stat != CompressionStatus::Success) { + return static_cast(stat); + } + + auto progress = [](std::size_t processed, std::size_t total) { + JNIEnv* env = IDCache::GetEnvForThread(); + env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), + IDCache::GetCompressProgressMethod(), static_cast(total), + static_cast(processed)); + }; + + bool success = FileUtil::DeCompressZ3DSFile(input_path, output_path, progress); + if (!success) { + FileUtil::Delete(output_path); + return static_cast(CompressionStatus::Decompress_Failed); + } + + return static_cast(CompressionStatus::Success); +} + +jstring Java_org_citra_citra_1emu_NativeLibrary_getRecommendedExtension( + JNIEnv* env, jobject obj, jstring j_input_path, jboolean j_should_compress) { + const std::string input_path = GetJString(env, j_input_path); + + std::string compressed_ext; + std::string uncompressed_ext; + + auto loader = Loader::GetLoader(input_path); + if (loader) { + auto compress_info = loader->GetCompressFileInfo(); + if (compress_info.is_supported) { + compressed_ext = compress_info.recommended_compressed_extension; + uncompressed_ext = compress_info.recommended_uncompressed_extension; + } + } else { + bool is_compressed = false; + if (Service::AM::CheckCIAToInstall(input_path, is_compressed, true) == + Service::AM::InstallStatus::Success) { + compressed_ext = "zcia"; + uncompressed_ext = "cia"; + } + } + + if (compressed_ext.empty()) { + return env->NewStringUTF(""); + } + + return env->NewStringUTF(j_should_compress ? compressed_ext.c_str() : uncompressed_ext.c_str()); +} + void Java_org_citra_citra_1emu_NativeLibrary_setUserDirectory(JNIEnv* env, [[maybe_unused]] jobject obj, jstring j_directory) { @@ -514,6 +768,9 @@ void Java_org_citra_citra_1emu_NativeLibrary_stopEmulation([[maybe_unused]] JNIE stop_run = true; pause_emulation = false; window->StopPresenting(); + if (secondary_window) { + secondary_window->StopPresenting(); + } running_cv.notify_all(); } @@ -583,6 +840,25 @@ void Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEn window->OnTouchMoved((int)x, (int)y); } +jboolean Java_org_citra_citra_1emu_NativeLibrary_onSecondaryTouchEvent([[maybe_unused]] JNIEnv* env, + [[maybe_unused]] jobject obj, + jfloat x, jfloat y, + jboolean pressed) { + if (!secondary_window) { + return JNI_FALSE; + } + return static_cast(secondary_window->OnTouchEvent( + static_cast(x + 0.5), static_cast(y + 0.5), pressed)); +} + +void Java_org_citra_citra_1emu_NativeLibrary_onSecondaryTouchMoved([[maybe_unused]] JNIEnv* env, + [[maybe_unused]] jobject obj, + jfloat x, jfloat y) { + if (secondary_window) { + secondary_window->OnTouchMoved((int)x, (int)y); + } +} + jlong Java_org_citra_citra_1emu_NativeLibrary_getTitleId(JNIEnv* env, [[maybe_unused]] jobject obj, jstring j_filename) { std::string filepath = GetJString(env, j_filename); @@ -826,4 +1102,9 @@ jlong Java_org_citra_citra_1emu_NativeLibrary_playTimeManagerGetCurrentTitleId(J return ptm_current_title_id; } +void Java_org_citra_citra_1emu_NativeLibrary_setInsertedCartridge(JNIEnv* env, jobject obj, + jstring path) { + inserted_cartridge = GetJString(env, path); +} + } // extern "C" diff --git a/src/android/app/src/main/res/drawable/cartridge.png b/src/android/app/src/main/res/drawable/cartridge.png new file mode 100644 index 000000000..cb669ee29 Binary files /dev/null and b/src/android/app/src/main/res/drawable/cartridge.png differ diff --git a/src/android/app/src/main/res/layout/card_game.xml b/src/android/app/src/main/res/layout/card_game.xml index 85392a813..5b1d558ea 100644 --- a/src/android/app/src/main/res/layout/card_game.xml +++ b/src/android/app/src/main/res/layout/card_game.xml @@ -28,6 +28,16 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + @@ -120,12 +121,13 @@ @@ -179,6 +180,37 @@ android:contentDescription="@string/cheats" android:text="@string/cheats" /> + + + + + + + diff --git a/src/android/app/src/main/res/layout/dialog_compress_progress.xml b/src/android/app/src/main/res/layout/dialog_compress_progress.xml new file mode 100644 index 000000000..bdf8dd669 --- /dev/null +++ b/src/android/app/src/main/res/layout/dialog_compress_progress.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/src/android/app/src/main/res/values-b+ca+ES+valencia/strings.xml b/src/android/app/src/main/res/values-b+ca+ES+valencia/strings.xml index 01e9deea1..cfbaacf0f 100644 --- a/src/android/app/src/main/res/values-b+ca+ES+valencia/strings.xml +++ b/src/android/app/src/main/res/values-b+ca+ES+valencia/strings.xml @@ -32,7 +32,6 @@ Canvia els fitxers que Azahar utilitza per a carregar aplicacions Modifica l\'aspecte de l\'app Instal·lar CIA - Més Informació.]]> Seleccionar driver de GPU @@ -112,8 +111,6 @@ És possible que alguns controladors no puguen assignar el D-pad com un eix. Si aquest és el cas, utilitza la secció D-Pad (botons). D-Pad (Botó) Assigna només el D-pad a aquests si tens problemes amb les assignacions de botons del D-Pad (Eix). - Eix Vertical - Eix Horitzontal Amunt Avall Esquerra @@ -122,8 +119,6 @@ Pulsa o mou un botó/palanca. Assignació de botons Prem o mou una entrada per enllaçar-la a %1$s. - Mou el joystick amunt o avall. - Mou el joystick a esquerra o dreta. HOME Intercanviar Pantalles Turbo @@ -193,6 +188,9 @@ Advertiment Regió No Vàlida La configuració del país no és vàlida per a la regió emulada seleccionada. La configuració del país no és vàlida per a la consola vinculada actual. + Emmagatzematge + Comprimir el contingut de CIAs instal·lats + Comprimix el contingut de fitxers CIA quan són instal·lats a la SD emulada. Només afecta contingut CIA instal·lat amb esta opció activada. Càmera interior @@ -214,21 +212,18 @@ Usa SPIR-V en vez de GLSL per a emetre el fragment de ombrejador utilitzat per a emular PICA. Desativar l\'optimitzador SPIR-V Desactiva la passada d\'optimització SPIR-V reduint considerablement el quequeig i afectant poc el rendiment. - Activar compilació de ombrejadors asíncrona Compila els ombrejats en segón pla per a reduir les aturades durant la partida. S\'esperen errors gràfics temporals quan estigue activat. Filtre Linear Activa el filtre linear, que fa que els gràfics del joc es vegen més suaus. Filtre de Textures Millora l\'aspecte visual de les aplicacions aplicant un filtre a les textures. Els filtres compatibles són Anime4K, Ultrafast, Bicubic, ScaleForce, xBRZ Freescale i MMPX. - Endarrerir fil de renderitzat del joc Retarda el fil de renderitzat del joc en enviar dades a la GPU. Ajuda a solucionar problemes de rendiment en les (poques) aplicacions amb velocitats de fotogrames dinàmiques. Avançat Mostreig de Textures Sobreescriu el filtre de mostreig usat en jocs. Pot ser útil en uns certs casos de jocs amb baix rendiment en pujar la resolució. Si no estàs segur, possa\'l en Controlat per Joc. Multiplicació Precisa Usa multiplicacions més precises en els ombrejos de Hardware, que podrien arreglar uns certs problemes gràfics. Quan s\'active, el rendiment es reduirà. - Activar Emulació Asíncrona de la GPU Usa un fil separat per a emular la GPU de manera asíncrona. Quan s\'active, el rendiment millorarà. Límit de velocitat Quan s\'active, la velocitat d\'emulació estarà limitada a un percentatge determinat de la velocitat normal. Quan es desactive, la velocitat d\'emulació no tindrà límit i la tecla d\'accés ràpid de velocitat turbo no funcionarà. @@ -283,7 +278,6 @@ S\'esperen errors gràfics temporals quan estigue activat. Volum Extensió d\'Àudio Estén l\'àudio per a reduir les aturades. Quan s\'active, la latència d\'àudio s\'incrementarà i reduirà un poc el rendiment. - Activar àudio en temps real Ajusta la velocitat de reproducció d\'àudio per a compensar les caigudes en la velocitat d\'emulació de quadres. Això significa que l\'àudio es reproduirà a velocitat completa fins i tot quan la velocitat de quadres del joc siga baixa. Pot causar problemes de desincronització d\'àudio. Dispositiu d\'entrada d\'àudio Mode d\'eixida de l\'àudio @@ -295,12 +289,9 @@ S\'esperen errors gràfics temporals quan estigue activat. Usa el hardware per a emular els ombrejadors de 3DS. Quan s\'active, el rendiment millorarà notablement. Velocitat de rellotge de la CPU Activar Sincronització Vertical - Sincronitza els quadres per segon del joc amb la taxa de refresc del teu dispositiu. Renderitzador de depuració Arxiva informació addicional gràfica relacionada amb la depuració. Quan està activada, el rendiment dels jocs serà reduït considerablement - Guardar l\'eixida del registre en cada missatge Envia immediatament el registre de depuració a un arxiu. Usa-ho si Azahar falla i es talla l\'eixida del registre. - Inici diferit amb mòduls LLE Retarda l\'inici de l\'aplicació quan els mòduls LLE estan habilitats. Operacions asíncrones deterministes Fa que les operacions asíncrones siguen deterministes per a la depuració. Habilitar esta opció pot causar bloquejos. @@ -356,8 +347,6 @@ S\'esperen errors gràfics temporals quan estigue activat. Auto-elegir Iniciar Cancel·lant - Important - No tornar a mostrar Visibilitat Informació @@ -398,6 +387,10 @@ S\'esperen errors gràfics temporals quan estigue activat. Configurar Controls Editar Estil Fet + Lliscament de botons + Mantindre el botó pressionat originalment + Mantindre el botó pressionat actualment + Mantindre el botó original i actualment pressionat Activar Controls Ajustar Escala Escala Global @@ -410,6 +403,8 @@ S\'esperen errors gràfics temporals quan estigue activat. Relació d\'Aspecte Estil de Pantalla Apaïsada Estil de Pantalla de Perfil + Estil de Pantalla Secundària + La disposició de la pantalla secundària connectada, amb cable o sense fil (Chromecast, Miracast) Pantalla amplia Vertical Pantalla Única @@ -417,6 +412,7 @@ S\'esperen errors gràfics temporals quan estigue activat. Pantalles híbrides Original Per omissió + Per defecte del sistema (espill) Estil Personalitzat Posició de Pantalla Xicoteta On hauria d\'aparéixer la pantalla xicoteta en relació amb la gran en Proporció de Pantalla Gran? @@ -512,13 +508,9 @@ S\'esperen errors gràfics temporals quan estigue activat. Error de guardat/càrrega Error Fatal Ha ocorregut un error fatal. Mira el registre per a més detalls.\nSeguir amb l\'emulació podria resultar en diversos penges i problemes. - Regió no vàlida Aplicació cifrada no suportada - Preparant ombrejadors - Construint ombrejadors - Jugar Desinstal·lar Aplicació @@ -538,35 +530,14 @@ S\'esperen errors gràfics temporals quan estigue activat. Crear drecera El nom de la drecera no pot estar buit Allargar per a ajustar la imatge - + ID: + Fitxer: + Tipus: Mostrar informació de rendiment Informació de rendiment Activar informació de rendiment Configura la informació de rendiment - Mostrar FPS - Mostra els fotogrames per segon actuals. - Mostrar duració de fotogrames - Mostra la duració actual de cada fotograma. - Mostrar velocitat - Mostra el percentatge de velocitat d\'emulació actual. - Mostrar l\'ús de memòria de l\'aplicació - Mostra la quantitat de memòria RAM que esta usant l\'emulador. - Mostrar memòria disponible - Mostra la quantitat de memòria RAM que esta disponible. - Mostrar la temperatura de la bateria - Mostra la temperatura actual de la bateria en Celsius i Fahrenheit. - Posició de la informació - Tria on la informació de rendiment serà mostrada en la pantalla. - Dalt a l\'esquerra - Dalt a la dreta - Avall a l\'esquerra - Avall a la dreta - Dalt al centre - Avall al centre - Fons de la informació - Agrega un fons darrere de la informació per a fer-la més llegible. - Trucs Afegir trucs @@ -669,7 +640,6 @@ S\'esperen errors gràfics temporals quan estigue activat. De costat a costat - De costat a costat invers Anàglifo Entrellaçat Entrellaçat invers @@ -858,4 +828,4 @@ S\'esperen errors gràfics temporals quan estigue activat. Guardat ràpid - %1$tF %1$tR Guardat ràpid no disponible. - + diff --git a/src/android/app/src/main/res/values-b+da+DK/strings.xml b/src/android/app/src/main/res/values-b+da+DK/strings.xml index f3ffab4b0..857c14106 100644 --- a/src/android/app/src/main/res/values-b+da+DK/strings.xml +++ b/src/android/app/src/main/res/values-b+da+DK/strings.xml @@ -32,7 +32,6 @@ Ændrer de filer, som Azahar bruger til at indlæse applikationer Rediger appens udseende Installer CIA - Lær mere.]]> Vælg GPU-driver @@ -67,13 +66,21 @@ Giv tilladelse Vil du droppe at give tilladelse til meddelelser? Azahar vil ikke være i stand til at give dig meddelelse om vigtige oplysninger. + Manglende tilladelser + Azahar kræver tilladelse til at administrere filer på denne enhed for at kunne gemme og administrere dens data.\n\nGiv venligst tilladelsen \"Filsystem\", før du fortsætter. Kamera Giv kameraet tilladelse nedenfor til at efterligne 3DS-kameraet. Mikrofon Giv mikrofonen tilladelse nedenfor til at efterligne 3DS-mikrofonen. + Filsystem + Giv filsystemet tilladelse nedenfor for at tillade Azahar at gemme filer. Tilladelse nægtet Vil du droppe at vælge applikationsmappen? Software vil ikke blive vist på applikationslisten, hvis en mappe ikke er valgt. + Tilladelser + Datamapper + (Brugermappe er påkrævet)]]> + Giv valgfrie tilladelser til at bruge specifikke funktioner i emulatoren Hjælp Spring over Annuller @@ -83,8 +90,12 @@ Behold den aktuelle Azahar-mappe Brug tidligere Lime3DS mappe Vælg + Du kan ikke springe opsætningen af ​​brugermappen over Dette trin er påkrævet for at Azahar kan fungere. Vælg en mappe og så kan du fortsætte. Du har mistet skrivetilladelse i din brugerdata mappe, hvor gemte tilstande og anden information er gemt. Dette kan ske efter en app- eller Android-opdatering. Vælg venligst mappen for at give tilladelse igen, så du kan fortsætte. + Ugyldigt valg + Valget af brugermappe var ugyldigt.\nVælg venligst brugermappen igen, og sørg for at navigere til den fra roden af ​​din enheds lager. + Azahar har mistet tilladelsen til at administrere filer på denne enhed. Dette kan ske efter nogle app- eller Android-opdateringer. Giv venligst denne tilladelse igen på den næste skærm for at fortsætte med at bruge appen. Temaindstillinger Konfigurer dine temaindstillinger for Azahar. Indstil tema @@ -107,8 +118,8 @@ Nogle kontrollere er muligvis ikke i stand til at tilknytte deres D-Pad som en akse. Hvis det er tilfældet, skal du bruge afsnittet D-Pad (knapper). D-Pad (knapper) Udfyld kun disse D-Pad, hvis du har problemer med opsætningen af D-Pad (akser). - Op/ned akse - Venstre/højre akse + Vertikal akse + Horisontal akse Op Ned Venstre @@ -117,8 +128,8 @@ Tryk på eller flyt et input. Inputbinding Tryk på eller flyt et input for at binde det til %1$s. - Bevæg joysticket op eller ned. - Bevæg joysticket til venstre eller højre + Tryk OP på dit joystick. + Tryk HØJRE på dit joystick. HOME Byt skærme Turbo @@ -157,6 +168,8 @@ Brugernavn Ny 3DS tilstand Brug LLE Applets (hvis installeret) + Anvend regionfri programrettelse på installerede programmer + Opdaterer regionen for installerede programmer, så de altid vises i startmenuen. Aktiver nødvendige LLE moduler til onlinefunktioner (hvis installeret) Aktiverer de LLE moduler, der kræves til online multiplayer, eShop-adgang osv. Ur @@ -188,6 +201,9 @@ Advarsel om uoverensstemmelse i region Landeindstillingen er ikke gyldig for det valgte emulerede område. Landeindstillingen er ikke gyldig for den aktuelle forbundne konsol. + Lager + Komprimer installeret CIA-indhold + Komprimerer indholdet af CIA-filer, når de installeres på det emulerede SD-kort. Påvirker kun CIA-indhold, der installeres, når indstillingen er aktiveret. Indre kamera @@ -207,14 +223,17 @@ Grafik API Aktiver generering af SPIR-V shader Udsender den fragment shader, der bruges til at emulere PICA med SPIR-V i stedet for GLSL + Deaktiver SPIR-V Optimeringsværktøj + Deaktiverer SPIR-V-optimeringspasset, hvilket reducerer hakken betydeligt, mens ydeevnen næsten ikke påvirkes. Aktiver asynkron shader kompilering Kompilerer shaders i baggrunden for at reducere hakken under spilet. Når det er aktiveret, skal du forvente tilfældige grafiske fejl Lineær filtrering Aktiverer lineær filtrering, hvilket får spillets grafik til at se mere jævnt ud. Teksturfilter Forbedrer det visuelle i applikationer ved at anvende et filter på teksturer. De understøttede filtre er Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale og MMPX. - Forsinket spillets renderingstråd + Forsink spillets renderingstråd Forsink spillets remderingstråd, når den sender data til GPU\'en. Hjælper med ydeevneproblemer i de (meget få) applikationer med dynamiske framerates. + Avanceret Tekstur sampling Tilsidesætter det samplingsfilter, der bruges af spillene. Dette kan i nogle tilfælde være nyttigt for spil, der ikke håndterer opskalering godt. Hvis du er usikker, skal du indstille dette til Styret af spillene. Nøjagtig multiplikation @@ -225,6 +244,8 @@ Når aktiveret, vil emuleringshastigheden være begrænset til en specificeret procentdel af normal hastighed. Hvis deaktiveret, vil emuleringshastigheden være ubegrænset, og genvejstasten for turbohastighed vil ikke fungere. Begræns hastighedsprocent Angiver procentdelen emuleringshastigheden skal begrænses til. Med standardværdien på 100% vil emulering være begrænset til normal hastighed. Værdier højere eller lavere vil øge eller mindske hastighedsgrænsen. + Skjul 3DS-afbildninger fra Android + Forhindre at Android indekserer og viser billeder fra 3DS-kamera, skærmbilleder og brugerdefinerede teksturer i galleriet. Din enhed skal muligvis genstartes, efter at du har ændret denne indstilling, for at den træder i kraft. Turbohastighedsgrænse Grænse for emuleringens hastighed bruges, når turbo-genvejstasten er aktiv. Anvend området ved frontkamera @@ -246,10 +267,18 @@ Advarsel: Ændringer i disse indstillinger vil gøre emuleringen langsommere Stereoskopi Stereoskopisk 3D-tilstand + Vælg den stereoskopiske 3D-tilstand til 3D-gengivelse. Side om side-tilstande er mest almindelige i moderne brug. Anaglyf- og interlaced-tilstande vil altid gælde for alle tilsluttede skærme. Dybde Angiver værdien af ​​3D-skyderen. Denne bør sættes højere end 0 %, når stereoskopisk 3D-tilstand er aktiveret.\nBemærk: Dybdeværdier over 100 % er ikke muligt på rigtig hardware og kan forårsage grafiske problemer Deaktiver rendering af højre øje Forbedrer ydeevnen betydeligt i nogle applikationer, men kan forårsage flimren i andre. + Skift øjne + Bytter om på hvilket øje, der skal se hvilken side. Kombineret med side om side-tilstanden er det muligt at se 3D ved at krydse øjnene! + Gengiv stereoskopisk 3D + Om stereoskopisk 3D skal aktiveres, og på hvilke skærme. Indstillingerne for en enkel skærm er kun relevant, når flere skærme er tilsluttet. + Til (alle skærme) + Til (kun primær skærm) + Til (kun sekundær skærm) Cardboard VR Cardboard skærmstørrelse Skalerer skærmen til en procentdel af dens oprindelige størrelse. @@ -286,18 +315,21 @@ Bruger hardware til at efterligne 3DS shaders. Når det er aktiveret, vil spillets ydeevne blive væsentligt forbedret. CPU Clock hastighed Aktiver V-Sync - Synkroniserer spillets frame rate med opdateringshastigheden på din enhed. + Synkroniserer spillets billedhastighed med din enheds opdateringshastighed. Kan forårsage yderligere inputforsinkelse, men kan reducere tearing i nogle tilfælde. Fejlsøg renderingen Log yderligere grafikrelaterede fejlfindingsoplysninger. Når det er aktiveret, vil spillets ydeevne blive væsentligt reduceret. - Tøm loggen for alle beskeder + Tøm loggen ved hver besked Overfør øjeblikkeligt fejlretningsloggen til fil. Brug dette, hvis Azahar går ned, og logoutputtet afbrydes. - Forsinket start med LLE moduler + Forsink start med LLE moduler Forsinker starten af ​​appen, når LLE moduler er aktiveret. Deterministiske asynkrone operationer Gør asynkrone operationer deterministiske for fejlretning. Aktivering af dette kan forårsage at programmet fryser fast. Aktivér RPC-server Aktiverer RPC-serveren på port 45987. Dette tillader fjernlæsning/skrivning af gæstehukommelse. - + Aktiver shader-JIT + Brug JIT-motoren i stedet for fortolkeren til software-shader-emulering. + + Skærmorientering Automatisk Landskab @@ -344,8 +376,6 @@ Automatisk valg Start Annullerer... - Vigtig - Vis ikke igen Sigtbarhed Information @@ -386,18 +416,24 @@ Konfigurer kontroller Rediger layout Færdig + Knap flytning + Hold den oprindeligt trykkede knap nede + Hold den aktuelt nede knap nede + Hold den oprindelige og den aktuelt nedtrykkede knap nede Skift kontrol Juster skala Global skala Nulstil alle Juster opacitet Relativt stick centrum - D-Pad glidning + D-Pad flytning Åbn Indstillinger Åbn snydekoder Billedformat Landskab skærmlayout Portræt skærmlayout + Layout af sekundær skærm + Layoutet, der bruges af en tilsluttet sekundær skærm, kablet eller trådløs (Chromecast, Miracast) Stor skærm Portræt Enkelt skærm @@ -405,7 +441,15 @@ Hybrid skærme Original Standard + Systemstandard (spejl) Brugerdefineret layout + Baggrundsfarve + Farven, der vises bag skærmene under emulering, repræsenteret som en RGB-værdi. + Rød + Grøn + Blå + Brugerdefineret layout skærmopacitet for anden skærm + Opaciteten af ​​den anden 3DS-skærm, når der bruges et brugerdefineret skærmlayout. Nyttig, hvis den anden skærm skal placeres oven på den første skærm. Position for lille skærm Hvor skal den lille skærm vises i forhold til den store i storskærmslayout? Øverst til højre @@ -431,6 +475,7 @@ Højde Skift layout Byt skærme + Roter skærmen oprejst Nulstil overlejring Vis controller-overlejring Luk spil @@ -499,13 +544,12 @@ Gem/indlæs fejl Fatal fejl Der opstod en fatal fejl. Kontroller loggen for detaljer.\nFortsat emulering kan resultere i nedbrud og fejl. - Ugyldig region Ikke understøttet krypteret applikation + Ugyldig systemtilstand + Nye 3DS-eksklusive applikationer kan ikke indlæses uden at aktivere den nye 3DS-tilstand. Forberedelse af shaders - Bygning af shaders - Spil Afinstaller applikation @@ -520,33 +564,44 @@ Afinstaller DLC Afinstaller opdateringer Genvej + Genvejsnavn + Rediger ikon + Opret genvej + Genvejsnavnet må ikke være tomt + Stræk for at tilpasse billedet + ID: + Fil: + Type: + Indsæt kassette + Udtag kassette + Vis ydelsesoverlejring Ydelsesoverlejring Aktivér ydelsesoverlejring Konfigurer, om ydelsesoverlejringen skal vises, og hvilke oplysninger der vises. - Vis FPS - Vis aktuelle billeder pr. sekund. - Vis billedtid - Vis aktuel billedtid. - Vis hastighed - Vis den aktuelle emuleringshastighed i procent. - Vis hukommelsesforbrug for app - Vis mængden af ​​RAM, der bruges af emulatoren. - Vis tilgængelig hukommelse - Vis mængden af ​​RAM, der er tilgængelig. - Vis batteritemperatur - Viser den aktuelle batteritemperatur i Celsius og Fahrenheit. - Position af overlejring - Vælg, hvor ydelsesoverlejringen skal vises på skærmen. - Øverst til venstre - Øverst til højre - Nederst til venstre - Nederst til højre - Midten øverst - Midten nederst - Overlejret baggrund - Tilføjer en baggrund bag overlejringen for lettere læsning. + Vis FPS + Vis aktuelle billeder pr. sekund. + Vis billedtid + Vis aktuel billedtid. + Vis hastighed + Vis den aktuelle emuleringshastighed i procent. + Vis hukommelsesforbrug for app + Vis mængden af ​​RAM, der bruges af emulatoren. + Vis tilgængelig hukommelse + Vis mængden af ​​RAM, der er tilgængelig. + Vis batteritemperatur + Viser den aktuelle batteritemperatur i Celsius og Fahrenheit. + Overlejret-position + Vælg, hvor performance-overlayet skal vises på skærmen. + Øverst til venstre + Øverst til højre + Nederst til venstre + Nederst til højre + Centreret top + Centreret bund + Overlejret baggrund + Tilføjer en baggrund bag det overlejrede for lettere læsning. Snyd @@ -650,7 +705,7 @@ Side om Side - Omvendt side om side + Side om side i fuld bredde Anaglyph Interlaced Omvendt interlaced @@ -839,4 +894,19 @@ Hurtig lagring - %1$tF %1$tR Ingen hurtig lagring tilgængelig. + + Komprimer + Komprimerer… + Dekomprimer + Dekomprimerer… + Komprimering gennemført. + Komprimering understøttes ikke for denne fil. + Filen er allerede komprimeret. + Komprimeringen mislykkedes. + Dekomprimeringen er gennemført. + Dekomprimering understøttes ikke for denne fil. + Filen er ikke komprimeret. + Dekomprimeringen mislykkedes. + Allerede installerede programmer kan ikke komprimeres eller dekomprimeres. + diff --git a/src/android/app/src/main/res/values-b+es+ES/strings.xml b/src/android/app/src/main/res/values-b+es+ES/strings.xml index b19e21f1d..3ffed8a57 100644 --- a/src/android/app/src/main/res/values-b+es+ES/strings.xml +++ b/src/android/app/src/main/res/values-b+es+ES/strings.xml @@ -32,7 +32,6 @@ Cambia los archivos que Azahar usa para cargar aplicaciones Modifica el aspecto de la app Instalar CIA - Más Información.]]> Seleccionar driver de GPU @@ -67,10 +66,13 @@ Conceder permiso ¿Saltarse la concesión del permiso de notificaciones? Azahar no podrá notificarte sobre información importante. + Falta Permisos Cámara Concede el permiso de cámara debajo para emular la cámara de la 3DS. Micrófono Concede el permiso de micrófono debajo para emular el micrófono de la 3DS. + Sistema de archivos + Concede el permiso de sistema de archivos debajo para permitir que Azahar almacene archivos. Permiso denegado ¿Saltarse la selección de la carpeta de aplicaciones? Nada se mostrará en la lista de aplicaciones si no se selecciona una carpeta. @@ -90,6 +92,7 @@ No puedes saltarte el configuración de la carpeta de usuario Este paso es necesario para permitir que Azahar funcione. Por favor, seleccione un directorio y luego puede continuar. Has perdido los permisos de escritura en tu directorio de datos de usuario, donde se guardan las partidas guardadas y otra información. Esto puede ocurrir después de algunas actualizaciones de aplicaciones o de Android. Vuelve a seleccionar el directorio para recuperar los permisos y poder continuar. + Selección no válido Configuración de tema Configura tus preferencias de tema de Azahar. Establecer tema @@ -122,8 +125,8 @@ Pulsa o mueve un botón/palanca. Asignación de botones Pulsa o mueve un botón para asignarlo a %1$s. - Mueve el joystick arriba o abajo. - Mueve el joystick a izquierda o derecha. + Presiona ARRIBA en tu joystick. + Presiona DERECHA en tu joystick. HOME Intercambiar Pantallas Turbo @@ -193,6 +196,9 @@ Advertencia Región No Válida La configuración del país no es válida para la región emulada seleccionada. La configuración del país no es válida para la consola vinculada actual. + Almacenamiento + Comprimir el contenido de CIAs instalados + Comprime el contenido de archivos CIA cuando son instalados a la SD emulada. Solo afecta contenido CIA instalado con esta opción activada. Cámara interior @@ -234,6 +240,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Cuando se active, la velocidad de emulación estará limitada a un porcentaje determinado de la velocidad normal. Cuando se desactive, la velocidad de emulación no tendrá límite y la tecla de acceso rápido de velocidad turbo no funcionará. Limitar porcentaje de velocidad Especifica el valor al que se limita la velocidad de emulación. Con el valor por defecto del 100%, la emulación se limitará a la velocidad normal. Los valores altos o altos incrementarán o reducirán el límite de velocidad. + Ocultar imágenes 3DS de Android Límite de Velocidad Turbo Límite de velocidad de emulación utilizado mientras la tecla de acceso rápido turbo está activa. Expandir al área de recorte @@ -259,6 +266,11 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Especifica el valor del regulador 3D. Debería estar puesto a más allá del 0% cuando el Modo 3D Estereoscópico está activado.\nNota: Los valores de profundidad superiores al 100 % no son posibles en hardware real y pueden causar problemas gráficos. Desactivar Renderizado de Ojo Derecho Mejora significativamente el rendimiento en algunas aplicaciones, pero puede causar parpadeo en otros. + Intercambiar Ojos + Renderizado 3D Estereoscópico + Activado (todas las pantallas) + Activado (solo pantalla principal) + Activado (solo pantalla secundaria) Cardboard VR Tamaño de la pantalla Cardboard Escala la pantalla a un porcentaje de su tamaño original. @@ -295,7 +307,6 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Usa el hardware para emular los sombreadores de 3DS. Cuando se active, el rendimiento mejorará notablemente. Velocidad de reloj de la CPU Activar Sincronización Vertical - Sincroniza los cuadros por segundo del juego con la tasa de refresco de tu dispositivo. Renderizador de depuración Archiva información adicional gráfica relacionada con la depuración. Cuando está activada, el rendimiento de los juegos será reducido considerablemente Limpiar la salida del registro en cada mensaje @@ -356,8 +367,6 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Auto-elegir Iniciar Cancelando... - Importante - No volver a mostrar Visibilidad Información @@ -398,6 +407,10 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Configurar Controles Editar Estilo Hecho + Deslizamiento de botones + Mantener el botón presionado originalmente + Mantener el botón presionado actualmente + Mantener el botón original y actualmente presionado Activar Controles Ajustar Escala Escala Global @@ -410,6 +423,8 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Relación de Aspecto Estilo de Pantalla Apaisada Estilo de Pantalla de Perfil + Estilo de Pantalla Secundaria + El estilo de la pantalla secundaria conectada, con cable o inalámbrica (Chromecast, Miracast) Pantalla amplia Retrato Pantalla Única @@ -417,7 +432,14 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Pantallas híbridas Original Por defecto + Por defecto del sistema (espejo) Estilo personalizado + Color de fondo + Rojo + Verde + Azul + Opacidad personalizado de la segunda pantalla + La opacidad de la segunda pantalla 3DS al usar el pantalla personalizado. Útil si la segunda pantalla ésta posición en la parte superior de la primera pantalla. Posición Pantalla Pequeña ¿Dónde debería aparecer la pantalla pequeña en relación con la grande en Disposicion de Pantalla Grande? Arriba a la Derecha @@ -512,12 +534,11 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Error de guardado/carga Error Fatal Ha ocurrido un error fatal. Mira el registro para más detalles.\nSeguir con la emulación podría resultar en diversos cuelgues y bugs. - Región no válida Aplicación encriptada no soportada - + Modo de sistema no válido Preparando shaders - Construyendo shaders + Construyendo%s Jugar @@ -538,34 +559,39 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Crear atajo El nombre del atajo no puede estar vacío Alargar para ajustar la imagen + ID: + Archivo: + Tipo: + Insertar Cartucho + Expulsar Cartucho Mostrar información de rendimiento Información de rendimiento Activar información de rendimiento Configura la información de rendimiento - Mostrar FPS - Muestra los fotogramas por segundo actuales. - Mostrar duración de fotogramas - Muestra la duración actual de cada fotograma. - Mostrar velocidad - Muestra el porcentaje de velocidad de emulación actual. - Mostrar el uso de memoria de la aplicación - Muestra la cantidad de memoria RAM que esta usando el emulador. - Mostrar memoria disponible - Muestra la cantidad de memoria RAM que esta disponible. - Mostrar la temperatura de la batería - Muestra la temperatura actual de la batería en Celsius y Fahrenheit. - Posición de la información - Elige donde la información de rendimiento será mostrada en la pantalla. - Arriba a la izquierda - Arriba a la derecha - Abajo a la izquierda - Abajo a la derecha - Centro superior - Centro inferior - Fondo de la información - Agrega un fondo detrás de la información para hacerla más legible. + Mostrar FPS + Muestra los fotogramas por segundo actuales. + Mostrar duración de fotogramas + Muestra la duración actual de cada fotograma. + Mostrar velocidad + Muestra el porcentaje de velocidad de emulación actual. + Mostrar el uso de memoria de la aplicación + Muestra la cantidad de memoria RAM que esta usando el emulador. + Mostrar memoria disponible + Muestra la cantidad de memoria RAM que esta disponible. + Mostrar la temperatura de la batería + Muestra la temperatura actual de la batería en Celsius y Fahrenheit. + Posición de la información + Elegir donde el superposición de rendimiento esta mostrado en el pantalla + Arriba a la Izquierda + Arriba a la Derecha + Abajo a la Izquierda + Abajo a la Derecha + Centro Superior + Centro Inferior + Fondo de la información + Agrega un fondo detrás de la información para hacerla más legible. Trucos @@ -670,7 +696,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. De lado a lado - De lado a lado inverso + De lado a lado ancho completo Anáglifo Entrelazado Entrelazado inverso @@ -859,4 +885,17 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Guardado rápido - %1$tF %1$tR Guardado rápido no disponible. - + + Comprimir + Compresando... + Descomprimir + Descomprimiendo… + Compresión completada con éxito. + Compresión no está soportado con este archivo. + Este archivo ya está comprimido. + Falló la compresión. + Descompresión completada con éxito. + Descompresión no está soportado con este archivo. + El archivo no está comprimido. + Falló la descompresión. + diff --git a/src/android/app/src/main/res/values-b+ja+JP/strings.xml b/src/android/app/src/main/res/values-b+ja+JP/strings.xml index 879f96568..5b9e3784f 100644 --- a/src/android/app/src/main/res/values-b+ja+JP/strings.xml +++ b/src/android/app/src/main/res/values-b+ja+JP/strings.xml @@ -9,7 +9,6 @@ MACアドレス MACアドレスを再生成 これを行うと、今のMACアドレスを新しいもので置き換えます。セットアップツールで実機からMACアドレスを吸い出した場合、これをするのは推奨しません。続行しますか? - 描写スレッドを遅延する GPUにデータを送信する間、ゲームの描写スレッドを遅延します。動的フレームレートである(ほんの一部の)アプリケーションでのパフォーマンスが向上します。 デバッグログを即座にファイルに書き込みます。Azaharがクラッシュしてログが途切れるときに有効にしてください。 その他 diff --git a/src/android/app/src/main/res/values-b+lt+LT/strings.xml b/src/android/app/src/main/res/values-b+lt+LT/strings.xml index 8a5875389..1bb6944f5 100644 --- a/src/android/app/src/main/res/values-b+lt+LT/strings.xml +++ b/src/android/app/src/main/res/values-b+lt+LT/strings.xml @@ -61,15 +61,12 @@ Garsumas Garso ištempimas - Įjungti realaus laiko garsą Automatinis Sužinoti daugiau Uždaryti Atstatyti visus nustatymus? Pradėti Atšaukiama... - Svarbu - Daugiau niekada nerodyti Nustatymai Sistema diff --git a/src/android/app/src/main/res/values-b+pl+PL/strings.xml b/src/android/app/src/main/res/values-b+pl+PL/strings.xml index f2976feb1..3e14f6051 100644 --- a/src/android/app/src/main/res/values-b+pl+PL/strings.xml +++ b/src/android/app/src/main/res/values-b+pl+PL/strings.xml @@ -32,7 +32,6 @@ Zmienia pliki, których Azahar używa do ładowania aplikacji Zmodyfikuj wygląd aplikacji Instaluj CIA - Więcej informacji.]]> Wybierz sterownik GPU @@ -67,10 +66,14 @@ Udzielenie zgody Pominąć udzielanie zgody na powiadomienie? Azahar nie będzie w stanie powiadomić cię o ważnych informacjach. + Brak uprawnień + Azahar wymaga uprawnień do zarządzania plikami na tym urządzeniu w celu przechowywania i zarządzania swoimi danymi. \n\nPrzed kontynuowaniem należy przyznać uprawnienia „System plików”. Kamera Udziel poniższych uprawnień kamery, aby emulować kamerę 3DS. Mikrofon Udziel poniższych uprawnień mikrofonu, aby emulować mikrofon 3DS. + System plików + Przyznaje poniższe uprawnienia systemu plików, aby umożliwić Azahar przechowywanie plików. Odmowa zezwolenia Pominąć wybór folderu z aplikacjami? Oprogramowania nie będą wyświetlane na liście aplikacji, jeśli nie wybrano folderu. @@ -90,6 +93,9 @@ Nie można pominąć konfiguracji folderu użytkownika. Ten krok jest wymagany, aby umożliwić działanie Azahar. Wybierz katalog, a następnie możesz kontynuować. Utraciłeś uprawnienia do zapisu w katalogu danych użytkownika, w którym przechowywane są zapisy i inne informacje. Może się to zdarzyć po niektórych aktualizacjach aplikacji lub systemu Android. Wybierz ponownie katalog, aby odzyskać uprawnienia i móc kontynuować. + Nieprawidłowy wybór + Wybór katalogu użytkownika był nieprawidłowy.\nProszę ponownie wybrać katalog użytkownika, upewniając się, że przechodzisz do niego z katalogu głównego pamięci urządzenia. + Azahar utracił uprawnienia do zarządzania plikami na tym urządzeniu. Może się to zdarzyć po aktualizacji niektórych aplikacji lub systemu Android. Aby kontynuować korzystanie z aplikacji, należy ponownie przyznać te uprawnienia na następnym ekranie. Ustawienia motywu Skonfiguruj ustawienia motywu dla Azahar. Ustaw motyw @@ -112,8 +118,8 @@ Niektóre kontrolery mogą nie być w stanie zmapować swojego D-pada jako osi. W takim przypadku należy użyć sekcji D-Pad (przyciski). Krzyżak (Przycisk) Zmapuj D-pad na te ustawienia tylko wtedy, gdy masz problemy z mapowaniem przycisków D-Pada (Oś). - Oś góra/dół - Oś lewa/prawa + Oś pionowa + Oś pozioma Góra Dół Lewo @@ -122,8 +128,8 @@ Naciśnij lub przenieś wejście. Powiązanie wejścia Naciśnij lub przesuń wejście, aby powiązać je z %1$s. - Przesuń analog w górę lub w dół. - Przesuń analog w lewo lub w prawo. + Naciśnij joystick w górę. + Naciśnij joystick w prawo. HOME Zamień ekrany Turbo @@ -162,6 +168,8 @@ Nazwa użytkownika Tryb New 3DS Użyj apletów LLE (jeśli są zainstalowane) + Zastosuj łatkę bez regionu do zainstalowanych aplikacji. + Naprawia region zainstalowanych aplikacji, aby były one wolne od ograniczeń regionalnych, dzięki czemu zawsze pojawiają się w menu głównym. Włącz wymagane moduły LLE dla funkcji online (jeśli są zainstalowane) łącza moduły LLE potrzebne do gry wieloosobowej online, dostępu do eShopu itp. Zegar @@ -193,6 +201,9 @@ Ostrzeżenie o niedopasowaniu regionów Ustawienie kraju nie jest prawidłowe dla wybranego emulowanego regionu. Ustawienie kraju nie jest prawidłowe dla aktualnie podłączonej konsoli. + Miejsce + Kompresuj zainstalowaną zawartość CIA + Kompresuje zawartość plików CIA zainstalowanych na emulowanej karcie SD. Ma wpływ tylko na zawartość CIA, która jest instalowana, gdy ustawienie jest włączone. Kamera wewnętrzna @@ -214,25 +225,27 @@ Emituje fragment shaderów używany do emulacji PICA przy użyciu SPIR-V zamiast GLSL. Wyłącz optymalizator SPIR-V Wyłącza optymalizację SPIR-V, znacznie zmniejszając zacinanie się obrazu przy minimalnym wpływie na wydajność. - Włącz asynchroniczną kompilację shaderów + Włącz Asynchroniczną Kompilację Shaderów Kompiluje shadery w tle, aby zmniejszyć zacinanie się podczas rozgrywki. Po włączeniu należy spodziewać się tymczasowych błędów graficznych Filtrowanie Linear Włącza filtrowanie liniowe, które sprawia, że grafika w grach jest płynniejsza. Filtr tekstur Ulepsza oprawę wizualną aplikacji poprzez zastosowanie filtrów do tekstur. Obsługiwane filtry to Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale i MMPX. - Opóźnienie renderowania wątku gry + Opóźnienie Renderowania Wątku Gry Opóźnia wątek renderowania aplikacji podczas przesyłania danych do GPU. Pomaga w kwestiach wydajności w (bardzo niewielu) aplikacjach z dynamiczną liczbą klatek na sekundę. Zaawansowane Próbkowanie tekstur Zastępuje filtr próbkowania używany przez gry. Może to być przydatne w niektórych przypadkach, gdy gry źle zachowują się podczas skalowania w górę. Jeśli nie masz pewności, ustaw tę opcję na Kontrolowane przez grę. Dokładne mnożenie Używa dokładniejszego mnożenia w shaderach sprzętu, dzięki czemu może naprawić niektóre błędy graficzne. Po włączeniu tej funkcji wydajność zostanie zmniejszona. - Włącz asynchroniczną emulację GPU + Włącz Asynchroniczną Emulację GPU Używa oddzielnego wątku do asynchronicznej emulacji GPU. Po włączeniu, wydajność zostanie poprawiona. Ogranicz prędkość Po włączeniu prędkość emulacji zostanie ograniczona do określonego procentu normalnej prędkości. Jeśli opcja ta jest wyłączona, prędkość emulacji nie zostanie ograniczona, a klawisz skrótu prędkości turbo nie będzie działał. Ogranicz procent prędkości Określa wartość procentową ograniczenia prędkości emulacji. Przy domyślnej wartości 100% emulacja będzie ograniczona do normalnej prędkości. Wyższe lub niższe wartości zwiększają lub zmniejszają ograniczenie prędkości. + Ukryj obrazy 3DS z systemu Android + Zapobiega indeksowaniu przez system Android zdjęć wykonanych aparatem 3DS, zrzutów ekranu i niestandardowych tekstur oraz wyświetlaniu ich w galerii. Aby zmiany ustawień zaczęły obowiązywać, może być konieczne ponowne uruchomienie urządzenia. Limit prędkości Turbo Limit prędkości emulacji wykorzystywany, gdy aktywny jest klawisz skrótu turbo. Rozszerz do obszaru wycięcia @@ -254,10 +267,18 @@ Ostrzeżenie: Zmiana tych ustawień spowolni emulację Sterowanie stereoskopowe Tryb stereoskopowy 3D + Wybierz tryb stereoskopowego 3D dla renderowania 3D.Tryb ekranów obok siebie jest obecnie najczęściej stosowany. Tryby obrazu Anaglyph i Interlaced będą zawsze stosowane do wyświetlania obrazu na wszystkich podłączonych monitorach. Zasięg Określa wartość suwaka 3D. Powinien być ustawiony na wartość wyższą niż 0%, gdy włączony jest tryb stereoskopowy 3D.\nUwaga: Wartość przekraczająca 100% nie jest możliwa na rzeczywistym sprzęcie i może powodować problemy graficzne. Wyłącz renderowanie prawego oka Znacznie poprawia wydajność w niektórych aplikacjach, ale może powodować migotanie w innych. + Zamiana Oczu + Zamiana oczu jest wyświetlana po obu stronach. W połączeniu z trybem obrazów obok siebie umożliwia oglądanie obrazu 3D poprzez przesunięcie oczu! + Render stereoskopowego 3D + Czy włączyć stereoskopowe 3D i na jakich wyświetlaczach to włączyć? Opcje dotyczące pojedynczego wyświetlacza mają znaczenie tylko wtedy, gdy podłączonych jest wiele wyświetlaczy. + Włącz (Wszystkie Wyświetlacze) + Włącz (Tylko Główny Wyświetlacz) + Włącz (Tylko na Dodatkowym Wyświetlaczu) Cardboard VR Rozmiar ekranu Cardboarda Skaluje ekran do wartości procentowej jego oryginalnego rozmiaru. @@ -282,7 +303,7 @@ Głośność Rozciągnij dźwięk Rozciąga dźwięk, aby zredukować zacinanie się. Po włączeniu tej opcji zwiększa opóźnienie dźwięku i nieznacznie obniża wydajność. - Włącz dźwięk w czasie rzeczywistym + Włącz Dźwięk w Czasie Rzeczywistym Skaluje prędkość odtwarzania dźwięku, aby uwzględnić spadki liczby klatek na sekundę w emulacji. Oznacza to, że dźwięk będzie odtwarzany z pełną prędkością, nawet jeśli liczba klatek na sekundę w grze jest niska. Może powodować problemy z desynchronizacją dźwięku. Urządzenie wejściowe dźwięku Tryb wyjścia dźwięku @@ -294,12 +315,12 @@ Używa sprzętu do emulacji shaderów 3DS. Po włączeniu, wydajność gry zostanie znacznie poprawiona. Prędkość taktowania procesora Włącz V-Sync - Synchronizuje liczbę klatek na sekundę gry z częstotliwością odświeżania urządzenia. + Synchronizuje częstotliwość klatek na sekundę w grze z częstotliwością odświeżania urządzenia. Może powodować dodatkowe opóźnienia wejściowe, ale w niektórych przypadkach może ograniczyć występowanie rozdarć obrazu. Render debugowania Rejestruje dodatkowe informacje debugowania związane z grafiką. Po włączeniu, wydajność gry zostanie znacznie zmniejszona. - Opróżnia log przy każdej wiadomości + Opróżnij Log Przy Każdej Wiadomości Natychmiast zapisuje log debugowania do pliku. Użyj tego, jeśli azahar ulegnie awarii, a dane wyjściowe logu zostaną przerwane. - Opóźnione uruchamianie z modułami LLE + Opóźnij Uruchamianie z Modułami LLE Opóźnia uruchomienie aplikacji, gdy włączone są moduły LLE. Deterministyczne operacje asynchroniczne Sprawia, że operacje asynchroniczne są deterministyczne dla debugowania. Włączenie tej opcji może powodować zawieszanie się gry. @@ -355,8 +376,6 @@ Wybór automatyczny Rozpocznij Anulowanie... - Ważne - Nie pokazuj tego ponownie Widoczność Informacje @@ -397,6 +416,10 @@ Konfiguracja sterowania Edytuj układ Gotowe + Przesuwanie przycisków + Przytrzymuje pierwotnie naciśnięty przycisk + przytrzymuje aktualnie naciśnięty przycisk + Przytrzymuje oryginalny i aktualnie naciśnięty przycisk Przełącz sterowanie Dostosuj Skalę Ogólna Skala @@ -409,6 +432,8 @@ Proporcje obrazu Geometryczny Układ Ekranu Pionowy Układ Ekranu + Układ ekranu wyświetlacza dodatkowego + Układ używany przez podłączony dodatkowy ekran, przewodowy lub bezprzewodowy (Chromecast, Miracast) Duży Ekran Ekran Pojedynczy ekran @@ -416,7 +441,15 @@ Hybrydowy Ekran Oryginalny Domyślny + Ustawienia domyślne systemu (mirror) Niestandardowy Układ + Kolor tła + Kolor wyświetlany za ekranami podczas emulacji, wyświetlany jako wartość RGB. + Czerwony + Zielony + Niebieski + Niestandardowy wygląd drugiego ekranu przezroczystości + Przezroczystość drugiego ekranu 3DS podczas korzystania z niestandardowego układu ekranu. Przydatne, jeśli drugi ekran ma być umieszczony nad pierwszym ekranem. Pozycja małego ekranu Gdzie powinien być wyświetlany mały ekran względem dużego w układzie dużego ekranu? Prawy górny róg @@ -511,12 +544,13 @@ Błąd zapisywania/wczytywania Krytyczny Błąd Wystąpił błąd krytyczny. Kontynuowanie emulacji może spowodować awarie i błędy. - Nieprawidłowy region Nieobsługiwana zaszyfrowana aplikacja + Nieprawidłowy moduł systemu + Aplikacje dostępne wyłącznie na konsoli New 3DS nie mogą być uruchamiane bez włączenia trybu New 3DS. Przygotowanie shaderów - Tworzenie shaderów + Tworzenie%s Odtwórz @@ -537,34 +571,39 @@ Utwórz skrót Nazwa skrótu nie może być pusta Rozciągnij, aby dopasować obraz + ID: + Plik: + Typ: + Włóż Kartridż + Wyjmij Kartridż Wyświetl nakładkę wydajności Nakładkę wydajności Włącz nakładkę wydajności Konfiguruje, czy wyświetlana jest nakładka wydajności i jakie informacje są wyświetlane. - Wyświetl FPS - Wyświetla aktualną liczbę klatek na sekundę. - Pokaż czas klatek - Wyświetla bieżący czas klatek. - Wyświetl Prędkość - Wyświetla aktualną procentową prędkość emulacji. - Wyświetl użycie pamięci aplikacji - Wyświetla ilość pamięci RAM używanej przez emulator. - Wyświetl dostępną pamięć - Wyświetla ilość dostępnej pamięci RAM. - Wyświetl temperaturę baterii - Wyświetla bieżącą temperaturę baterii w stopniach Celcjusza i Fahrenheita. - Pozycja nakładki - Wybierz miejsce wyświetlania nakładki wydajności na ekranie. - Lewy górny róg - Prawy górny róg - Lewy dolny róg - Prawy dolny róg - Środkowy górny - Środkowy dolny - Tło nakładki - Dodaje tło z tyłu nakładki w celu łatwego odczytu. + Wyświetl FPS + Wyświetla aktualną liczbę klatek na sekundę. + Wyświetl czas klatek + Wyświetla bieżący czas klatek. + Wyświetl Prędkość + Wyświetla aktualną procentową prędkość emulacji. + Wyświetl użycie pamięci aplikacji + Wyświetla ilość pamięci RAM używanej przez emulator. + Wyświetl dostępną pamięć + Wyświetla ilość dostępnej pamięci RAM. + Wyświetl temperaturę baterii + Wyświetla bieżącą temperaturę baterii w stopniach Celcjusza i Fahrenheita. + Pozycja nakładki + Wybierz miejsce wyświetlania nakładki wydajności na ekranie. + Lewy górny róg + Prawy górny róg + Lewy dolny róg + Prawy dolny róg + Środkowy górny + Środkowy dolny + Tło nakładki + Dodaje tło z tyłu nakładki w celu łatwego odczytu. Cheaty @@ -670,7 +709,7 @@ Obok Siebie - Odwróć Obok Siebie + Obok Siebie na Pełną Szerokość Analogiczny Naprzemienny Odwrócony Obraz @@ -859,4 +898,19 @@ Szybkie zapisywanie - %1$tF %1$tR Funkcja szybkiego zapisu nie jest dostępna. + + Kompresuj + Kompresowanie… + Dekompresuj + Dekompresowanie... + Kompresja została zakończona pomyślnie. + Kompresja nie jest obsługiwana dla tego pliku. + Plik jest już skompresowany. + Kompresja nie powiodła się. + Dekompresja została zakończona pomyślnie. + Dekompresja nie jest obsługiwana dla tego pliku. + Plik nie jest skompresowany. + Dekompresja nie powiodła się. + Aplikacje, które są już zainstalowane, nie mogą być kompresowane ani dekompresowane. + diff --git a/src/android/app/src/main/res/values-b+pt+BR/strings.xml b/src/android/app/src/main/res/values-b+pt+BR/strings.xml index 43f09e597..f963b9ad0 100644 --- a/src/android/app/src/main/res/values-b+pt+BR/strings.xml +++ b/src/android/app/src/main/res/values-b+pt+BR/strings.xml @@ -11,13 +11,13 @@ Opções Procurar Aplicativos - Definir configurações do emulador - Instale o arquivo CIA + Definir as configurações do emulador + Instalar arquivo CIA Instalar aplicativos, atualizações ou DLC - Compartilhar registro + Compartilhar Registro Compartilhe o arquivo de log do Azahar para depurar problemas - Gerenciador de driver da GPU - Instale o driver da GPU + Gerenciador de Driver da GPU + Instalar driver da GPU Instale drivers alternativos para poder obter desempenho ou precisão Driver já instalado Drivers personalizados não suportados @@ -27,15 +27,14 @@ Permitir que o Azahar preencha a lista de aplicativos Sobre Um emulador de 3DS de código aberto - Versão de compilação, créditos e mais - Diretório de aplicativos selecionado + Versão da compilação, créditos e mais + Diretório do aplicativo selecionado Altera os arquivos que o Azahar usa para carregar aplicativos Modificar a aparência do aplicativo - Instale a CIA - Saiba mais.]]> + Instalar arquivo CIA - Selecione o driver GPU + Selecionar driver da GPU Você quer substituir seu driver de GPU atual? Instalar Padrão @@ -67,16 +66,21 @@ Conceder permissão Ignorar a solicitação de notificação? O Azahar não poderá te notificar de informações importantes. + Permissões Ausentes + O Azahar requer permissão para gerenciar arquivos neste dispositivo a fim de armazenar e gerenciar seus dados.\n\nPor favor, conceda a permissão de \'Sistema de Arquivos\' antes de continuar. Câmera Conceda acesso a câmera abaixo para emular a câmera do 3DS. Microfone Conceda a acesso ao microfone abaixo para emular o microfone do 3DS. + Sistema de Arquivos + Conceda a permissão de arquivos abaixo para permitir que o Azahar armazene arquivos. Permissão negada Pular a seleção da pasta de aplicativos? Os softwares não serão exibidos na lista de Aplicativos se uma pasta não for selecionada. Premissões Pastas de Dados (Pasta de usuário é necessária)]]> + Conceda permissões opcionais para usar recursos específicos do emulador. Ajuda Pular Cancelar @@ -86,8 +90,12 @@ Manter diretório atual do Azahar Usar o diretório antigo do Lime3DS Selecionar + Você não pode pular a configuração da pasta do usuário. Este passo é necessário para permitir que o Azahar funcione. Selecione um diretório para continuar. Você perdeu suas permissões de escrita no seu diretório de dados de usuário, onde dados salvos e outras informações são guardadas. Isso pode acontecer depois que algum app ou Android atualiza. Re-selecione o diretório para reobter as permissões para que você possa continuar. + Seleção Inválida + A seleção do diretório de usuário é inválida.\nPor favor, selecione novamente o diretório de usuário, certificando-se de navegar até ele a partir da raiz do armazenamento do seu dispositivo. + O Azahar perdeu a permissão para gerenciar arquivos neste dispositivo. Isso pode acontecer após atualizações do aplicativo ou do Android. Por favor, conceda novamente esta permissão na próxima tela para continuar usando o app. Configurações de Tema Configure suas preferências de tema para o Azahar. Definir Tema @@ -110,8 +118,6 @@ Alguns controles podem não ser capazes de mapear os D-pads para um eixo. Se esse for o caso, use a seção de D-Pad (Botões). D-Pad (Botão) Só mapeie o D-pad para isso se você se você estiver encontrando problemas com o mapeamento de botão do D-Pad (Eixo). - Eixo vertical - Eixo horizontal Cima Baixo Esquerda @@ -120,8 +126,6 @@ Pressione ou mova uma entrada. Mapeamento de controles Pressione ou mova um botão/alavanca para mapear para %1$s. - Mova o seu joystick para cima ou para baixo. - Mova o seu joystick para esquerda ou para direita. Menu Principal Trocar telas Turbo @@ -160,6 +164,8 @@ Nome de usuário Modo do Novo 3DS Usar miniaplicativos LLE (se instalados) + Aplicar patch de região livre aos aplicativos instalados + Aplica um patch de região livre nos aplicativos instalados, para que eles sempre apareçam no menu inicial. Ativa os módulos LLE necessários para os recursos online (se instalado) Ativa os módulos LLE necessários para o multijogador online, acesso à eShop, etc. Relógio @@ -167,6 +173,7 @@ Configura o relógio emulado do 3DS para refletir o do seu dispositivo ou para começar numa data e hora simulados. Clock do Dispositivo Clock Simulado + Se o relógio estiver definido como \'Relógio simulado\', isso altera a data e hora fixas de início. Configurações de Perfil Região Linguagem @@ -190,6 +197,9 @@ Aviso de inconsistência de região O país configurado não é válido para a região emulada selecionada. O país configurado não é válido para o console vinculado atual. + Armazenamento + Comprimir conteúdo CIA instalado + Comprime o conteúdo dos arquivos CIA ao serem instalados no cartão SD emulado. Afeta apenas o conteúdo CIA instalado enquanto a opção estiver ativada. Câmera frontal @@ -209,26 +219,31 @@ API de gráficos Ativar geração de shaders SPIR-V Emite o fragment shader usado para emular PICA usando SPIR-V em vez de GLSL - Ativar a compilação assíncrona de shaders + Desativar otimizador SPIR-V + Desativa a etapa de otimização SPIR-V, reduzindo consideravelmente os travamentos, com impacto mínimo no desempenho. + Habilitar Compilação Assíncrona do Shader Compila shaders em segundo plano para reduzir travamentos durante o jogo. Quando ativado, espere falhas gráficas temporárias Filtragem Linear Ativa a filtragem linear, que suaviza o visual do jogo. Filtro de texturas Aprimora o visual dos aplicativos ao aplicar filtros às texturas. Os filtros compatíveis são: Anime4K Ultrafast, Bicúbico, ScaleForce, xBRZ Freescale e MMPX. - Atrasar thread de renderização do aplicativo + Atrasar Thread de Renderização do Aplicativo Atrasar thread de renderização do aplicativo quando for enviado dados para a GPU. Ajuda com problemas de desempenho em (muito poucos) aplicativos com taxa de quadros dinâmica. Avançado Amostragem de Texturas Substitui o filtro de amostragem usado pelos jogos. Isso pode ser útil em certos casos com jogos que se comportem mal durante o upscaling. Em caso de dúvidas, defina como Controlado pelo Jogo. Multiplicação precisa Utiliza uma multiplicação mais precisa de shaders no hardware, o que pode corrigir problemas visuais. Quando ativada, pode haver redução no desempenho. - Ativar emulação de GPU assíncrona + Habilitar Emulação de GPU Assíncrona Usa uma thread separada para emular a GPU de forma assíncrona. Esta opção aprimora o desempenho quando ativada. Limite de velocidade Quando ativo, a velocidade de emulação será limitada à uma porcentagem especificada da velocidade normal. Se desativado, a velocidade de emulação será destravada e a tecla de atalho do turbo não irá funcionar. Limite de velocidade percentual Especifica a porcentagem para limitar a velocidade. Com o padrão de 100% a emulação será limitada a velocidade normal. Valores maiores ou menores vão aumentar ou reduzir o limite de velocidade. + Esconder Imagens do 3DS do Android + Prevenir câmera do 3DS, screenshots e texturas personalizadas de serem indexadas pelo Android e mostradas na galeria. Seu dispositivo pode precisar ser reiniciado após mudar essa configuração para as mudanças serem efetuadas. Limite da Velocidade Turbo: + Limite de velocidade da emulação usado enquanto a tecla de atalho turbo está ativa. Expandir para a área recortada Expande a área da tela para incluir a área recortada (ou notch). Resolução Interna @@ -248,10 +263,18 @@ Aviso: modificar estas configurações tornará a emulação mais lenta Estereoscopia Modo 3D Estereoscópico + Escolha o modo 3D estereoscópico para a renderização 3D. Os modos Lado a Lado são os mais comuns atualmente. Os modos Anáglifo e Entrelaçado serão sempre aplicados a todas as telas conectadas. Profundidade Especifica o valor do controle deslizante 3D. Deve ser definido como superior a 0% quando o 3D Estereoscópico estiver ativado.\nNota: Valores de profundidade acima de 100% não são possíveis no hardware real e podem causar problemas gráficos Desativar a renderização do olho direito Melhora muito o desempenho em alguns aplicativos, mas pode causar piscadas em outros. + Inverter Olhos + Inverte qual olho é exibido em cada lado. Combinado com o modo Lado a Lado, torna possível ver em 3D cruzando os olhos! + Renderizar 3D Estereoscópico + Define se o 3D estereoscópico deve ser ativado e em quais telas. As opções de tela única só são relevantes quando várias telas estão conectadas. + Ativado (Todas as Telas) + Ativado (Apenas Tela Principal) + Ativado (Apenas Tela Secundária) VR Cardboard Tamanho da Tela do Cardboard Dimensiona a tela para uma porcentagem de seu tamanho original. @@ -276,7 +299,7 @@ Volume Alongamento de Áudio Estica o áudio para reduzir engasgos. Quando ativado, aumenta a latência do áudio e reduz levemente o desempenho. - Ativar áudio em tempo real + Ativar Áudio em Tempo Real Dimensiona a velocidade de reprodução de áudio para compensar quedas na taxa de quadros da emulação. Isso significa que o áudio será reproduzido em velocidade máxima mesmo quando a taxa de quadros do jogo estiver baixa. Pode causar problemas de dessincronização de áudio. Dispositivo de entrada de áudio Modo de Saída de Som @@ -288,16 +311,21 @@ Utiliza o hardware para emular os shaders do 3DS. Quando ativado, o desempenho do jogo será consideravelmente melhorado. Velocidade do Clock da CPU Ativar sincronização vertical - Sincroniza a taxa de quadros do jogo com a taxa de atualização da tela do seu dispositivo. + Sincroniza a taxa de quadros do jogo com a taxa de atualização do seu dispositivo. Pode causar latência de entrada adicional, mas pode reduzir o \"tearing\" (rasgo de tela) em alguns casos. Renderizador de Depuração Registre informações adicionais de depuração relacionadas a gráficos. Quando ativado, o desempenho do jogo será significativamente reduzido. - Limpar a saída do log a cada mensagem + Limpar a Saída do Log a Cada Mensagem Grava imediatamente o log de depuração no arquivo. Use isto se o Azahar travar e a saída do log estiver sendo cortada. - Atraso na inicialização com módulos LLE + Atraso na Inicialização com Módulos LLE Atrasa a inicialização do aplicativo quando os módulos LLE estão ativados. Operações Assíncronas Determinísticas Torna as operações assíncronas determinísticas para depuração. Ativar essa opção pode causar congelamentos. - + Ativar servidor RPC + Ativa o servidor RPC na porta 45987. Isso permite ler e escrever remotamente a memória do sistema emulado. + Ativar Shader JIT + Usa o mecanismo JIT em vez do interpretador para a emulação de shaders por software. + + Orientação da Tela Automático Paisagem @@ -344,8 +372,6 @@ Seleção Automática Iniciar Cancelando... - Importante - Não mostrar novamente Visibilidade Informação @@ -386,6 +412,10 @@ Configurar controles Editar Disposição Pronto + Deslizar Botão + Segurar o botão originalmente pressionado + Segurar o botão atualmente pressionado + Segurar o botão original e o atualmente pressionado Alternar controles Ajustar escala Escala Global @@ -398,6 +428,8 @@ Proporção da Tela Disposição de tela em paisagem Disposição da tela em retrato + Layout da Tela de Exibição Secundária + O layout usado por uma tela secundária conectada, com ou sem fio (Chromecast, Miracast) Tela Grande Retrato Tela única @@ -405,7 +437,15 @@ Telas Híbridas Original Padrão + Padrão do Sistema (espelhamento) Disposição Personalizada + Cor de Fundo + A cor que aparece atrás das telas durante a emulação, representada por um valor RGB. + Vermelho + Verde + Azul + Opacidade da Segunda Tela no Layout Personalizado + A opacidade da segunda tela do 3DS ao usar um layout de telas personalizado. Útil caso a segunda tela sobreponha a primeira. Posição da Tela Pequena Onde a tela pequena deverá aparecer relativa à grande na Disposição da Tela Grande? Superior Direita @@ -416,6 +456,8 @@ Inferior Esquerda Acima Abaixo + Espaço entre Telas + Espaço entre as telas em todos os modos de duas telas. Medido em pixels em relação à altura de 240 pixels da tela maior. Proporção de Tela Grande Quantas vezes maior é a tela grande em relação à tela pequena no Layout de Tela Grande? Ajuste a Disposição Personalizada nas Configurações @@ -429,7 +471,9 @@ Altura Trocar Disposições Trocar telas + Girar Tela para Posição Vertical Redefinir sobreposição + Mostrar Sobreposição do Controle Fechar jogo Alternar Pausa Diversos @@ -496,13 +540,12 @@ Erro ao Salvar/Carregar Erro Fatal Ocorreu um erro fatal. Verifique o registro para obter detalhes.\nContinuar a emulação pode resultar em falhas e bugs. - Região inválida Aplicativo criptografado não suportado + Modo de sistema inválido + Novos aplicativos exclusivos do New 3DS não podem ser carregados sem ativar o modo New 3DS. Preparando Shaders - Construindo Shaders - Jogar Desinstalar Aplicativo @@ -517,6 +560,45 @@ Desinstalar DLC Desinstalar atualizações Atalho + Nome do Atalho + Editar ícone + Criar Atalho + O nome do atalho não pode ficar vazio + Esticar para ajustar à imagem + ID: + Arquivo: + Tipo: + Inserir Cartucho + Ejetar Cartucho + + + Mostrar Sobreposição de Desempenho + Sobreposição de Desempenho + Ativa a Sobreposição de Desempenho + Configure se a sobreposição de desempenho será exibida e quais informações serão mostradas. + Mostrar FPS + Mostrar frames por segundo atuais. + Mostrar tempo de frame + Mostrar tempo de frame atual. + Mostrar velocidade + Mostrar atual porcentagem de velocidade da emulação. + Mostrar Uso da Memória pelo App + Mostrar o consumo de RAM pelo emulador. + Mostrar Memória Disponível + Mostrar a quantidade de RAM livre. + Mostrar Temperatura da Bateria + Mostrar atual temperatura da Bateria em Celsius e Fahrenheit. + Posição do Overlay + Escolha onde o overlay de performance é mostrado na tela. + Canto Superior Esquerdo + Canto Superior Direito + Canto Inferior Esquerdo + Canto Inferior Direito + Superior Central + Inferior Central + Plano de Fundo da Sobreposição + Adiciona um plano de fundo atrás do overlay para uma leitura mais fácil. + Truques Adicionar Trapaça @@ -620,7 +702,7 @@ Lado a Lado - Inverter Lado a Lado + Lado a Lado (Largura Total) Anáglifo Entrelaçado Entrelaçado Reverso @@ -809,4 +891,19 @@ Salvar rápido - %1$tF %1$tR Nenhum Salvamento Rápido disponível. + + Compactar + Compactando... + Descompactar + Descompactando... + Compactação concluída com sucesso. + Compactação não suportada para este arquivo. + O arquivo já está compactado. + A compactação falhou. + Descompactação concluída com sucesso. + Descompactação não suportada para este arquivo. + O arquivo não está compactado. + A descompactação falhou. + Aplicativos já instalados não podem ser compactados ou descompactados. + diff --git a/src/android/app/src/main/res/values-b+ru+RU/strings.xml b/src/android/app/src/main/res/values-b+ru+RU/strings.xml index b2e79499e..5772eb4c2 100644 --- a/src/android/app/src/main/res/values-b+ru+RU/strings.xml +++ b/src/android/app/src/main/res/values-b+ru+RU/strings.xml @@ -19,6 +19,7 @@ Версия сборки, разработчики и другое Настройка внешнего вида приложения Установить CIA + Выбрать драйвер GPU Заменить текущий драйвер GPU устройства? @@ -64,14 +65,10 @@ Триггеры Триггер Крестовина - Ось вверх/вниз - Ось влево/вправо Привязка %1$s %2$s Нажмите или отклоните элемент управления. Привязки ввода Нажмите или отклоните орган управления для привязки %1$s. - Наклоните джойстик вверх или вниз. - Наклоните джойстик влево или вправо. HOME Данный элемент управления должен быть привязан к аналоговому стику или крестовине геймпада! Данный элемент управления должен быть привязан к кнопке геймпада! @@ -120,14 +117,12 @@ Графический API Вкл. генерацию шейдеров на SPIR-V Запускать фрагментный шейдер, используемый для эмуляции PICA на SPIR-V вместо GLSL. - Вкл. асинхронную компиляцию шейдеров Компилировать шейдеры в фоновом потоке для уменьшения лагов во время игры. При включении возможны временные сбои графики. Линейное сглаживание Вкл. линейное сглаживание для смягчения графики в играх. Сглаживание текстур Точное умножение Исп. более точное умножение для аппаратных шейдеров. Может исправлять некоторые графические баги, но при включении снижает производительность. - Вкл. асинхронную эмуляцию GPU Использовать отдельный поток для асинхронной эмуляции GPU. При включении повышает производительность. Ограничивать скорость Процент ограничения скорости @@ -172,7 +167,6 @@ Эмулировать шейдеры 3DS аппаратными средствами. При включении существенно повышает производительность в играх. Скорость процессора Вкл. V-Sync - Синхронизирует кадровую частоту в играх с частотой обновления устройства. Отладка рендера Логировать расширенную отладочную информацию по графике. При включении существенно снижает производительность. @@ -310,8 +304,6 @@ Возникла критическая ошибка. Откройте лог для получения информации.\nВозобновление эмуляции может привести к сбоям и вылетам. Подготовка шейдеров - Построение шейдеров - Чит-коды Добавить чит-код diff --git a/src/android/app/src/main/res/values-b+tr+TR/strings.xml b/src/android/app/src/main/res/values-b+tr+TR/strings.xml index 1f5f10fcd..574a9d0e8 100644 --- a/src/android/app/src/main/res/values-b+tr+TR/strings.xml +++ b/src/android/app/src/main/res/values-b+tr+TR/strings.xml @@ -32,7 +32,6 @@ Azahar\'ın uygulama yüklemek için kullandığı dosyaları değiştirir Uygulamanın görünüşünü değiştir CIA Yükle - Daha fazla öğren.]]> GPU Sürücüsü seç @@ -74,6 +73,9 @@ İzin reddedildi Uygulama dosyasını seçmeyi atla? Eğer bir dosya seçili değilse yazılımlar uygulama listesinde görünmeyecektir. + İzinler + Veri Klasörleri + Emülatörün belirli özelliklerini kullanmak için isteğe bağlı izinler verin Yardım Atla İptal et @@ -83,6 +85,7 @@ Şimdiki Azahar Dizinini Koru Eski Lime3DS Dizinini Kullan Seç + Kullanıcı klasörü ayarlamayı atlayamazsınız Bu adım Azahar\'ın çalışması için gereklidir. Lütfen devam etmek için bir dizin seçin. Kayıtların ve diğer bilgilerin depolandığı kullanıcı verileridizininizdeki yazma izinlerini kaybettiniz. Bu durum bazı uygulama veya Android güncellemelerinden sonra meydana gelebilir. Devam edebilmeniz için lütfen izinleri yeniden kazanmak üzere dizini yeniden seçin. Tema Ayarları @@ -107,8 +110,6 @@ Bazı oyun kolları D-pad\'lerini bir eksen olarak atayamayabilir. Durum buysa D-Pad (butonlar) bölümünü kullanın. D-pad (Buton) Sadece D-Pad (Eksen) atamasında sorun yaşıyorsanız D-Pad\'inizi bunlara atayın. - Yukarı/Aşağı Eksen - Sol/Sağ Eksen Yukarı Aşağı Sol @@ -117,8 +118,6 @@ Bir girdiye basın veya hareket ettirin. Girdi Ataması Bir girdiyi %1$s e atamak için basın veya hareket ettirin. - Joystick\'inizi yukarı veya aşağı kaydırın. - Joystick\'inizi sağa veya sola kaydırın. HOME Ekranları değiştir Turbo @@ -185,7 +184,7 @@ Bölge Uyuşmazlık Uyarısı Ülke ayarı emülasyon bölgesi için geçerli değil. Ülke ayarı bağlı olan konsol için geçerli değil. - + Depolama   İç Kamera @@ -197,23 +196,24 @@ “Görüntü Kaynağı” ayarı ‘Cihaz Kamerası’ olarak ayarlanmışsa, bu ayar kullanılacak fiziksel kamerayı ayarlar. Ön Geri + Harici + Çevir + İşleyici Grafik API\'ı SPIR-V gölgelendirici oluşturmayı etkinleştir - Asenkron gölgeleme derlemesini etkinleştir Oyun sırasında takılmayı azaltmak için gölgelendiricileri arka planda derler. Etkinleştirildiğinde geçici grafik hataları meydana gelebilir. Doğrusal filtreleme Oyun görsellerinin daha pürüzsüz görünmesini sağlayan doğrusal filtrelemeyi etkinleştirir. Doku Filtresi Dokulara bir filtre uygulayarak uygulamaların görsellerini geliştirir. Desteklenen filtreler Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale ve MMPX\'tir. - Oyun işleme iş parçacığını geciktir GPU\'ya veri gönderirken oyun işleme iş parçacığını geciktirin. Dinamik kare hızlarına sahip (çok az sayıda) uygulamada performans sorunlarına yardımcı olur. + Gelişmiş Doku Örnekleme Uygulamalar tarafından kullanılan örnekleme filtresini geçersiz kılar. Bu, görüntü yükseltme sırasında hatalı davranan uygulamaların olduğu bazı durumlarda faydalı olabilir. Emin değilseniz, bunu Uygulama Kontrollü olarak ayarlayın. İsabetli Çoğaltma Donanım gölgelendiricilerinde daha doğru çarpım kullanır, bu da bazı grafik hatalarını düzeltebilir. Etkinleştirildiğinde performans düşecektir. - Asenkron GPU emülasyonunu etkinleştir GPU emülasyonunu asenkron olarak yapmak için ayrı bir iş parçacığı kullanır. Etkinleştirildiğinde performans artacaktır. Hızı Sınırlandır Etkinleştirildiğinde, emülasyon hızı normal hızın belirli bir yüzdesiyle sınırlandırılır. Devre dışı bırakılırsa, emülasyon hızı sınırlandırılmaz ve turbo hız kısayol tuşu çalışmaz. @@ -221,6 +221,7 @@ Emülasyon hızını sınırlamak için yüzdeyi belirtir. Varsayılan değer olan %100 ile emülasyon normal hız ile sınırlandırılacaktır. Daha yüksek veya daha düşük değerler hız sınırını artıracak veya azaltacaktır Etkinleştirildiğinde, emülasyon hızı normal hızın belirli bir yüzdesiyle sınırlandırılacaktır. Devre dışı bırakılırsa, emülasyon hızı sınırlandırılmaz ve turbo hız kısayol tuşu çalışmaz. Turbo Hız Limiti Turbo kısayolu aktfiken kullanılan emülasyon hız limiti. + Kesme Alanına Genişlet İç Çözünürlük Render için kullanılan çözünürlüğü belirtir. Yüksek çözünürlük görsel kaliteyi çok artıracaktır ancak performans açısından da oldukça ağırdır ve bazı uygulamalarda aksaklıklara neden olabilir. Otomatik (Ekran Boyutu) @@ -260,7 +261,7 @@ Ses düzeyi Ses Gerdirme Takılmayı azaltmak için sesi esnetir. Etkinleştirildiğinde, ses gecikmesini artırır ve performansı biraz düşürür. - Gerçek zamanlı sesi etkinleştir + Gerçek Zamanlı Sesi Etkinleştir Emülasyon kare hızındaki düşüşleri hesaba katmak için ses çalma hızını ölçeklendirir. Bu, oyun kare hızı düşük olsa bile sesin tam hızda çalınacağı anlamına gelir. Ses senkronizasyon sorunlarına neden olabilir. Ses Giriş Cihazı Ses Çıkış Modu @@ -272,15 +273,13 @@ 3DS shader\'larının emülasyonu için donanımı kullanır. Etkinleştirildiğinde oyun performansı önemli ölçüde artacaktır. CPU Saat Hızı V-Sync\'i Etkinleştir - Oyun kare hızını cihazınızın yenileme hızına senkronize eder. Hata Ayıklama İşleyicisi Grafiklerle ilgili ek hata ayıklama bilgilerini günlüğe kaydedin. Etkinleştirildiğinde, oyun performansı önemli ölçüde azalacaktır. - Her mesajda günlük çıktısını temizle Hata ayıklama günlüğünü hemen dosyaya işler. Azahar çöküyor ve günlük çıktısı kesiliyorsa bunu kullanın. - LLE modülleriyle başlamayı geciktir LLE modülleri etkinken uygulamanın başlamasını geciktirir Deterministik Asenkron İşlemler Hata ayıklama için asenkron işlemleri deterministik hale getirir. Bunu etkinleştirmek donmalara neden olabilir. + RPC Sunucusunu Etkinleştir Ekran Yönelimi Otomatik @@ -288,6 +287,13 @@ Ters Yatay Portre Ters Portre + Varsayılan + 16:9 + 4:3 + 21:9 + 16:10 + Gerdir + Temizle Varsayılan @@ -303,6 +309,7 @@ Varsayılanlara Sıfırla oyun kartuşlarınızı veya yüklü başlıklarınızıyeniden yüklemek için kılavuzları izleyin.]]> Varsayılan + Otomatik Kapalı Yükle Sil @@ -319,8 +326,9 @@ Otomatik Seç Başlat İptal ediliyor... - Önemli - Tekrar gösterme + Görünürlük + Bilgi + Oyun Dosyası Seç @@ -358,12 +366,14 @@ Kontrolleri Yapılandır Düzeni Değiştir Bitti + Buton Kayması Ölçeği Ayarla Tümünü Sıfırla Görünürlüğü Ayarla D-Pad kayması Ayarları Aç Hileleri Aç + En Boy Oranı Yatay Ekran Düzeni Dikey Ekran Düzeni Büyük Ekran @@ -373,7 +383,12 @@ Hibrit Ekranlar Orijinal Varsayılan + Sistem Varsayılanı (ayna) Özel Düzen + Arkaplan Rengi + Kırmızı + Yeşil + Mavi Küçük Ekran Konumu Büyük Ekran Düzeninde küçük ekran büyük ekrana kıyasla nerede olmalı? Sağ Üst @@ -399,6 +414,7 @@ Yükseklik Ekranları Değiştir Yerleşimi Sıfırla + Kontrolcü Yerleşimini Göster Oyunu Kapat Duraklatmayı Aç / Kapat Çeşitli @@ -462,13 +478,9 @@ Kaydetme/yükleme Hatası Ölümcül Hata Ölümcül bir hata oluştu. Ayrıntılar için log\'u kontrol edin.\nEmülasyona devam etmek çökmelere ve hatalara neden olabilir. - Geçersiz bölge Desteklenmeyen şifreli uygulama - Gölgelendiriciler Hazırlanıyor - Gölgelendiriciler Oluşturuluyor - Oyna Uygulamayı Sil @@ -483,6 +495,22 @@ DLC\'leri Sil Güncellemeleri Sil Kısayol + Kısayol Adı + Simgeyi düzenle + Kısayol Oluştur + ID: + Dosya: + Tür: + FPS\'i Göster + Hızı Göster + Kullanılabilir Belleği Göster + Pil Sıcaklığını Göster + Sol Üst + Sağ Üst + Sol Alt + Sağ Alt + Orta Üst + Orta Alt Hileler Hile Ekle @@ -585,7 +613,6 @@ Yan Yana - Ters Yan Yana Anaglif Geçmeli Ters Geçmeli @@ -603,6 +630,7 @@ Oyun Kontrollü + En Yakın Komşu Lineer @@ -773,4 +801,4 @@ Hızlı Kayıt - %1$tF %1$tR Hiçbir Hızlı Kayıt mevcut değil. - + diff --git a/src/android/app/src/main/res/values-b+zh+CN/strings.xml b/src/android/app/src/main/res/values-b+zh+CN/strings.xml index dae8dbe41..b417e255f 100644 --- a/src/android/app/src/main/res/values-b+zh+CN/strings.xml +++ b/src/android/app/src/main/res/values-b+zh+CN/strings.xml @@ -32,7 +32,6 @@ 更改 Azahar 用于加载应用的相关文件 更改应用程序的外观 安装 CIA - 了解详情。]]> 选择 GPU 驱动 @@ -112,8 +111,6 @@ 有些控制器可能无法将其方向键映射为轴。如果是这种情况,只能使用方向键(按键)部分。 十字键(按键) 仅当您在方向键 (轴) 映射遇到问题时,才将方向键映射到这些按键。 - 上/下轴 - 左/右轴 @@ -122,8 +119,6 @@ 按下或移动以进行输入。 绑定输入 按下按键或轻推摇杆,将其绑定到 %1$s。 - 向上或向下轻推您的摇杆。 - 向左或向右轻推您的摇杆。 HOME 交换屏幕 加速 @@ -193,6 +188,9 @@ 区域不匹配警告 此国家/地区设置对于所选择的模拟区域无效。 此国家/地区设置对于当前关联的掌机无效。 + 存储 + 压缩已安装的 CIA 内容 + 安装到模拟 SD 卡时,压缩 CIA 文件的内容。仅影响启用此设置时安装的 CIA 内容。 内置摄像头 @@ -233,6 +231,8 @@ 启用后,模拟速度将被限制为正常速度的指定百分比。如果禁用,模拟速度则不受限制,并且加速热键将不起作用。 限制运行速度百分比 指定限制运行速度的百分比。默认情况下,100% 将限制为正常运行速度。较高或较低的值将增加或降低运行速度。 + 在安卓设备上隐藏 3DS 图像 + 阻止 Android 索引 3DS 摄像、屏幕截图和自定义纹理图像并将其显示在图库中。更改此设置后,可能需要重启设备才能生效。 加速限制 加速热键激活时使用的模拟速度限制。 扩展到裁剪区域 @@ -259,7 +259,7 @@ 禁用右眼渲染 极大地提高某些应用的性能,但可能会导致其他应用出现闪烁。 Cardboard VR - Cardboard 屏幕尺寸 + 纸板屏幕大小 将屏幕缩放至其原始大小的指定百分比。 水平偏移 指定用于水平移动屏幕的百分比。正值会将左右两个视野移向中间,而负值会将左右两个视野向外侧移动。 @@ -294,10 +294,10 @@ 使用硬件模拟 3DS 着色器。启用后,游戏性能将显著提高。 CPU 时钟频率 启用垂直同步 - 将游戏帧率与设备的屏幕刷新率同步。 + 将游戏帧率与设备的屏幕刷新率同步。可能会增加输入延迟,但在某些情况下可以减少画面撕裂。 调试渲染器 记录更多与图形相关的调试信息。启用后,游戏性能将显著降低。 - 刷新每条消息的日志输出 + 每条消息都刷新日志输出 立即将调试日志提交到文件。如果 Azahar 崩溃并且日志输出被切断,请使用此选项。 使用 LLE 模块延迟启动 当 LLE 模块启用时延迟应用的启动。 @@ -355,8 +355,6 @@ 自动选择 开始 取消中… - 重要提示 - 不再显示 可见度 信息 @@ -397,18 +395,24 @@ 控制设置 编辑布局 完成 + 按键滑行 + 按住起始按下的按键 + 按住当前按下的按键 + 按住起始和当前按下的按键 切换控制 调整大小 全局缩放 重置全部 调整透明度 相对摇杆中心 - 十字方向键滑动 + 十字键滑行 打开设置项 开启金手指 宽高比 屏幕布局 纵向屏幕布局 + 副屏幕布局 + 有线或无线连接的副屏幕使用布局(Chromecast, Miracast) 大屏幕 纵向 单个屏幕 @@ -416,7 +420,15 @@ 混合式屏幕 原始 默认 + 系统默认(镜像) 自定义布局 + 背景颜色 + 在模拟运行时屏幕后面出现的颜色,以 RGB 值表示。 + + 绿 + + 自定义布局副屏幕不透明度 + 使用自定义屏幕布局时, 3DS 副屏的不透明度。当副屏位于主屏前面时,此选项很有用。 小屏幕位置 在“大屏幕”布局中,小屏幕相对于大屏幕应该出现的位置? 右上 @@ -513,13 +525,9 @@ 保存/读取出现错误 致命错误 发生致命错误。请查阅日志获取相关信息。\n继续模拟可能会导致错误和崩溃。 - 无效的地区 不支持的加密应用 - 正在准备着色器 - 正在构建着色器 - 开始游戏 卸载应用 @@ -539,34 +547,36 @@ 创建快捷方式 快捷方式名称不能为空 拉伸以适合图像 - + ID: + 文件: + 类型: 显示性能参数 性能参数覆盖 启用性能参数覆盖 设置是否显示性能参数以及其他覆盖信息。 - 显示帧率 - 显示当前每秒帧数。 - 显示帧生成时间 - 显示当前帧生成时间。 - 显示速度 - 显示当前模拟速度百分比。 - 显示应用内存占用 - 显示模拟器使用的内存容量。 - 显示可用内存 - 显示可用的内存容量。 - 显示电池温度 - 以摄氏度和华氏度显示当前电池温度。 - 覆盖位置 - 选择性能参数覆盖在屏幕上的显示位置。 - 左上 - 右上 - 左下 - 右下 - 中上 - 中下 - 覆盖背景 - 在覆盖层后面添加背景以便于识别。 + 显示帧率 + 显示当前每秒帧数。 + 显示帧生成时间 + 显示当前帧生成时间。 + 显示速度 + 显示当前模拟速度百分比。 + 显示应用内存使用情况 + 显示模拟器占用的内存大小。 + 显示可用内存 + 显示可用的内存大小。 + 显示电池温度 + 以摄氏度和华氏度显示当前电池温度。 + 覆盖位置 + 选择性能参数覆盖在屏幕上的显示位置。 + 左上 + 右上 + 左下 + 右下 + 中上 + 中下 + 覆盖背景 + 在覆盖层后面添加背景以便于识别。 金手指 @@ -671,7 +681,6 @@ 并排屏幕 - 反向并排 立体图形 交错 逆向交错 @@ -860,4 +869,4 @@ 快速保存 - %1$tF %1$tR 没有可用的快速保存。 - + diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 9a246b99d..5286641ed 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -32,7 +32,6 @@ Ändere die Dateien, die Azahar nutzt, um Anwendungen zu laden Ändere das Aussehen der App CIA Installieren - Erfahre mehr.]]> GPU-Treiber auswählen @@ -112,8 +111,6 @@ Einige Controller sind nicht in der Lage, das Steuerkreuz als Achse zuzuordnen. Wenn das der Fall ist, dann nutze den Abschnitt: „Steuerkreuz (Knöpfe)“. Steuerkreuz (Knöpfe) Nutze diese Funktion nur, wenn du Probleme mit der Funktion „Steuerkreuz (Achse) hast“. - Achse (Oben/Unten) - Achse (Links/Rechts) Hoch Runter Links @@ -122,8 +119,6 @@ Drücke eine Taste, oder bewege einen Stick Eingabeverknüpfung Drücke eine Taste, oder bewege einen Stick, um diesen als %1$s einzustellen. - Bewege den Joystick nach oben oder unten. - Bewegen den Joystick nach links oder rechts. HOME Bildschirme tauschen Turbo @@ -193,6 +188,9 @@ Region passt nicht überein Die Ländereinstellung ist für die ausgewählte emulierte Region nicht gültig. Die Ländereinstellung ist für die gekoppelte Konsole ungültig. + Speicher + Komprimiere installierten CIA Kontent + Komprimiert den Inhalt von CIA-Dateien, wenn diese auf der emulierten SD-Karte installiert werden. Betrifft nur CIA-Inhalte, die installiert werden, während die Einstellung aktiviert ist. Innenkamera @@ -214,20 +212,17 @@ Gibt den Fragment-Shader aus, der zur Emulation von PICA unter Verwendung von SPIR-V statt GLSL verwendet wird. SPIR-V Optimierer deaktivieren Deaktiviert den SPIR-V Optimierungsschritt, was stottern reduziert und die Leistung nur geringfügig beeinflusst. - Asynchrone GPU-Emulation aktivieren Kompiliere Shader im Hintergrund, um das Stottern des Spiels zu reduzieren. Dadurch kann es zu temporären grafischen Fehlern während des Spielens kommen. Lineare Filterung Aktiviert lineare Filterung, welche die Spieltexturen glättet. Texturfilter Verbessert die Optik von Anwendungen durch Anwenden eines Filters auf Texturen. Die unterstützten Filter sind Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale und MMPX. - Game-Render-Thread verzögern Verzögert den Render-Thread des Spiels, wenn er Daten an die GPU sendet. Hilft bei Leistungsproblemen in den (sehr wenigen) Anwendungen mit dynamischen Frameraten. Erweitert Textur-Sampling Setzt den von Spielen verwendeten Sampling-Filter außer Kraft. Dies kann in bestimmten Fällen nützlich sein, wenn sich die Spiele beim Hochskalieren schlecht verhalten. Wenn du dir unsicher bist, setze diese Einstellung auf „Spielgesteuert“ Genaue Multiplikation Benutzt genauere Multiplikation in Hardware-Shadern, welche einige Grafikbugs fixen kann. Wenn aktiviert, ist die Leistung reduziert. - Asynchrone GPU-Emulation aktivieren Verwendet einen separaten Thread, um die GPU asynchron zu emulieren. Wenn aktiviert, wird die Leistung verbessert. Höchstgeschwindigkeit Wenn aktiviert, wird die Emulationsgeschwindigkeit auf einen angegebenen Prozentsatz der normalen Geschwindigkeit begrenzt. Wenn diese Option deaktiviert ist, wird die Emulationsgeschwindigkeit nicht begrenzt und der Hotkey für die Turbogeschwindigkeit funktioniert nicht. @@ -282,7 +277,6 @@ Lautstärke Audiodehnung Dehnt Audio, um Stottern zu reduzieren. Wenn aktiviert, wird die Audiolatenz erhöht und die Leistung leicht verschlechtert. - Echtzeitaudio aktivieren Skaliert die Tonabspielgeschwindigkeit, um Einbrüche in der Emulationsframerate zu minimieren. Das bedeutet, dass der Ton in voller Geschwindigkeit abspielt, selbst wenn die Framerate des Spiels niedrig ist. Kann zu Tonverschiebungen führen. Audioeingabegerät Tonausgabemodus @@ -294,12 +288,9 @@ Benutzt Hardware, um die 3DS-Shader zu emulieren. Wenn aktiviert, wird die Spielleistung stark verbessert. CPU-Takt-Rate V-Sync aktivieren - Synchronisiert die Bildrate des Spiels mit der Bildwiederholrate des Geräts. Debug-Renderer Zusätzliche grafisch spezifische Debuginformationen werden protokolliert. Wenn dies aktiviert ist, ist die Leistung des Spiels minimal reduziert. - Protokollausgabe bei jeder Nachricht Überträgt das Debugprotokoll sofort in eine Datei. Verwenden Sie dies, wenn Azahar abstürzt und die Protokollausgabe abgeschnitten wird. - Start mit LLE-Module verzögern Verzögert den Start der App, wenn die LLE-Module aktiviert sind. Deterministische asynchrone Operationen Asynchrone Operationen werden für Debug-Zwecke deterministisch. Die Aktivierung dieser Funktion kann zum Einfrieren führen. @@ -355,8 +346,6 @@ Automatisch auswählen Start Wird abgebrochen... - Wichtig - Nicht noch einmal anzeigen Sichtbarkeit Information @@ -511,13 +500,9 @@ Fehler beim Speichern/Laden Schwerwiegender Fehler Es ist ein schwerwiegender Fehler aufgetreten. Weitere Informationen findest du in der Protokolldatei.\nDas Fortfahren könnte zu ungewollten Abstürzen oder Problemen führen. - Ungültige Region Nicht unterstützte verschlüsselte Anwendung - Shader werden vorbereitet - Shader werden erstellt - Spielen Anwendung deinstallieren @@ -532,15 +517,16 @@ DLC deinstallieren Updates deinstallieren Verknüpfung - Links Oben - Rechts Oben - Links Unten - Rechts Unten - Oben Mittig - Unten Mittig - Overlay Hintergrund - Fügt einen Hintergrund hinter dem Overlay hinzu für bessere Lesbarkeit. - + Verknüpfungsname + Symbol bearbeiten + Verknüpfung erstellen + Verknüpfungsname darf nicht leer sein + Bildgröße anpassen + + Leistungs-Overlay anzeigen + Leistungs-Overlay + Leistungsoverlay aktivieren + Konfigurieren Sie, ob das Leistungs-Overlay angezeigt wird und welche Informationen angezeigt werden. Cheats Cheat hinzufügen @@ -643,7 +629,6 @@ Nebeneinander - Invers Nebeneinander Anaglyphen Überlappend Invers überlappend @@ -832,4 +817,4 @@ Schnellspeichern - %1$tF %1$tR Kein Schnellspeicher vorhanden. - + diff --git a/src/android/app/src/main/res/values-el/strings.xml b/src/android/app/src/main/res/values-el/strings.xml index de2bd17a2..58ab06582 100644 --- a/src/android/app/src/main/res/values-el/strings.xml +++ b/src/android/app/src/main/res/values-el/strings.xml @@ -4,6 +4,7 @@ Εγκατάσταση αρχείου CIA Σχετικά Εγκατάσταση CIA + Εγκατάσταση Εγκαταστάθηκε %s diff --git a/src/android/app/src/main/res/values-fi/strings.xml b/src/android/app/src/main/res/values-fi/strings.xml index a44d0d32a..a6b180445 100644 --- a/src/android/app/src/main/res/values-fi/strings.xml +++ b/src/android/app/src/main/res/values-fi/strings.xml @@ -6,10 +6,6 @@ C-Tikku Liipaisimet D-Pad - Ylä/ala-akseli - Vasen/oikea akseli - Liikuta tattia ylös tai alas. - Liikuta tattia vasemmalle tai oikealle. Nappulat Järjestelmän kellotyyppi @@ -38,7 +34,6 @@ Aktivoi Laitteistovarjostin Käyttää laitteistoa emuloidakseen 3DS:n varjostimia. Kun tämä on päällä, pelien suorituskyky on huomattavasti parempi. Aktivoi V-Sync - Synkronoi pelin virkistystaajuus laitteesi virkistystaajuuteen. Tyhjennä Oletus diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index 5fb5c1d5e..95a18358a 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -32,7 +32,6 @@ Modifie les fichiers utilisés par Azahar pour charger les applications Modifier l\'apparence de l\'application Installer un CIA - En savoir plus.]]> Sélectionner le pilote du GPU @@ -67,10 +66,14 @@ Accorder l\'autorisation Ne pas autoriser les notifications ? Azahar ne pourra pas vous avertir des informations importantes. + Autorisations manquantes + Azahar a besoin de l\'autorisation de gérer les fichiers de cet appareil afin de stocker et gérer ses données.\n\nVeuillez accorder l\'autorisation \"Accès à tous les fichiers\" avant de continuer. Caméra Accorder l\'autorisation de la caméra ci-dessous pour émuler la caméra 3DS. Microphone Accorder l\'autorisation du microphone ci-dessous pour émuler le microphone 3DS. + Accès à tous les fichiers + Accordez l\'autorisation de l\'accès à tous les fichiers ci-dessous pour autoriser Azahar à stocker des fichiers. Autorisation refusée Passer la sélection du dossier des applications ? Les logiciels ne seront pas affichés dans la liste des applications si un dossier n\'est pas sélectionné. @@ -90,6 +93,9 @@ Vous ne pouvez pas ignorer la configuration du dossier utilisateur Cette étape est requise pour permettre à Azahar de fonctionner. Sélectionnez un répertoire et ensuite vous pourrez continuer. Vous avez perdu les droits d\'écriture sur votre répertoire de données utilisateur, où sont stockées les sauvegardes et autres informations. Cela peut se produire après certaines mises à jour d\'applications ou d\'Android. Veuillez resélectionner le répertoire pour récupérer les droits d\'accès afin de pouvoir continuer. + Sélection Invalide + La sélection du répertoire utilisateur était invalide.\nVeuillez re-sélectionner le répertoire utilisateur, en s\'assurant de le sélectionner depuis la racine du stockage de votre appareil. + Azahar a perdu l\'autorisation de gérer les fichiers de cet appareil. Cela peut arriver suite à des mises à jour d\'applis ou d\'Android. Veuillez ré-accorder cette autorisation sur l\'écran suivant pour continuer d\'utiliser l\'appli. Paramètres du thème Configurez les préférences de votre thème pour Azahar. Mettre le thème @@ -112,8 +118,8 @@ Certaines manettes ne sont pas en mesure d\'affecter leur manette + à un axe. Dans ce cas, utilisez la section manette + (boutons). Manette + (bouton) N\'affectez la manette + à ces boutons que si vous rencontrez des problèmes avec l\'affectation des boutons de la manette + (axes). - Axe Haut/Bas - Axe Gauche/Droite + Axe Vertical + Axe Horizontal Haut Bas Gauche @@ -122,8 +128,8 @@ Appuyez ou faites bouger une touche. Liaison de boutons Appuyez ou déplacez pour la rattacher à %1$s. - Déplacez votre joystick vers le haut ou vers le bas. - Déplacez votre joystick à gauche ou à droite. + Déplacez votre joystick vers le HAUT. + Déplacez votre joystick vers la DROITE. HOME Permuter les écrans Turbo @@ -162,6 +168,8 @@ Nom d\'utilisateur Mode New 3DS Utilise les applets LLE (si installés) + Appliquer des correctifs pour désactiver les restrictions régionales des applications installées + Corrige la région des applications installées pour qu\'elles soient sans région, afin qu\'elles apparaissent toujours dans le menu home. Activer les modules LLE requis pour les fonctionnalités en ligne (si installés) Active les modules LLE nécessaires pour le multijoueur en ligne, l\'accès à l\'eShop, etc. Horloge @@ -193,6 +201,9 @@ Avertissement d\'incompatibilité de région Le paramètre de pays n\'est pas valide pour la région émulée sélectionnée. Le paramètre de pays n\'est pas valide pour la console actuellement connectée. + Stockage + Compresser le contenu CIA installé + Compresse le contenu des fichiers CIA lorsqu\'ils sont installés sur la carte SD émulée. N\'affecte que le contenu CIA installé lorsque le paramètre est activé. Caméra intérieure @@ -220,19 +231,21 @@ Active le filtrage linéaire, qui améliorera le lissage graphique du jeu. Filtrage des textures Améliore l\'aspect visuel des applications en appliquant un filtre aux textures. Les filtres pris en charge sont Anime4K Ultrafast, Bicubique, ScaleForce, xBRZ freescale et MMPX. - Retarde le rendu de thread du jeu + Retarder le thread de rendu du jeu Délai le thread de rendu du jeu lorsqu\'il soumet des données au GPU. Cela permet de résoudre les problèmes de performance dans les (très rares) applications avec des fréquences d\'images dynamiques. Avancé Échantillonnage de texture Remplace le filtre d\'échantillonnage utilisé par les jeux. Cela peut être utile dans certains cas où les jeux se comportent mal lors de la conversion ascendante. En cas de doute, réglez ce paramètre sur « Contrôlé par le jeu ». Multiplication précise Utilise une multiplication plus précise dans les shaders hardware, ce qui peut corriger certains bugs graphiques. Lorsqu\'elle est activée, la performance sera réduite. - Active l\'émulation asynchone du GPU + Activer l\'émulation asynchrone du GPU Utilise une unité d’exécution séparée pour émuler le GPU de manière asynchrone. La performance sera améliorée. Limite de vitesse Une fois activée, la vitesse d\'émulation sera limitée à un pourcentage spécifié de la vitesse normale. Si elle est désactivée, la vitesse d\'émulation ne sera pas limitée et le raccourci clavier turbo ne fonctionnera pas. Limiter le pourcentage de vitesse Définit le taux de limitation de la vitesse d\'émulation. À 100%, par défaut, l\'émulation sera limitée à la vitesse normale. Des valeurs supérieures ou inférieures augmenteront ou diminueront la limite de la vitesse. + Cacher à Android les images 3DS + Empêche les photos, captures d\'écran et textures personnalisées 3DS d\'être indexées par Android et affichées dans la galerie. Votre appareil pourrait nécessiter un redémarrage pour que ce paramètre prenne effet après son changement. Turbo Speed Limite Limite de vitesse d\'émulation utilisée lorsque la touche de raccourci turbo est active. Étendre à la zone de découpe @@ -254,10 +267,18 @@ Attention : Modifier ces paramètres ralentira l\'émulation Stéréoscopie Mode 3D stéréoscopique + Choisissez le mode de 3D stéréoscopique pour l\'affichage 3D. Les modes Côte à Côte sont les plus courants en utilisation moderne. Les modes Anaglyphe et Entrelacé seront toujours appliqués à tout les écrans connectés. Profondeur Spécifie la valeur du curseur 3D. Cette valeur doit être supérieure à 0 % lorsque la 3D stéréoscopique est activée. Remarque : les valeurs de profondeur supérieures à 100 % ne sont pas possibles sur du matériel réel et peuvent entraîner des problèmes graphiques. Désactiver le rendu de l\'œil droit Améliore considérablement les performances dans certaines applications, mais peut provoquer des scintillements dans d\'autres. + Intervertir les yeux + Intervertis quel œil est affiché de quel côté. Combiné avec le mode Côte à Côte il est possible de voir en 3D en croisant vos yeux ! + Afficher la 3D stéréoscopique + Choisir s\'il faut activer la 3D stéréoscopique, et sur quel(s) écran(s). Les options d\'écran unique ne sont utiles que lorsque plusieurs écrans sont connectés. + Activé (Tous les écrans) + Activé (Écran principal uniquement) + Activé (Écran secondaire uniquement) Réalité virtuelle Cardboard Taille de l\'écran Cardboard Redimensionne l\'écran à un pourcentage de sa taille d\'origine. @@ -294,7 +315,7 @@ Utilise le hardware pour émuler les shaders de la 3DS. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative. Fréquence d\'horloge du CPU Activer la synchronisation verticale (VSync) - Synchronise la fréquence d\'images du jeu avec la fréquence de rafraîchissement de votre appareil. + Synchronise la fréquence d\'images du jeu avec la fréquence de rafraîchissement de votre appareil. Peut rajouter de la latence d\'entrée mais peut réduire le tearing dans certains cas. Rendu de débogage Enregistre des informations de débogage supplémentaires liées aux graphiques. Lorsqu\'il est activé, les performances du jeu seront significativement réduites. Vider la sortie des logs sur chaque message @@ -355,8 +376,6 @@ Sélection Automatique Démarrer Annulation... - Important - Ne pas montrer à nouveau Visibilité Information @@ -397,6 +416,10 @@ Configurer les commandes Modifier la disposition Terminé + Bouton coulissant + Maintenez le bouton initialement enfoncé + Maintenez le bouton enfoncé + Maintenez enfoncé le bouton d\'origine et celui qui est actuellement enfoncé Alterner les commandes Ajuster la taille Taille globale @@ -409,6 +432,8 @@ Rapport d\'aspect Disposition en mode paysage Disposition en mode portait + Disposition de l\'écran secondaire + La disposition utilisée par un écran secondaire connecté par câble ou sans fil (Chromecast, Miracast) Écran large Mode portrait Un seul écran @@ -416,7 +441,15 @@ Écrans hybrides Original Défaut + Par défaut (dupliquer) Disposition personnalisée + Couleur de fond + La couleur qui apparaît derrière les écrans pendant l\'émulation, représentée par une valeur RGB. + Rouge + Vert + Bleu + Opacité du deuxième écran dans la disposition personnalisée + L\'opacité du deuxième écran 3DS lors de l\'utilisation d\'une disposition personnalisée. Utile si le deuxième écran est au-dessus du premier. Position petit écran Où le petit écran doit-il apparaître par rapport au grand écran dans la disposition Écran large ? En haut à droite @@ -511,13 +544,12 @@ Erreur de sauvegarde/chargement Erreur fatale Une erreur fatale s\'est produite. Veuillez consulter les logs pour plus de détails.\nPoursuivre l\'émulation peut entraîner des plantages et des bugs. - Région invalide Application encryptée non supportée + Mode système invalide + Les applications exclusives à la New 3DS ne peuvent pas être chargées sans activer le mode New 3DS. Préparation des shaders - Construction des shaders - Jouer Désinstaller l\'application @@ -537,34 +569,39 @@ Créer un raccourci Le nom du raccourci ne peut pas être vide Étirer pour ajuster l\'image + ID : + Fichier : + Type : + Insérer Cartouche + Éjecter Cartouche Afficher l\'overlay des performances Overlay des performances Activer l\'overlay des performances Configurez si l\'overlay des performances doit être affichée et quelles informations doivent être affichées. - Afficher les FPS - Afficher le nombre d\'images par seconde actuel. - Afficher le temps d\'affichage - Afficher le temps d\'affichage actuel. - Afficher la vitesse - Afficher le pourcentage actuel de la vitesse d\'émulation. - Afficher l\'utilisation de la mémoire par l\'application - Affichez la quantité de RAM utilisée par l\'émulateur. - Afficher la mémoire disponible - Afficher la quantité de RAM disponible. - Afficher la température de la batterie - Afficher la température actuelle de la batterie en degrés Celsius et Fahrenheit. - Position de l\'overlay - Choisissez l\'emplacement d\'affichage de l\'overlay des performances à l\'écran. - En haut à gauche - En haut à droite - En bas à gauche - En bas à droite - Au centre en haut - Au centre en bas - Overlay de l\'arrière-plan - Ajoute un arrière-plan derrière l\'overlay pour faciliter la lecture. + Afficher IPS + Afficher le nombre actuel d\'images par seconde. + Afficher le temps d\'affichage d\'une image + Afficher le temps d\'affichage actuel d\'une image. + Afficher la vitesse + Afficher le pourcentage actuel de la vitesse d\'émulation. + Afficher l\'utilisation de la mémoire par l\'application + Affichez la quantité de RAM utilisée par l\'émulateur. + Afficher la mémoire disponible + Afficher la quantité de RAM disponible. + Afficher la température de la batterie + Afficher la température actuelle de la batterie en degrés Celsius et Fahrenheit. + Position de l\'overlay + Choisissez l\'emplacement d\'affichage de l\'overlay des performances à l\'écran. + En haut à gauche + En haut à droite + En bas à gauche + En bas à droite + Au centre en haut + Au centre en bas + Arrière-plan de l\'overlay + Ajoute un arrière-plan derrière l\'overlay pour faciliter la lecture. Codes de triche @@ -669,7 +706,7 @@ Côte à côte - Côte à côte inversé + Côte à côte largeur maximale Anaglyphe Entrelacé Entrelacement inversé @@ -858,4 +895,19 @@ Sauvegarde rapide - %1$tF %1$tR Aucune sauvegarde rapide disponible. + + Compresser + Compression ... + Décompresser + Décompression ... + La compression a été réalisée avec succès. + La compression n\'est pas supportée pour ce fichier. + Le fichier est déjà compressé. + Échec de la compression. + La décompression a été réalisée avec succès. + La décompression n\'est pas supportée pour ce fichier. + Le fichier n\'est pas compressé. + Échec de la décompression. + Les applications déjà installées ne peuvent pas être compressées ou décompressées. + diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index f737b738d..c354d0d64 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -19,6 +19,7 @@ Versi build, Kredit, dan lainnya Ubah tampilan aplikasi Install CIA + Pilih driver GPU Apakah anda ingin untuk mengganti driver GPU mu saat ini? diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index d04f12b33..7c3f37af6 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -14,45 +14,44 @@ Cos\'è questo: Opzioni Cerca Applicazioni - Configura impostazioni emulatore + Configura le impostazioni dell\'emulatore Installa file CIA Installa applicazioni, aggiornamenti o DLC - Condividi Log + Condividi log Condividi il file di log di Azahar per il debug di problemi Gestione driver GPU Installa driver GPU - Installa driver alternativi per possibili miglioramenti nelle performance o nell\'accuratezza + Installa driver alternativi per possibili miglioramenti delle prestazioni o dell\'accuratezza Driver già installato Driver personalizzato non supportato Il caricamento di driver personalizzati non è disponibile per questo dispositivo. Controlla ancora questa opzione in futuro per controllare se il supporto è stato aggiunto! Nessun file di log trovato Seleziona cartella applicazioni - Permette as Azahar di popolare la lista di applicazioni - Info + Permette ad Azahar di popolare la lista di applicazioni + Informazioni Un emulatore 3DS open-source - Versione build, crediti e altro + Versione build, riconoscimenti e altro Cartella applicazioni selezionata Cambia i file che Azahar usa per caricare le applicazioni Modifica l\'aspetto dell\'app Installa CIA - Scopri di più.]]> Seleziona il driver GPU - Vuoi rimpiazzare il tuo driver GPU attuale? + Vuoi sostituire l\'attuale driver GPU? Installa Predefinito - Installati%s - Driver GPU standard in uso - Driver selezionato non valido, verrà usato il driver standard di sistema! + Installati %s + Driver GPU predefinito in uso + Driver selezionato non valido, verrà usato il driver predefinito del sistema! Driver GPU di sistema Installazione driver... Copiato negli appunti - Contribuenti - Contribuenti che hanno fatto sì che Azahar fosse possibile + Contributori + I contributori che hanno reso Azahar possibile Progetti usati da Azahar per Android Build Licenze @@ -62,20 +61,24 @@ Controlla ancora questa opzione in futuro per controllare se il supporto è stat Inizia Completato! Applicazioni - Seleziona la tua cartella <b>Applicazioni</b> usando il bottone sotto + Seleziona la tua cartella <b>Applicazioni</b> usando il pulsante qui sotto. Fatto Adesso sei pronto. Divertiti usando l\'emulatore! Continua Notifiche - Concedi il permesso di notifica usando il bottone sottostante + Concedi il permesso di notifica usando il pulsante qui sotto. Concedi il permesso Vuoi saltare la concessione del permesso di notifica? Azahar non avrà il permesso di notificarti con informazioni importanti. + Permessi mancanti + Azahar richiede l\'autorizzazione per gestire i file su questo dispositivo per archiviare e gestire i propri dati.\n\nDare il permesso \"Filesystem\" prima di continuare. Fotocamera Concedi il permesso alla fotocamera qui sotto per emulare la fotocamera del 3DS Microfono Concedi il permesso all\'utilizzo del microfono per emulare il microfono del 3DS + Filesystem + Dare il permesso del file system qui sotto per consentire ad Azahar di archiviare file. Permesso negato Saltare la selezione della cartella applicazioni? Non verrà mostrato alcun software nella lista applicazioni se non viene selezionata alcuna cartella. @@ -85,9 +88,9 @@ Divertiti usando l\'emulatore! Concedere autorizzazioni opzionali per utilizzare specifiche funzionalità dell\'emulatore Aiuto Salta - Indietro + Annulla Seleziona cartella utente - utente usando il bottone sottostante.]]> + utente usando il pulsante qui sotto.]]> Sembra che tu abbia impostato la cartella utente sia per Lime3DS che per Azahar. Questo probabilmente è dovuto al fatto che hai eseguito l\'aggiornamento ad Azahar e, al momento della richiesta, hai scelto una directory utente diversa da quella utilizzata per Lime3DS.\n\nQuesto potrebbe averti fatto pensare di aver perso salvataggi o altre impostazioni - ci scusiamo se è successo.\n\nDesideri tornare a utilizzare la tua cartella utente originale di Lime3DS, ripristinando impostazioni e salvataggi da Lime3DS, oppure preferisci mantenere la cartella utente attuale di Azahar?\n\nNessuna delle cartelle verrà eliminata, indipendentemente dalla tua scelta, e potrai passare liberamente da una all\'altra utilizzando l\'opzione \"Seleziona Cartella Utente\". Mantieni la cartella di Azahar attuale Usa la cartella precedente di Lime3DS @@ -95,6 +98,9 @@ Divertiti usando l\'emulatore! Non puoi saltare la configurazione della cartella utente Questo passaggio è richiesto per permettere che Azahar funzioni. Quando la cartella verrà selezionata potrai continuare. Hai perso i permessi di scrittura sulla tua cartella dei dati utente, dove sono memorizzati i salvataggi e altre informazioni. Questo può accadere dopo alcuni aggiornamenti app o Android. Ri-seleziona la cartella per recuperare le autorizzazioni in modo da poter continuare. + Selezione non valida + La selezione della directory utente non era valida.\nSeleziona nuovamente la directory utente, assicurandoti di accedervi dalla radice dello spazio di archiviazione del tuo dispositivo. + Azahar ha perso l\'autorizzazione a gestire i file su questo dispositivo. Ciò può accadere dopo alcuni aggiornamenti di app o Android. Si prega di concedere nuovamente questa autorizzazione nella schermata successiva per continuare a utilizzare l\'app. Impostazioni tema Configura le impostazioni del tema di Azahar. Imposta tema @@ -107,64 +113,66 @@ Divertiti usando l\'emulatore! Installati - Pad Scorrevole - Stick C + Pad scorrevole + Levetta C Scorciatoie Grilletti Grilletto - Pad Direzionale - Pad Direzionale (Asse) - Alcuni controller potrebbero non essere in grado di mappare il pad direzionale come un asse. Se questo è il caso, usa la sezione Pad Direzionale (Bottoni). - Pad Direzionale (Bottone) - Mappa il pad direzionale in questa sezione solo se stai avendo problemi con la sezione Pad Direzionale (Asse) - Asse Verticale - Asse Orizzontale + Tasti direzionali + Tasti direzionali (asse) + Alcuni controller potrebbero non essere in grado di mappare i tasti direzionali come un asse. Se questo è il caso, usa la sezione Tasti direzionali (pulsante). + Tasti direzionali (pulsante) + Mappa i tasti direzionali in questa sezione solo se riscontri problemi con le mappature della sezione Tasti direzionali (asse). + Asse verticale + Asse orizzontale Su Giù Sinistra Destra - Associa%1$s%2$s + Associa %1$s %2$s Premi o sposta un comando Assegnazione Input Premi o muovi un comando per assegnarlo a %1$s. - Muovi il joystick in su o in giù. - Muovi il joystick a sinistra o a destra. Home - Inverti Schermi + Inverti schermi Turbo - Questo controllo dev\'essere assegnato ad uno stick analogico di un gamepad o ad un asse del Pad Direzionale! - Questo controllo dev\'essere assegnato a un pulsante del gamepad! - Turbo speed - \"Turbo speed\" abilitato - \"Turbo speed\" disabilitato + Questo comando dev\'essere assegnato alla levetta analogica di un gamepad o a un asse dei tasti direzionali! + Questo comando dev\'essere assegnato a un pulsante del gamepad! + Velocità Turbo + Velocità Turbo abilitata + Velocità Turbo disabilitata - File di Sistema + File di sistema Esegui operazioni sui file di sistema come installare file di sistema o avviare il Menu Home Connettiti a Artic Setup Tool Azahar Artic Setup Tool.
Note:
  • Questa operazione installerà dati unici della console su Azahar, non condividere le tue cartelle utente o NAND dopo aver completato il processo di configurazione!
  • Durante il processo di configurazione, Azahar si collegherà alla console che sta eseguendo lo strumento di configurazione. Puoi scollegare la console in seguito dalla scheda \"File di sistema\" nel menu delle opzioni dell\'emulatore.
  • Non andare online contemporaneamente con Azahar e la tua console 3DS dopo aver configurato i file di sistema, poiché ciò potrebbe causare problemi.
  • La configurazione del vecchio 3DS è necessaria affinché la configurazione del nuovo 3DS funzioni (si consiglia di configurare entrambi).
  • Entrambe le modalità di configurazione funzioneranno indipendentemente dal modello della console che esegue lo strumento di configurazione.
]]>
- Recupero dello stato attuale dei file di sistema, per favore attendi... + Recupero dello stato attuale dei file di sistema, attendere... + Scollega i dati univoci della console +
  • il tuo OTP, SecureInfo e LocalFriendCodeSeed verranno rimossi da Azahar.
  • La tua lista amici verrà reimpostata e verrai disconnesso dal tuo account NNID/PNID.
  • I file di sistema e i titoli eshop ottenuti tramite Azahar diventeranno inaccessibili finché la stessa console non verrà nuovamente collegata tramite lo strumento di configurazione (i dati di salvataggio non andranno persi).

Continuare?]]>
Setup Old 3DS Setup New 3DS Il setup è possibile. È necessario effettuare prima il setup di un Old 3DS. Setup già completato. Inserisci l\'indirizzo di Artic Setup Tool - Preparazione setup, per favore attendi... - Avvia il Menu HOME - Mostra le app del menu HOME nella lista applicazioni - Esegui il Setup di sistema quando il Menu HOME viene lanciato - Menu HOME + Preparazione del setup, attendi... + Avvia il menù HOME + Mostra le app del menù HOME nella lista applicazioni + Esegui la configurazione del sistema quando il menù HOME viene avviato + Menù HOME Pulsanti Pulsante - Impostazioni Emulazione - Nome Utente + Impostazioni emulazione + Nome utente Modalità New 3DS Usa Applet LLE (se installati) + Applica la patch region-free alle applicazioni installate + Corregge la regione delle applicazioni installate per renderle region-free, in modo che vengano sempre visualizzate nel menù Home. Abilitare i moduli LLE richiesti per le funzionalità online (se installati) Abilita i moduli LLE necessari per il multigiocatore online, l\'accesso all\'eShop, ecc. Orologio @@ -181,8 +189,8 @@ Divertiti usando l\'emulatore! Giorno Stato Monete di gioco - Contapassi Passi all\'ora - Numero di passi all\'ora rilevati dal contapassi. Range da 0 a 65.535. + Passi del contapassi all\'ora + Numero di passi all\'ora rilevati dal contapassi. Intervallo da 0 a 65.535. ID Console Rigenera ID Console Questo rimpiazzerà l\'ID virtuale della console 3DS con uno nuovo. L\'ID della console 3DS attuale non potrà essere recuperato. Questo potrebbe avere effetti inaspettati in alcue applicazioni. Questo processo potrebbe fallire se usi un salvataggio della configurazione obsoleto. Continuare? @@ -196,6 +204,9 @@ Divertiti usando l\'emulatore! Mancata corrispondenza della regione L\'impostazione del paese non è valida per la regione emulata selezionata. L\'impostazione del paese non è valida per la console attualmente collegata. + Archiviazione + Comprimi i contenuti CIA installati + Comprime il contenuto dei file CIA quando installati sulla scheda SD emulata. Riguarda solo i contenuti CIA installati mentre l\'impostazione è abilitata. Fotocamera Interna @@ -204,7 +215,7 @@ Divertiti usando l\'emulatore! Sorgente Fotocamera Imposta l\'immagine sorgente della fotocamera virtuale. Puoi utilizzare un file immagine, oppure la fotocamera del dispositivo quando supportato. Fotocamera - Se \"Immagine Sorgente\" è impostato su \"Fotocamera del Dispositivo\", da qui scegli quale fotocamera utilizzare. + Se l\'impostazione \"Origine immagine\" è impostata su \"Fotocamera dispositivo\", questa imposta la fotocamera fisica da utilizzare. Fronte Retro Esterna @@ -212,36 +223,39 @@ Divertiti usando l\'emulatore! Renderer - API grafiche + API grafica Abilita la generazione di shader SPIR-V - Crea le fragments shader usate per emulare PICA tramite SPIR-V, invece di GLSL - Disabilita SPIR-V Optimizer - Disabilita il passaggio di ottimizzazione SPIR-V, riducendo considerevolmente gli stutter e influendo appena sulle prestazioni. - Abilita la compilazione asincrona delle shader - Compila le shader in background per ridurre lo stuttering durante il gioco. Quando abilitato, potrebbero verificarsi dei glitch grafici. - Filtering Lineare + Crea il fragment shader usato per emulare PICA tramite SPIR-V, invece di GLSL + Disabilita ottimizzazione SPIR-V + Disabilita il passaggio di ottimizzazione SPIR-V, riducendo considerevolmente gli scatti con un impatto minimo sulle prestazioni. + Abilita la compilazione asincrona degli shader + Compila gli shader in background per ridurre gli scatti durante il gioco. Se l\'opzione è abilitata, potrebbero verificarsi dei glitch grafici temporanei. + Filtraggio lineare Abilita il filtraggio lineare, che fa sembrare più smussata la grafica dei giochi. - Filtro Texture + Filtro texture Migliora la grafica delle applicazioni applicando un filtro alle texture. I filtri supportati sono Anime4k Ultrafast, Bicubic, ScaleForce, xBRZ freescale e MMPX. Ritarda il thread di rendering del gioco Ritarda il thread di rendering del gioco quando invia dati alla GPU. Aiuta con i problemi di prestazioni nelle (poche) applicazioni con frame rate dinamici. Avanzato Campionamento texture Sovrascrive il filtro di campionamento utilizzato dai giochi. Questo può essere utile in alcuni casi con giochi che gestiscono male l\'upscaling. Se hai dubbi, imposta questa opzione su \"Gestito dal gioco\". - Moltiplicazione Accurata - Utilizza una moltiplicazione più accurata degli shader hardware, che potrebbe correggere alcuni bug grafici. Se abilitato, le prestazioni saranno ridotte. + Moltiplicazione accurata + Utilizza una moltiplicazione più accurata degli shader hardware, che potrebbe correggere alcuni bug grafici. Se l\'opzione è abilitata, le prestazioni saranno ridotte. Abilita l\'emulazione GPU asincrona Usa un thread separato per l\'emulazione asincrona della GPU. Quando è abilitato le prestazioni saranno migliori. - Limita Velocità - Quando abilitata, la velocità di emulazione sarà limitata a una percentuale specificata della velocità normale. Se disabilitato, la velocità di emulazione non sarà limitata e tasto di scelta rapida per \"Turbo speed\" non funzionerà. - Limita Velocità tramite Percentuale + Limita velocità + Quando l\'opzione è abilitata, la velocità di emulazione sarà limitata a una percentuale specificata della velocità normale. Se è disabilitata, la velocità di emulazione non verrà limitata e la scorciatoia della velocità Turbo non funzionerà. + Limite della velocità in percentuale Specifica a quale percentuale limitare la velocità d\'emulazione. Utilizzando l\'impostazione predefinita di 100% l\'emulazione sarà limitata alla velocità normale. Valori superiori o inferiori aumenteranno o diminuiranno il limite di velocità. - Limite \"Turbo speed\" - Limite di velocità dell\'emulazione usato quando il tasto di scelta rapida del turbo è attivo. + Nascondi le immagini 3DS da Android + Impedisci che le immagini della fotocamera 3DS, degli screenshot e delle texture personalizzate vengano indicizzate da Android e visualizzate nella galleria. Potrebbe essere necessario riavviare il dispositivo dopo aver modificato questa impostazione per avere effetto. + Limite della velocità Turbo + Limite di velocità dell\'emulazione usato quando la scorciatoia della velocità Turbo è attiva. Espandi all\'area di ritaglio Espande l\'area di visualizzazione per includere l\'area di ritaglio (o notch). - Risoluzione Interna + Risoluzione interna Specifica la risoluzione a cui renderizzare. Una risoluzione alta migliorerà la qualità visiva ma avrà un grande effetto sulle prestazioni e potrebbe causare glitch in alcune applicazioni. + Automatica (dimensione dello schermo) Nativa (400x240) 2x Nativa (800x480) 3x Nativa (1200x720) @@ -255,11 +269,19 @@ Divertiti usando l\'emulatore! Disabilitare questa impostazione riducerà significativamente le prestazioni dell\'emulazione! Per un\'esperienza migliore, è consigliato lasciare questa impostazione abilitata. Attenzione: Modificare queste impostazioni rallenterà l\'emulazione Stereoscopia - Modalità Stereoscopia 3D + Modalità 3D stereoscopico + Scegli la modalità 3D stereoscopica per il rendering 3D. Le modalità \"Affiancato\" sono le più comuni nell\'uso moderno. Le modalità \"Anaglifo\" e \"Interlacciato\" si applicheranno sempre a tutti i display collegati. Profondità - Specifica il valore del regolatore di profindità 3D. Questo valore deve essere impostato su un valore superiore allo 0% quando è abilitato il \"3D stereoscopico\".\nNote: Valori di profondità superiori al 100% non sono possibili su hardware reale e possono causare problemi grafici + Specifica il valore del regolatore di profondità 3D. Questo valore deve essere impostato su un valore superiore allo 0% quando è abilitato il 3D stereoscopico.\nNota: Valori di profondità superiori al 100% non sono possibili su un dispositivo reale e possono causare problemi grafici Disabilita il rendering dell\'occhio destro Migliora notevolmente le prestazioni in alcune applicazioni, ma può causare flickering in altre. + Inverti occhi + Cambia quale occhio viene visualizzato in quale lato. In combinazione con la modalità \"Affiancato\" è possibile vedere il 3D incrociando gli occhi! + Rendering 3D stereoscopico + Indica se abilitare il 3D stereoscopico e su quali schermi. Le opzioni di visualizzazione singola sono rilevanti solo quando sono collegati più display. + Attivo (tutti gli schermi) + Attivo (solo schermo primario) + Attivo (solo schermo secondario) Cardboard VR Grandezza Cardboard Scala lo schermo ad una percentuale fissata della sua grandezza originale @@ -268,47 +290,47 @@ Divertiti usando l\'emulatore! Spostamento Verticale Specifica la percentuale di spazio vuoto per spostare gli schermi verticalmente. Valori positivi muoveranno alla parte bassa dello schermo, mentre i negativi faranno il contrario. Shader JIT - Shader Cache su Disco - Riduce lo stuttering salvando e caricando le shader generate sul disco principale. Non può essere usato senza aver prima attivato \"Abilita Shader Hardware\" + Cache degli shader su disco + Riduce gli scatti salvando e caricando gli shader generati su disco. Non può essere usata senza aver prima attivato \"Abilita shader hardware\". Utilità - Estrai Textures - Le textures vengono estratte in dump/textures/[ID Gioco]/. - Textures Personalizzate + Estrai texture + Le texture vengono estratte in dump/textures/[ID Gioco]/. + Texture personalizzate Le texture vengono caricate da load/textures/[ID Gioco]/. - Precaricamento delle Textures Personalizzate + Precarica texture personalizzate Carica tutte le texture personalizzate nella RAM del dispositivo. Questa funzionalità può usare molta memoria. - Caricamento asincrono delle Textures + Caricamento asincrono delle texture personalizzate Carica le texture personalizzate in modo asincrono con i thread in background per ridurre lo stutter del caricamento. Volume - Allungamento Audio - Allunga l\'audio per ridurre lo stuttering. Se abilitato, aumenta la latenza dell\'audio e riduce lievemente le prestazioni. + Allungamento dell\'audio + Allunga l\'audio per ridurre gli scatti. Quando è abilitato, aumenta la latenza dell\'audio e riduce lievemente le prestazioni. Abilita audio in tempo reale - Scala la velocità della riproduzione audio per compensare cali nel framerate dell\'emulazione. Questo significa che l\'audio verrà riprodotto a velocità normale anche mentre il framerate del gioco è basso. Può causare problemi di desincronizzazione audio - Dispositivo di input Audio - Modalità di output audio + Regola la velocità della riproduzione dell\'audio per compensare i cali nel framerate dell\'emulazione. Questo significa che l\'audio verrà riprodotto a velocità normale anche mentre il framerate del gioco è basso. Può causare problemi di desincronizzazione dell\'audio. + Dispositivo di input dell\'audio + Modalità di output del suono CPU JIT Utilizza il compilatore Just-in-Time (JIT) per l\'emulazione della CPU. Se abilitato, le prestazioni di gioco miglioreranno significativamente. - Abilita le Shader Hardware + Abilita shader hardware Utilizza l\'hardware per emulare gli shader del 3DS. Se abilitato, le prestazioni dei giochi miglioreranno significativamente. - Velocità Clock CPU + Velocità di clock della CPU Abilita V-Sync - Sincronizza il frame rate dei giochi con il refresh rate del tuo dispositivo. - Renderer di Debug + Sincronizza il frame rate del gioco con la frequenza di aggiornamento del tuo dispositivo. Può causare ulteriore latenza di input ma può ridurre il tearing in alcuni casi. + Renderer di debug Registra ulteriori informazioni di debug relative alla grafica. Quando abilitata, le prestazioni del gioco saranno significativamente ridotte. Svuota l\'output del log ad ogni messaggio Invia immediatamente il log di debug al file. Usalo se Azahar si blocca e l\'output del log viene tagliato. Ritarda l\'avvio con moduli LLE Ritarda l\'avvio dell\'app quando i moduli LLE sono abilitati. - Operazioni Deterministiche desincronizzate + Operazioni asincrone deterministiche Rende le operazioni asincrone deterministiche per il debug. Abilitare questa opzione potrebbe causare blocchi. Abilita server RPC Abilita il server RPC sulla porta 45987. Questo permette di leggere e scrivere remotamente la memoria guest. Abilita shader JIT - Usa il motore JIT invece dell\'interprete per l\'emulazione di shader software. + Usa il motore JIT al posto dell\'interprete per l\'emulazione software degli shader. Orientamento schermo @@ -345,20 +367,18 @@ Divertiti usando l\'emulatore! Installa Cancella Reimpostare tutte le impostazioni? - Tutte le impostazioni avanzate verranno reimpostate alla loro configurazione standard. Questa operazione non può essere annullata. + Tutte le impostazioni avanzate verranno reimpostate alla loro configurazione predefinita. Questa operazione non può essere annullata. Reimpostazione impostazioni Seleziona data RTC Seleziona orario RTC - Vuoi reimpostare questa impostazione al suo valore standard? + Vuoi reimpostare questa opzione al suo valore predefinito? Non puoi modificare questo ora Impostazione disabilitata Questa impostazione è attualmente disattivata a causa di un\'altra impostazione che non è il valore appropriato. Questa opzione non può essere modificata mentre un gioco è in esecuzione. - Auto-seleziona. + Seleziona automaticamente Avvia - Cancellazione... - Importante - Non mostrare più + Annullamento in corso... Visibilità Informazione @@ -382,71 +402,90 @@ Divertiti usando l\'emulatore! Layout - La tua ROM è Criptata + La tua ROM è criptata Formato ROM non valido Il file ROM non esiste Nessun gioco avviabile è presente! Premi Indietro per accedere al menù - Salva Stato - Carica Stato + Salva stato + Carica stato Slot %1$d Slot %1$d-%2$tF%2$tR Mostra FPS Feedback aptico Impostazioni Overlay - Configura Controlli - Modifica Disposizione + Configura comandi + Modifica layout Fatto + Pulsante scorrevole + Tieni premuto il pulsante originariamente premuto + Tieni premuto il pulsante attualmente premuto + Tieni premuto il pulsante originale e quello attualmente premuto Attiva Controlli Regola la Dimensione Scala Globale Reimposta tutto Modifica Opacità Centro dello Stick Relativo - Trascinamento del D-Pad + Trascinamento dei tasti direzionali Apri Impostazioni Apri Trucchi - Layout Schermi Orizzontale - Layout Schermi Verticale - Schermo Grande + Proporzione + Layout degli schermi in orizzontale + Layout degli schermi in verticale + Layout degli schermi sullo schermo secondario + Il layout utilizzato da uno schermo secondario connesso, cablato o wireless (Chromecast, Miracast) + Schermo grande Verticale Schermo singolo - Schermi Affiancati - Schermi Ibridi + Schermi affiancati + Schermi ibridi Originale Standard + Predefinito del sistema (specchio) Layout personalizzato - Posizione schermo piccolo - Dove dovrebbe apparire lo schermo inferiore rispetto a quello superiore nella modalità Schermo Grande? - Alto-Destra - Centro-Destra - Basso-Destra (Standard) - Alto-Sinistra - Centro-Sinistra - Basso-Sinistra + Colore dello sfondo + Il colore che appare dietro gli schermi durante l\'emulazione, rappresentato come valore RGB. + Rosso + Verde + Blu + Opacità del secondo schermo nel layout personalizzato + L\'opacità del secondo schermo del 3DS quando si utilizza un layout dello schermo personalizzato. Utile se il secondo schermo deve essere posizionato sopra il primo. + Posizione dello schermo piccolo + Dove dovrebbe apparire lo schermo inferiore rispetto a quello superiore nella modalità Schermo grande? + In alto a destra + In centro a destra + In basso a destra (predefinito) + In alto a sinistra + In centro a sinistra + In basso a sinistra Sopra Sotto - Proporzioni Schermo Superiore - Quante volte più grande deve essere lo schermo superiore rispetto a quello inferiore nella modalità Schermo Grande? - Modifica Layout personalizzato nelle impostazioni - Layout personalizzato Orizzontale - Layout personalizzato Verticale + Spazio tra gli schermi + Spazio tra gli schermi in tutte le modalità a due schermi. Misurato in px rispetto all\'altezza di 240px dello schermo più grande. + Proporzioni dello schermo superiore + Quante volte più grande deve essere lo schermo superiore rispetto a quello inferiore nella modalità Schermo grande? + Modifica il layout personalizzato nelle impostazioni + Layout personalizzato orizzontale + Layout personalizzato verticale Schermo superiore Schermo inferiore - Posizione-X - Posizione-Y + Posizione X + Posizione Y Larghezza Altezza Rotazione Layout - Inverti Schermi + Inverti schermi + Ruota lo schermo in verticale Ripristina Disposizione - Chiudi il Gioco - Abilita/disabilita Pausa - Miscellanea + Mostra Overlay Controller + Chiudi il gioco + Metti in pausa/Riprendi + Varie Usa Artic Controller quando connesso a Artic Base Server - Usa i controlli forniti da Artic Base Server quando connesso ad esso al posto del dispositivo di input configurato. + Usa i comandi forniti da Artic Base Server quando si è connessi, al posto del dispositivo di input configurato. Sei sicuro di voler chiudere il gioco corrente? Amiibo Carica @@ -454,10 +493,10 @@ Divertiti usando l\'emulatore! Seleziona il file contenente il tuo Amiibo. Impossibile caricare l\'Amiibo Durante il caricamento del file Amiibo specificato, si è verificato un errore. Controlla che il file sia corretto. - Metti in pausa emulazione + Metti in pausa l\'emulazione Riprendi emulazione - Blocca cassetto - Sblocca cassetto + Blocca menù laterale + Sblocca menù laterale L\'emulatore ha bisogno dei permessi per l\'archiviazione dei dati su memoria esterna per funzionare correttamente Caricando le Impostazioni... @@ -473,8 +512,8 @@ Divertiti usando l\'emulatore! Spostamento Dati... Copia file: %s Copia completata - Save State - ATTENZIONE: I save state NON sono un SOSTITUTO per i salvataggi IN-GAME.\n\nUsa i save state a tuo RISCHIO e PERICOLO. + Stati salvati + Attenzione: Gli stati salvati NON sostituiscono i salvataggi in-game, e non sono pensati per essere affidabili.\n\nUsali a tuo rischio e pericolo. Tastiera Software @@ -496,32 +535,35 @@ Divertiti usando l\'emulatore! Microfono - Azahar ha bisogno di accedere al tuo microfono per emulare il microfono del 3DS.\n\nAlternativamente, puoi anche modificare \"Dispositivo di Input Audio\" nelle impostazioni Audio. + Azahar ha bisogno di accedere al tuo microfono per emulare il microfono del 3DS.\n\nIn alternativa, puoi modificare l\'opzione \"Dispositivo di input dell\'audio\" nelle impostazioni Audio. Annulla Continua Archivio di Sistema Non Trovato - %s è mancante. Fai il dump del tuo archivio di sistema.\nProseguire con l\'emulazione potrebbe causare crash e bugs + %s è mancante. Fai il dump del tuo archivio di sistema.\nProseguire con l\'emulazione potrebbe causare crash e bug. Installazione Fallita. File CIA non trovato Archivio di Sistema - Errore nel Salvataggio/Caricamento + Errore nel salvataggio/caricamento Errore Fatale Si è verificato un errore fatale. Controllare il log per i dettagli.\nContinuare l\'emulazione può causare crash e bug. - Regione non valida Applicazione criptata non supportata + Modalità di sistema non valida + Le applicazioni esclusive del New 3DS non possono essere caricate senza abilitare la modalità New 3DS. - Preparando le Shaders - Costruisco le Shaders - + Preparazione degli shader Riproduci Disinstalla applicazione Disinstallazione... + Apri cartella dei salvataggi + Apri cartella applicazione + Apri cartella delle mod Apri cartella delle texture Apri catella DLC Apri cartella degli aggiornamenti + Apri cartella extra Disinstalla DLC Disinstalla aggiornamenti Scorciatoia @@ -529,30 +571,44 @@ Divertiti usando l\'emulatore! Modifica icona Crea scorciatoia Il nome della scorciatoia non può essere vuoto + Estendi per adattare l\'immagine + ID: + File: + Tipo: + Inserisci schedina + Rimuovi schedina + Mostra overlay prestazioni + Overlay delle prestazioni Abilita overlay prestazioni Configura se l\'overlay delle prestazioni viene visualizzato e quali informazioni vengono visualizzate. - Mostra FPS - Mostra i fotogrammi al secondo attuali. - Mostra il frametime - Mostra il frametime attuale. - Mostra velocità - Mostra la percentuale di emulazione attuale. - Mostra utilizzo della memoria dell\'app - Mostra la quantità di RAM usata dall\'emulatore. - Mostra memoria disponibile - Mostra la quantità di RAM disponibile. - Mostra temperatura batteria - Mostra la temperatura attuale, in Celsius e Fahrenheit, della batteria. - Posizione overlay - Scegli dove visualizzare l\'overlay delle prestazioni sullo schermo. - Sfondo dell\'overlay - Aggiunge uno sfondo dietro all\'overlay per una lettura più facile. + Mostra FPS + Visualizza i fotogrammi al secondo attuali. + Mostra frametime + Mostra frametime attuale. + Mostra velocità + Visualizza la percentuale di velocità dell\'emulazione corrente. + Mostra l\'utilizzo della memoria dell\'app + Visualizza la quantità di RAM utilizzata dall\'emulatore. + Mostra memoria disponibile + Visualizza la quantità di RAM disponibile. + Mostra temperatura della batteria + Visualizza la temperatura attuale della batteria in gradi Celsius e Fahrenheit. + Posizione del overlay + Scegli dove visualizzare l\' overlay delle prestazioni sullo schermo. + In alto a sinistra + In alto a destra + In basso a sinistra + In basso a destra + In alto al centro + In basso al centro + Sfondo dell\'overlay + Aggiunge uno sfondo dietro al overlay per una lettura più semplice. Trucchi - Aggiungi Trucco + Aggiungi trucco Nome Note Codice @@ -567,7 +623,7 @@ Divertiti usando l\'emulatore! Installando %d file. Guarda le notifiche per maggiori dettagli. Installando %dfiles. Guarda le notifiche per maggiori dettagli. - Installando i file di %d. Guarda le notifiche per maggiori dettagli. + Installazione di %d file. Guarda le notifiche per maggiori dettagli. Notifiche di Azahar durante l\'installazione dei CIA Installando il CIA @@ -593,13 +649,13 @@ Divertiti usando l\'emulatore! Tema - Segui sistema - Chiara - Scura + Segui il sistema + Chiaro + Scuro - Material you - Utilizza il colore del tema del sistema operativo all\'interno dell\'app (sovrascrive l\'impostazione \"Colore tema\" quando abilitata) + Material You + Utilizza il colore del tema del sistema operativo all\'interno dell\'app (quando è abilitata, sovrascrive l\'impostazione \"Colore del tema\") Colore del tema @@ -625,12 +681,12 @@ Divertiti usando l\'emulatore! Tedesco (Deutsch) Italiano Spagnolo (Español) - Cinese Semplificato (简体中文) + Cinese semplificato (简体中文) Coreano (한국어) Olandese (Nederlands) Portoghese (Português) Russo (Русский) - Cinese Tradizionale (正體中文) + Cinese tradizionale (正體中文) Vuoto @@ -647,16 +703,16 @@ Divertiti usando l\'emulatore! Invertito - Rumore Statico - Dispositivo Reale (cubeb) - Dispositivo Reale (OpenAL) + Rumore statico + Dispositivo reale (cubeb) + Dispositivo reale (OpenAL) - Affiancati - Affiancato Invertito + Affiancato + Affiancato a larghezza intera Anaglifo Interlacciato - Interlacciato Invertito + Interlacciato invertito OpenGLES @@ -672,6 +728,8 @@ Divertiti usando l\'emulatore! Controllata dal gioco Nearest Neighbor + Lineare + Mono Stereo @@ -728,7 +786,7 @@ Divertiti usando l\'emulatore! Australia Austria Belgio - Bosnia Herzegovina + Bosnia ed Erzegovina Botswana Bulgaria Croazia @@ -758,7 +816,7 @@ Divertiti usando l\'emulatore! Nuova Zelanda Norvegia Polonia - Portogall + Portogallo Romania Russia Serbia @@ -780,7 +838,7 @@ Divertiti usando l\'emulatore! Chad Sudan Eritrea - Djibouti + Gibuti Somalia Andorra Gibilterra @@ -827,17 +885,32 @@ Divertiti usando l\'emulatore! Dicembre - Comunicazione con il server Artic Base fallita. L\'emulazione verrà interrotta + Comunicazione con il server Artic Base fallita. L\'emulazione verrà interrotta. Artic Base Connettiti a una console reale che sta eseguendo il server Artic Base Connetti ad Artic Base Inserisci l\'indirizzo del server Artic Base - Salvataggio Rapido - Salvataggio Rapido - Caricamento Rapido - Salvataggio Rapido - %1$tF %1$tR - Nessun salvataggio rapido disponibile + Salvataggio rapido + Salvataggio rapido + Carica salvataggio rapido + Salvataggio rapido - %1$tF %1$tR + Nessun salvataggio rapido disponibile. + + + Comprimi + Compressione... + Decomprimi + Decompressione... + Compressione completata con successo. + Compressione non supportata per questo file. + Il file è già compresso. + Compressione fallita. + Decompressione completata con successo. + Decompressione non supportata per questo file. + Il file non è compresso. + Decompressione fallita. + Le applicazioni già installate non possono essere compresse o decompresse. diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index 217319f54..b29e7f503 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -8,12 +8,8 @@ C-Spak Utløser Kontrollpluss - Opp/Ned Akse - Venstre/Høyre Akse Inngangsinnbinding Trykk eller flytt en inngang for å binde den til %1$s. - Beveg Joystick opp eller ned - Beveg Joystick venstre eller høyre Denne kontrollen må være bundet til en håndkontroller\'s analog spak eller kontrollpluss akse! Denne kontrollen må være bundet til en håndkontroller knapp! @@ -40,7 +36,6 @@ Tekstur Filter Aktiver nøyaktig shader-multiplikasjon Bruker mer nøyaktig multiplikasjon i maskinvare shaders, som kan fikse noen grafiske feil. Når dette er aktivert, reduseres ytelsen. - Aktiver asynkron GPU-emulering Bruker en egen tråd for å emulere GPU asynkront. Når dette er aktivert, forbedres ytelsen. Aktiver fartsbegrensning Begrens fartsprosent @@ -56,7 +51,6 @@ Aktiver maskinvare shader Bruker maskinvare for å etterligne 3DS shaders. Når dette er aktivert, vil spillytelsen bli betydelig forbedret. Aktiver V-Sync - Synkroniserer spillrammefrekvensen med oppdateringsfrekvensen på enheten din. Tøm Standard diff --git a/src/android/app/src/main/res/values-nl/strings.xml b/src/android/app/src/main/res/values-nl/strings.xml index 40afb28a0..4643dacee 100644 --- a/src/android/app/src/main/res/values-nl/strings.xml +++ b/src/android/app/src/main/res/values-nl/strings.xml @@ -24,6 +24,7 @@ Vink deze optie in de toekomst nogmaals aan om te zien of er ondersteuning is to Bouwversie, credits en meer Wijzig het uiterlijk van de app Installeer CIA + Selecteer GPU-stuurprogramma Wilt u uw huidige GPU-driver vervangen? @@ -83,8 +84,6 @@ Vink deze optie in de toekomst nogmaals aan om te zien of er ondersteuning is to Sommige controllers kunnen hun D-pad mogelijk niet als as in kaart brengen. Als dat het geval is, gebruik dan de D-Pad (knoppen) sectie. D-Pad (Knop) Wijs het D-pad hier alleen aan toe als je problemen ondervindt met de toewijzing van de D-Pad (as)-knoppen. - Op/neer-as - Links/rechts as Op Neer Links @@ -93,8 +92,6 @@ Vink deze optie in de toekomst nogmaals aan om te zien of er ondersteuning is to Druk op of verplaats een invoer. Invoerbinding Druk op of verplaats een invoer waaraan u deze wilt koppelen %1$s - Beweeg je joystick naar boven of beneden. - Beweeg je joystick naar links of rechts. HOME Verwissel Schermen Deze besturing moet worden gekoppeld aan een analoge gamepad-stick of D-pad-as! diff --git a/src/android/app/src/main/res/values-sv/strings.xml b/src/android/app/src/main/res/values-sv/strings.xml index d9ebcffe1..09828b12e 100644 --- a/src/android/app/src/main/res/values-sv/strings.xml +++ b/src/android/app/src/main/res/values-sv/strings.xml @@ -32,6 +32,7 @@ Ändrar de filer som Azahar använder för att ladda applikationer Modifiera utseendet på appen Installera CIA + Välj GPU-drivrutin Vill du ersätta din nuvarande GPU-drivrutin? @@ -65,20 +66,36 @@ Ge tillstånd Hoppa över att ge tillstånd för avisering? Azahar kommer inte att kunna meddela dig viktig information. + Saknar behörigheter + Azahar behöver behörighet för att hantera filer på den här enheten för att kunna lagra och hantera sina data. \n\nGe behörighet för ”Filsystem” innan du fortsätter. Kamera Ge kameratillståndet nedan för att emulera 3DS-kameran. Mikrofon Ge mikrofonbehörighet nedan för att emulera 3DS-mikrofonen. + Filsystem + Bevilja filsystemsbehörighet nedan för att tillåta Azahar att lagra filer. Tillstånd nekat Hoppa över att välja applikationsmapp? Programvara visas inte i listan Program om en mapp inte är markerad. + Behörigheter + Datamappar + (Användarmapp krävs)]]> + Bevilja valfria behörigheter för att använda specifika funktioner i emulatorn Hjälp Hoppa över Avbryt Välj användarmapp användardatakatalog med knappen nedan.]]> + Du verkar ha användarkataloger inställda för både Lime3DS och Azahar. Detta beror troligen på att du uppgraderade till Azahar och när du blev ombedd att välja en annan användarkatalog än den som användes för Lime3DS. \n\nDetta kan ha lett till att du trodde att du förlorat sparade spel eller andra inställningar – vi ber om ursäkt om så är fallet. Vill du gå tillbaka till att använda din ursprungliga Lime3DS-användarkatalog och återställa inställningar och spara spel från Lime3DS, eller behålla din nuvarande Azahar-användarkatalog? Ingen av katalogerna kommer att raderas, oavsett vilket val du gör, och du kan fritt växla mellan dem med hjälp av alternativet Välj användarkatalog. + Behåll aktuell Azahar-katalog + Använd tidigare Lime3DS-katalog Välj + Du kan inte hoppa över konfiguration av användarmappen Detta steg krävs för att Azahar ska fungera. Välj en katalog och sedan kan du fortsätta. + Du har förlorat skrivbehörighet till katalogen user data, där sparade filer och annan information lagras. Detta kan inträffa efter vissa app- eller Android-uppdateringar. Välj katalogen på nytt för att återfå behörigheten så att du kan fortsätta. + Ogiltigt val + Valet av användarkatalog var ogiltigt. Välj användarkatalogen igen och se till att du navigerar till den från roten av enhetens lagring. + Azahar har förlorat behörigheten att hantera filer på den här enheten. Detta kan inträffa efter vissa app- eller Android-uppdateringar. Bevilja denna behörighet på nästa skärm för att fortsätta använda appen. Temainställningar Konfigurera dina temapreferenser för Azahar. Ställ in tema @@ -101,8 +118,8 @@ Vissa styrenheter kanske inte kan mappa sina riktningsknappar som en axel. Om så är fallet, använd avsnittet Riktningsknappar (knappar). Riktningsknappar (knapp) Mappa endast D-pad till dessa om du har problem med knappmappningarna för D-pad (axel). - Axel upp/ner - Vänster/höger-axel + Vertikal axel + Horisontell axel Upp Ner Vänster @@ -111,17 +128,25 @@ Tryck på eller flytta en inmatning. Inmatningsbindning Tryck eller flytta en inmatning för att binda den till %1$s. - Flytta joysticken uppåt eller nedåt. - Flytta joysticken åt vänster eller höger. + Tryck UPP på din styrspak. + Tryck HÖGER på din styrspak. HOME Byt skärm + Turbo Den här kontrollen måste vara bunden till en gamepad-analog spak eller D-pad-axel! Den här kontrollen måste vara bunden till en gamepad-knapp! + Turbohastighet + Turbohastighet aktiverad + Turbohastighet inaktiverad + Systemfiler Utför systemfilsoperationer som att installera systemfiler eller starta upp startmenyn Anslut till Artic Setup Tool + Azahar Artic Setup Tool.
Anmärkningar:
  • Denna åtgärd installerar konsolens unika data på Azahar. Dela inte dina användar- eller nand-mappar efter att du har genomfört konfigurationsprocessen!
  • Under konfigurationsprocessen kommer Azahar att länka till konsolen som kör konfigurationsverktyget. Du kan koppla bort konsolen senare från fliken Systemfiler i emulatorns alternativmeny.
  • Gå inte online med både Azahar och din 3DS-konsol samtidigt efter att du har konfigurerat systemfilerna, eftersom detta kan orsaka problem.
  • Gammal 3DS-konfiguration krävs för att den nya 3DS-konfigurationen ska fungera (det rekommenderas att konfigurera båda).
  • Båda installationslägena fungerar oavsett vilken modell av konsol som kör installationsverktyget.
]]>
Hämtar aktuell status för systemfiler, vänta... + Avlänka konsolens unika data +
  • Din OTP, SecureInfo och LocalFriendCodeSeed kommer att tas bort från Azahar.
  • Din vänlista kommer att återställas och du kommer att loggas ut från ditt NNID/PNID-konto.
  • Systemfiler och e-butikstitlar som erhållits via Azahar kommer att bli otillgängliga tills samma konsol kopplas ihop igen med hjälp av installationsverktyget (spardata kommer inte att gå förlorade).

Fortsätt?]]>
Gammal 3DS-konfiguration Ny 3DS-konfiguration Konfiguration är möjlig. @@ -143,6 +168,8 @@ Användarnamn Nytt 3DS-läge Använd LLE Applets (om installerat) + Tillämpa regionsfri patch till installerade applikationer + Patchar regionen för installerade applikationer till att vara regionsfria så att de alltid visas på hemmenyn. Aktivera nödvändiga LLE-moduler för onlinefunktioner (om de är installerade) Aktiverar de LLE-moduler som krävs för multiplayer online, eShop-åtkomst etc. Klocka @@ -150,6 +177,7 @@ Ställ in den emulerade 3DS-klockan så att den antingen återspeglar den på din enhet eller startar vid ett simulerat datum och klockslag. Enhetsklocka Simulerad klocka + Om klockan är inställd på ”Simulerad klocka” ändras det fasta datumet och klockslaget för start. Profilinställningar Region Språk @@ -170,6 +198,13 @@ Inlästa 3GX-insticksmoduler från det emulerade SD-kortet om de finns tillgängliga. Tillåt applikationer att ändra insticksinläsarens tillstånd Tillåter homebrew-appar att aktivera insticksinläsaren även när den är inaktiverad. + Varning för regionskonflikt + Landsinställningen är inte giltig för den valda emulerade regionen. + Landsinställningen är inte giltig för den aktuella länkade konsolen. + Lagring + Komprimera installerat CIA-innehåll + Komprimerar innehållet i CIA-filer när det installeras på det emulerade SD-kortet. Påverkar endast CIA-innehåll som installeras medan inställningen är aktiverad. + Innerkamera Yttre vänstra kameran @@ -188,23 +223,36 @@ Grafik-API Aktivera generering av SPIR-V shader Skickar ut den fragment shader som används för att emulera PICA med SPIR-V istället för GLSL + Inaktivera SPIR-V Optimizer + Inaktiverar SPIR-V-optimeringspasset, vilket minskar hackandet avsevärt utan att påverka prestandan nämnvärt. Aktivera asynkron shader-kompilering Sammanställer shaders i bakgrunden för att minska stuttering under spelet. När det är aktiverat kan du förvänta dig tillfälliga grafiska glitches Lineär filtrering Aktiverar linjär filtrering, vilket gör att spelets grafik ser jämnare ut. Texturfilter Förbättrar det visuella i applikationer genom att tillämpa ett filter på texturer. De filter som stöds är Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale och MMPX. - Fördröj spelets renderingstråd + Fördröj spelrenderingstråd Fördröj spelets renderingstråd när den skickar data till GPU:n. Hjälper till med prestandaproblem i de (mycket få) applikationer med dynamiska bildfrekvenser. + Avancerat + Textursampling + Åsidosätter det samplingsfilter som används av spel. Detta kan vara användbart i vissa fall med spel som fungerar dåligt vid uppskalning. Om du är osäker, ställ in detta på Spelkontrollerat. Accurate Multiplication Använder mer exakt multiplikation i hårdvaru-shaders, vilket kan åtgärda vissa grafiska buggar. När detta är aktiverat kommer prestandan att minska. Aktivera asynkron GPU-emulering Använder en separat tråd för att emulera GPU:n asynkront. När detta är aktiverat kommer prestandan att förbättras. Begränsa hastighet + När funktionen är aktiverad begränsas emuleringshastigheten till en angiven procentandel av normal hastighet. Om funktionen är inaktiverad är emuleringshastigheten obegränsad och snabbtangenten för turbohastighet fungerar inte. Gränsa hastigheten i procent Anger procentsatsen för att begränsa emuleringshastigheten. Med standardvärdet 100% kommer emuleringen att begränsas till normal hastighet. Värden som är högre eller lägre ökar eller minskar hastighetsgränsen. + Dölj 3DS-bilder från Android + Förhindra att 3DS-kamera, skärmdumpar och anpassade texturbilder indexeras av Android och visas i galleriet. Enheten kan behöva startas om efter att denna inställning har ändrats för att den ska träda i kraft. + Begränsning för turbohastighet + Begränsning för emuleringshastighet som används när turbo-snabbtangenten är aktiv. + Expandera till hela skärmen + Expanderar visningsområdet till att inkludera sorgkanten (eller notch). Intern upplösning Anger den upplösning som används för rendering. En hög upplösning förbättrar den visuella kvaliteten avsevärt men är också ganska prestandakrävande och kan orsaka problem i vissa applikationer. + Automatiskt (Skärmstorlek) Inbyggd (400x240) 2x inbyggd (800x480) 3x inbyggd (1200x720) @@ -219,9 +267,18 @@ Varning: Om du ändrar dessa inställningar kommer emuleringen att bli långsammare Stereoskop Stereoskopiskt 3D-läge + Välj stereoskopiskt 3D-läge för 3D-rendering. Sida-vid-sida-lägen är vanligast i modern användning. Anaglyf- och interlaced-lägen gäller alltid för alla anslutna skärmar. Djup + Anger värdet för 3D-reglaget. Detta bör ställas in på högre än 0% när stereoskopisk 3D är aktiverat.\nObservera: Djupvärden över 100% är inte möjliga på verklig hårdvara och kan orsaka grafiska problem. Inaktivera rendering av höger öga Förbättrar prestandan avsevärt i vissa applikationer, men kan orsaka flimmer i andra. + Byt ögon + Byter vilket öga som visas på vilken sida. I kombination med Sida vid sida-läget kan du se 3D genom att korsa ögonen! + Rendera stereoskopisk 3D + Huruvida stereoskopisk 3D ska aktiveras och på vilka skärmar. Alternativen för en enda skärm är endast relevanta när flera skärmar är anslutna. + På (Alla skärmar) + På (Endast primär skärm) + På (Endast sekundär skärm) Cardboard VR Storlek på kartongskärm Skalar skärmen till en procentandel av dess ursprungliga storlek. @@ -258,28 +315,41 @@ Använder hårdvara för att emulera 3DS-shaders. När detta är aktiverat kommer spelprestanda att förbättras avsevärt. CPU-klockhastighet Aktivera V-Sync - Synkroniserar spelets bildfrekvens till uppdateringsfrekvensen på din enhet. + Synkroniserar spelets bildfrekvens med uppdateringsfrekvensen på din enhet. Kan orsaka ytterligare fördröjning av inmatningen, men kan i vissa fall minska bildfördröjningen. Felsök renderingsprogrammet Loggar ytterligare grafikrelaterad felsökningsinformation. När den är aktiverad kommer spelets prestanda att minska avsevärt. - Töm loggen för varje meddelande + Spola loggutdata vid varje meddelande Överför omedelbart felsökningsloggen till fil. Använd detta om Azahar kraschar och loggutmatningen skärs av. - Försenad start med LLE-moduler + Fördröjd start med LLE-moduler Fördröjer starten av appen när LLE-moduler är aktiverade. Deterministiska asynkrona operationer Gör asynkrona operationer deterministiska för felsökning. Om du aktiverar detta kan det orsaka frysningar. - + Aktivera RPC-server + Aktiverar RPC-servern på port 45987. Detta möjliggör fjärrläsning/skrivning av gästminne. + Aktivera Shader JIT + Använd JIT-motorn istället för tolken för emulering av programvaru-shader. + + Skärmorientering Automatisk Liggande Omvänd liggande Stående Omvänd stående + Standard + 16:9 + 4:3 + 21:9 + 16:10 + Sträck ut + Töm Standard Sparade inställningar Sparade inställningar för %1$s Fel vid sparande av %1$s.ini: %2$s + Sparar... Läser in... Nästa Bakåt @@ -300,10 +370,15 @@ Välj RTC-tid Vill du återställa inställningen till standardvärdet? Du kan inte redigera detta nu + Inställning inaktiverad + Denna inställning är för närvarande inaktiverad på grund av att en annan inställning inte har rätt värde. Det här alternativet kan inte ändras medan ett spel pågår. Autovälj Starta Avbryter... + Synlighet + Information + Välj spelmapp @@ -341,6 +416,10 @@ Konfigurera kontroller Redigera layout Klar + Knappglidning + Håll den ursprungligen intryckta knappen intryckt + Håll den aktuella knappen intryckt + Håll ursprungliga och aktuell knapptryckning intryckt Växla kontroller Justera skala Global skala @@ -350,8 +429,11 @@ Glidning för riktningsknappar Öppna inställningar Öppna fusk + Bildförhållande Liggande skärmlayout Stående skärmlayout + Layout för sekundär skärm + Layouten som används av en ansluten sekundär skärm, trådbunden eller trådlös (Chromecast, Miracast) Stor skärm Stående Enkel skärm @@ -359,7 +441,15 @@ Hybridskärmar Original Standard + Systemstandard (spegel) Anpassad layout + Bakgrundsfärg + Den färg som visas bakom skärmarna under emulering, representerad som ett RGB-värde. + Röd + Grön + Blå + Anpassad layout för opacitet på andra skärmen + Opaciteten för den andra 3DS-skärmen när du använder en anpassad skärmlayout. Användbart om den andra skärmen ska placeras ovanpå den första skärmen. Position för liten skärm Var ska den lilla skärmen visas i förhållande till den stora i storskärmslayout? Uppe till höger @@ -370,6 +460,8 @@ Ner till vänster Ovanför Under + Skärmavstånd + Avstånd mellan skärmarna i alla tvåskärmslägen. Mätt i px i förhållande till den större skärmens höjd på 240 px. Storbildsproportion Hur många gånger större är den stora skärmen än den lilla skärmen i storskärmslayout? Justera anpassad layout i inställningarna @@ -383,7 +475,9 @@ Höjd Växla layouter Skärmbyte + Vrid skärmen upprätt Återställ överlägg + Visa kontrolleröverlägg Stäng spelet Växla paus Diverse @@ -450,13 +544,65 @@ Spara/läs in-fel Allvarligt fel Ett allvarligt fel inträffade. Kontrollera loggen för detaljer.\nFortsatt emulering kan leda till krascher och buggar. + Krypterad applikation som inte stöds + Ogiltigt systemläge + Nya 3DS-exklusiva applikationer kan inte läsas in utan att aktivera Ny 3DS-läget. + Förbereder shaders - Bygger shaders - Spela + Avinstallera applikation + Avinstallerar... + Öppna mapp för sparat data + Öppna applikationsmapp + Öppna mapp för moddar + Öppna texturmapp + Öppna DLC-mapp + Öppna mapp för uppdateringar + Öppna extramapp + Avinstallera DLC + Avinstallera uppdateringar Genväg + Genvägsnamn + Redigera ikon + Skapa genväg + Genvägsnamnet får inte vara tomt + Sträck ut för att passa bild + ID: + Fil: + Typ: + Mata in cartridge + Mata ut cartridge + + + Visa prestandaöverlägg + Prestandaöverlägg + Aktivera prestandaöverlägg + Konfigurera om prestandaöverlägget ska visas och vilken information som ska visas. + Visa bilder/s + Visa aktuella bilder per sekund. + Visa bildrutetider + Visa aktuella bildrutetider. + Visa hastighet + Visa aktuell emuleringshastighet i procent. + Visa användning av programminne + Visa mängden RAM-minne som används av emulatorn. + Visa tillgängligt minne + Visa mängden tillgängligt RAM-minne. + Visa batteritemperatur + Visa aktuell batteritemperatur i Celsius och Fahrenheit. + Överläggsposition + Välj var prestandaöverlägget ska visas på skärmen. + Överst till vänster + Överst till höger + Nederst till vänster + Nederst till höger + Mitten längst upp + Mitten längst ner + Bakgrund för överlägg + Lägger till en bakgrund bakom överlägget för att underlätta läsningen. + Fusk Lägg till fusk @@ -477,6 +623,7 @@ Azahar-meddelanden under CIA-installation Installation av CIA + Installerar %1$s (%2$d/%3$d) Har installerat CIA Installation av CIA misslyckades \"%s\" har installerats framgångsrikt @@ -558,7 +705,7 @@ Sida vid sida - Omvänd sida vid sida + Sida vid sida full bredd Anaglyf Interlaced Omvänd interlaced @@ -574,7 +721,11 @@ xBRZ MMPX + + Spelkontrollerat Närmaste granne + Linjär + Mono Stereo @@ -743,4 +894,19 @@ Snabbspara - %1$tF %1$tR Ingen snabbsparning tillgänglig + + Komprimera + Komprimerar... + Avkomprimera + Avkomprimerar... + Komprimeringen färdigställd. + Komprimering stöds inte för denna fil. + Filen är redan komprimerad. + Komprimering misslyckades. + Avkomprimeringen färdigställd. + Avkomprimering stöds inte för denna fil. + Filen är inte komprimerad. + Avkomprimering misslyckades. + Redan installerade applikationer kan inte komprimeras eller avkomprimeras. + diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 92e549620..d581e4f65 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -35,12 +35,26 @@ @string/emulation_screen_layout_custom + + @string/emulation_secondary_display_default + @string/emulation_top_screen + @string/emulation_bottom_screen + @string/emulation_screen_layout_sidebyside + + 0 2 1 + + 0 + 1 + 2 + 3 + + @string/small_screen_position_top_right @string/small_screen_position_middle_right @@ -134,12 +148,12 @@ - @string/overlay_position_top_left - @string/overlay_position_center_top - @string/overlay_position_top_right - @string/overlay_position_bottom_left - @string/overlay_position_center_bottom - @string/overlay_position_bottom_right + @string/performance_overlay_position_top_left + @string/performance_overlay_position_center_top + @string/performance_overlay_position_top_right + @string/performance_overlay_position_bottom_left + @string/performance_overlay_position_center_bottom + @string/performance_overlay_position_bottom_right 0 @@ -225,9 +239,8 @@ - @string/off @string/side_by_side - @string/reverse_side_by_side + @string/side_by_side_full @string/anaglyph @string/interlaced @string/reverse_interlaced @@ -235,7 +248,6 @@ - 0 1 2 3 @@ -244,6 +256,20 @@ 6 + + @string/off + @string/render_3d_which_display_both + @string/render_3d_which_display_primary + @string/render_3d_which_display_secondary + + + + 0 + 1 + 2 + 3 + + @string/opengles @string/vulkan diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index ae12566a7..50fa23a1d 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -36,7 +36,6 @@ Changes the files that Azahar uses to load applications Modify the look of the app Install CIA - Learn more.]]> Select GPU driver @@ -76,10 +75,14 @@ Grant permission Skip granting the notification permission? Azahar won\'t be able to notify you of important information. + Missing Permissions + Azahar requires permission to manage files on this device in order to store and manage its data.\n\nPlease grant the \"Filesystem\" permission before continuing. Camera Grant the camera permission below to emulate the 3DS camera. Microphone Grant the microphone permission below to emulate the 3DS microphone. + Filesystem + Grant the filesystem permission below to allow Azahar to store files. Permission denied Skip selecting applications folder? Software won\'t be displayed in the Applications list if a folder isn\'t selected. @@ -100,6 +103,9 @@ You can\'t skip setting up the user folder This step is required to allow Azahar to work. Please select a directory and then you can continue. You have lost write permissions on your user data directory, where saves and other information are stored. This can happen after some app or Android updates. Please re-select the directory to regain permissions so you can continue. + Invalid Selection + The user directory selection was invalid.\nPlease re-select the user directory, ensuring that you navigate to it from the root of your device\'s storage. + Azahar has lost permission to manage files on this device. This can happen after some app or Android updates. Please re-grant this permission on the next screen to continue using the app. https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage Theme Settings Configure your theme preferences for Azahar. @@ -123,8 +129,8 @@ Some controllers may not be able to map their D-pad as an axis. If that\'s the case, use the D-Pad (buttons) section. D-Pad (Button) Only map the D-pad to these if you\'re facing issues with the D-Pad (Axis) button mappings. - Up/Down Axis - Left/Right Axis + Vertical Axis + Horizontal Axis Up Down Left @@ -133,8 +139,8 @@ Press or move an input. Input Binding Press or move an input to bind it to %1$s. - Move your joystick up or down. - Move your joystick left or right. + Press UP on your joystick. + Press RIGHT on your joystick. A B SELECT @@ -188,6 +194,8 @@ Username New 3DS Mode Use LLE Applets (if installed) + Apply region free patch to installed applications + Patches the region of installed applications to be region free, so that they always appear on the home menu. Enable required LLE modules for online features (if installed) Enables the LLE modules required for online multiplayer, eShop access, etc. Clock @@ -243,25 +251,27 @@ Emits the fragment shader used to emulate PICA using SPIR-V instead of GLSL Disable SPIR-V Optimizer Disables the SPIR-V optimization pass, reducing stuttering considerably while barely affecting performance. - Enable asynchronous shader compilation + Enable Asynchronous Shader Compilation Compiles shaders in the background to reduce stuttering during gameplay. When enabled expect temporary graphical glitches Linear Filtering Enables linear filtering, which causes game visuals to appear smoother. Texture Filter Enhances the visuals of applications by applying a filter to textures. The supported filters are Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale, and MMPX. - Delay game render thread + Delay Game Render Thread Delay the game render thread when it submits data to the GPU. Helps with performance issues in the (very few) applications with dynamic framerates. Advanced Texture Sampling Overrides the sampling filter used by games. This can be useful in certain cases with poorly behaved games when upscaling. If unsure, set this to Game Controlled. Accurate Multiplication Uses more accurate multiplication in hardware shaders, which may fix some graphical bugs. When enabled, performance will be reduced. - Enable asynchronous GPU emulation + Enable Asynchronous GPU Emulation Uses a separate thread to emulate the GPU asynchronously. When enabled, performance will be improved. Limit Speed When enabled, emulation speed will be limited to a specified percentage of normal speed. If disabled, emulation speed will be uncapped and the turbo speed hotkey will not work. Limit Speed Percent Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit. + Hide 3DS Images from Android + Prevent 3DS camera, screenshot, and custom texture images from being indexed by Android and displayed in the gallery. Your device may need to be rebooted after changing this setting to take effect. Turbo Speed Limit Emulation speed limit used while the turbo hotkey is active. Expand to Cutout Area @@ -283,10 +293,18 @@ Warning: Modifying these settings will slow emulation Stereoscopy Stereoscopic 3D Mode + Choose the stereoscopic 3D mode for 3D rendering. Side by Side modes are most common in modern use. Anaglyph and Interlaced modes will always apply to all connected displays. Depth Specifies the value of the 3D slider. This should be set to higher than 0% when Stereoscopic 3D is enabled.\nNote: Depth values over 100% are not possible on real hardware and may cause graphical issues Disable Right Eye Render Greatly improves performance in some applications, but can cause flickering in others. + Swap Eyes + Swaps which eye is shown in which side. Combined with Side by Side mode makes it possible to see 3D by crossing your eyes! + Render Stereoscopic 3D + Whether to enable stereoscopic 3D, and on which displays. The single display options are only relevant when multiple displays are connected. + On (All Displays) + On (Primary Display Only) + On (Secondary Display Only) Cardboard VR Cardboard Screen Size Scales the screen to a percentage of its original size. @@ -311,7 +329,7 @@ Volume Audio Stretching Stretches audio to reduce stuttering. When enabled, increases audio latency and slightly reduces performance. - Enable realtime audio + Enable Realtime Audio Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the game framerate is low. May cause audio desync issues. Audio Input Device Sound Output Mode @@ -323,12 +341,12 @@ Uses hardware to emulate 3DS shaders. When enabled, game performance will be significantly improved. CPU Clock Speed Enable V-Sync - Synchronizes the game frame rate to the refresh rate of your device. + Synchronizes the game frame rate to the refresh rate of your device. Can cause additional input latency but may reduce tearing in some cases. Debug Renderer Log additional graphics related debug information. When enabled, game performance will be significantly reduced. - Flush log output on every message + Flush Log Output on Every Message Immediately commits the debug log to file. Use this if Azahar crashes and the log output is being cut. - Delay start with LLE modules + Delay Start With LLE Modules Delays the start of the app when LLE modules are enabled. Deterministic Async Operations Makes async operations deterministic for debugging. Enabling this may cause freezes. @@ -384,8 +402,6 @@ Auto-Select Start Cancelling… - Important - Don\'t show again Visibility Information @@ -442,6 +458,8 @@ Aspect Ratio Landscape Screen Layout Portrait Screen Layout + Secondary Display Screen Layout + The layout used by a connected secondary screen, wired or wireless (Chromecast, Miracast) Large Screen Portrait Single Screen @@ -449,7 +467,15 @@ Hybrid Screens Original Default + System Default (mirror) Custom Layout + Background Color + The color which appears behind the screens during emulation, represented as an RGB value. + Red + Green + Blue + Custom Layout Second Screen Opacity + The opacity of the second 3DS screen when using a custom screen layout. Useful if the second screen is to be positioned on top of the first screen. Small Screen Position Where should the small screen appear relative to the large one in Large Screen Layout? Top Right @@ -545,10 +571,12 @@ Fatal Error A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs. Unsupported encrypted application + Invalid system mode + New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode. Preparing Shaders - Building Shaders + Building %s Play @@ -572,34 +600,36 @@ ID: File: Type: + Insert Cartridge + Eject Cartridge Show Performance Overlay Performance Overlay Enable Performance Overlay Configure whether the performance overlay is shown and what information is displayed. - Show FPS - Display current frames per second. - Show Frametime - Display current frametime. - Show Speed - Display current emulation speed percentage. - Show App Memory Usage - Display the amount of RAM getting used by the emulator. - Show Available Memory - Display the amount of RAM which is available. - Show Battery Temperature - Display current Battery temperature in Celsius and Fahrenheit. - Overlay Position - Choose where the performance overlay is displayed on the screen. - Top Left - Top Right - Bottom Left - Bottom Right - Center Top - Center Bottom - Overlay Background - Adds a background behind the overlay for easier reading. + Show FPS + Display current frames per second. + Show Frametime + Display current frametime. + Show Speed + Display current emulation speed percentage. + Show App Memory Usage + Display the amount of RAM getting used by the emulator. + Show Available Memory + Display the amount of RAM which is available. + Show Battery Temperature + Display current Battery temperature in Celsius and Fahrenheit. + Overlay Position + Choose where the performance overlay is displayed on the screen. + Top Left + Top Right + Bottom Left + Bottom Right + Center Top + Center Bottom + Overlay Background + Adds a background behind the overlay for easier reading. Cheats @@ -705,7 +735,7 @@ Side by Side - Reverse Side by Side + Side by Side Full Width Anaglyph Interlaced Reverse Interlaced @@ -894,4 +924,19 @@ Quicksave - %1$tF %1$tR No Quicksave available. + + Compress + Compressing… + Decompress + Decompressing… + Compression completed successfully. + Compression not supported for this file. + File is already compressed. + Compression failed. + Decompression completed successfully. + Decompression not supported for this file. + File is not compressed. + Decompression failed. + Already installed applications cannot be compressed or decompressed. + diff --git a/src/android/build.gradle.kts b/src/android/build.gradle.kts index aef05f5be..a0d43cb49 100644 --- a/src/android/build.gradle.kts +++ b/src/android/build.gradle.kts @@ -4,8 +4,8 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.11.1" apply false - id("com.android.library") version "8.11.1" apply false + id("com.android.application") version "8.13.1" apply false + id("com.android.library") version "8.13.1" apply false id("org.jetbrains.kotlin.android") version "2.0.20" apply false id("org.jetbrains.kotlin.plugin.serialization") version "2.0.20" } diff --git a/src/audio_core/cubeb_input.cpp b/src/audio_core/cubeb_input.cpp index 0cd650af6..63f66fd77 100644 --- a/src/audio_core/cubeb_input.cpp +++ b/src/audio_core/cubeb_input.cpp @@ -144,11 +144,6 @@ Samples CubebInput::Read() { while (impl->sample_queue.Pop(queue)) { samples.insert(samples.end(), queue.begin(), queue.end()); } - - if (samples.empty()) { - samples = GenerateSilentSamples(parameters); - } - return samples; } diff --git a/src/audio_core/dsp_interface.cpp b/src/audio_core/dsp_interface.cpp index 5f85b67e4..259459a5b 100644 --- a/src/audio_core/dsp_interface.cpp +++ b/src/audio_core/dsp_interface.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h index e2e76db6d..6e7ded2c1 100644 --- a/src/audio_core/dsp_interface.h +++ b/src/audio_core/dsp_interface.h @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -86,9 +86,6 @@ public: */ virtual void PipeWrite(DspPipe pipe_number, std::span buffer) = 0; - /// Returns a reference to the array backing DSP memory - virtual std::array& GetDspMemory() = 0; - /// Sets the handler for the interrupts we trigger virtual void SetInterruptHandler( std::function handler) = 0; diff --git a/src/audio_core/hle/aac_decoder.cpp b/src/audio_core/hle/aac_decoder.cpp index aba724978..054674367 100644 --- a/src/audio_core/hle/aac_decoder.cpp +++ b/src/audio_core/hle/aac_decoder.cpp @@ -8,7 +8,7 @@ namespace AudioCore::HLE { AACDecoder::AACDecoder(Memory::MemorySystem& memory) : memory(memory) { - OpenNewDecoder(); + Reset(); } AACDecoder::~AACDecoder() { @@ -63,6 +63,10 @@ BinaryMessage AACDecoder::ProcessRequest(const BinaryMessage& request) { } } +void AACDecoder::Reset() { + OpenNewDecoder(); +} + BinaryMessage AACDecoder::Decode(const BinaryMessage& request) { BinaryMessage response{}; response.header.codec = request.header.codec; diff --git a/src/audio_core/hle/aac_decoder.h b/src/audio_core/hle/aac_decoder.h index eb9d62295..1edbabd0b 100644 --- a/src/audio_core/hle/aac_decoder.h +++ b/src/audio_core/hle/aac_decoder.h @@ -16,6 +16,8 @@ public: ~AACDecoder() override; BinaryMessage ProcessRequest(const BinaryMessage& request) override; + void Reset() override; + private: BinaryMessage Decode(const BinaryMessage& request); bool OpenNewDecoder(); diff --git a/src/audio_core/hle/decoder.h b/src/audio_core/hle/decoder.h index 53365f45c..87bc3ef2c 100644 --- a/src/audio_core/hle/decoder.h +++ b/src/audio_core/hle/decoder.h @@ -1,4 +1,4 @@ -// Copyright 2018 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -137,6 +137,8 @@ class DecoderBase { public: virtual ~DecoderBase() = default; virtual BinaryMessage ProcessRequest(const BinaryMessage& request) = 0; + + virtual void Reset() = 0; }; } // namespace AudioCore::HLE diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index 2ad86ca73..f01631c7c 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -60,12 +61,14 @@ public: std::size_t GetPipeReadableSize(DspPipe pipe_number) const; void PipeWrite(DspPipe pipe_number, std::span buffer); - std::array& GetDspMemory(); - void SetInterruptHandler( std::function handler); private: + void Initialize(); + void Sleep(); + void Wakeup(); + void ResetPipes(); void WriteU16(DspPipe pipe_number, u16 value); void AudioPipeWriteStructAddresses(); @@ -81,7 +84,10 @@ private: DspState dsp_state = DspState::Off; std::array, num_dsp_pipe> pipe_data{}; - HLE::DspMemory dsp_memory; +public: + HLE::DspMemory* dsp_memory; + +private: std::array sources{{ HLE::Source(0), HLE::Source(1), HLE::Source(2), HLE::Source(3), HLE::Source(4), HLE::Source(5), HLE::Source(6), HLE::Source(7), HLE::Source(8), HLE::Source(9), @@ -91,6 +97,8 @@ private: }}; HLE::Mixers mixers{}; + HLE::DspMemory backup_dsp_memory; + DspHle& parent; Core::Timing& core_timing; Core::TimingEventType* tick_event{}; @@ -101,9 +109,10 @@ private: template void serialize(Archive& ar, const unsigned int) { + ar& boost::serialization::make_binary_object(backup_dsp_memory.raw_memory.data(), + backup_dsp_memory.raw_memory.size()); ar & dsp_state; ar & pipe_data; - ar & dsp_memory.raw_memory; ar & sources; ar & mixers; // interrupt_handler is reregistered when loading state from DSP_DSP @@ -113,7 +122,8 @@ private: DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing& timing) : parent(parent_), core_timing(timing) { - dsp_memory.raw_memory.fill(0); + dsp_memory = reinterpret_cast(memory.GetDspMemory(0)); + dsp_memory->raw_memory.fill(0); for (auto& source : sources) { source.SetMemory(memory); @@ -216,8 +226,6 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span buffer) { Sleep = 3, }; - // The difference between Initialize and Wakeup is that Input state is maintained - // when sleeping but isn't when turning it off and on again. (TODO: Implement this.) // Waking up from sleep garbles some of the structs in the memory region. (TODO: // Implement this.) Applications store away the state of these structs before // sleeping and reset it back after wakeup on behalf of the DSP. @@ -225,7 +233,7 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span buffer) { switch (static_cast(buffer[0])) { case StateChange::Initialize: LOG_INFO(Audio_DSP, "Application has requested initialization of DSP hardware"); - ResetPipes(); + Initialize(); AudioPipeWriteStructAddresses(); dsp_state = DspState::On; break; @@ -235,13 +243,13 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span buffer) { break; case StateChange::Wakeup: LOG_INFO(Audio_DSP, "Application has requested wakeup of DSP hardware"); - ResetPipes(); + Wakeup(); AudioPipeWriteStructAddresses(); dsp_state = DspState::On; break; case StateChange::Sleep: LOG_INFO(Audio_DSP, "Application has requested sleep of DSP hardware"); - UNIMPLEMENTED(); + Sleep(); AudioPipeWriteStructAddresses(); dsp_state = DspState::Sleeping; break; @@ -284,20 +292,56 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span buffer) { } } -std::array& DspHle::Impl::GetDspMemory() { - return dsp_memory.raw_memory; -} - void DspHle::Impl::SetInterruptHandler( std::function handler) { interrupt_handler = handler; } +void DspHle::Impl::Initialize() { + // TODO(PabloMK7): This is NOT the right way to do this, + // but it is close enough. This makes sure the DSP state + // is clean and consistent every time the HW is initialized, + // but what is exactly reset needs to be figured out. + dsp_memory->raw_memory.fill(0); + mixers.Reset(); + for (auto& s : sources) { + s.Reset(); + } + aac_decoder->Reset(); + ResetPipes(); +} + +void DspHle::Impl::Sleep() { + // TODO(PabloMK7): This is NOT the right way to do this, + // but it is close enough. What state is saved on + // real hardware still not figured out. + backup_dsp_memory.raw_memory = dsp_memory->raw_memory; + mixers.Sleep(); + for (auto& s : sources) { + s.Sleep(); + } + // TODO(PabloMK7): Figure out if we need to save the state + // of the AAC decoder, probably not. +} + +void DspHle::Impl::Wakeup() { + // TODO(PabloMK7): This is NOT the right way to do this, + // but it is close enough. What state is restored on + // real hardware still not figured out. + dsp_memory->raw_memory = backup_dsp_memory.raw_memory; + backup_dsp_memory.raw_memory.fill(0); + mixers.Wakeup(); + for (auto& s : sources) { + s.Wakeup(); + } + aac_decoder->Reset(); + ResetPipes(); +} + void DspHle::Impl::ResetPipes() { for (auto& data : pipe_data) { data.clear(); } - dsp_state = DspState::Off; } void DspHle::Impl::WriteU16(DspPipe pipe_number, u16 value) { @@ -343,8 +387,8 @@ void DspHle::Impl::AudioPipeWriteStructAddresses() { size_t DspHle::Impl::CurrentRegionIndex() const { // The region with the higher frame counter is chosen unless there is wraparound. // This function only returns a 0 or 1. - const u16 frame_counter_0 = dsp_memory.region_0.frame_counter; - const u16 frame_counter_1 = dsp_memory.region_1.frame_counter; + const u16 frame_counter_0 = dsp_memory->region_0.frame_counter; + const u16 frame_counter_1 = dsp_memory->region_1.frame_counter; if (frame_counter_0 == 0xFFFFu && frame_counter_1 != 0xFFFEu) { // Wraparound has occurred. @@ -360,11 +404,11 @@ size_t DspHle::Impl::CurrentRegionIndex() const { } HLE::SharedMemory& DspHle::Impl::ReadRegion() { - return CurrentRegionIndex() == 0 ? dsp_memory.region_0 : dsp_memory.region_1; + return CurrentRegionIndex() == 0 ? dsp_memory->region_0 : dsp_memory->region_1; } HLE::SharedMemory& DspHle::Impl::WriteRegion() { - return CurrentRegionIndex() != 0 ? dsp_memory.region_0 : dsp_memory.region_1; + return CurrentRegionIndex() != 0 ? dsp_memory->region_0 : dsp_memory->region_1; } StereoFrame16 DspHle::Impl::GenerateCurrentFrame() { @@ -399,15 +443,19 @@ StereoFrame16 DspHle::Impl::GenerateCurrentFrame() { } bool DspHle::Impl::Tick() { - StereoFrame16 current_frame = {}; + bool is_on = GetDspState() == DspState::On; - // TODO: Check dsp::DSP semaphore (which indicates emulated application has finished writing to - // shared memory region) - current_frame = GenerateCurrentFrame(); + if (is_on) { + StereoFrame16 current_frame = {}; - parent.OutputFrame(std::move(current_frame)); + // TODO: Check dsp::DSP semaphore (which indicates emulated application has finished writing + // to shared memory region) + current_frame = GenerateCurrentFrame(); - return GetDspState() == DspState::On; + parent.OutputFrame(std::move(current_frame)); + } + + return is_on; } void DspHle::Impl::AudioTickCallback(s64 cycles_late) { @@ -454,10 +502,6 @@ void DspHle::PipeWrite(DspPipe pipe_number, std::span buffer) { impl->PipeWrite(pipe_number, buffer); } -std::array& DspHle::GetDspMemory() { - return impl->GetDspMemory(); -} - void DspHle::SetInterruptHandler( std::function handler) { impl->SetInterruptHandler(handler); @@ -466,11 +510,13 @@ void DspHle::SetInterruptHandler( void DspHle::LoadComponent(std::span component_data) { // HLE doesn't need DSP program. Only log some info here LOG_INFO(Service_DSP, "Firmware hash: {:#018x}", - Common::ComputeHash64(component_data.data(), component_data.size())); + Common::ComputeHash64(component_data.data(), + component_data.size())); // Some versions of the firmware have the location of DSP structures listed here. if (component_data.size() > 0x37C) { - LOG_INFO(Service_DSP, "Structures hash: {:#018x}", - Common::ComputeHash64(component_data.data() + 0x340, 60)); + LOG_INFO( + Service_DSP, "Structures hash: {:#018x}", + Common::ComputeHash64(component_data.data() + 0x340, 60)); } } diff --git a/src/audio_core/hle/hle.h b/src/audio_core/hle/hle.h index 2ee4421e7..1dba7450a 100644 --- a/src/audio_core/hle/hle.h +++ b/src/audio_core/hle/hle.h @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -37,8 +37,6 @@ public: std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; void PipeWrite(DspPipe pipe_number, std::span buffer) override; - std::array& GetDspMemory() override; - void SetInterruptHandler( std::function handler) override; diff --git a/src/audio_core/hle/mixers.cpp b/src/audio_core/hle/mixers.cpp index e3a838886..cfe99244a 100644 --- a/src/audio_core/hle/mixers.cpp +++ b/src/audio_core/hle/mixers.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -15,6 +15,18 @@ void Mixers::Reset() { state = {}; } +void Mixers::Sleep() { + backup_state = state; + backup_frame = current_frame; +} + +void Mixers::Wakeup() { + state = backup_state; + current_frame = backup_frame; + backup_state = {}; + backup_frame.fill({}); +} + DspStatus Mixers::Tick(DspConfiguration& config, const IntermediateMixSamples& read_samples, IntermediateMixSamples& write_samples, const std::array& input) { diff --git a/src/audio_core/hle/mixers.h b/src/audio_core/hle/mixers.h index b09654dfc..95d9e86e3 100644 --- a/src/audio_core/hle/mixers.h +++ b/src/audio_core/hle/mixers.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -19,6 +19,9 @@ public: void Reset(); + void Sleep(); + void Wakeup(); + DspStatus Tick(DspConfiguration& config, const IntermediateMixSamples& read_samples, IntermediateMixSamples& write_samples, const std::array& input); @@ -28,10 +31,11 @@ public: private: StereoFrame16 current_frame = {}; + StereoFrame16 backup_frame = {}; // TODO(PabloMK7): Check if we actually need this using OutputFormat = DspConfiguration::OutputFormat; - struct { + struct MixerState { std::array intermediate_mixer_volume = {}; std::array aux_bus_enable = {}; @@ -39,7 +43,17 @@ private: OutputFormat output_format = OutputFormat::Stereo; - } state; + template + void serialize(Archive& ar, const unsigned int) { + ar & intermediate_mixer_volume; + ar & aux_bus_enable; + ar & intermediate_mix_buffer; + ar & output_format; + } + }; + + MixerState state; + MixerState backup_state; /// INTERNAL: Update our internal state based on the current config. void ParseConfig(DspConfiguration& config); @@ -58,10 +72,9 @@ private: template void serialize(Archive& ar, const unsigned int) { ar & current_frame; - ar & state.intermediate_mixer_volume; - ar & state.aux_bus_enable; - ar & state.intermediate_mix_buffer; - ar & state.output_format; + ar & backup_frame; + ar & state; + ar & backup_state; } friend class boost::serialization::access; }; diff --git a/src/audio_core/hle/shared_memory.h b/src/audio_core/hle/shared_memory.h index 41dc4e25c..194f517a9 100644 --- a/src/audio_core/hle/shared_memory.h +++ b/src/audio_core/hle/shared_memory.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -533,6 +533,7 @@ union DspMemory { u8 unused_2[0x8000]; }; }; +static_assert(sizeof(DspMemory) == 0x80000, "Incorrect DSP memory size"); static_assert(offsetof(DspMemory, region_0) == region0_offset, "DSP region 0 is at the wrong offset"); static_assert(offsetof(DspMemory, region_1) == region1_offset, diff --git a/src/audio_core/hle/source.cpp b/src/audio_core/hle/source.cpp index c90201bbd..018368704 100644 --- a/src/audio_core/hle/source.cpp +++ b/src/audio_core/hle/source.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -44,6 +44,18 @@ void Source::Reset() { state = {}; } +void Source::Sleep() { + backup_frame = current_frame; + backup_state = state; +} + +void Source::Wakeup() { + current_frame = backup_frame; + state = backup_state; + backup_frame.fill({}); + backup_state = {}; +} + void Source::SetMemory(Memory::MemorySystem& memory) { memory_system = &memory; } diff --git a/src/audio_core/hle/source.h b/src/audio_core/hle/source.h index 2073e9033..c0c1fdc1a 100644 --- a/src/audio_core/hle/source.h +++ b/src/audio_core/hle/source.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -42,6 +42,9 @@ public: /// Resets internal state. void Reset(); + void Sleep(); + void Wakeup(); + /// Sets the memory system to read data from void SetMemory(Memory::MemorySystem& memory); @@ -68,6 +71,7 @@ private: const std::size_t source_id; Memory::MemorySystem* memory_system{}; StereoFrame16 current_frame; + StereoFrame16 backup_frame; // TODO(PabloMK7): Check if we actually need this using Format = SourceConfiguration::Configuration::Format; using InterpolationMode = SourceConfiguration::Configuration::InterpolationMode; @@ -116,7 +120,7 @@ private: } }; - struct { + struct SourceState { // State variables @@ -179,8 +183,10 @@ private: ar & interpolation_mode; } friend class boost::serialization::access; + }; - } state; + SourceState state; + SourceState backup_state; // Internal functions @@ -197,6 +203,9 @@ private: template void serialize(Archive& ar, const unsigned int) { ar & state; + ar & backup_state; + ar & current_frame; + ar & backup_frame; } friend class boost::serialization::access; }; diff --git a/src/audio_core/input.h b/src/audio_core/input.h index e47f5942c..f43764296 100644 --- a/src/audio_core/input.h +++ b/src/audio_core/input.h @@ -53,22 +53,6 @@ public: */ virtual Samples Read() = 0; - /** - * Generates a buffer of silence. - * Takes into account the sample size and signedness of the input. - */ - virtual Samples GenerateSilentSamples(const InputParameters& params) { - u8 silent_value = 0x00; - - if (params.sample_size == 8) { - silent_value = params.sign == Signedness::Unsigned ? 0x80 : 0x00; - return std::vector(32, silent_value); - } else { - silent_value = params.sign == Signedness::Unsigned ? 0x80 : 0x00; - return std::vector(64, silent_value); - } - } - protected: InputParameters parameters; }; diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 91ac5dc73..0e301f72d 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -1,4 +1,4 @@ -// Copyright 2018 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -121,7 +121,9 @@ static u8 PipeIndexToSlotIndex(u8 pipe_index, PipeDirection direction) { } struct DspLle::Impl final { - Impl(Core::Timing& timing, bool multithread) : core_timing(timing), multithread(multithread) { + Impl(Core::Timing& timing, Memory::MemorySystem& memory, bool multithread) + : teakra(Teakra::UserConfig{.dsp_memory = memory.GetDspMemory(0)}), core_timing(timing), + multithread(multithread) { teakra_slice_event = core_timing.RegisterEvent( "DSP slice", [this](u64, int late) { TeakraSliceEvent(static_cast(late)); }); } @@ -189,12 +191,12 @@ struct DspLle::Impl final { } u8* GetDspDataPointer(u32 baddr) { - auto& memory = teakra.GetDspMemory(); + uint8_t* memory = teakra.GetDspMemory(); return &memory[DspDataOffset + baddr]; } const u8* GetDspDataPointer(u32 baddr) const { - auto& memory = teakra.GetDspMemory(); + const uint8_t* memory = teakra.GetDspMemory(); return &memory[DspDataOffset + baddr]; } @@ -312,9 +314,9 @@ struct DspLle::Impl final { teakra.Reset(); Dsp1 dsp(buffer); - auto& dsp_memory = teakra.GetDspMemory(); - u8* program = dsp_memory.data(); - u8* data = dsp_memory.data() + DspDataOffset; + auto dsp_memory = teakra.GetDspMemory(); + u8* program = dsp_memory; + u8* data = dsp_memory + DspDataOffset; for (const auto& segment : dsp.segments) { if (segment.memory_type == SegmentType::ProgramA || segment.memory_type == SegmentType::ProgramB) { @@ -403,10 +405,6 @@ void DspLle::PipeWrite(DspPipe pipe_number, std::span buffer) { impl->WritePipe(static_cast(pipe_number), buffer); } -std::array& DspLle::GetDspMemory() { - return impl->teakra.GetDspMemory(); -} - void DspLle::SetInterruptHandler( std::function handler) { impl->teakra.SetRecvDataHandler(0, [this, handler]() { @@ -469,7 +467,7 @@ DspLle::DspLle(Core::System& system, bool multithread) DspLle::DspLle(Core::System& system, Memory::MemorySystem& memory, Core::Timing& timing, bool multithread) - : DspInterface(system), impl(std::make_unique(timing, multithread)) { + : DspInterface(system), impl(std::make_unique(timing, memory, multithread)) { Teakra::AHBMCallback ahbm; ahbm.read8 = [&memory](u32 address) -> u8 { return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR); diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index 7ae64575d..7cfd62e29 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -1,4 +1,4 @@ -// Copyright 2018 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -31,8 +31,6 @@ public: std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; void PipeWrite(DspPipe pipe_number, std::span buffer) override; - std::array& GetDspMemory() override; - void SetInterruptHandler( std::function handler) override; diff --git a/src/audio_core/null_input.h b/src/audio_core/null_input.h index 1b0796ea7..448120247 100644 --- a/src/audio_core/null_input.h +++ b/src/audio_core/null_input.h @@ -30,11 +30,10 @@ public: void AdjustSampleRate(u32 sample_rate) override {} Samples Read() override { - return GenerateSilentSamples(parameters); + return {}; } private: - InputParameters parameters; bool is_sampling = false; }; diff --git a/src/audio_core/openal_input.cpp b/src/audio_core/openal_input.cpp index 3d4c55fb0..edf20bb47 100644 --- a/src/audio_core/openal_input.cpp +++ b/src/audio_core/openal_input.cpp @@ -108,10 +108,6 @@ Samples OpenALInput::Read() { return {}; } - if (samples.empty()) { - samples = GenerateSilentSamples(parameters); - } - return samples; } diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h index 65b5a820c..73a10f567 100644 --- a/src/audio_core/sink.h +++ b/src/audio_core/sink.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -9,7 +9,7 @@ namespace AudioCore { -constexpr char auto_device_name[] = "auto"; +constexpr char auto_device_name[] = "Auto"; /** * This class is an interface for an audio sink. An audio sink accepts samples in stereo signed diff --git a/src/citra_meta/CMakeLists.txt b/src/citra_meta/CMakeLists.txt index 9f9dcd574..3b6d2b230 100644 --- a/src/citra_meta/CMakeLists.txt +++ b/src/citra_meta/CMakeLists.txt @@ -17,6 +17,8 @@ if (APPLE) # Define app bundle metadata. include(GenerateBuildInfo) + set(SRC_DIR "${PROJECT_SOURCE_DIR}") + generate_build_info() set_target_properties(citra_meta PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_PLIST "${DIST_DIR}/Info.plist.in" @@ -60,6 +62,11 @@ if (ENABLE_QT AND UNIX AND NOT APPLE) target_link_libraries(citra_meta PRIVATE Qt6::DBus gamemode) endif() +if (ENABLE_QT AND APPLE) + find_package(Qt6 REQUIRED COMPONENTS GuiPrivate) + target_link_libraries(citra_meta PRIVATE Qt6::GuiPrivate) +endif() + if (ENABLE_QT AND USE_DISCORD_PRESENCE) target_link_libraries(citra_meta PRIVATE discord-rpc) endif() diff --git a/src/citra_meta/main.cpp b/src/citra_meta/main.cpp index 8b581af6c..134f2d2dd 100644 --- a/src/citra_meta/main.cpp +++ b/src/citra_meta/main.cpp @@ -4,6 +4,9 @@ #include +#include "common/detached_tasks.h" +#include "common/scope_exit.h" + #ifdef ENABLE_QT #include "citra_qt/citra_qt.h" #endif @@ -69,6 +72,9 @@ static bool CheckAndReportSSE42() { #endif int main(int argc, char* argv[]) { + Common::DetachedTasks detached_tasks; + SCOPE_EXIT({ detached_tasks.WaitForAllTasks(); }); + #if CITRA_HAS_SSE42 if (!CheckAndReportSSE42()) { return 1; @@ -84,8 +90,7 @@ int main(int argc, char* argv[]) { } if (launch_room) { - LaunchRoom(argc, argv, true); - return 0; + return LaunchRoom(argc, argv, true); } #endif @@ -98,13 +103,12 @@ int main(int argc, char* argv[]) { } if (!no_gui) { - LaunchQtFrontend(argc, argv); - return 0; + return LaunchQtFrontend(argc, argv); } #endif #if ENABLE_SDL2_FRONTEND - LaunchSdlFrontend(argc, argv); + return LaunchSdlFrontend(argc, argv); #else std::cout << "Cannot use SDL frontend as it was disabled at compile time. Exiting." << std::endl; diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index a36d40a4d..e6faa88ce 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -172,12 +172,12 @@ add_library(citra_qt STATIC EXCLUDE_FROM_ALL multiplayer/state.h multiplayer/validation.h precompiled_headers.h + qt_image_interface.cpp + qt_image_interface.h uisettings.cpp uisettings.h user_data_migration.cpp user_data_migration.h - qt_image_interface.cpp - qt_image_interface.h util/clickable_label.cpp util/clickable_label.h util/graphics_device_info.cpp @@ -190,6 +190,13 @@ add_library(citra_qt STATIC EXCLUDE_FROM_ALL util/util.h ) +if (APPLE) + target_sources(citra_qt PUBLIC + qt_swizzle.h + qt_swizzle.mm + ) +endif() + file(GLOB COMPAT_LIST ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) @@ -272,10 +279,17 @@ endif() if (NOT WIN32) find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) - target_include_directories(citra_qt PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) + if(Qt6_VERSION VERSION_GREATER_EQUAL "6.10.0") + find_package(Qt6 REQUIRED COMPONENTS GuiPrivate) + target_link_libraries(citra_qt PRIVATE Qt6::GuiPrivate) + else() + target_include_directories(citra_qt PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) + endif() endif() -if (UNIX AND NOT APPLE) +if (APPLE) + target_link_libraries(citra_qt PRIVATE Qt6::QDarwinCameraPermissionPlugin) +elseif (UNIX) target_link_libraries(citra_qt PRIVATE Qt6::DBus gamemode) endif() diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index b53dbd5b9..39649b8bf 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -18,6 +18,7 @@ #include "core/3ds.h" #include "core/core.h" #include "core/frontend/framebuffer_layout.h" +#include "core/loader/loader.h" #include "core/perf_stats.h" #include "input_common/keyboard.h" #include "input_common/main.h" @@ -64,26 +65,32 @@ void EmuThread::run() { MicroProfileOnThreadCreate("EmuThread"); const auto scope = core_context.Acquire(); - if (Settings::values.preload_textures) { - emit LoadProgress(VideoCore::LoadCallbackStage::Preload, 0, 0); + if (Settings::values.custom_textures && Settings::values.preload_textures) { + emit LoadProgress(VideoCore::LoadCallbackStage::Preload, 0, 0, ""); system.CustomTexManager().PreloadTextures( - stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, - std::size_t total) { emit LoadProgress(stage, value, total); }); + stop_run, + [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total, + const std::string& object) { emit LoadProgress(stage, value, total, object); }); } system.GPU().Renderer().Rasterizer()->SetSwitchDiskResourcesCallback( - [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { - emit SwitchDiskResources(stage, value, total); + [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total, + const std::string& object) { + emit SwitchDiskResources(stage, value, total, object); }); - emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); + emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0, ""); + + u64 program_id{}; + system.GetAppLoader().ReadProgramId(program_id); + system.GPU().ApplyPerProgramSettings(program_id); system.GPU().Renderer().Rasterizer()->LoadDefaultDiskResources( - stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { - emit LoadProgress(stage, value, total); - }); + stop_run, + [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total, + const std::string& object) { emit LoadProgress(stage, value, total, object); }); - emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); + emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0, ""); core_context.MakeCurrent(); @@ -754,7 +761,7 @@ bool GRenderWindow::InitializeOpenGL() { child->SetContext(std::move(child_context)); auto format = child_widget->windowHandle()->format(); - format.setSwapInterval(Settings::values.use_vsync_new.GetValue()); + format.setSwapInterval(Settings::values.use_vsync.GetValue()); child_widget->windowHandle()->setFormat(format); return true; diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index 8082b5590..118959c60 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h @@ -108,10 +108,11 @@ signals: void ErrorThrown(Core::System::ResultStatus, std::string); - void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); + void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total, + const std::string& object); void SwitchDiskResources(VideoCore::LoadCallbackStage stage, std::size_t value, - std::size_t total); + std::size_t total, const std::string& object); void HideLoadingScreen(); }; diff --git a/src/citra_qt/citra_qt.cpp b/src/citra_qt/citra_qt.cpp index bc126089f..d8e207ec9 100644 --- a/src/citra_qt/citra_qt.cpp +++ b/src/citra_qt/citra_qt.cpp @@ -60,7 +60,9 @@ #include "citra_qt/debugger/profiler.h" #include "citra_qt/debugger/registers.h" #include "citra_qt/debugger/wait_tree.h" +#ifdef USE_DISCORD_PRESENCE #include "citra_qt/discord.h" +#endif #include "citra_qt/dumping/dumping_dialog.h" #include "citra_qt/game_list.h" #include "citra_qt/hotkeys.h" @@ -69,6 +71,7 @@ #include "citra_qt/movie/movie_record_dialog.h" #include "citra_qt/multiplayer/state.h" #include "citra_qt/qt_image_interface.h" +#include "citra_qt/qt_swizzle.h" #include "citra_qt/uisettings.h" #include "common/play_time_manager.h" #ifdef ENABLE_QT_UPDATE_CHECKER @@ -79,7 +82,6 @@ #include "citra_qt/util/util.h" #include "common/arch.h" #include "common/common_paths.h" -#include "common/detached_tasks.h" #include "common/dynamic_library/dynamic_library.h" #include "common/file_util.h" #include "common/literals.h" @@ -114,6 +116,7 @@ #ifdef __APPLE__ #include "common/apple_authorization.h" +Q_IMPORT_PLUGIN(QDarwinCameraPermissionPlugin); #endif #ifdef USE_DISCORD_PRESENCE @@ -170,6 +173,21 @@ void GMainWindow::ShowCommandOutput(std::string title, std::string message) { #endif } +bool IsPrereleaseBuild() { + return ((strstr(Common::g_build_fullname, "alpha") != NULL) || + (strstr(Common::g_build_fullname, "beta") != NULL) || + (strstr(Common::g_build_fullname, "rc") != NULL)); +} + +#ifdef ENABLE_QT_UPDATE_CHECKER +bool ShouldCheckForPrereleaseUpdates() { + const bool update_channel = UISettings::values.update_check_channel.GetValue(); + const bool using_prerelease_channel = + (update_channel == UISettings::UpdateCheckChannels::PRERELEASE); + return (IsPrereleaseBuild() || using_prerelease_channel); +} +#endif + GMainWindow::GMainWindow(Core::System& system_) : ui{std::make_unique()}, system{system_}, movie{system.Movie()}, user_data_migrator{this}, config{std::make_unique()}, emu_thread{nullptr} { @@ -334,8 +352,10 @@ GMainWindow::GMainWindow(Core::System& system_) default_theme_paths = QIcon::themeSearchPaths(); UpdateUITheme(); +#ifdef USE_DISCORD_PRESENCE SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); discord_rpc->Update(); +#endif play_time_manager = std::make_unique(); @@ -376,7 +396,7 @@ GMainWindow::GMainWindow(Core::System& system_) } else if (caps.avx2) { cpu_string += '2'; } - if (caps.fma || caps.fma4) { + if (caps.fma) { cpu_string += " | FMA"; } } @@ -398,12 +418,9 @@ GMainWindow::GMainWindow(Core::System& system_) #ifdef ENABLE_QT_UPDATE_CHECKER if (UISettings::values.check_for_update_on_start) { update_future = QtConcurrent::run([]() -> QString { - const bool is_prerelease = // TODO: This can be done better -OS - ((strstr(Common::g_build_fullname, "alpha") != NULL) || - (strstr(Common::g_build_fullname, "beta") != NULL) || - (strstr(Common::g_build_fullname, "rc") != NULL)); const std::optional latest_release_tag = - UpdateChecker::GetLatestRelease(is_prerelease); + UpdateChecker::GetLatestRelease(ShouldCheckForPrereleaseUpdates()); + if (latest_release_tag && latest_release_tag.value() != Common::g_build_fullname) { return QString::fromStdString(latest_release_tag.value()); } @@ -977,6 +994,10 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList); connect(game_list, &GameList::PopulatingCompleted, this, [this] { multiplayer_state->UpdateGameList(game_list->GetModel()); }); +#ifdef ENABLE_DEVELOPER_OPTIONS + connect(game_list, &GameList::StartingLaunchStressTest, this, + &GMainWindow::StartLaunchStressTest); +#endif connect(game_list, &GameList::OpenPerGameGeneralRequested, this, &GMainWindow::OnGameListOpenPerGameProperties); @@ -1235,6 +1256,10 @@ bool GMainWindow::LoadROM(const QString& filename) { const auto scope = render_window->Acquire(); + if (!UISettings::values.inserted_cartridge.GetValue().empty()) { + system.InsertCartridge(UISettings::values.inserted_cartridge.GetValue()); + } + const Core::System::ResultStatus result{ system.Load(*render_window, filename.toStdString(), secondary_window)}; @@ -1305,6 +1330,11 @@ bool GMainWindow::LoadROM(const QString& filename) { system.GetStatusDetails()) .c_str())); break; + case Core::System::ResultStatus::ErrorN3DSApplication: + QMessageBox::critical(this, tr("Invalid system mode"), + tr("New 3DS exclusive applications cannot be loaded without " + "enabling the New 3DS mode.")); + break; default: QMessageBox::critical( this, tr("Error while loading App!"), @@ -1495,7 +1525,10 @@ void GMainWindow::ShutdownGame() { AllowOSSleep(); +#ifdef USE_DISCORD_PRESENCE discord_rpc->Pause(); +#endif + emu_thread->RequestStop(); // Release emu threads from any breakpoints @@ -1519,10 +1552,13 @@ void GMainWindow::ShutdownGame() { emu_thread->wait(); emu_thread = nullptr; + system.EjectCartridge(); + OnCloseMovie(); +#ifdef USE_DISCORD_PRESENCE discord_rpc->Update(); - +#endif #ifdef __unix__ Common::Linux::StopGamemode(); #endif @@ -1573,6 +1609,18 @@ void GMainWindow::ShutdownGame() { secondary_window->ReleaseRenderTarget(); } +#ifdef ENABLE_DEVELOPER_OPTIONS +void GMainWindow::StartLaunchStressTest(const QString& game_path) { + QThreadPool::globalInstance()->start([this, game_path] { + do { + ui->action_Stop->trigger(); + emit game_list->GameChosen(game_path); + QThread::sleep(2); + } while (emulation_running); + }); +} +#endif + void GMainWindow::StoreRecentFile(const QString& filename) { UISettings::values.recent_files.prepend(filename); UISettings::values.recent_files.removeDuplicates(); @@ -1870,7 +1918,9 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, LOG_ERROR(Frontend, "Failed to get IPersistFile interface"); return false; } - hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE); + hres = persist_file->Save( + std::filesystem::path{shortcut_path / (Common::UTF8ToUTF16W(name) + L".lnk")}.c_str(), + TRUE); if (FAILED(hres)) { LOG_ERROR(Frontend, "Failed to save shortcut"); return false; @@ -2273,8 +2323,8 @@ void GMainWindow::OnMenuBootHomeMenu(u32 region) { void GMainWindow::InstallCIA(QStringList filepaths) { ui->action_Install_CIA->setEnabled(false); game_list->SetDirectoryWatcherEnabled(false); - progress_bar->show(); - progress_bar->setMaximum(INT_MAX); + + emit UpdateProgress(0, 0); (void)QtConcurrent::run([&, filepaths] { Service::AM::InstallStatus status; @@ -2290,6 +2340,11 @@ void GMainWindow::InstallCIA(QStringList filepaths) { } void GMainWindow::OnUpdateProgress(std::size_t written, std::size_t total) { + if (written == 0 and total == 0) { + progress_bar->show(); + progress_bar->setValue(0); + progress_bar->setMaximum(INT_MAX); + } progress_bar->setValue( static_cast(INT_MAX * (static_cast(written) / static_cast(total)))); } @@ -2333,11 +2388,19 @@ void GMainWindow::OnCompressFinished(bool is_compress, bool success) { if (!success) { if (is_compress) { - QMessageBox::critical(this, tr("Error compressing file"), - tr("File compress operation failed, check log for details.")); + QMessageBox::critical(this, tr("Z3DS Compression"), + tr("Failed to compress some files, check log for details.")); } else { - QMessageBox::critical(this, tr("Error decompressing file"), - tr("File decompress operation failed, check log for details.")); + QMessageBox::critical(this, tr("Z3DS Compression"), + tr("Failed to decompress some files, check log for details.")); + } + } else { + if (is_compress) { + QMessageBox::information(this, tr("Z3DS Compression"), + tr("All files have been compressed successfully.")); + } else { + QMessageBox::information(this, tr("Z3DS Compression"), + tr("All files have been decompressed successfully.")); } } } @@ -2435,8 +2498,9 @@ void GMainWindow::OnStartGame() { play_time_manager->SetProgramId(game_title_id); play_time_manager->Start(); +#ifdef USE_DISCORD_PRESENCE discord_rpc->Update(); - +#endif #ifdef __unix__ Common::Linux::StartGamemode(); #endif @@ -2760,7 +2824,9 @@ void GMainWindow::OnConfigure() { const int old_input_profile_index = Settings::values.current_input_profile_index; const auto old_input_profiles = Settings::values.input_profiles; const auto old_touch_from_button_maps = Settings::values.touch_from_button_maps; +#ifdef USE_DISCORD_PRESENCE const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue(); +#endif #ifdef __unix__ const bool old_gamemode = Settings::values.enable_gamemode.GetValue(); #endif @@ -2772,9 +2838,11 @@ void GMainWindow::OnConfigure() { if (UISettings::values.theme != old_theme) { UpdateUITheme(); } +#ifdef USE_DISCORD_PRESENCE if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) { SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); } +#endif #ifdef __unix__ if (Settings::values.enable_gamemode.GetValue() != old_gamemode) { SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue()); @@ -3049,43 +3117,27 @@ void GMainWindow::OnDumpVideo() { } } -void GMainWindow::OnCompressFile() { - // NOTE: Encrypted files SHOULD NEVER be compressed, otherwise the resulting - // compressed file will have very poor compression ratios, due to the high - // entropy caused by encryption. This may cause confusion to the user as they - // will see the files do not compress well and blame the emulator. - // - // This is enforced using the loaders as they already return an error on encryption. - - QString filepath = QFileDialog::getOpenFileName( - this, tr("Load 3DS ROM File"), UISettings::values.roms_path, - tr("3DS ROM Files (*.cia *cci *3dsx *cxi)") + QStringLiteral(";;") + tr("All Files (*.*)")); - - if (filepath.isEmpty()) { - return; - } - std::string in_path = filepath.toStdString(); - - // Identify file type +static std::optional> GetCompressFileInfo( + const std::string& filepath, bool compress) { Loader::AppLoader::CompressFileInfo compress_info{}; compress_info.is_supported = false; size_t frame_size{}; - { - auto loader = Loader::GetLoader(in_path); - if (loader) { - compress_info = loader->GetCompressFileInfo(); - frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_FRAME_SIZE; - } else { - bool is_compressed = false; - if (Service::AM::CheckCIAToInstall(in_path, is_compressed, true) == - Service::AM::InstallStatus::Success) { - auto meta_info = Service::AM::GetCIAInfos(in_path); - compress_info.is_supported = true; - compress_info.is_compressed = is_compressed; - compress_info.recommended_compressed_extension = "zcia"; - compress_info.recommended_uncompressed_extension = "cia"; - compress_info.underlying_magic = std::array({'C', 'I', 'A', '\0'}); - frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_CIA_FRAME_SIZE; + auto loader = Loader::GetLoader(filepath); + if (loader) { + compress_info = loader->GetCompressFileInfo(); + frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_FRAME_SIZE; + } else { + bool is_compressed = false; + if (Service::AM::CheckCIAToInstall(filepath, is_compressed, compress ? true : false) == + Service::AM::InstallStatus::Success) { + compress_info.is_supported = true; + compress_info.is_compressed = is_compressed; + compress_info.recommended_compressed_extension = "zcia"; + compress_info.recommended_uncompressed_extension = "cia"; + compress_info.underlying_magic = std::array({'C', 'I', 'A', '\0'}); + frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_CIA_FRAME_SIZE; + if (compress) { + auto meta_info = Service::AM::GetCIAInfos(filepath); if (meta_info.Succeeded()) { const auto& meta_info_val = meta_info.Unwrap(); std::vector value(sizeof(Service::AM::TitleInfo)); @@ -3100,122 +3152,218 @@ void GMainWindow::OnCompressFile() { } } } + if (!compress_info.is_supported) { - QMessageBox::critical( - this, tr("Error compressing file"), - tr("The selected file is not a compatible 3DS ROM format. Make sure you have " - "chosen the right file, and that it is not encrypted.")); - return; + LOG_ERROR(Frontend, + "Error {} file {}, the selected file is not a compatible 3DS ROM format or is " + "encrypted.", + compress ? "compressing" : "decompressing", filepath); + return {}; } - if (compress_info.is_compressed) { - QMessageBox::warning(this, tr("Error compressing file"), - tr("The selected file is already compressed.")); + if (compress_info.is_compressed && compress) { + LOG_ERROR(Frontend, "Error compressing file {}, the selected file is already compressed", + filepath); + return {}; + } + if (!compress_info.is_compressed && !compress) { + LOG_ERROR(Frontend, + "Error decompressing file {}, the selected file is already decompressed", + filepath); + return {}; + } + + return std::pair(compress_info, frame_size); +} + +void GMainWindow::OnCompressFile() { + // NOTE: Encrypted files SHOULD NEVER be compressed, otherwise the resulting + // compressed file will have very poor compression ratios, due to the high + // entropy caused by encryption. This may cause confusion to the user as they + // will see the files do not compress well and blame the emulator. + // + // This is enforced using the loaders as they already return an error on encryption. + + QStringList filepaths = + QFileDialog::getOpenFileNames(this, tr("Load 3DS ROM Files"), UISettings::values.roms_path, + tr("3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds)") + + QStringLiteral(";;") + tr("All Files (*.*)")); + + QString out_path; + + if (filepaths.isEmpty()) { return; } - QString out_filter = - tr("3DS Compressed ROM File (*.%1)") - .arg(QString::fromStdString(compress_info.recommended_compressed_extension)); - - QFileInfo fileinfo(filepath); - QString final_path = fileinfo.path() + QStringLiteral(DIR_SEP) + fileinfo.completeBaseName() + - QStringLiteral(".") + - QString::fromStdString(compress_info.recommended_compressed_extension); - - filepath = QFileDialog::getSaveFileName(this, tr("Save 3DS Compressed ROM File"), final_path, - out_filter); - if (filepath.isEmpty()) { - return; - } - std::string out_path = filepath.toStdString(); - - progress_bar->show(); - progress_bar->setMaximum(INT_MAX); - - (void)QtConcurrent::run([&, in_path, out_path, compress_info, frame_size] { - const auto progress = [&](std::size_t written, std::size_t total) { - emit UpdateProgress(written, total); - }; - bool success = - FileUtil::CompressZ3DSFile(in_path, out_path, compress_info.underlying_magic, - frame_size, progress, compress_info.default_metadata); - if (!success) { - FileUtil::Delete(out_path); + bool single_file = filepaths.size() == 1; + if (single_file) { + // If it's a single file, ask the user for the output file. + auto compress_info = GetCompressFileInfo(filepaths[0].toStdString(), true); + if (!compress_info.has_value()) { + emit CompressFinished(true, false); + return; } - emit OnCompressFinished(true, success); + + QFileInfo fileinfo(filepaths[0]); + QString final_path = + fileinfo.path() + QStringLiteral(DIR_SEP) + fileinfo.completeBaseName() + + QStringLiteral(".") + + QString::fromStdString(compress_info.value().first.recommended_compressed_extension); + + QString out_filter = tr("3DS Compressed ROM File (*.%1)") + .arg(QString::fromStdString( + compress_info.value().first.recommended_compressed_extension)); + out_path = QFileDialog::getSaveFileName(this, tr("Save 3DS Compressed ROM File"), + final_path, out_filter); + if (out_path.isEmpty()) { + return; + } + } else { + // Otherwise, ask the user the directory to output the files. + out_path = QFileDialog::getExistingDirectory( + this, tr("Select Output 3DS Compressed ROM Folder"), UISettings::values.roms_path, + QFileDialog::ShowDirsOnly); + if (out_path.isEmpty()) { + return; + } + } + + (void)QtConcurrent::run([&, filepaths, out_path] { + bool single_file = filepaths.size() == 1; + QString out_filepath; + bool total_success = true; + + for (const QString& filepath : filepaths) { + + std::string in_path = filepath.toStdString(); + + // Identify file type + auto compress_info = GetCompressFileInfo(filepath.toStdString(), true); + if (!compress_info.has_value()) { + total_success = false; + continue; + } + + if (single_file) { + out_filepath = out_path; + } else { + QFileInfo fileinfo(filepath); + out_filepath = out_path + QStringLiteral(DIR_SEP) + fileinfo.completeBaseName() + + QStringLiteral(".") + + QString::fromStdString( + compress_info.value().first.recommended_compressed_extension); + } + + std::string out_path = out_filepath.toStdString(); + + emit UpdateProgress(0, 0); + + const auto progress = [&](std::size_t written, std::size_t total) { + emit UpdateProgress(written, total); + }; + bool success = FileUtil::CompressZ3DSFile(in_path, out_path, + compress_info.value().first.underlying_magic, + compress_info.value().second, progress, + compress_info.value().first.default_metadata); + if (!success) { + total_success = false; + FileUtil::Delete(out_path); + } + } + + emit CompressFinished(true, total_success); }); } + void GMainWindow::OnDecompressFile() { - QString filepath = QFileDialog::getOpenFileName( - this, tr("Load 3DS Compressed ROM File"), UISettings::values.roms_path, + + QStringList filepaths = QFileDialog::getOpenFileNames( + this, tr("Load 3DS Compressed ROM Files"), UISettings::values.roms_path, tr("3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi)") + QStringLiteral(";;") + tr("All Files (*.*)")); - if (filepath.isEmpty()) { + QString out_path; + + if (filepaths.isEmpty()) { return; } - std::string in_path = filepath.toStdString(); - // Identify file type - Loader::AppLoader::CompressFileInfo compress_info{}; - compress_info.is_supported = false; - { - auto loader = Loader::GetLoader(in_path); - if (loader) { - compress_info = loader->GetCompressFileInfo(); - } else { - bool is_compressed = false; - if (Service::AM::CheckCIAToInstall(in_path, is_compressed, false) == - Service::AM::InstallStatus::Success) { - compress_info.is_supported = true; - compress_info.is_compressed = is_compressed; - compress_info.recommended_compressed_extension = "zcia"; - compress_info.recommended_uncompressed_extension = "cia"; - compress_info.underlying_magic = std::array({'C', 'I', 'A', '\0'}); + bool single_file = filepaths.size() == 1; + if (single_file) { + // If it's a single file, ask the user for the output file. + auto compress_info = GetCompressFileInfo(filepaths[0].toStdString(), false); + if (!compress_info.has_value()) { + emit CompressFinished(false, false); + return; + } + + QFileInfo fileinfo(filepaths[0]); + QString final_path = + fileinfo.path() + QStringLiteral(DIR_SEP) + fileinfo.completeBaseName() + + QStringLiteral(".") + + QString::fromStdString(compress_info.value().first.recommended_uncompressed_extension); + + QString out_filter = + tr("3DS ROM File (*.%1)") + .arg(QString::fromStdString( + compress_info.value().first.recommended_uncompressed_extension)); + out_path = + QFileDialog::getSaveFileName(this, tr("Save 3DS ROM File"), final_path, out_filter); + if (out_path.isEmpty()) { + return; + } + } else { + // Otherwise, ask the user the directory to output the files. + out_path = QFileDialog::getExistingDirectory(this, tr("Select Output 3DS ROM Folder"), + UISettings::values.roms_path, + QFileDialog::ShowDirsOnly); + if (out_path.isEmpty()) { + return; + } + } + + (void)QtConcurrent::run([&, filepaths, out_path] { + bool single_file = filepaths.size() == 1; + QString out_filepath; + bool total_success = true; + + for (const QString& filepath : filepaths) { + + std::string in_path = filepath.toStdString(); + + // Identify file type + auto compress_info = GetCompressFileInfo(filepath.toStdString(), false); + if (!compress_info.has_value()) { + total_success = false; + continue; + } + + if (single_file) { + out_filepath = out_path; + } else { + QFileInfo fileinfo(filepath); + out_filepath = out_path + QStringLiteral(DIR_SEP) + fileinfo.completeBaseName() + + QStringLiteral(".") + + QString::fromStdString( + compress_info.value().first.recommended_uncompressed_extension); + } + + std::string out_path = out_filepath.toStdString(); + + emit UpdateProgress(0, 0); + + const auto progress = [&](std::size_t written, std::size_t total) { + emit UpdateProgress(written, total); + }; + + // TODO(PabloMK7): What should we do with the metadata? + bool success = FileUtil::DeCompressZ3DSFile(in_path, out_path, progress); + if (!success) { + total_success = false; + FileUtil::Delete(out_path); } } - } - if (!compress_info.is_supported) { - QMessageBox::critical(this, tr("Error decompressing file"), - tr("The selected file is not a compatible compressed 3DS ROM format. " - "Make sure you have " - "chosen the right file.")); - return; - } - if (!compress_info.is_compressed) { - QMessageBox::warning(this, tr("Error decompressing file"), - tr("The selected file is already decompressed.")); - return; - } - QString out_filter = - tr("3DS ROM File (*.%1)") - .arg(QString::fromStdString(compress_info.recommended_uncompressed_extension)); - - QFileInfo fileinfo(filepath); - QString final_path = fileinfo.path() + QStringLiteral(DIR_SEP) + fileinfo.completeBaseName() + - QStringLiteral(".") + - QString::fromStdString(compress_info.recommended_uncompressed_extension); - - filepath = QFileDialog::getSaveFileName(this, tr("Save 3DS ROM File"), final_path, out_filter); - if (filepath.isEmpty()) { - return; - } - std::string out_path = filepath.toStdString(); - - progress_bar->show(); - progress_bar->setMaximum(INT_MAX); - - (void)QtConcurrent::run([&, in_path, out_path, compress_info] { - const auto progress = [&](std::size_t written, std::size_t total) { - emit UpdateProgress(written, total); - }; - // TODO(PabloMK7): What should we do with the metadata? - bool success = FileUtil::DeCompressZ3DSFile(in_path, out_path, progress); - if (!success) { - FileUtil::Delete(out_path); - } - emit OnCompressFinished(false, success); + emit CompressFinished(false, total_success); }); } @@ -3555,6 +3703,12 @@ void GMainWindow::UpdateAPIIndicator(bool update) { if (api_index == static_cast(Settings::GraphicsAPI::Vulkan)) { api_index = (api_index + 1) % graphics_apis.size(); } +#else + if (physical_devices.empty()) { + if (api_index == static_cast(Settings::GraphicsAPI::Vulkan)) { + api_index = (api_index + 1) % graphics_apis.size(); + } + } #endif Settings::values.graphics_api = static_cast(api_index); } @@ -3697,6 +3851,9 @@ void GMainWindow::closeEvent(QCloseEvent* event) { ShutdownGame(); } + // Save settings in case they were changed from outside the configuration menu. + config->Save(); + render_window->close(); secondary_window->close(); multiplayer_state->Close(); @@ -3708,8 +3865,8 @@ static bool IsSingleFileDropEvent(const QMimeData* mime) { return mime->hasUrls() && mime->urls().length() == 1; } -static const std::array AcceptedExtensions = { - "cci", "cxi", "bin", "3dsx", "app", "elf", "axf", "zcci", "zcxi", "z3dsx"}; +static const std::array AcceptedExtensions = { + "cci", "cxi", "bin", "3dsx", "app", "elf", "axf", "zcci", "zcxi", "z3dsx", "3ds"}; static bool IsCorrectFileExtension(const QMimeData* mime) { const QString& filename = mime->urls().at(0).toLocalFile(); @@ -3926,21 +4083,27 @@ void GMainWindow::OnEmulatorUpdateAvailable() { .arg(version_string)); update_prompt.exec(); if (update_prompt.button(QMessageBox::Yes) == update_prompt.clickedButton()) { - QDesktopServices::openUrl( - QUrl(QString::fromStdString("https://azahar-emu.org/pages/download/"))); + std::string update_page_url; + if (ShouldCheckForPrereleaseUpdates()) { + update_page_url = "https://github.com/azahar-emu/azahar/releases"; + } else { + update_page_url = "https://azahar-emu.org/pages/download/"; + } + QDesktopServices::openUrl(QUrl(QString::fromStdString(update_page_url))); } } #endif void GMainWindow::OnSwitchDiskResources(VideoCore::LoadCallbackStage stage, std::size_t value, - std::size_t total) { + std::size_t total, const std::string& object) { if (stage == VideoCore::LoadCallbackStage::Prepare) { loading_shaders_label->setText(QString()); loading_shaders_label->setVisible(true); } else if (stage == VideoCore::LoadCallbackStage::Complete) { loading_shaders_label->setVisible(false); } else { - loading_shaders_label->setText(loading_screen->GetStageTranslation(stage, value, total)); + loading_shaders_label->setText( + loading_screen->GetStageTranslation(stage, value, total, object)); } } @@ -4036,18 +4199,16 @@ void GMainWindow::RetranslateStatusBar() { multiplayer_state->retranslateUi(); } -void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { #ifdef USE_DISCORD_PRESENCE +void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { if (state) { discord_rpc = std::make_unique(system); } else { discord_rpc = std::make_unique(); } -#else - discord_rpc = std::make_unique(); -#endif discord_rpc->Update(); } +#endif #ifdef __unix__ void GMainWindow::SetGamemodeEnabled(bool state) { @@ -4104,8 +4265,11 @@ static Qt::HighDpiScaleFactorRoundingPolicy GetHighDpiRoundingPolicy() { #endif } -void LaunchQtFrontend(int argc, char* argv[]) { - Common::DetachedTasks detached_tasks; +int LaunchQtFrontend(int argc, char* argv[]) { +#ifdef __APPLE__ + // Ensure that the linker doesn't optimize qt_swizzle.mm out of existence. + QtSwizzle::Dummy(); +#endif #if MICROPROFILE_ENABLED MicroProfileOnThreadCreate("Frontend"); @@ -4176,6 +4340,5 @@ void LaunchQtFrontend(int argc, char* argv[]) { &GMainWindow::OnAppFocusStateChanged); int result = app.exec(); - detached_tasks.WaitForAllTasks(); - exit(result); + return result; } diff --git a/src/citra_qt/citra_qt.h b/src/citra_qt/citra_qt.h index 70e0493f3..6657bdd22 100644 --- a/src/citra_qt/citra_qt.h +++ b/src/citra_qt/citra_qt.h @@ -66,9 +66,11 @@ namespace Camera { class QtMultimediaCameraHandlerFactory; } +#ifdef USE_DISCORD_PRESENCE namespace DiscordRPC { class DiscordInterface; } +#endif namespace PlayTime { class PlayTimeManager; @@ -90,7 +92,7 @@ namespace Service::FS { enum class MediaType : u32; } -void LaunchQtFrontend(int argc, char* argv[]); +int LaunchQtFrontend(int argc, char* argv[]); class GMainWindow : public QMainWindow { Q_OBJECT @@ -107,7 +109,9 @@ public: GameList* game_list; std::unique_ptr play_time_manager; +#ifdef USE_DISCORD_PRESENCE std::unique_ptr discord_rpc; +#endif bool DropAction(QDropEvent* event); void AcceptDropEvent(QDropEvent* event); @@ -168,7 +172,9 @@ private: void BootGame(const QString& filename); void ShutdownGame(); +#ifdef USE_DISCORD_PRESENCE void SetDiscordEnabled(bool state); +#endif void LoadAmiibo(const QString& filename); /** @@ -305,7 +311,10 @@ private slots: void OnEmulatorUpdateAvailable(); #endif void OnSwitchDiskResources(VideoCore::LoadCallbackStage stage, std::size_t value, - std::size_t total); + std::size_t total, const std::string& object); +#ifdef ENABLE_DEVELOPER_OPTIONS + void StartLaunchStressTest(const QString& game_path); +#endif private: Q_INVOKABLE void OnMoviePlaybackCompleted(); @@ -435,8 +444,8 @@ private: std::shared_ptr qt_cameras; - // Prompt shown when update check succeeds #ifdef ENABLE_QT_UPDATE_CHECKER + // Prompt shown when update check succeeds QFuture update_future; QFutureWatcher update_watcher; #endif diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 041085eec..ddb4eebd6 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -371,7 +371,7 @@ void QtConfig::ReadControlValues() { const auto append_profile = [this, num_touch_from_button_maps] { Settings::InputProfile profile; profile.name = - ReadSetting(QStringLiteral("name"), QStringLiteral("default")).toString().toStdString(); + ReadSetting(QStringLiteral("name"), QStringLiteral("Default")).toString().toStdString(); for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); profile.buttons[i] = ReadSetting(QString::fromUtf8(Settings::NativeButton::mapping[i]), @@ -517,6 +517,8 @@ void QtConfig::ReadLayoutValues() { ReadGlobalSetting(Settings::values.render_3d); ReadGlobalSetting(Settings::values.factor_3d); + ReadGlobalSetting(Settings::values.swap_eyes_3d); + ReadGlobalSetting(Settings::values.render_3d_which_display); ReadGlobalSetting(Settings::values.filter_mode); ReadGlobalSetting(Settings::values.pp_shader_name); ReadGlobalSetting(Settings::values.anaglyph_shader_name); @@ -564,8 +566,13 @@ void QtConfig::ReadMiscellaneousValues() { ReadBasicSetting(Settings::values.log_filter); ReadBasicSetting(Settings::values.log_regex_filter); +#ifdef __unix__ ReadBasicSetting(Settings::values.enable_gamemode); +#endif +#ifdef ENABLE_QT_UPDATE_CHECKER ReadBasicSetting(UISettings::values.check_for_update_on_start); + ReadBasicSetting(UISettings::values.update_check_channel); +#endif qt_config->endGroup(); } @@ -668,6 +675,11 @@ void QtConfig::ReadPathValues() { ReadSetting(QStringLiteral("last_artic_base_addr"), QString{}).toString(); UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList(); UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString(); + + ReadBasicSetting(UISettings::values.inserted_cartridge); + if (!FileUtil::Exists(UISettings::values.inserted_cartridge.GetValue())) { + UISettings::values.inserted_cartridge.SetValue(""); + } } qt_config->endGroup(); @@ -685,7 +697,8 @@ void QtConfig::ReadRendererValues() { ReadGlobalSetting(Settings::values.use_hw_shader); ReadGlobalSetting(Settings::values.shaders_accurate_mul); ReadGlobalSetting(Settings::values.use_disk_shader_cache); - ReadGlobalSetting(Settings::values.use_vsync_new); + ReadGlobalSetting(Settings::values.use_vsync); + ReadGlobalSetting(Settings::values.use_display_refresh_rate_detection); ReadGlobalSetting(Settings::values.resolution_factor); ReadGlobalSetting(Settings::values.frame_limit); ReadGlobalSetting(Settings::values.turbo_limit); @@ -745,6 +758,7 @@ void QtConfig::ReadSystemValues() { ReadBasicSetting(Settings::values.steps_per_hour); ReadBasicSetting(Settings::values.plugin_loader_enabled); ReadBasicSetting(Settings::values.allow_plugin_loader); + ReadBasicSetting(Settings::values.apply_region_free_patch); } qt_config->endGroup(); @@ -802,7 +816,9 @@ void QtConfig::ReadUIValues() { UISettings::values.theme = ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second)) .toString(); +#ifdef USE_DISCORD_PRESENCE ReadBasicSetting(UISettings::values.enable_discord_presence); +#endif ReadBasicSetting(UISettings::values.screenshot_resolution_factor); ReadUILayoutValues(); @@ -837,7 +853,6 @@ void QtConfig::ReadUIGameListValues() { ReadBasicSetting(UISettings::values.game_list_row_2); ReadBasicSetting(UISettings::values.game_list_hide_no_icon); ReadBasicSetting(UISettings::values.game_list_single_line_mode); - ReadBasicSetting(UISettings::values.show_3ds_files_warning); ReadBasicSetting(UISettings::values.show_compat_column); ReadBasicSetting(UISettings::values.show_region_column); @@ -1082,6 +1097,8 @@ void QtConfig::SaveLayoutValues() { WriteGlobalSetting(Settings::values.render_3d); WriteGlobalSetting(Settings::values.factor_3d); + WriteGlobalSetting(Settings::values.swap_eyes_3d); + WriteGlobalSetting(Settings::values.render_3d_which_display); WriteGlobalSetting(Settings::values.filter_mode); WriteGlobalSetting(Settings::values.pp_shader_name); WriteGlobalSetting(Settings::values.anaglyph_shader_name); @@ -1127,9 +1144,13 @@ void QtConfig::SaveMiscellaneousValues() { WriteBasicSetting(Settings::values.log_filter); WriteBasicSetting(Settings::values.log_regex_filter); +#ifdef __unix__ WriteBasicSetting(Settings::values.enable_gamemode); +#endif +#ifdef ENABLE_QT_UPDATE_CHECKER WriteBasicSetting(UISettings::values.check_for_update_on_start); - + WriteBasicSetting(UISettings::values.update_check_channel); +#endif qt_config->endGroup(); } @@ -1199,6 +1220,7 @@ void QtConfig::SavePathValues() { UISettings::values.last_artic_base_addr, QString{}); WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files); WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{}); + WriteBasicSetting(UISettings::values.inserted_cartridge); } qt_config->endGroup(); @@ -1216,7 +1238,8 @@ void QtConfig::SaveRendererValues() { WriteGlobalSetting(Settings::values.use_hw_shader); WriteGlobalSetting(Settings::values.shaders_accurate_mul); WriteGlobalSetting(Settings::values.use_disk_shader_cache); - WriteGlobalSetting(Settings::values.use_vsync_new); + WriteGlobalSetting(Settings::values.use_vsync); + WriteGlobalSetting(Settings::values.use_display_refresh_rate_detection); WriteGlobalSetting(Settings::values.resolution_factor); WriteGlobalSetting(Settings::values.frame_limit); WriteGlobalSetting(Settings::values.turbo_limit); @@ -1276,6 +1299,7 @@ void QtConfig::SaveSystemValues() { WriteBasicSetting(Settings::values.steps_per_hour); WriteBasicSetting(Settings::values.plugin_loader_enabled); WriteBasicSetting(Settings::values.allow_plugin_loader); + WriteBasicSetting(Settings::values.apply_region_free_patch); } qt_config->endGroup(); @@ -1316,7 +1340,9 @@ void QtConfig::SaveUIValues() { if (global) { WriteSetting(QStringLiteral("theme"), UISettings::values.theme, QString::fromUtf8(UISettings::themes[0].second)); +#ifdef USE_DISCORD_PRESENCE WriteBasicSetting(UISettings::values.enable_discord_presence); +#endif WriteBasicSetting(UISettings::values.screenshot_resolution_factor); SaveUILayoutValues(); @@ -1351,7 +1377,6 @@ void QtConfig::SaveUIGameListValues() { WriteBasicSetting(UISettings::values.game_list_row_2); WriteBasicSetting(UISettings::values.game_list_hide_no_icon); WriteBasicSetting(UISettings::values.game_list_single_line_mode); - WriteBasicSetting(UISettings::values.show_3ds_files_warning); WriteBasicSetting(UISettings::values.show_compat_column); WriteBasicSetting(UISettings::values.show_region_column); diff --git a/src/citra_qt/configuration/configure_audio.ui b/src/citra_qt/configuration/configure_audio.ui index 5bf8e3b0b..706e335c0 100644 --- a/src/citra_qt/configuration/configure_audio.ui +++ b/src/citra_qt/configuration/configure_audio.ui @@ -35,7 +35,7 @@ - Emulation: + Emulation @@ -88,7 +88,7 @@ - This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. + <html><head/><body><p>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</p></body></html> Enable audio stretching @@ -98,7 +98,7 @@ - Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues. + <html><head/><body><p>Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.</p></body></html> Enable realtime audio diff --git a/src/citra_qt/configuration/configure_camera.ui b/src/citra_qt/configuration/configure_camera.ui index 07977edd4..28b40ca74 100644 --- a/src/citra_qt/configuration/configure_camera.ui +++ b/src/citra_qt/configuration/configure_camera.ui @@ -28,7 +28,7 @@ Select the camera to configure - Camera to configure: + Camera to Configure @@ -59,7 +59,7 @@ Select the camera mode (single or double) - Camera mode: + Camera mode @@ -90,7 +90,7 @@ Select the position of camera to configure - Camera position: + Camera position @@ -127,17 +127,17 @@ - Select where the image of the emulated camera comes from. It may be an image or a real camera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> - Camera Image Source: + Camera Image Source - Select where the image of the emulated camera comes from. It may be an image or a real camera. + <html><head/><body><p>Select where the image of the emulated camera comes from. It may be an image or a real camera.</p></body></html> @@ -166,7 +166,7 @@ QFrame::NoFrame - File: + File @@ -193,7 +193,7 @@ QFrame::NoFrame - Camera: + Camera @@ -234,7 +234,7 @@ QFrame::NoFrame - Flip: + Flip diff --git a/src/citra_qt/configuration/configure_enhancements.cpp b/src/citra_qt/configuration/configure_enhancements.cpp index a40654a5d..aba7a7ac8 100644 --- a/src/citra_qt/configuration/configure_enhancements.cpp +++ b/src/citra_qt/configuration/configure_enhancements.cpp @@ -57,6 +57,7 @@ void ConfigureEnhancements::SetConfiguration() { ui->render_3d_combobox->setCurrentIndex( static_cast(Settings::values.render_3d.GetValue())); + ui->swap_eyes_3d->setChecked(Settings::values.swap_eyes_3d.GetValue()); ui->factor_3d->setValue(Settings::values.factor_3d.GetValue()); ui->mono_rendering_eye->setCurrentIndex( static_cast(Settings::values.mono_render_option.GetValue())); @@ -111,6 +112,7 @@ void ConfigureEnhancements::ApplyConfiguration() { ui->resolution_factor_combobox); Settings::values.render_3d = static_cast(ui->render_3d_combobox->currentIndex()); + Settings::values.swap_eyes_3d = ui->swap_eyes_3d->isChecked(); Settings::values.factor_3d = ui->factor_3d->value(); Settings::values.mono_render_option = static_cast(ui->mono_rendering_eye->currentIndex()); diff --git a/src/citra_qt/configuration/configure_enhancements.ui b/src/citra_qt/configuration/configure_enhancements.ui index b69676d02..ebf8520c4 100644 --- a/src/citra_qt/configuration/configure_enhancements.ui +++ b/src/citra_qt/configuration/configure_enhancements.ui @@ -236,7 +236,7 @@ - Reverse Side by Side + Side by Side Full Width @@ -318,14 +318,21 @@ - - - Disable Right Eye Rendering - - - <html><head/><body><p>Disable Right Eye Rendering</p><p>Disables rendering the right eye image when not using stereoscopic mode. Greatly improves performance in some applications, but can cause flickering in others.</p></body></html> - - + + + Disable Right Eye Rendering + + + <html><head/><body><p>Disable Right Eye Rendering</p><p>Disables rendering the right eye image when not using stereoscopic mode. Greatly improves performance in some applications, but can cause flickering in others.</p></body></html> + + + + + + + Swap Eyes + + @@ -342,7 +349,7 @@ <html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html> - Use Custom Textures + Use custom textures @@ -352,7 +359,7 @@ <html><head/><body><p>Dump textures to PNG files.</p><p>Textures are dumped to dump/textures/[Title ID]/.</p></body></html> - Dump Textures + Dump textures @@ -362,7 +369,7 @@ <html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the application requires them.</p></body></html> - Preload Custom Textures + Preload custom textures @@ -372,7 +379,7 @@ <html><head/><body><p>Load custom textures asynchronously with background threads to reduce loading stutter</p></body></html> - Async Custom Texture Loading + Async custom texture loading diff --git a/src/citra_qt/configuration/configure_general.cpp b/src/citra_qt/configuration/configure_general.cpp index 9a2d58a68..ab8eb2a3c 100644 --- a/src/citra_qt/configuration/configure_general.cpp +++ b/src/citra_qt/configuration/configure_general.cpp @@ -44,7 +44,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) ui->toggle_gamemode->setVisible(false); #endif #ifndef ENABLE_QT_UPDATE_CHECKER - ui->toggle_update_checker->setVisible(false); + ui->updates_group->setVisible(false); #endif SetupPerGameUI(); @@ -90,8 +90,12 @@ void ConfigureGeneral::SetConfiguration() { ui->toggle_background_mute->setChecked( UISettings::values.mute_when_in_background.GetValue()); ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue()); +#ifdef ENABLE_QT_UPDATE_CHECKER ui->toggle_update_checker->setChecked( UISettings::values.check_for_update_on_start.GetValue()); + ui->update_channel_combobox->setCurrentIndex( + UISettings::values.update_check_channel.GetValue()); +#endif #ifdef __unix__ ui->toggle_gamemode->setChecked(Settings::values.enable_gamemode.GetValue()); #endif @@ -178,7 +182,10 @@ void ConfigureGeneral::ApplyConfiguration() { UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked(); UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); +#ifdef ENABLE_QT_UPDATE_CHECKER UISettings::values.check_for_update_on_start = ui->toggle_update_checker->isChecked(); + UISettings::values.update_check_channel = ui->update_channel_combobox->currentIndex(); +#endif #ifdef __unix__ Settings::values.enable_gamemode = ui->toggle_gamemode->isChecked(); #endif @@ -211,5 +218,5 @@ void ConfigureGeneral::SetupPerGameUI() { ui->general_group->setVisible(false); ui->button_reset_defaults->setVisible(false); ui->toggle_gamemode->setVisible(false); - ui->toggle_update_checker->setVisible(false); + ui->updates_group->setVisible(false); } diff --git a/src/citra_qt/configuration/configure_general.ui b/src/citra_qt/configuration/configure_general.ui index 741b898c3..1c4a05631 100644 --- a/src/citra_qt/configuration/configure_general.ui +++ b/src/citra_qt/configuration/configure_general.ui @@ -16,6 +16,43 @@ + + + + Updates + + + + + + Check for updates + + + + + + + Update Channel + + + + + + + + Stable + + + + + Prerelease + + + + + + + @@ -57,13 +94,6 @@ - - - - Check for updates - - - @@ -97,7 +127,7 @@ - Set emulation speed: + Set emulation speed @@ -105,7 +135,7 @@ - Emulation Speed: + Emulation Speed @@ -315,7 +345,6 @@ toggle_check_exit toggle_background_pause toggle_hide_mouse - toggle_update_checker button_reset_defaults diff --git a/src/citra_qt/configuration/configure_graphics.cpp b/src/citra_qt/configuration/configure_graphics.cpp index eb706fb56..aac27ab16 100644 --- a/src/citra_qt/configuration/configure_graphics.cpp +++ b/src/citra_qt/configuration/configure_graphics.cpp @@ -21,9 +21,10 @@ ConfigureGraphics::ConfigureGraphics(QString gl_renderer, std::spangraphics_api_combo->setEnabled(!is_powered_on); ui->physical_device_combo->setEnabled(!is_powered_on); + ui->toggle_accurate_mul->setEnabled(!is_powered_on); ui->toggle_async_shaders->setEnabled(!is_powered_on); ui->toggle_async_present->setEnabled(!is_powered_on); - ui->toggle_accurate_mul->setEnabled(!is_powered_on); + ui->toggle_display_refresh_rate_detection->setEnabled(!is_powered_on); // Set the index to -1 to ensure the below lambda is called with setCurrentIndex ui->graphics_api_combo->setCurrentIndex(-1); @@ -142,7 +143,7 @@ void ConfigureGraphics::SetConfiguration() { ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader.GetValue()); ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul.GetValue()); ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); - ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new.GetValue()); + ui->toggle_vsync->setChecked(Settings::values.use_vsync.GetValue()); ui->spirv_shader_gen->setChecked(Settings::values.spirv_shader_gen.GetValue()); ui->disable_spirv_optimizer->setChecked(Settings::values.disable_spirv_optimizer.GetValue()); ui->toggle_async_shaders->setChecked(Settings::values.async_shader_compilation.GetValue()); @@ -150,6 +151,8 @@ void ConfigureGraphics::SetConfiguration() { if (Settings::IsConfiguringGlobal()) { ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit.GetValue()); + ui->toggle_display_refresh_rate_detection->setChecked( + Settings::values.use_display_refresh_rate_detection.GetValue()); } } @@ -174,14 +177,16 @@ void ConfigureGraphics::ApplyConfiguration() { ui->texture_sampling_combobox); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache, ui->toggle_disk_shader_cache, use_disk_shader_cache); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new, - use_vsync_new); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->toggle_vsync, + use_vsync); ConfigurationShared::ApplyPerGameSetting( &Settings::values.delay_game_render_thread_us, ui->delay_render_combo, [this](s32) { return ui->delay_render_slider->value(); }); if (Settings::IsConfiguringGlobal()) { Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked(); + Settings::values.use_display_refresh_rate_detection = + ui->toggle_display_refresh_rate_detection->isChecked(); } } @@ -197,8 +202,8 @@ void ConfigureGraphics::SetupPerGameUI() { ui->toggle_accurate_mul->setEnabled(Settings::values.shaders_accurate_mul.UsingGlobal()); ui->toggle_disk_shader_cache->setEnabled( Settings::values.use_disk_shader_cache.UsingGlobal()); - ui->toggle_vsync_new->setEnabled(ui->toggle_vsync_new->isEnabled() && - Settings::values.use_vsync_new.UsingGlobal()); + ui->toggle_vsync->setEnabled(ui->toggle_vsync->isEnabled() && + Settings::values.use_vsync.UsingGlobal()); ui->toggle_async_shaders->setEnabled( Settings::values.async_shader_compilation.UsingGlobal()); ui->widget_texture_sampling->setEnabled(Settings::values.texture_sampling.UsingGlobal()); @@ -216,6 +221,7 @@ void ConfigureGraphics::SetupPerGameUI() { }); ui->toggle_shader_jit->setVisible(false); + ui->toggle_display_refresh_rate_detection->setVisible(false); ConfigurationShared::SetColoredComboBox( ui->graphics_api_combo, ui->graphics_api_group, @@ -236,8 +242,8 @@ void ConfigureGraphics::SetupPerGameUI() { ConfigurationShared::SetColoredTristate(ui->toggle_disk_shader_cache, Settings::values.use_disk_shader_cache, use_disk_shader_cache); - ConfigurationShared::SetColoredTristate(ui->toggle_vsync_new, Settings::values.use_vsync_new, - use_vsync_new); + ConfigurationShared::SetColoredTristate(ui->toggle_vsync, Settings::values.use_vsync, + use_vsync); ConfigurationShared::SetColoredTristate(ui->toggle_async_shaders, Settings::values.async_shader_compilation, async_shader_compilation); diff --git a/src/citra_qt/configuration/configure_graphics.h b/src/citra_qt/configuration/configure_graphics.h index 1031b964a..61a462a67 100644 --- a/src/citra_qt/configuration/configure_graphics.h +++ b/src/citra_qt/configuration/configure_graphics.h @@ -38,7 +38,8 @@ private: ConfigurationShared::CheckState use_hw_shader; ConfigurationShared::CheckState shaders_accurate_mul; ConfigurationShared::CheckState use_disk_shader_cache; - ConfigurationShared::CheckState use_vsync_new; + ConfigurationShared::CheckState use_vsync; + ConfigurationShared::CheckState use_display_refresh_rate_detection; ConfigurationShared::CheckState async_shader_compilation; ConfigurationShared::CheckState async_presentation; ConfigurationShared::CheckState spirv_shader_gen; diff --git a/src/citra_qt/configuration/configure_graphics.ui b/src/citra_qt/configuration/configure_graphics.ui index fea3c523d..ff5ec613f 100644 --- a/src/citra_qt/configuration/configure_graphics.ui +++ b/src/citra_qt/configuration/configure_graphics.ui @@ -132,14 +132,14 @@ - SPIR-V Shader Generation + SPIR-V shader generation - Disable GLSL -> SPIR-V Optimizer + Disable GLSL -> SPIR-V optimizer <html><head/><body><p>Disables the SPIR-V optimization pass, reducing stuttering considerably while barely affecting performance.</p></body></html> @@ -176,7 +176,7 @@ <html><head/><body><p>Use the selected graphics API to accelerate shader emulation.</p><p>Requires a relatively powerful GPU for better performance.</p></body></html> - Enable Hardware Shader + Enable hardware shader @@ -201,7 +201,7 @@ <html><head/><body><p>Correctly handle all edge cases in multiplication operation in shaders. </p><p>Some applications requires this to be enabled for the hardware shader to render properly.</p><p>However this would reduce performance in most applications.</p></body></html> - Accurate Multiplication + Accurate multiplication @@ -217,7 +217,7 @@ <html><head/><body><p>Use the JIT engine instead of the interpreter for software shader emulation. </p><p>Enable this for better performance.</p></body></html> - Enable Shader JIT + Enable shader JIT @@ -227,17 +227,17 @@ <html><head/><body><p>Compile shaders using background threads to avoid shader compilation stutter. Expect temporary graphical glitches</p></body></html> - Enable Async Shader Compilation + Enable async shader compilation - <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications.</p></body></html> + <html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.</p></body></html> - Enable Async Presentation + Enable async presentation @@ -303,20 +303,30 @@ <html><head/><body><p>Reduce stuttering by storing and loading generated shaders to disk.</p></body></html> - Use Disk Shader Cache + Use disk shader cache - + - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. + <html><head/><body><p>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</p></body></html> Enable VSync + + + + <html><head/><body><p>When enabled, this setting detects when the refresh rate of the screen is below that of the 3DS, and when it is, disables VSync automatically to avoid emulation speed being forced below 100%.</p></body></html> + + + Enable display refresh rate detection + + + @@ -349,7 +359,7 @@ - Delay application render thread: + Delay Application Render Thread <html><head/><body><p>Delays the emulated application render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic framerate applications to fix performance issues.</p></body></html> @@ -416,7 +426,7 @@ toggle_accurate_mul toggle_shader_jit toggle_disk_shader_cache - toggle_vsync_new + toggle_vsync diff --git a/src/citra_qt/configuration/configure_layout.ui b/src/citra_qt/configuration/configure_layout.ui index 128e146e3..1125ab2fb 100644 --- a/src/citra_qt/configuration/configure_layout.ui +++ b/src/citra_qt/configuration/configure_layout.ui @@ -132,14 +132,14 @@ - Swap Screens + Swap screens - Rotate Screens Upright + Rotate screens upright @@ -531,7 +531,7 @@ - <html><head/><body><p>Bottom Screen Opacity % (OpenGL Only)</p></body></html> + <html><head/><body><p>Bottom Screen Opacity %</p></body></html> diff --git a/src/citra_qt/configuration/configure_storage.ui b/src/citra_qt/configuration/configure_storage.ui index 1c8358dbc..5cfd0c449 100644 --- a/src/citra_qt/configuration/configure_storage.ui +++ b/src/citra_qt/configuration/configure_storage.ui @@ -27,7 +27,7 @@ - Use Virtual SD + Use virtual SD card @@ -42,7 +42,7 @@ - Use Custom Storage + Use custom storage location @@ -187,7 +187,7 @@ Compress installed CIA content - Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled. + <html><head/><body><p>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</p></body></html> diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp index fb9f6d7bb..9ed8bebfa 100644 --- a/src/citra_qt/configuration/configure_system.cpp +++ b/src/citra_qt/configuration/configure_system.cpp @@ -313,6 +313,8 @@ void ConfigureSystem::SetConfiguration() { ui->region_combobox->setCurrentIndex(Settings::values.region_value.GetValue() + 1); } + ui->apply_region_free_patch->setChecked(Settings::values.apply_region_free_patch.GetValue()); + ui->combo_init_clock->setCurrentIndex(static_cast(Settings::values.init_clock.GetValue())); QDateTime date_time; date_time.setSecsSinceEpoch(Settings::values.init_time.GetValue()); @@ -488,6 +490,7 @@ void ConfigureSystem::ApplyConfiguration() { Settings::values.lle_applets = ui->toggle_lle_applets->isChecked(); Settings::values.enable_required_online_lle_modules = ui->enable_required_online_lle_modules->isChecked(); + Settings::values.apply_region_free_patch.SetValue(ui->apply_region_free_patch->isChecked()); Settings::values.plugin_loader_enabled.SetValue(ui->plugin_loader->isChecked()); Settings::values.allow_plugin_loader.SetValue(ui->allow_plugin_loader->isChecked()); @@ -710,6 +713,7 @@ void ConfigureSystem::SetupPerGameUI() { } // Hide most settings for now, we can implement them later + ui->apply_region_free_patch->setVisible(false); ui->label_username->setVisible(false); ui->label_birthday->setVisible(false); ui->label_init_clock->setVisible(false); diff --git a/src/citra_qt/configuration/configure_system.ui b/src/citra_qt/configuration/configure_system.ui index 244fb3c5f..7327223d6 100644 --- a/src/citra_qt/configuration/configure_system.ui +++ b/src/citra_qt/configuration/configure_system.ui @@ -92,7 +92,7 @@ online features (if installed) - Region: + Region @@ -140,7 +140,18 @@ online features (if installed) - + + + + Apply region free patch to +installed applications. + + + Patches the region of installed applications to be region free, so that they always appear on the home menu. + + + + @@ -153,21 +164,21 @@ online features (if installed) - + Username - + Birthday - + @@ -238,14 +249,14 @@ online features (if installed) - + Language - + Note: this can be overridden when region setting is auto-select @@ -312,14 +323,14 @@ online features (if installed) - + Sound output mode - + @@ -338,31 +349,31 @@ online features (if installed) - + Country - + - + - + Clock - + @@ -376,28 +387,28 @@ online features (if installed) - + Startup time - + yyyy-MM-ddTHH:mm:ss - + Offset time - + @@ -421,14 +432,14 @@ online features (if installed) - + Initial System Ticks - + @@ -442,14 +453,14 @@ online features (if installed) - + Initial System Ticks Override - + @@ -462,21 +473,21 @@ online features (if installed) - + Play Coins - + 300 - + <html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html> @@ -486,28 +497,28 @@ online features (if installed) - + 9999 - + Run System Setup when Home Menu is launched - + Console ID: - + @@ -523,14 +534,14 @@ online features (if installed) - + MAC: - + @@ -546,21 +557,21 @@ online features (if installed) - + - 3GX Plugin Loader: + 3GX Plugin Loader - + Enable 3GX plugin loader - + Allow applications to change plugin loader state diff --git a/src/citra_qt/configuration/configure_ui.ui b/src/citra_qt/configuration/configure_ui.ui index f522a910e..f59bc171f 100644 --- a/src/citra_qt/configuration/configure_ui.ui +++ b/src/citra_qt/configuration/configure_ui.ui @@ -37,7 +37,7 @@ - Interface language: + Interface Language @@ -51,7 +51,7 @@ - Theme: + Theme @@ -78,7 +78,7 @@ - Icon Size: + Icon Size @@ -108,7 +108,7 @@ - Row 1 Text: + Row 1 Text @@ -148,7 +148,7 @@ - Row 2 Text: + Row 2 Text @@ -191,14 +191,14 @@ - Hide Titles without Icon + Hide titles without icon - Single Line Mode + Single line mode @@ -218,7 +218,7 @@ - Show Advanced Frame Time Info + Show advanced frame time info diff --git a/src/citra_qt/configuration/configure_web.cpp b/src/citra_qt/configuration/configure_web.cpp index 511a06cfe..9d83547df 100644 --- a/src/citra_qt/configuration/configure_web.cpp +++ b/src/citra_qt/configuration/configure_web.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -23,12 +23,15 @@ ConfigureWeb::ConfigureWeb(QWidget* parent) ConfigureWeb::~ConfigureWeb() = default; void ConfigureWeb::SetConfiguration() { - +#ifdef USE_DISCORD_PRESENCE ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue()); +#endif } void ConfigureWeb::ApplyConfiguration() { +#ifdef USE_DISCORD_PRESENCE UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked(); +#endif } void ConfigureWeb::RetranslateUI() { diff --git a/src/citra_qt/configuration/configure_web.h b/src/citra_qt/configuration/configure_web.h index 53f7f2b18..92eed0238 100644 --- a/src/citra_qt/configuration/configure_web.h +++ b/src/citra_qt/configuration/configure_web.h @@ -1,11 +1,10 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include -#include #include namespace Ui { diff --git a/src/citra_qt/debugger/graphics/graphics_tracing.cpp b/src/citra_qt/debugger/graphics/graphics_tracing.cpp index e78acb096..9cf54940e 100644 --- a/src/citra_qt/debugger/graphics/graphics_tracing.cpp +++ b/src/citra_qt/debugger/graphics/graphics_tracing.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -63,8 +63,8 @@ void GraphicsTracingWidget::StartRecording() { return; auto& pica = system.GPU().PicaCore(); - auto shader_binary = pica.vs_setup.program_code; - auto swizzle_data = pica.vs_setup.swizzle_data; + const auto& shader_binary = pica.vs_setup.GetProgramCode(); + const auto& swizzle_data = pica.vs_setup.GetSwizzleData(); // Encode floating point numbers to 24-bit values // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally. @@ -86,7 +86,7 @@ void GraphicsTracingWidget::StartRecording() { CiTrace::Recorder::InitialState state; - const auto copy = [&](std::vector& dest, auto& data) { + const auto copy = [&](std::vector& dest, const auto& data) { dest.resize(sizeof(data)); std::memcpy(dest.data(), std::addressof(data), sizeof(data)); }; diff --git a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp index 46f8ec5cf..e25cf7733 100644 --- a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -508,11 +508,13 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, const void* ve info.Clear(); auto& pica = system.GPU().PicaCore(); - for (auto instr : pica.vs_setup.program_code) + const auto& program_code = pica.vs_setup.GetProgramCode(); + const auto& swizzle_data = pica.vs_setup.GetSwizzleData(); + for (auto instr : program_code) info.code.push_back({instr}); int num_attributes = pica.regs.internal.vs.max_input_attribute_index + 1; - for (auto pattern : pica.vs_setup.swizzle_data) { + for (auto pattern : swizzle_data) { const nihstro::SwizzleInfo swizzle_info = {.pattern = nihstro::SwizzlePattern{pattern}}; info.swizzle_info.push_back(swizzle_info); } diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index 049f7579c..f34753ca7 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -31,8 +33,11 @@ #include "citra_qt/game_list_p.h" #include "citra_qt/game_list_worker.h" #include "citra_qt/uisettings.h" +#include "common/common_paths.h" +#include "common/file_util.h" #include "common/logging/log.h" #include "common/settings.h" +#include "core/core.h" #include "core/file_sys/archive_extsavedata.h" #include "core/file_sys/archive_source_sd_savedata.h" #include "core/hle/service/am/am.h" @@ -306,6 +311,42 @@ void GameList::OnFilterCloseClicked() { main_window->filterBarSetChecked(false); } +class CartridgeIconDelegate : public QStyledItemDelegate { +public: + using QStyledItemDelegate::QStyledItemDelegate; + + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const override { + QStyleOptionViewItem opt(option); + initStyleOption(&opt, index); + + QStyle* style = opt.widget ? opt.widget->style() : QApplication::style(); + + // Draw the default item (background, text, selection, etc.) + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); + + // Draw cartridge inserted icon + quint32 can_insert = index.data(GameListItemPath::CanInsertRole).value(); + QString game_path = index.data(GameListItemPath::FullPathRole).value(); + + bool is_inserted = can_insert && UISettings::values.inserted_cartridge.GetValue() == + game_path.toStdString(); + + if (is_inserted) { + QPixmap pixmap = QIcon::fromTheme(QStringLiteral("cartridge")).pixmap(24); + + const int margin = 12; + QSize pmSize = pixmap.size() / pixmap.devicePixelRatio(); + + QRect pmRect(opt.rect.right() - pmSize.width() - margin, + opt.rect.center().y() - pmSize.height() / 2, pmSize.width(), + pmSize.height()); + + painter->drawPixmap(pmRect, pixmap); + } + } +}; + GameList::GameList(PlayTime::PlayTimeManager& play_time_manager_, GMainWindow* parent) : QWidget{parent}, play_time_manager{play_time_manager_} { watcher = new QFileSystemWatcher(this); @@ -328,6 +369,7 @@ GameList::GameList(PlayTime::PlayTimeManager& play_time_manager_, GMainWindow* p tree_view->setEditTriggers(QHeaderView::NoEditTriggers); tree_view->setContextMenuPolicy(Qt::CustomContextMenu); tree_view->setStyleSheet(QStringLiteral("QTreeView{ border: none; }")); + tree_view->setItemDelegateForColumn(0, new CartridgeIconDelegate(tree_view)); tree_view->header()->setContextMenuPolicy(Qt::CustomContextMenu); UpdateColumnVisibility(); @@ -351,40 +393,6 @@ GameList::GameList(PlayTime::PlayTimeManager& play_time_manager_, GMainWindow* p layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); - if (UISettings::values.show_3ds_files_warning.GetValue()) { - - warning_layout = new QHBoxLayout; - deprecated_3ds_warning = new QLabel; - deprecated_3ds_warning->setText( - tr("IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting " - "and/or renaming to .cci may be necessary. Learn more.")); - deprecated_3ds_warning->setOpenExternalLinks(true); - deprecated_3ds_warning->setStyleSheet( - QString::fromStdString("color: black; font-weight: bold;")); - - warning_hide = new QPushButton(tr("Don't show again")); - warning_hide->setStyleSheet( - QString::fromStdString("color: blue; text-decoration: underline;")); - warning_hide->setFlat(true); - warning_hide->setCursor(Qt::PointingHandCursor); - - connect(warning_hide, &QPushButton::clicked, [this]() { - warning_widget->setVisible(false); - UISettings::values.show_3ds_files_warning.SetValue(false); - }); - - warning_layout->addWidget(deprecated_3ds_warning); - warning_layout->addStretch(); - warning_layout->addWidget(warning_hide); - warning_layout->setContentsMargins(3, 3, 3, 3); - warning_widget = new QWidget; - warning_widget->setStyleSheet(QString::fromStdString("background-color: khaki;")); - warning_widget->setLayout(warning_layout); - - layout->addWidget(warning_widget); - } - layout->addWidget(tree_view); layout->addWidget(search_field); setLayout(layout); @@ -533,7 +541,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { selected.data(GameListItemPath::ProgramIdRole).toULongLong(), selected.data(GameListItemPath::ExtdataIdRole).toULongLong(), static_cast( - selected.data(GameListItemPath::MediaTypeRole).toUInt())); + selected.data(GameListItemPath::MediaTypeRole).toUInt()), + selected.data(GameListItemPath::CanInsertRole).toUInt() != 0); break; case GameListItemType::CustomDir: AddPermDirPopup(context_menu, selected); @@ -599,12 +608,50 @@ void ForEachOpenGLCacheFile(u64 program_id, auto func) { QFile file{QString::fromStdString(path)}; func(file); } + const std::string path = + fmt::format("{}opengl/transferable/{:016X}.bin", + FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir), program_id); + QFile file{QString::fromStdString(path)}; + func(file); +} +#endif + +#ifdef ENABLE_VULKAN +void ForEachVulkanCacheFile(u64 program_id, auto func) { + for (const std::string_view cache_type : {"vs", "fs", "gs", "pl"}) { + const std::string path = fmt::format("{}vulkan/transferable/{:016X}_{}.vkch", + FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir), + program_id, cache_type); + QFile file{QString::fromStdString(path)}; + func(file); + } + + FileUtil::ForeachDirectoryEntry( + nullptr, + fmt::format("{}vulkan/pipeline", FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)), + [program_id, &func]([[maybe_unused]] u64* num_entries_out, const std::string& directory, + const std::string& virtual_name) { + if (virtual_name.starts_with(fmt::format("{:016X}", program_id))) { + QFile file{QString::fromStdString(directory + DIR_SEP + virtual_name)}; + func(file); + } + + return true; + }); } #endif void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QString& name, - u64 program_id, u64 extdata_id, Service::FS::MediaType media_type) { + u64 program_id, u64 extdata_id, Service::FS::MediaType media_type, + bool can_insert) { QAction* favorite = context_menu.addAction(tr("Favorite")); + bool is_inserted = + can_insert && UISettings::values.inserted_cartridge.GetValue() == path.toStdString(); + QAction* cartridge_insert = nullptr; + if (can_insert) { + cartridge_insert = + context_menu.addAction(is_inserted ? tr("Eject Cartridge") : tr("Insert Cartridge")); + } context_menu.addSeparator(); QMenu* open_menu = context_menu.addMenu(tr("Open")); QAction* open_application_location = open_menu->addAction(tr("Application Location")); @@ -627,6 +674,10 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr QAction* delete_opengl_disk_shader_cache = shader_menu->addAction(tr("Delete OpenGL Shader Cache")); #endif +#ifdef ENABLE_VULKAN + QAction* delete_vulkan_disk_shader_cache = + shader_menu->addAction(tr("Delete Vulkan Shader Cache")); +#endif QMenu* uninstall_menu = context_menu.addMenu(tr("Uninstall")); QAction* uninstall_all = uninstall_menu->addAction(tr("Everything")); @@ -644,6 +695,11 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr shortcut_menu->addAction(tr("Add to Applications Menu")); #endif +#ifdef ENABLE_DEVELOPER_OPTIONS + context_menu.addSeparator(); + QAction* stress_test_launch = context_menu.addAction(tr("Stress Test: App Launch")); +#endif + context_menu.addSeparator(); QAction* properties = context_menu.addAction(tr("Properties")); @@ -658,6 +714,12 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr program_id, [&opengl_cache_exists](QFile& file) { opengl_cache_exists |= file.exists(); }); #endif +#ifdef ENABLE_VULKAN + bool vulkan_cache_exists = false; + ForEachVulkanCacheFile( + program_id, [&vulkan_cache_exists](QFile& file) { vulkan_cache_exists |= file.exists(); }); +#endif + favorite->setVisible(program_id != 0); favorite->setCheckable(true); favorite->setChecked(UISettings::values.favorited_ids.contains(program_id)); @@ -701,6 +763,10 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr delete_opengl_disk_shader_cache->setEnabled(opengl_cache_exists); #endif +#ifdef ENABLE_VULKAN + delete_vulkan_disk_shader_cache->setEnabled(vulkan_cache_exists); +#endif + uninstall_all->setEnabled(is_installed || has_update || has_dlc); uninstall_game->setEnabled(is_installed); uninstall_update->setEnabled(has_update); @@ -713,6 +779,16 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr connect(open_extdata_location, &QAction::triggered, this, [this, extdata_id] { emit OpenFolderRequested(extdata_id, GameListOpenTarget::EXT_DATA); }); + if (cartridge_insert) { + connect(cartridge_insert, &QAction::triggered, this, [this, path, is_inserted] { + if (is_inserted) { + UISettings::values.inserted_cartridge.SetValue(""); + } else { + UISettings::values.inserted_cartridge.SetValue(path.toStdString()); + } + tree_view->viewport()->update(); + }); + } connect(open_application_location, &QAction::triggered, this, [this, program_id] { emit OpenFolderRequested(program_id, GameListOpenTarget::APPLICATION); }); @@ -755,6 +831,10 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr [this, path, program_id] { emit DumpRomFSRequested(path, program_id); }); connect(remove_play_time_data, &QAction::triggered, [this, program_id]() { emit RemovePlayTimeRequested(program_id); }); +#ifdef ENABLE_DEVELOPER_OPTIONS + connect(stress_test_launch, &QAction::triggered, + [this, path]() { emit StartingLaunchStressTest(path); }); +#endif connect(properties, &QAction::triggered, this, [this, path]() { emit OpenPerGameGeneralRequested(path); }); connect(open_shader_cache_location, &QAction::triggered, this, [this, program_id] { @@ -766,6 +846,11 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr connect(delete_opengl_disk_shader_cache, &QAction::triggered, this, [program_id] { ForEachOpenGLCacheFile(program_id, [](QFile& file) { file.remove(); }); }); +#endif +#ifdef ENABLE_VULKAN + connect(delete_vulkan_disk_shader_cache, &QAction::triggered, this, [program_id] { + ForEachVulkanCacheFile(program_id, [](QFile& file) { file.remove(); }); + }); #endif connect(uninstall_all, &QAction::triggered, this, [=, this] { QMessageBox::StandardButton answer = QMessageBox::question( @@ -1039,12 +1124,27 @@ void GameList::LoadInterfaceLayout() { } const QStringList GameList::supported_file_extensions = { - QStringLiteral("3dsx"), QStringLiteral("elf"), QStringLiteral("axf"), - QStringLiteral("cci"), QStringLiteral("cxi"), QStringLiteral("app"), - QStringLiteral("z3dsx"), QStringLiteral("zcci"), QStringLiteral("zcxi"), + QStringLiteral("3dsx"), QStringLiteral("elf"), QStringLiteral("axf"), QStringLiteral("cci"), + QStringLiteral("cxi"), QStringLiteral("app"), QStringLiteral("z3dsx"), QStringLiteral("zcci"), + QStringLiteral("zcxi"), QStringLiteral("3ds"), }; void GameList::RefreshGameDirectory() { + // Do not scan directories when the system is powered on, it will be + // repopulated on shutdown anyways. + if (Core::System::GetInstance().IsPoweredOn()) { + return; + } + + const auto time_now = std::chrono::steady_clock::now(); + + // Max of 1 refresh every 1 second. + if (time_last_refresh + std::chrono::seconds(1) > time_now) { + return; + } + + time_last_refresh = time_now; + if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) { LOG_INFO(Frontend, "Change detected in the applications directory. Reloading game list."); PopulateAsync(UISettings::values.game_dirs); diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h index 92556bc04..25348d86b 100644 --- a/src/citra_qt/game_list.h +++ b/src/citra_qt/game_list.h @@ -107,6 +107,9 @@ signals: void AddDirectory(); void ShowList(bool show); void PopulatingCompleted(); +#ifdef ENABLE_DEVELOPER_OPTIONS + void StartingLaunchStressTest(const QString& game_path); +#endif private slots: void OnItemExpanded(const QModelIndex& item); @@ -123,7 +126,7 @@ private: void PopupContextMenu(const QPoint& menu_location); void PopupHeaderContextMenu(const QPoint& menu_location); void AddGamePopup(QMenu& context_menu, const QString& path, const QString& name, u64 program_id, - u64 extdata_id, Service::FS::MediaType media_type); + u64 extdata_id, Service::FS::MediaType media_type, bool can_insert); void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected); void AddPermDirPopup(QMenu& context_menu, QModelIndex selected); void AddFavoritesPopup(QMenu& context_menu); @@ -134,10 +137,6 @@ private: void changeEvent(QEvent*) override; void RetranslateUI(); - QHBoxLayout* warning_layout = nullptr; - QWidget* warning_widget = nullptr; - QLabel* deprecated_3ds_warning = nullptr; - QPushButton* warning_hide = nullptr; GameListSearchField* search_field; GMainWindow* main_window = nullptr; QVBoxLayout* layout = nullptr; @@ -150,6 +149,8 @@ private: friend class GameListSearchField; const PlayTime::PlayTimeManager& play_time_manager; + + std::chrono::time_point time_last_refresh; }; class GameListPlaceholder : public QWidget { diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h index 046ec7267..45df2a483 100644 --- a/src/citra_qt/game_list_p.h +++ b/src/citra_qt/game_list_p.h @@ -159,15 +159,18 @@ public: static constexpr int ExtdataIdRole = SortRole + 4; static constexpr int LongTitleRole = SortRole + 5; static constexpr int MediaTypeRole = SortRole + 6; + static constexpr int CanInsertRole = SortRole + 7; GameListItemPath() = default; GameListItemPath(const QString& game_path, std::span smdh_data, u64 program_id, - u64 extdata_id, Service::FS::MediaType media_type, bool is_encrypted) { + u64 extdata_id, Service::FS::MediaType media_type, bool is_encrypted, + bool can_insert) { setData(type(), TypeRole); setData(game_path, FullPathRole); setData(qulonglong(program_id), ProgramIdRole); setData(qulonglong(extdata_id), ExtdataIdRole); setData(quint32(media_type), MediaTypeRole); + setData(quint32(can_insert), CanInsertRole); if (UISettings::values.game_list_icon_size.GetValue() == UISettings::GameListIconSize::NoIcon) { diff --git a/src/citra_qt/game_list_worker.cpp b/src/citra_qt/game_list_worker.cpp index b6376261f..cc65b5082 100644 --- a/src/citra_qt/game_list_worker.cpp +++ b/src/citra_qt/game_list_worker.cpp @@ -92,7 +92,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign if (Loader::IsValidSMDH(smdh)) { if (system_title) { auto smdh_struct = reinterpret_cast(smdh.data()); - if (!(smdh_struct->flags & Loader::SMDH::Flags::Visible)) { + if (!smdh_struct->flags.visible) { // Skip system titles without the visible flag. return true; } @@ -113,7 +113,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign { new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id, extdata_id, media_type, - res == Loader::ResultStatus::ErrorEncrypted), + res == Loader::ResultStatus::ErrorEncrypted, + loader->GetFileType() == Loader::FileType::CCI), new GameListItemCompat(compatibility), new GameListItemRegion(smdh), new GameListItem(QString::fromStdString(Loader::GetFileTypeString( diff --git a/src/citra_qt/loading_screen.cpp b/src/citra_qt/loading_screen.cpp index ba2fdcaa6..84db1bb74 100644 --- a/src/citra_qt/loading_screen.cpp +++ b/src/citra_qt/loading_screen.cpp @@ -68,8 +68,7 @@ const static std::unordered_map stage QT_TRANSLATE_NOOP("LoadingScreen", "Preloading Textures %1 / %2")}, {VideoCore::LoadCallbackStage::Decompile, QT_TRANSLATE_NOOP("LoadingScreen", "Preparing Shaders %1 / %2")}, - {VideoCore::LoadCallbackStage::Build, - QT_TRANSLATE_NOOP("LoadingScreen", "Loading Shaders %1 / %2")}, + {VideoCore::LoadCallbackStage::Build, QT_TRANSLATE_NOOP("LoadingScreen", "Loading %3 %1 / %2")}, {VideoCore::LoadCallbackStage::Complete, QT_TRANSLATE_NOOP("LoadingScreen", "Launching...")}, }; const static std::unordered_map progressbar_style{ @@ -131,7 +130,7 @@ void LoadingScreen::Prepare(Loader::AppLoader& loader) { } ui->title->setText(tr("Now Loading\n%1").arg(QString::fromStdString(title))); eta_shown = false; - OnLoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); + OnLoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0, ""); } void LoadingScreen::OnLoadComplete() { @@ -139,7 +138,7 @@ void LoadingScreen::OnLoadComplete() { } void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, - std::size_t total) { + std::size_t total, const std::string& object) { using namespace std::chrono; const auto now = high_resolution_clock::now(); // reset the timer if the stage changes @@ -184,7 +183,7 @@ void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size } // update labels and progress bar - ui->stage->setText(GetStageTranslation(stage, value, total)); + ui->stage->setText(GetStageTranslation(stage, value, total, object)); ui->value->setText(estimate); ui->progress_bar->setValue(static_cast(value)); previous_time = now; @@ -199,11 +198,12 @@ void LoadingScreen::paintEvent(QPaintEvent* event) { } QString LoadingScreen::GetStageTranslation(VideoCore::LoadCallbackStage stage, std::size_t value, - std::size_t total) { + std::size_t total, const std::string& object) { const auto& stg = tr(stage_translations.at(stage)); - if (stage == VideoCore::LoadCallbackStage::Decompile || - stage == VideoCore::LoadCallbackStage::Build || - stage == VideoCore::LoadCallbackStage::Preload) { + if (stage == VideoCore::LoadCallbackStage::Build) { + return stg.arg(value).arg(total).arg(QString::fromStdString(object)); + } else if (stage == VideoCore::LoadCallbackStage::Decompile || + stage == VideoCore::LoadCallbackStage::Preload) { return stg.arg(value).arg(total); } else { return stg; diff --git a/src/citra_qt/loading_screen.h b/src/citra_qt/loading_screen.h index a6bfc7d09..ad4fc5298 100644 --- a/src/citra_qt/loading_screen.h +++ b/src/citra_qt/loading_screen.h @@ -40,7 +40,8 @@ public: void Clear(); /// Slot used to update the status of the progress bar - void OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); + void OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total, + const std::string& object); /// Hides the LoadingScreen with a fade out effect void OnLoadComplete(); @@ -50,10 +51,11 @@ public: void paintEvent(QPaintEvent* event) override; QString GetStageTranslation(VideoCore::LoadCallbackStage stage, std::size_t value, - std::size_t total); + std::size_t total, const std::string& object = ""); signals: - void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); + void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total, + const std::string& object); /// Signals that this widget is completely hidden now and should be replaced with the other /// widget void Hidden(); diff --git a/src/citra_qt/multiplayer/direct_connect.cpp b/src/citra_qt/multiplayer/direct_connect.cpp index c77aac36f..f1e29b145 100644 --- a/src/citra_qt/multiplayer/direct_connect.cpp +++ b/src/citra_qt/multiplayer/direct_connect.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -90,7 +90,8 @@ void DirectConnectWindow::Connect() { room_member->Join(ui->nickname->text().toStdString(), Service::CFG::GetConsoleIdHash(system), ui->ip->text().toStdString().c_str(), port, 0, - Network::NoPreferredMac, ui->password->text().toStdString().c_str()); + Service::CFG::GetConsoleMacAddress(system), + ui->password->text().toStdString().c_str()); } }); watcher->setFuture(f); diff --git a/src/citra_qt/multiplayer/host_room.cpp b/src/citra_qt/multiplayer/host_room.cpp index 5f29eed2d..53de0071c 100644 --- a/src/citra_qt/multiplayer/host_room.cpp +++ b/src/citra_qt/multiplayer/host_room.cpp @@ -193,8 +193,8 @@ void HostRoomWindow::Host() { } #endif member->Join(ui->username->text().toStdString(), Service::CFG::GetConsoleIdHash(system), - "127.0.0.1", static_cast(port), 0, Network::NoPreferredMac, password, - token); + "127.0.0.1", static_cast(port), 0, + Service::CFG::GetConsoleMacAddress(system), password, token); // Store settings UISettings::values.room_nickname = ui->username->text(); diff --git a/src/citra_qt/multiplayer/lobby.cpp b/src/citra_qt/multiplayer/lobby.cpp index 7a7f032c1..c18c8eefd 100644 --- a/src/citra_qt/multiplayer/lobby.cpp +++ b/src/citra_qt/multiplayer/lobby.cpp @@ -175,7 +175,8 @@ void Lobby::OnJoinRoom(const QModelIndex& source) { #endif if (auto room_member = Network::GetRoomMember().lock()) { room_member->Join(nickname, Service::CFG::GetConsoleIdHash(system), ip.c_str(), - static_cast(port), 0, Network::NoPreferredMac, password, token); + static_cast(port), 0, Service::CFG::GetConsoleMacAddress(system), + password, token); } }); watcher->setFuture(f); diff --git a/src/citra_qt/qt_swizzle.h b/src/citra_qt/qt_swizzle.h new file mode 100644 index 000000000..25c396b79 --- /dev/null +++ b/src/citra_qt/qt_swizzle.h @@ -0,0 +1,9 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +namespace QtSwizzle { + +void Dummy(); + +} // namespace QtSwizzle diff --git a/src/citra_qt/qt_swizzle.mm b/src/citra_qt/qt_swizzle.mm new file mode 100644 index 000000000..46acdad8f --- /dev/null +++ b/src/citra_qt/qt_swizzle.mm @@ -0,0 +1,48 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#import +#import + +namespace QtSwizzle { + +void Dummy() { + // Call this anywhere to make sure that qt_swizzle.mm is linked. + // noop +} + +} // namespace QtSwizzle + +@implementation QMetalLayer (AzaharPatch) + ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class targetClass = [self class]; + + // Get the original and swizzled methods + Method originalMethod = + class_getInstanceMethod(targetClass, @selector(setNeedsDisplayInRect:)); + Method swizzledMethod = + class_getInstanceMethod(targetClass, @selector(swizzled_setNeedsDisplayInRect:)); + + // Swap the implementations + method_exchangeImplementations(originalMethod, swizzledMethod); + }); +} + +- (void)swizzled_setNeedsDisplayInRect:(CGRect)rect { + constexpr auto tooBig = 1e10; // Arbitrary large number + + // Check for problematic huge rectangles + if ((!self.needsDisplay) && (rect.size.width > tooBig || rect.size.height > tooBig || + rect.origin.x < -tooBig || rect.origin.y < -tooBig)) { + return; + } + + // Call the original implementation + [self swizzled_setNeedsDisplayInRect:rect]; +} + +@end \ No newline at end of file diff --git a/src/citra_qt/uisettings.h b/src/citra_qt/uisettings.h index 393e20dd4..ef87b3fe3 100644 --- a/src/citra_qt/uisettings.h +++ b/src/citra_qt/uisettings.h @@ -59,6 +59,12 @@ enum class GameListText : s32 { ListEnd, ///< Keep this at the end of the enum. }; +class UpdateCheckChannels { +public: + static constexpr int STABLE = 0; + static constexpr int PRERELEASE = 1; +}; + struct Values { QByteArray geometry; QByteArray state; @@ -83,10 +89,18 @@ struct Values { Settings::Setting pause_when_in_background{false, "pauseWhenInBackground"}; Settings::Setting mute_when_in_background{false, "muteWhenInBackground"}; Settings::Setting hide_mouse{false, "hideInactiveMouse"}; +#ifdef ENABLE_QT_UPDATE_CHECKER Settings::Setting check_for_update_on_start{true, "check_for_update_on_start"}; + Settings::Setting update_check_channel{UpdateCheckChannels::STABLE, + "update_check_channel"}; +#endif + Settings::Setting inserted_cartridge{"", "inserted_cartridge"}; + +#ifdef USE_DISCORD_PRESENCE // Discord RPC Settings::Setting enable_discord_presence{true, "enable_discord_presence"}; +#endif // Game List Settings::Setting game_list_icon_size{GameListIconSize::LargeIcon, @@ -95,7 +109,6 @@ struct Values { Settings::Setting game_list_row_2{GameListText::FileName, "row2"}; Settings::Setting game_list_hide_no_icon{false, "hideNoIcon"}; Settings::Setting game_list_single_line_mode{false, "singleLineMode"}; - Settings::Setting show_3ds_files_warning{true, "show_3ds_files_warning"}; // Compatibility List Settings::Setting show_compat_column{true, "show_compat_column"}; diff --git a/src/citra_room/citra_room.cpp b/src/citra_room/citra_room.cpp index 2ad2e61f5..30017f4dd 100644 --- a/src/citra_room/citra_room.cpp +++ b/src/citra_room/citra_room.cpp @@ -19,7 +19,6 @@ #include "common/common_paths.h" #include "common/common_types.h" -#include "common/detached_tasks.h" #include "common/file_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" @@ -160,8 +159,7 @@ static void InitializeLogging(const std::string& log_file) { } /// Application entry point -void LaunchRoom(int argc, char** argv, bool called_by_option) { - Common::DetachedTasks detached_tasks; +int LaunchRoom(int argc, char** argv, bool called_by_option) { int option_index = 0; char* endarg; @@ -251,20 +249,20 @@ void LaunchRoom(int argc, char** argv, bool called_by_option) { break; case 'h': PrintHelp(argv[0]); - exit(0); + return 0; case 'v': PrintVersion(); - exit(0); + return 0; case 'e': PrintRemovedOptionWarning(argv[0], "--enable-citra-mods/-e"); - exit(255); + return 255; case 'g': PrintRemovedOptionWarning(argv[0], "--preferred-game/-g"); - exit(255); + return 255; case 0: if (strcmp(long_options[option_index].name, "preferred-game-id") == 0) { PrintRemovedOptionWarning(argv[0], "--preferred-game-id"); - exit(255); + return 255; } } } @@ -273,12 +271,12 @@ void LaunchRoom(int argc, char** argv, bool called_by_option) { if (room_name.empty()) { std::cout << "room name is empty!\n\n"; PrintHelp(argv[0]); - exit(-1); + return -1; } if (preferred_game.empty()) { std::cout << "preferred application is empty!\n\n"; PrintHelp(argv[0]); - exit(-1); + return -1; } if (preferred_game_id == 0) { std::cout @@ -289,12 +287,12 @@ void LaunchRoom(int argc, char** argv, bool called_by_option) { std::cout << "max_members needs to be in the range 2 - " << Network::MaxConcurrentConnections << "!\n\n"; PrintHelp(argv[0]); - exit(-1); + return -1; } if (port > 65535) { std::cout << "port needs to be in the range 0 - 65535!\n\n"; PrintHelp(argv[0]); - exit(-1); + return -1; } if (ban_list_file.empty()) { std::cout << "Ban list file not set!\nThis should get set to load and save room ban " @@ -351,7 +349,7 @@ void LaunchRoom(int argc, char** argv, bool called_by_option) { if (!room->Create(room_name, room_description, "", port, password, max_members, username, preferred_game, preferred_game_id, std::move(verify_backend), ban_list)) { std::cout << "Failed to create room: \n\n"; - exit(-1); + return -1; } std::cout << "Room is open. Close with Q+Enter...\n\n"; auto announce_session = std::make_unique(); @@ -377,5 +375,5 @@ void LaunchRoom(int argc, char** argv, bool called_by_option) { room->Destroy(); } Network::Shutdown(); - detached_tasks.WaitForAllTasks(); + return 0; } diff --git a/src/citra_room/citra_room.h b/src/citra_room/citra_room.h index 3d9b8749c..6a9549622 100644 --- a/src/citra_room/citra_room.h +++ b/src/citra_room/citra_room.h @@ -4,4 +4,4 @@ #pragma once -void LaunchRoom(int argc, char** argv, bool called_by_option); +int LaunchRoom(int argc, char** argv, bool called_by_option); diff --git a/src/citra_room_standalone/citra_room_standalone.cpp b/src/citra_room_standalone/citra_room_standalone.cpp index d06e53e0a..7c51676d9 100644 --- a/src/citra_room_standalone/citra_room_standalone.cpp +++ b/src/citra_room_standalone/citra_room_standalone.cpp @@ -3,7 +3,12 @@ // Refer to the license.txt file included. #include "citra_room/citra_room.h" +#include "common/detached_tasks.h" +#include "common/scope_exit.h" int main(int argc, char* argv[]) { + Common::DetachedTasks detached_tasks; + SCOPE_EXIT({ detached_tasks.WaitForAllTasks(); }); + LaunchRoom(argc, argv, false); } diff --git a/src/citra_sdl/citra_sdl.cpp b/src/citra_sdl/citra_sdl.cpp index 48009a5a2..9c0f4470a 100644 --- a/src/citra_sdl/citra_sdl.cpp +++ b/src/citra_sdl/citra_sdl.cpp @@ -25,7 +25,6 @@ #include "SDL_messagebox.h" #include "citra_meta/common_strings.h" #include "common/common_paths.h" -#include "common/detached_tasks.h" #include "common/file_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" @@ -171,11 +170,10 @@ static void OnStatusMessageReceived(const Network::StatusMessageEntry& msg) { } /// Application entry point -void LaunchSdlFrontend(int argc, char** argv) { +int LaunchSdlFrontend(int argc, char** argv) { Common::Log::Initialize(); Common::Log::SetColorConsoleBackendEnabled(true); Common::Log::Start(); - Common::DetachedTasks detached_tasks; SdlConfig config; int option_index = 0; bool use_gdbstub = Settings::values.use_gdbstub.GetValue(); @@ -192,7 +190,7 @@ void LaunchSdlFrontend(int argc, char** argv) { if (argv_w == nullptr) { LOG_CRITICAL(Frontend, "Failed to get command line arguments"); - exit(-1); + return -1; } #endif std::string filepath; @@ -238,12 +236,12 @@ void LaunchSdlFrontend(int argc, char** argv) { errno = EINVAL; if (errno != 0) { perror("--gdbport"); - exit(1); + return 1; } break; case 'h': PrintHelp(argv[0]); - exit(0); + return 0; case 'i': { const auto cia_progress = [](std::size_t written, std::size_t total) { LOG_INFO(Frontend, "{:02d}%", (written * 100 / total)); @@ -252,7 +250,7 @@ void LaunchSdlFrontend(int argc, char** argv) { Service::AM::InstallStatus::Success) errno = EINVAL; if (errno != 0) - exit(1); + return 1; break; } case 'p': @@ -273,7 +271,7 @@ void LaunchSdlFrontend(int argc, char** argv) { if (!std::regex_match(str_arg, re)) { std::cout << "Wrong format for option --multiplayer\n"; PrintHelp(argv[0]); - exit(0); + return 0; } std::smatch match; @@ -288,11 +286,11 @@ void LaunchSdlFrontend(int argc, char** argv) { if (!std::regex_match(nickname, nickname_re)) { std::cout << "Nickname is not valid. Must be 4 to 20 alphanumeric characters.\n"; - exit(0); + return 0; } if (address.empty()) { std::cout << "Address to room must not be empty.\n"; - exit(0); + return 0; } break; } @@ -300,7 +298,7 @@ void LaunchSdlFrontend(int argc, char** argv) { const std::string version_string = std::string("Azahar ") + Common::g_build_fullname; ShowCommandOutput("Version", version_string); - exit(0); + return 0; } } else { #ifdef _WIN32 @@ -321,12 +319,12 @@ void LaunchSdlFrontend(int argc, char** argv) { if (filepath.empty()) { LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); - exit(-1); + return -1; } if (!movie_record.empty() && !movie_play.empty()) { LOG_CRITICAL(Frontend, "Cannot both play and record a movie"); - exit(-1); + return -1; } auto& system = Core::System::GetInstance(); @@ -401,10 +399,10 @@ void LaunchSdlFrontend(int argc, char** argv) { switch (load_result) { case Core::System::ResultStatus::ErrorGetLoader: LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath); - exit(-1); + return -1; case Core::System::ResultStatus::ErrorLoader: LOG_CRITICAL(Frontend, "Failed to load ROM!"); - exit(-1); + return -1; case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: LOG_CRITICAL(Frontend, "The application that you are trying to load must be decrypted before " @@ -412,16 +410,16 @@ void LaunchSdlFrontend(int argc, char** argv) { "decrypting applications, please refer to: " "https://web.archive.org/web/20240304210021/https://citra-emu.org/" "wiki/dumping-game-cartridges/"); - exit(-1); + return -1; case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported."); - exit(-1); + return -1; case Core::System::ResultStatus::ErrorNotInitialized: LOG_CRITICAL(Frontend, "CPUCore not initialized"); - exit(-1); + return -1; case Core::System::ResultStatus::ErrorSystemMode: LOG_CRITICAL(Frontend, "Failed to determine system mode!"); - exit(-1); + return -1; case Core::System::ResultStatus::Success: break; // Expected case default: @@ -441,7 +439,7 @@ void LaunchSdlFrontend(int argc, char** argv) { Network::NoPreferredMac, password); } else { LOG_ERROR(Network, "Could not access RoomMember"); - exit(0); + return 0; } } @@ -476,6 +474,10 @@ void LaunchSdlFrontend(int argc, char** argv) { } }); + u64 program_id{}; + system.GetAppLoader().ReadProgramId(program_id); + system.GPU().ApplyPerProgramSettings(program_id); + std::atomic_bool stop_run; system.GPU().Renderer().Rasterizer()->LoadDefaultDiskResources( stop_run, [](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { @@ -524,6 +526,5 @@ void LaunchSdlFrontend(int argc, char** argv) { Common::Linux::StopGamemode(); #endif - detached_tasks.WaitForAllTasks(); - exit(0); + return 0; } diff --git a/src/citra_sdl/citra_sdl.h b/src/citra_sdl/citra_sdl.h index ba4b90ce0..9a1a2b6c3 100644 --- a/src/citra_sdl/citra_sdl.h +++ b/src/citra_sdl/citra_sdl.h @@ -1,7 +1,7 @@ -// Copyright Citra Emulator Project / Lime3DS Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once -void LaunchSdlFrontend(int argc, char** argv); +int LaunchSdlFrontend(int argc, char** argv); diff --git a/src/citra_sdl/config.cpp b/src/citra_sdl/config.cpp index da800cc30..a504dd3aa 100644 --- a/src/citra_sdl/config.cpp +++ b/src/citra_sdl/config.cpp @@ -145,7 +145,7 @@ void SdlConfig::ReadValues() { ReadSetting("Renderer", Settings::values.resolution_factor); ReadSetting("Renderer", Settings::values.use_disk_shader_cache); ReadSetting("Renderer", Settings::values.frame_limit); - ReadSetting("Renderer", Settings::values.use_vsync_new); + ReadSetting("Renderer", Settings::values.use_vsync); ReadSetting("Renderer", Settings::values.texture_filter); ReadSetting("Renderer", Settings::values.texture_sampling); ReadSetting("Renderer", Settings::values.delay_game_render_thread_us); @@ -253,6 +253,7 @@ void SdlConfig::ReadValues() { ReadSetting("System", Settings::values.plugin_loader_enabled); ReadSetting("System", Settings::values.allow_plugin_loader); ReadSetting("System", Settings::values.steps_per_hour); + ReadSetting("System", Settings::values.apply_region_free_patch); { constexpr const char* default_init_time_offset = "0 00:00:00"; diff --git a/src/citra_sdl/default_ini.h b/src/citra_sdl/default_ini.h index 358740243..4c97dbb89 100644 --- a/src/citra_sdl/default_ini.h +++ b/src/citra_sdl/default_ini.h @@ -121,7 +121,7 @@ use_shader_jit = # Forces VSync on the display thread. Usually doesn't impact performance, but on some drivers it can # so only turn this off if you notice a speed difference. # 0: Off, 1 (default): On -use_vsync_new = +use_vsync = # Reduce stuttering by storing and loading generated shaders to disk # 0: Off, 1 (default. On) @@ -163,6 +163,10 @@ render_3d = # 0 - 100: Intensity. 0 (default) factor_3d = +# Swap Eyes in 3D +# true or false (default) +swap_eyes_3d = + # Change Default Eye to Render When in Monoscopic Mode # 0 (default): Left, 1: Right mono_render_option = diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 44f0a67dc..6bb14fc9e 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -19,6 +19,10 @@ add_custom_command(OUTPUT scm_rev.cpp "${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h" "${VIDEO_CORE}/renderer_opengl/gl_shader_util.cpp" "${VIDEO_CORE}/renderer_opengl/gl_shader_util.h" + "${VIDEO_CORE}/renderer_vulkan/vk_shader_disk_cache.cpp" + "${VIDEO_CORE}/renderer_vulkan/vk_shader_disk_cache.h" + "${VIDEO_CORE}/renderer_vulkan/vk_pipeline_cache.cpp" + "${VIDEO_CORE}/renderer_vulkan/vk_pipeline_cache.h" "${VIDEO_CORE}/renderer_vulkan/vk_shader_util.cpp" "${VIDEO_CORE}/renderer_vulkan/vk_shader_util.h" "${VIDEO_CORE}/shader/generator/glsl_fs_shader_gen.cpp" @@ -29,6 +33,7 @@ add_custom_command(OUTPUT scm_rev.cpp "${VIDEO_CORE}/shader/generator/glsl_shader_gen.h" "${VIDEO_CORE}/shader/generator/pica_fs_config.cpp" "${VIDEO_CORE}/shader/generator/pica_fs_config.h" + "${VIDEO_CORE}/shader/generator/profile.h" "${VIDEO_CORE}/shader/generator/shader_gen.cpp" "${VIDEO_CORE}/shader/generator/shader_gen.h" "${VIDEO_CORE}/shader/generator/shader_uniforms.cpp" @@ -68,6 +73,7 @@ add_library(citra_common STATIC detached_tasks.cpp detached_tasks.h bit_field.h + bit_field.natvis bit_set.h bounded_threadsafe_queue.h cityhash.cpp @@ -216,3 +222,5 @@ if (SSE42_COMPILE_OPTION) target_compile_definitions(citra_common PRIVATE CITRA_HAS_SSE42) target_compile_options(citra_common PRIVATE ${SSE42_COMPILE_OPTION}) endif() + +target_link_libraries(citra_common PUBLIC xxHash::xxhash) \ No newline at end of file diff --git a/src/common/android_storage.cpp b/src/common/android_storage.cpp index a18ecefac..00648aa7d 100644 --- a/src/common/android_storage.cpp +++ b/src/common/android_storage.cpp @@ -1,9 +1,13 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #ifdef ANDROID +#include +#include #include "common/android_storage.h" +#include "common/file_util.h" +#include "common/logging/log.h" namespace AndroidStorage { JNIEnv* GetEnvForThread() { @@ -80,8 +84,9 @@ void CleanupJNI() { } bool CreateFile(const std::string& directory, const std::string& filename) { - if (create_file == nullptr) + if (create_file == nullptr) { return false; + } auto env = GetEnvForThread(); jstring j_directory = env->NewStringUTF(directory.c_str()); jstring j_filename = env->NewStringUTF(filename.c_str()); @@ -89,8 +94,9 @@ bool CreateFile(const std::string& directory, const std::string& filename) { } bool CreateDir(const std::string& directory, const std::string& filename) { - if (create_dir == nullptr) + if (create_dir == nullptr) { return false; + } auto env = GetEnvForThread(); jstring j_directory = env->NewStringUTF(directory.c_str()); jstring j_directory_name = env->NewStringUTF(filename.c_str()); @@ -98,8 +104,9 @@ bool CreateDir(const std::string& directory, const std::string& filename) { } int OpenContentUri(const std::string& filepath, AndroidOpenMode openmode) { - if (open_content_uri == nullptr) + if (open_content_uri == nullptr) { return -1; + } const char* mode = ""; switch (openmode) { @@ -135,8 +142,9 @@ int OpenContentUri(const std::string& filepath, AndroidOpenMode openmode) { std::vector GetFilesName(const std::string& filepath) { auto vector = std::vector(); - if (get_files_name == nullptr) + if (get_files_name == nullptr) { return vector; + } auto env = GetEnvForThread(); jstring j_filepath = env->NewStringUTF(filepath.c_str()); auto j_object = @@ -150,10 +158,37 @@ std::vector GetFilesName(const std::string& filepath) { return vector; } +std::optional GetUserDirectory() { + if (get_user_directory == nullptr) { + throw std::runtime_error( + "Unable to locate user directory: Function with ID 'get_user_directory' is missing"); + } + auto env = GetEnvForThread(); + auto j_user_directory = + (jstring)(env->CallStaticObjectMethod(native_library, get_user_directory, nullptr)); + auto result = env->GetStringUTFChars(j_user_directory, nullptr); + if (result == "") { + return std::nullopt; + } + return result; +} + +std::string GetBuildFlavor() { + if (get_build_flavor == nullptr) { + throw std::runtime_error( + "Unable get build flavor: Function with ID 'get_build_flavor' is missing"); + } + auto env = GetEnvForThread(); + const auto jflavor = + (jstring)(env->CallStaticObjectMethod(native_library, get_build_flavor, nullptr)); + return env->GetStringUTFChars(jflavor, nullptr); +} + bool CopyFile(const std::string& source, const std::string& destination_path, const std::string& destination_filename) { - if (copy_file == nullptr) + if (copy_file == nullptr) { return false; + } auto env = GetEnvForThread(); jstring j_source_path = env->NewStringUTF(source.c_str()); jstring j_destination_path = env->NewStringUTF(destination_path.c_str()); @@ -163,8 +198,14 @@ bool CopyFile(const std::string& source, const std::string& destination_path, } bool RenameFile(const std::string& source, const std::string& filename) { - if (rename_file == nullptr) + if (rename_file == nullptr) { return false; + } + if (std::string(FileUtil::GetFilename(source)) == + std::string(FileUtil::GetFilename(filename))) { + // TODO: Should this be treated as a success or failure? + return false; + } auto env = GetEnvForThread(); jstring j_source_path = env->NewStringUTF(source.c_str()); jstring j_destination_path = env->NewStringUTF(filename.c_str()); @@ -172,6 +213,86 @@ bool RenameFile(const std::string& source, const std::string& filename) { j_destination_path); } +bool UpdateDocumentLocation(const std::string& source_path, const std::string& destination_path) { + if (update_document_location == nullptr) { + return false; + } + auto env = GetEnvForThread(); + jstring j_source_path = env->NewStringUTF(source_path.c_str()); + jstring j_destination_path = env->NewStringUTF(destination_path.c_str()); + return env->CallStaticBooleanMethod(native_library, update_document_location, j_source_path, + j_destination_path); +} + +bool MoveFile(const std::string& filename, const std::string& source_dir_path, + const std::string& destination_dir_path) { + if (move_file == nullptr) { + return false; + } + if (source_dir_path == destination_dir_path) { + // TODO: Should this be treated as a success or failure? + return false; + } + auto env = GetEnvForThread(); + jstring j_filename = env->NewStringUTF(filename.c_str()); + jstring j_source_dir_path = env->NewStringUTF(source_dir_path.c_str()); + jstring j_destination_dir_path = env->NewStringUTF(destination_dir_path.c_str()); + return env->CallStaticBooleanMethod(native_library, move_file, j_filename, j_source_dir_path, + j_destination_dir_path); +} + +bool MoveAndRenameFile(const std::string& src_full_path, const std::string& dest_full_path) { + if (src_full_path == dest_full_path) { + // TODO: Should this be treated as a success or failure? + return false; + } + const auto src_filename = std::string(FileUtil::GetFilename(src_full_path)); + const auto src_parent_path = std::string(FileUtil::GetParentPath(src_full_path)); + const auto dest_filename = std::string(FileUtil::GetFilename(dest_full_path)); + const auto dest_parent_path = std::string(FileUtil::GetParentPath(dest_full_path)); + bool result; + + const std::string tmp_path = "/tmp"; + AndroidStorage::CreateDir("/", "tmp"); + + // If a simultaneous move and rename are not necessary, use individual methods + if (src_filename == dest_filename || src_parent_path == dest_parent_path) { + if (src_filename != dest_filename) { + return AndroidStorage::RenameFile(src_full_path, dest_filename); + } else if (src_parent_path != dest_parent_path) { + return AndroidStorage::MoveFile(src_filename, src_parent_path, dest_parent_path); + } + } + + // Step 1: Create directory named after UUID inside /tmp to house the moved file. + // This prevents clashes if files with the same name are moved simultaneously. + const auto uuid = boost::uuids::to_string(boost::uuids::time_generator_v7()()); + const auto allocated_tmp_path = tmp_path + "/" + uuid; + AndroidStorage::CreateDir(tmp_path, uuid); + + // Step 2: Attempt to move to allocated temporary directory. + // If this step fails, skip everything except the cleanup. + result = AndroidStorage::MoveFile(src_filename, src_parent_path, allocated_tmp_path); + if (result == true) { + // Step 3: Rename to desired file name. + AndroidStorage::RenameFile((allocated_tmp_path + "/" + src_filename), dest_filename); + + // Step 4: If a file with the desired name in the destination exists, remove it. + AndroidStorage::DeleteDocument(dest_full_path); + + // Step 5: Attempt to move file to desired location. + // If this step fails, move the file back to where it came from. + result = AndroidStorage::MoveFile(dest_filename, allocated_tmp_path, dest_parent_path); + if (result == false) { + AndroidStorage::MoveAndRenameFile((allocated_tmp_path + "/" + dest_filename), + src_full_path); + } + } + // Step 6: Clean up the allocated temp directory. + AndroidStorage::DeleteDocument(allocated_tmp_path); + return result; +} + #define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \ F(FunctionName, ReturnValue, JMethodID, Caller) #define F(FunctionName, ReturnValue, JMethodID, Caller) \ diff --git a/src/common/android_storage.h b/src/common/android_storage.h index 2ea0eb57c..bc4594362 100644 --- a/src/common/android_storage.h +++ b/src/common/android_storage.h @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -19,12 +19,23 @@ open_content_uri, "openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I") \ V(GetFilesName, std::vector, (const std::string& filepath), get_files_name, \ "getFilesName", "(Ljava/lang/String;)[Ljava/lang/String;") \ + V(GetUserDirectory, std::optional, (), get_user_directory, "getUserDirectory", \ + "(Landroid/net/Uri;)Ljava/lang/String;") \ V(CopyFile, bool, \ (const std::string& source, const std::string& destination_path, \ const std::string& destination_filename), \ copy_file, "copyFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z") \ V(RenameFile, bool, (const std::string& source, const std::string& filename), rename_file, \ - "renameFile", "(Ljava/lang/String;Ljava/lang/String;)Z") + "renameFile", "(Ljava/lang/String;Ljava/lang/String;)Z") \ + V(UpdateDocumentLocation, bool, \ + (const std::string& source_path, const std::string& destination_path), \ + update_document_location, "updateDocumentLocation", \ + "(Ljava/lang/String;Ljava/lang/String;)Z") \ + V(GetBuildFlavor, std::string, (), get_build_flavor, "getBuildFlavor", "()Ljava/lang/String;") \ + V(MoveFile, bool, \ + (const std::string& filename, const std::string& source_dir_path, \ + const std::string& destination_dir_path), \ + move_file, "moveFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z") #define ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(V) \ V(IsDirectory, bool, is_directory, CallStaticBooleanMethod, "isDirectory", \ "(Ljava/lang/String;)Z") \ @@ -34,6 +45,7 @@ V(DeleteDocument, bool, delete_document, CallStaticBooleanMethod, "deleteDocument", \ "(Ljava/lang/String;)Z") namespace AndroidStorage { + static JavaVM* g_jvm = nullptr; static jclass native_library = nullptr; #define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) F(JMethodID) @@ -44,6 +56,7 @@ ANDROID_STORAGE_FUNCTIONS(FS) #undef F #undef FS #undef FR +bool MoveAndRenameFile(const std::string& src_full_path, const std::string& dest_full_path); // Reference: // https://developer.android.com/reference/android/os/ParcelFileDescriptor#parseMode(java.lang.String) enum class AndroidOpenMode { @@ -57,6 +70,12 @@ enum class AndroidOpenMode { NEVER = EINVAL, }; +class AndroidBuildFlavors { +public: + static constexpr std::string GOOGLEPLAY = "googlePlay"; + static constexpr std::string VANILLA = "vanilla"; +}; + inline AndroidOpenMode operator|(AndroidOpenMode a, int b) { return static_cast(static_cast(a) | b); } @@ -80,5 +99,6 @@ ANDROID_STORAGE_FUNCTIONS(FS) ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR) #undef F #undef FR + } // namespace AndroidStorage #endif diff --git a/src/common/apple_utils.h b/src/common/apple_utils.h index 472982874..4354fbaa3 100644 --- a/src/common/apple_utils.h +++ b/src/common/apple_utils.h @@ -4,6 +4,7 @@ namespace AppleUtils { +float GetRefreshRate(); int IsLowPowerModeEnabled(); -} +} // namespace AppleUtils diff --git a/src/common/apple_utils.mm b/src/common/apple_utils.mm index 99a3d3235..5f9a2254b 100644 --- a/src/common/apple_utils.mm +++ b/src/common/apple_utils.mm @@ -2,10 +2,29 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#import +#import #import namespace AppleUtils { +float GetRefreshRate() { // TODO: How does this handle multi-monitor? -OS + NSScreen* screen = [NSScreen mainScreen]; + if (screen) { + NSDictionary* screenInfo = [screen deviceDescription]; + CGDirectDisplayID displayID = + (CGDirectDisplayID)[screenInfo[@"NSScreenNumber"] unsignedIntValue]; + CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(displayID); + if (displayMode) { + CGFloat refreshRate = CGDisplayModeGetRefreshRate(displayMode); + CFRelease(displayMode); + return refreshRate; + } + } + + return 60; // Something went wrong, so just return a generic value +} + int IsLowPowerModeEnabled() { return (int)[NSProcessInfo processInfo].lowPowerModeEnabled; } diff --git a/src/common/bit_field.natvis b/src/common/bit_field.natvis new file mode 100644 index 000000000..2bdc0ce11 --- /dev/null +++ b/src/common/bit_field.natvis @@ -0,0 +1,28 @@ + + + + + + + + {((unsigned long long)storage >> $T1) & (((unsigned long long)1 << $T2) - 1)} + + + + ((unsigned long long)storage >> $T1) & (((unsigned long long)1 << $T2) - 1) + + + (long long)((((unsigned long long)storage >> $T1) & ((1ULL << $T2)-1)) & (1ULL << ($T2-1)) + ? -((1ULL << $T2) - (((unsigned long long)storage >> $T1) & ((1ULL << $T2)-1))) + : (((unsigned long long)storage >> $T1) & ((1ULL << $T2)-1))) + + + $T1 + + + $T2 + + storage + + + diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index c740e8416..79c0afaca 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -304,20 +304,31 @@ bool DeleteDir(const std::string& filename) { return false; } -bool Rename(const std::string& srcFilename, const std::string& destFilename) { - LOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename); +bool Rename(const std::string& srcFullPath, const std::string& destFullPath) { + LOG_TRACE(Common_Filesystem, "{} --> {}", srcFullPath, destFullPath); #ifdef _WIN32 - if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(), - Common::UTF8ToUTF16W(destFilename).c_str()) == 0) + if (_wrename(Common::UTF8ToUTF16W(srcFullPath).c_str(), + Common::UTF8ToUTF16W(destFullPath).c_str()) == 0) return true; #elif ANDROID - if (AndroidStorage::RenameFile(srcFilename, std::string(GetFilename(destFilename)))) - return true; + // srcFullPath and destFullPath are relative to the user directory + if (AndroidStorage::GetBuildFlavor() == AndroidStorage::AndroidBuildFlavors::GOOGLEPLAY) { + if (AndroidStorage::MoveAndRenameFile(srcFullPath, destFullPath)) + return true; + } else { + std::optional userDirLocation = AndroidStorage::GetUserDirectory(); + if (userDirLocation && rename((*userDirLocation + srcFullPath).c_str(), + (*userDirLocation + destFullPath).c_str()) == 0) { + AndroidStorage::UpdateDocumentLocation(srcFullPath, destFullPath); + // ^ TODO: This shouldn't fail, but what should we do if it somehow does? + return true; + } + } #else - if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) + if (rename(srcFullPath.c_str(), destFullPath.c_str()) == 0) return true; #endif - LOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename, + LOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFullPath, destFullPath, GetLastErrorMsg()); return false; } @@ -874,7 +885,6 @@ void SetUserPath(const std::string& path) { g_paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP); g_paths.emplace(UserPath::StatesDir, user_path + STATES_DIR DIR_SEP); g_paths.emplace(UserPath::IconsDir, user_path + ICONS_DIR DIR_SEP); - g_paths.emplace(UserPath::PlayTimeDir, user_path + LOG_DIR DIR_SEP); g_default_paths = g_paths; } @@ -1244,20 +1254,19 @@ static std::size_t pread(int fd, void* buf, std::size_t count, uint64_t offset) #define pread ::pread #endif -std::size_t IOFile::ReadAtImpl(void* data, std::size_t length, std::size_t data_size, - std::size_t offset) { +std::size_t IOFile::ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) { if (!IsOpen()) { m_good = false; return std::numeric_limits::max(); } - if (length == 0) { + if (byte_count == 0) { return 0; } DEBUG_ASSERT(data != nullptr); - return pread(fileno(m_file), data, data_size * length, offset); + return pread(fileno(m_file), data, byte_count, offset); } std::size_t IOFile::WriteImpl(const void* data, std::size_t length, std::size_t data_size) { @@ -1305,19 +1314,19 @@ struct CryptoIOFileImpl { std::size_t res = f.IOFile::ReadImpl(data, length, data_size); if (res != std::numeric_limits::max() && res != 0) { d.ProcessData(reinterpret_cast(data), - reinterpret_cast(data), length * data_size); + reinterpret_cast(data), res * data_size); e.Seek(f.IOFile::Tell()); } return res; } - std::size_t ReadAtImpl(CryptoIOFile& f, void* data, std::size_t length, std::size_t data_size, + std::size_t ReadAtImpl(CryptoIOFile& f, void* data, std::size_t byte_count, std::size_t offset) { - std::size_t res = f.IOFile::ReadAtImpl(data, length, data_size, offset); + std::size_t res = f.IOFile::ReadAtImpl(data, byte_count, offset); if (res != std::numeric_limits::max() && res != 0) { d.Seek(offset); d.ProcessData(reinterpret_cast(data), - reinterpret_cast(data), length * data_size); + reinterpret_cast(data), res); e.Seek(f.IOFile::Tell()); } return res; @@ -1368,9 +1377,8 @@ std::size_t CryptoIOFile::ReadImpl(void* data, std::size_t length, std::size_t d return impl->ReadImpl(*this, data, length, data_size); } -std::size_t CryptoIOFile::ReadAtImpl(void* data, std::size_t length, std::size_t data_size, - std::size_t offset) { - return impl->ReadAtImpl(*this, data, length, data_size, offset); +std::size_t CryptoIOFile::ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) { + return impl->ReadAtImpl(*this, data, byte_count, offset); } std::size_t CryptoIOFile::WriteImpl(const void* data, std::size_t length, std::size_t data_size) { diff --git a/src/common/file_util.h b/src/common/file_util.h index 57a1d67e1..98d232dcf 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -51,7 +51,6 @@ enum class UserPath { LoadDir, LogDir, NANDDir, - PlayTimeDir, RootDir, SDMCDir, ShaderDir, @@ -136,13 +135,13 @@ bool Delete(const std::string& filename); // Deletes a directory filename, returns true on success bool DeleteDir(const std::string& filename); -// renames file srcFilename to destFilename, returns true on success -bool Rename(const std::string& srcFilename, const std::string& destFilename); +// Renames file srcFullPath to destFullPath, returns true on success +bool Rename(const std::string& srcFullPath, const std::string& destFullPath); -// copies file srcFilename to destFilename, returns true on success +// Copies file srcFilename to destFilename, returns true on success bool Copy(const std::string& srcFilename, const std::string& destFilename); -// creates an empty file filename, returns true on success +// Creates an empty file filename, returns true on success bool CreateEmptyFile(const std::string& filename); /** @@ -303,6 +302,7 @@ public: virtual bool Close(); + /// Returns the amount of T items read template std::size_t ReadArray(T* data, std::size_t length) { static_assert(std::is_trivially_copyable_v, @@ -315,16 +315,18 @@ public: return items_read; } + /// Returns the amount of bytes read template std::size_t ReadAtArray(T* data, std::size_t length, std::size_t offset) { static_assert(std::is_trivially_copyable_v, "Given array does not consist of trivially copyable objects"); - std::size_t items_read = ReadAtImpl(data, length, sizeof(T), offset); - if (items_read != length) + const size_t bytes = length * sizeof(T); + std::size_t size_read = ReadAtImpl(data, bytes, offset); + if (size_read != bytes) m_good = false; - return items_read; + return size_read; } template @@ -467,8 +469,7 @@ protected: virtual bool Open(); virtual std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size); - virtual std::size_t ReadAtImpl(void* data, std::size_t length, std::size_t data_size, - std::size_t offset); + virtual std::size_t ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset); virtual std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size); virtual bool SeekImpl(s64 off, int origin); @@ -521,8 +522,7 @@ private: std::unique_ptr impl; std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size) override; - std::size_t ReadAtImpl(void* data, std::size_t length, std::size_t data_size, - std::size_t offset) override; + std::size_t ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) override; std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size) override; bool SeekImpl(s64 off, int origin) override; diff --git a/src/common/hacks/hack_list.cpp b/src/common/hacks/hack_list.cpp index c5702df5e..4c611f6f6 100644 --- a/src/common/hacks/hack_list.cpp +++ b/src/common/hacks/hack_list.cpp @@ -55,6 +55,12 @@ HackManager hack_manager = { 0x00040000001D1400, // USA 0x00040000001D1500, // EUR 0x00040000001CA900, // JPN + + // Mario & Luigi: Paper Jam + 0x0004000000132600, // JPN + 0x0004000000132700, // USA + 0x0004000000132800, // EUR + 0x000400000018A100, // EUR (Demo) }, }}, @@ -67,6 +73,9 @@ HackManager hack_manager = { 0x0004013000002C02, // Normal 0x0004013000002C03, // Safe mode 0x0004013020002C03, // New 3DS safe mode + + // DLP + 0x0004013000002802, }, }}, @@ -155,6 +164,29 @@ HackManager hack_manager = { 0x0004013020003203, // New 3DS safe mode }, }}, + {HackType::REQUIRES_SHADER_FIXUP, + HackEntry{ + .mode = HackAllowMode::FORCE, + .affected_title_ids = + { + // 3D Thunder Blade + 0x0004000000128A00, // JPN + 0x0004000000158200, // EUR + 0x0004000000158C00, // USA + + // 3D After Burner II + 0x0004000000114200, // JPN + 0x0004000000157A00, // EUR + 0x0004000000158900, // USA + + // 3D Classics + 0x0004000000154000, // 1 (JPN) + 0x0004000000180E00, // 2 (JPN) + 0x000400000019A700, // 2 (EUR) + 0x0004000000185E00, // 2 (USA) + 0x00040000001AA300, // 3 (JPN) + }, + }}, }}; } \ No newline at end of file diff --git a/src/common/hacks/hack_list.h b/src/common/hacks/hack_list.h index 43d7ea409..0617fa51c 100644 --- a/src/common/hacks/hack_list.h +++ b/src/common/hacks/hack_list.h @@ -14,6 +14,7 @@ enum class HackType : int { DECRYPTION_AUTHORIZED, ONLINE_LLE_REQUIRED, REGION_FROM_SECURE, + REQUIRES_SHADER_FIXUP, }; class UserHackData {}; diff --git a/src/common/hash.h b/src/common/hash.h index 1a222b22e..8462c41b5 100644 --- a/src/common/hash.h +++ b/src/common/hash.h @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -6,19 +6,36 @@ #include #include -#include "common/cityhash.h" +#include +#include +#include "cityhash.h" #include "common/common_types.h" namespace Common { +namespace HashAlgo64 { +struct XXH3 { + static inline u64 hash(const void* data, std::size_t len) noexcept { + return XXH3_64bits(data, len); + } +}; + +struct CityHash { + static inline u64 hash(const void* data, std::size_t len) noexcept { + return CityHash64(reinterpret_cast(data), len); + } +}; +} // namespace HashAlgo64 + /** * Computes a 64-bit hash over the specified block of data * @param data Block of data to compute hash over * @param len Length of data (in bytes) to compute hash over * @returns 64-bit hash value that was computed over the data block */ +template static inline u64 ComputeHash64(const void* data, std::size_t len) noexcept { - return CityHash64(static_cast(data), len); + return Hasher::hash(data, len); } /** @@ -26,19 +43,25 @@ static inline u64 ComputeHash64(const void* data, std::size_t len) noexcept { * that either the struct includes no padding, or that any padding is initialized to a known value * by memsetting the struct to 0 before filling it in. */ -template +template static inline u64 ComputeStructHash64(const T& data) noexcept { static_assert(std::is_trivially_copyable_v, "Type passed to ComputeStructHash64 must be trivially copyable"); - return ComputeHash64(&data, sizeof(data)); + return ComputeHash64(&data, sizeof(data)); } /** * Combines the seed parameter with the provided hash, producing a new unique hash * Implementation from: http://boost.sourceforge.net/doc/html/boost/hash_combine.html */ -[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) { - return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2)); +[[nodiscard]] constexpr u64 HashCombine(u64 seed) { + return seed; +} + +template +[[nodiscard]] constexpr u64 HashCombine(u64 seed, u64 hash, Ts... rest) { + seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return HashCombine(seed, rest...); } template @@ -49,7 +72,7 @@ struct IdentityHash { }; /// A helper template that ensures the padding in a struct is initialized by memsetting to 0. -template +template struct HashableStruct { // In addition to being trivially copyable, T must also have a trivial default constructor, // because any member initialization would be overridden by memset @@ -78,8 +101,42 @@ struct HashableStruct { return !(*this == o); }; - std::size_t Hash() const noexcept { - return Common::ComputeStructHash64(state); + u64 Hash() const noexcept { + return Common::ComputeStructHash64(state); + } +}; + +/// Helper struct that provides a hashable string with basic string API +template +struct HashableString { + std::string value; + + HashableString() = default; + HashableString(const std::string& s) : value(s) {} + HashableString(std::string&& s) noexcept : value(std::move(s)) {} + + u64 Hash() const noexcept { + return ComputeHash64(value.data(), value.size()); + } + + bool empty() const noexcept { + return value.empty(); + } + + std::size_t size() const noexcept { + return value.size(); + } + + const char* data() const noexcept { + return value.data(); + } + + operator std::string_view() const noexcept { + return value; + } + + operator std::string&&() && noexcept { + return std::move(value); } }; diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 405cf9457..36fcfeccf 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -51,6 +51,8 @@ public: virtual void EnableForStacktrace() = 0; virtual void Flush() = 0; + + virtual void Close() = 0; }; /** @@ -72,6 +74,10 @@ public: std::fflush(stderr); } + void Close() override { + enabled = false; + } + void EnableForStacktrace() override { enabled = true; } @@ -130,6 +136,11 @@ public: file->Flush(); } + void Close() override { + file->Close(); + enabled = false; + } + void EnableForStacktrace() override { enabled = true; bytes_written = 0; @@ -158,6 +169,8 @@ public: void Flush() override {} + void Close() override {} + void EnableForStacktrace() override {} }; @@ -177,11 +190,14 @@ public: void Flush() override {} + void Close() override {} + void EnableForStacktrace() override {} }; #endif bool initialization_in_progress_suppress_logging = true; +bool logging_initialized = false; #ifdef CITRA_LINUX_GCC_BACKTRACE [[noreturn]] void SleepForever() { @@ -216,6 +232,7 @@ public: instance = std::unique_ptr( new Impl(fmt::format("{}{}", log_dir, log_file), filter), Deleter); initialization_in_progress_suppress_logging = false; + logging_initialized = true; } static void Start() { @@ -258,8 +275,8 @@ public: if (!filter.CheckMessage(log_class, log_level)) { return; } - Entry new_entry = - CreateEntry(log_class, log_level, filename, line_num, function, std::move(message)); + Entry new_entry = CreateEntry(log_class, log_level, filename, line_num, function, + std::move(message), time_origin); if (!regex_filter.empty() && !boost::regex_search(FormatLogMessage(new_entry), regex_filter)) { return; @@ -274,6 +291,24 @@ public: } } + static Entry CreateEntry(Class log_class, Level log_level, const char* filename, + unsigned int line_nr, const char* function, std::string&& message, + const std::chrono::steady_clock::time_point& time_origin) { + using std::chrono::duration_cast; + using std::chrono::microseconds; + using std::chrono::steady_clock; + + return { + .timestamp = duration_cast(steady_clock::now() - time_origin), + .log_class = log_class, + .log_level = log_level, + .filename = filename, + .line_num = line_nr, + .function = function, + .message = std::move(message), + }; + } + private: Impl(const std::string& file_backend_filename, const Filter& filter_) : filter{filter_}, file_backend{file_backend_filename} { @@ -295,9 +330,9 @@ private: } backend_thread.request_stop(); backend_thread.join(); - const auto signal_entry = - CreateEntry(Class::Log, Level::Critical, "?", 0, "?", - fmt::vformat("Received signal {}", fmt::make_format_args(sig))); + const auto signal_entry = CreateEntry( + Class::Log, Level::Critical, "?", 0, "?", + fmt::vformat("Received signal {}", fmt::make_format_args(sig)), time_origin); ForEachBackend([&signal_entry](Backend& backend) { backend.EnableForStacktrace(); backend.Write(signal_entry); @@ -310,12 +345,13 @@ private: abort(); } line.pop_back(); // Remove newline - const auto frame_entry = - CreateEntry(Class::Log, Level::Critical, "?", 0, "?", std::move(line)); + const auto frame_entry = CreateEntry(Class::Log, Level::Critical, "?", 0, "?", + std::move(line), time_origin); ForEachBackend([&frame_entry](Backend& backend) { backend.Write(frame_entry); }); } using namespace std::literals; - const auto rip_entry = CreateEntry(Class::Log, Level::Critical, "?", 0, "?", "RIP"s); + const auto rip_entry = + CreateEntry(Class::Log, Level::Critical, "?", 0, "?", "RIP"s, time_origin); ForEachBackend([&rip_entry](Backend& backend) { backend.Write(rip_entry); backend.Flush(); @@ -348,6 +384,8 @@ private: }; while (!stop_token.stop_requested()) { message_queue.PopWait(entry, stop_token); + // Only write the log if something was actually popped (entry.filename != nullptr) + // (for example, when the stop token is signaled). if (entry.filename != nullptr) { write_logs(); } @@ -367,24 +405,10 @@ private: backend_thread.join(); } - ForEachBackend([](Backend& backend) { backend.Flush(); }); - } - - Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, - const char* function, std::string&& message) const { - using std::chrono::duration_cast; - using std::chrono::microseconds; - using std::chrono::steady_clock; - - return { - .timestamp = duration_cast(steady_clock::now() - time_origin), - .log_class = log_class, - .log_level = log_level, - .filename = filename, - .line_num = line_nr, - .function = function, - .message = std::move(message), - }; + ForEachBackend([](Backend& backend) { + backend.Flush(); + backend.Close(); + }); } void ForEachBackend(auto lambda) { @@ -485,9 +509,19 @@ void SetColorConsoleBackendEnabled(bool enabled) { void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) { - if (!initialization_in_progress_suppress_logging) { + if (initialization_in_progress_suppress_logging) [[unlikely]] { + return; + } + + if (logging_initialized) [[likely]] { Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args)); + } else { + // In the rare case that logging occurs before initialization, write the + // message to stderr to preserve useful debug information. + Entry new_entry = Impl::CreateEntry(log_class, log_level, filename, line_num, function, + fmt::vformat(format, args), {}); + PrintMessage(new_entry); } } } // namespace Common::Log diff --git a/src/common/play_time_manager.cpp b/src/common/play_time_manager.cpp index c8b94ee08..e4cb9a628 100644 --- a/src/common/play_time_manager.cpp +++ b/src/common/play_time_manager.cpp @@ -20,19 +20,27 @@ struct PlayTimeElement { PlayTime play_time; }; +#define PLAY_TIME_FILENAME "play_time.bin" + std::string GetCurrentUserPlayTimePath() { - return FileUtil::GetUserPath(FileUtil::UserPath::PlayTimeDir) + DIR_SEP + "play_time.bin"; + return FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + DIR_SEP + PLAY_TIME_FILENAME; } [[nodiscard]] bool ReadPlayTimeFile(PlayTimeDatabase& out_play_time_db) { - const auto filename = GetCurrentUserPlayTimePath(); + const auto filepath = GetCurrentUserPlayTimePath(); + const auto old_filepath = + FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + DIR_SEP + PLAY_TIME_FILENAME; + + if (FileUtil::Exists(old_filepath) && !FileUtil::Exists(filepath)) { + static_cast(FileUtil::Rename(old_filepath, filepath)); + } out_play_time_db.clear(); - if (FileUtil::Exists(filename)) { - FileUtil::IOFile file{filename, "rb"}; + if (FileUtil::Exists(filepath)) { + FileUtil::IOFile file{filepath, "rb"}; if (!file.IsOpen()) { - LOG_ERROR(Frontend, "Failed to open play time file: {}", filename); + LOG_ERROR(Frontend, "Failed to open play time file: {}", filepath); return false; } @@ -54,11 +62,11 @@ std::string GetCurrentUserPlayTimePath() { } [[nodiscard]] bool WritePlayTimeFile(const PlayTimeDatabase& play_time_db) { - const auto filename = GetCurrentUserPlayTimePath(); + const auto filepath = GetCurrentUserPlayTimePath(); - FileUtil::IOFile file{filename, "wb"}; + FileUtil::IOFile file{filepath, "wb"}; if (!file.IsOpen()) { - LOG_ERROR(Frontend, "Failed to open play time file: {}", filename); + LOG_ERROR(Frontend, "Failed to open play time file: {}", filepath); return false; } diff --git a/src/common/settings.cpp b/src/common/settings.cpp index e2ae6e4b4..564090d0b 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -98,7 +98,7 @@ void LogSettings() { log_setting("Renderer_UseShaderJit", values.use_shader_jit.GetValue()); log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); - log_setting("Renderer_VSyncNew", values.use_vsync_new.GetValue()); + log_setting("Renderer_VSyncNew", values.use_vsync.GetValue()); log_setting("Renderer_PostProcessingShader", values.pp_shader_name.GetValue()); log_setting("Renderer_FilterMode", values.filter_mode.GetValue()); log_setting("Renderer_TextureFilter", GetTextureFilterName(values.texture_filter.GetValue())); @@ -108,12 +108,16 @@ void LogSettings() { log_setting("Renderer_DisableRightEyeRender", values.disable_right_eye_render.GetValue()); log_setting("Stereoscopy_Render3d", values.render_3d.GetValue()); log_setting("Stereoscopy_Factor3d", values.factor_3d.GetValue()); + log_setting("Stereoscopy_Swap_Eyes", values.swap_eyes_3d.GetValue()); + log_setting("Stereoscopy_Render_3d_to_which_display", + values.render_3d_which_display.GetValue()); log_setting("Stereoscopy_MonoRenderOption", values.mono_render_option.GetValue()); if (values.render_3d.GetValue() == StereoRenderOption::Anaglyph) { log_setting("Renderer_AnaglyphShader", values.anaglyph_shader_name.GetValue()); } log_setting("Layout_LayoutOption", values.layout_option.GetValue()); log_setting("Layout_PortraitLayoutOption", values.portrait_layout_option.GetValue()); + log_setting("Layout_SecondaryDisplayLayout", values.secondary_display_layout.GetValue()); log_setting("Layout_SwapScreen", values.swap_screen.GetValue()); log_setting("Layout_UprightScreen", values.upright_screen.GetValue()); log_setting("Layout_ScreenGap", values.screen_gap.GetValue()); @@ -152,6 +156,7 @@ void LogSettings() { log_setting("System_RegionValue", values.region_value.GetValue()); log_setting("System_PluginLoader", values.plugin_loader_enabled.GetValue()); log_setting("System_PluginLoaderAllowed", values.allow_plugin_loader.GetValue()); + log_setting("System_ApplyRegionFreePatch", values.apply_region_free_patch.GetValue()); log_setting("Debugging_DelayStartForLLEModules", values.delay_start_for_lle_modules.GetValue()); log_setting("Debugging_UseGdbstub", values.use_gdbstub.GetValue()); log_setting("Debugging_GdbstubPort", values.gdbstub_port.GetValue()); @@ -199,7 +204,7 @@ void RestoreGlobalState(bool is_powered_on) { values.use_hw_shader.SetGlobal(true); values.use_disk_shader_cache.SetGlobal(true); values.shaders_accurate_mul.SetGlobal(true); - values.use_vsync_new.SetGlobal(true); + values.use_vsync.SetGlobal(true); values.resolution_factor.SetGlobal(true); values.frame_limit.SetGlobal(true); values.texture_filter.SetGlobal(true); @@ -207,6 +212,7 @@ void RestoreGlobalState(bool is_powered_on) { values.delay_game_render_thread_us.SetGlobal(true); values.layout_option.SetGlobal(true); values.portrait_layout_option.SetGlobal(true); + values.secondary_display_layout.SetGlobal(true); values.swap_screen.SetGlobal(true); values.upright_screen.SetGlobal(true); values.large_screen_proportion.SetGlobal(true); @@ -216,6 +222,7 @@ void RestoreGlobalState(bool is_powered_on) { values.bg_green.SetGlobal(true); values.bg_blue.SetGlobal(true); values.render_3d.SetGlobal(true); + values.swap_eyes_3d.SetGlobal(true); values.factor_3d.SetGlobal(true); values.filter_mode.SetGlobal(true); values.pp_shader_name.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index e6576b748..709ba0cf8 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -54,6 +54,7 @@ enum class PortraitLayoutOption : u32 { PortraitOriginal }; +enum class SecondaryDisplayLayout : u32 { None, TopScreenOnly, BottomScreenOnly, SideBySide }; /** Defines where the small screen will appear relative to the large screen * when in Large Screen mode */ @@ -71,7 +72,7 @@ enum class SmallScreenPosition : u32 { enum class StereoRenderOption : u32 { Off = 0, SideBySide = 1, - ReverseSideBySide = 2, + SideBySideFull = 2, Anaglyph = 3, Interlaced = 4, ReverseInterlaced = 5, @@ -85,6 +86,14 @@ enum class MonoRenderOption : u32 { RightEye = 1, }; +// on android, which displays to render stereo mode to +enum class StereoWhichDisplay : u32 { + None = 0, // equivalent to StereoRenderOption = Off + Both = 1, + PrimaryOnly = 2, + SecondaryOnly = 3 +}; + enum class AudioEmulation : u32 { HLE = 0, LLE = 1, @@ -480,6 +489,7 @@ struct Values { Setting plugin_loader_enabled{false, "plugin_loader"}; Setting allow_plugin_loader{true, "allow_plugin_loader"}; Setting steps_per_hour{0, "steps_per_hour"}; + Setting apply_region_free_patch{true, "apply_region_free_patch"}; // Renderer SwitchableSetting graphics_api{ @@ -505,7 +515,13 @@ struct Values { SwitchableSetting use_hw_shader{true, "use_hw_shader"}; SwitchableSetting use_disk_shader_cache{true, "use_disk_shader_cache"}; SwitchableSetting shaders_accurate_mul{true, "shaders_accurate_mul"}; - SwitchableSetting use_vsync_new{true, "use_vsync_new"}; +#ifdef ANDROID // TODO: Fuck this -OS + SwitchableSetting use_vsync{false, "use_vsync"}; +#else + SwitchableSetting use_vsync{true, "use_vsync"}; +#endif + SwitchableSetting use_display_refresh_rate_detection{ + true, "use_display_refresh_rate_detection"}; Setting use_shader_jit{true, "use_shader_jit"}; SwitchableSetting resolution_factor{1, 0, 10, "resolution_factor"}; SwitchableSetting frame_limit{100, 0, 1000, "frame_limit"}; @@ -519,6 +535,8 @@ struct Values { SwitchableSetting layout_option{LayoutOption::Default, "layout_option"}; SwitchableSetting swap_screen{false, "swap_screen"}; SwitchableSetting upright_screen{false, "upright_screen"}; + SwitchableSetting secondary_display_layout{SecondaryDisplayLayout::None, + "secondary_display_layout"}; SwitchableSetting large_screen_proportion{4.f, 1.f, 16.f, "large_screen_proportion"}; SwitchableSetting screen_gap{0, "screen_gap"}; @@ -558,6 +576,10 @@ struct Values { SwitchableSetting render_3d{StereoRenderOption::Off, "render_3d"}; SwitchableSetting factor_3d{0, "factor_3d"}; + SwitchableSetting swap_eyes_3d{false, "swap_eyes_3d"}; + + SwitchableSetting render_3d_which_display{StereoWhichDisplay::None, + "render_3d_which_display"}; SwitchableSetting mono_render_option{MonoRenderOption::LeftEye, "mono_render_option"}; @@ -582,9 +604,9 @@ struct Values { SwitchableSetting enable_realtime_audio{false, "enable_realtime_audio"}; SwitchableSetting volume{1.f, 0.f, 1.f, "volume"}; Setting output_type{AudioCore::SinkType::Auto, "output_type"}; - Setting output_device{"auto", "output_device"}; + Setting output_device{"Auto", "output_device"}; Setting input_type{AudioCore::InputType::Auto, "input_type"}; - Setting input_device{"auto", "input_device"}; + Setting input_device{"Auto", "input_device"}; // Camera std::array camera_name; diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 0791a3f20..08290eb7f 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp @@ -1,7 +1,10 @@ -// Copyright 2013 Dolphin Emulator Project / 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. #include "common/arch.h" #if CITRA_ARCH(x86_64) @@ -131,13 +134,6 @@ static CPUCaps Detect() { std::memcpy(caps.cpu_string + 32, cpu_id, sizeof(cpu_id)); } - if (max_ex_fn >= 0x80000001) { - // Check for more features - __cpuid(cpu_id, 0x80000001); - if ((cpu_id[2] >> 16) & 1) - caps.fma4 = true; - } - return caps; } diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index 31ed1c584..7018ec0c1 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h @@ -1,7 +1,10 @@ -// Copyright 2013 Dolphin Emulator Project / 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. #pragma once #include "common/arch.h" @@ -25,7 +28,6 @@ struct CPUCaps { bool bmi1; bool bmi2; bool fma; - bool fma4; bool aes; }; diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp index 1e38877a1..3257fa2d8 100644 --- a/src/common/zstd_compression.cpp +++ b/src/common/zstd_compression.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -53,9 +53,12 @@ std::vector CompressDataZSTDDefault(std::span source) { return CompressDataZSTD(source, ZSTD_CLEVEL_DEFAULT); } +std::size_t GetDecompressedSize(std::span compressed) { + return ZSTD_getFrameContentSize(compressed.data(), compressed.size()); +} + std::vector DecompressDataZSTD(std::span compressed) { - const std::size_t decompressed_size = - ZSTD_getFrameContentSize(compressed.data(), compressed.size()); + const std::size_t decompressed_size = GetDecompressedSize(compressed); if (decompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) { LOG_ERROR(Common, "ZSTD decompressed size could not be determined."); @@ -354,8 +357,7 @@ std::size_t Z3DSWriteIOFile::ReadImpl(void* data, std::size_t length, std::size_ return 0; } -std::size_t Z3DSWriteIOFile::ReadAtImpl(void* data, std::size_t length, std::size_t data_size, - std::size_t offset) { +std::size_t Z3DSWriteIOFile::ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) { // Stubbed UNIMPLEMENTED(); return 0; @@ -616,12 +618,12 @@ bool Z3DSReadIOFile::Open() { } std::size_t Z3DSReadIOFile::ReadImpl(void* data, std::size_t length, std::size_t data_size) { - return impl->Read(data, length * data_size); + size_t res = impl->Read(data, length * data_size); + return res == std::numeric_limits::max() ? res : (res / data_size); } -std::size_t Z3DSReadIOFile::ReadAtImpl(void* data, std::size_t length, std::size_t data_size, - std::size_t offset) { - return impl->ReadAt(data, length * data_size, offset); +std::size_t Z3DSReadIOFile::ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) { + return impl->ReadAt(data, byte_count, offset); } std::size_t Z3DSReadIOFile::WriteImpl(const void* data, std::size_t length, std::size_t data_size) { diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h index 75aceab2e..0d3372bd5 100644 --- a/src/common/zstd_compression.h +++ b/src/common/zstd_compression.h @@ -40,6 +40,15 @@ namespace Common::Compression { */ [[nodiscard]] std::vector CompressDataZSTDDefault(std::span source); +/** + * Gets the decompressed size of the specified Zstandard compressed memory region. + * + * @param compressed the compressed source memory region. + * + * @return the size of the decompressed data. + */ +[[nodiscard]] std::size_t GetDecompressedSize(std::span compressed); + /** * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector. * @@ -174,8 +183,7 @@ private: bool Open() override; std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size) override; - std::size_t ReadAtImpl(void* data, std::size_t length, std::size_t data_size, - std::size_t offset) override; + std::size_t ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) override; std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size) override; bool SeekImpl(s64 off, int origin) override; @@ -241,8 +249,7 @@ private: bool Open() override; std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size) override; - std::size_t ReadAtImpl(void* data, std::size_t length, std::size_t data_size, - std::size_t offset) override; + std::size_t ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) override; std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size) override; bool SeekImpl(s64 off, int origin) override; diff --git a/src/core/cheats/cheats.cpp b/src/core/cheats/cheats.cpp index 2cdb75ad1..ebc783ad9 100644 --- a/src/core/cheats/cheats.cpp +++ b/src/core/cheats/cheats.cpp @@ -91,10 +91,6 @@ void CheatEngine::LoadCheatFile(u64 title_id) { FileUtil::CreateDir(cheat_dir); } - if (!FileUtil::Exists(filepath)) { - return; - } - auto gateway_cheats = GatewayCheat::LoadFile(filepath); { std::unique_lock lock{cheats_list_mutex}; diff --git a/src/core/cheats/gateway_cheat.cpp b/src/core/cheats/gateway_cheat.cpp index 176264b7d..b7cd229ac 100644 --- a/src/core/cheats/gateway_cheat.cpp +++ b/src/core/cheats/gateway_cheat.cpp @@ -487,6 +487,10 @@ std::string GatewayCheat::ToString() const { std::vector> GatewayCheat::LoadFile(const std::string& filepath) { std::vector> cheats; + if (!FileUtil::Exists(filepath)) { + return cheats; + } + boost::iostreams::stream file; FileUtil::OpenFStream(file, filepath); if (!file.is_open()) { diff --git a/src/core/core.cpp b/src/core/core.cpp index 005003ec8..00e79ae8b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -24,9 +24,11 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/dumping/backend.h" +#include "core/file_sys/ncch_container.h" #include "core/frontend/image_interface.h" #include "core/gdbstub/gdbstub.h" #include "core/global.h" +#include "core/hle/kernel/ipc_debugger/recorder.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" @@ -317,49 +319,103 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st } } - auto memory_mode = app_loader->LoadKernelMemoryMode(); - if (memory_mode.second != Loader::ResultStatus::Success) { - LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", - static_cast(memory_mode.second)); + Kernel::MemoryMode app_mem_mode; + Kernel::MemoryMode system_mem_mode; + bool used_default_mem_mode = false; + Kernel::New3dsHwCapabilities app_n3ds_hw_capabilities; - switch (memory_mode.second) { - case Loader::ResultStatus::ErrorEncrypted: - return ResultStatus::ErrorLoader_ErrorEncrypted; - case Loader::ResultStatus::ErrorInvalidFormat: - return ResultStatus::ErrorLoader_ErrorInvalidFormat; - case Loader::ResultStatus::ErrorGbaTitle: - return ResultStatus::ErrorLoader_ErrorGbaTitle; - case Loader::ResultStatus::ErrorArtic: - return ResultStatus::ErrorArticDisconnected; - default: - return ResultStatus::ErrorSystemMode; + if (m_mem_mode) { + // Use memory mode set by the FIRM launch parameters + system_mem_mode = static_cast(m_mem_mode.value()); + m_mem_mode = {}; + } else { + // Use default memory mode based on the n3ds setting + system_mem_mode = Settings::values.is_new_3ds.GetValue() ? Kernel::MemoryMode::NewProd + : Kernel::MemoryMode::Prod; + used_default_mem_mode = true; + } + + { + auto memory_mode = app_loader->LoadKernelMemoryMode(); + if (memory_mode.second != Loader::ResultStatus::Success) { + LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", + static_cast(memory_mode.second)); + + switch (memory_mode.second) { + case Loader::ResultStatus::ErrorEncrypted: + return ResultStatus::ErrorLoader_ErrorEncrypted; + case Loader::ResultStatus::ErrorInvalidFormat: + return ResultStatus::ErrorLoader_ErrorInvalidFormat; + case Loader::ResultStatus::ErrorGbaTitle: + return ResultStatus::ErrorLoader_ErrorGbaTitle; + case Loader::ResultStatus::ErrorArtic: + return ResultStatus::ErrorArticDisconnected; + default: + return ResultStatus::ErrorSystemMode; + } + } + + ASSERT(memory_mode.first); + app_mem_mode = memory_mode.first.value(); + } + + auto n3ds_hw_caps = app_loader->LoadNew3dsHwCapabilities(); + ASSERT(n3ds_hw_caps.first); + app_n3ds_hw_capabilities = n3ds_hw_caps.first.value(); + + if (!Settings::values.is_new_3ds.GetValue() && app_loader->IsN3DSExclusive()) { + return ResultStatus::ErrorN3DSApplication; + } + + // If the default mem mode has been used, we do not come from a FIRM launch. On real HW + // however, the home menu is in charge or setting the proper memory mode when launching + // applications by doing a FIRM launch. Since we launch the application without going + // through the home menu, we need to emulate the FIRM launch having happened and set the + // proper memory mode. + if (used_default_mem_mode) { + + // If we are on the Old 3DS prod mode and the application memory mode does not match, we + // need to adjust it. We do not need adjustment if we are on the New 3DS prod mode, as that + // one overrides all the Old 3DS memory modes. + if (system_mem_mode == Kernel::MemoryMode::Prod && app_mem_mode != system_mem_mode) { + system_mem_mode = app_mem_mode; + } + + // If we are on the New 3DS prod mode, and the application needs the New 3DS extended + // memory mode (only CTRAging is known to do this), adjust the memory mode. + else if (system_mem_mode == Kernel::MemoryMode::NewProd && + app_n3ds_hw_capabilities.memory_mode == Kernel::New3dsMemoryMode::NewDev1) { + system_mem_mode = Kernel::MemoryMode::NewDev1; } } - ASSERT(memory_mode.first); - auto n3ds_hw_caps = app_loader->LoadNew3dsHwCapabilities(); - ASSERT(n3ds_hw_caps.first); u32 num_cores = 2; if (Settings::values.is_new_3ds) { num_cores = 4; } - ResultStatus init_result{ - Init(emu_window, secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores)}; + ResultStatus init_result{Init(emu_window, secondary_window, system_mem_mode, num_cores)}; if (init_result != ResultStatus::Success) { LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", static_cast(init_result)); System::Shutdown(); return init_result; } - gpu->ReportLoadingProgramID(program_id); + + kernel->UpdateCPUAndMemoryState(program_id, app_mem_mode, app_n3ds_hw_capabilities); // Restore any parameters that should be carried through a reset. - if (restore_deliver_arg.has_value()) { - if (auto apt = Service::APT::GetModule(*this)) { + if (auto apt = Service::APT::GetModule(*this)) { + if (restore_deliver_arg.has_value()) { apt->GetAppletManager()->SetDeliverArg(restore_deliver_arg); + restore_deliver_arg.reset(); } - restore_deliver_arg.reset(); + if (restore_sys_menu_arg.has_value()) { + apt->GetAppletManager()->SetSysMenuArg(restore_sys_menu_arg.value()); + restore_sys_menu_arg.reset(); + } + apt->SetWirelessRebootInfoBuffer(restore_wireless_reboot_info); } + if (restore_plugin_context.has_value()) { if (auto plg_ldr = Service::PLGLDR::GetService(*this)) { plg_ldr->SetPluginLoaderContext(restore_plugin_context.value()); @@ -367,6 +423,10 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st restore_plugin_context.reset(); } + if (restore_ipc_recorder) { + kernel->RestoreIPCRecorder(std::move(restore_ipc_recorder)); + } + std::shared_ptr process; const Loader::ResultStatus load_result{app_loader->Load(process)}; if (Loader::ResultStatus::Success != load_result) { @@ -449,8 +509,7 @@ void System::Reschedule() { System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, Frontend::EmuWindow* secondary_window, - Kernel::MemoryMode memory_mode, - const Kernel::New3dsHwCapabilities& n3ds_hw_caps, u32 num_cores) { + Kernel::MemoryMode memory_mode, u32 num_cores) { LOG_DEBUG(HW_Memory, "initialized OK"); memory = std::make_unique(*this); @@ -459,7 +518,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, movie.GetOverrideBaseTicks()); kernel = std::make_unique( - *memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps, + *memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, movie.GetOverrideInitTime()); exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores); @@ -496,8 +555,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, dsp_core = std::make_unique(*this, multithread); } - memory->SetDSP(*dsp_core); - dsp_core->SetSink(Settings::values.output_type.GetValue(), Settings::values.output_device.GetValue()); dsp_core->EnableStretching(Settings::values.enable_audio_stretching.GetValue()); @@ -680,11 +737,15 @@ void System::Reset() { // This is needed as we don't currently support proper app jumping. if (auto apt = Service::APT::GetModule(*this)) { restore_deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg(); + restore_sys_menu_arg = apt->GetAppletManager()->GetSysMenuArg(); + restore_wireless_reboot_info = apt->GetWirelessRebootInfoBuffer(); } if (auto plg_ldr = Service::PLGLDR::GetService(*this)) { restore_plugin_context = plg_ldr->GetPluginLoaderContext(); } + restore_ipc_recorder = std::move(kernel->BackupIPCRecorder()); + Shutdown(); if (!m_chainloadpath.empty()) { @@ -752,6 +813,18 @@ void System::RegisterAppLoaderEarly(std::unique_ptr& loader) early_app_loader = std::move(loader); } +void System::InsertCartridge(const std::string& path) { + FileSys::NCCHContainer cartridge_container(path); + if (cartridge_container.LoadHeader() == Loader::ResultStatus::Success && + cartridge_container.IsNCSD()) { + inserted_cartridge = path; + } +} + +void System::EjectCartridge() { + inserted_cartridge.clear(); +} + bool System::IsInitialSetup() { return app_loader && app_loader->DoingInitialSetup(); } @@ -777,17 +850,19 @@ void System::serialize(Archive& ar, const unsigned int file_version) { } ar & lle_modules; + Kernel::MemoryMode mem_mode{}; + if (!Archive::is_loading::value) { + mem_mode = kernel->GetMemoryMode(); + } + ar & mem_mode; if (Archive::is_loading::value) { // When loading, we want to make sure any lingering state gets cleared out before we begin. // Shutdown, but persist a few things between loads... Shutdown(true); - // Re-initialize everything like it was before - auto memory_mode = this->app_loader->LoadKernelMemoryMode(); - auto n3ds_hw_caps = this->app_loader->LoadNew3dsHwCapabilities(); - [[maybe_unused]] const System::ResultStatus result = Init( - *m_emu_window, m_secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores); + [[maybe_unused]] const System::ResultStatus result = + Init(*m_emu_window, m_secondary_window, mem_mode, num_cores); } // Flush on save, don't flush on load @@ -819,22 +894,28 @@ void System::serialize(Archive& ar, const unsigned int file_version) { u32 cheats_pid; ar & cheats_pid; timing->UnlockEventQueue(); - memory->SetDSP(*dsp_core); cheat_engine.Connect(cheats_pid); + if (Settings::values.custom_textures) { + custom_tex_manager->FindCustomTextures(); + } + // Re-register gpu callback, because gsp service changed after service_manager got // serialized auto gsp = service_manager->GetService("gsp::Gpu"); gpu->SetInterruptHandler( [gsp](Service::GSP::InterruptId interrupt_id) { gsp->SignalInterrupt(interrupt_id); }); - // Switch the shader cache to the title running when the savestate was created + // Apply per program settings and switch the shader cache to the title running when the + // savestate was created. + // TODO(PabloMK7): Find better way to obtain the program ID. const u32 thread_id = gsp->GetActiveClientThreadId(); if (thread_id != std::numeric_limits::max()) { const auto thread = kernel->GetThreadByID(thread_id); if (thread) { const std::shared_ptr process = thread->owner_process.lock(); if (process) { + gpu->ApplyPerProgramSettings(process->codeset->program_id); gpu->Renderer().Rasterizer()->SwitchDiskResources(process->codeset->program_id); } } diff --git a/src/core/core.h b/src/core/core.h index 4ed8ff326..085a7b3b0 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -101,6 +101,7 @@ public: ErrorSystemFiles, ///< Error in finding system files ErrorSavestate, ///< Error saving or loading ErrorArticDisconnected, ///< Error when artic base disconnects + ErrorN3DSApplication, ///< Error launching New 3DS application in Old 3DS mode ShutdownRequested, ///< Emulated program requested a system shutdown ErrorUnknown ///< Any other error }; @@ -137,8 +138,9 @@ public: bool SendSignal(Signal signal, u32 param = 0); /// Request reset of the system - void RequestReset(const std::string& chainload = "") { + void RequestReset(const std::string& chainload = "", std::optional mem_mode = {}) { m_chainloadpath = chainload; + m_mem_mode = mem_mode; SendSignal(Signal::Reset); } @@ -374,6 +376,14 @@ public: void RegisterAppLoaderEarly(std::unique_ptr& loader); + void InsertCartridge(const std::string& path); + + void EjectCartridge(); + + const std::string& GetCartridge() const { + return inserted_cartridge; + } + bool IsInitialSetup(); private: @@ -386,9 +396,7 @@ private: */ [[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window, Frontend::EmuWindow* secondary_window, - Kernel::MemoryMode memory_mode, - const Kernel::New3dsHwCapabilities& n3ds_hw_caps, - u32 num_cores); + Kernel::MemoryMode memory_mode, u32 num_cores); /// Reschedule the core emulation void Reschedule(); @@ -399,6 +407,9 @@ private: // Temporary app loader passed from frontend std::unique_ptr early_app_loader; + /// Path for current inserted cartridge + std::string inserted_cartridge; + /// ARM11 CPU core std::vector> cpu_cores; ARM_Interface* running_core = nullptr; @@ -463,6 +474,7 @@ private: Frontend::EmuWindow* m_secondary_window; std::string m_filepath; std::string m_chainloadpath; + std::optional m_mem_mode; u64 title_id; bool self_delete_pending; @@ -474,7 +486,10 @@ private: bool mic_permission_granted = false; boost::optional restore_deliver_arg; + boost::optional restore_sys_menu_arg; boost::optional restore_plugin_context; + std::unique_ptr restore_ipc_recorder; + std::vector restore_wireless_reboot_info; std::vector lle_modules; diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp index fb0be5640..514a8736e 100644 --- a/src/core/file_sys/archive_ncch.cpp +++ b/src/core/file_sys/archive_ncch.cpp @@ -88,14 +88,31 @@ ResultVal> NCCHArchive::OpenFile(const Path& path, std::memcpy(&openfile_path, binary.data(), sizeof(NCCHFilePath)); std::string file_path; - if (Settings::values.is_new_3ds) { - // Try the New 3DS specific variant first. - file_path = Service::AM::GetTitleContentPath(media_type, title_id | 0x20000000, - openfile_path.content_index); - } - if (!Settings::values.is_new_3ds || !FileUtil::Exists(file_path)) { - file_path = - Service::AM::GetTitleContentPath(media_type, title_id, openfile_path.content_index); + + if (media_type == Service::FS::MediaType::GameCard) { + const auto& cartridge = Core::System::GetInstance().GetCartridge(); + if (cartridge.empty()) { + return ResultNotFound; + } + + u64 card_program_id; + auto cartridge_loader = Loader::GetLoader(cartridge); + FileSys::NCCHContainer cartridge_ncch(cartridge); + if (cartridge_ncch.ReadProgramId(card_program_id) != Loader::ResultStatus::Success || + card_program_id != title_id) { + return ResultNotFound; + } + file_path = cartridge; + } else { + if (Settings::values.is_new_3ds) { + // Try the New 3DS specific variant first. + file_path = Service::AM::GetTitleContentPath(media_type, title_id | 0x20000000, + openfile_path.content_index); + } + if (!Settings::values.is_new_3ds || !FileUtil::Exists(file_path)) { + file_path = + Service::AM::GetTitleContentPath(media_type, title_id, openfile_path.content_index); + } } auto ncch_container = NCCHContainer(file_path, 0, openfile_path.content_index); @@ -116,6 +133,15 @@ ResultVal> NCCHArchive::OpenFile(const Path& path, // Load NCCH .code or icon/banner/logo result = ncch_container.LoadSectionExeFS(openfile_path.exefs_filepath.data(), buffer); + if (result == Loader::ResultStatus::Success && Settings::values.apply_region_free_patch && + std::memcmp(openfile_path.exefs_filepath.data(), "icon", 4) == 0 && + buffer.size() >= sizeof(Loader::SMDH)) { + // Change the SMDH region lockout value to be region free + Loader::SMDH* smdh = reinterpret_cast(buffer.data()); + constexpr u32 REGION_LOCKOUT_REGION_FREE = 0x7FFFFFFF; + + smdh->region_lockout = REGION_LOCKOUT_REGION_FREE; + } std::unique_ptr delay_generator = std::make_unique(); file = std::make_unique(std::move(buffer), std::move(delay_generator)); } else { diff --git a/src/core/file_sys/ncch_container.cpp b/src/core/file_sys/ncch_container.cpp index 29232d4be..1438a766a 100644 --- a/src/core/file_sys/ncch_container.cpp +++ b/src/core/file_sys/ncch_container.cpp @@ -168,7 +168,6 @@ Loader::ResultStatus NCCHContainer::LoadHeader() { ASSERT(Loader::MakeMagic('N', 'C', 'S', 'D') == ncsd_header.magic); ASSERT(partition < 8); ncch_offset = ncsd_header.partitions[partition].offset * kBlockSize; - LOG_ERROR(Service_FS, "{}", ncch_offset); file->Seek(ncch_offset, SEEK_SET); file->ReadBytes(&ncch_header, sizeof(NCCH_Header)); } diff --git a/src/core/file_sys/plugin_3gx.cpp b/src/core/file_sys/plugin_3gx.cpp index fc7374d0b..f98e18a04 100644 --- a/src/core/file_sys/plugin_3gx.cpp +++ b/src/core/file_sys/plugin_3gx.cpp @@ -1,7 +1,9 @@ -// Copyright 2022 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +// Originally MIT-licensed code from The Pixellizer Group + // Copyright 2022 The Pixellizer Group // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and @@ -22,6 +24,7 @@ #include "core/file_sys/file_backend.h" #include "core/file_sys/plugin_3gx.h" #include "core/file_sys/plugin_3gx_bootloader.h" +#include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/vm_manager.h" #include "core/loader/loader.h" @@ -173,10 +176,10 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( } const std::array mem_region_sizes = { - 5 * 1024 * 1024, // 5 MiB - 2 * 1024 * 1024, // 2 MiB - 3 * 1024 * 1024, // 3 MiB - 4 * 1024 * 1024 // 4 MiB + 5 * 1024 * 1024, // 5 MiB + 2 * 1024 * 1024, // 2 MiB + 10 * 1024 * 1024, // 10 MiB + 5 * 1024 * 1024 // 5 MiB (reserved) }; const bool is_mem_private = header.infos.flags.use_private_memory != 0; @@ -184,65 +187,64 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( // Map memory block. This behaviour mimics how plugins are loaded on 3DS as much as possible. // Calculate the sizes of the different memory regions const u32 block_size = mem_region_sizes[header.infos.flags.memory_region_size.Value()]; + const u32 exe_offset = 0; const u32 exe_size = (sizeof(PluginHeader) + text_section.size() + rodata_section.size() + data_section.size() + header.executable.bss_size + 0x1000) & ~0xFFFu; + const u32 bootloader_offset = exe_offset + exe_size; + const u32 bootloader_size = bootloader_memory_size; + const u32 heap_offset = bootloader_offset + bootloader_size; + const u32 heap_size = block_size - heap_offset; - // Allocate the framebuffer block so that is in the highest FCRAM position possible - auto offset_fb = - kernel.GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->RLinearAllocate(_3GX_fb_size); - if (!offset_fb) { - LOG_ERROR(Service_PLGLDR, "Failed to load 3GX plugin. Not enough memory: {}", - plg_context.plugin_path); - return Loader::ResultStatus::ErrorMemoryAllocationFailed; + // Allocate a block of memory for the plugin + std::optional offset; + if (kernel.GetMemoryMode() == Kernel::MemoryMode::NewProd || + (plg_context.use_user_load_parameters && + plg_context.user_load_parameters.plugin_memory_strategy == + Service::PLGLDR::PLG_LDR::PluginMemoryStrategy::PLG_STRATEGY_MODE3)) { + // Allocate memory block from the end of the APPLICATION region + offset = + kernel.GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->RLinearAllocate(block_size); + + // If the reported available APP mem equals the actual size, remove the plugin block size. + if (offset) { + auto& config_mem = kernel.GetConfigMemHandler(); + if (config_mem.GetConfigMem().app_mem_alloc == + kernel.GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->size) { + config_mem.GetConfigMem().app_mem_alloc -= block_size; + } + } + plg_context.memory_region = Kernel::MemoryRegion::APPLICATION; + } else { + // Allocate memory block from the start of the SYSTEM region + offset = kernel.GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->LinearAllocate(block_size); + plg_context.memory_region = Kernel::MemoryRegion::SYSTEM; } - auto backing_memory_fb = kernel.memory.GetFCRAMRef(*offset_fb); - plg_ldr.SetPluginFBAddr(Memory::FCRAM_PADDR + *offset_fb); - std::fill(backing_memory_fb.GetPtr(), backing_memory_fb.GetPtr() + _3GX_fb_size, 0); - auto vma_heap_fb = process.vm_manager.MapBackingMemory( - _3GX_heap_load_addr, backing_memory_fb, _3GX_fb_size, - is_mem_private ? Kernel::MemoryState::Private : Kernel::MemoryState::Shared); - ASSERT(vma_heap_fb.Succeeded()); - process.vm_manager.Reprotect(vma_heap_fb.Unwrap(), Kernel::VMAPermission::ReadWrite); - - // Allocate a block from the end of FCRAM and clear it - auto offset = kernel.GetMemoryRegion(Kernel::MemoryRegion::SYSTEM) - ->RLinearAllocate(block_size - _3GX_fb_size); if (!offset) { - kernel.GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->Free(*offset_fb, _3GX_fb_size); LOG_ERROR(Service_PLGLDR, "Failed to load 3GX plugin. Not enough memory: {}", plg_context.plugin_path); return Loader::ResultStatus::ErrorMemoryAllocationFailed; } - auto backing_memory = kernel.memory.GetFCRAMRef(*offset); - std::fill(backing_memory.GetPtr(), backing_memory.GetPtr() + block_size - _3GX_fb_size, 0); - // Then we map part of the memory, which contains the executable - auto vma = process.vm_manager.MapBackingMemory(_3GX_exe_load_addr, backing_memory, exe_size, - is_mem_private ? Kernel::MemoryState::Private - : Kernel::MemoryState::Shared); - ASSERT(vma.Succeeded()); - process.vm_manager.Reprotect(vma.Unwrap(), Kernel::VMAPermission::ReadWriteExecute); + u32 fcram_offset = offset.value(); + + auto backing_memory_exe = kernel.memory.GetFCRAMRef(fcram_offset + exe_offset); + std::fill(backing_memory_exe.GetPtr(), backing_memory_exe.GetPtr() + exe_size, 0); + + // Map the executable + auto vma_exe = process.vm_manager.MapBackingMemory( + _3GX_exe_load_addr, backing_memory_exe, exe_size, + is_mem_private ? Kernel::MemoryState::Private : Kernel::MemoryState::Shared); + ASSERT(vma_exe.Succeeded()); + process.vm_manager.Reprotect(vma_exe.Unwrap(), Kernel::VMAPermission::ReadWriteExecute); - // Write text section - kernel.memory.WriteBlock(process, _3GX_exe_load_addr + sizeof(PluginHeader), - text_section.data(), header.executable.code_size); - // Write rodata section - kernel.memory.WriteBlock( - process, _3GX_exe_load_addr + sizeof(PluginHeader) + header.executable.code_size, - rodata_section.data(), header.executable.rodata_size); - // Write data section - kernel.memory.WriteBlock(process, - _3GX_exe_load_addr + sizeof(PluginHeader) + - header.executable.code_size + header.executable.rodata_size, - data_section.data(), header.executable.data_size); // Prepare plugin header and write it PluginHeader plugin_header = {0}; plugin_header.version = header.version; plugin_header.exe_size = exe_size; plugin_header.heap_VA = _3GX_heap_load_addr; - plugin_header.heap_size = block_size - exe_size; + plugin_header.heap_size = heap_size; plg_context.plg_event = _3GX_exe_load_addr - 0x4; plg_context.plg_reply = _3GX_exe_load_addr - 0x8; plugin_header.plgldr_event = plg_context.plg_event; @@ -254,39 +256,46 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( } kernel.memory.WriteBlock(process, _3GX_exe_load_addr, &plugin_header, sizeof(PluginHeader)); - // Map plugin heap - auto backing_memory_heap = kernel.memory.GetFCRAMRef(*offset + exe_size); + // Write text section + kernel.memory.WriteBlock(process, _3GX_exe_load_addr + sizeof(PluginHeader), + text_section.data(), header.executable.code_size); + // Write rodata section + kernel.memory.WriteBlock( + process, _3GX_exe_load_addr + sizeof(PluginHeader) + header.executable.code_size, + rodata_section.data(), header.executable.rodata_size); - // Map the rest of the memory at the heap location - auto vma_heap = process.vm_manager.MapBackingMemory( - _3GX_heap_load_addr + _3GX_fb_size, backing_memory_heap, - block_size - exe_size - _3GX_fb_size, - is_mem_private ? Kernel::MemoryState::Private : Kernel::MemoryState::Shared); - ASSERT(vma_heap.Succeeded()); - process.vm_manager.Reprotect(vma_heap.Unwrap(), Kernel::VMAPermission::ReadWriteExecute); + // Write data section + kernel.memory.WriteBlock(process, + _3GX_exe_load_addr + sizeof(PluginHeader) + + header.executable.code_size + header.executable.rodata_size, + data_section.data(), header.executable.data_size); - // Allocate a block from the end of FCRAM and clear it - auto bootloader_offset = kernel.GetMemoryRegion(Kernel::MemoryRegion::SYSTEM) - ->RLinearAllocate(bootloader_memory_size); - if (!bootloader_offset) { - kernel.GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->Free(*offset_fb, _3GX_fb_size); - kernel.GetMemoryRegion(Kernel::MemoryRegion::SYSTEM) - ->Free(*offset, block_size - _3GX_fb_size); - LOG_ERROR(Service_PLGLDR, "Failed to load 3GX plugin. Not enough memory: {}", - plg_context.plugin_path); - return Loader::ResultStatus::ErrorMemoryAllocationFailed; - } + // Map bootloader const bool use_internal = plg_context.load_exe_func.empty(); MapBootloader( - process, kernel, *bootloader_offset, + process, kernel, fcram_offset + bootloader_offset, (use_internal) ? exe_load_func : plg_context.load_exe_func, (use_internal) ? exe_load_args : plg_context.load_exe_args, header.executable.code_size + header.executable.rodata_size + header.executable.data_size, header.infos.exe_load_checksum, plg_context.use_user_load_parameters ? plg_context.user_load_parameters.no_flash : 0); + // Map plugin heap + auto backing_memory_heap = kernel.memory.GetFCRAMRef(fcram_offset + heap_offset); + std::fill(backing_memory_heap.GetPtr(), backing_memory_heap.GetPtr() + heap_size, 0); + + auto vma_heap = process.vm_manager.MapBackingMemory( + _3GX_heap_load_addr, backing_memory_heap, heap_size, + is_mem_private ? Kernel::MemoryState::Private : Kernel::MemoryState::Shared); + ASSERT(vma_heap.Succeeded()); + process.vm_manager.Reprotect(vma_heap.Unwrap(), Kernel::VMAPermission::ReadWriteExecute); + + kernel.memory.Plugin3GXFramebufferAddress() = Memory::FCRAM_PADDR + fcram_offset + heap_offset; plg_context.plugin_loaded = true; + plg_context.plugin_process_id = process.process_id; plg_context.use_user_load_parameters = false; + plg_context.memory_block = {fcram_offset, block_size}; + return Loader::ResultStatus::Success; } @@ -355,7 +364,7 @@ void FileSys::Plugin3GXLoader::MapBootloader(Kernel::Process& process, Kernel::K std::fill(backing_memory.GetPtr(), backing_memory.GetPtr() + bootloader_memory_size, 0); auto vma = process.vm_manager.MapBackingMemory(_3GX_exe_load_addr - bootloader_memory_size, backing_memory, bootloader_memory_size, - Kernel::MemoryState::Continuous); + Kernel::MemoryState::Private); ASSERT(vma.Succeeded()); process.vm_manager.Reprotect(vma.Unwrap(), Kernel::VMAPermission::ReadWriteExecute); diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 70658cf29..3216a1675 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -25,9 +25,8 @@ public: std::mutex mutex; bool touch_pressed = false; ///< True if touchpad area is currently pressed, otherwise false - - float touch_x = 0.0f; ///< Touchpad X-position - float touch_y = 0.0f; ///< Touchpad Y-position + float touch_x = 0.0f; ///< Touchpad X-position + float touch_y = 0.0f; ///< Touchpad Y-position private: class Device : public Input::TouchDevice { @@ -56,20 +55,44 @@ EmuWindow::EmuWindow(bool is_secondary_) : is_secondary{is_secondary_} { EmuWindow::~EmuWindow() = default; +Settings::StereoRenderOption EmuWindow::get3DMode() const { + Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue(); +#ifndef ANDROID + // on desktop, if separate windows and this is the bottom screen, then no stereo + if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows && + ((!is_secondary && Settings::values.swap_screen.GetValue()) || + (is_secondary && !Settings::values.swap_screen.GetValue()))) { + render_3d_mode = Settings::StereoRenderOption::Off; + } +#else + // adjust the StereoRenderOption setting to Off if appropriate on mobile + Settings::StereoWhichDisplay whichDisplay = Settings::values.render_3d_which_display.GetValue(); + if (whichDisplay == Settings::StereoWhichDisplay::None || + whichDisplay == Settings::StereoWhichDisplay::PrimaryOnly && is_secondary || + whichDisplay == Settings::StereoWhichDisplay::SecondaryOnly && !is_secondary) { + render_3d_mode = Settings::StereoRenderOption::Off; + } +#endif + return render_3d_mode; +} + bool EmuWindow::IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigned framebuffer_x, unsigned framebuffer_y) { #ifndef ANDROID // If separate windows and the touch is in the primary (top) screen, ignore it. if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows && - !is_secondary && !Settings::values.swap_screen.GetValue()) { + ((!is_secondary && !Settings::values.swap_screen.GetValue()) || + (is_secondary && Settings::values.swap_screen.GetValue()))) { return false; } #endif + Settings::StereoRenderOption render_3d_mode = get3DMode(); - Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue(); - - if (render_3d_mode == Settings::StereoRenderOption::SideBySide || - render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) { + if (framebuffer_x > layout.width / 2 && + render_3d_mode == Settings::StereoRenderOption::SideBySideFull) { + framebuffer_x = static_cast(framebuffer_x - layout.width / 2); + } + if (render_3d_mode == Settings::StereoRenderOption::SideBySide) { return (framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom && ((framebuffer_x >= layout.bottom_screen.left / 2 && @@ -93,25 +116,19 @@ bool EmuWindow::IsWithinTouchscreen(const Layout::FramebufferLayout& layout, uns } std::tuple EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) const { - Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue(); - bool separate_win = false; -#ifndef ANDROID - separate_win = - (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows); -#endif + + Settings::StereoRenderOption render_3d_mode = get3DMode(); if (new_x >= framebuffer_layout.width / 2) { - if ((render_3d_mode == Settings::StereoRenderOption::SideBySide || - render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) && - !separate_win) + if (render_3d_mode == Settings::StereoRenderOption::SideBySide || + render_3d_mode == Settings::StereoRenderOption::SideBySideFull) new_x -= framebuffer_layout.width / 2; else if (render_3d_mode == Settings::StereoRenderOption::CardboardVR) new_x -= (framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2); } - if ((render_3d_mode == Settings::StereoRenderOption::SideBySide || - render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) && - !separate_win) { + + if (render_3d_mode == Settings::StereoRenderOption::SideBySide) { new_x = std::max(new_x, framebuffer_layout.bottom_screen.left / 2); new_x = std::min(new_x, framebuffer_layout.bottom_screen.right / 2 - 1); } else { @@ -136,29 +153,22 @@ void EmuWindow::CreateTouchState() { } bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { - Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue(); - bool separate_win = false; -#ifndef ANDROID - separate_win = - (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows); -#endif - if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) return false; + Settings::StereoRenderOption render_3d_mode = get3DMode(); if (framebuffer_x >= framebuffer_layout.width / 2) { - if ((render_3d_mode == Settings::StereoRenderOption::SideBySide || - render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) && - !separate_win) + if (render_3d_mode == Settings::StereoRenderOption::SideBySide || + render_3d_mode == Settings::StereoRenderOption::SideBySideFull) framebuffer_x -= framebuffer_layout.width / 2; else if (render_3d_mode == Settings::StereoRenderOption::CardboardVR) framebuffer_x -= (framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2); } + std::scoped_lock guard(touch_state->mutex); - if ((render_3d_mode == Settings::StereoRenderOption::SideBySide || - render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) && - !separate_win) { + + if (render_3d_mode == Settings::StereoRenderOption::SideBySide) { touch_state->touch_x = static_cast(framebuffer_x - framebuffer_layout.bottom_screen.left / 2) / (framebuffer_layout.bottom_screen.right / 2 - @@ -200,8 +210,13 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_portrait_mode) { Layout::FramebufferLayout layout; - const Settings::LayoutOption layout_option = Settings::values.layout_option.GetValue(); + const Settings::StereoRenderOption stereo_option = get3DMode(); + bool render_full_stereo = (stereo_option == Settings::StereoRenderOption::SideBySideFull); + bool is_bottom = is_secondary; + if (Settings::values.swap_screen.GetValue()) + is_bottom = !is_bottom; + const Settings::PortraitLayoutOption portrait_layout_option = Settings::values.portrait_layout_option.GetValue(); const auto min_size = is_portrait_mode @@ -211,6 +226,9 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po width = std::max(width, min_size.first); height = std::max(height, min_size.second); + if (render_full_stereo) { + width = width / 2; + } if (is_portrait_mode) { switch (portrait_layout_option) { case Settings::PortraitLayoutOption::PortraitTopFullWidth: @@ -271,11 +289,21 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po break; } } +#ifdef ANDROID + if (is_secondary) { + layout = Layout::AndroidSecondaryLayout(width, height); + } +#endif + + if (render_full_stereo) { + layout.width = width * 2; + } UpdateMinimumWindowSize(min_size); if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) { layout = Layout::GetCardboardSettings(layout); } + layout.render_3d_mode = stereo_option; NotifyFramebufferLayoutChanged(layout); } diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 2752a3263..d5b7803cc 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -254,6 +254,11 @@ public: bool is_portrait_mode = {}); std::unique_ptr mailbox = nullptr; + bool isSecondary() const { + return is_secondary; + } + + Settings::StereoRenderOption get3DMode() const; protected: EmuWindow(); diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index a347053fd..392db8867 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -172,7 +172,7 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr emulation_height = std::max(large_height, small_height); } - const float window_aspect_ratio = static_cast(height) / width; + const float window_aspect_ratio = static_cast(height) / static_cast(width); const float emulation_aspect_ratio = emulation_height / emulation_width; Common::Rectangle screen_window_area{0, 0, width, height}; @@ -281,7 +281,7 @@ FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool u // Split the window into two parts. Give 2.25x width to the main screen, // and make a bar on the right side with 1x width top screen and 1.25x width bottom screen // To do that, find the total emulation box and maximize that based on window size - const float window_aspect_ratio = static_cast(height) / width; + const float window_aspect_ratio = static_cast(height) / static_cast(width); const float scale_factor = 2.25f; float main_screen_aspect_ratio = TOP_SCREEN_ASPECT_RATIO; @@ -338,6 +338,24 @@ FramebufferLayout SeparateWindowsLayout(u32 width, u32 height, bool is_secondary return SingleFrameLayout(width, height, is_secondary, upright); } +FramebufferLayout AndroidSecondaryLayout(u32 width, u32 height) { + const Settings::SecondaryDisplayLayout layout = + Settings::values.secondary_display_layout.GetValue(); + switch (layout) { + + case Settings::SecondaryDisplayLayout::BottomScreenOnly: + return SingleFrameLayout(width, height, true, Settings::values.upright_screen.GetValue()); + case Settings::SecondaryDisplayLayout::SideBySide: + return LargeFrameLayout(width, height, false, Settings::values.upright_screen.GetValue(), + 1.0f, Settings::SmallScreenPosition::MiddleRight); + case Settings::SecondaryDisplayLayout::None: + // this should never happen, but if it does, somehow, send the top screen + case Settings::SecondaryDisplayLayout::TopScreenOnly: + default: + return SingleFrameLayout(width, height, false, Settings::values.upright_screen.GetValue()); + } +} + FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool is_portrait_mode) { ASSERT(width > 0); ASSERT(height > 0); @@ -347,6 +365,12 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool } FramebufferLayout res{ width, height, true, true, {}, {}, !Settings::values.upright_screen, is_portrait_mode}; + float opacity_value = Settings::values.custom_second_layer_opacity.GetValue() / 100.0f; + + if (!is_portrait_mode && opacity_value < 1) { + is_swapped ? res.top_opacity = opacity_value : res.bottom_opacity = opacity_value; + } + const u16 top_x = is_portrait_mode ? Settings::values.custom_portrait_top_x.GetValue() : Settings::values.custom_top_x.GetValue(); const u16 top_width = is_portrait_mode ? Settings::values.custom_portrait_top_width.GetValue() @@ -389,53 +413,56 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar bool is_portrait) { u32 width, height, gap; gap = (int)(Settings::values.screen_gap.GetValue()) * res_scale; + + FramebufferLayout layout; if (is_portrait) { auto layout_option = Settings::values.portrait_layout_option.GetValue(); switch (layout_option) { case Settings::PortraitLayoutOption::PortraitCustomLayout: - return CustomFrameLayout( - std::max(Settings::values.custom_portrait_top_x.GetValue() + - Settings::values.custom_portrait_top_width.GetValue(), - Settings::values.custom_portrait_bottom_x.GetValue() + - Settings::values.custom_portrait_bottom_width.GetValue()), - std::max(Settings::values.custom_portrait_top_y.GetValue() + - Settings::values.custom_portrait_top_height.GetValue(), - Settings::values.custom_portrait_bottom_y.GetValue() + - Settings::values.custom_portrait_bottom_height.GetValue()), - Settings::values.swap_screen.GetValue(), is_portrait); + width = std::max(Settings::values.custom_portrait_top_x.GetValue() + + Settings::values.custom_portrait_top_width.GetValue(), + Settings::values.custom_portrait_bottom_x.GetValue() + + Settings::values.custom_portrait_bottom_width.GetValue()); + height = std::max(Settings::values.custom_portrait_top_y.GetValue() + + Settings::values.custom_portrait_top_height.GetValue(), + Settings::values.custom_portrait_bottom_y.GetValue() + + Settings::values.custom_portrait_bottom_height.GetValue()); + layout = CustomFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + is_portrait); + + break; case Settings::PortraitLayoutOption::PortraitTopFullWidth: width = Core::kScreenTopWidth * res_scale; // clang-format off height = (static_cast(Core::kScreenTopHeight + Core::kScreenBottomHeight * 1.25) * res_scale) + gap; // clang-format on - return PortraitTopFullFrameLayout(width, height, - Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); + layout = + PortraitTopFullFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue()); + break; case Settings::PortraitLayoutOption::PortraitOriginal: width = Core::kScreenTopWidth * res_scale; height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; - return PortraitOriginalLayout(width, height, Settings::values.swap_screen.GetValue()); + layout = PortraitOriginalLayout(width, height, Settings::values.swap_screen.GetValue()); + break; } } else { auto layout_option = Settings::values.layout_option.GetValue(); switch (layout_option) { case Settings::LayoutOption::CustomLayout: - return CustomFrameLayout(std::max(Settings::values.custom_top_x.GetValue() + - Settings::values.custom_top_width.GetValue(), - Settings::values.custom_bottom_x.GetValue() + - Settings::values.custom_bottom_width.GetValue()), - std::max(Settings::values.custom_top_y.GetValue() + - Settings::values.custom_top_height.GetValue(), - Settings::values.custom_bottom_y.GetValue() + - Settings::values.custom_bottom_height.GetValue()), - Settings::values.swap_screen.GetValue(), is_portrait); - - case Settings::LayoutOption::SingleScreen: -#ifndef ANDROID - case Settings::LayoutOption::SeparateWindows: -#endif - { + layout = + CustomFrameLayout(std::max(Settings::values.custom_top_x.GetValue() + + Settings::values.custom_top_width.GetValue(), + Settings::values.custom_bottom_x.GetValue() + + Settings::values.custom_bottom_width.GetValue()), + std::max(Settings::values.custom_top_y.GetValue() + + Settings::values.custom_top_height.GetValue(), + Settings::values.custom_bottom_y.GetValue() + + Settings::values.custom_bottom_height.GetValue()), + Settings::values.swap_screen.GetValue(), is_portrait); + break; + case Settings::LayoutOption::SingleScreen: { const bool swap_screens = is_secondary || Settings::values.swap_screen.GetValue(); if (swap_screens) { width = Core::kScreenBottomWidth * res_scale; @@ -447,8 +474,10 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar if (Settings::values.upright_screen.GetValue()) { std::swap(width, height); } - return SingleFrameLayout(width, height, swap_screens, - Settings::values.upright_screen.GetValue()); + + layout = SingleFrameLayout(width, height, swap_screens, + Settings::values.upright_screen.GetValue()); + break; } case Settings::LayoutOption::LargeScreen: { @@ -477,10 +506,11 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar if (Settings::values.upright_screen.GetValue()) { std::swap(width, height); } - return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue(), - Settings::values.large_screen_proportion.GetValue(), - Settings::values.small_screen_position.GetValue()); + layout = LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue(), + Settings::values.large_screen_proportion.GetValue(), + Settings::values.small_screen_position.GetValue()); + break; } case Settings::LayoutOption::SideScreen: width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale + gap; @@ -489,10 +519,10 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar if (Settings::values.upright_screen.GetValue()) { std::swap(width, height); } - return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue(), 1, - Settings::SmallScreenPosition::MiddleRight); - + layout = LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue(), 1, + Settings::SmallScreenPosition::MiddleRight); + break; case Settings::LayoutOption::HybridScreen: height = Core::kScreenTopHeight * res_scale; @@ -508,9 +538,9 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar std::swap(width, height); } - return HybridScreenLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); - + layout = HybridScreenLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue()); + break; case Settings::LayoutOption::Default: default: width = Core::kScreenTopWidth * res_scale; @@ -519,10 +549,13 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar if (Settings::values.upright_screen.GetValue()) { std::swap(width, height); } - return DefaultFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); + layout = DefaultFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue()); + break; } } + + return layout; UNREACHABLE(); } diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 6e4dc45a8..1d15e2c89 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -35,6 +35,8 @@ struct FramebufferLayout { bool is_rotated = true; bool is_portrait = false; bool additional_screen_enabled; + float top_opacity = 1.0f; + float bottom_opacity = 1.0f; Common::Rectangle additional_screen; CardboardSettings cardboard; @@ -46,6 +48,8 @@ struct FramebufferLayout { u32 GetScalingRatio() const; static float GetAspectRatioValue(Settings::AspectRatio aspect_ratio); + + Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue(); }; /** @@ -133,6 +137,14 @@ FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool u */ FramebufferLayout SeparateWindowsLayout(u32 width, u32 height, bool is_secondary, bool upright); +/** + * Method for constructing the secondary layout for Android, based on + * the appropriate setting. + * @param width Window framebuffer width in pixels + * @param height Window framebuffer height in pixels + */ +FramebufferLayout AndroidSecondaryLayout(u32 width, u32 height); + /** * Factory method for constructing a custom FramebufferLayout * @param width Window framebuffer width in pixels diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index c722b8e30..21ca655db 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -7,6 +7,7 @@ #include #include "common/archives.h" #include "common/serialization/atomic.h" +#include "common/settings.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/handle_table.h" @@ -26,14 +27,13 @@ namespace Kernel { /// Initialize the kernel KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, std::function prepare_reschedule_callback, - MemoryMode memory_mode, u32 num_cores, - const New3dsHwCapabilities& n3ds_hw_caps, u64 override_init_time) + MemoryMode memory_mode, u32 num_cores, u64 override_init_time) : memory(memory), timing(timing), - prepare_reschedule_callback(std::move(prepare_reschedule_callback)), memory_mode(memory_mode), - n3ds_hw_caps(n3ds_hw_caps) { + prepare_reschedule_callback(std::move(prepare_reschedule_callback)), + memory_mode(memory_mode) { std::generate(memory_regions.begin(), memory_regions.end(), [] { return std::make_shared(); }); - MemoryInit(memory_mode, n3ds_hw_caps.memory_mode, override_init_time); + MemoryInit(memory_mode, override_init_time); resource_limits = std::make_unique(*this); for (u32 core_id = 0; core_id < num_cores; ++core_id) { @@ -151,6 +151,14 @@ const IPCDebugger::Recorder& KernelSystem::GetIPCRecorder() const { return *ipc_recorder; } +std::unique_ptr KernelSystem::BackupIPCRecorder() { + return std::move(ipc_recorder); +} + +void KernelSystem::RestoreIPCRecorder(std::unique_ptr recorder) { + ipc_recorder = std::move(recorder); +} + void KernelSystem::AddNamedPort(std::string name, std::shared_ptr port) { named_ports.emplace(std::move(name), std::move(port)); } @@ -163,6 +171,37 @@ void KernelSystem::ResetThreadIDs() { next_thread_id = 0; } +void KernelSystem::UpdateCPUAndMemoryState(u64 title_id, MemoryMode memory_mode, + New3dsHwCapabilities n3ds_hw_cap) { + if (Settings::values.is_new_3ds) { + SetRunning804MHz(n3ds_hw_cap.enable_804MHz_cpu); + } + + u32 tid_high = static_cast(title_id >> 32); + + constexpr u32 TID_HIGH_APPLET = 0x00040030; + constexpr u32 TID_HIGH_SYSMODULE = 0x00040130; + + // PM only updates the reported memory for normal applications. + // TODO(PabloMK7): Using the title ID is not correct, but close enough. + if (tid_high != TID_HIGH_APPLET && tid_high != TID_HIGH_SYSMODULE) { + UpdateReportedMemory(memory_mode, n3ds_hw_cap.memory_mode); + } +} + +void KernelSystem::RestoreMemoryState(u64 title_id) { + u32 tid_high = static_cast(title_id >> 32); + + constexpr u32 TID_HIGH_APPLET = 0x00040030; + constexpr u32 TID_HIGH_SYSMODULE = 0x00040130; + + // PM only updates the reported memory for normal applications. + // TODO(PabloMK7): Using the title ID is not correct, but close enough. + if (tid_high != TID_HIGH_APPLET && tid_high != TID_HIGH_SYSMODULE) { + RestoreReportedMemory(); + } +} + template void KernelSystem::serialize(Archive& ar, const unsigned int) { ar & memory_regions; @@ -184,7 +223,7 @@ void KernelSystem::serialize(Archive& ar, const unsigned int) { ar & stored_processes; ar & next_thread_id; ar & memory_mode; - ar & n3ds_hw_caps; + ar & running_804MHz; ar & main_thread_extended_sleep; // Deliberately don't include debugger info to allow debugging through loads diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d3b0bc53e..53d88cddf 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -111,6 +111,9 @@ enum class MemoryMode : u8 { Dev2 = 3, ///< 80MB app memory Dev3 = 4, ///< 72MB app memory Dev4 = 5, ///< 32MB app memory + + NewProd = 6, ///< 124MB app memory + NewDev1 = 7, ///< 178MB app memory }; /// New 3DS memory modes. @@ -137,8 +140,7 @@ class KernelSystem { public: explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, std::function prepare_reschedule_callback, MemoryMode memory_mode, - u32 num_cores, const New3dsHwCapabilities& n3ds_hw_caps, - u64 override_init_time = 0); + u32 num_cores, u64 override_init_time = 0); ~KernelSystem(); using PortPair = std::pair, std::shared_ptr>; @@ -305,6 +307,8 @@ public: IPCDebugger::Recorder& GetIPCRecorder(); const IPCDebugger::Recorder& GetIPCRecorder() const; + std::unique_ptr BackupIPCRecorder(); + void RestoreIPCRecorder(std::unique_ptr recorder); std::shared_ptr GetMemoryRegion(MemoryRegion region); @@ -327,8 +331,12 @@ public: return memory_mode; } - const New3dsHwCapabilities& GetNew3dsHwCapabilities() const { - return n3ds_hw_caps; + void SetRunning804MHz(bool enable) { + running_804MHz = enable; + } + + bool GetRunning804MHz() const { + return running_804MHz; } std::recursive_mutex& GetHLELock() { @@ -365,8 +373,16 @@ public: return pending_async_operations != 0; } + void UpdateCPUAndMemoryState(u64 title_id, MemoryMode memory_mode, + New3dsHwCapabilities n3ds_hw_cap); + + void RestoreMemoryState(u64 title_id); + private: - void MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode, u64 override_init_time); + void MemoryInit(MemoryMode memory_mode, u64 override_init_time); + + void UpdateReportedMemory(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode); + void RestoreReportedMemory(); std::function prepare_reschedule_callback; @@ -404,7 +420,7 @@ private: u32 next_thread_id; MemoryMode memory_mode; - New3dsHwCapabilities n3ds_hw_caps; + bool running_804MHz = false; /* * Synchronizes access to the internal HLE kernel structures, it is acquired when a guest diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index fffa8dd6f..362e88ac5 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -41,23 +41,9 @@ static const u32 memory_region_sizes[8][3] = { {0x0B200000, 0x02E00000, 0x02000000}, // 7 }; -void KernelSystem::MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode, - u64 override_init_time) { +void KernelSystem::MemoryInit(MemoryMode memory_mode, u64 override_init_time) { const bool is_new_3ds = Settings::values.is_new_3ds.GetValue(); - u32 mem_type_index = static_cast(memory_mode); - u32 reported_mem_type = static_cast(memory_mode); - if (is_new_3ds) { - if (n3ds_mode == New3dsMemoryMode::NewProd || n3ds_mode == New3dsMemoryMode::NewDev2) { - mem_type_index = 6; - reported_mem_type = 6; - } else if (n3ds_mode == New3dsMemoryMode::NewDev1) { - mem_type_index = 7; - reported_mem_type = 7; - } else { - // On the N3ds, all O3ds configurations (<=5) are forced to 6 instead. - mem_type_index = 6; - } - } + const u32 mem_type_index = static_cast(memory_mode); // The kernel allocation regions (APPLICATION, SYSTEM and BASE) are laid out in sequence, with // the sizes specified in the memory_region_sizes table. @@ -73,14 +59,41 @@ void KernelSystem::MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode config_mem_handler = std::make_shared(); auto& config_mem = config_mem_handler->GetConfigMem(); - config_mem.app_mem_type = reported_mem_type; - config_mem.app_mem_alloc = memory_region_sizes[reported_mem_type][0]; + config_mem.app_mem_type = static_cast(memory_mode); + config_mem.app_mem_alloc = memory_regions[0]->size; config_mem.sys_mem_alloc = memory_regions[1]->size; config_mem.base_mem_alloc = memory_regions[2]->size; shared_page_handler = std::make_shared(timing, override_init_time); } +void KernelSystem::UpdateReportedMemory(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode) { + // If we are in New 3DS prod memory mode, and the application n3ds memory mode is set to legacy + // (all Old 3DS applications), then update reported available memory to the proper one according + // to the memory mode. + // This is normally done by PM when launching applications using svcSetResourceLimitLimitValues, + // but we do not implement that. + if (GetMemoryMode() == Kernel::MemoryMode::NewProd && + n3ds_mode == Kernel::New3dsMemoryMode::Legacy) { + const u32 mem_type_index = static_cast(memory_mode); + auto& config_mem = config_mem_handler->GetConfigMem(); + config_mem.app_mem_alloc = memory_region_sizes[mem_type_index][0]; + } +} + +void KernelSystem::RestoreReportedMemory() { + // If we are on New 3DS prod memory mode and we have terminated a process, restore the available + // memory to the proper size. + // This is normally done by PM when the application ends using svcSetResourceLimitLimitValues, + // but we do not implement that. + auto mem_mode = GetMemoryMode(); + if (mem_mode == Kernel::MemoryMode::NewProd) { + const u32 mem_type_index = static_cast(mem_mode); + auto& config_mem = config_mem_handler->GetConfigMem(); + config_mem.app_mem_alloc = memory_region_sizes[mem_type_index][0]; + } +} + std::shared_ptr KernelSystem::GetMemoryRegion(MemoryRegion region) { switch (region) { case MemoryRegion::APPLICATION: diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index e4200e5df..5e0d3810f 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -124,6 +124,8 @@ void KernelSystem::TerminateProcess(std::shared_ptr process) { GetThreadManager(core).TerminateProcessThreads(process); } + RestoreMemoryState(process->codeset->program_id); + process->Exit(); std::erase(process_list, process); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c0bd6540b..58530f494 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -119,6 +119,11 @@ enum class SystemInfoType { * For the ARM11 NATIVE_FIRM kernel, this is 5, for processes sm, fs, pm, loader, and pxi." */ KERNEL_SPAWNED_PIDS = 26, + /** + * Check various Luma3DS config values. This parameter is not available on real systems, + * but can be used by homebrew applications. + */ + LUMA_CFW_INFO = 0x10000, /** * Check if the current system is a new 3DS. This parameter is not available on real systems, * but can be used by homebrew applications. @@ -270,6 +275,13 @@ enum class SystemInfoMemUsageRegion { BASE = 3, }; +enum class SystemInfoLumaCFWInformation { + REAL_APP_REGION_SIZE = 0x80, // Gets the real APPLICATION region size, + // instead of the one reported by the kernel shared page + // which depends on the memory mode. + IS_N3DS = 0x201, // Checks if the system is a N3DS or not. +}; + /** * Accepted by svcGetSystemInfo param with CITRA_INFORMATION type. Selects which information * to fetch from Citra. Some string params don't fit in 7 bytes, so they are split. @@ -1827,6 +1839,20 @@ Result SVC::GetSystemInfo(s64* out, u32 type, s32 param) { case SystemInfoType::KERNEL_SPAWNED_PIDS: *out = 5; break; + case SystemInfoType::LUMA_CFW_INFO: + switch ((SystemInfoLumaCFWInformation)param) { + case SystemInfoLumaCFWInformation::REAL_APP_REGION_SIZE: + *out = kernel.GetMemoryRegion(MemoryRegion::APPLICATION)->size; + break; + case SystemInfoLumaCFWInformation::IS_N3DS: + *out = Settings::values.is_new_3ds ? 1 : 0; + break; + default: + LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=0x10000 region: param={}", param); + *out = 0; + break; + } + break; case SystemInfoType::NEW_3DS_INFO: // The actual subtypes are not implemented, homebrew just check // this doesn't return an error in n3ds to know the system type diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 7dd42cecc..645a015b6 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -850,22 +850,30 @@ bool CIAFile::Close() { current_content_install_result.type = InstallResult::Type::NONE; } - bool complete = - from_cdn ? is_done - : (install_state >= CIAInstallState::TMDLoaded && - content_written.size() == container.GetTitleMetadata().GetContentCount() && - std::all_of(content_written.begin(), content_written.end(), - [this, i = 0](auto& bytes_written) mutable { - return bytes_written >= - container.GetContentSize(static_cast(i++)); - })); + bool complete; + + if (is_cancel) { + complete = false; + } else { + complete = + from_cdn ? is_done + : (install_state >= CIAInstallState::TMDLoaded && + content_written.size() == container.GetTitleMetadata().GetContentCount() && + std::all_of(content_written.begin(), content_written.end(), + [this, i = 0](auto& bytes_written) mutable { + return bytes_written >= + container.GetContentSize(static_cast(i++)); + })); + } // Install aborted if (!complete) { - LOG_ERROR(Service_AM, "CIAFile closed prematurely, aborting install..."); + LOG_ERROR(Service_AM, "CIAFile closed prematurely or cancelled, aborting install..."); if (!is_additional_content) { - FileUtil::DeleteDirRecursively( - GetTitlePath(media_type, container.GetTitleMetadata().GetTitleID())); + // Only delete the content folder as there may be user save data in the title folder. + const std::string title_content_path = + GetTitlePath(media_type, container.GetTitleMetadata().GetTitleID()) + "content/"; + FileUtil::DeleteDirRecursively(title_content_path); } return true; } @@ -1277,7 +1285,7 @@ std::string GetTitleContentPath(Service::FS::MediaType media_type, u64 tid, std: auto fs_user = Core::System::GetInstance().ServiceManager().GetService( "fs:USER"); - return fs_user->GetCurrentGamecardPath(); + return fs_user->GetRegisteredGamecardPath(); } std::string content_path = GetTitlePath(media_type, tid) + "content/"; @@ -1322,7 +1330,7 @@ std::string GetTitlePath(Service::FS::MediaType media_type, u64 tid) { auto fs_user = Core::System::GetInstance().ServiceManager().GetService( "fs:USER"); - return fs_user->GetCurrentGamecardPath(); + return fs_user->GetRegisteredGamecardPath(); } return ""; @@ -1343,7 +1351,7 @@ std::string GetMediaTitlePath(Service::FS::MediaType media_type) { auto fs_user = Core::System::GetInstance().ServiceManager().GetService( "fs:USER"); - return fs_user->GetCurrentGamecardPath(); + return fs_user->GetRegisteredGamecardPath(); } return ""; @@ -1406,39 +1414,52 @@ void Module::ScanForTitlesImpl(Service::FS::MediaType media_type) { LOG_DEBUG(Service_AM, "Starting title scan for media_type={}", static_cast(media_type)); - std::string title_path = GetMediaTitlePath(media_type); - - FileUtil::FSTEntry entries; - FileUtil::ScanDirectoryTree(title_path, entries, 1, &stop_scan_flag); - for (const FileUtil::FSTEntry& tid_high : entries.children) { - if (stop_scan_flag) { - break; + if (media_type == FS::MediaType::GameCard) { + const auto& cartridge = system.GetCartridge(); + if (!cartridge.empty()) { + u64 program_id = 0; + FileSys::NCCHContainer cartridge_ncch(cartridge); + Loader::ResultStatus res = cartridge_ncch.ReadProgramId(program_id); + if (res == Loader::ResultStatus::Success) { + am_title_list[static_cast(media_type)].push_back(program_id); + } } - for (const FileUtil::FSTEntry& tid_low : tid_high.children) { + } else { + std::string title_path = GetMediaTitlePath(media_type); + + FileUtil::FSTEntry entries; + FileUtil::ScanDirectoryTree(title_path, entries, 1, &stop_scan_flag); + for (const FileUtil::FSTEntry& tid_high : entries.children) { if (stop_scan_flag) { break; } - std::string tid_string = tid_high.virtualName + tid_low.virtualName; + for (const FileUtil::FSTEntry& tid_low : tid_high.children) { + if (stop_scan_flag) { + break; + } + std::string tid_string = tid_high.virtualName + tid_low.virtualName; - if (tid_string.length() == TITLE_ID_VALID_LENGTH) { - const u64 tid = std::stoull(tid_string, nullptr, 16); + if (tid_string.length() == TITLE_ID_VALID_LENGTH) { + const u64 tid = std::stoull(tid_string, nullptr, 16); - if (tid & TWL_TITLE_ID_FLAG) { - // TODO(PabloMK7) Move to TWL Nand, for now only check that - // the contents exists in CTR Nand as this is a SRL file - // instead of NCCH. - if (FileUtil::Exists(GetTitleContentPath(media_type, tid))) { - am_title_list[static_cast(media_type)].push_back(tid); - } - } else { - FileSys::NCCHContainer container(GetTitleContentPath(media_type, tid)); - if (container.Load() == Loader::ResultStatus::Success) { - am_title_list[static_cast(media_type)].push_back(tid); + if (tid & TWL_TITLE_ID_FLAG) { + // TODO(PabloMK7) Move to TWL Nand, for now only check that + // the contents exists in CTR Nand as this is a SRL file + // instead of NCCH. + if (FileUtil::Exists(GetTitleContentPath(media_type, tid))) { + am_title_list[static_cast(media_type)].push_back(tid); + } + } else { + FileSys::NCCHContainer container(GetTitleContentPath(media_type, tid)); + if (container.Load() == Loader::ResultStatus::Success) { + am_title_list[static_cast(media_type)].push_back(tid); + } } } } } } + LOG_DEBUG(Service_AM, "Finished title scan for media_type={}", static_cast(media_type)); } @@ -1447,6 +1468,7 @@ void Module::ScanForAllTitles() { ScanForTicketsImpl(); ScanForTitlesImpl(Service::FS::MediaType::NAND); ScanForTitlesImpl(Service::FS::MediaType::SDMC); + ScanForTitlesImpl(Service::FS::MediaType::GameCard); } else { scan_all_future = std::async([this]() { std::scoped_lock lock(am_lists_mutex); @@ -1457,6 +1479,9 @@ void Module::ScanForAllTitles() { if (!stop_scan_flag) { ScanForTitlesImpl(Service::FS::MediaType::SDMC); } + if (!stop_scan_flag) { + ScanForTitlesImpl(Service::FS::MediaType::GameCard); + } }); } } @@ -1979,30 +2004,75 @@ void Module::Interface::GetProgramList(Kernel::HLERequestContext& ctx) { } } -Result GetTitleInfoFromList(std::span title_id_list, Service::FS::MediaType media_type, +Result GetTitleInfoFromList(Core::System& system, std::span title_id_list, + Service::FS::MediaType media_type, std::vector& title_info_out) { title_info_out.reserve(title_id_list.size()); for (u32 i = 0; i < title_id_list.size(); i++) { - std::string tmd_path = GetTitleMetadataPath(media_type, title_id_list[i]); + if (media_type == Service::FS::MediaType::GameCard) { + auto& cartridge = system.GetCartridge(); + if (cartridge.empty()) { + LOG_DEBUG(Service_AM, "cartridge not inserted"); + return Result(ErrorDescription::NotFound, ErrorModule::AM, + ErrorSummary::InvalidState, ErrorLevel::Permanent); + } - TitleInfo title_info = {}; - title_info.tid = title_id_list[i]; + FileSys::NCCHContainer ncch_container(cartridge); + if (ncch_container.Load() != Loader::ResultStatus::Success || + !ncch_container.IsNCSD()) { + LOG_ERROR(Service_AM, "failed to load cartridge card"); + return Result(ErrorDescription::NotFound, ErrorModule::AM, + ErrorSummary::InvalidState, ErrorLevel::Permanent); + } - FileSys::TitleMetadata tmd; - if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) { - // TODO(shinyquagsire23): This is the total size of all files this process owns, - // including savefiles and other content. This comes close but is off. - title_info.size = tmd.GetContentSizeByIndex(FileSys::TMDContentIndex::Main); - title_info.version = tmd.GetTitleVersion(); - title_info.type = tmd.GetTitleType(); + // This is what Process9 does for getting the information, from disassembly. + // It is still unclear what do those values mean, like the title info type. + if (ncch_container.exheader_header.arm11_system_local_caps.program_id != + title_id_list[i]) { + LOG_DEBUG(Service_AM, + "cartridge has different title ID than requested title_id={:016X} != " + "cartridge_title_id={:016X}", + title_id_list[i], + ncch_container.exheader_header.arm11_system_local_caps.program_id); + return Result(ErrorDescription::NotFound, ErrorModule::AM, + ErrorSummary::InvalidState, ErrorLevel::Permanent); + } + + TitleInfo title_info = {}; + title_info.tid = title_id_list[i]; + title_info.version = + (*reinterpret_cast( + &ncch_container.exheader_header.codeset_info.flags.remaster_version) + << 10) & + 0xFC00; + title_info.size = 0; + title_info.type = 0x40; + + LOG_DEBUG(Service_AM, "found title_id={:016X} version={:04X}", title_id_list[i], + title_info.version); + title_info_out.push_back(title_info); } else { - LOG_DEBUG(Service_AM, "not found title_id={:016X}", title_id_list[i]); - return Result(ErrorDescription::NotFound, ErrorModule::AM, ErrorSummary::InvalidState, - ErrorLevel::Permanent); + std::string tmd_path = GetTitleMetadataPath(media_type, title_id_list[i]); + + TitleInfo title_info = {}; + title_info.tid = title_id_list[i]; + + FileSys::TitleMetadata tmd; + if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) { + // TODO(shinyquagsire23): This is the total size of all files this process owns, + // including savefiles and other content. This comes close but is off. + title_info.size = tmd.GetContentSizeByIndex(FileSys::TMDContentIndex::Main); + title_info.version = tmd.GetTitleVersion(); + title_info.type = tmd.GetTitleType(); + } else { + LOG_DEBUG(Service_AM, "not found title_id={:016X}", title_id_list[i]); + return Result(ErrorDescription::NotFound, ErrorModule::AM, + ErrorSummary::InvalidState, ErrorLevel::Permanent); + } + LOG_DEBUG(Service_AM, "found title_id={:016X} version={:04X}", title_id_list[i], + title_info.version); + title_info_out.push_back(title_info); } - LOG_DEBUG(Service_AM, "found title_id={:016X} version={:04X}", title_id_list[i], - title_info.version); - title_info_out.push_back(title_info); } return ResultSuccess; @@ -2134,7 +2204,7 @@ void Module::Interface::GetProgramInfosImpl(Kernel::HLERequestContext& ctx, bool } if (async_data->res.IsSuccess()) { - async_data->res = GetTitleInfoFromList(async_data->title_id_list, + async_data->res = GetTitleInfoFromList(am->system, async_data->title_id_list, async_data->media_type, async_data->out); } return 0; @@ -2348,7 +2418,7 @@ void Module::Interface::GetDLCTitleInfos(Kernel::HLERequestContext& ctx) { } if (async_data->res.IsSuccess()) { - async_data->res = GetTitleInfoFromList(async_data->title_id_list, + async_data->res = GetTitleInfoFromList(am->system, async_data->title_id_list, async_data->media_type, async_data->out); } return 0; @@ -2495,7 +2565,7 @@ void Module::Interface::GetPatchTitleInfos(Kernel::HLERequestContext& ctx) { } if (async_data->res.IsSuccess()) { - async_data->res = GetTitleInfoFromList(async_data->title_id_list, + async_data->res = GetTitleInfoFromList(am->system, async_data->title_id_list, async_data->media_type, async_data->out); } return 0; @@ -3212,91 +3282,6 @@ void Module::Interface::CheckContentRightsIgnorePlatform(Kernel::HLERequestConte LOG_DEBUG(Service_AM, "tid={:016x}, content_index={}", tid, content_index); } -void Module::Interface::BeginImportProgram(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx); - auto media_type = static_cast(rp.Pop()); - - if (am->cia_installing) { - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(Result(ErrCodes::InvalidImportState, ErrorModule::AM, ErrorSummary::InvalidState, - ErrorLevel::Permanent)); - return; - } - - // Create our CIAFile handle for the app to write to, and while the app writes - // Citra will store contents out to sdmc/nand - const FileSys::Path cia_path = {}; - auto file = std::make_shared( - am->system.Kernel(), std::make_unique(am->system, media_type), cia_path); - - am->cia_installing = true; - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ResultSuccess); // No error - rb.PushCopyObjects(file->Connect()); - - LOG_WARNING(Service_AM, "(STUBBED) media_type={}", media_type); -} - -void Module::Interface::BeginImportProgramTemporarily(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx); - - if (am->cia_installing) { - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(Result(ErrCodes::InvalidImportState, ErrorModule::AM, ErrorSummary::InvalidState, - ErrorLevel::Permanent)); - return; - } - - // Note: This function should register the title in the temp_i.db database, but we can get away - // with not doing that because we traverse the file system to detect installed titles. - // Create our CIAFile handle for the app to write to, and while the app writes Citra will store - // contents out to sdmc/nand - const FileSys::Path cia_path = {}; - auto file = std::make_shared( - am->system.Kernel(), std::make_unique(am->system, FS::MediaType::NAND), cia_path); - - am->cia_installing = true; - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ResultSuccess); // No error - rb.PushCopyObjects(file->Connect()); - - LOG_WARNING(Service_AM, "(STUBBED)"); -} - -void Module::Interface::EndImportProgram(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx); - [[maybe_unused]] const auto cia = rp.PopObject(); - - LOG_DEBUG(Service_AM, ""); - - am->ScanForAllTitles(); - - am->cia_installing = false; - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultSuccess); -} - -void Module::Interface::EndImportProgramWithoutCommit(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx); - [[maybe_unused]] const auto cia = rp.PopObject(); - - // Note: This function is basically a no-op for us since we don't use title.db or ticket.db - // files to keep track of installed titles. - am->ScanForAllTitles(); - - am->cia_installing = false; - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultSuccess); - - LOG_WARNING(Service_AM, "(STUBBED)"); -} - -void Module::Interface::CommitImportPrograms(Kernel::HLERequestContext& ctx) { - CommitImportTitlesImpl(ctx, false, false); -} - /// Wraps all File operations to allow adding an offset to them. class AMFileWrapper : public FileSys::FileBackend { public: @@ -3412,6 +3397,123 @@ ResultVal GetFileBackendFromSession(std::shared_ptr f return Kernel::ResultNotImplemented; } +void Module::Interface::BeginImportProgram(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + auto media_type = static_cast(rp.Pop()); + + if (am->cia_installing) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(Result(ErrCodes::InvalidImportState, ErrorModule::AM, ErrorSummary::InvalidState, + ErrorLevel::Permanent)); + return; + } + + // Create our CIAFile handle for the app to write to, and while the app writes + // Citra will store contents out to sdmc/nand + const FileSys::Path cia_path = {}; + auto file = std::make_shared( + am->system.Kernel(), std::make_unique(am->system, media_type), cia_path); + + am->cia_installing = true; + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(ResultSuccess); // No error + rb.PushCopyObjects(file->Connect()); + + LOG_WARNING(Service_AM, "(STUBBED) media_type={}", media_type); +} + +void Module::Interface::BeginImportProgramTemporarily(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + + if (am->cia_installing) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(Result(ErrCodes::InvalidImportState, ErrorModule::AM, ErrorSummary::InvalidState, + ErrorLevel::Permanent)); + return; + } + + // Note: This function should register the title in the temp_i.db database, but we can get away + // with not doing that because we traverse the file system to detect installed titles. + // Create our CIAFile handle for the app to write to, and while the app writes Citra will store + // contents out to sdmc/nand + const FileSys::Path cia_path = {}; + std::shared_ptr file; + { + auto cia_file = std::make_unique(am->system, FS::MediaType::NAND); + + AuthorizeCIAFileDecryption(cia_file.get(), ctx); + + file = + std::make_shared(am->system.Kernel(), std::move(cia_file), cia_path); + } + am->cia_installing = true; + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(ResultSuccess); // No error + rb.PushCopyObjects(file->Connect()); + + LOG_WARNING(Service_AM, "(STUBBED)"); +} + +void Module::Interface::CancelImportProgram(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + const auto cia = rp.PopObject(); + + LOG_DEBUG(Service_AM, ""); + + auto cia_file = GetFileBackendFromSession(cia); + if (cia_file.Succeeded()) { + cia_file.Unwrap()->Cancel(); + } + + am->cia_installing = false; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultSuccess); +} + +void Module::Interface::EndImportProgram(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + const auto cia = rp.PopObject(); + + LOG_DEBUG(Service_AM, ""); + + auto cia_file = GetFileBackendFromSession(cia); + if (cia_file.Succeeded()) { + cia_file.Unwrap()->Close(); + } + + am->ScanForAllTitles(); + + am->cia_installing = false; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultSuccess); +} + +void Module::Interface::EndImportProgramWithoutCommit(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + const auto cia = rp.PopObject(); + + auto cia_file = GetFileBackendFromSession(cia); + if (cia_file.Succeeded()) { + cia_file.Unwrap()->Close(); + } + + // Note: This function is basically a no-op for us since we don't use title.db or ticket.db + // files to keep track of installed titles. + am->ScanForAllTitles(); + + am->cia_installing = false; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultSuccess); + + LOG_WARNING(Service_AM, "(STUBBED)"); +} + +void Module::Interface::CommitImportPrograms(Kernel::HLERequestContext& ctx) { + CommitImportTitlesImpl(ctx, false, false); +} + void Module::Interface::GetProgramInfoFromCia(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); [[maybe_unused]] const auto media_type = static_cast(rp.Pop()); @@ -3446,7 +3548,7 @@ void Module::Interface::GetProgramInfoFromCia(Kernel::HLERequestContext& ctx) { title_info.version = tmd.GetTitleVersion(); title_info.type = tmd.GetTitleType(); - IPC::RequestBuilder rb = rp.MakeBuilder(8, 0); + IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); rb.Push(ResultSuccess); rb.PushRaw(title_info); } diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 5f92d7adc..4dec69e80 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -224,6 +224,11 @@ public: is_done = true; } + void Cancel() { + is_cancel = true; + Close(); + } + const std::vector& GetInstallResults() const { return install_results; } @@ -237,6 +242,7 @@ private: bool decryption_authorized; bool is_done = false; bool is_closed = false; + bool is_cancel = false; bool is_additional_content = false; // Whether it's installing an update, and what step of installation it is at @@ -815,6 +821,17 @@ public: */ void BeginImportProgramTemporarily(Kernel::HLERequestContext& ctx); + /** + * AM::CancelImportProgram service function + * Cancel importing a CTR Installable Archive + * Inputs: + * 0 : Command header (0x04040002) + * 1-2 : CIAFile handle application wrote to + * Outputs: + * 1 : Result, 0 on success, otherwise error code + */ + void CancelImportProgram(Kernel::HLERequestContext& ctx); + /** * AM::EndImportProgram service function * Finish importing from a CTR Installable Archive diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp index 1ed88ea8b..039ea91b3 100644 --- a/src/core/hle/service/am/am_net.cpp +++ b/src/core/hle/service/am/am_net.cpp @@ -58,7 +58,7 @@ AM_NET::AM_NET(std::shared_ptr am) : Module::Interface(std::move(am), "a {0x0401, nullptr, "UpdateFirmwareTo"}, {0x0402, &AM_NET::BeginImportProgram, "BeginImportProgram"}, {0x0403, &AM_NET::BeginImportProgramTemporarily, "BeginImportProgramTemporarily"}, - {0x0404, nullptr, "CancelImportProgram"}, + {0x0404, &AM_NET::CancelImportProgram, "CancelImportProgram"}, {0x0405, &AM_NET::EndImportProgram, "EndImportProgram"}, {0x0406, &AM_NET::EndImportProgramWithoutCommit, "EndImportProgramWithoutCommit"}, {0x0407, &AM_NET::CommitImportPrograms, "CommitImportPrograms"}, diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp index 32395d75a..0356999d8 100644 --- a/src/core/hle/service/am/am_u.cpp +++ b/src/core/hle/service/am/am_u.cpp @@ -58,7 +58,7 @@ AM_U::AM_U(std::shared_ptr am) : Module::Interface(std::move(am), "am:u" {0x0401, nullptr, "UpdateFirmwareTo"}, {0x0402, &AM_U::BeginImportProgram, "BeginImportProgram"}, {0x0403, &AM_U::BeginImportProgramTemporarily, "BeginImportProgramTemporarily"}, - {0x0404, nullptr, "CancelImportProgram"}, + {0x0404, &AM_U::CancelImportProgram, "CancelImportProgram"}, {0x0405, &AM_U::EndImportProgram, "EndImportProgram"}, {0x0406, &AM_U::EndImportProgramWithoutCommit, "EndImportProgramWithoutCommit"}, {0x0407, &AM_U::CommitImportPrograms, "CommitImportPrograms"}, diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp index 2d21f9ae8..1dcbb430e 100644 --- a/src/core/hle/service/apt/applet_manager.cpp +++ b/src/core/hle/service/apt/applet_manager.cpp @@ -122,6 +122,37 @@ static u64 GetTitleIdForApplet(AppletId id, u32 region_value) { return itr->title_ids[region_value]; } +static constexpr std::size_t NumTitleIDConverts = 3; +static constexpr std::array, NumTitleIDConverts> TitleIDConvertTable = {{ + // MSET + {{0x0004001000020000, 0x0004001000021000, 0x0004001000022000, 0x0004001000020000, + 0x0004001000026000, 0x0004001000027000, 0x0004001000028000}}, + // eShop + {{0x0004001000020900, 0x0004001000021900, 0x0004001000022900, 0x0004001000020900, + 0x0004001000020900, 0x0004001000027900, 0x0004001000028900}}, + // NNID Settings + {{0x000400100002BF00, 0x000400100002C000, 0x000400100002C100, 0x000400100002BF00, + 0x000400100002BF00, 0x000400100002BF00, 0x000400100002BF00}}, +}}; + +static u64 ConvertTitleID(Core::System& system, u64 base_title_id) { + + auto cfg = Service::CFG::GetModule(system); + if (!cfg) { + return base_title_id; + } + + u32 region_value = cfg->GetRegionValue(false); + + for (auto& entry : TitleIDConvertTable) { + if (base_title_id == entry[0]) { + return entry[region_value]; + } + } + + return base_title_id; +} + static bool IsSystemAppletId(AppletId applet_id) { return (static_cast(applet_id) & static_cast(AppletId::AnySystemApplet)) != 0; } @@ -365,6 +396,10 @@ ResultVal AppletManager::Initialize(AppletId ap // Note: In the real console the title id of a given applet slot is set by the APT module when // calling StartApplication. slot_data->title_id = system.Kernel().GetCurrentProcess()->codeset->program_id; + if (app_id == AppletId::Application) { + slot_data->media_type = next_app_mediatype; + next_app_mediatype = static_cast(UINT32_MAX); + } slot_data->attributes.raw = attributes.raw; // Applications need to receive a Wakeup signal to actually start up, this signal is usually @@ -1013,6 +1048,22 @@ Result AppletManager::LeaveHomeMenu(std::shared_ptr object, return ResultSuccess; } +Result AppletManager::LoadSysMenuArg(std::vector& buffer) { + if (sys_menu_arg.has_value()) { + std::memcpy(buffer.data(), sys_menu_arg.value().data(), + std::min(buffer.size(), sys_menu_arg.value().size())); + } + // Always succeed, even if there is no data to copy. + return ResultSuccess; +} + +Result AppletManager::StoreSysMenuArg(const std::vector& buffer) { + sys_menu_arg = std::array(); + std::memcpy(sys_menu_arg.value().data(), buffer.data(), + std::min(buffer.size(), sys_menu_arg.value().size())); + return ResultSuccess; +} + Result AppletManager::OrderToCloseApplication() { if (active_slot == AppletSlot::Error) { return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState, @@ -1160,7 +1211,14 @@ ResultVal AppletManager::GetAppletInfo(AppletId app_i ErrorLevel::Status); } - auto media_type = Service::AM::GetTitleMediaType(slot_data->title_id); + FS::MediaType media_type; + if (slot_data->media_type != static_cast(UINT32_MAX)) { + media_type = slot_data->media_type; + } else { + // Applet was not started from StartApplication, so we need to guess. + media_type = Service::AM::GetTitleMediaType(slot_data->title_id); + } + return AppletInfo{ .title_id = slot_data->title_id, .media_type = media_type, @@ -1187,7 +1245,13 @@ ResultVal AppletManager::Unknown54(u32 in_param) { in_param >= 0x40 ? Service::FS::MediaType::GameCard : Service::FS::MediaType::SDMC; auto check_update = in_param == 0x01 || in_param == 0x42; - auto app_media_type = Service::AM::GetTitleMediaType(slot_data->title_id); + FS::MediaType app_media_type; + if (slot_data->media_type != static_cast(UINT32_MAX)) { + app_media_type = slot_data->media_type; + } else { + // Applet was not started from StartApplication, so we need to guess. + app_media_type = Service::AM::GetTitleMediaType(slot_data->title_id); + } auto app_update_media_type = Service::AM::GetTitleMediaType(Service::AM::GetTitleUpdateId(slot_data->title_id)); if (app_media_type == check_target || (check_update && app_update_media_type == check_target)) { @@ -1213,8 +1277,8 @@ ApplicationRunningMode AppletManager::GetApplicationRunningMode() { // APT checks whether the system is a New 3DS and the 804MHz CPU speed is enabled to determine // the result. - auto new_3ds_mode = GetTargetPlatform() == TargetPlatform::New3ds && - system.Kernel().GetNew3dsHwCapabilities().enable_804MHz_cpu; + auto new_3ds_mode = + GetTargetPlatform() == TargetPlatform::New3ds && system.Kernel().GetRunning804MHz(); if (slot_data->registered) { return new_3ds_mode ? ApplicationRunningMode::New3dsRegistered : ApplicationRunningMode::Old3dsRegistered; @@ -1236,13 +1300,21 @@ Result AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType med // Save the title data to send it to the Home Menu when DoApplicationJump is called. auto application_slot_data = GetAppletSlot(AppletSlot::Application); app_jump_parameters.current_title_id = application_slot_data->title_id; - app_jump_parameters.current_media_type = - Service::AM::GetTitleMediaType(application_slot_data->title_id); + + FS::MediaType curr_media_type; + if (application_slot_data->media_type != static_cast(UINT32_MAX)) { + curr_media_type = application_slot_data->media_type; + } else { + // Applet was not started from StartApplication, so we need to guess. + curr_media_type = Service::AM::GetTitleMediaType(application_slot_data->title_id); + } + + app_jump_parameters.current_media_type = curr_media_type; if (flags == ApplicationJumpFlags::UseCurrentParameters) { app_jump_parameters.next_title_id = app_jump_parameters.current_title_id; app_jump_parameters.next_media_type = app_jump_parameters.current_media_type; } else { - app_jump_parameters.next_title_id = title_id; + app_jump_parameters.next_title_id = ConvertTitleID(system, title_id); app_jump_parameters.next_media_type = media_type; } app_jump_parameters.flags = flags; @@ -1301,7 +1373,7 @@ Result AppletManager::DoApplicationJump(const DeliverArg& arg) { */ NS::RebootToTitle(system, app_jump_parameters.next_media_type, - app_jump_parameters.next_title_id); + app_jump_parameters.next_title_id, std::nullopt); return ResultSuccess; } } @@ -1320,6 +1392,61 @@ Result AppletManager::PrepareToStartApplication(u64 title_id, FS::MediaType medi ErrorLevel::Status}; } + title_id = ConvertTitleID(system, title_id); + + std::string path; + if (media_type == FS::MediaType::GameCard) { + path = system.GetCartridge(); + } else { + path = AM::GetTitleContentPath(media_type, title_id); + } + + next_app_mediatype = media_type; + + auto loader = Loader::GetLoader(path); + + if (!loader) { + LOG_ERROR(Service_APT, "Could not find .app for title 0x{:016x}", title_id); + // TODO: Find proper error code + return ResultUnknown; + } + + auto plg_ldr = Service::PLGLDR::GetService(system); + if (plg_ldr) { + const auto& plg_context = plg_ldr->GetPluginLoaderContext(); + if (plg_context.is_enabled && plg_context.use_user_load_parameters && + plg_context.user_load_parameters.low_title_Id == static_cast(title_id) && + plg_context.user_load_parameters.plugin_memory_strategy == + PLGLDR::PLG_LDR::PluginMemoryStrategy::PLG_STRATEGY_MODE3) { + loader->SetKernelMemoryModeOverride(Kernel::MemoryMode::Dev2); + } + } + + auto mem_mode = loader->LoadKernelMemoryMode(); + if (mem_mode.second != Loader::ResultStatus::Success || !mem_mode.first.has_value()) { + // This cannot happen on real HW at this point of execution + LOG_ERROR(Service_APT, "Could not determine memory mode"); + return ResultUnknown; + } + + auto curr_mem_mode = system.Kernel().GetMemoryMode(); + + if (mem_mode.first.value() != curr_mem_mode) { + if (system.Kernel().GetMemoryMode() == Kernel::MemoryMode::NewProd) { + // On New 3DS prod memory mode, only incorrect state is if the app + // reports having the "unused" memory mode 1. TODO: Figure out + // how this works and if it is even used. + if (mem_mode.first.value() == static_cast(1)) { + return {ErrCodes::IncorrectMemoryMode, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status}; + } + } else { + // On other memory modes, the state is incorrect. + return {ErrCodes::IncorrectMemoryMode, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; + } + } + ASSERT_MSG(!app_start_parameters, "Trying to prepare an application when another is already prepared"); @@ -1403,6 +1530,44 @@ Result AppletManager::CancelApplication() { return ResultSuccess; } +Result AppletManager::PrepareToStartNewestHomeMenu() { + if (active_slot == AppletSlot::Error || + GetAppletSlot(active_slot)->attributes.applet_pos != AppletPos::System) { + return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState, + ErrorLevel::Status}; + } + + bool is_standard; + if (Settings::values.is_new_3ds) { + // Memory layout is standard if it is not NewDev1 (178MB) + is_standard = system.Kernel().GetMemoryMode() != Kernel::MemoryMode::NewDev1; + } else { + // Memory layout is standard if it is Prod (64MB) + is_standard = system.Kernel().GetMemoryMode() == Kernel::MemoryMode::Prod; + } + + if (is_standard) { + return Result{ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status}; + } + + home_menu_tid_to_start = GetAppletSlot(active_slot)->title_id; + return ResultSuccess; +} + +Result AppletManager::StartNewestHomeMenu() { + if (!home_menu_tid_to_start) { + return Result{ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status}; + } + + u64 titleID = home_menu_tid_to_start; + home_menu_tid_to_start = 0; + + NS::RebootToTitle(system, Service::FS::MediaType::NAND, titleID, std::nullopt); + return ResultSuccess; +} + void AppletManager::SendApplicationParameterAfterRegistration(const MessageParameter& parameter) { auto slot = GetAppletSlotFromId(parameter.destination_id); diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h index 5aaf7fdac..3924ec510 100644 --- a/src/core/hle/service/apt/applet_manager.h +++ b/src/core/hle/service/apt/applet_manager.h @@ -1,4 +1,4 @@ -// Copyright 2018 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -118,6 +118,8 @@ enum class ApplicationRunningMode : u8 { New3dsUnregistered = 4, }; +constexpr std::size_t SysMenuArgSize = 0x40; + /// Holds information about the parameters used in Send/Glance/ReceiveParameter struct MessageParameter { AppletId sender_id = AppletId::None; @@ -180,6 +182,8 @@ private: friend class boost::serialization::access; }; +using SysMenuArg = std::array; + struct ApplicationJumpParameters { u64 next_title_id; FS::MediaType next_media_type; @@ -322,6 +326,16 @@ public: Result PrepareToLeaveHomeMenu(); Result LeaveHomeMenu(std::shared_ptr object, const std::vector& buffer); + Result LoadSysMenuArg(std::vector& buffer); + Result StoreSysMenuArg(const std::vector& buffer); + + boost::optional GetSysMenuArg() { + return sys_menu_arg; + } + void SetSysMenuArg(const SysMenuArg& arg) { + sys_menu_arg = arg; + } + Result OrderToCloseApplication(); Result PrepareToCloseApplication(bool return_to_sys); Result CloseApplication(std::shared_ptr object, const std::vector& buffer); @@ -376,6 +390,9 @@ public: Result WakeupApplication(std::shared_ptr object, const std::vector& buffer); Result CancelApplication(); + Result PrepareToStartNewestHomeMenu(); + Result StartNewestHomeMenu(); + struct AppletManInfo { AppletPos active_applet_pos; AppletId requested_applet_id; @@ -417,6 +434,8 @@ private: ApplicationJumpParameters app_jump_parameters{}; boost::optional app_start_parameters{}; boost::optional deliver_arg{}; + boost::optional sys_menu_arg{}; + u64 home_menu_tid_to_start{}; boost::optional capture_info; boost::optional capture_buffer_info; @@ -437,6 +456,7 @@ private: AppletId applet_id; AppletSlot slot; u64 title_id; + FS::MediaType media_type; bool registered; bool loaded; AppletAttributes attributes; @@ -457,6 +477,7 @@ private: ar & applet_id; ar & slot; ar & title_id; + ar & media_type; ar & registered; ar & loaded; ar & attributes.raw; @@ -495,6 +516,8 @@ private: bool last_home_button_state = false; bool last_power_button_state = false; + FS::MediaType next_app_mediatype = static_cast(UINT32_MAX); + Core::System& system; AppletSlotData* GetAppletSlot(AppletSlot slot) { @@ -532,6 +555,8 @@ private: ar & delayed_parameter; ar & app_start_parameters; ar & deliver_arg; + ar & sys_menu_arg; + ar & home_menu_tid_to_start; ar & capture_info; ar & capture_buffer_info; ar & active_slot; @@ -548,6 +573,7 @@ private: ar & capture_info; ar & applet_slots; ar & library_applet_closing_command; + ar & next_app_mediatype; if (Archive::is_loading::value) { LoadInputDevices(); diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 002bd3728..fcc9b2a89 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -75,6 +75,20 @@ void Module::NSInterface::SetWirelessRebootInfo(Kernel::HLERequestContext& ctx) LOG_WARNING(Service_APT, "called size={}", size); } +void Module::NSInterface::CardUpdateInitialize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + rp.Pop(); // Shared mem size + rp.Pop(); // Always 0 + rp.Pop(); // Shared mem handle + + LOG_WARNING(Service_APT, "(stubbed) called"); + const Result update_not_needed(11, ErrorModule::CUP, ErrorSummary::NothingHappened, + ErrorLevel::Status); + + auto rb = rp.MakeBuilder(1, 0); + rb.Push(update_not_needed); +} + void Module::NSInterface::ShutdownAsync(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); @@ -92,16 +106,15 @@ void Module::NSInterface::RebootSystem(Kernel::HLERequestContext& ctx) { const auto title_id = rp.Pop(); const auto media_type = static_cast(rp.Pop()); rp.Skip(1, false); // Skip padding - // TODO: Utilize requested memory type. const auto mem_type = rp.Pop(); LOG_WARNING(Service_APT, "called launch_title={}, title_id={:016X}, media_type={:02X}, mem_type={:02X}", launch_title, title_id, media_type, mem_type); - // TODO: Handle mem type. if (launch_title) { - NS::RebootToTitle(apt->system, media_type, title_id); + NS::RebootToTitle(apt->system, media_type, title_id, + static_cast(mem_type)); } else { apt->system.RequestReset(); } @@ -763,16 +776,12 @@ void Module::APTInterface::PrepareToStartSystemApplet(Kernel::HLERequestContext& void Module::APTInterface::PrepareToStartNewestHomeMenu(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); LOG_DEBUG(Service_APT, "called"); - // TODO(Subv): This command can only be called by a System Applet (return 0xC8A0CC04 otherwise). - - // This command must return an error when called, otherwise the Home Menu will try to reboot the - // system. - rb.Push(Result(ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState, - ErrorLevel::Status)); + rb.Push(apt->applet_manager->PrepareToStartNewestHomeMenu()); } void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx) { @@ -821,6 +830,19 @@ void Module::APTInterface::StartSystemApplet(Kernel::HLERequestContext& ctx) { rb.Push(apt->applet_manager->StartSystemApplet(applet_id, object, buffer)); } +void Module::APTInterface::StartNewestHomeMenu(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + + const auto buffer_size = rp.Pop(); + [[maybe_unused]] const auto object = rp.PopGenericObject(); + [[maybe_unused]] const auto buffer = rp.PopStaticBuffer(); + + LOG_DEBUG(Service_APT, "called, size={:08X}", buffer_size); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(apt->applet_manager->StartNewestHomeMenu()); +} + void Module::APTInterface::OrderToCloseApplication(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); @@ -1011,10 +1033,10 @@ void Module::APTInterface::LoadSysMenuArg(Kernel::HLERequestContext& ctx) { // This service function does not clear the buffer. std::vector buffer(size); - std::copy_n(apt->sys_menu_arg_buffer.cbegin(), size, buffer.begin()); + Result res = apt->applet_manager->LoadSysMenuArg(buffer); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ResultSuccess); + rb.Push(res); rb.PushStaticBuffer(std::move(buffer), 0); } @@ -1026,10 +1048,10 @@ void Module::APTInterface::StoreSysMenuArg(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_APT, "called"); ASSERT_MSG(buffer.size() >= size, "Buffer too small to hold requested data"); - std::copy_n(buffer.cbegin(), size, apt->sys_menu_arg_buffer.begin()); + Result res = apt->applet_manager->StoreSysMenuArg(buffer); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultSuccess); + rb.Push(res); } void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx) { @@ -1365,8 +1387,8 @@ void Module::APTInterface::Reboot(Kernel::HLERequestContext& ctx) { "called title_id={:016X}, media_type={:02X}, mem_type={:02X}, firm_tid_low={:08X}", title_id, media_type, mem_type, firm_tid_low); - // TODO: Handle mem type and FIRM TID low. - NS::RebootToTitle(apt->system, media_type, title_id); + // TODO: Handle FIRM TID low. + NS::RebootToTitle(apt->system, media_type, title_id, static_cast(mem_type)); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultSuccess); @@ -1420,8 +1442,7 @@ void Module::APTInterface::IsStandardMemoryLayout(Kernel::HLERequestContext& ctx bool is_standard; if (Settings::values.is_new_3ds) { // Memory layout is standard if it is not NewDev1 (178MB) - is_standard = apt->system.Kernel().GetNew3dsHwCapabilities().memory_mode != - Kernel::New3dsMemoryMode::NewDev1; + is_standard = apt->system.Kernel().GetMemoryMode() != Kernel::MemoryMode::NewDev1; } else { // Memory layout is standard if it is Prod (64MB) is_standard = apt->system.Kernel().GetMemoryMode() == Kernel::MemoryMode::Prod; @@ -1472,6 +1493,14 @@ std::shared_ptr Module::GetAppletManager() const { return applet_manager; } +std::vector Module::GetWirelessRebootInfoBuffer() const { + return wireless_reboot_info; +} + +void Module::SetWirelessRebootInfoBuffer(std::vector info_buf) { + wireless_reboot_info = info_buf; +} + std::shared_ptr GetModule(Core::System& system) { auto apt = system.ServiceManager().GetService("APT:A"); if (!apt) diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 8e20a788b..85b92bb60 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -31,8 +31,6 @@ class AppletManager; /// Each APT service can only have up to 2 sessions connected at the same time. static const u32 MaxAPTSessions = 2; -constexpr std::size_t SysMenuArgSize = 0x40; - enum class StartupArgumentType : u32 { OtherApp = 0, Restart = 1, @@ -53,6 +51,9 @@ public: std::shared_ptr GetAppletManager() const; + std::vector GetWirelessRebootInfoBuffer() const; + void SetWirelessRebootInfoBuffer(std::vector info_buf); + class NSInterface : public ServiceFramework { public: NSInterface(std::shared_ptr apt, const char* name, u32 max_session); @@ -74,6 +75,8 @@ public: */ void SetWirelessRebootInfo(Kernel::HLERequestContext& ctx); + void CardUpdateInitialize(Kernel::HLERequestContext& ctx); + /** * NS::ShutdownAsync service function. * Inputs: @@ -547,6 +550,21 @@ public: */ void StartSystemApplet(Kernel::HLERequestContext& ctx); + /** + * APT::StartNewestHomeMenu service function + * Inputs: + * 0 : Command header [0x00200044] + * 1 : Partameters size + * 2 : 0x0 + * 3 : Handle parameter + * 4 : (Parameters Size << 14) | 2 + * 5 : void*, Parameters + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ + void StartNewestHomeMenu(Kernel::HLERequestContext& ctx); + /** * APT::OrderToCloseApplication service function * Inputs: @@ -1073,8 +1091,6 @@ private: u32 cpu_percent = 0; ///< CPU time available to the running application - std::array sys_menu_arg_buffer; - ScreencapPostPermission screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index dc4c72c90..9de07a57d 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -42,7 +42,7 @@ APT_A::APT_A(std::shared_ptr apt) {0x001D, &APT_A::CancelApplication, "CancelApplication"}, {0x001E, &APT_A::StartLibraryApplet, "StartLibraryApplet"}, {0x001F, &APT_A::StartSystemApplet, "StartSystemApplet"}, - {0x0020, nullptr, "StartNewestHomeMenu"}, + {0x0020, &APT_A::StartNewestHomeMenu, "StartNewestHomeMenu"}, {0x0021, &APT_A::OrderToCloseApplication, "OrderToCloseApplication"}, {0x0022, &APT_A::PrepareToCloseApplication, "PrepareToCloseApplication"}, {0x0023, nullptr, "PrepareToJumpToApplication"}, diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index 9bd6d81ed..a332cebf6 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -42,7 +42,7 @@ APT_S::APT_S(std::shared_ptr apt) {0x001D, &APT_S::CancelApplication, "CancelApplication"}, {0x001E, &APT_S::StartLibraryApplet, "StartLibraryApplet"}, {0x001F, &APT_S::StartSystemApplet, "StartSystemApplet"}, - {0x0020, nullptr, "StartNewestHomeMenu"}, + {0x0020, &APT_S::StartNewestHomeMenu, "StartNewestHomeMenu"}, {0x0021, &APT_S::OrderToCloseApplication, "OrderToCloseApplication"}, {0x0022, &APT_S::PrepareToCloseApplication, "PrepareToCloseApplication"}, {0x0023, nullptr, "PrepareToJumpToApplication"}, diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index fd302ab4e..8e1fd18c6 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -42,7 +42,7 @@ APT_U::APT_U(std::shared_ptr apt) {0x001D, &APT_U::CancelApplication, "CancelApplication"}, {0x001E, &APT_U::StartLibraryApplet, "StartLibraryApplet"}, {0x001F, &APT_U::StartSystemApplet, "StartSystemApplet"}, - {0x0020, nullptr, "StartNewestHomeMenu"}, + {0x0020, &APT_U::StartNewestHomeMenu, "StartNewestHomeMenu"}, {0x0021, &APT_U::OrderToCloseApplication, "OrderToCloseApplication"}, {0x0022, &APT_U::PrepareToCloseApplication, "PrepareToCloseApplication"}, {0x0023, nullptr, "PrepareToJumpToApplication"}, diff --git a/src/core/hle/service/apt/errors.h b/src/core/hle/service/apt/errors.h index 25bffb9af..4de973906 100644 --- a/src/core/hle/service/apt/errors.h +++ b/src/core/hle/service/apt/errors.h @@ -1,4 +1,4 @@ -// Copyright 2018 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -8,6 +8,7 @@ namespace Service::APT::ErrCodes { enum { ParameterPresent = 2, InvalidAppletSlot = 4, + IncorrectMemoryMode = 5, AppNotRunning = 11, }; } // namespace Service::APT::ErrCodes diff --git a/src/core/hle/service/apt/ns.cpp b/src/core/hle/service/apt/ns.cpp index c71c23419..6b36d97d1 100644 --- a/src/core/hle/service/apt/ns.cpp +++ b/src/core/hle/service/apt/ns.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -11,11 +11,21 @@ namespace Service::NS { std::shared_ptr LaunchTitle(Core::System& system, FS::MediaType media_type, u64 title_id) { - std::string path = AM::GetTitleContentPath(media_type, title_id); - auto loader = Loader::GetLoader(path); + std::string path; - if (!loader) { - LOG_WARNING(Service_NS, "Could not find .app for title 0x{:016x}", title_id); + if (media_type == FS::MediaType::GameCard) { + path = system.GetCartridge(); + } else { + path = AM::GetTitleContentPath(media_type, title_id); + } + + auto loader = Loader::GetLoader(path); + u64 program_id; + + if (!loader || loader->ReadProgramId(program_id) != Loader::ResultStatus::Success || + program_id != title_id) { + LOG_WARNING(Service_NS, "Could not load title=0x{:016x} media_type={}", title_id, + static_cast(media_type)); return nullptr; } @@ -30,6 +40,23 @@ std::shared_ptr LaunchTitle(Core::System& system, FS::MediaType } } + { + // This is normally done by PM, but we don't emulate it + // so we do it here instead. + auto mem_mode_res = loader->LoadKernelMemoryMode(); + Kernel::MemoryMode mem_mode{}; + auto n3ds_cap_res = loader->LoadNew3dsHwCapabilities(); + Kernel::New3dsHwCapabilities n3ds_hw_cap{}; + + if (mem_mode_res.second == Loader::ResultStatus::Success && mem_mode_res.first) { + mem_mode = mem_mode_res.first.value(); + } + if (n3ds_cap_res.second == Loader::ResultStatus::Success && n3ds_cap_res.first) { + n3ds_hw_cap = n3ds_cap_res.first.value(); + } + system.Kernel().UpdateCPUAndMemoryState(title_id, mem_mode, n3ds_hw_cap); + } + std::shared_ptr process; Loader::ResultStatus result = loader->Load(process); @@ -41,8 +68,15 @@ std::shared_ptr LaunchTitle(Core::System& system, FS::MediaType return process; } -void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id) { - auto new_path = AM::GetTitleContentPath(media_type, title_id); +void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id, + std::optional mem_mode) { + std::string new_path; + if (media_type == FS::MediaType::GameCard) { + new_path = system.GetCartridge(); + } else { + new_path = AM::GetTitleContentPath(media_type, title_id); + } + if (new_path.empty() || !FileUtil::Exists(new_path)) { // TODO: This can happen if the requested title is not installed. Need a way to find // non-installed titles in the game list. @@ -51,7 +85,12 @@ void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id) new_path); new_path.clear(); } - system.RequestReset(new_path); + + std::optional mem_mode_u8; + if (mem_mode) { + mem_mode_u8 = static_cast(mem_mode.value()); + } + system.RequestReset(new_path, mem_mode_u8); } } // namespace Service::NS diff --git a/src/core/hle/service/apt/ns.h b/src/core/hle/service/apt/ns.h index 8fa80e11b..2a7dda254 100644 --- a/src/core/hle/service/apt/ns.h +++ b/src/core/hle/service/apt/ns.h @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -20,6 +20,7 @@ std::shared_ptr LaunchTitle(Core::System& system, FS::MediaType u64 title_id); /// Reboots the system to the specified title. -void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id); +void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id, + std::optional mem_mode); } // namespace Service::NS diff --git a/src/core/hle/service/apt/ns_s.cpp b/src/core/hle/service/apt/ns_s.cpp index dfb178d7b..ab267a0d4 100644 --- a/src/core/hle/service/apt/ns_s.cpp +++ b/src/core/hle/service/apt/ns_s.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -17,7 +17,7 @@ NS_S::NS_S(std::shared_ptr apt) {0x0004, nullptr, "TerminateProcess"}, {0x0005, nullptr, "LaunchApplicationFIRM"}, {0x0006, &NS_S::SetWirelessRebootInfo, "SetWirelessRebootInfo"}, - {0x0007, nullptr, "CardUpdateInitialize"}, + {0x0007, &NS_S::CardUpdateInitialize, "CardUpdateInitialize"}, {0x0008, nullptr, "CardUpdateShutdown"}, {0x000D, nullptr, "SetTWLBannerHMAC"}, {0x000E, &NS_S::ShutdownAsync, "ShutdownAsync"}, diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 4d04af017..070612250 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -1264,6 +1264,10 @@ std::string GetConsoleIdHash(Core::System& system) { return fmt::format("{:02x}", fmt::join(hash.begin(), hash.end(), "")); } +std::array GetConsoleMacAddress(Core::System& system) { + return MacToArray(GetModule(system)->GetMacAddress()); +} + std::array MacToArray(const std::string& mac) { std::array ret; int last = -1; diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h index 7536680c0..8b02d6f8e 100644 --- a/src/core/hle/service/cfg/cfg.h +++ b/src/core/hle/service/cfg/cfg.h @@ -672,6 +672,8 @@ u64 MacToU64(const std::string& mac); std::string GenerateRandomMAC(); +std::array GetConsoleMacAddress(Core::System& system); + } // namespace Service::CFG SERVICE_CONSTRUCT(Service::CFG::Module) diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 2a48a741a..131cb58c0 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -30,11 +30,16 @@ namespace Service::FS { +bool IsInstalledApplication(std::string_view path) { + return path.rfind(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "title", 0) == 0 || + path.rfind(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "Nintendo 3DS", 0) == 0; +} + MediaType GetMediaTypeFromPath(std::string_view path) { - if (path.rfind(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), 0) == 0) { + if (path.rfind(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "title", 0) == 0) { return MediaType::NAND; } - if (path.rfind(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), 0) == 0) { + if (path.rfind(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "Nintendo 3DS", 0) == 0) { return MediaType::SDMC; } return MediaType::GameCard; diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 387b11dba..2e017f3e0 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -51,6 +51,7 @@ enum class ArchiveIdCode : u32 { /// Media types for the archives enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; +bool IsInstalledApplication(std::string_view path); MediaType GetMediaTypeFromPath(std::string_view path); enum class SpecialContentType : u8 { diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 99390cd40..c9641a518 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -913,6 +913,14 @@ void FS_USER::GetFreeBytes(Kernel::HLERequestContext& ctx) { } } +void FS_USER::GetCardType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(ResultSuccess); + rb.Push(0); // CTR Card + LOG_DEBUG(Service_FS, "(STUBBED) called"); +} + void FS_USER::GetSdmcArchiveResource(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); @@ -999,8 +1007,8 @@ void FS_USER::CardSlotIsInserted(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(ResultSuccess); - rb.Push(false); - LOG_WARNING(Service_FS, "(STUBBED) called"); + rb.Push(!system.GetCartridge().empty()); + LOG_DEBUG(Service_FS, "called"); } void FS_USER::DeleteSystemSaveData(Kernel::HLERequestContext& ctx) { @@ -1681,14 +1689,20 @@ void FS_USER::GetSaveDataSecureValue(Kernel::HLERequestContext& ctx) { } void FS_USER::RegisterProgramInfo(u32 process_id, u64 program_id, const std::string& filepath) { - const MediaType media_type = GetMediaTypeFromPath(filepath); + MediaType media_type; + if (filepath == system.GetCartridge()) { + media_type = MediaType::GameCard; + } else { + media_type = GetMediaTypeFromPath(filepath); + } + program_info_map.insert_or_assign(process_id, ProgramInfo{program_id, media_type}); if (media_type == MediaType::GameCard) { current_gamecard_path = filepath; } } -std::string FS_USER::GetCurrentGamecardPath() const { +std::string FS_USER::GetRegisteredGamecardPath() const { return current_gamecard_path; } @@ -1779,7 +1793,7 @@ FS_USER::FS_USER(Core::System& system) {0x0810, &FS_USER::CreateLegacySystemSaveData, "CreateLegacySystemSaveData"}, {0x0811, nullptr, "DeleteSystemSaveData"}, {0x0812, &FS_USER::GetFreeBytes, "GetFreeBytes"}, - {0x0813, nullptr, "GetCardType"}, + {0x0813, &FS_USER::GetCardType, "GetCardType"}, {0x0814, &FS_USER::GetSdmcArchiveResource, "GetSdmcArchiveResource"}, {0x0815, &FS_USER::GetNandArchiveResource, "GetNandArchiveResource"}, {0x0816, nullptr, "GetSdmcFatfsError"}, diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h index 11fbef4db..bdce1b7eb 100644 --- a/src/core/hle/service/fs/fs_user.h +++ b/src/core/hle/service/fs/fs_user.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -54,7 +54,7 @@ public: // loader and pm, which we HLEed, we can just directly use it here void RegisterProgramInfo(u32 process_id, u64 program_id, const std::string& filepath); - std::string GetCurrentGamecardPath() const; + std::string GetRegisteredGamecardPath() const; struct ProductInfo { std::array product_code; @@ -361,6 +361,8 @@ private: */ void GetFreeBytes(Kernel::HLERequestContext& ctx); + void GetCardType(Kernel::HLERequestContext& ctx); + /** * FS_User::GetSdmcArchiveResource service function. * Inputs: diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp index dc33488b4..39d10f2d3 100644 --- a/src/core/hle/service/gsp/gsp_gpu.cpp +++ b/src/core/hle/service/gsp/gsp_gpu.cpp @@ -20,6 +20,7 @@ #include "core/memory.h" #include "video_core/gpu.h" #include "video_core/gpu_debugger.h" +#include "video_core/pica/pica_core.h" #include "video_core/pica/regs_lcd.h" #include "video_core/renderer_base.h" #include "video_core/right_eye_disabler.h" @@ -467,6 +468,8 @@ void GSP_GPU::TriggerCmdReqQueue(Kernel::HLERequestContext& ctx) { void GSP_GPU::ImportDisplayCaptureInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); + LOG_DEBUG(Service_GSP, "called"); + if (active_thread_id == std::numeric_limits::max()) { LOG_WARNING(Service_GSP, "Called without an active thread."); @@ -503,28 +506,64 @@ void GSP_GPU::ImportDisplayCaptureInfo(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); rb.PushRaw(top_entry); rb.PushRaw(bottom_entry); - - LOG_WARNING(Service_GSP, "called"); } -static void CopyFrameBuffer(Core::System& system, VAddr dst, VAddr src, u32 stride, u32 lines) { - auto dst_ptr = system.Memory().GetPointer(dst); - const auto src_ptr = system.Memory().GetPointer(src); +static void CopyFrameBuffer(Core::System& system, VAddr dst, VAddr src, u32 dst_stride, + u32 src_stride, u32 lines) { + auto* dst_ptr = system.Memory().GetPointer(dst); + const auto* src_ptr = system.Memory().GetPointer(src); + if (!dst_ptr || !src_ptr) { LOG_WARNING(Service_GSP, "Could not resolve pointers for framebuffer capture, skipping screen."); return; } - system.Memory().RasterizerFlushVirtualRegion(src, stride * lines, Memory::FlushMode::Flush); - std::memcpy(dst_ptr, src_ptr, stride * lines); - system.Memory().RasterizerFlushVirtualRegion(dst, stride * lines, + system.Memory().RasterizerFlushVirtualRegion(src, src_stride * lines, Memory::FlushMode::Flush); + + const u32 copy_bytes_per_line = std::min(src_stride, dst_stride); + for (u32 y = 0; y < lines; ++y) { + std::memcpy(dst_ptr, src_ptr, copy_bytes_per_line); + src_ptr += src_stride; + dst_ptr += dst_stride; + } + + system.Memory().RasterizerFlushVirtualRegion(dst, dst_stride * lines, + Memory::FlushMode::Invalidate); +} + +static void ClearFramebuffer(Core::System& system, VAddr dst, u32 dst_stride, u32 lines) { + auto* dst_ptr = system.Memory().GetPointer(dst); + + if (!dst_ptr) { + LOG_WARNING(Service_GSP, + "Could not resolve pointers for framebuffer clear, skipping screen."); + return; + } + + const u32 set_bytes_per_line = dst_stride; + for (u32 y = 0; y < lines; ++y) { + std::memset(dst_ptr, 0, set_bytes_per_line); + dst_ptr += dst_stride; + } + + system.Memory().RasterizerFlushVirtualRegion(dst, dst_stride * lines, Memory::FlushMode::Invalidate); } void GSP_GPU::SaveVramSysArea(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); + LOG_DEBUG(Service_GSP, "called"); + + // Taken from GSP decomp. TODO: GSP seems to so something special + // when the fb format results in bpp of 0 or 4, most likely clearing + // it, more research needed. + static const u8 bpp_per_format[] = {// Valid values + 4, 3, 2, 2, 2, + // Invalid values + 0, 0, 0}; + if (active_thread_id == std::numeric_limits::max()) { LOG_WARNING(Service_GSP, "Called without an active thread."); @@ -534,47 +573,71 @@ void GSP_GPU::SaveVramSysArea(Kernel::HLERequestContext& ctx) { return; } - LOG_INFO(Service_GSP, "called"); - - // TODO: This should also save LCD register state. system.Memory().RasterizerFlushVirtualRegion(Memory::VRAM_VADDR, Memory::VRAM_SIZE, Memory::FlushMode::Flush); const auto vram = system.Memory().GetPointer(Memory::VRAM_VADDR); saved_vram.emplace(std::vector(Memory::VRAM_SIZE)); std::memcpy(saved_vram.get().data(), vram, Memory::VRAM_SIZE); - const auto top_screen = GetFrameBufferInfo(active_thread_id, 0); + auto top_screen = GetFrameBufferInfo(active_thread_id, 0); if (top_screen) { + u8 bytes_per_pixel = + bpp_per_format[top_screen->framebuffer_info[top_screen->index].GetPixelFormat()]; const auto top_fb = top_screen->framebuffer_info[top_screen->index]; - if (top_fb.address_left) { + if (top_fb.address_left && bytes_per_pixel != 0 && bytes_per_pixel != 4) { CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_TOP_LEFT, top_fb.address_left, - top_fb.stride, TOP_FRAMEBUFFER_HEIGHT); + FRAMEBUFFER_WIDTH * bytes_per_pixel, top_fb.stride, + TOP_FRAMEBUFFER_HEIGHT); } else { - LOG_WARNING(Service_GSP, "No framebuffer bound to top left screen, skipping capture."); + LOG_DEBUG(Service_GSP, "Invalid framebuffer bound to top left screen, clearing..."); + ClearFramebuffer(system, FRAMEBUFFER_SAVE_AREA_TOP_LEFT, + FRAMEBUFFER_WIDTH * bytes_per_pixel, TOP_FRAMEBUFFER_HEIGHT); } - if (top_fb.address_right) { + if (top_fb.address_right && bytes_per_pixel != 0 && bytes_per_pixel != 4) { CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_TOP_RIGHT, top_fb.address_right, - top_fb.stride, TOP_FRAMEBUFFER_HEIGHT); + FRAMEBUFFER_WIDTH * bytes_per_pixel, top_fb.stride, + TOP_FRAMEBUFFER_HEIGHT); } else { - LOG_WARNING(Service_GSP, "No framebuffer bound to top right screen, skipping capture."); + LOG_DEBUG(Service_GSP, "Invalid framebuffer bound to top right screen, clearing..."); + ClearFramebuffer(system, FRAMEBUFFER_SAVE_AREA_TOP_RIGHT, + FRAMEBUFFER_WIDTH * bytes_per_pixel, TOP_FRAMEBUFFER_HEIGHT); } + + FrameBufferInfo fb_info = top_screen->framebuffer_info[top_screen->index]; + + fb_info.address_left = FRAMEBUFFER_SAVE_AREA_TOP_LEFT; + fb_info.address_right = FRAMEBUFFER_SAVE_AREA_TOP_RIGHT; + fb_info.stride = FRAMEBUFFER_WIDTH * bytes_per_pixel; + system.GPU().SetBufferSwap(0, fb_info); } else { LOG_WARNING(Service_GSP, "No top screen bound, skipping capture."); } - const auto bottom_screen = GetFrameBufferInfo(active_thread_id, 1); + auto bottom_screen = GetFrameBufferInfo(active_thread_id, 1); if (bottom_screen) { + u8 bytes_per_pixel = + bpp_per_format[bottom_screen->framebuffer_info[bottom_screen->index].GetPixelFormat()]; const auto bottom_fb = bottom_screen->framebuffer_info[bottom_screen->index]; - if (bottom_fb.address_left) { + if (bottom_fb.address_left && bytes_per_pixel != 0 && bytes_per_pixel != 4) { CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_BOTTOM, bottom_fb.address_left, - bottom_fb.stride, BOTTOM_FRAMEBUFFER_HEIGHT); + FRAMEBUFFER_WIDTH * bytes_per_pixel, bottom_fb.stride, + BOTTOM_FRAMEBUFFER_HEIGHT); } else { - LOG_WARNING(Service_GSP, "No framebuffer bound to bottom screen, skipping capture."); + LOG_DEBUG(Service_GSP, "Invalid framebuffer bound to bottom screen, clearing..."); + ClearFramebuffer(system, FRAMEBUFFER_SAVE_AREA_BOTTOM, + FRAMEBUFFER_WIDTH * bytes_per_pixel, BOTTOM_FRAMEBUFFER_HEIGHT); } + FrameBufferInfo fb_info = bottom_screen->framebuffer_info[bottom_screen->index]; + + fb_info.address_left = FRAMEBUFFER_SAVE_AREA_BOTTOM; + fb_info.stride = FRAMEBUFFER_WIDTH * bytes_per_pixel; + system.GPU().SetBufferSwap(1, fb_info); } else { LOG_WARNING(Service_GSP, "No bottom screen bound, skipping capture."); } + // Real GSP waits for VBlank here, but we don't need it (?). + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultSuccess); } @@ -582,16 +645,31 @@ void GSP_GPU::SaveVramSysArea(Kernel::HLERequestContext& ctx) { void GSP_GPU::RestoreVramSysArea(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); - LOG_INFO(Service_GSP, "called"); + LOG_DEBUG(Service_GSP, "called"); if (saved_vram) { - // TODO: This should also restore LCD register state. auto vram = system.Memory().GetPointer(Memory::VRAM_VADDR); std::memcpy(vram, saved_vram.get().data(), Memory::VRAM_SIZE); system.Memory().RasterizerFlushVirtualRegion(Memory::VRAM_VADDR, Memory::VRAM_SIZE, Memory::FlushMode::Invalidate); } + auto top_screen = GetFrameBufferInfo(active_thread_id, 0); + if (top_screen) { + system.GPU().SetBufferSwap(0, top_screen->framebuffer_info[top_screen->index]); + } else { + LOG_WARNING(Service_GSP, "No top screen bound, skipping restore."); + } + + auto bottom_screen = GetFrameBufferInfo(active_thread_id, 1); + if (bottom_screen) { + system.GPU().SetBufferSwap(1, bottom_screen->framebuffer_info[top_screen->index]); + } else { + LOG_WARNING(Service_GSP, "No bottom screen bound, skipping restore."); + } + + // Real GSP waits for VBlank here, but we don't need it (?). + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultSuccess); } @@ -608,8 +686,17 @@ Result GSP_GPU::AcquireGpuRight(const Kernel::HLERequestContext& ctx, Common::Hacks::hack_manager.GetHackAllowMode(Common::Hacks::HackType::RIGHT_EYE_DISABLE, process->codeset->program_id) != Common::Hacks::HackAllowMode::DISALLOW; + + bool requires_shader_fixup = + Common::Hacks::hack_manager.GetHackAllowMode( + Common::Hacks::HackType::REQUIRES_SHADER_FIXUP, process->codeset->program_id, + Common::Hacks::HackAllowMode::DISALLOW) != Common::Hacks::HackAllowMode::DISALLOW; + auto& gpu = system.GPU(); + gpu.ApplyPerProgramSettings(process->codeset->program_id); gpu.GetRightEyeDisabler().SetEnabled(right_eye_disable_allow); + gpu.PicaCore().vs_setup.requires_fixup = requires_shader_fixup; + gpu.PicaCore().gs_setup.requires_fixup = requires_shader_fixup; if (active_thread_id == session_data->thread_id) { return {ErrorDescription::AlreadyDone, ErrorModule::GX, ErrorSummary::Success, diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h index f5f810c44..0864e37de 100644 --- a/src/core/hle/service/gsp/gsp_gpu.h +++ b/src/core/hle/service/gsp/gsp_gpu.h @@ -30,6 +30,8 @@ class SharedMemory; namespace Service::GSP { struct FrameBufferInfo { + static constexpr u32 PIXEL_FORMAT_MASK = 0x7; + u32 active_fb; // 0 = first, 1 = second u32 address_left; u32 address_right; @@ -37,6 +39,10 @@ struct FrameBufferInfo { u32 format; // maps to 0x1EF00X70 ? u32 shown_fb; // maps to 0x1EF00X78 ? u32 unknown; + + u32 GetPixelFormat() { + return format & PIXEL_FORMAT_MASK; + } }; static_assert(sizeof(FrameBufferInfo) == 0x1c, "Struct has incorrect size"); diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 3a08ffbee..43547ee42 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -106,15 +106,19 @@ void NWM_UDS::BroadcastNodeMap() { packet.channel = network_channel; packet.type = Network::WifiPacket::PacketType::NodeMap; packet.destination_address = Network::BroadcastMac; - std::size_t num_entries = std::count_if(node_map.begin(), node_map.end(), - [](const auto& node) { return node.second.connected; }); + auto node_can_broad = [](auto& node) -> bool { + return node.second.connected && !node.second.spec; + }; + std::size_t num_entries = + std::count_if(node_map.begin(), node_map.end(), + [&node_can_broad](const auto& node) { return node_can_broad(node); }); using node_t = decltype(node_map)::value_type; packet.data.resize(sizeof(num_entries) + (sizeof(node_t::first) + sizeof(node_t::second.node_id)) * num_entries); std::memcpy(packet.data.data(), &num_entries, sizeof(num_entries)); std::size_t offset = sizeof(num_entries); for (const auto& node : node_map) { - if (node.second.connected) { + if (node_can_broad(node)) { std::memcpy(packet.data.data() + offset, node.first.data(), sizeof(node.first)); std::memcpy(packet.data.data() + offset + sizeof(node.first), &node.second.node_id, sizeof(node.second.node_id)); @@ -185,7 +189,8 @@ void NWM_UDS::HandleAssociationResponseFrame(const Network::WifiPacket& packet) using Network::WifiPacket; WifiPacket eapol_start; eapol_start.channel = network_channel; - eapol_start.data = GenerateEAPoLStartFrame(std::get(assoc_result), current_node); + eapol_start.data = + GenerateEAPoLStartFrame(std::get(assoc_result), conn_type, current_node); // TODO(B3N30): Encrypt the packet. eapol_start.destination_address = packet.transmitter_address; eapol_start.type = WifiPacket::PacketType::Data; @@ -217,24 +222,36 @@ void NWM_UDS::HandleEAPoLPacket(const Network::WifiPacket& packet) { ASSERT(connection_status.max_nodes != connection_status.total_nodes); - auto node = DeserializeNodeInfoFromFrame(packet.data); + auto eapol_start = DeserializeEAPolStartPacket(packet.data); - // Get an unused network node id - u16 node_id = GetNextAvailableNodeId(); - node.network_node_id = node_id; + auto node = DeserializeNodeInfo(eapol_start.node); - connection_status.node_bitmask |= 1 << (node_id - 1); - connection_status.changed_nodes |= 1 << (node_id - 1); - connection_status.nodes[node_id - 1] = node.network_node_id; - connection_status.total_nodes++; + if (eapol_start.conn_type == ConnectionType::Client) { + // Get an unused network node id + u16 node_id = GetNextAvailableNodeId(); + node.network_node_id = node_id; - node_info[node_id - 1] = node; - network_info.total_nodes++; + connection_status.node_bitmask |= 1 << (node_id - 1); + connection_status.changed_nodes |= 1 << (node_id - 1); + connection_status.nodes[node_id - 1] = node.network_node_id; + connection_status.total_nodes++; - node_map[packet.transmitter_address].node_id = node.network_node_id; - node_map[packet.transmitter_address].connected = true; + node_info[node_id - 1] = node; + network_info.total_nodes++; - BroadcastNodeMap(); + node_map[packet.transmitter_address].node_id = node.network_node_id; + node_map[packet.transmitter_address].connected = true; + node_map[packet.transmitter_address].spec = false; + + BroadcastNodeMap(); + } else if (eapol_start.conn_type == ConnectionType::Spectator) { + node_map[packet.transmitter_address].node_id = NodeIDSpec; + node_map[packet.transmitter_address].connected = true; + node_map[packet.transmitter_address].spec = true; + } else { + LOG_ERROR(Service_NWM, "Client tried connecting with unknown connection type: 0x{:x}", + static_cast(eapol_start.conn_type)); + } // Send the EAPoL-Logoff packet. using Network::WifiPacket; @@ -282,15 +299,23 @@ void NWM_UDS::HandleEAPoLPacket(const Network::WifiPacket& packet) { node_info[index - 1] = DeserializeNodeInfo(node); } + if (conn_type == ConnectionType::Client) { + connection_status.status = NetworkStatus::ConnectedAsClient; + } else if (conn_type == ConnectionType::Spectator) { + connection_status.status = NetworkStatus::ConnectedAsSpectator; + } else { + LOG_ERROR(Service_NWM, "Unknown connection type: 0x{:x}", static_cast(conn_type)); + } + // We're now connected, signal the application - connection_status.status = NetworkStatus::ConnectedAsClient; connection_status.status_change_reason = NetworkStatusChangeReason::ConnectionEstablished; // Some games require ConnectToNetwork to block, for now it doesn't // If blocking is implemented this lock needs to be changed, // otherwise it might cause deadlocks connection_status_event->Signal(); connection_event->Signal(); - } else if (connection_status.status == NetworkStatus::ConnectedAsClient) { + } else if (connection_status.status == NetworkStatus::ConnectedAsClient || + connection_status.status == NetworkStatus::ConnectedAsSpectator) { // TODO(B3N30): Remove that section and send/receive a proper connection_status packet // On a 3ds this packet wouldn't be addressed to already connected clients // We use this information because in the current implementation the host @@ -328,9 +353,9 @@ void NWM_UDS::HandleSecureDataPacket(const Network::WifiPacket& packet) { std::scoped_lock lock{connection_status_mutex, system.Kernel().GetHLELock()}; if (connection_status.status != NetworkStatus::ConnectedAsHost && - connection_status.status != NetworkStatus::ConnectedAsClient) { - // TODO(B3N30): Handle spectators - LOG_DEBUG(Service_NWM, "Ignored SecureDataPacket, because connection status is {}", + connection_status.status != NetworkStatus::ConnectedAsClient && + connection_status.status != NetworkStatus::ConnectedAsSpectator) { + LOG_DEBUG(Service_NWM, "Ignored SecureDataPacket because connection status is {}", static_cast(connection_status.status)); return; } @@ -370,12 +395,14 @@ void NWM_UDS::HandleSecureDataPacket(const Network::WifiPacket& packet) { // TODO(B3N30): Allow more than one bind node per channel. auto channel_info = channel_data.find(secure_data.data_channel); // Ignore packets from channels we're not interested in. - if (channel_info == channel_data.end()) + if (channel_info == channel_data.end()) { return; + } if (channel_info->second.network_node_id != BroadcastNetworkNodeId && - channel_info->second.network_node_id != secure_data.src_node_id) + channel_info->second.network_node_id != secure_data.src_node_id) { return; + } // Add the received packet to the data queue. channel_info->second.received_packets.emplace_back(packet.data); @@ -432,7 +459,9 @@ void NWM_UDS::HandleAuthenticationFrame(const Network::WifiPacket& packet) { // Only the SEQ1 auth frame is handled here, the SEQ2 frame doesn't need any special behavior if (GetAuthenticationSeqNumber(packet.data) == AuthenticationSeq::SEQ1) { using Network::WifiPacket; - WifiPacket auth_request; + AuthenticationFrame auth_request; + memcpy(&auth_request, packet.data.data(), sizeof(auth_request)); + WifiPacket auth_response; { std::scoped_lock lock(connection_status_mutex); if (connection_status.status != NetworkStatus::ConnectedAsHost) { @@ -454,13 +483,13 @@ void NWM_UDS::HandleAuthenticationFrame(const Network::WifiPacket& packet) { return; } // Respond with an authentication response frame with SEQ2 - auth_request.channel = network_channel; - auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ2); - auth_request.destination_address = packet.transmitter_address; - auth_request.type = WifiPacket::PacketType::Authentication; + auth_response.channel = network_channel; + auth_response.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ2); + auth_response.destination_address = packet.transmitter_address; + auth_response.type = WifiPacket::PacketType::Authentication; node_map[packet.transmitter_address].connected = false; } - SendPacket(auth_request); + SendPacket(auth_response); SendAssociationResponseFrame(packet.transmitter_address); } @@ -495,16 +524,16 @@ void NWM_UDS::HandleDeauthenticationFrame(const Network::WifiPacket& packet) { return; } - connection_status.node_bitmask &= ~(1 << (node.node_id - 1)); - connection_status.changed_nodes |= 1 << (node.node_id - 1); - connection_status.total_nodes--; - connection_status.nodes[node.node_id - 1] = 0; - - network_info.total_nodes--; - // TODO(B3N30): broadcast new connection_status to clients + if (!node.spec) { + connection_status.node_bitmask &= ~(1 << (node.node_id - 1)); + connection_status.changed_nodes |= 1 << (node.node_id - 1); + connection_status.total_nodes--; + connection_status.nodes[node.node_id - 1] = 0; + network_info.total_nodes--; + // TODO(B3N30): broadcast new connection_status to clients + } node_it->Reset(); - connection_status_event->Signal(); } @@ -584,71 +613,6 @@ void NWM_UDS::Shutdown(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NWM, "called"); } -void NWM_UDS::RecvBeaconBroadcastData(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx); - - u32 out_buffer_size = rp.Pop(); - u32 unk1 = rp.Pop(); - u32 unk2 = rp.Pop(); - - MacAddress mac_address; - rp.PopRaw(mac_address); - - rp.Skip(9, false); - - u32 wlan_comm_id = rp.Pop(); - u32 id = rp.Pop(); - // From 3dbrew: - // 'Official user processes create a new event handle which is then passed to this command. - // However, those user processes don't save that handle anywhere afterwards.' - // So we don't save/use that event too. - std::shared_ptr input_event = rp.PopObject(); - - Kernel::MappedBuffer out_buffer = rp.PopMappedBuffer(); - ASSERT(out_buffer.GetSize() == out_buffer_size); - - std::size_t cur_buffer_size = sizeof(BeaconDataReplyHeader); - - // Retrieve all beacon frames that were received from the desired mac address. - auto beacons = GetReceivedBeacons(mac_address); - - BeaconDataReplyHeader data_reply_header{}; - data_reply_header.total_entries = static_cast(beacons.size()); - data_reply_header.max_output_size = out_buffer_size; - - // Write each of the received beacons into the buffer - for (const auto& beacon : beacons) { - BeaconEntryHeader entry{}; - // TODO(Subv): Figure out what this size is used for. - entry.unk_size = static_cast(sizeof(BeaconEntryHeader) + beacon.data.size()); - entry.total_size = static_cast(sizeof(BeaconEntryHeader) + beacon.data.size()); - entry.wifi_channel = beacon.channel; - entry.header_size = sizeof(BeaconEntryHeader); - entry.mac_address = beacon.transmitter_address; - - ASSERT(cur_buffer_size < out_buffer_size); - - out_buffer.Write(&entry, cur_buffer_size, sizeof(BeaconEntryHeader)); - cur_buffer_size += sizeof(BeaconEntryHeader); - const unsigned char* beacon_data = beacon.data.data(); - out_buffer.Write(beacon_data, cur_buffer_size, beacon.data.size()); - cur_buffer_size += beacon.data.size(); - } - - // Update the total size in the structure and write it to the buffer again. - data_reply_header.total_size = static_cast(cur_buffer_size); - out_buffer.Write(&data_reply_header, 0, sizeof(BeaconDataReplyHeader)); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ResultSuccess); - rb.PushMappedBuffer(out_buffer); - - LOG_DEBUG(Service_NWM, - "called out_buffer_size=0x{:08X}, wlan_comm_id=0x{:08X}, id=0x{:08X}," - "unk1=0x{:08X}, unk2=0x{:08X}, offset={}", - out_buffer_size, wlan_comm_id, id, unk1, unk2, cur_buffer_size); -} - ResultVal> NWM_UDS::Initialize( u32 sharedmem_size, const NodeInfo& node, u16 version, std::shared_ptr sharedmem) { @@ -1042,6 +1006,7 @@ void NWM_UDS::DestroyNetwork(Kernel::HLERequestContext& ctx) { } void NWM_UDS::DisconnectNetwork(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NWM, "disconnecting from network"); IPC::RequestParser rp(ctx); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -1272,11 +1237,88 @@ private: friend class boost::serialization::access; }; +void NWM_UDS::RecvBeaconBroadcastData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + + u32 out_buffer_size = rp.Pop(); + + // scan input struct + u32 unk1 = rp.Pop(); + u32 unk2 = rp.Pop(); + + MacAddress mac_address; + rp.PopRaw(mac_address); + + // uninitialized data in scan input struct + rp.Skip(9, false); + + // end scan input struct + + u32 wlan_comm_id = rp.Pop(); + u32 id = rp.Pop(); + // From 3dbrew: + // 'Official user processes create a new event handle which is then passed to this command. + // However, those user processes don't save that handle anywhere afterwards.' + // So we don't save/use that event too. + std::shared_ptr input_event = rp.PopObject(); + + Kernel::MappedBuffer out_buffer = rp.PopMappedBuffer(); + ASSERT(out_buffer.GetSize() == out_buffer_size); + + std::size_t cur_buffer_size = sizeof(BeaconDataReplyHeader); + + // on a real 3ds this is about 0.38 seconds + static constexpr std::chrono::nanoseconds UDSBeaconScanInterval{300000000}; + + ctx.SleepClientThread("uds::RecvBeaconBroadcastData", UDSBeaconScanInterval, + std::make_shared(0xF)); + + // Retrieve all beacon frames that were received from the desired mac address. + auto beacons = GetReceivedBeacons(mac_address); + + BeaconDataReplyHeader data_reply_header{}; + data_reply_header.total_entries = static_cast(beacons.size()); + data_reply_header.max_output_size = out_buffer_size; + + // Write each of the received beacons into the buffer + for (const auto& beacon : beacons) { + BeaconEntryHeader entry{}; + // TODO(Subv): Figure out what this size is used for. + entry.unk_size = static_cast(sizeof(BeaconEntryHeader) + beacon.data.size()); + entry.total_size = static_cast(sizeof(BeaconEntryHeader) + beacon.data.size()); + entry.wifi_channel = beacon.channel; + entry.header_size = sizeof(BeaconEntryHeader); + entry.mac_address = beacon.transmitter_address; + + ASSERT(cur_buffer_size < out_buffer_size); + + out_buffer.Write(&entry, cur_buffer_size, sizeof(BeaconEntryHeader)); + cur_buffer_size += sizeof(BeaconEntryHeader); + const unsigned char* beacon_data = beacon.data.data(); + out_buffer.Write(beacon_data, cur_buffer_size, beacon.data.size()); + cur_buffer_size += beacon.data.size(); + } + + // Update the total size in the structure and write it to the buffer again. + data_reply_header.total_size = static_cast(cur_buffer_size); + out_buffer.Write(&data_reply_header, 0, sizeof(BeaconDataReplyHeader)); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(ResultSuccess); + rb.PushMappedBuffer(out_buffer); + + LOG_DEBUG(Service_NWM, + "called out_buffer_size=0x{:08X}, wlan_comm_id=0x{:08X}, id=0x{:08X}," + "unk1=0x{:08X}, unk2=0x{:08X}, offset={}", + out_buffer_size, wlan_comm_id, id, unk1, unk2, cur_buffer_size); +} + void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id, std::span network_info_buffer, u8 connection_type, std::vector passphrase) { network_info = {}; std::memcpy(&network_info, network_info_buffer.data(), network_info_buffer.size()); + conn_type = static_cast(connection_type); // Start the connection sequence StartConnectionSequence(network_info.host_mac_address); diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h index cf59e7bcd..045d4ba96 100644 --- a/src/core/hle/service/nwm/nwm_uds.h +++ b/src/core/hle/service/nwm/nwm_uds.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -18,6 +18,7 @@ #include #include "common/common_types.h" #include "common/swap.h" +#include "core/hle/service/nwm/uds_common.h" #include "core/hle/service/service.h" #include "network/network.h" @@ -47,6 +48,8 @@ const u16 DefaultBeaconInterval = 100; /// The maximum number of nodes that can exist in an UDS session. constexpr u32 UDSMaxNodes = 16; +constexpr u16 NodeIDSpec = 0; + struct NodeInfo { u64_le friend_code_seed; std::array username; @@ -95,7 +98,7 @@ static_assert(sizeof(ConnectionStatus) == 0x30, "ConnectionStatus has incorrect struct NetworkInfo { std::array host_mac_address; u8 channel; - INSERT_PADDING_BYTES(1); + u8 unk1; u8 initialized; INSERT_PADDING_BYTES(3); std::array oui_value; @@ -477,7 +480,7 @@ private: void HandleSecureDataPacket(const Network::WifiPacket& packet); /* - * Start a connection sequence with an UDS server. The sequence starts by sending an 802.11 + * Start a connection sequence with a UDS server. The sequence starts by sending an 802.11 * authentication frame with SEQ1. */ void StartConnectionSequence(const MacAddress& server); @@ -526,6 +529,9 @@ private: // Node information about our own system. NodeInfo current_node; + // whether you are connecting as a client or a spec + ConnectionType conn_type; + struct BindNodeData { u32 bind_node_id; ///< Id of the bind node associated with this data. u8 channel; ///< Channel that this bind node was bound to. @@ -548,6 +554,7 @@ private: // Mapping of mac addresses to their respective node_ids. struct Node { bool connected; + bool spec; u16 node_id; private: diff --git a/src/core/hle/service/nwm/uds_common.h b/src/core/hle/service/nwm/uds_common.h new file mode 100644 index 000000000..fb2e118fa --- /dev/null +++ b/src/core/hle/service/nwm/uds_common.h @@ -0,0 +1,16 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::NWM { + +enum class ConnectionType : u8 { + Client = 0x1, + Spectator = 0x2, +}; + +}; // namespace Service::NWM diff --git a/src/core/hle/service/nwm/uds_data.cpp b/src/core/hle/service/nwm/uds_data.cpp index abf2b36f9..305aec843 100644 --- a/src/core/hle/service/nwm/uds_data.cpp +++ b/src/core/hle/service/nwm/uds_data.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -286,9 +286,11 @@ SecureDataHeader ParseSecureDataHeader(std::span data) { return header; } -std::vector GenerateEAPoLStartFrame(u16 association_id, const NodeInfo& node_info) { +std::vector GenerateEAPoLStartFrame(u16 association_id, ConnectionType conn_type, + const NodeInfo& node_info) { EAPoLStartPacket eapol_start{}; eapol_start.association_id = association_id; + eapol_start.conn_type = conn_type; eapol_start.node.friend_code_seed = node_info.friend_code_seed; std::copy(node_info.username.begin(), node_info.username.end(), @@ -327,13 +329,7 @@ NodeInfo DeserializeNodeInfoFromFrame(std::span frame) { // Skip the LLC header std::memcpy(&eapol_start, frame.data() + sizeof(LLCHeader), sizeof(eapol_start)); - NodeInfo node{}; - node.friend_code_seed = eapol_start.node.friend_code_seed; - - std::copy(eapol_start.node.username.begin(), eapol_start.node.username.end(), - node.username.begin()); - - return node; + return DeserializeNodeInfo(eapol_start.node); } NodeInfo DeserializeNodeInfo(const EAPoLNodeInfo& node) { @@ -380,4 +376,11 @@ EAPoLLogoffPacket ParseEAPoLLogoffFrame(std::span frame) { return eapol_logoff; } +EAPoLStartPacket DeserializeEAPolStartPacket(std::span frame) { + EAPoLStartPacket eapol_start; + + std::memcpy(&eapol_start, frame.data() + sizeof(LLCHeader), sizeof(eapol_start)); + return eapol_start; +} + } // namespace Service::NWM diff --git a/src/core/hle/service/nwm/uds_data.h b/src/core/hle/service/nwm/uds_data.h index 291cca0f5..faaf53448 100644 --- a/src/core/hle/service/nwm/uds_data.h +++ b/src/core/hle/service/nwm/uds_data.h @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nwm/uds_beacon.h" +#include "core/hle/service/nwm/uds_common.h" #include "core/hle/service/service.h" namespace Service::NWM { @@ -90,9 +91,8 @@ constexpr u16 EAPoLStartMagic = 0x201; struct EAPoLStartPacket { u16_be magic = EAPoLStartMagic; u16_be association_id; - // This value is hardcoded to 1 in the NWM module. - u16_be unknown = 1; - INSERT_PADDING_BYTES(2); + enum_le conn_type; + INSERT_PADDING_BYTES(3); EAPoLNodeInfo node; }; @@ -132,7 +132,8 @@ SecureDataHeader ParseSecureDataHeader(std::span data); * communication. * @returns The generated frame body. */ -std::vector GenerateEAPoLStartFrame(u16 association_id, const NodeInfo& node_info); +std::vector GenerateEAPoLStartFrame(u16 association_id, ConnectionType conn_type, + const NodeInfo& node_info); /* * Returns the EtherType of the specified 802.11 frame. @@ -151,6 +152,8 @@ u16 GetEAPoLFrameType(std::span frame); */ NodeInfo DeserializeNodeInfoFromFrame(std::span frame); +EAPoLStartPacket DeserializeEAPolStartPacket(std::span frame); + /* * Returns a NodeInfo constructed from the data in the specified EAPoLNodeInfo. */ diff --git a/src/core/hle/service/plgldr/plgldr.cpp b/src/core/hle/service/plgldr/plgldr.cpp index d619a0d0d..788569383 100644 --- a/src/core/hle/service/plgldr/plgldr.cpp +++ b/src/core/hle/service/plgldr/plgldr.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +// Originally MIT-licensed code from The Pixellizer Group + // Copyright 2022 The Pixellizer Group // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and @@ -70,6 +72,9 @@ void PLG_LDR::PluginLoaderContext::serialize(Archive& ar, const unsigned int) { ar & plugin_loaded; ar & is_default_path; ar & plugin_path; + ar & memory_region; + ar & memory_block; + ar & plugin_process_id; ar & use_user_load_parameters; ar & user_load_parameters; ar & plg_event; @@ -79,7 +84,6 @@ void PLG_LDR::PluginLoaderContext::serialize(Archive& ar, const unsigned int) { ar & exe_load_checksum; ar & load_exe_func; ar & load_exe_args; - ar & plugin_fb_addr; } SERIALIZE_IMPL(PLG_LDR::PluginLoaderContext) @@ -111,9 +115,10 @@ void PLG_LDR::OnProcessRun(Kernel::Process& process, Kernel::KernelSystem& kerne } } FileSys::Plugin3GXLoader plugin_loader; + const auto low_title_Id = plgldr_context.user_load_parameters.low_title_Id; if (plgldr_context.use_user_load_parameters && - plgldr_context.user_load_parameters.low_title_Id == - static_cast(process.codeset->program_id) && + (low_title_Id == static_cast(process.codeset->program_id) || + low_title_Id == 0 /* Should load for any title */) && plgldr_context.user_load_parameters.path[0]) { std::string plugin_file = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + std::string(plgldr_context.user_load_parameters.path + 1); @@ -148,12 +153,22 @@ void PLG_LDR::OnProcessRun(Kernel::Process& process, Kernel::KernelSystem& kerne } void PLG_LDR::OnProcessExit(Kernel::Process& process, Kernel::KernelSystem& kernel) { - if (plgldr_context.plugin_loaded) { + if (plgldr_context.plugin_loaded && process.process_id == plgldr_context.plugin_process_id) { u32 status = kernel.memory.Read32(FileSys::Plugin3GXLoader::_3GX_exe_load_addr - 0xC); if (status == 0) { LOG_CRITICAL(Service_PLGLDR, "Failed to launch {}: Checksum failed", plgldr_context.plugin_path); } + if (plgldr_context.memory_region != static_cast(0)) { + kernel.GetMemoryRegion(plgldr_context.memory_region) + ->Free(plgldr_context.memory_block.first, plgldr_context.memory_block.second); + plgldr_context.memory_region = static_cast(0); + } + plgldr_context.plugin_loaded = false; + plgldr_context.plugin_process_id = UINT32_MAX; + plgldr_context.memory_changed_handle = 0; + kernel.memory.Plugin3GXFramebufferAddress() = 0; + LOG_INFO(Service_PLGLDR, "Plugin unloaded successfully."); } } diff --git a/src/core/hle/service/plgldr/plgldr.h b/src/core/hle/service/plgldr/plgldr.h index 01952b587..d18b7e24a 100644 --- a/src/core/hle/service/plgldr/plgldr.h +++ b/src/core/hle/service/plgldr/plgldr.h @@ -1,7 +1,9 @@ -// Copyright 2022 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +// Originally MIT-licensed code from The Pixellizer Group + // Copyright 2022 The Pixellizer Group // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and @@ -62,6 +64,9 @@ public: bool plugin_loaded = false; bool is_default_path = false; std::string plugin_path = ""; + u32 plugin_process_id = UINT32_MAX; + Kernel::MemoryRegion memory_region{}; + std::pair memory_block{}; bool use_user_load_parameters = false; PluginLoadParameters user_load_parameters; @@ -76,8 +81,6 @@ public: std::vector load_exe_func; u32_le load_exe_args[4] = {0}; - PAddr plugin_fb_addr = 0; - template void serialize(Archive& ar, const unsigned int); friend class boost::serialization::access; @@ -109,12 +112,6 @@ public: bool GetAllowGameChangeState() { return plgldr_context.allow_game_change; } - void SetPluginFBAddr(PAddr addr) { - plgldr_context.plugin_fb_addr = addr; - } - PAddr GetPluginFBAddr() { - return plgldr_context.plugin_fb_addr; - } private: Core::System& system; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index b574b574a..6ead40057 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -78,7 +78,7 @@ const std::array service_module_map{ false}, {"CECD", 0x00040130'00002602, CECD::InstallInterfaces, false}, {"CFG", 0x00040130'00001702, CFG::InstallInterfaces, false}, - {"DLP", 0x00040130'00002802, DLP::InstallInterfaces, false}, + {"DLP", 0x00040130'00002802, DLP::InstallInterfaces, true}, {"DSP", 0x00040130'00001A02, DSP::InstallInterfaces, false}, {"FRD", 0x00040130'00003202, FRD::InstallInterfaces, true}, {"GSP", 0x00040130'00001C02, GSP::InstallInterfaces, false}, @@ -178,7 +178,7 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(u32* cmd_buf, const Funct void ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { auto itr = handlers.find(context.CommandHeader().command_id.Value()); const FunctionInfoBase* info = itr == handlers.end() ? nullptr : &itr->second; - if (info == nullptr || info->handler_callback == nullptr) { + if (info == nullptr || !info->implemented) { context.ReportUnimplemented(); return ReportUnimplementedFunction(context.CommandBuffer(), info); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index fbe368c2c..3dddf39d4 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -82,6 +82,7 @@ private: struct FunctionInfoBase { u32 command_id; + bool implemented; HandlerFnP handler_callback; const char* name; }; @@ -96,6 +97,8 @@ private: void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); void ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info); + void Empty(Kernel::HLERequestContext& ctx) {} + /// Identifier string used to connect to the service. std::string service_name; /// Maximum number of concurrent sessions that this service can handle. @@ -134,9 +137,11 @@ protected: */ constexpr FunctionInfo(u32 command_id, HandlerFnP handler_callback, const char* name) : FunctionInfoBase{ - command_id, + command_id, handler_callback != nullptr, // Type-erase member function pointer by casting it down to the base class. - static_cast>(handler_callback), name} {} + handler_callback ? static_cast>(handler_callback) + : &ServiceFrameworkBase::Empty, + name} {} }; /** diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index e989ee7e2..83a41a5e7 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -249,6 +249,17 @@ static THREEDSX_Error Load3DSXFile(Core::System& system, FileUtil::IOFile* file, return ERROR_NONE; } +AppLoader_THREEDSX::AppLoader_THREEDSX(Core::System& system_, FileUtil::IOFile&& file, + const std::string& filename, const std::string& filepath) + : AppLoader(system_, std::move(file)), filename(filename), filepath(filepath) { + + filetype = IdentifyType(this->file.get()); + + if (FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(this->file.get()) != std::nullopt) { + this->file = std::make_unique(std::move(this->file)); + } +} + FileType AppLoader_THREEDSX::IdentifyType(FileUtil::IOFile* file) { u32 magic; file->Seek(0, SEEK_SET); @@ -270,10 +281,6 @@ ResultStatus AppLoader_THREEDSX::Load(std::shared_ptr& process) if (!file->IsOpen()) return ResultStatus::Error; - if (FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(file.get()) != std::nullopt) { - file = std::make_unique(std::move(file)); - } - std::shared_ptr codeset; if (Load3DSXFile(system, file.get(), Memory::PROCESS_IMAGE_VADDR, &codeset) != ERROR_NONE) return ResultStatus::Error; @@ -341,13 +348,12 @@ AppLoader::CompressFileInfo AppLoader_THREEDSX::GetCompressFileInfo() { info.recommended_compressed_extension = "z3dsx"; info.recommended_uncompressed_extension = "3dsx"; info.underlying_magic = std::array({'3', 'D', 'S', 'X'}); - info.is_compressed = - FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(file.get()) != std::nullopt; + info.is_compressed = file->IsCompressed(); return info; } bool AppLoader_THREEDSX::IsFileCompressed() { - return FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(file.get()) != std::nullopt; + return file->IsCompressed(); } ResultStatus AppLoader_THREEDSX::ReadIcon(std::vector& buffer) { diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h index e7cf2ab74..60c035f57 100644 --- a/src/core/loader/3dsx.h +++ b/src/core/loader/3dsx.h @@ -19,8 +19,7 @@ namespace Loader { class AppLoader_THREEDSX final : public AppLoader { public: AppLoader_THREEDSX(Core::System& system_, FileUtil::IOFile&& file, const std::string& filename, - const std::string& filepath) - : AppLoader(system_, std::move(file)), filename(filename), filepath(filepath) {} + const std::string& filepath); /** * Returns the type of the file @@ -30,7 +29,7 @@ public: static FileType IdentifyType(FileUtil::IOFile* file); FileType GetFileType() override { - return IdentifyType(file.get()); + return filetype; } ResultStatus Load(std::shared_ptr& process) override; @@ -46,6 +45,7 @@ public: private: std::string filename; std::string filepath; + FileType filetype; }; } // namespace Loader diff --git a/src/core/loader/artic.cpp b/src/core/loader/artic.cpp index 30f62dc57..9c7aefbeb 100644 --- a/src/core/loader/artic.cpp +++ b/src/core/loader/artic.cpp @@ -134,6 +134,16 @@ Apploader_Artic::LoadNew3dsHwCapabilities() { return std::make_pair(std::move(caps), ResultStatus::Success); } +bool Apploader_Artic::IsN3DSExclusive() { + std::vector smdh_buffer; + if (ReadIcon(smdh_buffer) == ResultStatus::Success && IsValidSMDH(smdh_buffer)) { + SMDH* smdh = reinterpret_cast(smdh_buffer.data()); + return smdh->flags.n3ds_exclusive != 0; + } + + return false; +} + ResultStatus Apploader_Artic::LoadExec(std::shared_ptr& process) { if (!is_loaded) diff --git a/src/core/loader/artic.h b/src/core/loader/artic.h index 13b92c189..a6de6e0fd 100644 --- a/src/core/loader/artic.h +++ b/src/core/loader/artic.h @@ -56,6 +56,8 @@ public: std::pair, ResultStatus> LoadNew3dsHwCapabilities() override; + bool IsN3DSExclusive() override; + ResultStatus IsExecutable(bool& out_executable) override; ResultStatus ReadCode(std::vector& buffer) override; diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 3b23f7762..f1d610d9e 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -48,7 +48,7 @@ FileType GuessFromExtension(const std::string& extension_) { if (extension == ".elf" || extension == ".axf") return FileType::ELF; - if (extension == ".cci" || extension == ".zcci") + if (extension == ".cci" || extension == ".zcci" || extension == ".3ds") return FileType::CCI; if (extension == ".cxi" || extension == ".app" || extension == ".zcxi") @@ -164,7 +164,11 @@ std::unique_ptr GetLoader(const std::string& filename) { FileType filename_type = GuessFromExtension(filename_extension); if (type != filename_type) { - LOG_WARNING(Loader, "File {} has a different type than its extension.", filename); + // Do not show the error for CIA files, as their type cannot be determined. + if (!(type == FileType::Unknown && filename_type == FileType::CIA)) { + LOG_WARNING(Loader, "File {} has a different type than its extension.", filename); + } + if (FileType::Unknown == type) type = filename_type; } diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 2c5ef952f..9e4c76122 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -163,6 +163,10 @@ public: ResultStatus::Success); } + virtual bool IsN3DSExclusive() { + return false; + } + /** * Get whether this application is executable. * @param out_executable Reference to store the executable flag into. @@ -298,6 +302,10 @@ public: return false; } + virtual std::string GetFilePath() { + return file ? file->Filename() : ""; + } + protected: Core::System& system; std::unique_ptr file; diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index ef33c42d3..0b2058293 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -125,6 +125,23 @@ AppLoader_NCCH::LoadNew3dsHwCapabilities() { return std::make_pair(std::move(caps), ResultStatus::Success); } +bool AppLoader_NCCH::IsN3DSExclusive() { + if (!is_loaded) { + ResultStatus res = base_ncch.Load(); + if (res != ResultStatus::Success) { + return false; + } + } + + std::vector smdh_buffer; + if (ReadIcon(smdh_buffer) == ResultStatus::Success && IsValidSMDH(smdh_buffer)) { + SMDH* smdh = reinterpret_cast(smdh_buffer.data()); + return smdh->flags.n3ds_exclusive != 0; + } + + return false; +} + ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr& process) { using Kernel::CodeSet; diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index d36e4c249..f1bf69855 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h @@ -50,6 +50,8 @@ public: std::pair, ResultStatus> LoadNew3dsHwCapabilities() override; + bool IsN3DSExclusive() override; + ResultStatus IsExecutable(bool& out_executable) override; ResultStatus ReadCode(std::vector& buffer) override; @@ -78,6 +80,10 @@ public: bool IsFileCompressed() override; + std::string GetFilePath() override { + return filepath; + } + private: /** * Loads .code section into memory for booting diff --git a/src/core/loader/smdh.h b/src/core/loader/smdh.h index 2913b195b..04a97f5d4 100644 --- a/src/core/loader/smdh.h +++ b/src/core/loader/smdh.h @@ -7,6 +7,7 @@ #include #include #include +#include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" @@ -37,7 +38,23 @@ struct SMDH { u32_le region_lockout; u32_le match_maker_id; u64_le match_maker_bit_id; - u32_le flags; + union { + u32_le raw; + + BitField<0, 1, u32> visible; + BitField<1, 1, u32> autoboot; + BitField<2, 1, u32> allow_3D; + BitField<3, 1, u32> require_eula; + BitField<4, 1, u32> autosave; + BitField<5, 1, u32> extended_banner; + BitField<6, 1, u32> rating_required; + BitField<7, 1, u32> uses_savedata; + BitField<8, 1, u32> record_usage; + BitField<10, 1, u32> disable_save_backup; + BitField<12, 1, u32> n3ds_exclusive; + BitField<14, 1, u32> parental_restricted; + } flags; + u16_le eula_version; INSERT_PADDING_BYTES(2); float_le banner_animation_frame; @@ -73,10 +90,6 @@ struct SMDH { Taiwan = 6, }; - enum Flags { - Visible = 1 << 0, - }; - /** * Checks if SMDH is valid. */ diff --git a/src/core/memory.cpp b/src/core/memory.cpp index c49aa2704..41ad049e5 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -91,19 +91,20 @@ public: std::unique_ptr fcram = std::make_unique(Memory::FCRAM_N3DS_SIZE); std::unique_ptr vram = std::make_unique(Memory::VRAM_SIZE); std::unique_ptr n3ds_extra_ram = std::make_unique(Memory::N3DS_EXTRA_RAM_SIZE); + std::unique_ptr dsp_ram = std::make_unique(Memory::DSP_RAM_SIZE); Core::System& system; std::shared_ptr current_page_table = nullptr; RasterizerCacheMarker cache_marker; std::vector> page_table_list; - AudioCore::DspInterface* dsp = nullptr; - std::shared_ptr fcram_mem; std::shared_ptr vram_mem; std::shared_ptr n3ds_extra_ram_mem; std::shared_ptr dsp_mem; + PAddr plugin_fb_address{}; + Impl(Core::System& system_); const u8* GetPtr(Region r) const { @@ -111,7 +112,7 @@ public: case Region::VRAM: return vram.get(); case Region::DSP: - return dsp->GetDspMemory().data(); + return dsp_ram.get(); case Region::FCRAM: return fcram.get(); case Region::N3DS: @@ -126,7 +127,7 @@ public: case Region::VRAM: return vram.get(); case Region::DSP: - return dsp->GetDspMemory().data(); + return dsp_ram.get(); case Region::FCRAM: return fcram.get(); case Region::N3DS: @@ -263,12 +264,8 @@ public: if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { return {vram_mem, addr - VRAM_VADDR}; } - if (addr >= PLUGIN_3GX_FB_VADDR && addr < PLUGIN_3GX_FB_VADDR_END) { - auto plg_ldr = Service::PLGLDR::GetService(system); - if (plg_ldr) { - return {fcram_mem, - addr - PLUGIN_3GX_FB_VADDR + plg_ldr->GetPluginFBAddr() - FCRAM_PADDR}; - } + if (addr >= PLUGIN_3GX_FB_VADDR && addr < PLUGIN_3GX_FB_VADDR_END && plugin_fb_address) { + return {fcram_mem, addr - PLUGIN_3GX_FB_VADDR + plugin_fb_address - FCRAM_PADDR}; } UNREACHABLE(); @@ -307,9 +304,8 @@ public: CheckRegion(LINEAR_HEAP_VADDR, LINEAR_HEAP_VADDR_END, FCRAM_PADDR); CheckRegion(NEW_LINEAR_HEAP_VADDR, NEW_LINEAR_HEAP_VADDR_END, FCRAM_PADDR); CheckRegion(VRAM_VADDR, VRAM_VADDR_END, VRAM_PADDR); - auto plg_ldr = Service::PLGLDR::GetService(system); - if (plg_ldr && plg_ldr->GetPluginFBAddr()) { - CheckRegion(PLUGIN_3GX_FB_VADDR, PLUGIN_3GX_FB_VADDR_END, plg_ldr->GetPluginFBAddr()); + if (plugin_fb_address) { + CheckRegion(PLUGIN_3GX_FB_VADDR, PLUGIN_3GX_FB_VADDR_END, plugin_fb_address); } } @@ -324,6 +320,7 @@ private: fcram.get(), save_n3ds_ram ? Memory::FCRAM_N3DS_SIZE : Memory::FCRAM_SIZE); ar& boost::serialization::make_binary_object( n3ds_extra_ram.get(), save_n3ds_ram ? Memory::N3DS_EXTRA_RAM_SIZE : 0); + ar& boost::serialization::make_binary_object(dsp_ram.get(), Memory::DSP_RAM_SIZE); ar & cache_marker; ar & page_table_list; // dsp is set from Core::System at startup @@ -332,6 +329,7 @@ private: ar & vram_mem; ar & n3ds_extra_ram_mem; ar & dsp_mem; + ar & plugin_fb_address; } }; @@ -390,6 +388,10 @@ void MemorySystem::RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode impl->RasterizerFlushVirtualRegion(start, size, mode); } +PAddr& Memory::MemorySystem::Plugin3GXFramebufferAddress() { + return impl->plugin_fb_address; +} + void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type) { LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), @@ -638,13 +640,10 @@ std::string MemorySystem::ReadCString(VAddr vaddr, std::size_t max_length) { return string; } -u8* MemorySystem::GetPhysicalPointer(PAddr address) { - return GetPhysicalRef(address); -} - -MemoryRef MemorySystem::GetPhysicalRef(PAddr address) { - if (address == physical_ptr_cache.first) { - return physical_ptr_cache.second; +MemorySystem::PhysMemRegionInfo MemorySystem::GetPhysMemRegionInfo(PAddr address) { + if (address >= phys_mem_region_info_cache.region_start && + address < phys_mem_region_info_cache.region_end) { + return phys_mem_region_info_cache; } constexpr std::array memory_areas = { @@ -661,38 +660,52 @@ MemoryRef MemorySystem::GetPhysicalRef(PAddr address) { }); if (area == memory_areas.end()) [[unlikely]] { - LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#08X} at PC {:#08X}", address, + LOG_ERROR(HW_Memory, "Unknown GetPhysMemRegionInfo @ {:#08X} at PC {:#08X}", address, impl->GetPC()); - physical_ptr_cache = {address, {nullptr}}; - return physical_ptr_cache.second; + phys_mem_region_info_cache = PhysMemRegionInfo(); + return phys_mem_region_info_cache; } - u32 offset_into_region = address - area->first; - - std::shared_ptr target_mem = nullptr; switch (area->first) { case VRAM_PADDR: - target_mem = impl->vram_mem; + phys_mem_region_info_cache = {&impl->vram_mem, area->first, area->second}; break; case DSP_RAM_PADDR: - target_mem = impl->dsp_mem; + phys_mem_region_info_cache = {&impl->dsp_mem, area->first, area->second}; break; case FCRAM_PADDR: - target_mem = impl->fcram_mem; + phys_mem_region_info_cache = {&impl->fcram_mem, area->first, area->second}; break; case N3DS_EXTRA_RAM_PADDR: - target_mem = impl->n3ds_extra_ram_mem; + phys_mem_region_info_cache = {&impl->n3ds_extra_ram_mem, area->first, area->second}; break; default: UNREACHABLE(); } - if (offset_into_region > target_mem->GetSize()) [[unlikely]] { - physical_ptr_cache = {address, {nullptr}}; - return physical_ptr_cache.second; + + return phys_mem_region_info_cache; +} + +u8* MemorySystem::GetPhysicalPointer(PAddr address) { + auto target_mem = GetPhysMemRegionInfo(address); + + if (!target_mem.valid()) [[unlikely]] { + return {nullptr}; } - physical_ptr_cache = {address, {target_mem, offset_into_region}}; - return physical_ptr_cache.second; + u32 offset_into_region = address - target_mem.region_start; + return target_mem.backing_mem->get()->GetPtr() + offset_into_region; +} + +MemoryRef MemorySystem::GetPhysicalRef(PAddr address) { + const auto& target_mem = GetPhysMemRegionInfo(address); + + if (!target_mem.valid()) [[unlikely]] { + return {nullptr}; + } + + u32 offset_into_region = address - target_mem.region_start; + return {*target_mem.backing_mem, offset_into_region}; } std::vector MemorySystem::PhysicalToVirtualAddressForRasterizer(PAddr addr) { @@ -700,12 +713,9 @@ std::vector MemorySystem::PhysicalToVirtualAddressForRasterizer(PAddr add return {addr - VRAM_PADDR + VRAM_VADDR}; } // NOTE: Order matters here. - auto plg_ldr = Service::PLGLDR::GetService(impl->system); - if (plg_ldr) { - auto fb_addr = plg_ldr->GetPluginFBAddr(); - if (addr >= fb_addr && addr < fb_addr + PLUGIN_3GX_FB_SIZE) { - return {addr - fb_addr + PLUGIN_3GX_FB_VADDR}; - } + PAddr plg_fb_addr = Plugin3GXFramebufferAddress(); + if (plg_fb_addr && addr >= plg_fb_addr && addr < plg_fb_addr + PLUGIN_3GX_FB_SIZE) { + return {addr - plg_fb_addr + PLUGIN_3GX_FB_VADDR}; } if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { return {addr - FCRAM_PADDR + LINEAR_HEAP_VADDR, addr - FCRAM_PADDR + NEW_LINEAR_HEAP_VADDR}; @@ -989,8 +999,9 @@ MemoryRef MemorySystem::GetFCRAMRef(std::size_t offset) const { return MemoryRef(impl->fcram_mem, offset); } -void MemorySystem::SetDSP(AudioCore::DspInterface& dsp) { - impl->dsp = &dsp; +u8* MemorySystem::GetDspMemory(std::size_t offset) const { + ASSERT(offset <= Memory::DSP_RAM_SIZE); + return impl->dsp_ram.get() + offset; } } // namespace Memory diff --git a/src/core/memory.h b/src/core/memory.h index a3245f8ca..5c215b3f2 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -641,10 +641,14 @@ public: /// Unregisters page table for rasterizer cache marking void UnregisterPageTable(std::shared_ptr page_table); - void SetDSP(AudioCore::DspInterface& dsp); + /// Gets pointer to DSP shared memory with given offset + u8* GetDspMemory(std::size_t offset) const; void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode); + /// Returns a reference to the framebuffer address of the currently loaded 3GX plugin. + PAddr& Plugin3GXFramebufferAddress(); + private: template T Read(const std::shared_ptr& page_table, const VAddr vaddr); @@ -663,14 +667,35 @@ private: */ MemoryRef GetPointerForRasterizerCache(VAddr addr) const; - void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type); + class PhysMemRegionInfo { + public: + // Use a pointer to the shared pointer instead of the shared pointer directly to prevent + // overhead in hot code. + const std::shared_ptr* backing_mem{}; - std::pair physical_ptr_cache; + PAddr region_start{}; + PAddr region_end{}; + + PhysMemRegionInfo() = default; + + PhysMemRegionInfo(const std::shared_ptr* mem, PAddr reg_start, size_t reg_size) + : backing_mem(mem), region_start{reg_start}, + region_end{reg_start + static_cast(reg_size)} {} + + bool valid() const { + return backing_mem != nullptr; + } + }; + PhysMemRegionInfo GetPhysMemRegionInfo(PAddr address); + + void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type); private: class Impl; std::unique_ptr impl; + PhysMemRegionInfo phys_mem_region_info_cache{}; + friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int file_version); diff --git a/src/installer/citra.nsi b/src/installer/citra.nsi index 505fb3753..99af76203 100644 --- a/src/installer/citra.nsi +++ b/src/installer/citra.nsi @@ -17,6 +17,8 @@ !error "PRODUCT_VARIANT must be defined" !endif +ManifestDPIAware true + !define PRODUCT_NAME "Azahar" !define PRODUCT_PUBLISHER "Azahar Emulator Developers" !define PRODUCT_WEB_SITE "https://azahar-emu.org/" @@ -60,6 +62,7 @@ Page custom desktopShortcutPageCreate desktopShortcutPageLeave ; Instfiles page !insertmacro MUI_PAGE_INSTFILES ; Finish page +!define MUI_FINISHPAGE_RUN "$INSTDIR\azahar.exe" !insertmacro MUI_PAGE_FINISH ; Uninstaller pages @@ -106,7 +109,6 @@ Function .onInit StrCpy $DesktopShortcut 1 !insertmacro MULTIUSER_INIT - ; Keep in sync with build_info.txt !define MIN_WIN10_VERSION 1607 ${IfNot} ${AtLeastwin10} ${OrIfNot} ${AtLeastWaaS} ${MIN_WIN10_VERSION} @@ -123,9 +125,9 @@ FunctionEnd !macro UPDATE_DISPLAYNAME ${If} $MultiUser.InstallMode == "CurrentUser" - StrCpy $DisplayName "$(^Name) (User)" + StrCpy $DisplayName "${PRODUCT_NAME} (User)" ${Else} - StrCpy $DisplayName "$(^Name)" + StrCpy $DisplayName "${PRODUCT_NAME}" ${EndIf} !macroend @@ -165,9 +167,6 @@ Section "Base" ${If} $DesktopShortcut == 1 CreateShortCut "$DESKTOP\$DisplayName.lnk" "$INSTDIR\azahar.exe" ${EndIf} - - ; ?? - SetOutPath "$TEMP" SectionEnd !include "FileFunc.nsh" @@ -207,9 +206,10 @@ Section Uninstall RMDir /r "$INSTDIR\scripting" RMDir "$INSTDIR" + DeleteRegKey HKCU "Software\Classes\discord-1345366770436800533" + DeleteRegKey SHCTX "${PRODUCT_UNINST_KEY}" DeleteRegKey SHCTX "${PRODUCT_DIR_REGKEY}" - DeleteRegKey HKCU "Software\Classes\discord-1345366770436800533" SetAutoClose true SectionEnd diff --git a/src/network/artic_base/artic_base_client.cpp b/src/network/artic_base/artic_base_client.cpp index 861e23477..b38416cc4 100644 --- a/src/network/artic_base/artic_base_client.cpp +++ b/src/network/artic_base/artic_base_client.cpp @@ -6,6 +6,7 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "algorithm" #include "chrono" #include "limits.h" #include "memory" @@ -143,15 +144,35 @@ void Client::UDPStream::Handle() { } // Limit receive buffer so that packets don't get qeued and are dropped instead. - int buffer_size_int = static_cast(buffer_size); - if (::setsockopt(main_socket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&buffer_size_int), - sizeof(buffer_size_int)) || + // macOS requires larger UDP buffer sizes for reliable operation +#ifdef __APPLE__ + const int min_macos_buffer_size = 8192; // 8KB minimum for macOS + int effective_buffer_size = std::max(static_cast(buffer_size), min_macos_buffer_size); +#else + int effective_buffer_size = static_cast(buffer_size); +#endif + + if (::setsockopt(main_socket, SOL_SOCKET, SO_RCVBUF, + reinterpret_cast(&effective_buffer_size), + sizeof(effective_buffer_size)) < 0 || !thread_run) { + LOG_ERROR(Network, "Cannot change receive buffer size: {} (errno: {})", strerror(GET_ERRNO), + GET_ERRNO); closesocket(main_socket); - LOG_ERROR(Network, "Cannot change receive buffer size"); return; } + // Verify the buffer size was actually set + socklen_t actual_size_len = sizeof(int); + int actual_buffer_size; + if (::getsockopt(main_socket, SOL_SOCKET, SO_RCVBUF, + reinterpret_cast(&actual_buffer_size), &actual_size_len) == 0) { + LOG_INFO(Network, "UDP buffer size set to: {} (requested: {})", actual_buffer_size, + effective_buffer_size); + } else { + LOG_WARNING(Network, "Could not verify UDP buffer size setting"); + } + // Send data to server so that it knows client address. char zero = '\0'; int send_res = diff --git a/src/tests/audio_core/hle/hle.cpp b/src/tests/audio_core/hle/hle.cpp index 09e7ec5ab..9c4396973 100644 --- a/src/tests/audio_core/hle/hle.cpp +++ b/src/tests/audio_core/hle/hle.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -22,8 +22,7 @@ TEST_CASE("DSP LLE vs HLE", "[audio_core][hle]") { Memory::MemorySystem lle_memory{system}; Core::Timing lle_core_timing(1, 100); Kernel::KernelSystem lle_kernel( - lle_memory, lle_core_timing, [] {}, Kernel::MemoryMode::Prod, 1, - Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); + lle_memory, lle_core_timing, [] {}, Kernel::MemoryMode::NewProd, 1); AudioCore::DspHle hle(system, hle_memory, hle_core_timing); AudioCore::DspLle lle(system, lle_memory, lle_core_timing, true); diff --git a/src/tests/audio_core/merryhime_3ds_audio/merry_audio/service_fixture.cpp b/src/tests/audio_core/merryhime_3ds_audio/merry_audio/service_fixture.cpp index 9417cea97..7b3169920 100644 --- a/src/tests/audio_core/merryhime_3ds_audio/merry_audio/service_fixture.cpp +++ b/src/tests/audio_core/merryhime_3ds_audio/merry_audio/service_fixture.cpp @@ -1,3 +1,7 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #include "audio_core/hle/hle.h" #include "audio_core/lle/lle.h" #include "common/settings.h" @@ -85,7 +89,7 @@ Result ServiceFixture::DSP_ReadPipeIfPossible(u32 channel, u32 /*peer*/, void* o Result ServiceFixture::ServiceFixture::DSP_ConvertProcessAddressFromDspDram(u32 dsp_address, u16** host_address) { *host_address = reinterpret_cast( - (dsp_address << 1) + (reinterpret_cast(dsp->GetDspMemory().data()) + 0x40000u)); + (dsp_address << 1) + (reinterpret_cast(memory.GetDspMemory(0)) + 0x40000u)); return ResultSuccess; } diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp index f908e5f2c..372ea563f 100644 --- a/src/tests/core/hle/kernel/hle_ipc.cpp +++ b/src/tests/core/hle/kernel/hle_ipc.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -23,9 +23,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel Core::Timing timing(1, 100); Core::System system; Memory::MemorySystem memory{system}; - Kernel::KernelSystem kernel( - memory, timing, [] {}, Kernel::MemoryMode::Prod, 1, - Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); + Kernel::KernelSystem kernel(memory, timing, [] {}, Kernel::MemoryMode::NewProd, 1); auto [server, client] = kernel.CreateSessionPair(); HLERequestContext context(kernel, std::move(server), nullptr); @@ -256,9 +254,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { Core::Timing timing(1, 100); Core::System system; Memory::MemorySystem memory{system}; - Kernel::KernelSystem kernel( - memory, timing, [] {}, Kernel::MemoryMode::Prod, 1, - Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); + Kernel::KernelSystem kernel(memory, timing, [] {}, Kernel::MemoryMode::NewProd, 1); auto [server, client] = kernel.CreateSessionPair(); HLERequestContext context(kernel, std::move(server), nullptr); diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp index 597ac5132..6254c3b0d 100644 --- a/src/tests/core/memory/memory.cpp +++ b/src/tests/core/memory/memory.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -12,9 +12,7 @@ TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") { Core::Timing timing(1, 100); Core::System system; Memory::MemorySystem memory{system}; - Kernel::KernelSystem kernel( - memory, timing, [] {}, Kernel::MemoryMode::Prod, 1, - Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); + Kernel::KernelSystem kernel(memory, timing, [] {}, Kernel::MemoryMode::NewProd, 1); SECTION("these regions should not be mapped on an empty process") { auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); diff --git a/src/tests/core/memory/vm_manager.cpp b/src/tests/core/memory/vm_manager.cpp index f58ad2e5b..c15760d8a 100644 --- a/src/tests/core/memory/vm_manager.cpp +++ b/src/tests/core/memory/vm_manager.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -16,9 +16,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") { Core::Timing timing(1, 100); Core::System system; Memory::MemorySystem memory{system}; - Kernel::KernelSystem kernel( - memory, timing, [] {}, Kernel::MemoryMode::Prod, 1, - Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); + Kernel::KernelSystem kernel(memory, timing, [] {}, Kernel::MemoryMode::NewProd, 1); Kernel::Process process(kernel); SECTION("mapping memory") { // Because of the PageTable, Kernel::VMManager is too big to be created on the stack. diff --git a/src/tests/video_core/shader.cpp b/src/tests/video_core/shader.cpp index 8747808d2..db868a260 100644 --- a/src/tests/video_core/shader.cpp +++ b/src/tests/video_core/shader.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -63,11 +63,15 @@ static std::unique_ptr CompileShaderSetup( const auto shbin = nihstro::InlineAsm::CompileToRawBinary(code); auto shader = std::make_unique(); - - std::transform(shbin.program.begin(), shbin.program.end(), shader->program_code.begin(), + Pica::ProgramCode program_code{}; + Pica::SwizzleData swizzle_data{}; + std::transform(shbin.program.begin(), shbin.program.end(), program_code.begin(), [](const auto& x) { return x.hex; }); - std::transform(shbin.swizzle_table.begin(), shbin.swizzle_table.end(), - shader->swizzle_data.begin(), [](const auto& x) { return x.hex; }); + std::transform(shbin.swizzle_table.begin(), shbin.swizzle_table.end(), swizzle_data.begin(), + [](const auto& x) { return x.hex; }); + + shader->UpdateProgramCode(program_code); + shader->UpdateSwizzleData(swizzle_data); return shader; } @@ -143,12 +147,16 @@ private: class ShaderJitTest : public ShaderTest { public: explicit ShaderJitTest(std::initializer_list code) : ShaderTest(code) { - shader_jit.Compile(&shader_setup->program_code, &shader_setup->swizzle_data); + const auto& program_code = shader_setup->GetProgramCode(); + const auto& swizzle_data = shader_setup->GetSwizzleData(); + shader_jit.Compile(&program_code, &swizzle_data); } explicit ShaderJitTest(std::unique_ptr input_shader_setup) : ShaderTest(std::move(input_shader_setup)) { - shader_jit.Compile(&shader_setup->program_code, &shader_setup->swizzle_data); + const auto& program_code = shader_setup->GetProgramCode(); + const auto& swizzle_data = shader_setup->GetSwizzleData(); + shader_jit.Compile(&program_code, &swizzle_data); } void RunShader(Pica::ShaderUnit& shader_unit, std::span inputs) override { @@ -210,12 +218,12 @@ SHADER_TEST_CASE("CALL", "[video_core][shader]") { // call foo CALL.flow_control.dest_offset = 2; CALL.flow_control.num_instructions = 1; - shader_setup->program_code[0] = CALL.hex; + shader_setup->UpdateProgramCode(0, CALL.hex); // call ex2 CALL.flow_control.dest_offset = 4; CALL.flow_control.num_instructions = 1; - shader_setup->program_code[2] = CALL.hex; + shader_setup->UpdateProgramCode(2, CALL.hex); auto shader = TestType(std::move(shader_setup)); @@ -608,7 +616,7 @@ SHADER_TEST_CASE("MAD", "[video_core][shader]") { MAD.mad.src2 = sh_input2; MAD.mad.src3 = sh_input3; MAD.mad.dest = sh_output; - shader_setup->program_code[0] = MAD.hex; + shader_setup->UpdateProgramCode(0, MAD.hex); nihstro::SwizzlePattern swizzle = {}; swizzle.dest_mask = 0b1111; @@ -624,7 +632,7 @@ SHADER_TEST_CASE("MAD", "[video_core][shader]") { swizzle.SetSelectorSrc3(1, SwizzlePattern::Selector::y); swizzle.SetSelectorSrc3(2, SwizzlePattern::Selector::z); swizzle.SetSelectorSrc3(3, SwizzlePattern::Selector::w); - shader_setup->swizzle_data[0] = swizzle.hex; + shader_setup->UpdateSwizzleData(0, swizzle.hex); auto shader = TestType(std::move(shader_setup)); @@ -713,7 +721,7 @@ SHADER_TEST_CASE("Conditional", "[video_core][shader]") { { auto shader_setup = CompileShaderSetup(assembly_template); IFC.flow_control.op = nihstro::Instruction::FlowControlType::Op::JustX; - shader_setup->program_code[0] = IFC.hex; + shader_setup->UpdateProgramCode(0, IFC.hex); const float result = result_x ? 1.0f : 0.0f; auto shader_test = TestType(std::move(shader_setup)); @@ -726,7 +734,7 @@ SHADER_TEST_CASE("Conditional", "[video_core][shader]") { { auto shader_setup = CompileShaderSetup(assembly_template); IFC.flow_control.op = nihstro::Instruction::FlowControlType::Op::JustY; - shader_setup->program_code[0] = IFC.hex; + shader_setup->UpdateProgramCode(0, IFC.hex); const float result = result_y ? 1.0f : 0.0f; auto shader_test = TestType(std::move(shader_setup)); @@ -739,7 +747,7 @@ SHADER_TEST_CASE("Conditional", "[video_core][shader]") { { auto shader_setup = CompileShaderSetup(assembly_template); IFC.flow_control.op = nihstro::Instruction::FlowControlType::Op::Or; - shader_setup->program_code[0] = IFC.hex; + shader_setup->UpdateProgramCode(0, IFC.hex); const float result = (result_x || result_y) ? 1.0f : 0.0f; auto shader_test = TestType(std::move(shader_setup)); @@ -752,7 +760,7 @@ SHADER_TEST_CASE("Conditional", "[video_core][shader]") { { auto shader_setup = CompileShaderSetup(assembly_template); IFC.flow_control.op = nihstro::Instruction::FlowControlType::Op::And; - shader_setup->program_code[0] = IFC.hex; + shader_setup->UpdateProgramCode(0, IFC.hex); const float result = (result_x && result_y) ? 1.0f : 0.0f; auto shader_test = TestType(std::move(shader_setup)); diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 27076cbe4..3da82159e 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -189,6 +189,8 @@ if (ENABLE_VULKAN) renderer_vulkan/vk_present_window.h renderer_vulkan/vk_render_manager.cpp renderer_vulkan/vk_render_manager.h + renderer_vulkan/vk_shader_disk_cache.cpp + renderer_vulkan/vk_shader_disk_cache.h renderer_vulkan/vk_shader_util.cpp renderer_vulkan/vk_shader_util.h renderer_vulkan/vk_stream_buffer.cpp diff --git a/src/video_core/custom_textures/custom_tex_manager.cpp b/src/video_core/custom_textures/custom_tex_manager.cpp index 2ec3c946b..58e5fe918 100644 --- a/src/video_core/custom_textures/custom_tex_manager.cpp +++ b/src/video_core/custom_textures/custom_tex_manager.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -228,7 +228,8 @@ void CustomTexManager::PreloadTextures(const std::atomic_bool& stop_run, material->LoadFromDisk(flip_png_files); size_sum += material->size; if (callback) { - callback(VideoCore::LoadCallbackStage::Preload, preloaded, custom_textures.size()); + callback(VideoCore::LoadCallbackStage::Preload, preloaded, custom_textures.size(), + ""); } preloaded++; } diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 88ee841c1..9b76be5fc 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -1,5 +1,5 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include @@ -184,17 +184,18 @@ void DumpShader(const std::string& filename, const ShaderRegs& config, const Sha dvlb.dvle_offset = QueueForWriting(reinterpret_cast(&dvle), sizeof(dvle)); // TODO: Reduce the amount of binary code written to relevant portions + const auto& program_code = setup.GetProgramCode(); dvlp.binary_offset = write_offset - dvlp_offset; - dvlp.binary_size_words = static_cast(setup.program_code.size()); - QueueForWriting(reinterpret_cast(setup.program_code.data()), - static_cast(setup.program_code.size()) * sizeof(u32)); + dvlp.binary_size_words = static_cast(program_code.size()); + QueueForWriting(reinterpret_cast(program_code.data()), + static_cast(program_code.size()) * sizeof(u32)); + const auto& swizzle_data = setup.GetSwizzleData(); dvlp.swizzle_info_offset = write_offset - dvlp_offset; - dvlp.swizzle_info_num_entries = static_cast(setup.swizzle_data.size()); + dvlp.swizzle_info_num_entries = static_cast(swizzle_data.size()); u32 dummy = 0; - for (unsigned int i = 0; i < setup.swizzle_data.size(); ++i) { - QueueForWriting(reinterpret_cast(&setup.swizzle_data[i]), - sizeof(setup.swizzle_data[i])); + for (unsigned int i = 0; i < swizzle_data.size(); ++i) { + QueueForWriting(reinterpret_cast(&swizzle_data[i]), sizeof(swizzle_data[i])); QueueForWriting(reinterpret_cast(&dummy), sizeof(dummy)); } @@ -272,7 +273,7 @@ void StartPicaTracing() { } void OnPicaRegWrite(u16 cmd_id, u16 mask, u32 value) { - if (!g_is_pica_tracing) + if (!g_is_pica_tracing) [[likely]] return; std::lock_guard lock(pica_trace_mutex); diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 74d5eeb46..37272d4ad 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -57,11 +57,10 @@ PAddr GPU::VirtualToPhysicalAddress(VAddr addr) { if (addr >= Memory::NEW_LINEAR_HEAP_VADDR && addr <= Memory::NEW_LINEAR_HEAP_VADDR_END) { return addr - Memory::NEW_LINEAR_HEAP_VADDR + Memory::FCRAM_PADDR; } - if (addr >= Memory::PLUGIN_3GX_FB_VADDR && addr <= Memory::PLUGIN_3GX_FB_VADDR_END) { - auto plg_ldr = Service::PLGLDR::GetService(impl->system); - if (plg_ldr) { - return addr - Memory::PLUGIN_3GX_FB_VADDR + plg_ldr->GetPluginFBAddr(); - } + PAddr plg_fb_addr; + if (addr >= Memory::PLUGIN_3GX_FB_VADDR && addr <= Memory::PLUGIN_3GX_FB_VADDR_END && + (plg_fb_addr = impl->system.Memory().Plugin3GXFramebufferAddress())) { + return addr - Memory::PLUGIN_3GX_FB_VADDR + plg_fb_addr; } LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x{:08X}", addr); @@ -312,7 +311,7 @@ GraphicsDebugger& GPU::Debugger() { return impl->gpu_debugger; } -void GPU::ReportLoadingProgramID(u64 program_ID) { +void GPU::ApplyPerProgramSettings(u64 program_ID) { auto hack = Common::Hacks::hack_manager.GetHack( Common::Hacks::HackType::ACCURATE_MULTIPLICATION, program_ID); bool use_accurate_mul = Settings::values.shaders_accurate_mul.GetValue(); diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index c2d344a2c..1b326a067 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -94,7 +94,7 @@ public: return *right_eye_disabler; } - void ReportLoadingProgramID(u64 program_ID); + void ApplyPerProgramSettings(u64 program_ID); private: void SubmitCmdList(u32 index); diff --git a/src/video_core/pica/dirty_regs.h b/src/video_core/pica/dirty_regs.h index cf0410e92..3cdb31b9b 100644 --- a/src/video_core/pica/dirty_regs.h +++ b/src/video_core/pica/dirty_regs.h @@ -16,6 +16,10 @@ union DirtyRegs { qwords[reg_id >> 6] |= 1ULL << (reg_id & 0x3f); } + void SetAllDirty() { + qwords.fill(UINT64_MAX); + } + void Reset() { qwords.fill(0ULL); } diff --git a/src/video_core/pica/pica_core.cpp b/src/video_core/pica/pica_core.cpp index d12a986c1..9f19e9572 100644 --- a/src/video_core/pica/pica_core.cpp +++ b/src/video_core/pica/pica_core.cpp @@ -35,6 +35,7 @@ PicaCore::PicaCore(Memory::MemorySystem& memory_, std::shared_ptr geometry_pipeline{regs.internal, gs_unit, gs_setup}, shader_engine{CreateEngine(Settings::values.use_shader_jit.GetValue())} { InitializeRegs(); + dirty_regs.SetAllDirty(); const auto submit_vertex = [this](const AttributeBuffer& buffer) { const auto add_triangle = [this](const OutputVertex& v0, const OutputVertex& v1, @@ -258,8 +259,7 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask, bool& stop_requeste if (offset >= 4096) { LOG_ERROR(HW_GPU, "Invalid GS program offset {}", offset); } else { - gs_setup.program_code[offset] = value; - gs_setup.MarkProgramCodeDirty(); + gs_setup.UpdateProgramCode(offset, value); offset++; } break; @@ -274,11 +274,10 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask, bool& stop_requeste case PICA_REG_INDEX(gs.swizzle_patterns.set_word[6]): case PICA_REG_INDEX(gs.swizzle_patterns.set_word[7]): { u32& offset = regs.internal.gs.swizzle_patterns.offset; - if (offset >= gs_setup.swizzle_data.size()) { + if (offset >= gs_setup.GetSwizzleData().size()) { LOG_ERROR(HW_GPU, "Invalid GS swizzle pattern offset {}", offset); } else { - gs_setup.swizzle_data[offset] = value; - gs_setup.MarkSwizzleDataDirty(); + gs_setup.UpdateSwizzleData(offset, value); offset++; } break; @@ -340,11 +339,10 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask, bool& stop_requeste if (offset >= 512) { LOG_ERROR(HW_GPU, "Invalid VS program offset {}", offset); } else { - vs_setup.program_code[offset] = value; - vs_setup.MarkProgramCodeDirty(); - if (!regs.internal.pipeline.gs_unit_exclusive_configuration) { - gs_setup.program_code[offset] = value; - gs_setup.MarkProgramCodeDirty(); + vs_setup.UpdateProgramCode(offset, value); + if (!regs.internal.pipeline.gs_unit_exclusive_configuration && + regs.internal.pipeline.use_gs == PipelineRegs::UseGS::No) { + gs_setup.UpdateProgramCode(offset, value); } offset++; } @@ -360,14 +358,13 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask, bool& stop_requeste case PICA_REG_INDEX(vs.swizzle_patterns.set_word[6]): case PICA_REG_INDEX(vs.swizzle_patterns.set_word[7]): { u32& offset = regs.internal.vs.swizzle_patterns.offset; - if (offset >= vs_setup.swizzle_data.size()) { + if (offset >= vs_setup.GetSwizzleData().size()) { LOG_ERROR(HW_GPU, "Invalid VS swizzle pattern offset {}", offset); } else { - vs_setup.swizzle_data[offset] = value; - vs_setup.MarkSwizzleDataDirty(); - if (!regs.internal.pipeline.gs_unit_exclusive_configuration) { - gs_setup.swizzle_data[offset] = value; - gs_setup.MarkSwizzleDataDirty(); + vs_setup.UpdateSwizzleData(offset, value); + if (!regs.internal.pipeline.gs_unit_exclusive_configuration && + regs.internal.pipeline.use_gs == PipelineRegs::UseGS::No) { + gs_setup.UpdateSwizzleData(offset, value); } offset++; } diff --git a/src/video_core/pica/pica_core.h b/src/video_core/pica/pica_core.h index 8cdcb493d..61d8e75c2 100644 --- a/src/video_core/pica/pica_core.h +++ b/src/video_core/pica/pica_core.h @@ -185,6 +185,9 @@ public: template void serialize(Archive& ar, const u32 file_version) { ar& boost::serialization::make_binary_object(this, sizeof(ProcTex)); + if (Archive::is_loading::value) { + table_dirty = TableAllDirty; + } } }; @@ -225,6 +228,9 @@ public: template void serialize(Archive& ar, const u32 file_version) { ar& boost::serialization::make_binary_object(this, sizeof(Lighting)); + if (Archive::is_loading::value) { + lut_dirty = LutAllDirty; + } } }; @@ -253,6 +259,9 @@ public: template void serialize(Archive& ar, const u32 file_version) { ar& boost::serialization::make_binary_object(this, sizeof(Fog)); + if (Archive::is_loading::value) { + lut_dirty = true; + } } }; @@ -285,6 +294,9 @@ private: ar & geometry_pipeline; ar & primitive_assembler; ar & cmd_list; + if (Archive::is_loading::value) { + dirty_regs.SetAllDirty(); + } } public: diff --git a/src/video_core/pica/shader_setup.cpp b/src/video_core/pica/shader_setup.cpp index 70808b02f..64647a442 100644 --- a/src/video_core/pica/shader_setup.cpp +++ b/src/video_core/pica/shader_setup.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/assert.h" #include "common/bit_set.h" #include "common/hash.h" @@ -51,7 +52,9 @@ std::optional ShaderSetup::WriteUniformFloatReg(ShaderRegs& config, u32 val u64 ShaderSetup::GetProgramCodeHash() { if (program_code_hash_dirty) { - program_code_hash = Common::ComputeHash64(&program_code, sizeof(program_code)); + const auto& prog_code = GetProgramCode(); + program_code_hash = + Common::ComputeHash64(prog_code.data(), biggest_program_size * sizeof(u32)); program_code_hash_dirty = false; } return program_code_hash; @@ -59,10 +62,126 @@ u64 ShaderSetup::GetProgramCodeHash() { u64 ShaderSetup::GetSwizzleDataHash() { if (swizzle_data_hash_dirty) { - swizzle_data_hash = Common::ComputeHash64(&swizzle_data, sizeof(swizzle_data)); + swizzle_data_hash = + Common::ComputeHash64(swizzle_data.data(), biggest_swizzle_size * sizeof(u32)); swizzle_data_hash_dirty = false; } return swizzle_data_hash; } +void ShaderSetup::DoProgramCodeFixup() { + // This function holds shader fixups that are required for proper emulation of some games. As + // emulation gets more accurate the goal is to have this function as empty as possible. + // WARNING: If the hashing method is changed, the hashes of the different shaders will need + // adjustment. + + if (!requires_fixup || !program_code_pending_fixup) { + return; + } + program_code_pending_fixup = false; + + auto prepare_for_fixup = [this]() { + memcpy(program_code_fixup.data(), program_code.data(), program_code.size()); + has_fixup = true; + program_code_hash_dirty = true; + }; + + /** + * Affected games: + * Some Sega 3D Classics games. + * + * Problem: + * The geometry shaders used by some of the Sega 3D Classics have a shader + * (gf2_five_color_gshader.vsh) that presents two separate issues. + * + * - The shader does not have an "end" instruction. This causes the execution + * to be unbounded and start running whatever is in the code buffer after the end of the + * program. Usually this is filled with zeroes, which are add instructions that have no effect + * due to no more vertices being emitted. It's not clear what happens when the PC reaches + * 0x3FFC and is incremented. The most likely scenario is that it overflows back to the start, + * where there is an end instruction close by. This causes the game to execute around 4K + * instructions per vertex, which is very slow on emulator. + * + * - The shader relies on a HW bug or quirk that we do not currently understand or implement. + * The game builds a quad (4 vertices) using two inputs, the upper left coordinate, and the + * bottom right coordinate. The generated vertex coordinates are put in output register o0 + * before being emitted. Here is the pseudocode of the shader: + * o0.xyzw = leftTop.xyzw + * emit <- Emits the top left vertex + * o0._yzw = leftTop.xyzw + * o0.x___ = rightBottom.xyzw + * emit <- Emits the top right vertex + * o0._y__ = rightBottom.xyzw + * emit <- Emits the bottom left vertex (!) + * o0.xyzw = rightBottom.xyzw + * emit <- Emits the bottom right vertex + * + * This shader code has a bug. When the bottom left vertex is emitted, the y element is + * updated to the bottom coordinate, but the x element is left untouched. One would say that + * since the x element was last set to the RIGHT coordinate, the vertex would end up being + * drawn to the bottom RIGHT instead of the intended bottom LEFT (which is what we observe on + * the emulator). But on real HW, the vertex is drawn to the bottom LEFT instead. This + * suggests a HW bug or quirk that is triggered whenever some elements of an output register + * are not written to between emits. In order for the quad to look proper, the xzw elements + * should somehow keep the contents from the first emit, where the top left coordinate was + * written. The specifics of the HW bug that causes this are unknown. + * + * Solution: + * The following patches are made to fix the shaders: + * + * - An end instruction is inserted at the end of the shader to prevent unbounded execution. + * + * - Before the third vertex is emited and the y element of o0 is adjusted, a mov o0.xywz + * leftTop.xywz instruction is inserted to update the xzw elements of the output register to + * the expected values. This requires making room in the shader code, but luckily there are no + * jumps that need relocation. + * + */ + constexpr u64 SEGA_3D_CLASSICS_THUNDER_BLADE = 0x0797513756f2c8c9; + constexpr u64 SEGA_3D_CLASSICS_AFTER_BURNER = 0x188e959fbe31324d; + constexpr u64 SEGA_3D_CLASSICS_COLLECTION_TB = 0x5954c8e4d13cdd86; + constexpr u64 SEGA_3D_CLASSICS_COLLECTION_PD = 0x27496993b307355b; + + const auto fix_3d_classics_common = [this](u32 offset_base, u32 mov_swizzle) { + offset_base /= 4; + + // Make some room to insert an instruction + std::memmove(program_code_fixup.data() + offset_base + 1, + program_code_fixup.data() + offset_base, 0x1C); + + // mov o0.xyzw v0.xyzw (out.pos <- vLeftTop) + program_code_fixup[offset_base] = 0x4c000000 | mov_swizzle; + + // end + program_code_fixup[offset_base + 0x20] = 0x88000000; + + // Adjust biggest program size + if (biggest_program_size <= offset_base + 0x20) { + biggest_program_size = offset_base + 0x20 + 1; + } + }; + + // Select shader fixup + switch (GetProgramCodeHash()) { + case SEGA_3D_CLASSICS_THUNDER_BLADE: { + prepare_for_fixup(); + fix_3d_classics_common(0x510, 0xA); + } break; + case SEGA_3D_CLASSICS_AFTER_BURNER: { + prepare_for_fixup(); + fix_3d_classics_common(0x50C, 0xA); + } break; + case SEGA_3D_CLASSICS_COLLECTION_TB: { + prepare_for_fixup(); + fix_3d_classics_common(0xAE0, 0xC); + } break; + case SEGA_3D_CLASSICS_COLLECTION_PD: { + prepare_for_fixup(); + fix_3d_classics_common(0xAF0, 0xC); + } break; + default: + break; + } +} + } // namespace Pica diff --git a/src/video_core/pica/shader_setup.h b/src/video_core/pica/shader_setup.h index ad4981b95..afad847e8 100644 --- a/src/video_core/pica/shader_setup.h +++ b/src/video_core/pica/shader_setup.h @@ -51,6 +51,17 @@ struct ShaderRegs; * The geometry shaders has a unique configuration so when enabled it has its own setup. */ struct ShaderSetup { +private: + void MakeProgramCodeDirty() { + program_code_hash_dirty = true; + program_code_pending_fixup = true; + has_fixup = false; + } + + void MakeSwizzleDataDirty() { + swizzle_data_hash_dirty = true; + } + public: explicit ShaderSetup(); ~ShaderSetup(); @@ -65,28 +76,88 @@ public: u64 GetSwizzleDataHash(); - void MarkProgramCodeDirty() { - program_code_hash_dirty = true; + void DoProgramCodeFixup(); + + inline void UpdateProgramCode(size_t offset, u32 value) { + u32& inst = program_code[offset]; + u32 old = inst; + + if (old == value) + return; + + inst = value; + if (!program_code_hash_dirty) { + MakeProgramCodeDirty(); + } + if ((offset + 1) > biggest_program_size) { + biggest_program_size = offset + 1; + } } - void MarkSwizzleDataDirty() { - swizzle_data_hash_dirty = true; + void UpdateProgramCode(const ProgramCode& other, u32 other_size = MAX_PROGRAM_CODE_LENGTH) { + program_code = other; + biggest_program_size = std::max(biggest_program_size, other_size); + MakeProgramCodeDirty(); + } + + inline void UpdateSwizzleData(size_t offset, u32 value) { + u32& data = swizzle_data[offset]; + u32 old = data; + + if (old == value) + return; + + data = value; + if (!swizzle_data_hash_dirty) { + MakeSwizzleDataDirty(); + } + if ((offset + 1) > biggest_swizzle_size) { + biggest_swizzle_size = offset + 1; + } + } + + void UpdateSwizzleData(const SwizzleData& other, u32 other_size = MAX_SWIZZLE_DATA_LENGTH) { + swizzle_data = other; + biggest_swizzle_size = std::max(biggest_swizzle_size, other_size); + MakeSwizzleDataDirty(); + } + + const ProgramCode& GetProgramCode() const { + return (has_fixup) ? program_code_fixup : program_code; + } + + const SwizzleData& GetSwizzleData() const { + return swizzle_data; + } + + u32 GetBiggestProgramSize() const { + return biggest_program_size; + } + + u32 GetBiggestSwizzleSize() const { + return biggest_swizzle_size; } public: Uniforms uniforms; PackedAttribute uniform_queue; - ProgramCode program_code{}; - SwizzleData swizzle_data{}; u32 entry_point{}; const void* cached_shader{}; bool uniforms_dirty = true; + bool requires_fixup = false; + bool has_fixup = false; private: + ProgramCode program_code{}; + ProgramCode program_code_fixup{}; + SwizzleData swizzle_data{}; bool program_code_hash_dirty{true}; bool swizzle_data_hash_dirty{true}; - u64 program_code_hash{0xDEADC0DE}; - u64 swizzle_data_hash{0xDEADC0DE}; + bool program_code_pending_fixup{true}; + u32 biggest_program_size = 0; + u32 biggest_swizzle_size = 0; + u64 program_code_hash{0}; + u64 swizzle_data_hash{0}; friend class boost::serialization::access; template @@ -94,11 +165,20 @@ private: ar & uniforms; ar & uniform_queue; ar & program_code; + ar & program_code_fixup; ar & swizzle_data; ar & program_code_hash_dirty; ar & swizzle_data_hash_dirty; + ar & program_code_pending_fixup; + ar & biggest_program_size; + ar & biggest_swizzle_size; ar & program_code_hash; ar & swizzle_data_hash; + ar & requires_fixup; + ar & has_fixup; + if (Archive::is_loading::value) { + uniforms_dirty = true; + } } }; diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index 65aa6aeca..09d936020 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -1053,9 +1053,10 @@ u64 RasterizerCache::ComputeHash(const SurfaceParams& load_info, std::span(width * height * bpp); DecodeTexture(load_info, load_info.addr, load_info.end, upload_data, decoded, false); - return Common::ComputeHash64(decoded.data(), decoded.size()); + return Common::ComputeHash64(decoded.data(), decoded.size()); } else { - return Common::ComputeHash64(upload_data.data(), upload_data.size()); + return Common::ComputeHash64(upload_data.data(), + upload_data.size()); } } diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 01b82f2f0..88bdd35c0 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -26,7 +26,8 @@ enum class LoadCallbackStage { Build, Complete, }; -using DiskResourceLoadCallback = std::function; +using DiskResourceLoadCallback = + std::function; class RasterizerInterface { public: diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index 16b59107a..e78ab9c91 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -35,7 +35,7 @@ void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) { window.UpdateCurrentFramebufferLayout(layout.width, layout.height, is_portrait_mode); }; update_layout(render_window); - if (secondary_window) { + if (secondary_window != nullptr) { update_layout(*secondary_window); } } @@ -66,5 +66,4 @@ void RendererBase::RequestScreenshot(void* data, std::function callb settings.screenshot_framebuffer_layout = layout; settings.screenshot_requested = true; } - } // namespace VideoCore diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index a44d513fd..5a737a37f 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -61,7 +61,8 @@ public: virtual void CleanupVideoDumping() {} /// This is called to notify the rendering backend of a surface change - virtual void NotifySurfaceChanged() {} + // if second == true then it is the second screen + virtual void NotifySurfaceChanged(bool second) {} /// Returns the resolution scale factor relative to the native 3DS screen resolution u32 GetResolutionScaleFactor(); @@ -106,10 +107,12 @@ public: protected: Core::System& system; RendererSettings settings; - Frontend::EmuWindow& render_window; ///< Reference to the render window handle. - Frontend::EmuWindow* secondary_window; ///< Reference to the secondary render window handle. - f32 current_fps = 0.0f; ///< Current framerate, should be set by the renderer - s32 current_frame = 0; ///< Current frame, should be set by the renderer + Frontend::EmuWindow& render_window; /// Reference to the render window handle. + Frontend::EmuWindow* secondary_window; /// Reference to the secondary render window handle. + +protected: + f32 current_fps = 0.0f; /// Current framerate, should be set by the renderer + s32 current_frame = 0; /// Current frame, should be set by the renderer }; } // namespace VideoCore diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index c8b6f725b..2c721bcf7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -211,14 +211,14 @@ void RasterizerOpenGL::SwitchDiskResources(u64 title_id) { render_window, driver, title_id, !driver.IsOpenGLES())); if (switch_disk_resources_callback) { - switch_disk_resources_callback(VideoCore::LoadCallbackStage::Prepare, 0, 0); + switch_disk_resources_callback(VideoCore::LoadCallbackStage::Prepare, 0, 0, ""); } std::atomic_bool stop_loading; new_manager->LoadDiskCache(stop_loading, switch_disk_resources_callback, accurate_mul); if (switch_disk_resources_callback) { - switch_disk_resources_callback(VideoCore::LoadCallbackStage::Complete, 0, 0); + switch_disk_resources_callback(VideoCore::LoadCallbackStage::Complete, 0, 0, ""); } } diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index e70319ef3..786fb3fc5 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -9,6 +9,7 @@ #include #include #include +#include "common/hash.h" #include "common/settings.h" #include "core/frontend/emu_window.h" #include "video_core/pica/shader_setup.h" @@ -89,15 +90,10 @@ static std::tuple BuildVSConfigFromRaw( std::copy_n(raw.GetProgramCode().begin() + Pica::MAX_PROGRAM_CODE_LENGTH, Pica::MAX_SWIZZLE_DATA_LENGTH, swizzle_data.begin()); Pica::ShaderSetup setup; - setup.program_code = program_code; - setup.swizzle_data = swizzle_data; + setup.UpdateProgramCode(program_code); + setup.UpdateSwizzleData(swizzle_data); - // Enable the geometry-shader only if we are actually doing per-fragment lighting - // and care about proper quaternions. Otherwise just use standard vertex+fragment shaders - const bool use_geometry_shader = !raw.GetRawShaderConfig().lighting.disable; - return {PicaVSConfig{raw.GetRawShaderConfig(), setup, driver.HasClipCullDistance(), - use_geometry_shader, accurate_mul}, - setup}; + return {PicaVSConfig{raw.GetRawShaderConfig(), setup}, setup}; } /** @@ -163,31 +159,31 @@ public: ~ShaderCache() = default; template - std::tuple> Get(const KeyConfigType& config, - Args&&... args) { - auto [iter, new_shader] = shaders.emplace(config, OGLShaderStage{separable}); + std::tuple> Get(const KeyConfigType& config, + Args&&... args) { + auto [iter, new_shader] = shaders.emplace(config.Hash(), OGLShaderStage{separable}); OGLShaderStage& cached_shader = iter->second; std::optional result{}; if (new_shader) { result = CodeGenerator(config, args...); cached_shader.Create(result->c_str(), ShaderType); } - return {cached_shader.GetHandle(), std::move(result)}; + return {iter->first, cached_shader.GetHandle(), std::move(result)}; } void Inject(const KeyConfigType& key, OGLProgram&& program) { OGLShaderStage stage{separable}; stage.Inject(std::move(program)); - shaders.emplace(key, std::move(stage)); + shaders.emplace(key.Hash(), std::move(stage)); } void Inject(const KeyConfigType& key, OGLShaderStage&& stage) { - shaders.emplace(key, std::move(stage)); + shaders.emplace(key.Hash(), std::move(stage)); } private: bool separable; - std::unordered_map shaders; + std::unordered_map shaders; }; // This is a cache designed for shaders translated from PICA shaders. The first cache matches the @@ -195,62 +191,68 @@ private: // GLSL code. The configuration is like this because there might be leftover code in the PICA shader // program buffer from the previous shader, which is hashed into the config, resulting several // different config values from the same shader program. -template class ShaderDoubleCache { public: - explicit ShaderDoubleCache(bool separable) : separable(separable) {} - std::tuple> Get(const KeyConfigType& key, - const Pica::ShaderSetup& setup) { + explicit ShaderDoubleCache(bool _separable) : separable{_separable} {} + std::tuple> Get(const KeyConfigType& key, + const ExtraConfigType& extra, + const Pica::ShaderSetup& setup) { std::optional result{}; - auto map_it = shader_map.find(key); + const size_t key_hash = key.Hash(); + auto map_it = shader_map.find(key_hash); if (map_it == shader_map.end()) { - auto program = CodeGenerator(setup, key, separable); + auto program = Common::HashableString(CodeGenerator(setup, key, extra)); if (program.empty()) { - shader_map[key] = nullptr; - return {0, std::nullopt}; + shader_map[key_hash] = nullptr; + return {0, 0, std::nullopt}; } - auto [iter, new_shader] = shader_cache.emplace(program, OGLShaderStage{separable}); + auto [iter, new_shader] = + shader_cache.emplace(program.Hash(), OGLShaderStage{separable}); OGLShaderStage& cached_shader = iter->second; if (new_shader) { - result = program; - cached_shader.Create(program.c_str(), ShaderType); + result = std::move(program); + cached_shader.Create((*result).c_str(), ShaderType); } - shader_map[key] = &cached_shader; - return {cached_shader.GetHandle(), std::move(result)}; + shader_map[key_hash] = &cached_shader; + return {key_hash, cached_shader.GetHandle(), std::move(result)}; } if (map_it->second == nullptr) { - return {0, std::nullopt}; + return {0, 0, std::nullopt}; } - return {map_it->second->GetHandle(), std::nullopt}; + return {key_hash, map_it->second->GetHandle(), std::nullopt}; } void Inject(const KeyConfigType& key, std::string decomp, OGLProgram&& program) { OGLShaderStage stage{separable}; stage.Inject(std::move(program)); - const auto iter = shader_cache.emplace(std::move(decomp), std::move(stage)).first; + auto decomp_hash = Common::HashableString(std::move(decomp)); + const auto iter = shader_cache.emplace(decomp_hash.Hash(), std::move(stage)).first; OGLShaderStage& cached_shader = iter->second; - shader_map.insert_or_assign(key, &cached_shader); + shader_map.insert_or_assign(key.Hash(), &cached_shader); } void Inject(const KeyConfigType& key, std::string decomp, OGLShaderStage&& stage) { - const auto iter = shader_cache.emplace(std::move(decomp), std::move(stage)).first; + auto decomp_hash = Common::HashableString(std::move(decomp)); + const auto iter = shader_cache.emplace(decomp_hash.Hash(), std::move(stage)).first; OGLShaderStage& cached_shader = iter->second; - shader_map.insert_or_assign(key, &cached_shader); + shader_map.insert_or_assign(key.Hash(), &cached_shader); } private: bool separable; - std::unordered_map shader_map; - std::unordered_map shader_cache; + std::unordered_map shader_map; + std::unordered_map shader_cache; }; using ProgrammableVertexShaders = - ShaderDoubleCache; + ShaderDoubleCache; using FixedGeometryShaders = ShaderCache; @@ -326,6 +328,23 @@ public: std::unordered_map program_cache; OGLPipeline pipeline; ShaderDiskCache disk_cache; + + Pica::Shader::Generator::ExtraVSConfig CalcExtraConfig( + const Pica::Shader::Generator::PicaVSConfig& config, bool accurate_mul) { + auto res = ExtraVSConfig(); + + // Enable the geometry-shader only if we are actually doing per-fragment lighting + // and care about proper quaternions. Otherwise just use standard vertex+fragment shaders. + const bool use_geometry_shader = !config.state.lighting_disable; + + res.use_clip_planes = profile.has_clip_planes; + res.use_geometry_shader = use_geometry_shader; + res.sanitize_mul = accurate_mul; + res.separable_shader = separable; + res.load_flags.fill(AttribLoadFlags::Float); + + return res; + } }; ShaderProgramManager::ShaderProgramManager(Frontend::EmuWindow& emu_window_, const Driver& driver_, @@ -339,27 +358,26 @@ ShaderProgramManager::~ShaderProgramManager() = default; bool ShaderProgramManager::UseProgrammableVertexShader(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, bool accurate_mul) { - // Enable the geometry-shader only if we are actually doing per-fragment lighting - // and care about proper quaternions. Otherwise just use standard vertex+fragment shaders - const bool use_geometry_shader = !regs.lighting.disable; - PicaVSConfig config{regs, setup, driver.HasClipCullDistance(), use_geometry_shader, - accurate_mul}; - auto [handle, result] = impl->programmable_vertex_shaders.Get(config, setup); + PicaVSConfig config{regs, setup}; + ExtraVSConfig extra = impl->CalcExtraConfig(config, accurate_mul); + + auto [hash, handle, result] = impl->programmable_vertex_shaders.Get(config, extra, setup); if (handle == 0) return false; impl->current.vs = handle; - impl->current.vs_hash = config.Hash(); + impl->current.vs_hash = hash; // Save VS to the disk cache if its a new shader if (result) { auto& disk_cache = impl->disk_cache; - ProgramCode program_code{setup.program_code.begin(), setup.program_code.end()}; - program_code.insert(program_code.end(), setup.swizzle_data.begin(), - setup.swizzle_data.end()); - const u64 unique_identifier = GetUniqueIdentifier(regs, program_code); + const auto& program_code = setup.GetProgramCode(); + const auto& swizzle_data = setup.GetSwizzleData(); + ProgramCode new_program_code{program_code.begin(), program_code.end()}; + new_program_code.insert(new_program_code.end(), swizzle_data.begin(), swizzle_data.end()); + const u64 unique_identifier = GetUniqueIdentifier(regs, new_program_code); const ShaderDiskCacheRaw raw{unique_identifier, ProgramType::VS, regs, - std::move(program_code)}; + std::move(new_program_code)}; disk_cache.SaveRaw(raw); disk_cache.SaveDecompiled(unique_identifier, *result, accurate_mul); } @@ -372,10 +390,15 @@ void ShaderProgramManager::UseTrivialVertexShader() { } void ShaderProgramManager::UseFixedGeometryShader(const Pica::RegsInternal& regs) { - PicaFixedGSConfig gs_config(regs, driver.HasClipCullDistance()); - auto [handle, _] = impl->fixed_geometry_shaders.Get(gs_config, impl->separable); + PicaFixedGSConfig gs_config(regs); + ExtraFixedGSConfig extra{ + .use_clip_planes = driver.HasClipCullDistance(), + .separable_shader = impl->separable, + }; + + auto [hash, handle, _] = impl->fixed_geometry_shaders.Get(gs_config, extra); impl->current.gs = handle; - impl->current.gs_hash = gs_config.Hash(); + impl->current.gs_hash = hash; } void ShaderProgramManager::UseTrivialGeometryShader() { @@ -385,10 +408,10 @@ void ShaderProgramManager::UseTrivialGeometryShader() { void ShaderProgramManager::UseFragmentShader(const Pica::RegsInternal& regs, const Pica::Shader::UserConfig& user) { - const FSConfig fs_config{regs, user, impl->profile}; - auto [handle, result] = impl->fragment_shaders.Get(fs_config, impl->profile); + const FSConfig fs_config{regs}; + auto [hash, handle, result] = impl->fragment_shaders.Get(fs_config, user, impl->profile); impl->current.fs = handle; - impl->current.fs_hash = fs_config.Hash(); + impl->current.fs_hash = hash; // Save FS to the disk cache if its a new shader if (result) { auto& disk_cache = impl->disk_cache; @@ -456,7 +479,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, std::mutex mutex; std::atomic_bool compilation_failed = false; if (callback) { - callback(VideoCore::LoadCallbackStage::Decompile, 0, raws.size()); + callback(VideoCore::LoadCallbackStage::Decompile, 0, raws.size(), ""); } std::vector load_raws_index; // Loads both decompiled and precompiled shaders from the cache. If either one is missing for @@ -512,7 +535,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, std::move(shader)); } else if (raw.GetProgramType() == ProgramType::FS) { // TODO: Support UserConfig in disk shader cache - const FSConfig conf(raw.GetRawShaderConfig(), {}, impl->profile); + const FSConfig conf(raw.GetRawShaderConfig()); std::scoped_lock lock(mutex); impl->fragment_shaders.Inject(conf, std::move(shader)); } else { @@ -529,7 +552,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, load_raws_index.push_back(i); } if (callback) { - callback(VideoCore::LoadCallbackStage::Decompile, i, raw_cache.size()); + callback(VideoCore::LoadCallbackStage::Decompile, i, raw_cache.size(), ""); } } }; @@ -560,7 +583,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, break; } if (callback) { - callback(VideoCore::LoadCallbackStage::Decompile, ++i, dump_map.size()); + callback(VideoCore::LoadCallbackStage::Decompile, ++i, dump_map.size(), ""); } } }; @@ -589,7 +612,7 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, const std::size_t load_raws_size = load_all_raws ? raws.size() : load_raws_index.size(); if (callback) { - callback(VideoCore::LoadCallbackStage::Build, 0, load_raws_size); + callback(VideoCore::LoadCallbackStage::Build, 0, load_raws_size, "Shader"); } compilation_failed = false; @@ -614,17 +637,18 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, // precompiled file if (raw.GetProgramType() == ProgramType::VS) { auto [conf, setup] = BuildVSConfigFromRaw(raw, driver, accurate_mul); - code = GLSL::GenerateVertexShader(setup, conf, impl->separable); + ExtraVSConfig extra = impl->CalcExtraConfig(conf, accurate_mul); + code = GLSL::GenerateVertexShader(setup, conf, extra); OGLShaderStage stage{impl->separable}; stage.Create(code.c_str(), GL_VERTEX_SHADER); handle = stage.GetHandle(); - sanitize_mul = conf.state.sanitize_mul; + sanitize_mul = accurate_mul; std::scoped_lock lock(mutex); impl->programmable_vertex_shaders.Inject(conf, code, std::move(stage)); } else if (raw.GetProgramType() == ProgramType::FS) { // TODO: Support UserConfig in disk shader cache - const FSConfig fs_config{raw.GetRawShaderConfig(), {}, impl->profile}; - code = GLSL::GenerateFragmentShader(fs_config, impl->profile); + const FSConfig fs_config{raw.GetRawShaderConfig()}; + code = GLSL::GenerateFragmentShader(fs_config, {}, impl->profile); OGLShaderStage stage{impl->separable}; stage.Create(code.c_str(), GL_FRAGMENT_SHADER); handle = stage.GetHandle(); @@ -652,7 +676,8 @@ void ShaderProgramManager::LoadDiskCache(const std::atomic_bool& stop_loading, } if (callback) { - callback(VideoCore::LoadCallbackStage::Build, ++built_shaders, load_raws_size); + callback(VideoCore::LoadCallbackStage::Build, ++built_shaders, load_raws_size, + "Shader"); } } }; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 0dd68c55b..967fd21fa 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -100,7 +100,15 @@ void RendererOpenGL::SwapBuffers() { const auto& main_layout = render_window.GetFramebufferLayout(); RenderToMailbox(main_layout, render_window.mailbox, false); -#ifndef ANDROID +#ifdef ANDROID + // On Android, if secondary_window is defined at all, + // it means we have a second display + if (secondary_window) { + const auto& secondary_layout = secondary_window->GetFramebufferLayout(); + RenderToMailbox(secondary_layout, secondary_window->mailbox, false); + secondary_window->PollEvents(); + } +#else if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) { ASSERT(secondary_window); const auto& secondary_layout = secondary_window->GetFramebufferLayout(); @@ -108,6 +116,7 @@ void RendererOpenGL::SwapBuffers() { secondary_window->PollEvents(); } #endif + if (frame_dumper.IsDumping()) { try { RenderToMailbox(frame_dumper.GetLayout(), frame_dumper.mailbox, true); @@ -317,7 +326,7 @@ void RendererOpenGL::InitOpenGLObjects() { glSamplerParameteri(samplers[i].handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - ReloadShader(); + ReloadShader(Settings::values.render_3d.GetValue()); // Generate VBO handle for drawing vertex_buffer.Create(); @@ -363,10 +372,10 @@ void RendererOpenGL::InitOpenGLObjects() { state.Apply(); } -void RendererOpenGL::ReloadShader() { +void RendererOpenGL::ReloadShader(Settings::StereoRenderOption render_3d) { // Link shaders and get variable locations std::string shader_data = fragment_shader_precision_OES; - if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Anaglyph) { + if (render_3d == Settings::StereoRenderOption::Anaglyph) { if (Settings::values.anaglyph_shader_name.GetValue() == "Dubois (builtin)") { shader_data += HostShaders::OPENGL_PRESENT_ANAGLYPH_FRAG; } else { @@ -379,9 +388,8 @@ void RendererOpenGL::ReloadShader() { shader_data += shader_text; } } - } else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Interlaced || - Settings::values.render_3d.GetValue() == - Settings::StereoRenderOption::ReverseInterlaced) { + } else if (render_3d == Settings::StereoRenderOption::Interlaced || + render_3d == Settings::StereoRenderOption::ReverseInterlaced) { shader_data += HostShaders::OPENGL_PRESENT_INTERLACED_FRAG; } else { if (Settings::values.pp_shader_name.GetValue() == "None (builtin)") { @@ -402,17 +410,16 @@ void RendererOpenGL::ReloadShader() { state.Apply(); uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix"); uniform_color_texture = glGetUniformLocation(shader.handle, "color_texture"); - if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Anaglyph || - Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Interlaced || - Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::ReverseInterlaced) { + if (render_3d == Settings::StereoRenderOption::Anaglyph || + render_3d == Settings::StereoRenderOption::Interlaced || + render_3d == Settings::StereoRenderOption::ReverseInterlaced) { uniform_color_texture_r = glGetUniformLocation(shader.handle, "color_texture_r"); } - if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Interlaced || - Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::ReverseInterlaced) { + if (render_3d == Settings::StereoRenderOption::Interlaced || + render_3d == Settings::StereoRenderOption::ReverseInterlaced) { GLuint uniform_reverse_interlaced = glGetUniformLocation(shader.handle, "reverse_interlaced"); - if (Settings::values.render_3d.GetValue() == - Settings::StereoRenderOption::ReverseInterlaced) + if (render_3d == Settings::StereoRenderOption::ReverseInterlaced) glUniform1i(uniform_reverse_interlaced, 1); else glUniform1i(uniform_reverse_interlaced, 0); @@ -649,7 +656,7 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f // Update fragment shader before drawing shader.Release(); // Link shaders and get variable locations - ReloadShader(); + ReloadShader(layout.render_3d_mode); } const auto& top_screen = layout.top_screen; @@ -667,9 +674,9 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f glUniform1i(uniform_color_texture, 0); const bool stereo_single_screen = - Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Anaglyph || - Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Interlaced || - Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::ReverseInterlaced; + layout.render_3d_mode == Settings::StereoRenderOption::Anaglyph || + layout.render_3d_mode == Settings::StereoRenderOption::Interlaced || + layout.render_3d_mode == Settings::StereoRenderOption::ReverseInterlaced; // Bind a second texture for the right eye if in Anaglyph mode if (stereo_single_screen) { @@ -680,12 +687,12 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f if (!Settings::values.swap_screen.GetValue()) { DrawTopScreen(layout, top_screen); glUniform1i(uniform_layer, 0); - ApplySecondLayerOpacity(layout.is_portrait); + ApplySecondLayerOpacity(layout.bottom_opacity); DrawBottomScreen(layout, bottom_screen); } else { DrawBottomScreen(layout, bottom_screen); glUniform1i(uniform_layer, 0); - ApplySecondLayerOpacity(layout.is_portrait); + ApplySecondLayerOpacity(layout.top_opacity); DrawTopScreen(layout, top_screen); } @@ -697,33 +704,23 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f DrawBottomScreen(layout, additional_screen); } } - ResetSecondLayerOpacity(layout.is_portrait); + ResetSecondLayerOpacity(); } -void RendererOpenGL::ApplySecondLayerOpacity(bool isPortrait) { - // TODO: Allow for second layer opacity in portrait mode android - - if (!isPortrait && - (Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout) && - Settings::values.custom_second_layer_opacity.GetValue() < 100) { - state.blend.src_rgb_func = GL_CONSTANT_ALPHA; - state.blend.src_a_func = GL_CONSTANT_ALPHA; - state.blend.dst_a_func = GL_ONE_MINUS_CONSTANT_ALPHA; - state.blend.dst_rgb_func = GL_ONE_MINUS_CONSTANT_ALPHA; - state.blend.color.alpha = Settings::values.custom_second_layer_opacity.GetValue() / 100.0f; - } +void RendererOpenGL::ApplySecondLayerOpacity(float opacity) { + state.blend.src_rgb_func = GL_CONSTANT_ALPHA; + state.blend.src_a_func = GL_CONSTANT_ALPHA; + state.blend.dst_a_func = GL_ONE_MINUS_CONSTANT_ALPHA; + state.blend.dst_rgb_func = GL_ONE_MINUS_CONSTANT_ALPHA; + state.blend.color.alpha = opacity; } -void RendererOpenGL::ResetSecondLayerOpacity(bool isPortrait) { - if (!isPortrait && - (Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout) && - Settings::values.custom_second_layer_opacity.GetValue() < 100) { - state.blend.src_rgb_func = GL_ONE; - state.blend.dst_rgb_func = GL_ZERO; - state.blend.src_a_func = GL_ONE; - state.blend.dst_a_func = GL_ZERO; - state.blend.color.alpha = 0.0f; - } +void RendererOpenGL::ResetSecondLayerOpacity() { + state.blend.src_rgb_func = GL_ONE; + state.blend.dst_rgb_func = GL_ZERO; + state.blend.src_a_func = GL_ONE; + state.blend.dst_a_func = GL_ZERO; + state.blend.color.alpha = 0.0f; } void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, @@ -731,6 +728,9 @@ void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, if (!layout.top_screen_enabled) { return; } + int leftside, rightside; + leftside = Settings::values.swap_eyes_3d.GetValue() ? 1 : 0; + rightside = Settings::values.swap_eyes_3d.GetValue() ? 0 : 1; const float top_screen_left = static_cast(top_screen.left); const float top_screen_top = static_cast(top_screen.top); @@ -739,7 +739,7 @@ void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, const auto orientation = layout.is_rotated ? Layout::DisplayOrientation::Landscape : Layout::DisplayOrientation::Portrait; - switch (Settings::values.render_3d.GetValue()) { + switch (layout.render_3d_mode) { case Settings::StereoRenderOption::Off: { const int eye = static_cast(Settings::values.mono_render_option.GetValue()); DrawSingleScreen(screen_infos[eye], top_screen_left, top_screen_top, top_screen_width, @@ -747,29 +747,29 @@ void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, break; } case Settings::StereoRenderOption::SideBySide: { - DrawSingleScreen(screen_infos[0], top_screen_left / 2, top_screen_top, top_screen_width / 2, - top_screen_height, orientation); + DrawSingleScreen(screen_infos[leftside], top_screen_left / 2, top_screen_top, + top_screen_width / 2, top_screen_height, orientation); glUniform1i(uniform_layer, 1); - DrawSingleScreen(screen_infos[1], + DrawSingleScreen(screen_infos[rightside], static_cast((top_screen_left / 2) + (layout.width / 2)), top_screen_top, top_screen_width / 2, top_screen_height, orientation); break; } - case Settings::StereoRenderOption::ReverseSideBySide: { - DrawSingleScreen(screen_infos[1], top_screen_left / 2, top_screen_top, top_screen_width / 2, + case Settings::StereoRenderOption::SideBySideFull: { + DrawSingleScreen(screen_infos[leftside], top_screen_left, top_screen_top, top_screen_width, top_screen_height, orientation); glUniform1i(uniform_layer, 1); - DrawSingleScreen(screen_infos[0], - static_cast((top_screen_left / 2) + (layout.width / 2)), - top_screen_top, top_screen_width / 2, top_screen_height, orientation); + DrawSingleScreen(screen_infos[rightside], + static_cast(top_screen_left + layout.width / 2), top_screen_top, + top_screen_width, top_screen_height, orientation); break; } case Settings::StereoRenderOption::CardboardVR: { - DrawSingleScreen(screen_infos[0], top_screen_left, top_screen_top, top_screen_width, + DrawSingleScreen(screen_infos[leftside], top_screen_left, top_screen_top, top_screen_width, top_screen_height, orientation); glUniform1i(uniform_layer, 1); DrawSingleScreen( - screen_infos[1], + screen_infos[rightside], static_cast(layout.cardboard.top_screen_right_eye + (layout.width / 2)), top_screen_top, top_screen_width, top_screen_height, orientation); break; @@ -777,8 +777,8 @@ void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, case Settings::StereoRenderOption::Anaglyph: case Settings::StereoRenderOption::Interlaced: case Settings::StereoRenderOption::ReverseInterlaced: { - DrawSingleScreenStereo(screen_infos[0], screen_infos[1], top_screen_left, top_screen_top, - top_screen_width, top_screen_height, orientation); + DrawSingleScreenStereo(screen_infos[leftside], screen_infos[rightside], top_screen_left, + top_screen_top, top_screen_width, top_screen_height, orientation); break; } } @@ -798,31 +798,30 @@ void RendererOpenGL::DrawBottomScreen(const Layout::FramebufferLayout& layout, const auto orientation = layout.is_rotated ? Layout::DisplayOrientation::Landscape : Layout::DisplayOrientation::Portrait; - bool separate_win = false; -#ifndef ANDROID - separate_win = - (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows); -#endif - - switch (Settings::values.render_3d.GetValue()) { + switch (layout.render_3d_mode) { case Settings::StereoRenderOption::Off: { DrawSingleScreen(screen_infos[2], bottom_screen_left, bottom_screen_top, bottom_screen_width, bottom_screen_height, orientation); break; } case Settings::StereoRenderOption::SideBySide: // Bottom screen is identical on both sides - case Settings::StereoRenderOption::ReverseSideBySide: { - if (separate_win) { - DrawSingleScreen(screen_infos[2], bottom_screen_left, bottom_screen_top, - bottom_screen_width, bottom_screen_height, orientation); - } else { - DrawSingleScreen(screen_infos[2], bottom_screen_left / 2, bottom_screen_top, - bottom_screen_width / 2, bottom_screen_height, orientation); - glUniform1i(uniform_layer, 1); - DrawSingleScreen( - screen_infos[2], static_cast((bottom_screen_left / 2) + (layout.width / 2)), - bottom_screen_top, bottom_screen_width / 2, bottom_screen_height, orientation); - } + { + + DrawSingleScreen(screen_infos[2], bottom_screen_left / 2, bottom_screen_top, + bottom_screen_width / 2, bottom_screen_height, orientation); + glUniform1i(uniform_layer, 1); + DrawSingleScreen( + screen_infos[2], static_cast((bottom_screen_left / 2) + (layout.width / 2)), + bottom_screen_top, bottom_screen_width / 2, bottom_screen_height, orientation); + + break; + } + case Settings::StereoRenderOption::SideBySideFull: { + DrawSingleScreen(screen_infos[2], bottom_screen_left, bottom_screen_top, + bottom_screen_width, bottom_screen_height, orientation); + glUniform1i(uniform_layer, 1); + DrawSingleScreen(screen_infos[2], bottom_screen_left + layout.width / 2, bottom_screen_top, + bottom_screen_width, bottom_screen_height, orientation); break; } case Settings::StereoRenderOption::CardboardVR: { diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 7fa1af976..2f2b318ed 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -56,7 +56,7 @@ public: private: void InitOpenGLObjects(); - void ReloadShader(); + void ReloadShader(Settings::StereoRenderOption render_3d); void PrepareRendertarget(); void RenderScreenshot(); void RenderToMailbox(const Layout::FramebufferLayout& layout, @@ -65,8 +65,8 @@ private: const Pica::FramebufferConfig& framebuffer, const Pica::ColorFill& color_fill); void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped); - void ApplySecondLayerOpacity(bool isPortrait = false); - void ResetSecondLayerOpacity(bool isPortrait = false); + void ApplySecondLayerOpacity(float opacity = 1.0f); + void ResetSecondLayerOpacity(); void DrawBottomScreen(const Layout::FramebufferLayout& layout, const Common::Rectangle& bottom_screen); void DrawTopScreen(const Layout::FramebufferLayout& layout, diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index db1b0f439..59a5a1c94 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -60,27 +60,11 @@ constexpr static std::array PRESENT_BINDINGS namespace { static bool IsLowRefreshRate() { -#ifdef ENABLE_SDL2 - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - LOG_ERROR(Render_Vulkan, "SDL video failed to initialize, unable to check refresh rate"); + if (!Settings::values.use_display_refresh_rate_detection) { + LOG_INFO(Render_Vulkan, "Refresh rate detection is currently disabled via settings"); return false; } - - SDL_DisplayMode cur_display_mode; - SDL_GetCurrentDisplayMode(0, &cur_display_mode); // TODO: Multimonitor handling. -OS - const auto cur_refresh_rate = cur_display_mode.refresh_rate; - - SDL_QuitSubSystem(SDL_INIT_VIDEO); - - if (cur_refresh_rate < SCREEN_REFRESH_RATE) { - LOG_WARNING(Render_Vulkan, - "Detected refresh rate lower than the emulated 3DS screen: {}hz. FIFO will " - "be disabled", - cur_refresh_rate); - return true; - } -#endif - +#if defined(__APPLE__) || defined(ENABLE_SDL2) #ifdef __APPLE__ // Apple's low power mode sometimes limits applications to 30fps without changing the refresh // rate, meaning the above code doesn't catch it. @@ -89,8 +73,34 @@ static bool IsLowRefreshRate() { "framerate. FIFO will be disabled"); return true; } -#endif + const auto cur_refresh_rate = AppleUtils::GetRefreshRate(); +#elif defined(ENABLE_SDL2) + if (SDL_WasInit(SDL_INIT_VIDEO) == 0) { + LOG_ERROR(Render_Vulkan, "Attempted to check refresh rate via SDL, but failed because " + "SDL_INIT_VIDEO wasn't initialized"); + return false; + } + + SDL_DisplayMode cur_display_mode; + SDL_GetCurrentDisplayMode(0, &cur_display_mode); // TODO: Multimonitor handling. -OS + + const auto cur_refresh_rate = cur_display_mode.refresh_rate; +#endif // ENABLE_SDL2 + + if (cur_refresh_rate < SCREEN_REFRESH_RATE) { + LOG_WARNING(Render_Vulkan, + "Detected refresh rate lower than the emulated 3DS screen: {}hz. FIFO will " + "be disabled", + cur_refresh_rate); + return true; + } else { + LOG_INFO(Render_Vulkan, "Refresh rate is above emulated 3DS screen: {}hz. Good.", + cur_refresh_rate); + } +#endif // defined(__APPLE__) || defined(ENABLE_SDL2) + + // We have no available method of checking refresh rate. Just assume that everything is fine :) return false; } } // Anonymous namespace @@ -100,27 +110,33 @@ RendererVulkan::RendererVulkan(Core::System& system, Pica::PicaCore& pica_, : RendererBase{system, window, secondary_window}, memory{system.Memory()}, pica{pica_}, instance{window, Settings::values.physical_device.GetValue()}, scheduler{instance}, renderpass_cache{instance, scheduler}, - main_window{window, instance, scheduler, IsLowRefreshRate()}, + main_present_window{window, instance, scheduler, IsLowRefreshRate()}, vertex_buffer{instance, scheduler, vk::BufferUsageFlagBits::eVertexBuffer, VERTEX_BUFFER_SIZE}, - update_queue{instance}, - rasterizer{ - memory, pica, system.CustomTexManager(), *this, render_window, - instance, scheduler, renderpass_cache, update_queue, main_window.ImageCount()}, + update_queue{instance}, rasterizer{memory, + pica, + system.CustomTexManager(), + *this, + render_window, + instance, + scheduler, + renderpass_cache, + update_queue, + main_present_window.ImageCount()}, present_heap{instance, scheduler.GetMasterSemaphore(), PRESENT_BINDINGS, 32} { CompileShaders(); BuildLayouts(); BuildPipelines(); if (secondary_window) { - second_window = std::make_unique(*secondary_window, instance, scheduler, - IsLowRefreshRate()); + secondary_present_window_ptr = std::make_unique( + *secondary_window, instance, scheduler, IsLowRefreshRate()); } } RendererVulkan::~RendererVulkan() { vk::Device device = instance.GetDevice(); scheduler.Finish(); - main_window.WaitPresent(); + main_present_window.WaitPresent(); device.waitIdle(); device.destroyShaderModule(present_vertex_shader); @@ -172,7 +188,8 @@ void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout& } renderpass_cache.EndRendering(); - scheduler.Record([this, layout, frame, present_set, renderpass = main_window.Renderpass(), + scheduler.Record([this, layout, frame, present_set, + renderpass = main_present_window.Renderpass(), index = current_pipeline](vk::CommandBuffer cmdbuf) { const vk::Viewport viewport = { .x = 0.0f, @@ -364,7 +381,13 @@ void RendererVulkan::BuildPipelines() { }; const vk::PipelineColorBlendAttachmentState colorblend_attachment = { - .blendEnable = false, + .blendEnable = true, + .srcColorBlendFactor = vk::BlendFactor::eConstantAlpha, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusConstantAlpha, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eConstantAlpha, + .dstAlphaBlendFactor = vk::BlendFactor::eOneMinusConstantAlpha, + .alphaBlendOp = vk::BlendOp::eAdd, .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, }; @@ -373,7 +396,6 @@ void RendererVulkan::BuildPipelines() { .logicOpEnable = false, .attachmentCount = 1, .pAttachments = &colorblend_attachment, - .blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f}, }; const vk::Viewport placeholder_viewport = vk::Viewport{0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; @@ -386,6 +408,7 @@ void RendererVulkan::BuildPipelines() { }; const std::array dynamic_states = { + vk::DynamicState::eBlendConstants, vk::DynamicState::eViewport, vk::DynamicState::eScissor, }; @@ -429,7 +452,7 @@ void RendererVulkan::BuildPipelines() { .pColorBlendState = &color_blending, .pDynamicState = &dynamic_info, .layout = *present_pipeline_layout, - .renderPass = main_window.Renderpass(), + .renderPass = main_present_window.Renderpass(), }; const auto [result, pipeline] = @@ -556,8 +579,7 @@ void RendererVulkan::FillScreen(Common::Vec3 color, const TextureInfo& textu }); } -void RendererVulkan::ReloadPipeline() { - const Settings::StereoRenderOption render_3d = Settings::values.render_3d.GetValue(); +void RendererVulkan::ReloadPipeline(Settings::StereoRenderOption render_3d) { switch (render_3d) { case Settings::StereoRenderOption::Anaglyph: current_pipeline = 1; @@ -717,12 +739,21 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, fl }); } +void RendererVulkan::ApplySecondLayerOpacity(float alpha) { + scheduler.Record([alpha](vk::CommandBuffer cmdbuf) { + const std::array blend_constants = {0.0f, 0.0f, 0.0f, alpha}; + cmdbuf.setBlendConstants(blend_constants.data()); + }); +} + void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout, const Common::Rectangle& top_screen) { if (!layout.top_screen_enabled) { return; } - + int leftside, rightside; + leftside = Settings::values.swap_eyes_3d.GetValue() ? 1 : 0; + rightside = Settings::values.swap_eyes_3d.GetValue() ? 0 : 1; const float top_screen_left = static_cast(top_screen.left); const float top_screen_top = static_cast(top_screen.top); const float top_screen_width = static_cast(top_screen.GetWidth()); @@ -730,7 +761,7 @@ void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout, const auto orientation = layout.is_rotated ? Layout::DisplayOrientation::Landscape : Layout::DisplayOrientation::Portrait; - switch (Settings::values.render_3d.GetValue()) { + switch (layout.render_3d_mode) { case Settings::StereoRenderOption::Off: { const int eye = static_cast(Settings::values.mono_render_option.GetValue()); DrawSingleScreen(eye, top_screen_left, top_screen_top, top_screen_width, top_screen_height, @@ -738,35 +769,36 @@ void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout, break; } case Settings::StereoRenderOption::SideBySide: { - DrawSingleScreen(0, top_screen_left / 2, top_screen_top, top_screen_width / 2, + DrawSingleScreen(leftside, top_screen_left / 2, top_screen_top, top_screen_width / 2, top_screen_height, orientation); draw_info.layer = 1; - DrawSingleScreen(1, static_cast((top_screen_left / 2) + (layout.width / 2)), + DrawSingleScreen(rightside, static_cast((top_screen_left / 2) + (layout.width / 2)), top_screen_top, top_screen_width / 2, top_screen_height, orientation); break; } - case Settings::StereoRenderOption::ReverseSideBySide: { - DrawSingleScreen(1, top_screen_left / 2, top_screen_top, top_screen_width / 2, + case Settings::StereoRenderOption::SideBySideFull: { + DrawSingleScreen(leftside, top_screen_left, top_screen_top, top_screen_width, top_screen_height, orientation); draw_info.layer = 1; - DrawSingleScreen(0, static_cast((top_screen_left / 2) + (layout.width / 2)), - top_screen_top, top_screen_width / 2, top_screen_height, orientation); + DrawSingleScreen(rightside, top_screen_left + layout.width / 2, top_screen_top, + top_screen_width, top_screen_height, orientation); break; } case Settings::StereoRenderOption::CardboardVR: { - DrawSingleScreen(0, top_screen_left, top_screen_top, top_screen_width, top_screen_height, - orientation); + DrawSingleScreen(leftside, top_screen_left, top_screen_top, top_screen_width, + top_screen_height, orientation); draw_info.layer = 1; DrawSingleScreen( - 1, static_cast(layout.cardboard.top_screen_right_eye + (layout.width / 2)), + rightside, + static_cast(layout.cardboard.top_screen_right_eye + (layout.width / 2)), top_screen_top, top_screen_width, top_screen_height, orientation); break; } case Settings::StereoRenderOption::Anaglyph: case Settings::StereoRenderOption::Interlaced: case Settings::StereoRenderOption::ReverseInterlaced: { - DrawSingleScreenStereo(0, 1, top_screen_left, top_screen_top, top_screen_width, - top_screen_height, orientation); + DrawSingleScreenStereo(leftside, rightside, top_screen_left, top_screen_top, + top_screen_width, top_screen_height, orientation); break; } } @@ -786,31 +818,29 @@ void RendererVulkan::DrawBottomScreen(const Layout::FramebufferLayout& layout, const auto orientation = layout.is_rotated ? Layout::DisplayOrientation::Landscape : Layout::DisplayOrientation::Portrait; - bool separate_win = false; -#ifndef ANDROID - separate_win = - (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows); -#endif - - switch (Settings::values.render_3d.GetValue()) { + switch (layout.render_3d_mode) { case Settings::StereoRenderOption::Off: { DrawSingleScreen(2, bottom_screen_left, bottom_screen_top, bottom_screen_width, bottom_screen_height, orientation); + break; } case Settings::StereoRenderOption::SideBySide: // Bottom screen is identical on both sides - case Settings::StereoRenderOption::ReverseSideBySide: { - if (separate_win) { - DrawSingleScreen(2, bottom_screen_left, bottom_screen_top, bottom_screen_width, - bottom_screen_height, orientation); - } else { - DrawSingleScreen(2, bottom_screen_left / 2, bottom_screen_top, bottom_screen_width / 2, - bottom_screen_height, orientation); - draw_info.layer = 1; - DrawSingleScreen(2, static_cast((bottom_screen_left / 2) + (layout.width / 2)), - bottom_screen_top, bottom_screen_width / 2, bottom_screen_height, - orientation); - } + { + DrawSingleScreen(2, bottom_screen_left / 2, bottom_screen_top, bottom_screen_width / 2, + bottom_screen_height, orientation); + draw_info.layer = 1; + DrawSingleScreen(2, static_cast((bottom_screen_left / 2) + (layout.width / 2)), + bottom_screen_top, bottom_screen_width / 2, bottom_screen_height, + orientation); + break; + } + case Settings::StereoRenderOption::SideBySideFull: { + DrawSingleScreen(2, bottom_screen_left, bottom_screen_top, bottom_screen_width, + bottom_screen_height, orientation); + draw_info.layer = 1; + DrawSingleScreen(2, bottom_screen_left + layout.width / 2, bottom_screen_top, + bottom_screen_width, bottom_screen_height, orientation); break; } case Settings::StereoRenderOption::CardboardVR: { @@ -825,13 +855,8 @@ void RendererVulkan::DrawBottomScreen(const Layout::FramebufferLayout& layout, case Settings::StereoRenderOption::Anaglyph: case Settings::StereoRenderOption::Interlaced: case Settings::StereoRenderOption::ReverseInterlaced: { - if (separate_win) { - DrawSingleScreen(2, bottom_screen_left, bottom_screen_top, bottom_screen_width, - bottom_screen_height, orientation); - } else { - DrawSingleScreenStereo(2, 2, bottom_screen_left, bottom_screen_top, bottom_screen_width, - bottom_screen_height, orientation); - } + DrawSingleScreenStereo(2, 2, bottom_screen_left, bottom_screen_top, bottom_screen_width, + bottom_screen_height, orientation); break; } } @@ -845,7 +870,7 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout& clear_color.float32[2] = Settings::values.bg_blue.GetValue(); } if (settings.shader_update_requested.exchange(false)) { - ReloadPipeline(); + ReloadPipeline(layout.render_3d_mode); } PrepareDraw(frame, layout); @@ -855,13 +880,23 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout& draw_info.modelview = MakeOrthographicMatrix(layout.width, layout.height); draw_info.layer = 0; + + // Apply the initial default opacity value; Needed to avoid flickering + ApplySecondLayerOpacity(1.0f); + if (!Settings::values.swap_screen.GetValue()) { DrawTopScreen(layout, top_screen); draw_info.layer = 0; + if (layout.bottom_opacity < 1) { + ApplySecondLayerOpacity(layout.bottom_opacity); + } DrawBottomScreen(layout, bottom_screen); } else { DrawBottomScreen(layout, bottom_screen); draw_info.layer = 0; + if (layout.top_opacity < 1) { + ApplySecondLayerOpacity(layout.top_opacity); + } DrawTopScreen(layout, top_screen); } @@ -882,19 +917,32 @@ void RendererVulkan::SwapBuffers() { const Layout::FramebufferLayout& layout = render_window.GetFramebufferLayout(); PrepareRendertarget(); RenderScreenshot(); - RenderToWindow(main_window, layout, false); + RenderToWindow(main_present_window, layout, false); #ifndef ANDROID if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) { ASSERT(secondary_window); const auto& secondary_layout = secondary_window->GetFramebufferLayout(); - if (!second_window) { - second_window = std::make_unique(*secondary_window, instance, scheduler, - IsLowRefreshRate()); + if (!secondary_present_window_ptr) { + secondary_present_window_ptr = std::make_unique( + *secondary_window, instance, scheduler, IsLowRefreshRate()); } - RenderToWindow(*second_window, secondary_layout, false); + RenderToWindow(*secondary_present_window_ptr, secondary_layout, false); secondary_window->PollEvents(); } #endif + +#ifdef ANDROID + if (secondary_window) { + const auto& secondary_layout = secondary_window->GetFramebufferLayout(); + if (!secondary_present_window_ptr) { + secondary_present_window_ptr = std::make_unique( + *secondary_window, instance, scheduler, IsLowRefreshRate()); + } + RenderToWindow(*secondary_present_window_ptr, secondary_layout, false); + secondary_window->PollEvents(); + } +#endif + system.perf_stats->EndSwap(); rasterizer.TickFrame(); EndFrame(); @@ -949,7 +997,7 @@ void RendererVulkan::RenderScreenshotWithStagingCopy() { vk::Buffer staging_buffer{unsafe_buffer}; Frame frame{}; - main_window.RecreateFrame(&frame, width, height); + main_present_window.RecreateFrame(&frame, width, height); DrawScreens(&frame, layout, false); @@ -1122,7 +1170,7 @@ bool RendererVulkan::TryRenderScreenshotWithHostMemory() { device.bindBufferMemory(imported_buffer.get(), imported_memory.get(), 0); Frame frame{}; - main_window.RecreateFrame(&frame, width, height); + main_present_window.RecreateFrame(&frame, width, height); DrawScreens(&frame, layout, false); @@ -1185,4 +1233,14 @@ bool RendererVulkan::TryRenderScreenshotWithHostMemory() { return true; } +void RendererVulkan::NotifySurfaceChanged(bool is_second_window) { + if (is_second_window) { + if (secondary_present_window_ptr) { + secondary_present_window_ptr->NotifySurfaceChanged(); + } + } else { + main_present_window.NotifySurfaceChanged(); + } +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index a5ad3a72f..29ed8a66e 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -74,15 +74,13 @@ public: return &rasterizer; } - void NotifySurfaceChanged() override { - main_window.NotifySurfaceChanged(); - } + void NotifySurfaceChanged(bool second) override; void SwapBuffers() override; void TryPresent(int timeout_ms, bool is_secondary) override {} private: - void ReloadPipeline(); + void ReloadPipeline(Settings::StereoRenderOption render_3d); void CompileShaders(); void BuildLayouts(); void BuildPipelines(); @@ -100,12 +98,16 @@ private: void DrawScreens(Frame* frame, const Layout::FramebufferLayout& layout, bool flipped); void DrawBottomScreen(const Layout::FramebufferLayout& layout, const Common::Rectangle& bottom_screen); + void DrawTopScreen(const Layout::FramebufferLayout& layout, const Common::Rectangle& top_screen); void DrawSingleScreen(u32 screen_id, float x, float y, float w, float h, Layout::DisplayOrientation orientation); void DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y, float w, float h, Layout::DisplayOrientation orientation); + + void ApplySecondLayerOpacity(float alpha); + void LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer, ScreenInfo& screen_info, bool right_eye); void FillScreen(Common::Vec3 color, const TextureInfo& texture); @@ -117,11 +119,11 @@ private: Instance instance; Scheduler scheduler; RenderManager renderpass_cache; - PresentWindow main_window; + PresentWindow main_present_window; StreamBuffer vertex_buffer; DescriptorUpdateQueue update_queue; RasterizerVulkan rasterizer; - std::unique_ptr second_window; + std::unique_ptr secondary_present_window_ptr; DescriptorHeap present_heap; vk::UniquePipelineLayout present_pipeline_layout; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index adcad826e..7c078802d 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -4,6 +4,7 @@ #include +#include "common/alignment.h" #include "common/hash.h" #include "common/microprofile.h" #include "video_core/renderer_vulkan/pica_to_vk.h" @@ -31,25 +32,32 @@ vk::ShaderStageFlagBits MakeShaderStage(std::size_t index) { return vk::ShaderStageFlagBits::eVertex; } -u64 PipelineInfo::Hash(const Instance& instance) const { - u64 info_hash = 0; - const auto append_hash = [&info_hash](const auto& data) { - const u64 data_hash = Common::ComputeStructHash64(data); - info_hash = Common::HashCombine(info_hash, data_hash); - }; - - append_hash(vertex_layout); - append_hash(attachments); - append_hash(blending); +u64 StaticPipelineInfo::OptimizedHash(const Instance& instance) const { + u64 info_hash = Common::HashCombine( + shader_ids[0], shader_ids[1], shader_ids[2], Common::ComputeStructHash64(vertex_layout), + Common::ComputeStructHash64(attachments), Common::ComputeStructHash64(blending)); if (!instance.IsExtendedDynamicStateSupported()) { - append_hash(rasterization); - append_hash(depth_stencil); + info_hash = Common::HashCombine(info_hash, Common::ComputeStructHash64(rasterization), + Common::ComputeStructHash64(depth_stencil)); } return info_hash; } +u16 PipelineInfo::GetFinalColorWriteMask(const Instance& instance) { + u16 color_write_mask = state.blending.color_write_mask; + const bool is_logic_op_emulated = + instance.NeedsLogicOpEmulation() && !state.blending.blend_enable; + const bool is_logic_op_noop = state.blending.logic_op == Pica::FramebufferRegs::LogicOp::NoOp; + if (is_logic_op_emulated && is_logic_op_noop) { + // Color output is disabled by logic operation. We use color write mask to skip + // color but allow depth write. + color_write_mask = 0; + } + return color_write_mask; +} + Shader::Shader(const Instance& instance) : device{instance.GetDevice()} {} Shader::Shader(const Instance& instance, vk::ShaderStageFlagBits stage, std::string code) @@ -100,20 +108,22 @@ bool GraphicsPipeline::TryBuild(bool wait_built) { bool GraphicsPipeline::Build(bool fail_on_compile_required) { MICROPROFILE_SCOPE(Vulkan_Pipeline); + + const u32 stride_alignment = instance.GetMinVertexStrideAlignment(); std::array bindings; - for (u32 i = 0; i < info.vertex_layout.binding_count; i++) { - const auto& binding = info.vertex_layout.bindings[i]; + for (u32 i = 0; i < info.state.vertex_layout.binding_count; i++) { + const auto& binding = info.state.vertex_layout.bindings[i]; bindings[i] = vk::VertexInputBindingDescription{ .binding = binding.binding, - .stride = binding.stride, + .stride = Common::AlignUp(binding.byte_count.Value(), stride_alignment), .inputRate = binding.fixed.Value() ? vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex, }; } std::array attributes; - for (u32 i = 0; i < info.vertex_layout.attribute_count; i++) { - const auto& attr = info.vertex_layout.attributes[i]; + for (u32 i = 0; i < info.state.vertex_layout.attribute_count; i++) { + const auto& attr = info.state.vertex_layout.attributes[i]; const FormatTraits& traits = instance.GetTraits(attr.type, attr.size); attributes[i] = vk::VertexInputAttributeDescription{ .location = attr.location, @@ -131,23 +141,23 @@ bool GraphicsPipeline::Build(bool fail_on_compile_required) { } const vk::PipelineVertexInputStateCreateInfo vertex_input_info = { - .vertexBindingDescriptionCount = info.vertex_layout.binding_count, + .vertexBindingDescriptionCount = info.state.vertex_layout.binding_count, .pVertexBindingDescriptions = bindings.data(), - .vertexAttributeDescriptionCount = info.vertex_layout.attribute_count, + .vertexAttributeDescriptionCount = info.state.vertex_layout.attribute_count, .pVertexAttributeDescriptions = attributes.data(), }; const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { - .topology = PicaToVK::PrimitiveTopology(info.rasterization.topology), + .topology = PicaToVK::PrimitiveTopology(info.state.rasterization.topology), .primitiveRestartEnable = false, }; const vk::PipelineRasterizationStateCreateInfo raster_state = { .depthClampEnable = false, .rasterizerDiscardEnable = false, - .cullMode = - PicaToVK::CullMode(info.rasterization.cull_mode, info.rasterization.flip_viewport), - .frontFace = PicaToVK::FrontFace(info.rasterization.cull_mode), + .cullMode = PicaToVK::CullMode(info.state.rasterization.cull_mode, + info.state.rasterization.flip_viewport), + .frontFace = PicaToVK::FrontFace(info.state.rasterization.cull_mode), .depthBiasEnable = false, .lineWidth = 1.0f, }; @@ -158,19 +168,20 @@ bool GraphicsPipeline::Build(bool fail_on_compile_required) { }; const vk::PipelineColorBlendAttachmentState colorblend_attachment = { - .blendEnable = info.blending.blend_enable, - .srcColorBlendFactor = PicaToVK::BlendFunc(info.blending.src_color_blend_factor), - .dstColorBlendFactor = PicaToVK::BlendFunc(info.blending.dst_color_blend_factor), - .colorBlendOp = PicaToVK::BlendEquation(info.blending.color_blend_eq), - .srcAlphaBlendFactor = PicaToVK::BlendFunc(info.blending.src_alpha_blend_factor), - .dstAlphaBlendFactor = PicaToVK::BlendFunc(info.blending.dst_alpha_blend_factor), - .alphaBlendOp = PicaToVK::BlendEquation(info.blending.alpha_blend_eq), - .colorWriteMask = static_cast(info.blending.color_write_mask), + .blendEnable = info.state.blending.blend_enable, + .srcColorBlendFactor = PicaToVK::BlendFunc(info.state.blending.src_color_blend_factor), + .dstColorBlendFactor = PicaToVK::BlendFunc(info.state.blending.dst_color_blend_factor), + .colorBlendOp = PicaToVK::BlendEquation(info.state.blending.color_blend_eq), + .srcAlphaBlendFactor = PicaToVK::BlendFunc(info.state.blending.src_alpha_blend_factor), + .dstAlphaBlendFactor = PicaToVK::BlendFunc(info.state.blending.dst_alpha_blend_factor), + .alphaBlendOp = PicaToVK::BlendEquation(info.state.blending.alpha_blend_eq), + .colorWriteMask = + static_cast(info.GetFinalColorWriteMask(instance)), }; const vk::PipelineColorBlendStateCreateInfo color_blending = { - .logicOpEnable = !info.blending.blend_enable && !instance.NeedsLogicOpEmulation(), - .logicOp = PicaToVK::LogicOp(info.blending.logic_op), + .logicOpEnable = !info.state.blending.blend_enable && !instance.NeedsLogicOpEmulation(), + .logicOp = PicaToVK::LogicOp(info.state.blending.logic_op), .attachmentCount = 1, .pAttachments = &colorblend_attachment, .blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f}, @@ -219,18 +230,18 @@ bool GraphicsPipeline::Build(bool fail_on_compile_required) { }; const vk::StencilOpState stencil_op_state = { - .failOp = PicaToVK::StencilOp(info.depth_stencil.stencil_fail_op), - .passOp = PicaToVK::StencilOp(info.depth_stencil.stencil_pass_op), - .depthFailOp = PicaToVK::StencilOp(info.depth_stencil.stencil_depth_fail_op), - .compareOp = PicaToVK::CompareFunc(info.depth_stencil.stencil_compare_op), + .failOp = PicaToVK::StencilOp(info.state.depth_stencil.stencil_fail_op), + .passOp = PicaToVK::StencilOp(info.state.depth_stencil.stencil_pass_op), + .depthFailOp = PicaToVK::StencilOp(info.state.depth_stencil.stencil_depth_fail_op), + .compareOp = PicaToVK::CompareFunc(info.state.depth_stencil.stencil_compare_op), }; const vk::PipelineDepthStencilStateCreateInfo depth_info = { - .depthTestEnable = static_cast(info.depth_stencil.depth_test_enable.Value()), - .depthWriteEnable = static_cast(info.depth_stencil.depth_write_enable.Value()), - .depthCompareOp = PicaToVK::CompareFunc(info.depth_stencil.depth_compare_op), + .depthTestEnable = static_cast(info.state.depth_stencil.depth_test_enable.Value()), + .depthWriteEnable = static_cast(info.state.depth_stencil.depth_write_enable.Value()), + .depthCompareOp = PicaToVK::CompareFunc(info.state.depth_stencil.depth_compare_op), .depthBoundsTestEnable = false, - .stencilTestEnable = static_cast(info.depth_stencil.stencil_test_enable.Value()), + .stencilTestEnable = static_cast(info.state.depth_stencil.stencil_test_enable.Value()), .front = stencil_op_state, .back = stencil_op_state, }; @@ -263,8 +274,8 @@ bool GraphicsPipeline::Build(bool fail_on_compile_required) { .pColorBlendState = &color_blending, .pDynamicState = &dynamic_info, .layout = pipeline_layout, - .renderPass = - renderpass_cache.GetRenderpass(info.attachments.color, info.attachments.depth, false), + .renderPass = renderpass_cache.GetRenderpass(info.state.attachments.color, + info.state.attachments.depth, false), }; if (fail_on_compile_required) { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index ab85771d7..5f817094e 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -2,12 +2,18 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#pragma once + +#include "common/hash.h" #include "common/thread_worker.h" #include "video_core/pica/regs_pipeline.h" #include "video_core/pica/regs_rasterizer.h" #include "video_core/rasterizer_cache/pixel_format.h" #include "video_core/renderer_vulkan/vk_common.h" +#define LAYOUT_HASH static_cast(sizeof(T)), static_cast(alignof(T)) +#define FIELD_HASH(x) static_cast(offsetof(T, x)), static_cast(sizeof(x)) + namespace Common { struct AsyncHandle { @@ -51,14 +57,29 @@ constexpr u32 MAX_VERTEX_BINDINGS = 13; * the overhead of hashing as much as possible */ union RasterizationState { - u8 value = 0; + u8 value; BitField<0, 2, Pica::PipelineRegs::TriangleTopology> topology; BitField<4, 2, Pica::RasterizerRegs::CullMode> cull_mode; BitField<6, 1, u8> flip_viewport; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = RasterizationState; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(topology), FIELD_HASH(cull_mode), + FIELD_HASH(flip_viewport)); + } }; +static_assert(std::is_trivial_v); union DepthStencilState { - u32 value = 0; + u32 value; BitField<0, 1, u32> depth_test_enable; BitField<1, 1, u32> depth_write_enable; BitField<2, 1, u32> stencil_test_enable; @@ -67,14 +88,32 @@ union DepthStencilState { BitField<9, 3, Pica::FramebufferRegs::StencilAction> stencil_pass_op; BitField<12, 3, Pica::FramebufferRegs::StencilAction> stencil_depth_fail_op; BitField<15, 3, Pica::FramebufferRegs::CompareFunc> stencil_compare_op; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = DepthStencilState; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(depth_test_enable), FIELD_HASH(depth_write_enable), + FIELD_HASH(stencil_test_enable), FIELD_HASH(depth_compare_op), + FIELD_HASH(stencil_fail_op), FIELD_HASH(stencil_pass_op), + FIELD_HASH(stencil_depth_fail_op), + FIELD_HASH(stencil_compare_op)); + } }; +static_assert(std::is_trivial_v); struct BlendingState { u16 blend_enable; u16 color_write_mask; Pica::FramebufferRegs::LogicOp logic_op; union { - u32 value = 0; + u32 value; BitField<0, 4, Pica::FramebufferRegs::BlendFactor> src_color_blend_factor; BitField<4, 4, Pica::FramebufferRegs::BlendFactor> dst_color_blend_factor; BitField<8, 3, Pica::FramebufferRegs::BlendEquation> color_blend_eq; @@ -82,9 +121,149 @@ struct BlendingState { BitField<15, 4, Pica::FramebufferRegs::BlendFactor> dst_alpha_blend_factor; BitField<19, 3, Pica::FramebufferRegs::BlendEquation> alpha_blend_eq; }; -}; -struct DynamicState { + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = BlendingState; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(blend_enable), FIELD_HASH(color_write_mask), + FIELD_HASH(logic_op), FIELD_HASH(src_color_blend_factor), + FIELD_HASH(dst_color_blend_factor), FIELD_HASH(color_blend_eq), + FIELD_HASH(src_alpha_blend_factor), + FIELD_HASH(dst_alpha_blend_factor), FIELD_HASH(alpha_blend_eq)); + } +}; +static_assert(std::is_trivial_v); + +union VertexBinding { + u16 value; + BitField<0, 4, u16> binding; + BitField<4, 1, u16> fixed; + BitField<5, 11, u16> byte_count; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = VertexBinding; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(binding), FIELD_HASH(fixed), FIELD_HASH(byte_count)); + } +}; +static_assert(std::is_trivial_v); + +union VertexAttribute { + u32 value; + BitField<0, 4, u32> binding; + BitField<4, 4, u32> location; + BitField<8, 3, Pica::PipelineRegs::VertexAttributeFormat> type; + BitField<11, 3, u32> size; + BitField<14, 11, u32> offset; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = VertexAttribute; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(binding), FIELD_HASH(location), FIELD_HASH(type), + FIELD_HASH(size), FIELD_HASH(offset)); + } +}; +static_assert(std::is_trivial_v); + +struct VertexLayout { + u8 binding_count; + u8 attribute_count; + std::array bindings; + std::array attributes; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = VertexLayout; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(binding_count), FIELD_HASH(attribute_count), + FIELD_HASH(bindings), FIELD_HASH(attributes), + + // nested layout + VertexBinding::StructHash(), VertexAttribute::StructHash()); + } +}; +static_assert(std::is_trivial_v); + +struct AttachmentInfo { + VideoCore::PixelFormat color; + VideoCore::PixelFormat depth; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = AttachmentInfo; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(color), FIELD_HASH(depth)); + } +}; +static_assert(std::is_trivial_v); + +struct StaticPipelineInfo { + std::array shader_ids; + + BlendingState blending; + AttachmentInfo attachments; + VertexLayout vertex_layout; + + RasterizationState rasterization; + DepthStencilState depth_stencil; + + [[nodiscard]] u64 OptimizedHash(const Instance& instance) const; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = StaticPipelineInfo; + return Common::HashCombine( + STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(shader_ids), FIELD_HASH(blending), FIELD_HASH(attachments), + FIELD_HASH(vertex_layout), FIELD_HASH(rasterization), FIELD_HASH(depth_stencil), + + // nested layout + BlendingState::StructHash(), AttachmentInfo::StructHash(), VertexLayout::StructHash(), + RasterizationState::StructHash(), DepthStencilState::StructHash()); + } +}; +static_assert(std::is_trivial_v); + +struct DynamicPipelineInfo { u32 blend_color = 0; u8 stencil_reference; u8 stencil_compare_mask; @@ -93,61 +272,28 @@ struct DynamicState { Common::Rectangle scissor; Common::Rectangle viewport; - bool operator==(const DynamicState& other) const noexcept { - return std::memcmp(this, &other, sizeof(DynamicState)) == 0; + bool operator==(const DynamicPipelineInfo& other) const noexcept { + return std::memcmp(this, &other, sizeof(DynamicPipelineInfo)) == 0; } }; -union VertexBinding { - u16 value = 0; - BitField<0, 4, u16> binding; - BitField<4, 1, u16> fixed; - BitField<5, 11, u16> stride; -}; - -union VertexAttribute { - u32 value = 0; - BitField<0, 4, u32> binding; - BitField<4, 4, u32> location; - BitField<8, 3, Pica::PipelineRegs::VertexAttributeFormat> type; - BitField<11, 3, u32> size; - BitField<14, 11, u32> offset; -}; - -struct VertexLayout { - u8 binding_count; - u8 attribute_count; - std::array bindings; - std::array attributes; -}; - -struct AttachmentInfo { - VideoCore::PixelFormat color; - VideoCore::PixelFormat depth; -}; - /** * Information about a graphics pipeline */ -struct PipelineInfo { - BlendingState blending; - AttachmentInfo attachments; - RasterizationState rasterization; - DepthStencilState depth_stencil; - DynamicState dynamic; - VertexLayout vertex_layout; - - [[nodiscard]] u64 Hash(const Instance& instance) const; +struct PipelineInfo : Common::HashableStruct { + DynamicPipelineInfo dynamic_info; [[nodiscard]] bool IsDepthWriteEnabled() const noexcept { - const bool has_stencil = attachments.depth == VideoCore::PixelFormat::D24S8; + const bool has_stencil = state.attachments.depth == VideoCore::PixelFormat::D24S8; const bool depth_write = - depth_stencil.depth_test_enable && depth_stencil.depth_write_enable; - const bool stencil_write = - has_stencil && depth_stencil.stencil_test_enable && dynamic.stencil_write_mask != 0; + state.depth_stencil.depth_test_enable && state.depth_stencil.depth_write_enable; + const bool stencil_write = has_stencil && state.depth_stencil.stencil_test_enable && + dynamic_info.stencil_write_mask != 0; return depth_write || stencil_write; } + + [[nodiscard]] u16 GetFinalColorWriteMask(const Instance& instance); }; struct Shader : public Common::AsyncHandle { @@ -195,3 +341,6 @@ private: }; } // namespace Vulkan + +#undef LAYOUT_HASH +#undef FIELD_HASH diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index d087d49b1..09984b53f 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -1,4 +1,4 @@ -// Copyright 2022 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -30,8 +30,10 @@ struct FormatTraits { bool needs_conversion = false; bool needs_emulation = false; vk::ImageUsageFlags usage{}; - vk::ImageAspectFlags aspect; + vk::ImageAspectFlags aspect{}; vk::Format native = vk::Format::eUndefined; + + auto operator<=>(const FormatTraits&) const = default; }; class Instance { @@ -48,6 +50,10 @@ public: const FormatTraits& GetTraits(Pica::PipelineRegs::VertexAttributeFormat format, u32 count) const; + const std::array& GetAllTraits() const { + return attrib_table; + } + /// Returns a formatted string for the driver version std::string GetDriverVersionName(); @@ -229,7 +235,7 @@ public: } /// Returns the maximum supported elements in a texel buffer - u32 MaxTexelBufferElements() const { + u64 MaxTexelBufferElements() const { return properties.limits.maxTexelBufferElements; } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 1ff478984..97b7cc8b0 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -95,6 +95,7 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, GLSL::GenerateTrivialVertexShader(instance.IsShaderClipDistanceSupported(), true)} { scheduler.RegisterOnDispatch([this] { update_queue.Flush(); }); profile = Pica::Shader::Profile{ + .enable_accurate_mul = false, .has_separable_shaders = true, .has_clip_planes = instance.IsShaderClipDistanceSupported(), .has_geometry_shader = instance.UseGeometryShaders(), @@ -104,8 +105,26 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, .has_blend_minmax_factor = false, .has_minus_one_to_one_range = false, .has_logic_op = !instance.NeedsLogicOpEmulation(), + .vk_disable_spirv_optimizer = Settings::values.disable_spirv_optimizer.GetValue(), + .vk_use_spirv_generator = Settings::values.spirv_shader_gen.GetValue(), .is_vulkan = true, }; + + const auto& traits = instance.GetAllTraits(); + size_t i = 0; + for (const auto& it : traits) { + profile.vk_format_traits[i].transfer_support = it.transfer_support; + profile.vk_format_traits[i].blit_support = it.blit_support; + profile.vk_format_traits[i].attachment_support = it.attachment_support; + profile.vk_format_traits[i].storage_support = it.storage_support; + profile.vk_format_traits[i].needs_conversion = it.needs_conversion; + profile.vk_format_traits[i].needs_emulation = it.needs_emulation; + profile.vk_format_traits[i].usage_flags = static_cast(it.usage); + profile.vk_format_traits[i].aspect_flags = static_cast(it.aspect); + profile.vk_format_traits[i].native_format = static_cast(it.native); + ++i; + } + BuildLayout(); } @@ -125,24 +144,59 @@ void PipelineCache::BuildLayout() { } PipelineCache::~PipelineCache() { - SaveDiskCache(); + workers.WaitForRequests(); + SaveDriverPipelineDiskCache(); } -void PipelineCache::LoadDiskCache(const std::atomic_bool& stop_loading, - const VideoCore::DiskResourceLoadCallback& callback) { +void PipelineCache::LoadCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + LoadDriverPipelineDiskCache(stop_loading, callback); + LoadDiskCache(stop_loading, callback); +} + +void PipelineCache::SwitchCache(u64 title_id, const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + if (GetProgramID() == title_id) { + LOG_DEBUG(Render_Vulkan, + "Skipping pipeline cache switch - already using cache for title_id={:016X}", + title_id); + return; + } + + // Make sure we have a valid pipeline cache before switching + if (!driver_pipeline_cache) { + vk::PipelineCacheCreateInfo cache_info{}; + try { + driver_pipeline_cache = instance.GetDevice().createPipelineCacheUnique(cache_info); + } catch (const vk::SystemError& err) { + LOG_ERROR(Render_Vulkan, "Failed to create pipeline cache: {}", err.what()); + return; + } + } + + LOG_INFO(Render_Vulkan, "Switching pipeline cache to title_id={:016X}", title_id); + + // Save current driver cache, update program ID and load the new driver cache + SaveDriverPipelineDiskCache(); + SetProgramID(title_id); + LoadDriverPipelineDiskCache(stop_loading, nullptr); + + // Switch the disk shader cache after driver cache is switched + SwitchDiskCache(title_id, stop_loading, callback); +} + +void PipelineCache::LoadDriverPipelineDiskCache( + const std::atomic_bool& stop_loading, const VideoCore::DiskResourceLoadCallback& callback) { vk::PipelineCacheCreateInfo cache_info{}; if (callback) { - callback(VideoCore::LoadCallbackStage::Prepare, 0, 0); - } - if (callback) { - callback(VideoCore::LoadCallbackStage::Build, 0, 1); + callback(VideoCore::LoadCallbackStage::Build, 0, 1, "Driver Pipeline Cache"); } auto load_cache = [this, &cache_info, &callback](bool allow_fallback) { const vk::Device device = instance.GetDevice(); try { - pipeline_cache = device.createPipelineCacheUnique(cache_info); + driver_pipeline_cache = device.createPipelineCacheUnique(cache_info); } catch (const vk::SystemError& err) { LOG_ERROR(Render_Vulkan, "Failed to create pipeline cache: {}", err.what()); if (allow_fallback) { @@ -150,7 +204,7 @@ void PipelineCache::LoadDiskCache(const std::atomic_bool& stop_loading, cache_info.initialDataSize = 0; cache_info.pInitialData = nullptr; try { - pipeline_cache = device.createPipelineCacheUnique(cache_info); + driver_pipeline_cache = device.createPipelineCacheUnique(cache_info); } catch (const vk::SystemError& err) { LOG_ERROR(Render_Vulkan, "Failed to create fallback pipeline cache: {}", err.what()); @@ -158,7 +212,7 @@ void PipelineCache::LoadDiskCache(const std::atomic_bool& stop_loading, } } if (callback) { - callback(VideoCore::LoadCallbackStage::Complete, 0, 0); + callback(VideoCore::LoadCallbackStage::Build, 1, 1, "Driver Pipeline Cache"); } }; @@ -210,9 +264,9 @@ void PipelineCache::LoadDiskCache(const std::atomic_bool& stop_loading, load_cache(true); } -void PipelineCache::SaveDiskCache() { +void PipelineCache::SaveDriverPipelineDiskCache() { // Save Vulkan pipeline cache - if (!Settings::values.use_disk_shader_cache || !pipeline_cache) { + if (!Settings::values.use_disk_shader_cache || !driver_pipeline_cache) { return; } @@ -232,32 +286,89 @@ void PipelineCache::SaveDiskCache() { } const vk::Device device = instance.GetDevice(); - const auto cache_data = device.getPipelineCacheData(*pipeline_cache); + const auto cache_data = device.getPipelineCacheData(*driver_pipeline_cache); if (cache_file.WriteBytes(cache_data.data(), cache_data.size()) != cache_data.size()) { LOG_ERROR(Render_Vulkan, "Error during pipeline cache write"); return; } } -bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) { +void PipelineCache::LoadDiskCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + + disk_caches.clear(); + curr_disk_cache = + disk_caches.emplace_back(std::make_shared(*this, GetProgramID())); + + curr_disk_cache->Init(stop_loading, callback); +} + +void PipelineCache::SwitchDiskCache(u64 title_id, const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + // NOTE: curr_disk_cache can be null if emulation restarted without calling + // LoadDefaultDiskResources + + // Check if the current cache is for the specified TID. + if (curr_disk_cache && curr_disk_cache->GetProgramID() == title_id) { + return; + } + + // Search for an existing manager + size_t new_pos = 0; + for (new_pos = 0; new_pos < disk_caches.size(); new_pos++) { + if (disk_caches[new_pos]->GetProgramID() == title_id) { + break; + } + } + // Manager does not exist, create it and append to the end + if (new_pos >= disk_caches.size()) { + new_pos = disk_caches.size(); + auto& new_manager = + disk_caches.emplace_back(std::make_shared(*this, title_id)); + + new_manager->Init(stop_loading, callback); + } + + auto is_applet = [](u64 tid) { + constexpr u32 APPLET_TID_HIGH = 0x00040030; + return static_cast(tid >> 32) == APPLET_TID_HIGH; + }; + + bool prev_applet = curr_disk_cache ? is_applet(curr_disk_cache->GetProgramID()) : false; + bool new_applet = is_applet(disk_caches[new_pos]->GetProgramID()); + curr_disk_cache = disk_caches[new_pos]; + + if (prev_applet) { + // If we came from an applet, clean up all other applets + for (auto it = disk_caches.begin(); it != disk_caches.end();) { + if (it == disk_caches.begin() || *it == curr_disk_cache || + !is_applet((*it)->GetProgramID())) { + it++; + continue; + } + it = disk_caches.erase(it); + } + } + if (!new_applet) { + // If we are going into a non-applet, clean up everything + for (auto it = disk_caches.begin(); it != disk_caches.end();) { + if (it == disk_caches.begin() || *it == curr_disk_cache) { + it++; + continue; + } + it = disk_caches.erase(it); + } + } +} + +bool PipelineCache::BindPipeline(PipelineInfo& info, bool wait_built) { MICROPROFILE_SCOPE(Vulkan_Bind); - u64 shader_hash = 0; for (u32 i = 0; i < MAX_SHADER_STAGES; i++) { - shader_hash = Common::HashCombine(shader_hash, shader_hashes[i]); + info.state.shader_ids[i] = shader_hashes[i]; } - const u64 info_hash = info.Hash(instance); - const u64 pipeline_hash = Common::HashCombine(shader_hash, info_hash); - - auto [it, new_pipeline] = graphics_pipelines.try_emplace(pipeline_hash); - if (new_pipeline) { - it.value() = - std::make_unique(instance, renderpass_cache, info, *pipeline_cache, - *pipeline_layout, current_shaders, &workers); - } - - GraphicsPipeline* const pipeline{it->second.get()}; + GraphicsPipeline* const pipeline = curr_disk_cache->GetPipeline(info); if (!pipeline->IsDone() && !pipeline->TryBuild(wait_built)) { return false; } @@ -265,12 +376,12 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) { const bool is_dirty = scheduler.IsStateDirty(StateFlags::Pipeline); const bool pipeline_dirty = (current_pipeline != pipeline) || is_dirty; scheduler.Record([this, is_dirty, pipeline_dirty, pipeline, - current_dynamic = current_info.dynamic, dynamic = info.dynamic, + current_dynamic = current_info.dynamic_info, dynamic = info.dynamic_info, descriptor_sets = bound_descriptor_sets, offsets = offsets, - current_rasterization = current_info.rasterization, - current_depth_stencil = current_info.depth_stencil, - rasterization = info.rasterization, - depth_stencil = info.depth_stencil](vk::CommandBuffer cmdbuf) { + current_rasterization = current_info.state.rasterization, + current_depth_stencil = current_info.state.depth_stencil, + rasterization = info.state.rasterization, + depth_stencil = info.state.depth_stencil](vk::CommandBuffer cmdbuf) { if (dynamic.viewport != current_dynamic.viewport || is_dirty) { const vk::Viewport vk_viewport = { .x = static_cast(dynamic.viewport.left), @@ -383,65 +494,54 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) { return true; } -bool PipelineCache::UseProgrammableVertexShader(const Pica::RegsInternal& regs, - Pica::ShaderSetup& setup, - const VertexLayout& layout, bool accurate_mul) { +ExtraVSConfig PipelineCache::CalcExtraConfig(const PicaVSConfig& config) { + auto res = ExtraVSConfig(); + // Enable the geometry-shader only if we are actually doing per-fragment lighting // and care about proper quaternions. Otherwise just use standard vertex+fragment shaders. // We also don't need the geometry shader if we have the barycentric extension. - const bool use_geometry_shader = instance.UseGeometryShaders() && !regs.lighting.disable && + const bool use_geometry_shader = instance.UseGeometryShaders() && + !config.state.lighting_disable && !instance.IsFragmentShaderBarycentricSupported(); - PicaVSConfig config{regs, setup, instance.IsShaderClipDistanceSupported(), use_geometry_shader, - accurate_mul}; - for (u32 i = 0; i < layout.attribute_count; i++) { - const VertexAttribute& attr = layout.attributes[i]; - const FormatTraits& traits = instance.GetTraits(attr.type, attr.size); - const u32 location = attr.location.Value(); - AttribLoadFlags& flags = config.state.load_flags[location]; + res.use_clip_planes = instance.IsShaderClipDistanceSupported(); + res.use_geometry_shader = use_geometry_shader; + res.sanitize_mul = profile.enable_accurate_mul; + res.separable_shader = true; + res.load_flags.fill(AttribLoadFlags::Float); + + for (u32 i = 0; i < config.state.used_input_vertex_attributes; i++) { + const auto& attr = config.state.input_vertex_attributes[i]; + const u32 location = attr.location; + const Pica::PipelineRegs::VertexAttributeFormat type = + static_cast(attr.type); + const FormatTraits& traits = instance.GetTraits(type, attr.size); + AttribLoadFlags& flags = res.load_flags[location]; if (traits.needs_conversion) { - flags = MakeAttribLoadFlag(attr.type); + flags = MakeAttribLoadFlag(type); } if (traits.needs_emulation) { flags |= AttribLoadFlags::ZeroW; } } - const auto [it, new_config] = programmable_vertex_map.try_emplace(config); - if (new_config) { - auto program = GLSL::GenerateVertexShader(setup, config, true); - if (program.empty()) { - LOG_ERROR(Render_Vulkan, "Failed to retrieve programmable vertex shader"); - programmable_vertex_map[config] = nullptr; - return false; - } + return res; +} - auto [iter, new_program] = programmable_vertex_cache.try_emplace(program, instance); - auto& shader = iter->second; +bool PipelineCache::UseProgrammableVertexShader(const Pica::RegsInternal& regs, + Pica::ShaderSetup& setup, + const VertexLayout& layout) { - if (new_program) { - shader.program = std::move(program); - const vk::Device device = instance.GetDevice(); - workers.QueueWork([device, &shader] { - shader.module = Compile(shader.program, vk::ShaderStageFlagBits::eVertex, device); - shader.MarkDone(); - }); - } + auto res = curr_disk_cache->UseProgrammableVertexShader(regs, setup, layout); - it->second = &shader; + if (res.has_value()) { + current_shaders[ProgramType::VS] = (*res).second; + shader_hashes[ProgramType::VS] = (*res).first; + return true; } - Shader* const shader{it->second}; - if (!shader) { - LOG_ERROR(Render_Vulkan, "Failed to retrieve programmable vertex shader"); - return false; - } - - current_shaders[ProgramType::VS] = shader; - shader_hashes[ProgramType::VS] = config.Hash(); - - return true; + return false; } void PipelineCache::UseTrivialVertexShader() { @@ -450,27 +550,16 @@ void PipelineCache::UseTrivialVertexShader() { } bool PipelineCache::UseFixedGeometryShader(const Pica::RegsInternal& regs) { - if (!instance.UseGeometryShaders()) { - UseTrivialGeometryShader(); + + auto res = curr_disk_cache->UseFixedGeometryShader(regs); + + if (res.has_value()) { + current_shaders[ProgramType::GS] = (*res).second; + shader_hashes[ProgramType::GS] = (*res).first; return true; } - const PicaFixedGSConfig gs_config{regs, instance.IsShaderClipDistanceSupported()}; - auto [it, new_shader] = fixed_geometry_shaders.try_emplace(gs_config, instance); - auto& shader = it->second; - - if (new_shader) { - workers.QueueWork([gs_config, device = instance.GetDevice(), &shader]() { - const auto code = GLSL::GenerateFixedGeometryShader(gs_config, true); - shader.module = Compile(code, vk::ShaderStageFlagBits::eGeometry, device); - shader.MarkDone(); - }); - } - - current_shaders[ProgramType::GS] = &shader; - shader_hashes[ProgramType::GS] = gs_config.Hash(); - - return true; + return false; } void PipelineCache::UseTrivialGeometryShader() { @@ -480,27 +569,13 @@ void PipelineCache::UseTrivialGeometryShader() { void PipelineCache::UseFragmentShader(const Pica::RegsInternal& regs, const Pica::Shader::UserConfig& user) { - const FSConfig fs_config{regs, user, profile}; - const auto [it, new_shader] = fragment_shaders.try_emplace(fs_config, instance); - auto& shader = it->second; - if (new_shader) { - workers.QueueWork([fs_config, this, &shader]() { - const bool use_spirv = Settings::values.spirv_shader_gen.GetValue(); - if (use_spirv && !fs_config.UsesSpirvIncompatibleConfig()) { - const std::vector code = SPIRV::GenerateFragmentShader(fs_config, profile); - shader.module = CompileSPV(code, instance.GetDevice()); - } else { - const std::string code = GLSL::GenerateFragmentShader(fs_config, profile); - shader.module = - Compile(code, vk::ShaderStageFlagBits::eFragment, instance.GetDevice()); - } - shader.MarkDone(); - }); + auto res = curr_disk_cache->UseFragmentShader(regs, user); + + if (res.has_value()) { + current_shaders[ProgramType::FS] = (*res).second; + shader_hashes[ProgramType::FS] = (*res).first; } - - current_shaders[ProgramType::FS] = &shader; - shader_hashes[ProgramType::FS] = fs_config.Hash(); } bool PipelineCache::IsCacheValid(std::span data) const { @@ -556,53 +631,20 @@ bool PipelineCache::EnsureDirectories() const { }; return create_dir(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) && - create_dir(GetPipelineCacheDir()); + create_dir(GetVulkanDir()) && create_dir(GetPipelineCacheDir()) && + create_dir(GetTransferableDir()); +} + +std::string PipelineCache::GetVulkanDir() const { + return FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir) + "vulkan" + DIR_SEP; } std::string PipelineCache::GetPipelineCacheDir() const { - return FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir) + "vulkan" + DIR_SEP + "pipeline" + - DIR_SEP; + return GetVulkanDir() + "pipeline" + DIR_SEP; } -void PipelineCache::SwitchPipelineCache(u64 title_id, const std::atomic_bool& stop_loading, - const VideoCore::DiskResourceLoadCallback& callback) { - if (!Settings::values.use_disk_shader_cache || GetProgramID() == title_id) { - LOG_DEBUG(Render_Vulkan, - "Skipping pipeline cache switch - already using cache for title_id={:016X}", - title_id); - return; - } - - if (callback) { - callback(VideoCore::LoadCallbackStage::Prepare, 0, 0); - } - if (callback) { - callback(VideoCore::LoadCallbackStage::Build, 0, 1); - } - - // Make sure we have a valid pipeline cache before switching - if (!pipeline_cache) { - vk::PipelineCacheCreateInfo cache_info{}; - try { - pipeline_cache = instance.GetDevice().createPipelineCacheUnique(cache_info); - } catch (const vk::SystemError& err) { - LOG_ERROR(Render_Vulkan, "Failed to create pipeline cache: {}", err.what()); - return; - } - } - - LOG_INFO(Render_Vulkan, "Switching pipeline cache to title_id={:016X}", title_id); - - // Save current cache before switching - SaveDiskCache(); - - // Update program ID and load the new pipeline cache - SetProgramID(title_id); - LoadDiskCache(stop_loading, nullptr); - - if (callback) { - callback(VideoCore::LoadCallbackStage::Complete, 0, 0); - } +std::string PipelineCache::GetTransferableDir() const { + return GetVulkanDir() + DIR_SEP + "transferable"; } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 650df5680..111960073 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -5,11 +5,11 @@ #pragma once #include -#include #include "video_core/rasterizer_interface.h" #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" #include "video_core/renderer_vulkan/vk_resource_pool.h" +#include "video_core/renderer_vulkan/vk_shader_disk_cache.h" #include "video_core/shader/generator/pica_fs_config.h" #include "video_core/shader/generator/profile.h" #include "video_core/shader/generator/shader_gen.h" @@ -58,19 +58,23 @@ public: offsets[binding] = offset; } - /// Loads the pipeline cache stored to disk - void LoadDiskCache(const std::atomic_bool& stop_loading = std::atomic_bool{false}, - const VideoCore::DiskResourceLoadCallback& callback = {}); + /// Loads the driver pipeline cache and the disk shader cache + void LoadCache(const std::atomic_bool& stop_loading = std::atomic_bool{false}, + const VideoCore::DiskResourceLoadCallback& callback = {}); - /// Stores the generated pipeline cache to disk - void SaveDiskCache(); + /// Switches the driver pipeline cache and the shader disk cache to the specified title + void SwitchCache(u64 title_id, const std::atomic_bool& stop_loading = std::atomic_bool{false}, + const VideoCore::DiskResourceLoadCallback& callback = {}); /// Binds a pipeline using the provided information - bool BindPipeline(const PipelineInfo& info, bool wait_built = false); + bool BindPipeline(PipelineInfo& info, bool wait_built = false); + + Pica::Shader::Generator::ExtraVSConfig CalcExtraConfig( + const Pica::Shader::Generator::PicaVSConfig& config); /// Binds a PICA decompiled vertex shader bool UseProgrammableVertexShader(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, - const VertexLayout& layout, bool accurate_mul); + const VertexLayout& layout); /// Binds a passthrough vertex shader void UseTrivialVertexShader(); @@ -84,11 +88,6 @@ public: /// Binds a fragment shader generated from PICA state void UseFragmentShader(const Pica::RegsInternal& regs, const Pica::Shader::UserConfig& user); - /// Switches the shader disk cache to the specified title - void SwitchPipelineCache(u64 title_id, - const std::atomic_bool& stop_loading = std::atomic_bool{false}, - const VideoCore::DiskResourceLoadCallback& callback = {}); - /// Gets the current program ID u64 GetProgramID() const { return current_program_id; @@ -98,7 +97,28 @@ public: current_program_id = program_id; } + void SetAccurateMul(bool _accurate_mul) { + profile.enable_accurate_mul = _accurate_mul; + } + private: + friend ShaderDiskCache; + + /// Loads the driver pipeline cache + void LoadDriverPipelineDiskCache(const std::atomic_bool& stop_loading = std::atomic_bool{false}, + const VideoCore::DiskResourceLoadCallback& callback = {}); + + /// Stores the generated pipeline cache + void SaveDriverPipelineDiskCache(); + + /// Loads the shader disk cache + void LoadDiskCache(const std::atomic_bool& stop_loading = std::atomic_bool{false}, + const VideoCore::DiskResourceLoadCallback& callback = {}); + + /// Switches the disk cache at runtime to use a different title ID + void SwitchDiskCache(u64 title_id, const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback); + /// Builds the rasterizer pipeline layout void BuildLayout(); @@ -108,9 +128,15 @@ private: /// Create pipeline cache directories. Returns true on success. bool EnsureDirectories() const; + /// Returns the Vulkan shader directory + std::string GetVulkanDir() const; + /// Returns the pipeline cache storage dir std::string GetPipelineCacheDir() const; + /// Returns the transferable shader dir + std::string GetTransferableDir() const; + private: const Instance& instance; Scheduler& scheduler; @@ -118,27 +144,24 @@ private: DescriptorUpdateQueue& update_queue; Pica::Shader::Profile profile{}; - vk::UniquePipelineCache pipeline_cache; + vk::UniquePipelineCache driver_pipeline_cache; vk::UniquePipelineLayout pipeline_layout; std::size_t num_worker_threads; Common::ThreadWorker workers; PipelineInfo current_info{}; GraphicsPipeline* current_pipeline{}; - tsl::robin_map, Common::IdentityHash> - graphics_pipelines; std::array descriptor_heaps; std::array bound_descriptor_sets{}; std::array offsets{}; std::array shader_hashes; std::array current_shaders; - std::unordered_map programmable_vertex_map; - std::unordered_map programmable_vertex_cache; - std::unordered_map fixed_geometry_shaders; - std::unordered_map fragment_shaders; + Shader trivial_vertex_shader; u64 current_program_id{0}; + std::vector> disk_caches; + std::shared_ptr curr_disk_cache{}; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_present_window.cpp b/src/video_core/renderer_vulkan/vk_present_window.cpp index 7cdf455dc..4d049d97d 100644 --- a/src/video_core/renderer_vulkan/vk_present_window.cpp +++ b/src/video_core/renderer_vulkan/vk_present_window.cpp @@ -105,7 +105,7 @@ PresentWindow::PresentWindow(Frontend::EmuWindow& emu_window_, const Instance& i swapchain{instance, emu_window.GetFramebufferLayout().width, emu_window.GetFramebufferLayout().height, surface, low_refresh_rate_}, graphics_queue{instance.GetGraphicsQueue()}, present_renderpass{CreateRenderpass()}, - vsync_enabled{Settings::values.use_vsync_new.GetValue()}, + vsync_enabled{Settings::values.use_vsync.GetValue()}, blit_supported{ CanBlitToSwapchain(instance.GetPhysicalDevice(), swapchain.GetSurfaceFormat().format)}, use_present_thread{Settings::values.async_presentation.GetValue()}, @@ -360,7 +360,7 @@ void PresentWindow::CopyToSwapchain(Frame* frame) { }; #ifndef ANDROID - const bool use_vsync = Settings::values.use_vsync_new.GetValue(); + const bool use_vsync = Settings::values.use_vsync.GetValue(); const bool size_changed = swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; const bool vsync_changed = vsync_enabled != use_vsync; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index e9df994f7..7a27032e9 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -87,7 +87,7 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory, Pica::PicaCore& // Define vertex layout for software shaders MakeSoftwareVertexLayout(); - pipeline_info.vertex_layout = software_layout; + pipeline_info.state.vertex_layout = software_layout; const vk::Device device = instance.GetDevice(); texture_lf_view = device.createBufferViewUnique({ @@ -152,66 +152,67 @@ void RasterizerVulkan::LoadDefaultDiskResources( program_id = 0; } + if (callback) { + callback(VideoCore::LoadCallbackStage::Prepare, 0, 0, ""); + } + pipeline_cache.SetProgramID(program_id); - pipeline_cache.LoadDiskCache(stop_loading, callback); + pipeline_cache.SetAccurateMul(accurate_mul); + pipeline_cache.LoadCache(stop_loading, callback); + + if (callback) { + callback(VideoCore::LoadCallbackStage::Complete, 0, 0, ""); + } } void RasterizerVulkan::SyncDrawState() { SyncDrawUniforms(); // SyncCullMode(); - pipeline_info.rasterization.cull_mode.Assign(regs.rasterizer.cull_mode); + pipeline_info.state.rasterization.cull_mode.Assign(regs.rasterizer.cull_mode); // If the framebuffer is flipped, request to also flip vulkan viewport const bool is_flipped = regs.framebuffer.framebuffer.IsFlipped(); - pipeline_info.rasterization.flip_viewport.Assign(is_flipped); + pipeline_info.state.rasterization.flip_viewport.Assign(is_flipped); // SyncBlendEnabled(); - pipeline_info.blending.blend_enable = regs.framebuffer.output_merger.alphablend_enable; + pipeline_info.state.blending.blend_enable = regs.framebuffer.output_merger.alphablend_enable; // SyncBlendFuncs(); - pipeline_info.blending.color_blend_eq.Assign( + pipeline_info.state.blending.color_blend_eq.Assign( regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb); - pipeline_info.blending.alpha_blend_eq.Assign( + pipeline_info.state.blending.alpha_blend_eq.Assign( regs.framebuffer.output_merger.alpha_blending.blend_equation_a); - pipeline_info.blending.src_color_blend_factor.Assign( + pipeline_info.state.blending.src_color_blend_factor.Assign( regs.framebuffer.output_merger.alpha_blending.factor_source_rgb); - pipeline_info.blending.dst_color_blend_factor.Assign( + pipeline_info.state.blending.dst_color_blend_factor.Assign( regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb); - pipeline_info.blending.src_alpha_blend_factor.Assign( + pipeline_info.state.blending.src_alpha_blend_factor.Assign( regs.framebuffer.output_merger.alpha_blending.factor_source_a); - pipeline_info.blending.dst_alpha_blend_factor.Assign( + pipeline_info.state.blending.dst_alpha_blend_factor.Assign( regs.framebuffer.output_merger.alpha_blending.factor_dest_a); // SyncBlendColor(); - pipeline_info.dynamic.blend_color = regs.framebuffer.output_merger.blend_const.raw; + pipeline_info.dynamic_info.blend_color = regs.framebuffer.output_merger.blend_const.raw; // SyncLogicOp(); // SyncColorWriteMask(); - pipeline_info.blending.logic_op = regs.framebuffer.output_merger.logic_op; - const bool is_logic_op_emulated = - instance.NeedsLogicOpEmulation() && !regs.framebuffer.output_merger.alphablend_enable; - const bool is_logic_op_noop = - regs.framebuffer.output_merger.logic_op == Pica::FramebufferRegs::LogicOp::NoOp; - if (is_logic_op_emulated && is_logic_op_noop) { - // Color output is disabled by logic operation. We use color write mask to skip - // color but allow depth write. - pipeline_info.blending.color_write_mask = 0; - } else { - const u32 color_mask = regs.framebuffer.framebuffer.allow_color_write != 0 - ? (regs.framebuffer.output_merger.depth_color_mask >> 8) & 0xF - : 0; - pipeline_info.blending.color_write_mask = color_mask; - } + pipeline_info.state.blending.logic_op = regs.framebuffer.output_merger.logic_op; + + const u32 color_mask = regs.framebuffer.framebuffer.allow_color_write != 0 + ? (regs.framebuffer.output_merger.depth_color_mask >> 8) & 0xF + : 0; + pipeline_info.state.blending.color_write_mask = color_mask; + // SyncStencilTest(); const auto& stencil_test = regs.framebuffer.output_merger.stencil_test; const bool test_enable = stencil_test.enable && regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8; - pipeline_info.depth_stencil.stencil_test_enable.Assign(test_enable); - pipeline_info.depth_stencil.stencil_fail_op.Assign(stencil_test.action_stencil_fail); - pipeline_info.depth_stencil.stencil_pass_op.Assign(stencil_test.action_depth_pass); - pipeline_info.depth_stencil.stencil_depth_fail_op.Assign(stencil_test.action_depth_fail); - pipeline_info.depth_stencil.stencil_compare_op.Assign(stencil_test.func); - pipeline_info.dynamic.stencil_reference = stencil_test.reference_value; - pipeline_info.dynamic.stencil_compare_mask = stencil_test.input_mask; + pipeline_info.state.depth_stencil.stencil_test_enable.Assign(test_enable); + pipeline_info.state.depth_stencil.stencil_fail_op.Assign(stencil_test.action_stencil_fail); + pipeline_info.state.depth_stencil.stencil_pass_op.Assign(stencil_test.action_depth_pass); + pipeline_info.state.depth_stencil.stencil_depth_fail_op.Assign(stencil_test.action_depth_fail); + pipeline_info.state.depth_stencil.stencil_compare_op.Assign(stencil_test.func); + pipeline_info.dynamic_info.stencil_reference = stencil_test.reference_value; + pipeline_info.dynamic_info.stencil_compare_mask = stencil_test.input_mask; // SyncStencilWriteMask(); - pipeline_info.dynamic.stencil_write_mask = + pipeline_info.dynamic_info.stencil_write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0) ? static_cast(regs.framebuffer.output_merger.stencil_test.write_mask) : 0; @@ -222,12 +223,12 @@ void RasterizerVulkan::SyncDrawState() { ? regs.framebuffer.output_merger.depth_test_func.Value() : Pica::FramebufferRegs::CompareFunc::Always; - pipeline_info.depth_stencil.depth_test_enable.Assign(test_enabled); - pipeline_info.depth_stencil.depth_compare_op.Assign(compare_op); + pipeline_info.state.depth_stencil.depth_test_enable.Assign(test_enabled); + pipeline_info.state.depth_stencil.depth_compare_op.Assign(compare_op); // SyncDepthWriteMask(); const bool write_enable = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 && regs.framebuffer.output_merger.depth_write_enable); - pipeline_info.depth_stencil.depth_write_enable.Assign(write_enable); + pipeline_info.state.depth_stencil.depth_write_enable.Assign(write_enable); } void RasterizerVulkan::SetupVertexArray() { @@ -246,7 +247,7 @@ void RasterizerVulkan::SetupVertexArray() { const PAddr base_address = vertex_attributes.GetPhysicalBaseAddress(); // GPUREG_ATTR_BUF_BASE const u32 stride_alignment = instance.GetMinVertexStrideAlignment(); - VertexLayout& layout = pipeline_info.vertex_layout; + VertexLayout& layout = pipeline_info.state.vertex_layout; layout.binding_count = 0; layout.attribute_count = 16; enable_attributes.fill(false); @@ -322,7 +323,8 @@ void RasterizerVulkan::SetupVertexArray() { VertexBinding& binding = layout.bindings[layout.binding_count]; binding.binding.Assign(layout.binding_count); binding.fixed.Assign(0); - binding.stride.Assign(aligned_stride); + // Will be adjusted on pipeline build, to keep the info transferable. + binding.byte_count.Assign(loader.byte_count); // Keep track of the binding offsets so we can bind the vertex buffer later binding_offsets[layout.binding_count++] = static_cast(array_offset + buffer_offset); @@ -337,7 +339,7 @@ void RasterizerVulkan::SetupVertexArray() { void RasterizerVulkan::SetupFixedAttribs() { const auto& vertex_attributes = regs.pipeline.vertex_attributes; - VertexLayout& layout = pipeline_info.vertex_layout; + VertexLayout& layout = pipeline_info.state.vertex_layout; auto [fixed_ptr, fixed_offset, _] = stream_buffer.Map(16 * sizeof(Common::Vec4f), 0); binding_offsets[layout.binding_count] = static_cast(fixed_offset); @@ -391,7 +393,7 @@ void RasterizerVulkan::SetupFixedAttribs() { VertexBinding& binding = layout.bindings[layout.binding_count]; binding.binding.Assign(layout.binding_count++); binding.fixed.Assign(1); - binding.stride.Assign(offset); + binding.byte_count.Assign(offset); stream_buffer.Commit(offset); } @@ -399,7 +401,7 @@ void RasterizerVulkan::SetupFixedAttribs() { bool RasterizerVulkan::SetupVertexShader() { MICROPROFILE_SCOPE(Vulkan_VS); return pipeline_cache.UseProgrammableVertexShader(regs, pica.vs_setup, - pipeline_info.vertex_layout, accurate_mul); + pipeline_info.state.vertex_layout); } bool RasterizerVulkan::SetupGeometryShader() { @@ -412,8 +414,9 @@ bool RasterizerVulkan::SetupGeometryShader() { // Enable the quaternion fix-up geometry-shader only if we are actually doing per-fragment // lighting and care about proper quaternions. Otherwise just use standard vertex+fragment - // shaders. We also don't need a geometry shader if the barycentric extension is supported. - if (regs.lighting.disable || instance.IsFragmentShaderBarycentricSupported()) { + // shaders. We also don't need a geometry shader if the barycentric extension is supported, + // but that will be decided later as the GS config needs to be cached anyways. + if (regs.lighting.disable) { pipeline_cache.UseTrivialGeometryShader(); return true; } @@ -431,7 +434,7 @@ bool RasterizerVulkan::AccelerateDrawBatch(bool is_indexed) { } } - pipeline_info.rasterization.topology.Assign(regs.pipeline.triangle_topology); + pipeline_info.state.rasterization.topology.Assign(regs.pipeline.triangle_topology); if (regs.pipeline.triangle_topology == TriangleTopology::Fan && !instance.IsTriangleFanSupported()) { LOG_DEBUG(Render_Vulkan, @@ -467,7 +470,7 @@ bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) { const DrawParams params = { .vertex_count = regs.pipeline.num_vertices, .vertex_offset = -static_cast(vertex_info.vs_input_index_min), - .binding_count = pipeline_info.vertex_layout.binding_count, + .binding_count = pipeline_info.state.vertex_layout.binding_count, .bindings = binding_offsets, .is_indexed = is_indexed, }; @@ -521,8 +524,8 @@ void RasterizerVulkan::DrawTriangles() { return; } - pipeline_info.rasterization.topology.Assign(Pica::PipelineRegs::TriangleTopology::List); - pipeline_info.vertex_layout = software_layout; + pipeline_info.state.rasterization.topology.Assign(Pica::PipelineRegs::TriangleTopology::List); + pipeline_info.state.vertex_layout = software_layout; pipeline_cache.UseTrivialVertexShader(); pipeline_cache.UseTrivialGeometryShader(); @@ -537,14 +540,14 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { const bool shadow_rendering = regs.framebuffer.IsShadowRendering(); const bool has_stencil = regs.framebuffer.HasStencil(); - const bool write_color_fb = shadow_rendering || pipeline_info.blending.color_write_mask; + const bool write_color_fb = shadow_rendering || pipeline_info.GetFinalColorWriteMask(instance); const bool write_depth_fb = pipeline_info.IsDepthWriteEnabled(); const bool using_color_fb = regs.framebuffer.framebuffer.GetColorBufferPhysicalAddress() != 0 && write_color_fb; const bool using_depth_fb = !shadow_rendering && regs.framebuffer.framebuffer.GetDepthBufferPhysicalAddress() != 0 && (write_depth_fb || regs.framebuffer.output_merger.depth_test_enable != 0 || - (has_stencil && pipeline_info.depth_stencil.stencil_test_enable)); + (has_stencil && pipeline_info.state.depth_stencil.stencil_test_enable)); const auto fb_helper = res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb); const Framebuffer* framebuffer = fb_helper.Framebuffer(); @@ -552,8 +555,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { return true; } - pipeline_info.attachments.color = framebuffer->Format(SurfaceType::Color); - pipeline_info.attachments.depth = framebuffer->Format(SurfaceType::Depth); + pipeline_info.state.attachments.color = framebuffer->Format(SurfaceType::Color); + pipeline_info.state.attachments.depth = framebuffer->Format(SurfaceType::Depth); // Update scissor uniforms const auto [scissor_x1, scissor_y2, scissor_x2, scissor_y1] = fb_helper.Scissor(); @@ -585,13 +588,13 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { // Configure viewport and scissor const auto viewport = fb_helper.Viewport(); - pipeline_info.dynamic.viewport = Common::Rectangle{ + pipeline_info.dynamic_info.viewport = Common::Rectangle{ viewport.x, viewport.y, viewport.x + viewport.width, viewport.y + viewport.height, }; - pipeline_info.dynamic.scissor = draw_rect; + pipeline_info.dynamic_info.scissor = draw_rect; // Draw the vertex batch bool succeeded = true; @@ -807,7 +810,7 @@ void RasterizerVulkan::MakeSoftwareVertexLayout() { VertexBinding& binding = software_layout.bindings[i]; binding.binding.Assign(i); binding.fixed.Assign(0); - binding.stride.Assign(sizeof(HardwareVertex)); + binding.byte_count.Assign(sizeof(HardwareVertex)); } u32 offset = 0; @@ -985,7 +988,17 @@ void RasterizerVulkan::UploadUniforms(bool accelerate_draw) { void RasterizerVulkan::SwitchDiskResources(u64 title_id) { std::atomic_bool stop_loading = false; - pipeline_cache.SwitchPipelineCache(title_id, stop_loading, switch_disk_resources_callback); + + if (switch_disk_resources_callback) { + switch_disk_resources_callback(VideoCore::LoadCallbackStage::Prepare, 0, 0, ""); + } + + pipeline_cache.SetAccurateMul(accurate_mul); + pipeline_cache.SwitchCache(title_id, stop_loading, switch_disk_resources_callback); + + if (switch_disk_resources_callback) { + switch_disk_resources_callback(VideoCore::LoadCallbackStage::Complete, 0, 0, ""); + } } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_shader_disk_cache.cpp b/src/video_core/renderer_vulkan/vk_shader_disk_cache.cpp new file mode 100644 index 000000000..15e45ce81 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_shader_disk_cache.cpp @@ -0,0 +1,1525 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_paths.h" +#include "common/file_util.h" +#include "common/scm_rev.h" +#include "common/settings.h" +#include "common/static_lru_cache.h" +#include "common/zstd_compression.h" +#include "video_core/renderer_vulkan/vk_instance.h" +#include "video_core/renderer_vulkan/vk_pipeline_cache.h" +#include "video_core/renderer_vulkan/vk_shader_disk_cache.h" +#include "video_core/renderer_vulkan/vk_shader_util.h" +#include "video_core/shader/generator/glsl_fs_shader_gen.h" +#include "video_core/shader/generator/glsl_shader_gen.h" +#include "video_core/shader/generator/shader_gen.h" +#include "video_core/shader/generator/spv_fs_shader_gen.h" + +#define MALFORMED_DISK_CACHE \ + do { \ + LOG_ERROR(Render_Vulkan, "Malformed disk shader cache"); \ + cleanup_on_error(); \ + return false; \ + } while (0) + +// Enable to debug when new cache objects are created. +// #define ENABLE_LOG_NEW_OBJECT + +#ifdef ENABLE_LOG_NEW_OBJECT +#define LOG_NEW_OBJECT LOG_DEBUG +#else +#define LOG_NEW_OBJECT(...) ((void)0) +#endif + +namespace Vulkan { + +using namespace Pica::Shader::Generator; +using namespace Pica::Shader; + +static VideoCore::DiskResourceLoadCallback MakeThrottledCallback( + VideoCore::DiskResourceLoadCallback original) { + + if (!original) + return nullptr; + + auto last_call = std::chrono::steady_clock::now() - std::chrono::milliseconds(10); + + return [original, last_call](VideoCore::LoadCallbackStage stage, std::size_t current, + std::size_t total, const std::string& name) mutable { + const auto now = std::chrono::steady_clock::now(); + if (now - last_call >= std::chrono::milliseconds(10)) { + last_call = now; + original(stage, current, total, name); + } + }; +} + +void ShaderDiskCache::Init(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + + if (!Settings::values.use_disk_shader_cache) + return; + + auto new_callback = MakeThrottledCallback(callback); + + if (!stop_loading && !InitVSCache(stop_loading, new_callback)) { + RecreateCache(vs_cache, CacheFileType::VS_CACHE); + } + if (!stop_loading && !InitFSCache(stop_loading, new_callback)) { + RecreateCache(fs_cache, CacheFileType::FS_CACHE); + } + if (!stop_loading && !InitGSCache(stop_loading, new_callback)) { + RecreateCache(gs_cache, CacheFileType::GS_CACHE); + } + if (!stop_loading && !InitPLCache(stop_loading, new_callback)) { + RecreateCache(pl_cache, CacheFileType::PL_CACHE); + } +} + +std::optional> ShaderDiskCache::UseProgrammableVertexShader( + const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, const VertexLayout& layout) { + + PicaVSConfig config{regs, setup}; + + // Transfer vertex attributes to the VS config + config.state.used_input_vertex_attributes = layout.attribute_count; + for (u32 i = 0; i < layout.attribute_count; i++) { + auto& dst = config.state.input_vertex_attributes[i]; + const auto& src = layout.attributes[i]; + + dst.location = src.location; + dst.type = static_cast(src.type.Value()); + dst.size = src.size; + } + + const auto config_hash = config.Hash(); + + const auto [iter_config, new_config] = programmable_vertex_map.try_emplace(config_hash); + if (new_config) { + + LOG_NEW_OBJECT(Render_Vulkan, "New VS config {:016X}", config_hash); + + ExtraVSConfig extra_config = parent.CalcExtraConfig(config); + + auto program = + Common::HashableString(GLSL::GenerateVertexShader(setup, config, extra_config)); + + if (program.empty()) { + LOG_ERROR(Render_Vulkan, "Failed to retrieve programmable vertex shader"); + programmable_vertex_map.erase(config_hash); + return {}; + } + + const u64 spirv_id = program.Hash(); + + auto [iter_prog, new_program] = + programmable_vertex_cache.try_emplace(spirv_id, parent.instance); + auto& shader = iter_prog->second; + + if (new_program) { + LOG_NEW_OBJECT(Render_Vulkan, "New VS SPIRV {:016X}", spirv_id); + + shader.program = std::move(program); + const vk::Device device = parent.instance.GetDevice(); + parent.workers.QueueWork([device, &shader, this, spirv_id] { + auto spirv = CompileGLSL(shader.program, vk::ShaderStageFlagBits::eVertex); + AppendVSSPIRV(vs_cache, spirv, spirv_id); + shader.program.clear(); + shader.module = CompileSPV(spirv, device); + shader.MarkDone(); + }); + } + + AppendVSConfigProgram(vs_cache, config, setup, config_hash, spirv_id); + + iter_config->second = &shader; + } + + Shader* const shader{iter_config->second}; + if (!shader) { + LOG_ERROR(Render_Vulkan, "Failed to retrieve programmable vertex shader"); + return {}; + } + + return std::make_pair(config_hash, shader); +} + +std::optional> ShaderDiskCache::UseFragmentShader( + const Pica::RegsInternal& regs, const Pica::Shader::UserConfig& user) { + + const FSConfig fs_config{regs}; + const auto fs_config_hash = fs_config.Hash(); + const auto [it, new_shader] = fragment_shaders.try_emplace(fs_config_hash, parent.instance); + auto& shader = it->second; + + if (new_shader) { + LOG_NEW_OBJECT(Render_Vulkan, "New FS config {:016X}", fs_config_hash); + + parent.workers.QueueWork([fs_config, user, this, &shader, fs_config_hash]() { + std::vector spirv; + const bool use_spirv = parent.profile.vk_use_spirv_generator; + if (use_spirv && !fs_config.UsesSpirvIncompatibleConfig()) { + spirv = SPIRV::GenerateFragmentShader(fs_config, parent.profile); + shader.module = CompileSPV(spirv, parent.instance.GetDevice()); + } else { + const std::string code = + GLSL::GenerateFragmentShader(fs_config, user, parent.profile); + spirv = CompileGLSL(code, vk::ShaderStageFlagBits::eFragment); + shader.module = CompileSPV(spirv, parent.instance.GetDevice()); + } + shader.MarkDone(); + + if (user.IsCacheable()) { + // Only cache to disk if the user config is cacheable + AppendFSSPIRV(fs_cache, spirv, fs_config_hash); + FSConfigEntry entry{.version = FSConfigEntry::EXPECTED_VERSION, + .fs_config = fs_config}; + AppendFSConfig(fs_cache, entry, fs_config_hash); + } + }); + } + + return std::make_pair(fs_config_hash, &shader); +} + +std::optional> ShaderDiskCache::UseFixedGeometryShader( + const Pica::RegsInternal& regs) { + + const PicaFixedGSConfig gs_config{regs}; + const auto gs_config_hash = gs_config.Hash(); + + if (!parent.instance.UseGeometryShaders() || + parent.instance.IsFragmentShaderBarycentricSupported()) { + // Even if we don't support geometry shaders, we still need to cache them + // so that the shader cache is transferable. There is no need to cache + // or build the SPIRV. + + if (known_geometry_shaders.emplace(gs_config_hash).second) { + GSConfigEntry entry{ + .version = GSConfigEntry::EXPECTED_VERSION, + .gs_config = gs_config, + }; + AppendGSConfig(gs_cache, entry, gs_config_hash); + } + + return std::make_pair(gs_config_hash, nullptr); + } else { + auto [it, new_shader] = fixed_geometry_shaders.try_emplace(gs_config_hash, parent.instance); + auto& shader = it->second; + + if (new_shader) { + LOG_NEW_OBJECT(Render_Vulkan, "New GS config {:016X}", gs_config_hash); + + parent.workers.QueueWork([gs_config, this, &shader, gs_config_hash]() { + ExtraFixedGSConfig extra; + extra.use_clip_planes = parent.profile.has_clip_planes; + extra.separable_shader = true; + + const auto code = GLSL::GenerateFixedGeometryShader(gs_config, extra); + const auto spirv = CompileGLSL(code, vk::ShaderStageFlagBits::eGeometry); + shader.module = CompileSPV(spirv, parent.instance.GetDevice()); + shader.MarkDone(); + + AppendGSSPIRV(gs_cache, spirv, gs_config_hash); + GSConfigEntry entry{ + .version = GSConfigEntry::EXPECTED_VERSION, + .gs_config = gs_config, + }; + AppendGSConfig(gs_cache, entry, gs_config_hash); + }); + } + + return std::make_pair(gs_config_hash, &shader); + } +} + +GraphicsPipeline* ShaderDiskCache::GetPipeline(const PipelineInfo& info) { + + u64 hash = info.Hash(); + u64 optimized_hash = info.state.OptimizedHash(parent.instance); + + auto [it, new_pipeline] = graphics_pipelines.try_emplace(optimized_hash); + if (new_pipeline) { + if (!parent.instance.UseGeometryShaders() || + parent.instance.IsFragmentShaderBarycentricSupported()) { + // If we don't need geometry shaders disable + // them before building the pipeline. It's done here + // so that the shader ID could be hashed and saved with + // the pipeline info so that it is transferable. + parent.UseTrivialGeometryShader(); + } + it.value() = std::make_unique( + parent.instance, parent.renderpass_cache, info, *parent.driver_pipeline_cache, + *parent.pipeline_layout, parent.current_shaders, &parent.workers); + } + + if (known_graphic_pipelines.emplace(hash).second) { + LOG_NEW_OBJECT(Render_Vulkan, "New Pipeline {:016X}", hash); + + PLConfigEntry entry{ + .version = PLConfigEntry::EXPECTED_VERSION, + .pl_info = info.state, + }; + + AppendPLConfig(pl_cache, entry, hash); + } + + return it.value().get(); +} + +ShaderDiskCache::SourceFileCacheVersionHash ShaderDiskCache::GetSourceFileCacheVersionHash() { + SourceFileCacheVersionHash hash{}; + const std::size_t length = std::min(std::strlen(Common::g_shader_cache_version), hash.size()); + std::memcpy(hash.data(), Common::g_shader_cache_version, length); + return hash; +} + +ShaderDiskCache::CacheEntry ShaderDiskCache::CacheFile::ReadFirst() { + return ReadAt(0); +} + +ShaderDiskCache::CacheEntry ShaderDiskCache::CacheFile::ReadNext(const CacheEntry& previous) { + if (!previous.valid) + return CacheEntry(); + + return ReadAt(previous.position + previous.header.entry_size); +} + +std::pair +ShaderDiskCache::CacheFile::ReadNextHeader( + const ShaderDiskCache::CacheEntry::CacheEntryHeader& previous, size_t previous_position) { + + size_t new_pos = previous_position + previous.entry_size; + + return {new_pos, ReadAtHeader(new_pos)}; +} + +ShaderDiskCache::CacheEntry::CacheEntryHeader ShaderDiskCache::CacheFile::ReadAtHeader( + size_t position) { + + CacheEntry::CacheEntryHeader header; + + if (file.ReadAtArray(&header, 1, position) == sizeof(CacheEntry::CacheEntryHeader)) { + return header; + } + + return CacheEntry::CacheEntryHeader(); +} + +ShaderDiskCache::CacheEntry ShaderDiskCache::CacheFile::ReadAt(size_t position) { + CacheEntry res{}; + res.position = position; + + constexpr u32 headers_size = + sizeof(CacheEntry::CacheEntryHeader) + sizeof(CacheEntry::CacheEntryFooter); + + res.header = ReadAtHeader(position); + + if (res.header.Valid()) { + + // We have everything validated, read the data. + u32 payload_size = res.header.entry_size - headers_size; + std::vector payload(payload_size); + + if (file.ReadAtBytes(payload.data(), payload_size, + position + sizeof(CacheEntry::CacheEntryHeader)) == payload_size) { + // Decompress data if needed + if (res.header.zstd_compressed) { + if (Common::Compression::GetDecompressedSize(payload) < + CacheEntry::MAX_ENTRY_SIZE) { + res.data = Common::Compression::DecompressDataZSTD(payload); + res.valid = true; + } + } else { + res.data = std::move(payload); + res.valid = true; + } + } + } + return res; +} + +size_t ShaderDiskCache::CacheFile::GetTotalEntries() { + if (!file.IsGood()) { + next_entry_id = SIZE_MAX; + return next_entry_id; + } + + if (next_entry_id != SIZE_MAX) { + return next_entry_id; + } + + const size_t file_size = file.GetSize(); + if (file_size == 0) { + next_entry_id = 0; + return next_entry_id; + } + + CacheEntry::CacheEntryFooter footer{}; + + if (file.ReadAtArray(&footer, 1, file_size - sizeof(footer)) == sizeof(footer) && + footer.version == CacheEntry::CacheEntryFooter::ENTRY_VERSION) { + next_entry_id = footer.entry_id + 1; + } else { + return SIZE_MAX; + } + + return next_entry_id; +} + +void ShaderDiskCache::CacheFile::Append(CacheEntryType type, u64 id, std::span data, + bool compress) { + if (curr_mode != CacheOpMode::APPEND) { + return; + } + + std::vector copy_data(data.begin(), data.end()); + + append_worker.QueueWork([this, type, id, compress, data = std::move(copy_data)]() { + if (next_entry_id == SIZE_MAX || !file.IsGood()) { + return; + } + + std::span data_final; + std::vector data_compress; + + CacheEntry::CacheEntryHeader header{}; + CacheEntry::CacheEntryFooter footer{}; + + constexpr u32 headers_size = + sizeof(CacheEntry::CacheEntryHeader) + sizeof(CacheEntry::CacheEntryFooter); + + if (compress) { + data_compress = Common::Compression::CompressDataZSTDDefault(data); + data_final = data_compress; + header.zstd_compressed.Assign(true); + } else { + data_final = data; + } + header.entry_version = CacheEntry::CacheEntryHeader::ENTRY_VERSION; + footer.version.Assign(CacheEntry::CacheEntryFooter::ENTRY_VERSION); + header.entry_size = footer.entry_size = data_final.size() + headers_size; + footer.entry_id.Assign(next_entry_id++); + + header.type = type; + header.id = id; + + std::vector out_data(data_final.size() + headers_size); + memcpy(out_data.data(), &header, sizeof(header)); + memcpy(out_data.data() + sizeof(header), data_final.data(), data_final.size()); + memcpy(out_data.data() + sizeof(header) + data_final.size(), &footer, sizeof(footer)); + + file.WriteBytes(out_data.data(), out_data.size()); + if (file.IsGood()) { + file.Flush(); + } + }); +} + +bool ShaderDiskCache::CacheFile::SwitchMode(CacheOpMode mode) { + if (curr_mode == mode) { + return true; + } + if (curr_mode == CacheOpMode::APPEND) { + append_worker.WaitForRequests(); + } + + switch (mode) { + case CacheOpMode::READ: { + next_entry_id = SIZE_MAX; // Force reading entries agains + file = FileUtil::IOFile(filepath, "rb"); + bool is_open = file.IsGood(); + if (is_open) { + GetTotalEntries(); + } + curr_mode = mode; + return is_open; + } + case CacheOpMode::APPEND: { + if (!SwitchMode(CacheOpMode::READ)) { + curr_mode = mode; + return false; + } + file.Close(); + curr_mode = mode; + if (next_entry_id == SIZE_MAX) { + // Cannot append if getting total items fails + return false; + } + + file = FileUtil::IOFile(filepath, "ab"); + return file.IsGood(); + } + case CacheOpMode::DELETE: { + next_entry_id = SIZE_MAX; + file.Close(); + curr_mode = mode; + return FileUtil::Delete(filepath); + } + case CacheOpMode::RECREATE: { + if (!SwitchMode(CacheOpMode::DELETE)) { + return false; + } + if (!FileUtil::CreateEmptyFile(filepath)) { + return false; + } + return SwitchMode(CacheOpMode::APPEND); + } + default: + UNREACHABLE(); + } + return false; +} + +std::string ShaderDiskCache::GetVSFile(u64 title_id, bool is_temp) const { + return parent.GetTransferableDir() + DIR_SEP + fmt::format("{:016X}_vs", title_id) + + (is_temp ? "_temp" : "") + ".vkch"; +} + +std::string ShaderDiskCache::GetFSFile(u64 title_id, bool is_temp) const { + return parent.GetTransferableDir() + DIR_SEP + fmt::format("{:016X}_fs", title_id) + + (is_temp ? "_temp" : "") + ".vkch"; +} + +std::string ShaderDiskCache::GetGSFile(u64 title_id, bool is_temp) const { + return parent.GetTransferableDir() + DIR_SEP + fmt::format("{:016X}_gs", title_id) + + (is_temp ? "_temp" : "") + ".vkch"; +} + +std::string ShaderDiskCache::GetPLFile(u64 title_id, bool is_temp) const { + return parent.GetTransferableDir() + DIR_SEP + fmt::format("{:016X}_pl", title_id) + + (is_temp ? "_temp" : "") + ".vkch"; +} + +bool ShaderDiskCache::RecreateCache(CacheFile& file, CacheFileType type) { + file.SwitchMode(CacheFile::CacheOpMode::RECREATE); + + std::array build_name{}; + size_t name_len = std::strlen(Common::g_build_fullname); + memcpy(build_name.data(), Common::g_build_fullname, std::min(name_len, build_name.size())); + + auto get_hash = [](CacheFileType type) { + switch (type) { + case CacheFileType::VS_CACHE: + return PicaVSConfigState::StructHash(); + case CacheFileType::FS_CACHE: + return FSConfig::StructHash(); + case CacheFileType::GS_CACHE: + return PicaGSConfigState::StructHash(); + case CacheFileType::PL_CACHE: + return StaticPipelineInfo::StructHash(); + default: + UNREACHABLE(); + return u64{}; + }; + }; + + FileInfoEntry entry{ + .cache_magic = FileInfoEntry::CACHE_FILE_MAGIC, + .file_version = FileInfoEntry::CACHE_FILE_VERSION, + .config_struct_hash = get_hash(type), + .file_type = type, + .source_hash = GetSourceFileCacheVersionHash(), + .build_name = build_name, + .profile = parent.profile, + }; + + file.Append(CacheEntryType::FILE_INFO, 0, entry, false); + return true; +} + +bool ShaderDiskCache::InitVSCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + std::vector pending_configs; + std::unordered_map pending_programs; + std::unique_ptr shader_setup; + std::unique_ptr regenerate_file; + + auto cleanup_on_error = [&]() { + programmable_vertex_cache.clear(); + programmable_vertex_map.clear(); + known_vertex_programs.clear(); + if (regenerate_file) { + regenerate_file->SwitchMode(CacheFile::CacheOpMode::DELETE); + } + }; + + LOG_INFO(Render_Vulkan, "Loading VS disk shader cache for title {:016X}", title_id); + + vs_cache.SetFilePath(GetVSFile(title_id, false)); + + if (!vs_cache.SwitchMode(CacheFile::CacheOpMode::READ)) { + LOG_INFO(Render_Vulkan, "Missing VS disk shader cache for title {:016X}", title_id); + cleanup_on_error(); + return false; + } + + u32 tot_entries = vs_cache.GetTotalEntries(); + auto curr = vs_cache.ReadFirst(); + if (!curr.Valid() || curr.Type() != CacheEntryType::FILE_INFO) { + MALFORMED_DISK_CACHE; + } + + const FileInfoEntry* file_info = curr.Payload(); + if (!file_info || file_info->cache_magic != FileInfoEntry::CACHE_FILE_MAGIC || + file_info->file_version != FileInfoEntry::CACHE_FILE_VERSION || + file_info->file_type != CacheFileType::VS_CACHE) { + MALFORMED_DISK_CACHE; + } + + if (file_info->config_struct_hash != PicaVSConfigState::StructHash()) { + LOG_ERROR(Render_Vulkan, + "Cache was created for a different PicaVSConfigState, resetting..."); + cleanup_on_error(); + return false; + } + + if (file_info->source_hash != GetSourceFileCacheVersionHash()) { + LOG_INFO(Render_Vulkan, "Cache contains old vertex program, cache needs regeneration."); + regenerate_file = std::make_unique(GetVSFile(title_id, true)); + } + + if (file_info->profile != parent.profile && !regenerate_file) { + LOG_INFO(Render_Vulkan, + "Cache has driver and user settings mismatch, cache needs regeneration."); + regenerate_file = std::make_unique(GetVSFile(title_id, true)); + } + + if (regenerate_file) { + RecreateCache(*regenerate_file, CacheFileType::VS_CACHE); + } + + CacheEntry::CacheEntryHeader curr_header = curr.Header(); + size_t curr_offset = curr.Position(); + + size_t current_callback_index = 0; + size_t tot_callback_index = tot_entries - 1; + + // Scan the entire file first, while keeping track of configs and programs. + // SPIRV can be compiled directly and will be linked to the proper config entries + // later. + for (int i = 1; i < tot_entries; i++) { + + if (stop_loading) { + cleanup_on_error(); + return true; + } + + std::tie(curr_offset, curr_header) = vs_cache.ReadNextHeader(curr_header, curr_offset); + + if (!curr_header.Valid()) { + MALFORMED_DISK_CACHE; + } + + LOG_DEBUG(Render_Vulkan, "Processing ID: {:016X} (type {})", curr_header.Id(), + curr_header.Type()); + + if (curr_header.Type() == CacheEntryType::VS_CONFIG) { + pending_configs.push_back(curr_offset); + } else if (curr_header.Type() == CacheEntryType::VS_PROGRAM) { + pending_programs.try_emplace(curr_header.Id(), curr_offset); + + // We won't use this entry sequentially again, so report progress. + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Vertex Shader"); + } + } else if (curr_header.Type() == CacheEntryType::VS_SPIRV) { + + // Only use SPIRV entries if we are not regenerating the cache, as the driver or + // user settings do not match, which could lead to different SPIRV. + // These will be re-created from the cached config and programs later. + if (!regenerate_file) { + LOG_DEBUG(Render_Vulkan, " processing SPIRV."); + + curr = vs_cache.ReadAt(curr_offset); + if (!curr.Valid() || curr.Type() != CacheEntryType::VS_SPIRV) { + MALFORMED_DISK_CACHE; + } + + const u8* spirv_data = curr.Data().data(); + const size_t spirv_size = curr.Data().size(); + + auto [iter_prog, new_program] = + programmable_vertex_cache.try_emplace(curr.Id(), parent.instance); + if (new_program) { + LOG_DEBUG(Render_Vulkan, " compiling SPIRV."); + + const auto spirv = std::span( + reinterpret_cast(spirv_data), spirv_size / sizeof(u32)); + + iter_prog->second.module = CompileSPV(spirv, parent.instance.GetDevice()); + iter_prog->second.MarkDone(); + + if (!iter_prog->second.module) { + // Compilation failed for some reason, remove from cache to let it + // be re-generated at runtime or during config and program processing. + LOG_ERROR(Render_Vulkan, "Unexpected program compilation failure"); + programmable_vertex_cache.erase(iter_prog); + } + } + } + + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Vertex Shader"); + } + } else { + MALFORMED_DISK_CACHE; + } + } + + // Once we have all the shader instances created from SPIRV, we can link them to the VS configs. + LOG_DEBUG(Render_Vulkan, "Linking with config entries."); + + // Mmultiple config entries may point to the same program entry. We could load all program + // entries to memory to prevent having to read them from disk on every config entry, but program + // entries are pretty big (around 50KB each). A LRU cache is a middle point between disk access + // and memory usage. + std::unique_ptr> program_lru = + std::make_unique>(); + + for (auto& offset : pending_configs) { + if (stop_loading) { + cleanup_on_error(); + return true; + } + + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Vertex Shader"); + } + + curr = vs_cache.ReadAt(offset); + const VSConfigEntry* entry; + + if (!curr.Valid() || curr.Type() != CacheEntryType::VS_CONFIG || + !(entry = curr.Payload()) || + entry->version != VSConfigEntry::EXPECTED_VERSION) { + MALFORMED_DISK_CACHE; + } + + if (curr.Id() != entry->vs_config.Hash()) { + LOG_ERROR(Render_Vulkan, "Unexpected PicaVSConfig hash mismatch"); + continue; + } + + LOG_DEBUG(Render_Vulkan, "Linking {:016X}.", curr.Id()); + + auto [iter_config, new_config] = programmable_vertex_map.try_emplace(curr.Id()); + if (new_config) { + // New config entry, usually always taken unless there is duplicate entries on the cache + // for some reason. + + auto shader_it = programmable_vertex_cache.find(entry->spirv_entry_id); + if (shader_it != programmable_vertex_cache.end()) { + // The config entry uses a SPIRV entry that was already compiled (this is the usual + // path when the cache doesn't need to be re-generated). + + LOG_DEBUG(Render_Vulkan, " linked with existing SPIRV {:016X}.", + entry->spirv_entry_id); + + iter_config->second = &shader_it->second; + + if (regenerate_file) { + // In case we are re-generating the cache, we could only have gotten here if the + // SPIRV was already compiled and cached, so only cache the config. + AppendVSConfig(*regenerate_file, *entry, curr.Id()); + } + + bool new_program = known_vertex_programs.emplace(entry->program_entry_id).second; + if (new_program && regenerate_file) { + // If the vertex program is not known at this point we need to save it as well. + // This can happen to config entries that compile to the same SPIRV but use + // different program code (maybe because garbage data was in the program + // buffer). + auto program_it = pending_programs.find(entry->program_entry_id); + if (program_it == pending_programs.end()) { + // Program code not in disk cache, should never happen. + LOG_ERROR(Render_Vulkan, "Missing program code for config entry"); + programmable_vertex_map.erase(iter_config); + continue; + } + + // This is very rare so no need to use the LRU. + auto program_cache_entry = vs_cache.ReadAt(program_it->second); + const VSProgramEntry* program_entry; + + if (!program_cache_entry.Valid() || + program_cache_entry.Type() != CacheEntryType::VS_PROGRAM || + !(program_entry = program_cache_entry.Payload()) || + program_entry->version != VSProgramEntry::EXPECTED_VERSION) { + MALFORMED_DISK_CACHE; + } + + AppendVSProgram(*regenerate_file, *program_entry, entry->program_entry_id); + } + } else { + // Cached SPIRV not found, need to recompile. + + // Search program entry in a LRU first, to prevent having to read from the cache + // file on each separate config entry. + auto [found, program_lru_entry] = program_lru->request(entry->program_entry_id); + if (!found) { + LOG_DEBUG(Render_Vulkan, " reading program {:016X}.", + entry->program_entry_id); + + // Program not on the LRU, need to read it from cache file + auto program_it = pending_programs.find(entry->program_entry_id); + if (program_it == pending_programs.end()) { + // Program code not in disk cache, should never happen. + LOG_ERROR(Render_Vulkan, "Missing program code for config entry"); + programmable_vertex_map.erase(iter_config); + continue; + } + + auto program_cache_entry = vs_cache.ReadAt(program_it->second); + const VSProgramEntry* program_entry; + + if (!program_cache_entry.Valid() || + program_cache_entry.Type() != CacheEntryType::VS_PROGRAM || + !(program_entry = program_cache_entry.Payload()) || + program_entry->version != VSProgramEntry::EXPECTED_VERSION) { + MALFORMED_DISK_CACHE; + } + + program_lru_entry = *program_entry; + + bool new_program = + known_vertex_programs.emplace(entry->program_entry_id).second; + + if (new_program && regenerate_file) { + // When regenerating, only append if it's a new program entry not seen + // before. + AppendVSProgram(*regenerate_file, program_lru_entry, + entry->program_entry_id); + } + } + + // Recompile SPIRV from config and program now. + LOG_DEBUG(Render_Vulkan, " using program {:016X}.", entry->program_entry_id); + + shader_setup = std::make_unique(); + shader_setup->UpdateProgramCode(program_lru_entry.program_code, + program_lru_entry.program_len); + shader_setup->UpdateSwizzleData(program_lru_entry.swizzle_code, + program_lru_entry.swizzle_len); + shader_setup->DoProgramCodeFixup(); + + if (entry->vs_config.state.program_hash != shader_setup->GetProgramCodeHash() || + entry->vs_config.state.swizzle_hash != shader_setup->GetSwizzleDataHash()) { + LOG_ERROR(Render_Vulkan, "Unexpected ShaderSetup hash mismatch"); + programmable_vertex_map.erase(iter_config); + continue; + } + + ExtraVSConfig extra_config = parent.CalcExtraConfig(entry->vs_config); + + auto program_glsl = Common::HashableString( + GLSL::GenerateVertexShader(*shader_setup, entry->vs_config, extra_config)); + if (program_glsl.empty()) { + LOG_ERROR(Render_Vulkan, "Failed to retrieve programmable vertex shader"); + programmable_vertex_map.erase(iter_config); + continue; + } + + const u64 spirv_id = program_glsl.Hash(); + + auto [iter_prog, new_spirv] = + programmable_vertex_cache.try_emplace(spirv_id, parent.instance); + + LOG_DEBUG(Render_Vulkan, " processing SPIRV."); + + if (new_spirv) { + LOG_DEBUG(Render_Vulkan, " compiling SPIRV."); + + auto spirv = CompileGLSL(program_glsl, vk::ShaderStageFlagBits::eVertex); + + iter_prog->second.module = CompileSPV(spirv, parent.instance.GetDevice()); + iter_prog->second.MarkDone(); + + if (regenerate_file) { + // If we are regenerating, save the new spirv to disk. + AppendVSSPIRV(*regenerate_file, spirv, spirv_id); + } + } + + if (regenerate_file) { + // If we are regenerating, save the config entry to the cache. We need to make a + // copy first because it's possible the SPIRV id has changed and we need to + // adjust it. + std::unique_ptr entry_copy = + std::make_unique(*entry); + entry_copy->spirv_entry_id = spirv_id; + AppendVSConfig(*regenerate_file, *entry_copy, curr.Id()); + } + + // Asign the SPIRV shader to the config + iter_config->second = &iter_prog->second; + + LOG_DEBUG(Render_Vulkan, " linked with new SPIRV {:016X}.", + entry->spirv_entry_id); + } + } + } + + if (regenerate_file) { + // If we are regenerating, replace the old file with the new one. + vs_cache.SwitchMode(CacheFile::CacheOpMode::DELETE); + regenerate_file.reset(); + FileUtil::Rename(GetVSFile(title_id, true), GetVSFile(title_id, false)); + } + + // Switch to append mode to receive new entries. + return vs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND); +} + +bool ShaderDiskCache::InitFSCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + std::vector> pending_configs; + std::unique_ptr regenerate_file; + + auto cleanup_on_error = [&]() { + fragment_shaders.clear(); + if (regenerate_file) { + regenerate_file->SwitchMode(CacheFile::CacheOpMode::DELETE); + } + }; + + LOG_INFO(Render_Vulkan, "Loading FS disk shader cache for title {:016X}", title_id); + + fs_cache.SetFilePath(GetFSFile(title_id, false)); + + if (!fs_cache.SwitchMode(CacheFile::CacheOpMode::READ)) { + LOG_INFO(Render_Vulkan, "Missing FS disk shader cache for title {:016X}", title_id); + cleanup_on_error(); + return false; + } + + u32 tot_entries = fs_cache.GetTotalEntries(); + auto curr = fs_cache.ReadFirst(); + if (!curr.Valid() || curr.Type() != CacheEntryType::FILE_INFO) { + MALFORMED_DISK_CACHE; + } + + const FileInfoEntry* file_info = curr.Payload(); + if (!file_info || file_info->cache_magic != FileInfoEntry::CACHE_FILE_MAGIC || + file_info->file_version != FileInfoEntry::CACHE_FILE_VERSION || + file_info->file_type != CacheFileType::FS_CACHE) { + MALFORMED_DISK_CACHE; + } + + if (file_info->config_struct_hash != FSConfig::StructHash()) { + LOG_ERROR(Render_Vulkan, "Cache was created for a different FSConfig, resetting..."); + cleanup_on_error(); + return false; + } + + if (file_info->source_hash != GetSourceFileCacheVersionHash()) { + LOG_INFO(Render_Vulkan, "Cache contains old fragment program, cache needs regeneration."); + regenerate_file = std::make_unique(GetFSFile(title_id, true)); + } + + if (file_info->profile != parent.profile && !regenerate_file) { + LOG_INFO(Render_Vulkan, + "Cache has driver and user settings mismatch, cache needs regeneration."); + regenerate_file = std::make_unique(GetFSFile(title_id, true)); + } + + if (regenerate_file) { + RecreateCache(*regenerate_file, CacheFileType::FS_CACHE); + } + + CacheEntry::CacheEntryHeader curr_header = curr.Header(); + size_t curr_offset = curr.Position(); + + size_t current_callback_index = 0; + size_t tot_callback_index = tot_entries - 1; + + // Scan the entire file first, while keeping track of configs. + // SPIRV can be compiled directly, if a config has a missing + // SPIRV entry it can be regenerated later. + for (int i = 1; i < tot_entries; i++) { + if (stop_loading) { + cleanup_on_error(); + return true; + } + + std::tie(curr_offset, curr_header) = fs_cache.ReadNextHeader(curr_header, curr_offset); + + if (!curr_header.Valid()) { + MALFORMED_DISK_CACHE; + } + + LOG_DEBUG(Render_Vulkan, "Processing ID: {:016X} (type {})", curr_header.Id(), + curr_header.Type()); + + if (curr_header.Type() == CacheEntryType::FS_CONFIG) { + pending_configs.push_back({curr_header.Id(), curr_offset}); + } else if (curr_header.Type() == CacheEntryType::FS_SPIRV) { + + // Only use SPIRV entries if we are not regenerating the cache, as the driver or + // user settings do not match, which could lead to different SPIRV. + // These will be regenerated from the cached config later. + if (!regenerate_file) { + LOG_DEBUG(Render_Vulkan, " processing SPIRV."); + + curr = fs_cache.ReadAt(curr_offset); + if (!curr.Valid() || curr.Type() != CacheEntryType::FS_SPIRV) { + MALFORMED_DISK_CACHE; + } + + const u8* spirv_data = curr.Data().data(); + const size_t spirv_size = curr.Data().size(); + + auto [iter_spirv, new_program] = + fragment_shaders.try_emplace(curr.Id(), parent.instance); + if (new_program) { + LOG_DEBUG(Render_Vulkan, " compiling SPIRV."); + + const auto spirv = std::span( + reinterpret_cast(spirv_data), spirv_size / sizeof(u32)); + + iter_spirv->second.module = CompileSPV(spirv, parent.instance.GetDevice()); + iter_spirv->second.MarkDone(); + + if (!iter_spirv->second.module) { + // Compilation failed for some reason, remove from cache to let it + // be regenerated at runtime or during config processing. + LOG_ERROR(Render_Vulkan, "Unexpected program compilation failure"); + fragment_shaders.erase(iter_spirv); + } + } + } + + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Fragment Shader"); + } + } else { + MALFORMED_DISK_CACHE; + } + } + + // Once we have all the shader instances created from SPIRV, we can link them to the FS configs. + LOG_DEBUG(Render_Vulkan, "Linking with config entries."); + + for (auto& offset : pending_configs) { + if (stop_loading) { + cleanup_on_error(); + return true; + } + + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Fragment Shader"); + } + + LOG_DEBUG(Render_Vulkan, "Linking {:016X}.", curr.Id()); + + if (fragment_shaders.find(offset.first) != fragment_shaders.end()) { + // SPIRV of config was already compiled, no need to regenerate + // it from the cache. This can only happen if we are not regenerating + // the cache. + LOG_DEBUG(Render_Vulkan, " linked with existing SPIRV."); + continue; + } + + // Cached SPIRV not found, need to recompile. Should only happen if + // we are regenerating the cache. + + curr = fs_cache.ReadAt(offset.second); + const FSConfigEntry* entry; + + if (!curr.Valid() || curr.Type() != CacheEntryType::FS_CONFIG || + !(entry = curr.Payload()) || + entry->version != FSConfigEntry::EXPECTED_VERSION) { + MALFORMED_DISK_CACHE; + } + + const auto fs_config_hash = entry->fs_config.Hash(); + if (curr.Id() != fs_config_hash) { + LOG_ERROR(Render_Vulkan, "Unexpected FSConfig hash mismatch"); + continue; + } + + const auto [it, new_shader] = fragment_shaders.try_emplace(fs_config_hash, parent.instance); + auto& shader = it->second; + + std::vector spirv; + if (parent.profile.vk_use_spirv_generator && + !entry->fs_config.UsesSpirvIncompatibleConfig()) { + // Use SPIRV generator directly + + spirv = SPIRV::GenerateFragmentShader(entry->fs_config, parent.profile); + shader.module = CompileSPV(spirv, parent.instance.GetDevice()); + } else { + // Use GLSL generator then convert to SPIRV + + UserConfig user{}; + const std::string code_glsl = + GLSL::GenerateFragmentShader(entry->fs_config, user, parent.profile); + + if (code_glsl.empty()) { + LOG_ERROR(Render_Vulkan, "Failed to retrieve programmable vertex shader"); + fragment_shaders.erase(it); + continue; + } + + spirv = CompileGLSL(code_glsl, vk::ShaderStageFlagBits::eFragment); + shader.module = CompileSPV(spirv, parent.instance.GetDevice()); + } + shader.MarkDone(); + + if (regenerate_file) { + // Append the config and SPIRV to the new file. + AppendFSSPIRV(*regenerate_file, spirv, fs_config_hash); + AppendFSConfig(*regenerate_file, *entry, fs_config_hash); + } + + LOG_DEBUG(Render_Vulkan, " linked with new SPIRV."); + } + + if (regenerate_file) { + // If we are regenerating, replace the old file with the new one. + fs_cache.SwitchMode(CacheFile::CacheOpMode::DELETE); + regenerate_file.reset(); + FileUtil::Rename(GetFSFile(title_id, true), GetFSFile(title_id, false)); + } + + // Switch to append mode to receive new entries. + return fs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND); +} + +bool ShaderDiskCache::InitGSCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + std::vector> pending_configs; + std::unique_ptr regenerate_file; + + auto cleanup_on_error = [&]() { + fixed_geometry_shaders.clear(); + if (regenerate_file) { + regenerate_file->SwitchMode(CacheFile::CacheOpMode::DELETE); + } + }; + + LOG_INFO(Render_Vulkan, "Loading GS disk shader cache for title {:016X}", title_id); + + gs_cache.SetFilePath(GetGSFile(title_id, false)); + + if (!gs_cache.SwitchMode(CacheFile::CacheOpMode::READ)) { + LOG_INFO(Render_Vulkan, "Missing GS disk shader cache for title {:016X}", title_id); + cleanup_on_error(); + return false; + } + + u32 tot_entries = gs_cache.GetTotalEntries(); + auto curr = gs_cache.ReadFirst(); + if (!curr.Valid() || curr.Type() != CacheEntryType::FILE_INFO) { + MALFORMED_DISK_CACHE; + } + + const FileInfoEntry* file_info = curr.Payload(); + if (!file_info || file_info->cache_magic != FileInfoEntry::CACHE_FILE_MAGIC || + file_info->file_version != FileInfoEntry::CACHE_FILE_VERSION || + file_info->file_type != CacheFileType::GS_CACHE) { + MALFORMED_DISK_CACHE; + } + + if (file_info->config_struct_hash != PicaGSConfigState::StructHash()) { + LOG_ERROR(Render_Vulkan, + "Cache was created for a different PicaGSConfigState, resetting..."); + cleanup_on_error(); + return false; + } + + // There is no need to load geometry shaders if we don't support them. + // We can just load the known IDs and skip SPIRV and cache regeneration. + const auto geo_shaders_needed = parent.instance.UseGeometryShaders() && + !parent.instance.IsFragmentShaderBarycentricSupported(); + + if (geo_shaders_needed && file_info->source_hash != GetSourceFileCacheVersionHash()) { + LOG_INFO(Render_Vulkan, "Cache contains old fragment program, cache needs regeneration."); + regenerate_file = std::make_unique(GetGSFile(title_id, true)); + } + + if (geo_shaders_needed && file_info->profile != parent.profile && !regenerate_file) { + LOG_INFO(Render_Vulkan, + "Cache has driver and user settings mismatch, cache needs regeneration."); + regenerate_file = std::make_unique(GetGSFile(title_id, true)); + } + + if (regenerate_file) { + RecreateCache(*regenerate_file, CacheFileType::GS_CACHE); + } + + CacheEntry::CacheEntryHeader curr_header = curr.Header(); + size_t curr_offset = curr.Position(); + + size_t current_callback_index = 0; + size_t tot_callback_index = tot_entries - 1; + + // Scan the entire file first, while keeping track of configs. + // SPIRV can be compiled directly, if a config has a missing + // SPIRV entry it can be regenerated later. + for (int i = 1; i < tot_entries; i++) { + if (stop_loading) { + cleanup_on_error(); + return true; + } + + std::tie(curr_offset, curr_header) = gs_cache.ReadNextHeader(curr_header, curr_offset); + + if (!curr_header.Valid()) { + MALFORMED_DISK_CACHE; + } + + LOG_DEBUG(Render_Vulkan, "Processing ID: {:016X} (type {})", curr_header.Id(), + curr_header.Type()); + + if (curr_header.Type() == CacheEntryType::GS_CONFIG) { + if (geo_shaders_needed) { + pending_configs.push_back({curr_header.Id(), curr_offset}); + } else { + known_geometry_shaders.emplace(curr_header.Id()); + + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Geometry Shader"); + } + } + } else if (curr_header.Type() == CacheEntryType::GS_SPIRV) { + + // Only use SPIRV entries if we are not regenerating the cache, as the driver or + // user settings do not match, which could lead to different SPIRV. + // These will be regenerated from the cached config later. + // Also, only use SPIRV entries if we support geometry shaders on this device. + if (geo_shaders_needed && !regenerate_file) { + LOG_DEBUG(Render_Vulkan, " processing SPIRV."); + + curr = gs_cache.ReadAt(curr_offset); + if (!curr.Valid() || curr.Type() != CacheEntryType::GS_SPIRV) { + MALFORMED_DISK_CACHE; + } + + const u8* spirv_data = curr.Data().data(); + const size_t spirv_size = curr.Data().size(); + + auto [iter_spirv, new_program] = + fixed_geometry_shaders.try_emplace(curr.Id(), parent.instance); + if (new_program) { + LOG_DEBUG(Render_Vulkan, " compiling SPIRV."); + + const auto spirv = std::span( + reinterpret_cast(spirv_data), spirv_size / sizeof(u32)); + + iter_spirv->second.module = CompileSPV(spirv, parent.instance.GetDevice()); + iter_spirv->second.MarkDone(); + + if (!iter_spirv->second.module) { + // Compilation failed for some reason, remove from cache to let it + // be regenerated at runtime or during config processing. + LOG_ERROR(Render_Vulkan, "Unexpected program compilation failure"); + fixed_geometry_shaders.erase(iter_spirv); + } + } + } + + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Geometry Shader"); + } + } else { + MALFORMED_DISK_CACHE; + } + } + + // Once we have all the shader instances created from SPIRV, we can link them to the FS configs. + LOG_DEBUG(Render_Vulkan, "Linking with config entries."); + + for (auto& offset : pending_configs) { + if (stop_loading) { + cleanup_on_error(); + return true; + } + + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Geometry Shader"); + } + + LOG_DEBUG(Render_Vulkan, "Linking {:016X}.", curr.Id()); + + if (fixed_geometry_shaders.find(offset.first) != fixed_geometry_shaders.end()) { + // SPIRV of config was already compiled, no need to regenerate + // it from the cache. This can only happen if we are not regenerating + // the cache. + LOG_DEBUG(Render_Vulkan, " linked with existing SPIRV."); + continue; + } + + // Cached SPIRV not found, need to recompile. Should only happen if + // we are regenerating the cache. + + curr = gs_cache.ReadAt(offset.second); + const GSConfigEntry* entry; + + if (!curr.Valid() || curr.Type() != CacheEntryType::GS_CONFIG || + !(entry = curr.Payload()) || + entry->version != GSConfigEntry::EXPECTED_VERSION) { + MALFORMED_DISK_CACHE; + } + + const auto gs_config_hash = entry->gs_config.Hash(); + if (curr.Id() != gs_config_hash) { + LOG_ERROR(Render_Vulkan, "Unexpected PicaGSConfigState hash mismatch"); + continue; + } + + const auto [it, new_shader] = + fixed_geometry_shaders.try_emplace(gs_config_hash, parent.instance); + auto& shader = it->second; + + std::vector spirv; + ExtraFixedGSConfig extra; + extra.use_clip_planes = parent.profile.has_clip_planes; + extra.separable_shader = true; + + const auto code_glsl = GLSL::GenerateFixedGeometryShader(entry->gs_config, extra); + + if (code_glsl.empty()) { + LOG_ERROR(Render_Vulkan, "Failed to retrieve fixed geometry shader"); + fixed_geometry_shaders.erase(it); + continue; + } + + spirv = CompileGLSL(code_glsl, vk::ShaderStageFlagBits::eGeometry); + shader.module = CompileSPV(spirv, parent.instance.GetDevice()); + shader.MarkDone(); + + if (regenerate_file) { + // Append the config and SPIRV to the new file. + AppendGSSPIRV(*regenerate_file, spirv, gs_config_hash); + AppendGSConfig(*regenerate_file, *entry, gs_config_hash); + } + + LOG_DEBUG(Render_Vulkan, " linked with new SPIRV."); + } + + if (regenerate_file) { + // If we are regenerating, replace the old file with the new one. + gs_cache.SwitchMode(CacheFile::CacheOpMode::DELETE); + regenerate_file.reset(); + FileUtil::Rename(GetGSFile(title_id, true), GetGSFile(title_id, false)); + } + + // Switch to append mode to receive new entries. + return gs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND); +} + +bool ShaderDiskCache::InitPLCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + + auto cleanup_on_error = [&]() { graphics_pipelines.clear(); }; + + LOG_INFO(Render_Vulkan, "Loading PL disk shader cache for title {:016X}", title_id); + + pl_cache.SetFilePath(GetPLFile(title_id, false)); + + if (!pl_cache.SwitchMode(CacheFile::CacheOpMode::READ)) { + LOG_INFO(Render_Vulkan, "Missing PL disk shader cache for title {:016X}", title_id); + cleanup_on_error(); + return false; + } + + u32 tot_entries = pl_cache.GetTotalEntries(); + auto curr = pl_cache.ReadFirst(); + if (!curr.Valid() || curr.Type() != CacheEntryType::FILE_INFO) { + MALFORMED_DISK_CACHE; + } + + const FileInfoEntry* file_info = curr.Payload(); + if (!file_info || file_info->cache_magic != FileInfoEntry::CACHE_FILE_MAGIC || + file_info->file_version != FileInfoEntry::CACHE_FILE_VERSION || + file_info->file_type != CacheFileType::PL_CACHE) { + MALFORMED_DISK_CACHE; + } + + if (file_info->config_struct_hash != StaticPipelineInfo::StructHash()) { + LOG_ERROR(Render_Vulkan, + "Cache was created for a different StaticPipelineInfo, resetting..."); + cleanup_on_error(); + return false; + } + + size_t current_callback_index = 0; + size_t tot_callback_index = tot_entries - 1; + + // There is only one entry type in the pipeline info cache, + // no need to keep track of anything. + for (int i = 1; i < tot_entries; i++) { + if (stop_loading) { + cleanup_on_error(); + return true; + } + + curr = pl_cache.ReadNext(curr); + + if (!curr.Valid()) { + MALFORMED_DISK_CACHE; + } + + LOG_DEBUG(Render_Vulkan, "Processing ID: {:016X} (type {})", curr.Id(), curr.Type()); + + if (curr.Type() == CacheEntryType::PL_CONFIG) { + + const PLConfigEntry* entry; + + if (!(entry = curr.Payload()) || + entry->version != PLConfigEntry::EXPECTED_VERSION) { + MALFORMED_DISK_CACHE; + } + + if (callback) { + callback(VideoCore::LoadCallbackStage::Build, current_callback_index++, + tot_callback_index, "Pipeline"); + } + + known_graphic_pipelines.emplace(curr.Id()); + auto pl_hash_opt = entry->pl_info.OptimizedHash(parent.instance); + + if (graphics_pipelines.find(pl_hash_opt) != graphics_pipelines.end()) { + // Multiple entries can have the same optimized hash. Skip if that's the case. + LOG_DEBUG(Render_Vulkan, " skipping.", curr.Id()); + continue; + } + + // Fetch all the shaders used in the pipeline, + // if any is missing we cannot build it. + std::array shaders; + + if (entry->pl_info.shader_ids[ProgramType::VS]) { + auto it_vs = + programmable_vertex_map.find(entry->pl_info.shader_ids[ProgramType::VS]); + if (it_vs == programmable_vertex_map.end()) { + LOG_ERROR(Render_Vulkan, "Missing vertex shader {:016X} for pipeline {:016X}", + entry->pl_info.shader_ids[ProgramType::VS], curr.Id()); + continue; + } + shaders[ProgramType::VS] = it_vs->second; + } else { + shaders[ProgramType::VS] = &parent.trivial_vertex_shader; + } + + auto it_fs = fragment_shaders.find(entry->pl_info.shader_ids[ProgramType::FS]); + if (it_fs == fragment_shaders.end()) { + LOG_ERROR(Render_Vulkan, "Missing fragment shader {:016X} for pipeline {:016X}", + entry->pl_info.shader_ids[ProgramType::FS], curr.Id()); + continue; + } + shaders[ProgramType::FS] = &it_fs->second; + + if (parent.instance.UseGeometryShaders() && + !parent.instance.IsFragmentShaderBarycentricSupported() && + entry->pl_info.shader_ids[ProgramType::GS]) { + auto it_gs = + fixed_geometry_shaders.find(entry->pl_info.shader_ids[ProgramType::GS]); + if (it_gs == fixed_geometry_shaders.end()) { + LOG_ERROR(Render_Vulkan, "Missing geometry shader {:016X} for pipeline {:016X}", + entry->pl_info.shader_ids[ProgramType::GS], curr.Id()); + continue; + } + shaders[ProgramType::GS] = &it_gs->second; + } else { + shaders[ProgramType::GS] = nullptr; + } + + // Build the pipeline using the cached pipeline info. + // The dynamic state can be left default initialized. + PipelineInfo info{}; + info.state = entry->pl_info; + + auto [it_pl, _] = graphics_pipelines.try_emplace(pl_hash_opt); + it_pl.value() = std::make_unique( + parent.instance, parent.renderpass_cache, info, *parent.driver_pipeline_cache, + *parent.pipeline_layout, shaders, &parent.workers); + + it_pl.value()->TryBuild(false); + + LOG_DEBUG(Render_Vulkan, " built."); + + } else { + MALFORMED_DISK_CACHE; + } + } + + // Switch to append mode to receive new entries. + return pl_cache.SwitchMode(CacheFile::CacheOpMode::APPEND); +} + +void ShaderDiskCache::AppendVSConfigProgram(CacheFile& file, + const Pica::Shader::Generator::PicaVSConfig& config, + const Pica::ShaderSetup& setup, u64 config_id, + u64 spirv_id) { + + VSConfigEntry entry; + entry.version = VSConfigEntry::EXPECTED_VERSION; + entry.vs_config = config; + entry.spirv_entry_id = spirv_id; + entry.program_entry_id = + Common::HashCombine(config.state.program_hash, config.state.swizzle_hash); + + bool new_entry = known_vertex_programs.emplace(entry.program_entry_id).second; + if (new_entry) { + std::unique_ptr prog_entry = std::make_unique(); + prog_entry->version = VSProgramEntry::EXPECTED_VERSION; + prog_entry->program_len = setup.GetBiggestProgramSize(); + prog_entry->program_code = setup.GetProgramCode(); + prog_entry->swizzle_len = setup.GetBiggestSwizzleSize(); + prog_entry->swizzle_code = setup.GetSwizzleData(); + + AppendVSProgram(file, *prog_entry, entry.program_entry_id); + } + + AppendVSConfig(file, entry, config_id); +} + +void ShaderDiskCache::AppendVSProgram(CacheFile& file, const VSProgramEntry& entry, + u64 program_id) { + file.Append(CacheEntryType::VS_PROGRAM, program_id, entry, true); +} + +void ShaderDiskCache::AppendVSConfig(CacheFile& file, const VSConfigEntry& entry, u64 config_id) { + file.Append(CacheEntryType::VS_CONFIG, config_id, entry, true); +} + +void ShaderDiskCache::AppendVSSPIRV(CacheFile& file, std::span program, u64 program_id) { + file.Append(CacheEntryType::VS_SPIRV, program_id, + {reinterpret_cast(program.data()), program.size() * sizeof(u32)}, true); +} + +void ShaderDiskCache::AppendFSConfig(CacheFile& file, const FSConfigEntry& entry, u64 config_id) { + file.Append(CacheEntryType::FS_CONFIG, config_id, entry, true); +} + +void ShaderDiskCache::AppendFSSPIRV(CacheFile& file, std::span program, u64 program_id) { + file.Append(CacheEntryType::FS_SPIRV, program_id, + {reinterpret_cast(program.data()), program.size() * sizeof(u32)}, true); +} + +void ShaderDiskCache::AppendGSConfig(CacheFile& file, const GSConfigEntry& entry, u64 config_id) { + file.Append(CacheEntryType::GS_CONFIG, config_id, entry, true); +} + +void ShaderDiskCache::AppendGSSPIRV(CacheFile& file, std::span program, u64 program_id) { + file.Append(CacheEntryType::GS_SPIRV, program_id, + {reinterpret_cast(program.data()), program.size() * sizeof(u32)}, true); +} + +void ShaderDiskCache::AppendPLConfig(CacheFile& file, const PLConfigEntry& entry, u64 config_id) { + file.Append(CacheEntryType::PL_CONFIG, config_id, entry, true); +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_shader_disk_cache.h b/src/video_core/renderer_vulkan/vk_shader_disk_cache.h new file mode 100644 index 000000000..d6b487f18 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_shader_disk_cache.h @@ -0,0 +1,352 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "common/common_types.h" +#include "common/file_util.h" +#include "common/thread_worker.h" +#include "video_core/pica/shader_setup.h" +#include "video_core/rasterizer_interface.h" +#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" +#include "video_core/renderer_vulkan/vk_instance.h" +#include "video_core/shader/generator/pica_fs_config.h" +#include "video_core/shader/generator/profile.h" +#include "video_core/shader/generator/shader_gen.h" + +namespace Vulkan { + +class PipelineCache; + +class ShaderDiskCache { +public: + ShaderDiskCache(PipelineCache& _parent, u64 _title_id) : parent(_parent), title_id(_title_id) {} + + void Init(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback); + + std::optional> UseProgrammableVertexShader( + const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, const VertexLayout& layout); + std::optional> UseFragmentShader( + const Pica::RegsInternal& regs, const Pica::Shader::UserConfig& user); + std::optional> UseFixedGeometryShader( + const Pica::RegsInternal& regs); + + GraphicsPipeline* GetPipeline(const PipelineInfo& info); + + u64 GetProgramID() const { + return title_id; + } + +private: + static constexpr std::size_t SOURCE_FILE_HASH_LENGTH = 64; + using SourceFileCacheVersionHash = std::array; + + static SourceFileCacheVersionHash GetSourceFileCacheVersionHash(); + + enum class CacheFileType : u32 { + VS_CACHE = 0, + FS_CACHE = 1, + GS_CACHE = 2, + PL_CACHE = 3, + + MAX, + }; + + enum class CacheEntryType : u16 { + // Common + FILE_INFO = 0, + + // VS_CACHE + VS_CONFIG = 1, + VS_PROGRAM = 2, + VS_SPIRV = 3, + + // FS_CACHE + FS_CONFIG = 4, + FS_SPIRV = 5, + + // GS_CACHE + GS_CONFIG = 6, + GS_SPIRV = 7, + + // PL_CACHE + PL_CONFIG = 8, + + MAX, + }; + + struct FileInfoEntry { + static constexpr u32 CACHE_FILE_MAGIC = 0x48434B56; + static constexpr u32 CACHE_FILE_VERSION = 0; + + u32_le cache_magic; + u32 file_version; + u64 config_struct_hash; + CacheFileType file_type; + SourceFileCacheVersionHash source_hash; + std::array build_name; + + union { + u8 reserved[0x400]; + Pica::Shader::Profile profile; + }; + }; + static_assert(sizeof(FileInfoEntry) == 1144); + + struct VSConfigEntry { + static constexpr u8 EXPECTED_VERSION = 0; + + u8 version; // Surprise tool that can help us later + u64 program_entry_id; + u64 spirv_entry_id; + Pica::Shader::Generator::PicaVSConfig vs_config; + }; + static_assert(sizeof(VSConfigEntry) == 216); + + struct VSProgramEntry { + static constexpr u8 EXPECTED_VERSION = 0; + + u8 version; // Surprise tool that can help us later + u32 program_len; + u32 swizzle_len; + Pica::ProgramCode program_code; + Pica::SwizzleData swizzle_code; + }; + static_assert(sizeof(VSProgramEntry) == 32780); + + struct FSConfigEntry { + static constexpr u8 EXPECTED_VERSION = 0; + + u8 version; // Surprise tool that can help us later + Pica::Shader::FSConfig fs_config; + }; + static_assert(sizeof(FSConfigEntry) == 276); + + struct GSConfigEntry { + static constexpr u8 EXPECTED_VERSION = 0; + + u8 version; // Surprise tool that can help us later + Pica::Shader::Generator::PicaFixedGSConfig gs_config; + }; + static_assert(sizeof(GSConfigEntry) == 44); + + struct PLConfigEntry { + static constexpr u8 EXPECTED_VERSION = 0; + + u8 version; // Surprise tool that can help us later + StaticPipelineInfo pl_info; + }; + static_assert(sizeof(PLConfigEntry) == 152); + + class CacheFile; + class CacheEntry { + public: + static constexpr u32 MAX_ENTRY_SIZE = 4 * 1024 * 1024; + + struct CacheEntryFooter { + static constexpr u8 ENTRY_VERSION = 0x24; + union { + u32 first_word{}; + + BitField<0, 8, u32> version; + BitField<8, 24, u32> entry_id; + }; + u32 entry_size{}; + u64 reserved{}; + }; + static_assert(sizeof(CacheEntryFooter) == 0x10); + + struct CacheEntryHeader { + static constexpr u8 ENTRY_VERSION = 0x42; + u8 entry_version{}; + union { + u8 flags{}; + + BitField<0, 1, u8> zstd_compressed; + BitField<1, 7, u8> reserved; + }; + CacheEntryType type{}; + u32 entry_size{}; + u64 id{}; + + CacheEntryType Type() const { + return type; + } + + u64 Id() const { + return id; + } + + bool Valid() { + constexpr u32 headers_size = + sizeof(CacheEntry::CacheEntryHeader) + sizeof(CacheEntry::CacheEntryFooter); + + return entry_version == ENTRY_VERSION && type < CacheEntryType::MAX && + entry_size < CacheEntry::MAX_ENTRY_SIZE && entry_size >= headers_size; + } + }; + static_assert(sizeof(CacheEntryHeader) == 0x10); + + bool Valid() const { + return valid; + } + + CacheEntryType Type() const { + return header.Type(); + } + + u64 Id() const { + return header.Id(); + } + + const std::span Data() const { + return data; + } + + template + const T* Payload() const { + if (data.size() != sizeof(T)) { + return nullptr; + } + + return reinterpret_cast(data.data()); + } + + size_t Position() const { + return position; + } + + const CacheEntryHeader& Header() const { + return header; + } + + private: + friend CacheFile; + + CacheEntry() = default; + + CacheEntryHeader header{}; + + size_t position = SIZE_MAX; + bool valid = false; + std::vector data{}; + }; + + class CacheFile { + public: + enum class CacheOpMode { + NONE = 0, + READ, + APPEND, + DELETE, + RECREATE, + }; + + CacheFile() = default; + CacheFile(const std::string& _filepath) : filepath(_filepath) {} + ~CacheFile() { + append_worker.WaitForRequests(); + } + + void SetFilePath(const std::string& path) { + filepath = path; + } + + CacheEntry ReadFirst(); + CacheEntry ReadNext(const CacheEntry& previous); + + CacheEntry ReadAt(size_t position); + + std::pair ReadNextHeader( + const ShaderDiskCache::CacheEntry::CacheEntryHeader& previous, + size_t previous_position); + + CacheEntry::CacheEntryHeader ReadAtHeader(size_t position); + + size_t GetTotalEntries(); + + template + void Append(CacheEntryType type, u64 id, const T& object, bool compress) { + static_assert(std::is_trivially_copyable_v); + + auto bytes = std::as_bytes(std::span{&object, 1}); + auto u8_span = + std::span(reinterpret_cast(bytes.data()), bytes.size()); + Append(type, id, u8_span, compress); + } + + void Append(CacheEntryType type, u64 id, std::span data, bool compress); + + bool SwitchMode(CacheOpMode mode); + + private: + CacheOpMode curr_mode = CacheOpMode::NONE; + std::string filepath; + FileUtil::IOFile file{}; + std::atomic next_entry_id = SIZE_MAX; + Common::ThreadWorker append_worker{1, "Disk Shader Cache Append Worker"}; + }; + + std::string GetVSFile(u64 title_id, bool is_temp) const; + std::string GetFSFile(u64 title_id, bool is_temp) const; + std::string GetGSFile(u64 title_id, bool is_temp) const; + std::string GetPLFile(u64 title_id, bool is_temp) const; + + bool RecreateCache(CacheFile& file, CacheFileType type); + + bool InitVSCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback); + + bool InitFSCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback); + + bool InitGSCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback); + + bool InitPLCache(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback); + + void AppendVSConfigProgram(CacheFile& file, const Pica::Shader::Generator::PicaVSConfig& config, + const Pica::ShaderSetup& setup, u64 config_id, u64 program_id); + void AppendVSProgram(CacheFile& file, const VSProgramEntry& entry, u64 program_id); + void AppendVSConfig(CacheFile& file, const VSConfigEntry& entry, u64 config_id); + void AppendVSSPIRV(CacheFile& file, std::span program, u64 program_id); + + void AppendFSConfig(CacheFile& file, const FSConfigEntry& entry, u64 config_id); + void AppendFSSPIRV(CacheFile& file, std::span program, u64 program_id); + + void AppendGSConfig(CacheFile& file, const GSConfigEntry& entry, u64 config_id); + void AppendGSSPIRV(CacheFile& file, std::span program, u64 program_id); + + void AppendPLConfig(CacheFile& file, const PLConfigEntry& entry, u64 config_id); + + CacheFile vs_cache; + CacheFile fs_cache; + CacheFile gs_cache; + CacheFile pl_cache; + + PipelineCache& parent; + u64 title_id; + + std::unordered_map programmable_vertex_cache; + std::unordered_map programmable_vertex_map; + std::unordered_set known_vertex_programs; + + std::unordered_map fragment_shaders; + + std::unordered_map fixed_geometry_shaders; + std::unordered_set known_geometry_shaders; + + tsl::robin_map, Common::IdentityHash> + graphics_pipelines; + std::unordered_set known_graphic_pipelines; +}; + +} // namespace Vulkan \ No newline at end of file diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp index ee3db73de..1a5a71827 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp @@ -160,8 +160,8 @@ bool InitializeCompiler() { } } // Anonymous namespace -vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, vk::Device device, - std::string_view premable) { +std::vector CompileGLSL(std::string_view code, vk::ShaderStageFlagBits stage, + std::string_view premable) { if (!InitializeCompiler()) { return {}; } @@ -217,7 +217,7 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v LOG_INFO(Render_Vulkan, "SPIR-V conversion messages: {}", spv_messages); } - return CompileSPV(out_code, device); + return out_code; } vk::ShaderModule CompileSPV(std::span code, vk::Device device) { @@ -229,10 +229,15 @@ vk::ShaderModule CompileSPV(std::span code, vk::Device device) { try { return device.createShaderModule(shader_info); } catch (vk::SystemError& err) { - UNREACHABLE_MSG("{}", err.what()); + LOG_ERROR(Render_Vulkan, "{}", err.what()); } return {}; } +vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, vk::Device device, + std::string_view premable) { + return CompileSPV(CompileGLSL(code, stage, premable), device); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_shader_util.h b/src/video_core/renderer_vulkan/vk_shader_util.h index cb91aedf8..91fe9709d 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.h +++ b/src/video_core/renderer_vulkan/vk_shader_util.h @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -14,10 +14,9 @@ namespace Vulkan { * @brief Creates a vulkan shader module from GLSL by converting it to SPIR-V using glslang. * @param code The string containing GLSL code. * @param stage The pipeline stage the shader will be used in. - * @param device The vulkan device handle. */ -vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, vk::Device device, - std::string_view premable = ""); +std::vector CompileGLSL(std::string_view code, vk::ShaderStageFlagBits stage, + std::string_view premable = ""); /** * @brief Creates a vulkan shader module from SPIR-V bytecode. @@ -26,4 +25,7 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v */ vk::ShaderModule CompileSPV(std::span code, vk::Device device); +vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, vk::Device device, + std::string_view premable = ""); + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index ac5340653..56e4cf429 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -161,7 +161,7 @@ void Swapchain::FindPresentFormat() { void Swapchain::SetPresentMode() { const auto modes = instance.GetPhysicalDevice().getSurfacePresentModesKHR(surface); - const bool use_vsync = Settings::values.use_vsync_new.GetValue(); + const bool use_vsync = Settings::values.use_vsync.GetValue(); const auto find_mode = [&modes](vk::PresentModeKHR requested) { const auto it = std::find_if(modes.begin(), modes.end(), diff --git a/src/video_core/shader/generator/glsl_fs_shader_gen.cpp b/src/video_core/shader/generator/glsl_fs_shader_gen.cpp index 96be02d05..7d7ae63bb 100644 --- a/src/video_core/shader/generator/glsl_fs_shader_gen.cpp +++ b/src/video_core/shader/generator/glsl_fs_shader_gen.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -101,8 +101,10 @@ layout (binding = 2, std140) uniform fs_data { }; )"; -FragmentModule::FragmentModule(const FSConfig& config_, const Profile& profile_) - : config{config_}, profile{profile_} { +FragmentModule::FragmentModule(const FSConfig& config_, const UserConfig& user_, + const Profile& profile_) + : config{config_}, user{user_}, profile{profile_} { + config.ApplyProfile(profile_); out.reserve(RESERVE_SIZE); DefineExtensions(); DefineInterface(); @@ -172,6 +174,7 @@ vec4 secondary_fragment_color = vec4(0.0); break; case TexturingRegs::FogMode::Gas: WriteGas(); + // Return early due to unimplemented gas mode return out; default: break; @@ -503,7 +506,7 @@ void FragmentModule::WriteLighting() { return fmt::format("2.0 * (sampleTexUnit{}()).rgb - 1.0", lighting.bump_selector.Value()); }; - if (config.user.use_custom_normal) { + if (user.use_custom_normal) { const auto texel = fmt::format("2.0 * (texture(tex_normal, texcoord0)).rgb - 1.0"); out += fmt::format("vec3 surface_normal = {};\n", texel); out += "vec3 surface_tangent = vec3(1.0, 0.0, 0.0);\n"; @@ -664,7 +667,7 @@ void FragmentModule::WriteLighting() { const std::string value = get_lut_value(LightingRegs::SpotlightAttenuationSampler(light_config.num), light_config.num, lighting.lut_sp.type, lighting.lut_sp.abs_input); - spot_atten = fmt::format("({:#} * {})", lighting.lut_sp.scale, value); + spot_atten = fmt::format("({:#} * {})", lighting.lut_sp.GetScale(), value); } // If enabled, compute distance attenuation value @@ -692,7 +695,7 @@ void FragmentModule::WriteLighting() { const std::string value = get_lut_value(LightingRegs::LightingSampler::Distribution0, light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); - d0_lut_value = fmt::format("({:#} * {})", lighting.lut_d0.scale, value); + d0_lut_value = fmt::format("({:#} * {})", lighting.lut_d0.GetScale(), value); } std::string specular_0 = fmt::format("({} * {}.specular_0)", d0_lut_value, light_src); if (light_config.geometric_factor_0) { @@ -706,7 +709,7 @@ void FragmentModule::WriteLighting() { std::string value = get_lut_value(LightingRegs::LightingSampler::ReflectRed, light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); - value = fmt::format("({:#} * {})", lighting.lut_rr.scale, value); + value = fmt::format("({:#} * {})", lighting.lut_rr.GetScale(), value); out += fmt::format("refl_value.r = {};\n", value); } else { out += "refl_value.r = 1.0;\n"; @@ -719,7 +722,7 @@ void FragmentModule::WriteLighting() { std::string value = get_lut_value(LightingRegs::LightingSampler::ReflectGreen, light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); - value = fmt::format("({:#} * {})", lighting.lut_rg.scale, value); + value = fmt::format("({:#} * {})", lighting.lut_rg.GetScale(), value); out += fmt::format("refl_value.g = {};\n", value); } else { out += "refl_value.g = refl_value.r;\n"; @@ -732,7 +735,7 @@ void FragmentModule::WriteLighting() { std::string value = get_lut_value(LightingRegs::LightingSampler::ReflectBlue, light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); - value = fmt::format("({:#} * {})", lighting.lut_rb.scale, value); + value = fmt::format("({:#} * {})", lighting.lut_rb.GetScale(), value); out += fmt::format("refl_value.b = {};\n", value); } else { out += "refl_value.b = refl_value.r;\n"; @@ -747,7 +750,7 @@ void FragmentModule::WriteLighting() { const std::string value = get_lut_value(LightingRegs::LightingSampler::Distribution1, light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); - d1_lut_value = fmt::format("({:#} * {})", lighting.lut_d1.scale, value); + d1_lut_value = fmt::format("({:#} * {})", lighting.lut_d1.GetScale(), value); } std::string specular_1 = fmt::format("({} * refl_value * {}.specular_1)", d1_lut_value, light_src); @@ -764,7 +767,7 @@ void FragmentModule::WriteLighting() { std::string value = get_lut_value(LightingRegs::LightingSampler::Fresnel, light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); - value = fmt::format("({:#} * {})", lighting.lut_fr.scale, value); + value = fmt::format("({:#} * {})", lighting.lut_fr.GetScale(), value); // Enabled for diffuse lighting alpha component if (lighting.enable_primary_alpha) { @@ -832,7 +835,10 @@ void FragmentModule::WriteFog() { void FragmentModule::WriteGas() { // TODO: Implement me LOG_CRITICAL(Render, "Unimplemented gas mode"); - out += "discard; }"; + // Replace the output color with a transparent pixel, + // (just discarding the pixel causes graphical issues + // in some MH games). + out += "color = vec4(0.0); }"; } void FragmentModule::WriteShadow() { @@ -1307,7 +1313,7 @@ void FragmentModule::DefineBindingsVK() { if (config.framebuffer.shadow_rendering) { out += "layout(set = 2, binding = 0, r32ui) uniform uimage2D shadow_buffer;\n\n"; } - if (config.user.use_custom_normal) { + if (user.use_custom_normal) { out += "layout(set = 2, binding = 1) uniform sampler2D tex_normal;\n"; } } @@ -1328,7 +1334,7 @@ void FragmentModule::DefineBindingsGL() { } // Utility textures - if (config.user.use_custom_normal) { + if (user.use_custom_normal) { out += "layout(binding = 6) uniform sampler2D tex_normal;\n"; } if (use_blend_fallback) { @@ -1748,8 +1754,9 @@ void FragmentModule::DefineTexUnitSampler(u32 texture_unit) { out += "\n}\n"; } -std::string GenerateFragmentShader(const FSConfig& config, const Profile& profile) { - FragmentModule module{config, profile}; +std::string GenerateFragmentShader(const FSConfig& config, const UserConfig& user, + const Profile& profile) { + FragmentModule module{config, user, profile}; return module.Generate(); } diff --git a/src/video_core/shader/generator/glsl_fs_shader_gen.h b/src/video_core/shader/generator/glsl_fs_shader_gen.h index 10dab5b26..55d5b5256 100644 --- a/src/video_core/shader/generator/glsl_fs_shader_gen.h +++ b/src/video_core/shader/generator/glsl_fs_shader_gen.h @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -10,7 +10,7 @@ namespace Pica::Shader::Generator::GLSL { class FragmentModule { public: - explicit FragmentModule(const FSConfig& config, const Profile& profile); + explicit FragmentModule(const FSConfig& config, const UserConfig& user, const Profile& profile); ~FragmentModule(); /// Emits GLSL source corresponding to the provided pica fragment configuration @@ -83,7 +83,8 @@ private: void DefineTexUnitSampler(u32 i); private: - const FSConfig& config; + FSConfig config; + const UserConfig& user; const Profile& profile; std::string out; bool use_blend_fallback{}; @@ -97,6 +98,7 @@ private: * configuration (NOTE: Use state in this struct only, not the Pica registers!) * @returns String of the shader source code */ -std::string GenerateFragmentShader(const FSConfig& config, const Profile& profile); +std::string GenerateFragmentShader(const FSConfig& config, const UserConfig& user, + const Profile& profile); } // namespace Pica::Shader::Generator::GLSL diff --git a/src/video_core/shader/generator/glsl_shader_gen.cpp b/src/video_core/shader/generator/glsl_shader_gen.cpp index 154ff1908..b537df375 100644 --- a/src/video_core/shader/generator/glsl_shader_gen.cpp +++ b/src/video_core/shader/generator/glsl_shader_gen.cpp @@ -153,7 +153,9 @@ std::string_view MakeLoadPrefix(AttribLoadFlags flag) { } std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& config, - bool separable_shader) { + const ExtraVSConfig& extra) { + const bool separable_shader = extra.separable_shader; + std::string out; if (separable_shader) { out += "#extension GL_ARB_separate_shader_objects : enable\n"; @@ -178,8 +180,8 @@ std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& c }; auto program_source = - DecompileProgram(setup.program_code, setup.swizzle_data, config.state.main_offset, - get_input_reg, get_output_reg, config.state.sanitize_mul); + DecompileProgram(setup.GetProgramCode(), setup.GetSwizzleData(), config.state.main_offset, + get_input_reg, get_output_reg, extra.sanitize_mul); if (program_source.empty()) { return ""; @@ -188,7 +190,7 @@ std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& c // input attributes declaration for (std::size_t i = 0; i < used_regs.size(); ++i) { if (used_regs[i]) { - const auto flags = config.state.load_flags[i]; + const auto flags = extra.load_flags[i]; const std::string_view prefix = MakeLoadPrefix(flags); out += fmt::format("layout(location = {0}) in {1}vec4 vs_in_typed_reg{0};\n", i, prefix); @@ -197,7 +199,7 @@ std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& c } out += '\n'; - if (config.state.use_geometry_shader) { + if (extra.use_geometry_shader) { // output attributes declaration for (u32 i = 0; i < config.state.num_outputs; ++i) { if (separable_shader) { @@ -207,19 +209,21 @@ std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& c } out += "void EmitVtx() {}\n"; } else { - out += GetVertexInterfaceDeclaration(true, config.state.use_clip_planes, separable_shader); + out += GetVertexInterfaceDeclaration(true, extra.use_clip_planes, separable_shader); // output attributes declaration for (u32 i = 0; i < config.state.num_outputs; ++i) { out += fmt::format("vec4 vs_out_attr{};\n", i); } - const auto semantic = - [&state = config.state](VSOutputAttributes::Semantic slot_semantic) -> std::string { + const auto semantic_maps = config.state.gs_state.GetSemanticMaps(); + + const auto semantic = [&state = config.state, &semantic_maps]( + VSOutputAttributes::Semantic slot_semantic) -> std::string { const u32 slot = static_cast(slot_semantic); - const u32 attrib = state.gs_state.semantic_maps[slot].attribute_index; - const u32 comp = state.gs_state.semantic_maps[slot].component_index; - if (attrib < state.gs_state.gs_output_attributes) { + const u32 attrib = semantic_maps[slot].attribute_index; + const u32 comp = semantic_maps[slot].component_index; + if (attrib < state.gs_state.gs_output_attributes_count) { return fmt::format("vs_out_attr{}.{}", attrib, "xyzw"[comp]); } return "1.0"; @@ -242,7 +246,7 @@ std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& c out += " vtx_pos.y = -vtx_pos.y;\n"; out += " }\n"; out += " gl_Position = vec4(vtx_pos.x, vtx_pos.y, -vtx_pos.z, vtx_pos.w);\n"; - if (config.state.use_clip_planes) { + if (extra.use_clip_planes) { out += " gl_ClipDistance[0] = -vtx_pos.z;\n"; // fixed PICA clipping plane z <= 0 out += " if (enable_clip1) {\n"; out += " gl_ClipDistance[1] = dot(clip_coef, vtx_pos);\n"; @@ -279,7 +283,7 @@ std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& c for (std::size_t i = 0; i < used_regs.size(); ++i) { if (used_regs[i]) { out += fmt::format("vs_in_reg{0} = vec4(vs_in_typed_reg{0});\n", i); - if (True(config.state.load_flags[i] & AttribLoadFlags::ZeroW)) { + if (True(extra.load_flags[i] & AttribLoadFlags::ZeroW)) { out += fmt::format("vs_in_reg{0}.w = 0;\n", i); } } @@ -294,13 +298,15 @@ std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& c return out; } -static std::string GetGSCommonSource(const PicaGSConfigState& state, bool separable_shader) { - std::string out = GetVertexInterfaceDeclaration(true, state.use_clip_planes, separable_shader); +static std::string GetGSCommonSource(const PicaGSConfigState& state, + const ExtraFixedGSConfig& extra) { + std::string out = + GetVertexInterfaceDeclaration(true, extra.use_clip_planes, extra.separable_shader); out += VSUniformBlockDef; out += '\n'; - for (u32 i = 0; i < state.vs_output_attributes; ++i) { - if (separable_shader) { + for (u32 i = 0; i < state.vs_output_attributes_count; ++i) { + if (extra.separable_shader) { out += fmt::format("layout(location = {}) ", i); } out += fmt::format("in vec4 vs_out_attr{}[];\n", i); @@ -309,14 +315,17 @@ static std::string GetGSCommonSource(const PicaGSConfigState& state, bool separa out += R"( struct Vertex { )"; - out += fmt::format(" vec4 attributes[{}];\n", state.gs_output_attributes); + out += fmt::format(" vec4 attributes[{}];\n", state.gs_output_attributes_count); out += "};\n\n"; - const auto semantic = [&state](VSOutputAttributes::Semantic slot_semantic) -> std::string { + const auto semantic_maps = state.GetSemanticMaps(); + + const auto semantic = + [&state, &semantic_maps](VSOutputAttributes::Semantic slot_semantic) -> std::string { const u32 slot = static_cast(slot_semantic); - const u32 attrib = state.semantic_maps[slot].attribute_index; - const u32 comp = state.semantic_maps[slot].component_index; - if (attrib < state.gs_output_attributes) { + const u32 attrib = semantic_maps[slot].attribute_index; + const u32 comp = semantic_maps[slot].component_index; + if (attrib < state.gs_output_attributes_count) { return fmt::format("vtx.attributes[{}].{}", attrib, "xyzw"[comp]); } return "1.0"; @@ -339,7 +348,7 @@ struct Vertex { out += " vtx_pos.y = -vtx_pos.y;\n"; out += " }\n"; out += " gl_Position = vec4(vtx_pos.x, vtx_pos.y, -vtx_pos.z, vtx_pos.w);\n"; - if (state.use_clip_planes) { + if (extra.use_clip_planes) { out += " gl_ClipDistance[0] = -vtx_pos.z;\n"; // fixed PICA clipping plane z <= 0 out += " if (enable_clip1) {\n"; out += " gl_ClipDistance[1] = dot(clip_coef, vtx_pos);\n"; @@ -388,7 +397,10 @@ void EmitPrim(Vertex vtx0, Vertex vtx1, Vertex vtx2) { return out; }; -std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader) { +std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, + const ExtraFixedGSConfig& extra) { + const bool separable_shader = extra.separable_shader; + std::string out; if (separable_shader) { out += "#extension GL_ARB_separate_shader_objects : enable\n"; @@ -400,7 +412,7 @@ layout(triangle_strip, max_vertices = 3) out; )"; - out += GetGSCommonSource(config.state, separable_shader); + out += GetGSCommonSource(config.state, extra); out += R"( void main() { @@ -408,8 +420,8 @@ void main() { )"; for (u32 vtx = 0; vtx < 3; ++vtx) { out += fmt::format(" prim_buffer[{}].attributes = vec4[{}](", vtx, - config.state.gs_output_attributes); - for (u32 i = 0; i < config.state.vs_output_attributes; ++i) { + config.state.gs_output_attributes_count); + for (u32 i = 0; i < config.state.vs_output_attributes_count; ++i) { out += fmt::format("{}vs_out_attr{}[{}]", i == 0 ? "" : ", ", i, vtx); } out += ");\n"; diff --git a/src/video_core/shader/generator/glsl_shader_gen.h b/src/video_core/shader/generator/glsl_shader_gen.h index 20d826f90..5d6ad8661 100644 --- a/src/video_core/shader/generator/glsl_shader_gen.h +++ b/src/video_core/shader/generator/glsl_shader_gen.h @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -27,7 +27,9 @@ struct ShaderSetup; namespace Pica::Shader::Generator { struct PicaVSConfig; +struct ExtraVSConfig; struct PicaFixedGSConfig; +struct ExtraFixedGSConfig; } // namespace Pica::Shader::Generator namespace Pica::Shader::Generator::GLSL { @@ -44,12 +46,13 @@ std::string GenerateTrivialVertexShader(bool use_clip_planes, bool separable_sha * @returns String of the shader source code; empty on failure */ std::string GenerateVertexShader(const Pica::ShaderSetup& setup, const PicaVSConfig& config, - bool separable_shader); + const ExtraVSConfig& extra); /** * Generates the GLSL fixed geometry shader program source code for non-GS PICA pipeline * @returns String of the shader source code */ -std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader); +std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, + const ExtraFixedGSConfig& extra_config); } // namespace Pica::Shader::Generator::GLSL diff --git a/src/video_core/shader/generator/pica_fs_config.cpp b/src/video_core/shader/generator/pica_fs_config.cpp index 34dee8712..0f3854ce8 100644 --- a/src/video_core/shader/generator/pica_fs_config.cpp +++ b/src/video_core/shader/generator/pica_fs_config.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -6,7 +6,7 @@ namespace Pica::Shader { -FramebufferConfig::FramebufferConfig(const Pica::RegsInternal& regs, const Profile& profile) { +FramebufferConfig::FramebufferConfig(const Pica::RegsInternal& regs) { const auto& output_merger = regs.framebuffer.output_merger; scissor_test_mode.Assign(regs.rasterizer.scissor_test.mode); depthmap_enable.Assign(regs.rasterizer.depthmap_enable); @@ -15,31 +15,43 @@ FramebufferConfig::FramebufferConfig(const Pica::RegsInternal& regs, const Profi ? output_merger.alpha_test.func.Value() : Pica::FramebufferRegs::CompareFunc::Always); - // Emulate logic op in the shader if needed and not supported. + alphablend_enable.Assign(output_merger.alphablend_enable); + requested_logic_op = output_merger.logic_op; + logic_op.Assign(Pica::FramebufferRegs::LogicOp::Copy); - if (!profile.has_logic_op && !regs.framebuffer.output_merger.alphablend_enable) { - logic_op.Assign(regs.framebuffer.output_merger.logic_op); + + if (alphablend_enable) { + rgb_blend.eq = output_merger.alpha_blending.blend_equation_rgb.Value(); + rgb_blend.src_factor = output_merger.alpha_blending.factor_source_rgb; + rgb_blend.dst_factor = output_merger.alpha_blending.factor_dest_rgb; + + alpha_blend.eq = output_merger.alpha_blending.blend_equation_a.Value(); + alpha_blend.src_factor = output_merger.alpha_blending.factor_source_a; + alpha_blend.dst_factor = output_merger.alpha_blending.factor_dest_a; + } +} + +void FramebufferConfig::ApplyProfile(const Profile& profile) { + // Emulate logic op in the shader if needed and not supported. + if (!profile.has_logic_op && !alphablend_enable) { + logic_op.Assign(requested_logic_op); } - const auto alpha_eq = output_merger.alpha_blending.blend_equation_a.Value(); - const auto rgb_eq = output_merger.alpha_blending.blend_equation_rgb.Value(); - if (!profile.has_blend_minmax_factor && output_merger.alphablend_enable) { - if (rgb_eq == Pica::FramebufferRegs::BlendEquation::Max || - rgb_eq == Pica::FramebufferRegs::BlendEquation::Min) { - rgb_blend.eq = rgb_eq; - rgb_blend.src_factor = output_merger.alpha_blending.factor_source_rgb; - rgb_blend.dst_factor = output_merger.alpha_blending.factor_dest_rgb; + // Min/max blend emulation + if (!profile.has_blend_minmax_factor && alphablend_enable) { + if (rgb_blend.eq != Pica::FramebufferRegs::BlendEquation::Min && + rgb_blend.eq != Pica::FramebufferRegs::BlendEquation::Max) { + rgb_blend = {}; } - if (alpha_eq == Pica::FramebufferRegs::BlendEquation::Max || - alpha_eq == Pica::FramebufferRegs::BlendEquation::Min) { - alpha_blend.eq = alpha_eq; - alpha_blend.src_factor = output_merger.alpha_blending.factor_source_a; - alpha_blend.dst_factor = output_merger.alpha_blending.factor_dest_a; + + if (alpha_blend.eq != Pica::FramebufferRegs::BlendEquation::Min && + alpha_blend.eq != Pica::FramebufferRegs::BlendEquation::Max) { + alpha_blend = {}; } } } -TextureConfig::TextureConfig(const Pica::TexturingRegs& regs, const Profile& profile) { +TextureConfig::TextureConfig(const Pica::TexturingRegs& regs) { texture0_type.Assign(regs.texture0.type); texture2_use_coord1.Assign(regs.main_config.texture2_use_coord1 != 0); combiner_buffer_input.Assign(regs.tev_combiner_buffer_input.update_mask_rgb.Value() | @@ -48,16 +60,13 @@ TextureConfig::TextureConfig(const Pica::TexturingRegs& regs, const Profile& pro fog_flip.Assign(regs.fog_flip != 0); shadow_texture_orthographic.Assign(regs.shadow.orthographic != 0); - // Emulate custom border color if needed and not supported. const auto pica_textures = regs.GetTextures(); for (u32 tex_index = 0; tex_index < 3; tex_index++) { - const auto& config = pica_textures[tex_index].config; - texture_border_color[tex_index].enable_s.Assign( - !profile.has_custom_border_color && - config.wrap_s == Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder); - texture_border_color[tex_index].enable_t.Assign( - !profile.has_custom_border_color && - config.wrap_t == Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder); + requested_wrap[tex_index].s = pica_textures[tex_index].config.wrap_s; + requested_wrap[tex_index].t = pica_textures[tex_index].config.wrap_t; + + texture_border_color[tex_index].enable_s.Assign(false); + texture_border_color[tex_index].enable_t.Assign(false); } const auto& stages = regs.GetTevStages(); @@ -75,6 +84,21 @@ TextureConfig::TextureConfig(const Pica::TexturingRegs& regs, const Profile& pro } } +void TextureConfig::ApplyProfile(const Profile& profile) { + // Emulate custom border color if needed and not supported. + if (profile.has_custom_border_color) { + return; + } + + for (u32 i = 0; i < 3; i++) { + texture_border_color[i].enable_s.Assign( + requested_wrap[i].s == Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder); + + texture_border_color[i].enable_t.Assign( + requested_wrap[i].t == Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder); + } +} + LightConfig::LightConfig(const Pica::LightingRegs& regs) { if (regs.disable) { return; @@ -116,48 +140,48 @@ LightConfig::LightConfig(const Pica::LightingRegs& regs) { if (lut_d0.enable) { lut_d0.abs_input.Assign(regs.abs_lut_input.disable_d0 == 0); lut_d0.type.Assign(regs.lut_input.d0.Value()); - lut_d0.scale = regs.lut_scale.GetScale(regs.lut_scale.d0); + lut_d0.SetScale(regs.lut_scale.GetScale(regs.lut_scale.d0)); } lut_d1.enable.Assign(regs.config1.disable_lut_d1 == 0); if (lut_d1.enable) { lut_d1.abs_input.Assign(regs.abs_lut_input.disable_d1 == 0); lut_d1.type.Assign(regs.lut_input.d1.Value()); - lut_d1.scale = regs.lut_scale.GetScale(regs.lut_scale.d1); + lut_d1.SetScale(regs.lut_scale.GetScale(regs.lut_scale.d1)); } // This is a dummy field due to lack of the corresponding register lut_sp.enable.Assign(1); lut_sp.abs_input.Assign(regs.abs_lut_input.disable_sp == 0); lut_sp.type.Assign(regs.lut_input.sp.Value()); - lut_sp.scale = regs.lut_scale.GetScale(regs.lut_scale.sp); + lut_sp.SetScale(regs.lut_scale.GetScale(regs.lut_scale.sp)); lut_fr.enable.Assign(regs.config1.disable_lut_fr == 0); if (lut_fr.enable) { lut_fr.abs_input.Assign(regs.abs_lut_input.disable_fr == 0); lut_fr.type.Assign(regs.lut_input.fr.Value()); - lut_fr.scale = regs.lut_scale.GetScale(regs.lut_scale.fr); + lut_fr.SetScale(regs.lut_scale.GetScale(regs.lut_scale.fr)); } lut_rr.enable.Assign(regs.config1.disable_lut_rr == 0); if (lut_rr.enable) { lut_rr.abs_input.Assign(regs.abs_lut_input.disable_rr == 0); lut_rr.type.Assign(regs.lut_input.rr.Value()); - lut_rr.scale = regs.lut_scale.GetScale(regs.lut_scale.rr); + lut_rr.SetScale(regs.lut_scale.GetScale(regs.lut_scale.rr)); } lut_rg.enable.Assign(regs.config1.disable_lut_rg == 0); if (lut_rg.enable) { lut_rg.abs_input.Assign(regs.abs_lut_input.disable_rg == 0); lut_rg.type.Assign(regs.lut_input.rg.Value()); - lut_rg.scale = regs.lut_scale.GetScale(regs.lut_scale.rg); + lut_rg.SetScale(regs.lut_scale.GetScale(regs.lut_scale.rg)); } lut_rb.enable.Assign(regs.config1.disable_lut_rb == 0); if (lut_rb.enable) { lut_rb.abs_input.Assign(regs.abs_lut_input.disable_rb == 0); lut_rb.type.Assign(regs.lut_input.rb.Value()); - lut_rb.scale = regs.lut_scale.GetScale(regs.lut_scale.rb); + lut_rb.SetScale(regs.lut_scale.GetScale(regs.lut_scale.rb)); } } @@ -186,8 +210,8 @@ ProcTexConfig::ProcTexConfig(const Pica::TexturingRegs& regs) { lut_filter.Assign(regs.proctex_lut.filter); } -FSConfig::FSConfig(const Pica::RegsInternal& regs, const UserConfig& user_, const Profile& profile) - : framebuffer{regs, profile}, texture{regs.texturing, profile}, lighting{regs.lighting}, - proctex{regs.texturing}, user{user_} {} +FSConfig::FSConfig(const Pica::RegsInternal& regs) + : framebuffer{regs}, texture{regs.texturing}, lighting{regs.lighting}, proctex{regs.texturing} { +} } // namespace Pica::Shader diff --git a/src/video_core/shader/generator/pica_fs_config.h b/src/video_core/shader/generator/pica_fs_config.h index 18d6d92d7..736880a5b 100644 --- a/src/video_core/shader/generator/pica_fs_config.h +++ b/src/video_core/shader/generator/pica_fs_config.h @@ -8,16 +8,46 @@ #include "video_core/pica/regs_internal.h" #include "video_core/shader/generator/profile.h" +#define LAYOUT_HASH static_cast(sizeof(T)), static_cast(alignof(T)) +#define FIELD_HASH(x) static_cast(offsetof(T, x)), static_cast(sizeof(x)) + namespace Pica::Shader { +/** + * WARNING! + * + * The following structs are saved to the disk as cache entries! + * Any modification to their members will invalidate the cache, breaking their + * transferable properties. + * + * Only modify the entries if such modifications are justified. + * If the struct is modified in a way that results in the exact same layout + * (for example, replacing an u8 with another u8 in the same place), then bump + * the struct's STRUCT_VERSION value. + */ + struct BlendConfig { Pica::FramebufferRegs::BlendEquation eq; Pica::FramebufferRegs::BlendFactor src_factor; Pica::FramebufferRegs::BlendFactor dst_factor; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = BlendConfig; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(eq), FIELD_HASH(src_factor), FIELD_HASH(dst_factor)); + } }; +static_assert(std::has_unique_object_representations_v); struct FramebufferConfig { - explicit FramebufferConfig(const Pica::RegsInternal& regs, const Profile& profile); + explicit FramebufferConfig(const Pica::RegsInternal& regs); union { u32 raw{}; @@ -26,9 +56,33 @@ struct FramebufferConfig { BitField<5, 1, Pica::RasterizerRegs::DepthBuffering> depthmap_enable; BitField<6, 4, Pica::FramebufferRegs::LogicOp> logic_op; BitField<10, 1, u32> shadow_rendering; + BitField<11, 1, u32> alphablend_enable; }; BlendConfig rgb_blend{}; BlendConfig alpha_blend{}; + + Pica::FramebufferRegs::LogicOp requested_logic_op{}; + + void ApplyProfile(const Profile& profile); + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = FramebufferConfig; + return Common::HashCombine( + STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(alpha_test_func), FIELD_HASH(scissor_test_mode), FIELD_HASH(depthmap_enable), + FIELD_HASH(logic_op), FIELD_HASH(shadow_rendering), FIELD_HASH(alphablend_enable), + FIELD_HASH(rgb_blend), FIELD_HASH(alpha_blend), FIELD_HASH(requested_logic_op), + + // nested layout + BlendConfig::StructHash()); + } }; static_assert(std::has_unique_object_representations_v); @@ -46,15 +100,48 @@ struct TevStageConfigRaw { .scales_raw = scales_raw, }; } + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = TevStageConfigRaw; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(sources_raw), FIELD_HASH(modifiers_raw), + FIELD_HASH(ops_raw), FIELD_HASH(scales_raw)); + } }; +static_assert(std::has_unique_object_representations_v); union TextureBorder { + u32 raw{}; BitField<0, 1, u32> enable_s; BitField<1, 1, u32> enable_t; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = TextureBorder; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(enable_s), FIELD_HASH(enable_t), + + // nested layout + BlendConfig::StructHash()); + } }; +static_assert(std::has_unique_object_representations_v); struct TextureConfig { - explicit TextureConfig(const Pica::TexturingRegs& regs, const Profile& profile); + explicit TextureConfig(const Pica::TexturingRegs& regs); union { u32 raw{}; @@ -67,6 +154,48 @@ struct TextureConfig { }; std::array texture_border_color{}; std::array tev_stages{}; + + struct TextureWrap { + Pica::TexturingRegs::TextureConfig::WrapMode s; + Pica::TexturingRegs::TextureConfig::WrapMode t; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = TextureWrap; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(s), FIELD_HASH(t)); + } + }; + std::array requested_wrap{}; + + void ApplyProfile(const Profile& profile); + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = TextureConfig; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(texture0_type), FIELD_HASH(texture2_use_coord1), + FIELD_HASH(combiner_buffer_input), FIELD_HASH(fog_mode), + FIELD_HASH(fog_flip), FIELD_HASH(shadow_texture_orthographic), + FIELD_HASH(texture_border_color), FIELD_HASH(tev_stages), + FIELD_HASH(requested_wrap), + + // nested layout + TextureBorder::StructHash(), TevStageConfigRaw::StructHash(), + TextureWrap::StructHash()); + } }; static_assert(std::has_unique_object_representations_v); @@ -80,6 +209,22 @@ union Light { BitField<7, 1, u16> geometric_factor_0; BitField<8, 1, u16> geometric_factor_1; BitField<9, 1, u16> shadow_enable; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = Light; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(num), FIELD_HASH(directional), + FIELD_HASH(two_sided_diffuse), FIELD_HASH(dist_atten_enable), + FIELD_HASH(spot_atten_enable), FIELD_HASH(geometric_factor_0), + FIELD_HASH(geometric_factor_1), FIELD_HASH(shadow_enable)); + } }; static_assert(std::has_unique_object_representations_v); @@ -90,8 +235,31 @@ struct LutConfig { BitField<1, 1, u32> abs_input; BitField<2, 3, Pica::LightingRegs::LightingLutInput> type; }; - f32 scale; + + // Needed for std::has_unique_object_representations_v + u32 scale_bits; + inline f32 GetScale() const noexcept { + return std::bit_cast(scale_bits); + } + inline void SetScale(f32 value) noexcept { + scale_bits = std::bit_cast(value); + } + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = LutConfig; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(enable), FIELD_HASH(abs_input), FIELD_HASH(type), + FIELD_HASH(scale_bits)); + } }; +static_assert(std::has_unique_object_representations_v); struct LightConfig { explicit LightConfig(const Pica::LightingRegs& regs); @@ -122,7 +290,32 @@ struct LightConfig { LutConfig lut_rg{}; LutConfig lut_rb{}; std::array lights{}; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = LightConfig; + return Common::HashCombine( + STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(enable), FIELD_HASH(src_num), FIELD_HASH(bump_mode), + FIELD_HASH(bump_selector), FIELD_HASH(bump_renorm), FIELD_HASH(clamp_highlights), + FIELD_HASH(config), FIELD_HASH(enable_primary_alpha), + FIELD_HASH(enable_secondary_alpha), FIELD_HASH(enable_shadow), + FIELD_HASH(shadow_primary), FIELD_HASH(shadow_secondary), FIELD_HASH(shadow_invert), + FIELD_HASH(shadow_alpha), FIELD_HASH(shadow_selector), FIELD_HASH(lut_d0), + FIELD_HASH(lut_d1), FIELD_HASH(lut_sp), FIELD_HASH(lut_fr), FIELD_HASH(lut_rr), + FIELD_HASH(lut_rg), FIELD_HASH(lut_rb), FIELD_HASH(lights), + + // nested layout + LutConfig::StructHash(), Light::StructHash()); + } }; +static_assert(std::has_unique_object_representations_v); struct ProcTexConfig { explicit ProcTexConfig(const Pica::TexturingRegs& regs); @@ -148,18 +341,43 @@ struct ProcTexConfig { s32 lut_offset3{}; u16 lod_min{}; u16 lod_max{}; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = ProcTexConfig; + return Common::HashCombine( + STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(enable), FIELD_HASH(coord), FIELD_HASH(u_clamp), FIELD_HASH(v_clamp), + FIELD_HASH(color_combiner), FIELD_HASH(alpha_combiner), FIELD_HASH(lut_filter), + FIELD_HASH(separate_alpha), FIELD_HASH(noise_enable), FIELD_HASH(u_shift), + FIELD_HASH(v_shift), FIELD_HASH(lut_width), FIELD_HASH(lut_offset0), + FIELD_HASH(lut_offset1), FIELD_HASH(lut_offset2), FIELD_HASH(lut_offset3), + FIELD_HASH(lod_min), FIELD_HASH(lod_max)); + } }; static_assert(std::has_unique_object_representations_v); union UserConfig { u32 raw{}; BitField<0, 1, u32> use_custom_normal; + + // Whether a FSConfig + UserConfig combination can be + // cached to disk. Right now, this is true if the + // UserConfig was default constructed + bool IsCacheable() const { + return raw == u32{}; + } }; static_assert(std::has_unique_object_representations_v); struct FSConfig { - explicit FSConfig(const Pica::RegsInternal& regs, const UserConfig& user, - const Profile& profile); + explicit FSConfig(const Pica::RegsInternal& regs); [[nodiscard]] bool TevStageUpdatesCombinerBufferColor(u32 stage_index) const { return (stage_index < 4) && (texture.combiner_buffer_input & (1 << stage_index)); @@ -180,6 +398,11 @@ struct FSConfig { framebuffer.shadow_rendering.Value(); } + void ApplyProfile(const Profile& profile) { + framebuffer.ApplyProfile(profile); + texture.ApplyProfile(profile); + } + bool operator==(const FSConfig& other) const noexcept { return std::memcmp(this, &other, sizeof(FSConfig)) == 0; } @@ -192,8 +415,27 @@ struct FSConfig { TextureConfig texture; LightConfig lighting; ProcTexConfig proctex; - UserConfig user; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = FSConfig; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(framebuffer), FIELD_HASH(texture), + FIELD_HASH(lighting), FIELD_HASH(proctex), + + // nested layout + FramebufferConfig::StructHash(), TextureConfig::StructHash(), + LightConfig::StructHash(), ProcTexConfig::StructHash()); + } }; +static_assert(std::has_unique_object_representations_v); +static_assert(std::is_trivially_copyable_v); } // namespace Pica::Shader @@ -205,3 +447,6 @@ struct hash { } }; } // namespace std + +#undef FIELD_HASH +#undef LAYOUT_HASH diff --git a/src/video_core/shader/generator/profile.h b/src/video_core/shader/generator/profile.h index 819baae33..a8fb21a8f 100644 --- a/src/video_core/shader/generator/profile.h +++ b/src/video_core/shader/generator/profile.h @@ -1,27 +1,53 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once +#include +#include "common/common_types.h" + namespace Pica::Shader { +struct VKFormatTraits { + u8 transfer_support{}; + u8 blit_support{}; + u8 attachment_support{}; + u8 storage_support{}; + u8 needs_conversion{}; + u8 needs_emulation{}; + u32 usage_flags{}; + u32 aspect_flags{}; + u32 native_format{}; + + auto operator<=>(const VKFormatTraits&) const = default; +}; + struct Profile { - bool has_separable_shaders{}; - bool has_clip_planes{}; - bool has_geometry_shader{}; - bool has_custom_border_color{}; - bool has_fragment_shader_interlock{}; - bool has_fragment_shader_barycentric{}; - bool has_blend_minmax_factor{}; - bool has_minus_one_to_one_range{}; - bool has_logic_op{}; - bool has_gl_ext_framebuffer_fetch{}; - bool has_gl_arm_framebuffer_fetch{}; - bool has_gl_nv_fragment_shader_interlock{}; - bool has_gl_intel_fragment_shader_ordering{}; - bool has_gl_nv_fragment_shader_barycentric{}; - bool is_vulkan{}; + u8 enable_accurate_mul{}; + u8 has_separable_shaders{}; + u8 has_clip_planes{}; + u8 has_geometry_shader{}; + u8 has_custom_border_color{}; + u8 has_fragment_shader_interlock{}; + u8 has_fragment_shader_barycentric{}; + u8 has_blend_minmax_factor{}; + u8 has_minus_one_to_one_range{}; + u8 has_logic_op{}; + + u8 has_gl_ext_framebuffer_fetch{}; + u8 has_gl_arm_framebuffer_fetch{}; + u8 has_gl_nv_fragment_shader_interlock{}; + u8 has_gl_intel_fragment_shader_ordering{}; + u8 has_gl_nv_fragment_shader_barycentric{}; + + u8 vk_disable_spirv_optimizer{}; + u8 vk_use_spirv_generator{}; + std::array vk_format_traits{}; + + u8 is_vulkan{}; + + auto operator<=>(const Profile&) const = default; }; } // namespace Pica::Shader diff --git a/src/video_core/shader/generator/shader_gen.cpp b/src/video_core/shader/generator/shader_gen.cpp index 6d7e61190..70af303fb 100644 --- a/src/video_core/shader/generator/shader_gen.cpp +++ b/src/video_core/shader/generator/shader_gen.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -11,19 +11,25 @@ namespace Pica::Shader::Generator { -void PicaGSConfigState::Init(const Pica::RegsInternal& regs, bool use_clip_planes_) { - use_clip_planes = use_clip_planes_; +void PicaGSConfigState::Init(const Pica::RegsInternal& regs) { + vs_output_attributes_count = Common::BitSet(regs.vs.output_mask).Count(); + gs_output_attributes_count = vs_output_attributes_count; + vs_output_total = regs.rasterizer.vs_output_total; - vs_output_attributes = Common::BitSet(regs.vs.output_mask).Count(); - gs_output_attributes = vs_output_attributes; + memcpy(vs_output_attributes.data(), regs.rasterizer.vs_output_attributes, + vs_output_total * sizeof(Pica::RasterizerRegs::VSOutputAttributes)); +} + +std::array PicaGSConfigState::GetSemanticMaps() const { + std::array semantic_maps{}; semantic_maps.fill({16, 0}); - for (u32 attrib = 0; attrib < regs.rasterizer.vs_output_total; ++attrib) { + for (u32 attrib = 0; attrib < vs_output_total; ++attrib) { const std::array semantics{ - regs.rasterizer.vs_output_attributes[attrib].map_x.Value(), - regs.rasterizer.vs_output_attributes[attrib].map_y.Value(), - regs.rasterizer.vs_output_attributes[attrib].map_z.Value(), - regs.rasterizer.vs_output_attributes[attrib].map_w.Value(), + vs_output_attributes[attrib].map_x.Value(), + vs_output_attributes[attrib].map_y.Value(), + vs_output_attributes[attrib].map_z.Value(), + vs_output_attributes[attrib].map_w.Value(), }; for (u32 comp = 0; comp < 4; ++comp) { const auto semantic = semantics[comp]; @@ -34,38 +40,34 @@ void PicaGSConfigState::Init(const Pica::RegsInternal& regs, bool use_clip_plane } } } + + return semantic_maps; } -void PicaVSConfigState::Init(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, - bool use_clip_planes_, bool use_geometry_shader_, bool accurate_mul_) { - use_clip_planes = use_clip_planes_; - use_geometry_shader = use_geometry_shader_; - sanitize_mul = accurate_mul_; - +void PicaVSConfigState::Init(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup) { + setup.DoProgramCodeFixup(); program_hash = setup.GetProgramCodeHash(); swizzle_hash = setup.GetSwizzleDataHash(); main_offset = regs.vs.main_offset; + lighting_disable = regs.lighting.disable; + num_outputs = 0; - load_flags.fill(AttribLoadFlags::Float); output_map.fill(16); for (u32 reg : Common::BitSet(regs.vs.output_mask)) { output_map[reg] = num_outputs++; } - if (!use_geometry_shader_) { - gs_state.Init(regs, use_clip_planes_); - } + gs_state.Init(regs); } -PicaVSConfig::PicaVSConfig(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, - bool use_clip_planes_, bool use_geometry_shader_, bool accurate_mul_) { - state.Init(regs, setup, use_clip_planes_, use_geometry_shader_, accurate_mul_); +PicaVSConfig::PicaVSConfig(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup) { + state.Init(regs, setup); } -PicaFixedGSConfig::PicaFixedGSConfig(const Pica::RegsInternal& regs, bool use_clip_planes_) { - state.Init(regs, use_clip_planes_); +PicaFixedGSConfig::PicaFixedGSConfig(const Pica::RegsInternal& regs) { + state.Init(regs); } } // namespace Pica::Shader::Generator diff --git a/src/video_core/shader/generator/shader_gen.h b/src/video_core/shader/generator/shader_gen.h index 560dfc6a1..babb50111 100644 --- a/src/video_core/shader/generator/shader_gen.h +++ b/src/video_core/shader/generator/shader_gen.h @@ -1,10 +1,14 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include "common/hash.h" +#include "video_core/pica/regs_rasterizer.h" + +#define LAYOUT_HASH static_cast(sizeof(T)), static_cast(alignof(T)) +#define FIELD_HASH(x) static_cast(offsetof(T, x)), static_cast(sizeof(x)) namespace Pica { struct RegsInternal; @@ -31,7 +35,7 @@ enum Attributes { ATTRIBUTE_VIEW, }; -enum class AttribLoadFlags { +enum class AttribLoadFlags : u32 { Float = 1 << 0, Sint = 1 << 1, Uint = 1 << 2, @@ -39,25 +43,53 @@ enum class AttribLoadFlags { }; DECLARE_ENUM_FLAG_OPERATORS(AttribLoadFlags) +/** + * WARNING! + * + * The following structs are saved to the disk as cache entries! + * Any modification to their members will invalidate the cache, breaking their + * transferable properties. + * + * Only modify the entries if such modifications are justified. + * If the struct is modified in a way that results in the exact same layout + * (for example, replacing an u8 with another u8 in the same place), then bump + * the struct's STRUCT_VERSION value. + */ + /** * This struct contains common information to identify a GLSL geometry shader generated from * PICA geometry shader. */ struct PicaGSConfigState { - void Init(const Pica::RegsInternal& regs, bool use_clip_planes_); + void Init(const Pica::RegsInternal& regs); - bool use_clip_planes; + u32 vs_output_attributes_count; + u32 gs_output_attributes_count; + u32 vs_output_total; - u32 vs_output_attributes; - u32 gs_output_attributes; + std::array vs_output_attributes; + // semantic_maps[semantic name] -> GS output attribute index + component index struct SemanticMap { u32 attribute_index; u32 component_index; }; + std::array GetSemanticMaps() const; - // semantic_maps[semantic name] -> GS output attribute index + component index - std::array semantic_maps; + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = PicaGSConfigState; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(vs_output_attributes_count), + FIELD_HASH(gs_output_attributes_count), + FIELD_HASH(vs_output_total), FIELD_HASH(vs_output_attributes)); + } }; /** @@ -65,25 +97,48 @@ struct PicaGSConfigState { * PICA vertex shader. */ struct PicaVSConfigState { - void Init(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, bool use_clip_planes_, - bool use_geometry_shader_, bool accurate_mul_); - - bool use_clip_planes; - bool use_geometry_shader; + void Init(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup); + u8 lighting_disable; u64 program_hash; u64 swizzle_hash; u32 main_offset; - bool sanitize_mul; u32 num_outputs; - // Load operations to apply to the input vertex data - std::array load_flags; // output_map[output register index] -> output attribute index std::array output_map; + // These represent relevant input vertex attributes + struct VAttr { + u8 location; + u8 type; + u8 size; + }; + u8 used_input_vertex_attributes; + std::array input_vertex_attributes; + PicaGSConfigState gs_state; + + static consteval u64 StructHash() { + constexpr u64 STRUCT_VERSION = 0; + + using T = PicaVSConfigState; + return Common::HashCombine(STRUCT_VERSION, + + // layout + LAYOUT_HASH, + + // fields + FIELD_HASH(lighting_disable), FIELD_HASH(program_hash), + FIELD_HASH(swizzle_hash), FIELD_HASH(main_offset), + FIELD_HASH(num_outputs), FIELD_HASH(output_map), + FIELD_HASH(used_input_vertex_attributes), + FIELD_HASH(input_vertex_attributes), FIELD_HASH(gs_state), + + // nested layout + PicaGSConfigState::StructHash()); + } }; /** @@ -91,8 +146,21 @@ struct PicaVSConfigState { * shader. */ struct PicaVSConfig : Common::HashableStruct { - explicit PicaVSConfig(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, - bool use_clip_planes_, bool use_geometry_shader_, bool accurate_mul_); + PicaVSConfig() = default; + explicit PicaVSConfig(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup); +}; + +/** + * This struct contains complementary user/driver information to generate a vertex shader. + */ +struct ExtraVSConfig { + u8 use_clip_planes; + u8 use_geometry_shader; + u8 sanitize_mul; + u8 separable_shader; + + // Load operations to apply to the input vertex data + std::array load_flags; }; /** @@ -100,7 +168,12 @@ struct PicaVSConfig : Common::HashableStruct { * shader pipeline */ struct PicaFixedGSConfig : Common::HashableStruct { - explicit PicaFixedGSConfig(const Pica::RegsInternal& regs, bool use_clip_planes_); + explicit PicaFixedGSConfig(const Pica::RegsInternal& regs); +}; + +struct ExtraFixedGSConfig { + u8 use_clip_planes; + u8 separable_shader; }; } // namespace Pica::Shader::Generator @@ -120,3 +193,6 @@ struct hash { } }; } // namespace std + +#undef FIELD_HASH +#undef LAYOUT_HASH \ No newline at end of file diff --git a/src/video_core/shader/generator/spv_fs_shader_gen.cpp b/src/video_core/shader/generator/spv_fs_shader_gen.cpp index 0c8d32623..93ab3e367 100644 --- a/src/video_core/shader/generator/spv_fs_shader_gen.cpp +++ b/src/video_core/shader/generator/spv_fs_shader_gen.cpp @@ -21,6 +21,7 @@ FragmentModule::FragmentModule(const FSConfig& config_, const Profile& profile_) : Sirit::Module{SPIRV_VERSION_1_3}, config{config_}, profile{profile_}, use_fragment_shader_barycentric{profile.has_fragment_shader_barycentric && config.lighting.enable} { + config.ApplyProfile(profile_); DefineArithmeticTypes(); DefineUniformStructs(); DefineInterface(); @@ -454,7 +455,7 @@ void FragmentModule::WriteLighting() { const Id value{ get_lut_value(LightingRegs::SpotlightAttenuationSampler(light_config.num), light_config.num, lighting.lut_sp.type, lighting.lut_sp.abs_input)}; - spot_atten = OpFMul(f32_id, ConstF32(lighting.lut_sp.scale), value); + spot_atten = OpFMul(f32_id, ConstF32(lighting.lut_sp.GetScale()), value); } // If enabled, compute distance attenuation value @@ -486,7 +487,7 @@ void FragmentModule::WriteLighting() { const Id value{get_lut_value(LightingRegs::LightingSampler::Distribution0, light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input)}; - d0_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d0.scale), value); + d0_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d0.GetScale()), value); } Id specular_0{OpVectorTimesScalar(vec_ids.Get(3), GetLightMember(0), d0_lut_value)}; @@ -503,7 +504,7 @@ void FragmentModule::WriteLighting() { light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input)}; - refl_value_r = OpFMul(f32_id, ConstF32(lighting.lut_rr.scale), value); + refl_value_r = OpFMul(f32_id, ConstF32(lighting.lut_rr.GetScale()), value); } // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used @@ -515,7 +516,7 @@ void FragmentModule::WriteLighting() { light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input)}; - refl_value_g = OpFMul(f32_id, ConstF32(lighting.lut_rg.scale), value); + refl_value_g = OpFMul(f32_id, ConstF32(lighting.lut_rg.GetScale()), value); } // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used @@ -526,7 +527,7 @@ void FragmentModule::WriteLighting() { const Id value{get_lut_value(LightingRegs::LightingSampler::ReflectBlue, light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input)}; - refl_value_b = OpFMul(f32_id, ConstF32(lighting.lut_rb.scale), value); + refl_value_b = OpFMul(f32_id, ConstF32(lighting.lut_rb.GetScale()), value); } // Specular 1 component @@ -538,7 +539,7 @@ void FragmentModule::WriteLighting() { const Id value{get_lut_value(LightingRegs::LightingSampler::Distribution1, light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input)}; - d1_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d1.scale), value); + d1_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d1.GetScale()), value); } const Id refl_value{ @@ -559,7 +560,7 @@ void FragmentModule::WriteLighting() { // Lookup fresnel LUT value Id value{get_lut_value(LightingRegs::LightingSampler::Fresnel, light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input)}; - value = OpFMul(f32_id, ConstF32(lighting.lut_fr.scale), value); + value = OpFMul(f32_id, ConstF32(lighting.lut_fr.GetScale()), value); // Enabled for diffuse lighting alpha component if (lighting.enable_primary_alpha) { diff --git a/src/video_core/shader/generator/spv_fs_shader_gen.h b/src/video_core/shader/generator/spv_fs_shader_gen.h index cbbede01f..f19769682 100644 --- a/src/video_core/shader/generator/spv_fs_shader_gen.h +++ b/src/video_core/shader/generator/spv_fs_shader_gen.h @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -220,7 +220,7 @@ private: Id CompareShadow(Id pixel, Id z); private: - const FSConfig& config; + FSConfig config; const Profile& profile; bool use_fragment_shader_barycentric{}; diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp index bf19c037f..cb06a62bc 100644 --- a/src/video_core/shader/shader_interpreter.cpp +++ b/src/video_core/shader/shader_interpreter.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -105,8 +105,8 @@ static void RunInterpreter(const ShaderSetup& setup, ShaderUnit& state, }; const auto& uniforms = setup.uniforms; - const auto& swizzle_data = setup.swizzle_data; - const auto& program_code = setup.program_code; + const auto& swizzle_data = setup.GetSwizzleData(); + const auto& program_code = setup.GetProgramCode(); // Constants for handling invalid inputs static f24 dummy_vec4_float24_zeros[4] = {f24::Zero(), f24::Zero(), f24::Zero(), f24::Zero()}; @@ -118,7 +118,21 @@ static void RunInterpreter(const ShaderSetup& setup, ShaderUnit& state, bool is_break = false; const u32 old_program_counter = program_counter; - const Instruction instr = {program_code[program_counter]}; + // Always treat the last instruction of the program code as an + // end instruction. This fixes some games such as Thunder Blade + // or After Burner II which have malformed geo shaders without an + // end instruction crashing the emulator due to the program counter + // growing uncontrollably. + // TODO(PabloMK7): Find how real HW reacts to this, most likely the + // program counter wraps around after reaching the last instruction, + // but more testing is needed. + Instruction instr{}; + if (program_counter < MAX_PROGRAM_CODE_LENGTH - 1) { + instr.hex = program_code[program_counter]; + } else { + instr.opcode.Assign(OpCode::Id::END); + } + const SwizzlePattern swizzle = {swizzle_data[instr.common.operand_desc_id]}; Record(debug_data, iteration, program_counter); @@ -722,6 +736,7 @@ static void RunInterpreter(const ShaderSetup& setup, ShaderUnit& state, void InterpreterEngine::SetupBatch(ShaderSetup& setup, unsigned int entry_point) { ASSERT(entry_point < MAX_PROGRAM_CODE_LENGTH); + setup.DoProgramCodeFixup(); setup.entry_point = entry_point; } diff --git a/src/video_core/shader/shader_jit.cpp b/src/video_core/shader/shader_jit.cpp index 644586226..a45cf519c 100644 --- a/src/video_core/shader/shader_jit.cpp +++ b/src/video_core/shader/shader_jit.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -26,6 +26,7 @@ void JitEngine::SetupBatch(ShaderSetup& setup, u32 entry_point) { ASSERT(entry_point < MAX_PROGRAM_CODE_LENGTH); setup.entry_point = entry_point; + setup.DoProgramCodeFixup(); const u64 code_hash = setup.GetProgramCodeHash(); const u64 swizzle_hash = setup.GetSwizzleDataHash(); @@ -35,7 +36,7 @@ void JitEngine::SetupBatch(ShaderSetup& setup, u32 entry_point) { setup.cached_shader = iter->second.get(); } else { auto shader = std::make_unique(); - shader->Compile(&setup.program_code, &setup.swizzle_data); + shader->Compile(&setup.GetProgramCode(), &setup.GetSwizzleData()); setup.cached_shader = shader.get(); cache.emplace_hint(iter, cache_key, std::move(shader)); } diff --git a/src/video_core/shader/shader_jit_a64_compiler.cpp b/src/video_core/shader/shader_jit_a64_compiler.cpp index 18793317e..3c9786b29 100644 --- a/src/video_core/shader/shader_jit_a64_compiler.cpp +++ b/src/video_core/shader/shader_jit_a64_compiler.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -899,7 +899,21 @@ void JitShader::Compile_NextInstr() { l(instruction_labels[program_counter]); - const Instruction instr = {(*program_code)[program_counter++]}; + // Always treat the last instruction of the program code as an + // end instruction. This fixes some games such as Thunder Blade + // or After Burner II which have malformed geo shaders without an + // end instruction crashing the emulator due to the program counter + // growing uncontrollably. + // TODO(PabloMK7): Find how real HW reacts to this, most likely the + // program counter wraps around after reaching the last instruction, + // but more testing is needed. + Instruction instr{}; + if (program_counter < MAX_PROGRAM_CODE_LENGTH - 1) { + instr.hex = (*program_code)[program_counter]; + } else { + instr.opcode.Assign(OpCode::Id::END); + } + ++program_counter; const OpCode::Id opcode = instr.opcode.Value(); const auto instr_func = instr_table[static_cast(opcode)]; diff --git a/src/video_core/shader/shader_jit_x64_compiler.cpp b/src/video_core/shader/shader_jit_x64_compiler.cpp index fd47ac0a1..84cdc09bc 100644 --- a/src/video_core/shader/shader_jit_x64_compiler.cpp +++ b/src/video_core/shader/shader_jit_x64_compiler.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -936,7 +936,21 @@ void JitShader::Compile_NextInstr() { L(instruction_labels[program_counter]); - Instruction instr = {(*program_code)[program_counter++]}; + // Always treat the last instruction of the program code as an + // end instruction. This fixes some games such as Thunder Blade + // or After Burner II which have malformed geo shaders without an + // end instruction crashing the emulator due to the program counter + // growing uncontrollably. + // TODO(PabloMK7): Find how real HW reacts to this, most likely the + // program counter wraps around after reaching the last instruction, + // but more testing is needed. + Instruction instr{}; + if (program_counter < MAX_PROGRAM_CODE_LENGTH - 1) { + instr.hex = (*program_code)[program_counter]; + } else { + instr.opcode.Assign(OpCode::Id::END); + } + ++program_counter; OpCode::Id opcode = instr.opcode.Value(); auto instr_func = instr_table[static_cast(opcode)]; diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 59b9d140a..b756c65ed 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -16,6 +16,10 @@ #endif #include "video_core/video_core.h" +#ifdef ENABLE_SDL2 +#include +#endif + namespace VideoCore { std::unique_ptr CreateRenderer(Frontend::EmuWindow& emu_window, @@ -29,6 +33,12 @@ std::unique_ptr CreateRenderer(Frontend::EmuWindow& emu_window, #endif #ifdef ENABLE_VULKAN case Settings::GraphicsAPI::Vulkan: +#if defined(ENABLE_SDL2) && !defined(__APPLE__) + // TODO: When we migrate to SDL3, refactor so that we don't need to init here. + if (SDL_WasInit(SDL_INIT_VIDEO) == 0) { + SDL_Init(SDL_INIT_VIDEO); + } +#endif // ENABLE_SDL2 return std::make_unique(system, pica, emu_window, secondary_window); #endif #ifdef ENABLE_OPENGL diff --git a/tools/README.md b/tools/README.md index c654936af..b4db3f866 100644 --- a/tools/README.md +++ b/tools/README.md @@ -7,7 +7,7 @@ The scripts in this directory assume that your current working directory is the ## Pre-release checklist - [ ] Update compatibility list -- [ ] Update translations +- [ ] If this is a major release (2123.1 -> major.minor), update translations ### Note: diff --git a/tools/enter-docker-dev-container.sh b/tools/enter-docker-dev-container.sh new file mode 100755 index 000000000..f03105be6 --- /dev/null +++ b/tools/enter-docker-dev-container.sh @@ -0,0 +1,5 @@ +#!/bin/bash -ex + +# This script assumes that Docker is installed + +docker run -it --rm -v $(pwd):/mnt opensauce04/azahar-build-environment diff --git a/tools/purge-github-cache.sh b/tools/purge-github-cache.sh new file mode 100755 index 000000000..01fdb2fed --- /dev/null +++ b/tools/purge-github-cache.sh @@ -0,0 +1,6 @@ +#!/bin/bash -ex + +# This script assumes that the Github CLI is installed and that +# the authenticated user has appropriate authorization. + +gh cache delete --all \ No newline at end of file